diff options
Diffstat (limited to 'src')
361 files changed, 26148 insertions, 14887 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2ecc8cb6..96334dd1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,4 @@ -# -# Copyright (C) 2021 Saturneric +# Copyright (C) 2021 Saturneric <[email protected]> # # This file is part of GpgFrontend. # @@ -20,91 +19,106 @@ # the gpg4usb project, which is under GPL-3.0-or-later. # # All the source code of GpgFrontend was modified and released by -# Saturneric<[email protected]> starting on May 12, 2021. +# Saturneric <[email protected]> starting on May 12, 2021. # # SPDX-License-Identifier: GPL-3.0-or-later -# Introduce boost -if(NOT BOOST_ROOT) - find_package(Boost COMPONENTS date_time system REQUIRED) -else() - find_package(Boost - COMPONENTS date_time system REQUIRED - PATHS ${BOOST_ROOT} NO_DEFAULT_PATH) +if(APPLE) + add_compile_definitions("_GNU_SOURCE") endif() +# Introduce GpgME +find_package(Gpgme REQUIRED) + +# Introduce Config++ +find_package(Config++ REQUIRED) + # Introduce OpenSSL -if(APPLE) - set(OPENSSL_ROOT_DIR /usr/local/opt/openssl@3) +if (APPLE) + # Define possible OpenSSL directories + set(OPENSSL_DIR_CANDIDATES + /usr/local/opt/openssl@3 + /opt/homebrew/opt/openssl@3 + ) + + # Find the valid OpenSSL directory + foreach(DIR IN LISTS OPENSSL_DIR_CANDIDATES) + if(IS_DIRECTORY "${DIR}" OR EXISTS "${DIR}") + set(OPENSSL_ROOT_DIR "${DIR}") + break() # Stop loop once a valid directory is found + endif() + endforeach() + + # If not found, throw an error or warning + if(NOT OPENSSL_ROOT_DIR) + message(FATAL_ERROR "OpenSSL not found in the standard directories. Please install it or set OPENSSL_ROOT_DIR manually.") + endif() endif() find_package(OpenSSL REQUIRED) # Introduce Qt -if (QT5_ENV_SUPPORT) - # Support Qt version: 6.x, 5.12.x and 5.15.x - find_package(Qt6 6 COMPONENTS Core Test Widgets PrintSupport Network Core5Compat) - if(NOT Qt6_DIR) - find_package(Qt5 5 COMPONENTS Core Test Widgets PrintSupport Network REQUIRED) - message(STATUS "Use Qt5 for application building ${Qt5_DIR}") - else() - message(STATUS "Use Qt6 for application building ${Qt6_DIR}") - add_definitions(-DGPGFRONTEND_GUI_QT6) - endif() - - # Qt configuration - set(CMAKE_AUTOMOC ON) - set(CMAKE_AUTORCC ON) - set(CMAKE_AUTOUIC ON) +# Support Qt version: 6.x +find_package(Qt6 6 COMPONENTS Core Test Widgets PrintSupport Network Core5Compat LinguistTools REQUIRED) + +# Qt configuration +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +set(CMAKE_AUTORCC_OPTIONS "--compress;9") +set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui) - set(CMAKE_AUTORCC_OPTIONS "--compress;9") - set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui) -endif () # configure for output path and resources -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) aux_source_directory(. BASE_SOURCE) set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc") set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico) if (NOT XCODE_BUILD) # Set Binary Output Path - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/artifacts) else () # Set Binary Output Path set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}) endif () endif () +if (BUILD_CORE) + # core depends pinentry + message("[+] Build Pinentry") + add_subdirectory(pinentry) -if (GPG_CORE) - message(STATUS "Build Gpg Core") + message("[+] Build Core") add_subdirectory(core) endif () -if (UI_CORE) - message(STATUS "Build UI Core") +if (BUILD_UI) + message("[+] Build UI") add_subdirectory(ui) endif () -if (SERVER_SUPPORT) - message(STATUS "Build Server Support") - add_compile_definitions(SERVER_SUPPORT) - add_subdirectory(server) +if (BUILD_MODULE) + message("[+] Build Module") + add_subdirectory(module) endif () -if (ADVANCE_SUPPORT) - message(STATUS "Build Advance Support") - add_compile_definitions(ADVANCE_SUPPORT) - add_subdirectory(advance) +# build to test gpgfrontend core +if (BUILD_TEST) + include(CTest) + enable_testing() + add_subdirectory(test) endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) # Set Resource Output Path if (${CMAKE_BUILD_TYPE} STREQUAL "Release") if (APPLE) set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources) elseif (LINUX AND NOT LINUX_INSTALL_SOFTWARE) file(COPY ${CMAKE_SOURCE_DIR}/resource/lfs/app-image/gpgfrontend DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/appstream/com.bktus.gpgfrontend.metainfo.xml DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share/metainfo FOLLOW_SYMLINK_CHAIN) + file(COPY ${CMAKE_SOURCE_DIR}/resource/appstream/com.bktus.gpgfrontend.desktop DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share/applications FOLLOW_SYMLINK_CHAIN) set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share) else () set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) @@ -114,52 +128,6 @@ if (APPLICATION_BUILD) endif () endif () -# Get ALL SOURCE FILES -file(GLOB_RECURSE ALL_SOURCE_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/src/*.cpp) - -# i18n -if (MULTI_LANG_SUPPORT) - message(STATUS "Build Multiply Languages Support") - # Set Translation Files - find_package(Gettext REQUIRED) - FIND_PROGRAM(GETTEXT_MSGFMT_EXECUTABLE msgfmt) - FIND_PROGRAM(GETTEXT_XGETTEXT_EXECUTABLE xgettext) - - set(LOCALE_OUTPUT_PATH ${RESOURCE_OUTPUT_DIRECTORY}/locales) - - if (NOT GETTEXT_MSGFMT_EXECUTABLE OR NOT GETTEXT_XGETTEXT_EXECUTABLE) - message(ERROR "msgfmt or xgettext not found. Translations will *not* be installed") - else() - message(STATUS "Setting target translations") - add_custom_target(translations) - set(OUTPUT_POT_PATH ${CMAKE_SOURCE_DIR}/resource/lfs/locale/template/${PROJECT_NAME}.pot) - add_custom_command( - TARGET translations - COMMAND find ${CMAKE_SOURCE_DIR}/src -iname \"*.cpp\" | xargs xgettext --package-name=${PROJECT_NAME} --copyright-holder=Saturneric --package-version=${PROJECT_VERSION} [email protected] --add-comments="/*" --c++ -k_ -o ${OUTPUT_POT_PATH} - ) - - file(GLOB ALL_PO_FILES ${CMAKE_SOURCE_DIR}/resource/lfs/locale/po/*.po) - SET(GMO_FILES) - - foreach (_poFile ${ALL_PO_FILES}) - GET_FILENAME_COMPONENT(_poFileName ${_poFile} NAME) - string(REGEX REPLACE "\\.[^.]*$" "" _langName ${_poFileName}) - message(STATUS "GNU gettext po file ${_langName}") - make_directory(${RESOURCE_OUTPUT_DIRECTORY}/locales) - make_directory(${RESOURCE_OUTPUT_DIRECTORY}/locales/${_langName}/LC_MESSAGES) - add_custom_command( - TARGET translations - COMMAND echo Processing po LANG ${_langName} - ) - add_custom_command( - TARGET translations - COMMAND msgfmt --check --verbose --output-file ${LOCALE_OUTPUT_PATH}/${_langName}/LC_MESSAGES/GpgFrontend.mo ${_poFile} - ) - endforeach () - - endif () -endif () - if (BASIC_ENV_CONFIG) # Set Build Information configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontend.h @ONLY) @@ -170,17 +138,14 @@ if (BASIC_ENV_CONFIG) endif () endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) # Copy Resource Files file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) file(COPY ${CMAKE_SOURCE_DIR}/resource/lfs/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) file(COPY ${CMAKE_SOURCE_DIR}/TRANSLATORS DESTINATION ${RESOURCE_OUTPUT_DIRECTORY} FOLLOW_SYMLINK_CHAIN) - if (GPG_STANDALONE_MODE) - file(COPY ${CMAKE_SOURCE_DIR}/resource/gpg1.4 DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - endif () endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) if (${CMAKE_BUILD_TYPE} STREQUAL "Release") if (APPLE) file(COPY ${CMAKE_SOURCE_DIR}/gpgfrontend.icns DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) @@ -192,7 +157,7 @@ if (APPLICATION_BUILD) endif () endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) # Copy Utils Files if (MINGW) message(STATUS "Copying Dependent DLL For Windows Runtime Env") @@ -209,10 +174,6 @@ if (APPLICATION_BUILD) list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) unset(_libDllPath) - file(GLOB _libDllPath "${_libDllBinPath}/libconfig++-*.dll") - list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) - - unset(_libDllPath) file(GLOB _libDllPath "${_libDllBinPath}/libarchive-*.dll") list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) @@ -341,18 +302,15 @@ if (APPLICATION_BUILD) endif () endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) set(RESOURCE_FILES ${CMAKE_SOURCE_DIR}/gpgfrontend.qrc ${APP_ICON_RESOURCE_WINDOWS} ${QON_QM_FILES}) add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES}) - if (MULTI_LANG_SUPPORT) - add_dependencies(resources translations) - endif () endif () -if (APPLICATION_BUILD) +if (BUILD_APPLICATION) if (${CMAKE_BUILD_TYPE} STREQUAL "Release") if (MINGW) - add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES}) # include qt dependencies if(NOT Qt6_DIR) add_custom_command(TARGET ${AppName} POST_BUILD @@ -363,10 +321,10 @@ if (APPLICATION_BUILD) endif() elseif (APPLE AND NOT XCODE_BUILD) # custom app bundle packing - add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES}) set_target_properties(${AppName} PROPERTIES BUNDLE True - MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend + MACOSX_BUNDLE_GUI_IDENTIFIER com.bktus.gpgfrontend MACOSX_BUNDLE_BUNDLE_NAME ${AppName} MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} @@ -381,7 +339,7 @@ if (APPLICATION_BUILD) WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMENT "Copying Resources into App Bundle Resource") elseif (LINUX AND NOT LINUX_INSTALL_SOFTWARE) - add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES}) add_custom_command(TARGET ${AppName} POST_BUILD COMMAND /bin/mkdir -p ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} @@ -393,10 +351,10 @@ if (APPLICATION_BUILD) # app bundle packing using xcode elseif (APPLE AND XCODE_BUILD) # standard app bundle packing - add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES}) set_target_properties(${AppName} PROPERTIES BUNDLE True - MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend + MACOSX_BUNDLE_GUI_IDENTIFIER com.bktus.gpgfrontend MACOSX_BUNDLE_BUNDLE_NAME ${AppName} MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} @@ -444,11 +402,11 @@ if (APPLICATION_BUILD) XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}" ) else () - add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES}) endif () else () # if the status is debug - add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES}) if(MINGW) # include qt dependencies if(NOT Qt6_DIR) @@ -463,125 +421,75 @@ if (APPLICATION_BUILD) # Make app build with resources add_dependencies(${AppName} resources) + + # using c++ standard 17 + target_compile_features(${AppName} PUBLIC cxx_std_17) endif () # link options for GpgFrontend -if (APPLICATION_BUILD) - target_link_libraries(${AppName} gpgfrontend_ui) +if (BUILD_APPLICATION) + target_link_libraries(${AppName} gpgfrontend_ui gpgfrontend_module gpgfrontend_test) if (MINGW) message(STATUS "Link Application Library For MINGW") target_link_libraries(${AppName} crypto) elseif (APPLE) message(STATUS "Link Application Library For macOS") - target_link_libraries(${AppName} intl) else () message(STATUS "Link Application Library For Linux") target_link_libraries(${AppName} crypto pthread) - # link for freebsd - if(FREEBSD) - target_link_libraries(${AppName} intl) - endif() - # issue on filesystem support of gcc - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 9.0) - target_link_libraries(${AppName} stdc++fs) - endif () endif () endif () -# using c++ standard 17 -target_compile_features(${AppName} PUBLIC cxx_std_17) +# add i18n support +if (BUILD_APPLICATION) + set(LOCALE_TS_PATH ${CMAKE_SOURCE_DIR}/resource/lfs/locale/ts) + set(TS_FILES "${LOCALE_TS_PATH}/GpgFrontend.de_DE.ts" + "${LOCALE_TS_PATH}/GpgFrontend.fr_FR.ts" + "${LOCALE_TS_PATH}/GpgFrontend.zh_CN.ts" + "${LOCALE_TS_PATH}/GpgFrontend.zh_TW.ts" + "${LOCALE_TS_PATH}/GpgFrontend.it_IT.ts") + file(GLOB_RECURSE ALL_SOURCE_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/src/*.cpp) + qt_add_translations(${AppName} + RESOURCE_PREFIX "/i18n" + TS_FILES ${TS_FILES} + SOURCES ${ALL_SOURCE_FILES} + INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/src) +endif() # if building linux package if (LINUX AND LINUX_INSTALL_SOFTWARE) + include(GNUInstallDirs) if (INSTALL_GPGFRONTEND_APP) install(TARGETS ${AppName} gpgfrontend_core gpgfrontend_ui EXPORT GpgFrontendTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) - install(DIRECTORY /usr/local/lib/ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - FILES_MATCHING PATTERN "libgpgme.so*") - install(DIRECTORY /usr/local/lib/ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - FILES_MATCHING PATTERN "libassuan.so*") - install(DIRECTORY /usr/local/lib/ - DESTINATION ${CMAKE_INSTALL_LIBDIR} - FILES_MATCHING PATTERN "libgpg-error.so*") + RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + install(DIRECTORY ${PC_GPGME_LIBDIR} + DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + FILES_MATCHING PATTERN "libgpgme.so*" + PATTERN "lib" EXCLUDE) + install(DIRECTORY ${PC_GPGME_LIBDIR} + DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + FILES_MATCHING PATTERN "libassuan.so*" + PATTERN "lib" EXCLUDE) + install(DIRECTORY ${PC_GPGME_LIBDIR} + DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + FILES_MATCHING PATTERN "libgpg-error.so*" + PATTERN "lib" EXCLUDE) install(FILES ${CMAKE_SOURCE_DIR}/TRANSLATORS - DESTINATION /usr/local/share/${AppName}/) - install(FILES ${CMAKE_SOURCE_DIR}/resource/meta/pub.gpgfrontend.gpgfrontend.appdata.xml - DESTINATION /usr/share/metainfo/) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource/desktop/ - DESTINATION /usr/share/applications/) + DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/${AppName}/) + install(FILES ${CMAKE_SOURCE_DIR}/resource/appstream/com.bktus.gpgfrontend.appdata.xml + DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/metainfo/) + install(FILES ${CMAKE_SOURCE_DIR}/resource/appstream/com.bktus.gpgfrontend.desktop + DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/applications/) install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource/lfs/pixmaps/ - DESTINATION /usr/share/pixmaps/) + DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/pixmaps/) install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource/lfs/hicolor/ - DESTINATION /usr/share/icons/hicolor/) - endif () - if (MULTI_LANG_SUPPORT) - install(DIRECTORY ${LOCALE_OUTPUT_PATH}/ - DESTINATION ${CMAKE_INSTALL_FULL_LOCALEDIR}) - endif () - - if (APP_PACKAGE_DEB) - message(STATUS "Configure DEB Package") - SET(CPACK_GENERATOR "DEB") - set(CPACK_INSTALL_PREFIX "/usr/local/") - set(CPACK_PACKAGE_NAME "gpgfrontend") - set(CPACK_DEBIAN_PACKAGE_NAME "gpgfrontend") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") - set(CPACK_PACKAGE_CONTACT "[email protected]") - SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Saturneric") - - if (${DISTRO_NAME} MATCHES "Ubuntu") - if (${DISTRO_VERSION_ID} STREQUAL "22.04") - set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9), libconfig++9v5 (>=1.5), libarchive13(>= 3.4), openssl(>= 1.1.1), libicu70") - elseif (${DISTRO_VERSION_ID} STREQUAL "20.04") - set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9), libconfig++9v5 (>=1.5), libarchive13(>= 3.4), openssl(>= 1.1.1), libicu66") - endif () - endif () - - set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") - set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") - set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") - include(CPack) - endif () - - if (APP_PACKAGE_RPM) - message(STATUS "Configure RPM Package") - SET(CPACK_GENERATOR "RPM") - set(CPACK_INSTALL_PREFIX "/usr/local/") - set(CPACK_PACKAGE_NAME "gpgfrontend") - set(CPACK_DEBIAN_PACKAGE_NAME "gpgfrontend") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") - set(CPACK_PACKAGE_CONTACT "[email protected]") - SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Saturneric") - - set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") - set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") - set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") - include(CPack) - endif () - - if (APP_PACKAGE_FREEBSD) - message(STATUS "Configure PKG Package") - SET(CPACK_GENERATOR "FREEBSD") - set(CPACK_INSTALL_PREFIX "/usr/local/") - set(CPACK_FREEBSD_PACKAGE_NAME "gpgfrontend") - set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") - set(CPACK_PACKAGE_CONTACT "[email protected]") - SET(CPACK_FREEBSD_PACKAGE_MAINTAINER "Saturneric") - - set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") - set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") - set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") - include(CPack) + DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/icons/hicolor/) endif () endif () message(STATUS "Resource Files: ${RESOURCE_OUTPUT_DIRECTORY}") -message(STATUS "Locale Files: ${LOCALE_OUTPUT_PATH}") message(STATUS "Runtime Files: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in index f441fb8f..56173bbd 100644 --- a/src/GpgFrontend.h.in +++ b/src/GpgFrontend.h.in @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,62 +20,20 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_H_IN -#define GPGFRONTEND_H_IN - -// standard headers -#include <cstdint> -#include <optional> -#include <filesystem> +#pragma once #ifdef WINDOWS -#include <winsock2.h> #include <windows.h> +#include <winsock2.h> #endif - -// i18n support -#include <libintl.h> -#define _(String) gettext (String) -#define gettext_noop(String) String -#define N_(String) gettext_noop (String) - - -// fix macro bugs in mingw -#ifdef WINDOWS -#include <clocale> -#undef vsnprintf -#undef sprintf -#undef snprintf -#endif - - -// logging system -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE -#include <spdlog/spdlog.h> - // build info #define PROJECT_NAME "@CMAKE_PROJECT_NAME@" -#define OS_PLATFORM @OS_PLATFORM@ +#define OS_PLATFORM "@OS_PLATFORM@" #define LOCALE_DIR "@LOCALE_DIR@" - - -// macros to find resource files -#if defined(MACOS) && defined(RELEASE) -#define RESOURCE_DIR(appDir) (appDir + "/../Resources/") -#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "Resources") -#elif defined(LINUX) && defined(RELEASE) -#define RESOURCE_DIR(appDir) (appDir + "/../share/") -#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "share") -#else -#define RESOURCE_DIR(appDir) (appDir) -#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir) -#endif - -#endif // GPGFRONTEND_H_IN diff --git a/src/GpgFrontendBuildInfo.h.in b/src/GpgFrontendBuildInfo.h.in index eff6e966..c6242b1e 100644 --- a/src/GpgFrontendBuildInfo.h.in +++ b/src/GpgFrontendBuildInfo.h.in @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,20 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_BUILD_INFO_H_IN -#define GPGFRONTEND_BUILD_INFO_H_IN +#pragma once /** * Logic Version (*.*.*) */ -#define VERSION_MAJOR @CMAKE_PROJECT_VERSION_MAJOR@ -#define VERSION_MINOR @CMAKE_PROJECT_VERSION_MINOR@ -#define VERSION_PATCH @CMAKE_PROJECT_VERSION_PATCH@ +#define VERSION_MAJOR "@CMAKE_PROJECT_VERSION_MAJOR@" +#define VERSION_MINOR "@CMAKE_PROJECT_VERSION_MINOR@" +#define VERSION_PATCH "@CMAKE_PROJECT_VERSION_PATCH@" /** * Code Version (According to Git) @@ -45,18 +44,12 @@ /** * Generated Information (According to CMake) */ -#define PROJECT_NAME "@PROJECT_NAME@" #define BUILD_VERSION "@BUILD_VERSION@" #define GIT_VERSION "@GIT_VERSION@" /** * Build Information */ -#define BUILD_FLAG @BUILD_FLAG@ +#define BUILD_FLAG "@BUILD_FLAG@" #define BUILD_TIMESTAMP "@BUILD_TIMESTAMP@" -#define APP_INSTALL_FLAG "@APP_INSTALL_FLAG@" - - - - -#endif // GPGFRONTEND_BUILD_INFO_H_IN +#define APP_INSTALL_FLAG "@APP_INSTALL_FLAG@"
\ No newline at end of file diff --git a/src/GpgFrontendBuildInstallInfo.h.in b/src/GpgFrontendBuildInstallInfo.h.in index abc1af0f..79ae30b6 100644 --- a/src/GpgFrontendBuildInstallInfo.h.in +++ b/src/GpgFrontendBuildInstallInfo.h.in @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_BUILD_INSTALL_INFO_H_IN -#define GPGFRONTEND_BUILD_INSTALL_INFO_H_IN +#pragma once /** * Build & Install Path Information @@ -36,6 +35,4 @@ #define APP_BIN_PATH "@CMAKE_INSTALL_FULL_BINDIR@" #define APP_LOCALSTATE_PATH "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@" #define APP_SYSCONF_PATH "@CMAKE_INSTALL_FULL_SYSCONFDIR@" -#define APP_INFO_PATH "@CMAKE_INSTALL_FULL_INFODIR@" - -#endif // GPGFRONTEND_BUILD_INSTALL_INFO_H_IN
\ No newline at end of file +#define APP_INFO_PATH "@CMAKE_INSTALL_FULL_INFODIR@"
\ No newline at end of file diff --git a/src/GpgFrontendContext.cpp b/src/GpgFrontendContext.cpp new file mode 100644 index 00000000..9d264dcd --- /dev/null +++ b/src/GpgFrontendContext.cpp @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgFrontendContext.h" + +#include <qapplication.h> +#include <qcoreapplication.h> +#include <qobject.h> +#include <qthread.h> + +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +void GpgFrontendContext::InitApplication() { + app_ = SecureCreateObject<QApplication>(argc, argv); +} + +auto GpgFrontendContext::GetApp() -> QApplication* { return app_; } + +GpgFrontendContext::GpgFrontendContext(int argc, char** argv) + : argc(argc), argv(argv) {} + +GpgFrontendContext::~GpgFrontendContext() { + if (app_ != nullptr) { + SecureDestroyObject(app_); + } +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/GpgFrontendContext.h b/src/GpgFrontendContext.h new file mode 100644 index 00000000..e0d176f1 --- /dev/null +++ b/src/GpgFrontendContext.h @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +struct GpgFrontendContext; + +using GFCxtWPtr = std::weak_ptr<GpgFrontendContext>; +using GFCxtSPtr = std::shared_ptr<GpgFrontendContext>; + +struct GpgFrontendContext { + int argc; + char** argv; + spdlog::level::level_enum log_level; + + bool load_ui_env; + bool gather_external_gnupg_info; + bool load_default_gpg_context; + + /** + * @brief Construct a new Gpg Frontend Context object + * + * @param argc + * @param argv + */ + GpgFrontendContext(int argc, char** argv); + + /** + * @brief Destroy the Gpg Frontend Context object + * + */ + ~GpgFrontendContext(); + + /** + * @brief + * + */ + void InitApplication(); + + /** + * @brief Get the App object + * + * @return QCoreApplication* + */ + auto GetApp() -> QApplication*; + + private: + QApplication* app_ = nullptr; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp new file mode 100644 index 00000000..6d207373 --- /dev/null +++ b/src/app.cpp @@ -0,0 +1,111 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgFrontendContext.h" +#include "core/GpgConstants.h" +#include "core/GpgCoreInit.h" +#include "module/GpgFrontendModuleInit.h" +#include "ui/GpgFrontendUIInit.h" + +// main +#include "main.h" + +namespace GpgFrontend { + +constexpr int kCrashCode = ~0; ///< + +/** + * @brief + * + * @param argc + * @param argv + * @return int + */ +auto StartApplication(const GFCxtWPtr& p_ctx) -> int { + GFCxtSPtr ctx = p_ctx.lock(); + if (ctx == nullptr) { + GF_MAIN_LOG_ERROR("cannot get gpgfrontend context."); + return -1; + } + + auto* app = ctx->GetApp(); + if (app == nullptr) { + GF_MAIN_LOG_ERROR("cannot get qapplication from gpgfrontend context."); + return -1; + } + + GF_MAIN_LOG_INFO("start running gui application"); + + /** + * internationalisation. loop to restart main window + * with changed translation when settings change. + */ + int return_from_event_loop_code; + int restart_count = 0; + + do { + // after that load ui totally + GpgFrontend::UI::InitGpgFrontendUI(app); + + // finally create main window + return_from_event_loop_code = GpgFrontend::UI::RunGpgFrontendUI(app); + + GF_MAIN_LOG_DEBUG("try to destroy modules system and core"); + + restart_count++; + + GF_MAIN_LOG_DEBUG( + "restart loop refresh, event loop code: {}, restart count: {}", + return_from_event_loop_code, restart_count); + } while (return_from_event_loop_code == GpgFrontend::kRestartCode && + restart_count < 99); + + // first should shutdown the module system + GpgFrontend::Module::ShutdownGpgFrontendModules(); + + // then shutdown the core + GpgFrontend::DestroyGpgFrontendCore(); + GF_MAIN_LOG_DEBUG("core and modules system destroyed"); + + // log for debug + GF_MAIN_LOG_INFO("GpgFrontend is about to exit."); + + // deep restart mode + if (return_from_event_loop_code == GpgFrontend::kDeepRestartCode || + return_from_event_loop_code == kCrashCode) { + // log for debug + GF_MAIN_LOG_DEBUG( + "deep restart or cash loop status caught, restart a new application"); + QProcess::startDetached(qApp->arguments()[0], qApp->arguments()); + }; + + // exit the program + return return_from_event_loop_code; +} + +} // namespace GpgFrontend diff --git a/src/app.h b/src/app.h new file mode 100644 index 00000000..89004e07 --- /dev/null +++ b/src/app.h @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "GpgFrontendContext.h" + +namespace GpgFrontend { + +auto StartApplication(const GFCxtWPtr& p_ctx) -> int; + +} diff --git a/src/cmd.cpp b/src/cmd.cpp new file mode 100644 index 00000000..e19ad218 --- /dev/null +++ b/src/cmd.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "cmd.h" + +#include "main.h" + +// std +#include <iostream> + +// GpgFrontend +#include "GpgFrontendBuildInfo.h" +#include "GpgFrontendContext.h" +#include "test/GpgFrontendTest.h" + +namespace GpgFrontend { + +auto PrintVersion() -> int { + QTextStream stream(stdin); + stream << PROJECT_NAME << " " + << "v" << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH + << '\n'; + stream << "Copyright (C) 2021 Saturneric <[email protected]>" << '\n' + << QObject::tr( + "This is free software; see the source for copying conditions.") + << '\n' + << '\n'; + + stream << QObject::tr("Build Timestamp: ") << BUILD_TIMESTAMP << '\n' + << QObject::tr("Build Version: ") << BUILD_VERSION << '\n' + << QObject::tr("Source Code Version: ") << GIT_VERSION << '\n'; + + stream << Qt::endl; + + return 0; +} + +auto ParseLogLevel(const QString& log_level) -> spdlog::level::level_enum { + if (log_level == "trace") { + return spdlog::level::trace; + } + if (log_level == "debug") { + return spdlog::level::debug; + } + if (log_level == "info") { + return spdlog::level::info; + } + if (log_level == "warn") { + return spdlog::level::warn; + } + if (log_level == "error") { + return spdlog::level::err; + } + + return spdlog::level::info; +} + +auto RunTest(const GFCxtWPtr& p_ctx) -> int { + GpgFrontend::GFCxtSPtr const ctx = p_ctx.lock(); + if (ctx == nullptr) { + GF_MAIN_LOG_ERROR("cannot get gpgfrontend context for test running"); + return -1; + } + + GpgFrontend::Test::GpgFrontendContext test_init_args; + test_init_args.argc = ctx->argc; + test_init_args.argv = ctx->argv; + + return GpgFrontend::Test::ExecuteAllTestCase(test_init_args); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/cmd.h b/src/cmd.h new file mode 100644 index 00000000..061926dc --- /dev/null +++ b/src/cmd.h @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "GpgFrontendContext.h" + +namespace GpgFrontend { + +// functions + +auto PrintVersion() -> int; + +auto ParseLogLevel(const QString& level) -> spdlog::level::level_enum; + +auto RunTest(const GFCxtWPtr&) -> int; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 22a0b88a..d51ec6d1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,4 @@ -# -# Copyright (C) 2021 Saturneric +# Copyright (C) 2021 Saturneric <[email protected]> # # This file is part of GpgFrontend. # @@ -20,31 +19,34 @@ # the gpg4usb project, which is under GPL-3.0-or-later. # # All the source code of GpgFrontend was modified and released by -# Saturneric<[email protected]> starting on May 12, 2021. +# Saturneric <[email protected]> starting on May 12, 2021. # # SPDX-License-Identifier: GPL-3.0-or-later -aux_source_directory(./function/result_analyse GPG_SOURCE) -aux_source_directory(./function/gpg GPG_SOURCE) -aux_source_directory(./function/aes GPG_SOURCE) -aux_source_directory(./function GPG_SOURCE) -aux_source_directory(./thread GPG_SOURCE) -aux_source_directory(./model GPG_SOURCE) -aux_source_directory(./common GPG_SOURCE) -aux_source_directory(. GPG_SOURCE) + +aux_source_directory(./function/result_analyse CORE_SOURCE) +aux_source_directory(./function/basic CORE_SOURCE) +aux_source_directory(./function/gpg CORE_SOURCE) +aux_source_directory(./function/secure_memory CORE_SOURCE) +aux_source_directory(./function CORE_SOURCE) +aux_source_directory(./thread CORE_SOURCE) +aux_source_directory(./model CORE_SOURCE) +aux_source_directory(./common CORE_SOURCE) +aux_source_directory(./module CORE_SOURCE) +aux_source_directory(./utils/aes CORE_SOURCE) +aux_source_directory(./utils CORE_SOURCE) +aux_source_directory(. CORE_SOURCE) # define libgpgfrontend_core set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) -add_library(gpgfrontend_core SHARED ${GPG_SOURCE}) +add_library(gpgfrontend_core SHARED ${CORE_SOURCE}) set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendCoreExport.h") generate_export_header(gpgfrontend_core EXPORT_FILE_NAME "${_export_file}") -# link third-party libraries -target_link_libraries(gpgfrontend_core PUBLIC config++) -if (NOT LINUX) - target_link_libraries(gpgfrontend_core PUBLIC config++ intl) -endif () +if(NOT APPLE) + target_link_libraries(gpgfrontend_core PUBLIC mimalloc) +endif() # qt-aes target_sources(gpgfrontend_core PRIVATE @@ -54,24 +56,10 @@ target_sources(gpgfrontend_core PRIVATE aux_source_directory(${CMAKE_SOURCE_DIR}/third_party/encoding-detect ENCODING_DETECT_SOURCE_CODE) target_sources(gpgfrontend_core PUBLIC ${ENCODING_DETECT_SOURCE_CODE}) -# icu -if (APPLE) - target_include_directories(gpgfrontend_core PRIVATE /usr/local/opt/icu4c/include) - target_link_directories(gpgfrontend_core PRIVATE /usr/local/opt/icu4c/lib) - target_link_libraries(gpgfrontend_core PRIVATE icui18n icuuc icudata) -else () - find_package(ICU 60.0 REQUIRED COMPONENTS i18n uc data) - message("ICU version: ${ICU_VERSION}") - message("ICU libraries: ${ICU_LIBRARIES}") - target_link_libraries(gpgfrontend_core PRIVATE ${ICU_LIBRARIES}) -endif () - # link gnupg libraries -target_link_libraries(gpgfrontend_core PRIVATE gpgme assuan gpg-error) +target_link_libraries(gpgfrontend_core PUBLIC gpgme assuan gpg-error) # link openssl target_link_libraries(gpgfrontend_core PUBLIC OpenSSL::SSL OpenSSL::Crypto) -# link boost libraries -target_link_libraries(gpgfrontend_core PUBLIC ${Boost_LIBRARIES}) if (MINGW) # for uuid ability in mingw target_link_libraries(gpgfrontend_core PUBLIC bcrypt) @@ -81,17 +69,15 @@ endif () target_link_libraries(gpgfrontend_core PRIVATE spdlog) # link libarchive +if(APPLE) + set(LibArchive_INCLUDE_DIR "/usr/local/opt/libarchive/include") +endif() +find_package(LibArchive REQUIRED) +target_include_directories(gpgfrontend_core PRIVATE ${LibArchive_INCLUDE_DIR}) target_link_libraries(gpgfrontend_core PRIVATE archive) - -# link json -target_link_libraries(gpgfrontend_core - PUBLIC nlohmann_json::nlohmann_json) + # link Qt core -if(Qt6_DIR) - target_link_libraries(gpgfrontend_core PUBLIC Qt6::Core) -else() - target_link_libraries(gpgfrontend_core PUBLIC Qt5::Core) -endif() +target_link_libraries(gpgfrontend_core PUBLIC Qt6::Core) # set up pch target_precompile_headers(gpgfrontend_core diff --git a/src/core/GpgConstants.cpp b/src/core/GpgConstants.cpp index 35e485d4..ade003a8 100644 --- a/src/core/GpgConstants.cpp +++ b/src/core/GpgConstants.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,177 +28,5 @@ #include "core/GpgConstants.h" -#include <boost/algorithm/string/predicate.hpp> - -#include "function/FileOperator.h" - -const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN = - "-----BEGIN PGP MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_CRYPT_END = - "-----END PGP MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN = - "-----BEGIN PGP SIGNED MESSAGE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNED_END = - "-----END PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN = - "-----BEGIN PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_END = - "-----END PGP SIGNATURE-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_PUBLIC_KEY_BEGIN = - "-----BEGIN PGP PUBLIC KEY BLOCK-----"; ///< -const char* GpgFrontend::GpgConstants::PGP_PRIVATE_KEY_BEGIN = - "-----BEGIN PGP PRIVATE KEY BLOCK-----"; ///< -const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = - "GpgF_Scpt://"; ///< - -gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err) { - if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - SPDLOG_ERROR("[error: {}] source: {} description: {}", gpg_err_code(err), - gpgme_strsource(err), gpgme_strerror(err)); - } - return err; -} - -gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err, - gpgme_error_t predict) { - auto err_code = gpg_err_code(err); - if (err_code != gpg_err_code(predict)) { - if (err_code == GPG_ERR_NO_ERROR) - SPDLOG_WARN("[Warning {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - else - SPDLOG_ERROR("[Error {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - } - return err_code; -} - -gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err, - const std::string& comment) { - if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - SPDLOG_WARN("[Error {}] Source: {} description: {} predict: {}", - gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), - gpgme_strerror(err)); - } - return err; -} - -std::string GpgFrontend::beautify_fingerprint( - GpgFrontend::BypeArrayConstRef fingerprint) { - auto len = fingerprint.size(); - std::stringstream out; - decltype(len) count = 0; - while (count < len) { - if (count && !(count % 5)) out << " "; - out << fingerprint[count]; - count++; - } - return out.str(); -} - -static inline void ltrim(std::string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); -} - -static inline void rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - s.end()); -} - -static inline std::string trim(std::string& s) { - ltrim(s); - rtrim(s); - return s; -} - -std::string GpgFrontend::read_all_data_in_file(const std::string& utf8_path) { - std::string data; - FileOperator::ReadFileStd(utf8_path, data); - return data; -} - -bool GpgFrontend::write_buffer_to_file(const std::string& utf8_path, - const std::string& out_buffer) { - return FileOperator::WriteFileStd(utf8_path, out_buffer); -} - -std::string GpgFrontend::get_file_extension(const std::string& path) { - // Create a path object from given string - std::filesystem::path path_obj(path); - - // Check if file name in the path object has extension - if (path_obj.has_extension()) { - // Fetch the extension from path object and return - return path_obj.extension().u8string(); - } - // In case of no extension return empty string - return {}; -} - -std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) { - // Create a path object from given string - std::filesystem::path path_obj(path); - // Check if file name in the path object has extension - if (path_obj.has_filename()) { - // Fetch the extension from path object and return - return (path_obj.parent_path() / path_obj.stem()).u8string(); - } - // In case of no extension return empty string - return {}; -} - -int GpgFrontend::text_is_signed(GpgFrontend::BypeArrayRef text) { - using boost::algorithm::ends_with; - using boost::algorithm::starts_with; - - auto trim_text = trim(text); - if (starts_with(trim_text, GpgConstants::PGP_SIGNED_BEGIN) && - ends_with(trim_text, GpgConstants::PGP_SIGNED_END)) - return 2; - else if (text.find(GpgConstants::PGP_SIGNED_BEGIN) != std::string::npos && - text.find(GpgConstants::PGP_SIGNED_END) != std::string::npos) - return 1; - else - return 0; -} - -GpgFrontend::GpgEncrResult GpgFrontend::_new_result( - gpgme_encrypt_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgDecrResult GpgFrontend::_new_result( - gpgme_decrypt_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgSignResult GpgFrontend::_new_result( - gpgme_sign_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgVerifyResult GpgFrontend::_new_result( - gpgme_verify_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -GpgFrontend::GpgGenKeyResult GpgFrontend::_new_result( - gpgme_genkey_result_t&& result) { - gpgme_result_ref(result); - return {result, _result_ref_deletor()}; -} - -void GpgFrontend::_result_ref_deletor::operator()(void* _result) { - SPDLOG_TRACE("gpgme unref {}", _result); - if (_result != nullptr) gpgme_result_unref(_result); -} +namespace GpgFrontend { +} // namespace GpgFrontend diff --git a/src/core/GpgConstants.h b/src/core/GpgConstants.h index a8a87835..c2125650 100644 --- a/src/core/GpgConstants.h +++ b/src/core/GpgConstants.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,200 +20,35 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPG_CONSTANTS_H -#define GPG_CONSTANTS_H - -#include "GpgFrontendCore.h" - -const int RESTART_CODE = 1000; ///< only refresh ui -const int DEEP_RESTART_CODE = 1001; // refresh core and ui +#pragma once namespace GpgFrontend { -using ByteArray = std::string; ///< -using ByteArrayPtr = std::unique_ptr<ByteArray>; ///< -using StdBypeArrayPtr = std::unique_ptr<ByteArray>; ///< -using BypeArrayRef = ByteArray&; ///< -using BypeArrayConstRef = const ByteArray&; ///< -using StringArgsPtr = std::unique_ptr<std::vector<std::string>>; ///< -using StringArgsRef = std::vector<std::string>&; ///< - -using GpgError = gpgme_error_t; - -/** - * @brief Result Deleter - * - */ -struct _result_ref_deletor { - void operator()(void* _result); -}; - -using GpgEncrResult = std::shared_ptr<struct _gpgme_op_encrypt_result>; ///< -using GpgDecrResult = std::shared_ptr<struct _gpgme_op_decrypt_result>; ///< -using GpgSignResult = std::shared_ptr<struct _gpgme_op_sign_result>; ///< -using GpgVerifyResult = std::shared_ptr<struct _gpgme_op_verify_result>; ///< -using GpgGenKeyResult = std::shared_ptr<struct _gpgme_op_genkey_result>; ///< -// Convert from gpgme_xxx_result to GpgXXXResult - -/** - * @brief - * - * @param result - * @return GpgEncrResult - */ -GPGFRONTEND_CORE_EXPORT GpgEncrResult -_new_result(gpgme_encrypt_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgDecrResult - */ -GPGFRONTEND_CORE_EXPORT GpgDecrResult -_new_result(gpgme_decrypt_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgSignResult - */ -GPGFRONTEND_CORE_EXPORT GpgSignResult _new_result(gpgme_sign_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgVerifyResult - */ -GPGFRONTEND_CORE_EXPORT GpgVerifyResult -_new_result(gpgme_verify_result_t&& result); - -/** - * @brief - * - * @param result - * @return GpgGenKeyResult - */ -GPGFRONTEND_CORE_EXPORT GpgGenKeyResult -_new_result(gpgme_genkey_result_t&& result); - -// Error Info Printer - -/** - * @brief - * - * @param err - * @return GpgError - */ -GPGFRONTEND_CORE_EXPORT GpgError check_gpg_error(GpgError err); - -/** - * @brief - * - * @param gpgmeError - * @param comment - * @return GpgError - */ -GPGFRONTEND_CORE_EXPORT GpgError check_gpg_error(GpgError gpgmeError, - const std::string& comment); - -/** - * @brief - * - * @param err - * @param predict - * @return gpg_err_code_t - */ -GPGFRONTEND_CORE_EXPORT gpg_err_code_t check_gpg_error_2_err_code( - gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR); - -// Fingerprint - -/** - * @brief - * - * @param fingerprint - * @return std::string - */ -GPGFRONTEND_CORE_EXPORT std::string beautify_fingerprint( - BypeArrayConstRef fingerprint); - -// File Operation - -/** - * @brief - * - * @param path - * @return std::string - */ -std::string read_all_data_in_file(const std::string& path); - -/** - * @brief - * - * @param path - * @param out_buffer - * @return true - * @return false - */ -GPGFRONTEND_CORE_EXPORT bool write_buffer_to_file( - const std::string& path, const std::string& out_buffer); - -/** - * @brief Get the file extension object - * - * @param path - * @return std::string - */ -std::string get_file_extension(const std::string& path); - -/** - * @brief Get the only file name with path object - * - * @param path - * @return std::string - */ -std::string get_only_file_name_with_path(const std::string& path); - -// Check - -/** - * @brief - * - * @param text - * @return int - */ -int text_is_signed(BypeArrayRef text); +constexpr int kRestartCode = 1000; ///< only refresh ui +constexpr int kDeepRestartCode = 1001; // refresh core and ui // Channels -const int GPGFRONTEND_DEFAULT_CHANNEL = 0; ///< -const int GPGFRONTEND_NON_ASCII_CHANNEL = 2; ///< - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgConstants { - public: - static const char* PGP_CRYPT_BEGIN; ///< - static const char* PGP_CRYPT_END; ///< - static const char* PGP_SIGNED_BEGIN; ///< - static const char* PGP_SIGNED_END; ///< - static const char* PGP_SIGNATURE_BEGIN; ///< - static const char* PGP_SIGNATURE_END; ///< - static const char* PGP_PUBLIC_KEY_BEGIN; ///< - static const char* PGP_PRIVATE_KEY_BEGIN; ///< - static const char* GPG_FRONTEND_SHORT_CRYPTO_HEAD; ///< -}; +constexpr int kGpgFrontendDefaultChannel = 0; ///< +constexpr int kGpgFrontendNonAsciiChannel = 2; ///< + +// HEADER +constexpr const char* PGP_CRYPT_BEGIN = "-----BEGIN PGP MESSAGE-----"; ///< +constexpr const char* PGP_CRYPT_END = "-----END PGP MESSAGE-----"; ///< +constexpr const char* PGP_SIGNED_BEGIN = + "-----BEGIN PGP SIGNED MESSAGE-----"; ///< +constexpr const char* PGP_SIGNED_END = "-----END PGP SIGNATURE-----"; ///< +constexpr const char* PGP_SIGNATURE_BEGIN = + "-----BEGIN PGP SIGNATURE-----"; ///< +constexpr const char* PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----"; ///< +constexpr const char* PGP_PUBLIC_KEY_BEGIN = + "-----BEGIN PGP PUBLIC KEY BLOCK-----"; ///< +constexpr const char* PGP_PRIVATE_KEY_BEGIN = + "-----BEGIN PGP PRIVATE KEY BLOCK-----"; ///< } // namespace GpgFrontend - -#endif // GPG_CONSTANTS_H diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp deleted file mode 100644 index 7d98004d..00000000 --- a/src/core/GpgContext.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "core/GpgContext.h" - -#include <gpg-error.h> -#include <gpgme.h> -#include <spdlog/spdlog.h> -#include <unistd.h> - -#include <mutex> -#include <shared_mutex> -#include <string> - -#include "core/GpgConstants.h" -#include "core/common/CoreCommonUtil.h" -#include "core/function/CoreSignalStation.h" -#include "core/function/gpg/GpgCommandExecutor.h" -#include "core/thread/Task.h" -#include "core/thread/TaskRunnerGetter.h" -#include "function/gpg/GpgKeyGetter.h" - -#ifdef _WIN32 -#include <windows.h> -#endif - -namespace GpgFrontend { - -GpgContext::GpgContext(int channel) - : SingletonFunctionObject<GpgContext>(channel) {} - -/** - * Constructor - * Set up gpgme-context, set paths to app-run path - */ -GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { - gpgme_ctx_t _p_ctx; - - // get gpgme library version - info_.GpgMEVersion = gpgme_check_version(nullptr); - - // create a new context - check_gpg_error(gpgme_new(&_p_ctx)); - _ctx_ref = CtxRefHandler(_p_ctx); - - if (args.gpg_alone) { - info_.AppPath = args.gpg_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - if (args.custom_gpgconf && !args.custom_gpgconf_path.empty()) { - SPDLOG_DEBUG("set custom gpgconf path: {}", args.custom_gpgconf_path); - auto err = - gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_GPGCONF, - args.custom_gpgconf_path.c_str(), nullptr); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - // set context offline mode - SPDLOG_DEBUG("gpg context offline mode: {}", args_.offline_mode); - gpgme_set_offline(_ctx_ref.get(), args_.offline_mode ? 1 : 0); - - // set option auto import missing key - // invalid at offline mode - SPDLOG_DEBUG("gpg context auto import missing key: {}", args_.offline_mode); - if (!args.offline_mode && args.auto_import_missing_key) - check_gpg_error(gpgme_set_ctx_flag(_ctx_ref.get(), "auto-key-import", "1")); - - // get engine info - auto engine_info = gpgme_ctx_get_engine_info(*this); - // Check ENV before running - bool check_passed = false, find_openpgp = false, find_gpgconf = false, - find_cms = false; - - while (engine_info != nullptr) { - if (!strcmp(engine_info->version, "1.0.0")) { - engine_info = engine_info->next; - continue; - } - - SPDLOG_DEBUG( - "gpg context engine info: {} {} {} {}", - gpgme_get_protocol_name(engine_info->protocol), - std::string(engine_info->file_name == nullptr ? "null" - : engine_info->file_name), - std::string(engine_info->home_dir == nullptr ? "null" - : engine_info->home_dir), - std::string(engine_info->version ? "null" : engine_info->version)); - - switch (engine_info->protocol) { - case GPGME_PROTOCOL_OpenPGP: - find_openpgp = true; - info_.AppPath = engine_info->file_name; - info_.GnupgVersion = engine_info->version; - info_.DatabasePath = std::string(engine_info->home_dir == nullptr - ? "default" - : engine_info->home_dir); - break; - case GPGME_PROTOCOL_CMS: - find_cms = true; - info_.CMSPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_GPGCONF: - find_gpgconf = true; - info_.GpgConfPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_ASSUAN: - info_.AssuanPath = engine_info->file_name; - break; - case GPGME_PROTOCOL_G13: - break; - case GPGME_PROTOCOL_UISERVER: - break; - case GPGME_PROTOCOL_SPAWN: - break; - case GPGME_PROTOCOL_DEFAULT: - break; - case GPGME_PROTOCOL_UNKNOWN: - break; - } - engine_info = engine_info->next; - } - - // set custom key db path - if (!args.db_path.empty()) { - info_.DatabasePath = args.db_path; - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - SPDLOG_DEBUG("ctx set custom key db path: {}", info_.DatabasePath); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } - - // conditional check - if ((info_.GnupgVersion >= "2.0.0" && find_gpgconf && find_openpgp && - find_cms) || - (info_.GnupgVersion > "1.0.0" && find_gpgconf)) - check_passed = true; - - if (!check_passed) { - this->good_ = false; - SPDLOG_ERROR("env check failed"); - return; - } else { - // speed up loading process - gpgme_set_offline(*this, 1); - - // set keylist mode - if (info_.GnupgVersion >= "2.0.0") { - check_gpg_error(gpgme_set_keylist_mode( - *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | - GPGME_KEYLIST_MODE_SIGS | - GPGME_KEYLIST_MODE_SIG_NOTATIONS | - GPGME_KEYLIST_MODE_WITH_TOFU)); - } else { - check_gpg_error(gpgme_set_keylist_mode( - *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS | - GPGME_KEYLIST_MODE_SIG_NOTATIONS | - GPGME_KEYLIST_MODE_WITH_TOFU)); - } - - // async, init context - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask(new Thread::Task( - [=](Thread::Task::DataObjectPtr) -> int { - post_init_ctx(); - return 0; - }, - "post_init_ctx")); - - good_ = true; - } -} - -void GpgContext::post_init_ctx() { - // Set Independent Database - if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) { - info_.DatabasePath = args_.db_path; - SPDLOG_DEBUG("custom key db path {}", info_.DatabasePath); - auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, - info_.AppPath.c_str(), - info_.DatabasePath.c_str()); - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - } else { - info_.DatabasePath = "default"; - } - - if (args_.ascii) { - /** Setting the output type must be done at the beginning */ - /** think this means ascii-armor --> ? */ - gpgme_set_armor(*this, 1); - } else { - /** Setting the output type must be done at the beginning */ - /** think this means ascii-armor --> ? */ - gpgme_set_armor(*this, 0); - } - - // for unit test - if (args_.test_mode) { - if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb); - gpgme_set_status_cb(*this, test_status_cb, nullptr); - } - - // preload info - auto &info = GetInfo(); - - // use custom qt dialog to replace pinentry - if (!args_.use_pinentry) { - SetPassphraseCb(custom_passphrase_cb); - } - - connect(this, &GpgContext::SignalNeedUserInputPassphrase, - CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalNeedUserInputPassphrase); -} - -bool GpgContext::good() const { return good_; } - -void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const { - if (info_.GnupgVersion >= "2.1.0") { - if (gpgme_get_pinentry_mode(*this) != GPGME_PINENTRY_MODE_LOOPBACK) { - gpgme_set_pinentry_mode(*this, GPGME_PINENTRY_MODE_LOOPBACK); - } - gpgme_set_passphrase_cb(*this, cb, nullptr); - } else { - SPDLOG_ERROR("not supported for gnupg version: {}", info_.GnupgVersion); - } -} - -gpgme_error_t GpgContext::test_passphrase_cb(void *opaque, const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - size_t res; - std::string pass = "abcdefg\n"; - auto pass_len = pass.size(); - - size_t off = 0; - - do { - res = gpgme_io_write(fd, &pass[off], pass_len - off); - if (res > 0) off += res; - } while (res > 0 && off != pass_len); - - return off == pass_len ? 0 : gpgme_error_from_errno(errno); -} - -gpgme_error_t GpgContext::custom_passphrase_cb(void *opaque, - const char *uid_hint, - const char *passphrase_info, - int last_was_bad, int fd) { - SPDLOG_DEBUG("custom passphrase cb called, bad times: {}", last_was_bad); - - if (last_was_bad > 3) { - SPDLOG_WARN("failure_counts is over three times"); - return gpgme_error_from_errno(GPG_ERR_CANCELED); - } - - std::string passphrase = - CoreCommonUtil::GetInstance()->GetTempCacheValue("__key_passphrase"); - // no pawword is an error situation - if (passphrase.empty()) { - // user input passphrase - SPDLOG_DEBUG("might need user to input passparase"); - passphrase = GpgContext::GetInstance().need_user_input_passphrase(); - if (passphrase.empty()) { - gpgme_io_write(fd, "\n", 1); - return gpgme_error_from_errno(GPG_ERR_CANCELED); - } - } - - // the user must at least write a newline character before returning from the - // callback. - passphrase = passphrase.append("\n"); - auto passpahrase_size = passphrase.size(); - - size_t off = 0, res = 0; - do { - res = gpgme_io_write(fd, &passphrase[off], passpahrase_size - off); - if (res > 0) off += res; - } while (res > 0 && off != passpahrase_size); - - return off == passpahrase_size ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED); -} - -gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword, - const char *args) { - SPDLOG_DEBUG("keyword {}", keyword); - return GPG_ERR_NO_ERROR; -} - -std::string GpgContext::need_user_input_passphrase() { - emit SignalNeedUserInputPassphrase(); - - std::string final_passphrase; - bool input_done = false; - SPDLOG_DEBUG("loop start to wait from user"); - auto connection = - connect(CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalUserInputPassphraseDone, this, - [&](QString passphrase) { - SPDLOG_DEBUG("SignalUserInputPassphraseDone emitted"); - final_passphrase = passphrase.toStdString(); - input_done = true; - }); - while (!input_done) { - QCoreApplication::processEvents(QEventLoop::AllEvents, 800); - } - disconnect(connection); - - SPDLOG_DEBUG("lopper end"); - return final_passphrase; -} - -const GpgInfo &GpgContext::GetInfo(bool refresh) { - if (!extend_info_loaded_ || refresh) { - // try lock - std::unique_lock lock(preload_lock_); - - // check twice - if (extend_info_loaded_ && !refresh) return info_; - - SPDLOG_DEBUG("start to load extra info"); - - // get all components - GpgCommandExecutor::GetInstance().Execute( - info_.GpgConfPath, {"--list-components"}, - [=](int exit_code, const std::string &p_out, const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf components exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} ,process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &components_info = info_.ComponentsInfo; - components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, - _("Embedded In"), "/"}; - - auto gpgconf_binary_checksum = - check_binary_chacksum(info_.GpgConfPath); - components_info["gpgconf"] = {"GPG Configure", "/", info_.GpgConfPath, - gpgconf_binary_checksum.has_value() - ? gpgconf_binary_checksum.value() - : "/"}; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - if (info_split_list.size() != 3) continue; - - auto component_name = info_split_list[0]; - auto component_desc = info_split_list[1]; - auto component_path = info_split_list[2]; - - boost::algorithm::trim(component_name); - boost::algorithm::trim(component_desc); - boost::algorithm::trim(component_path); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(component_path, "%3a", ":"); -#endif - - auto binary_checksum = check_binary_chacksum(component_path); - - SPDLOG_DEBUG( - "gnupg component name: {} desc: {} checksum: {} path: {} ", - component_name, component_desc, - binary_checksum.has_value() ? binary_checksum.value() : "/", - component_path); - - std::string version = "/"; - - if (component_name == "gpg") { - version = info_.GnupgVersion; - } - if (component_name == "gpg-agent") { - info_.GpgAgentPath = component_path; - } - if (component_name == "dirmngr") { - info_.DirmngrPath = component_path; - } - if (component_name == "keyboxd") { - info_.KeyboxdPath = component_path; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - // add component info to list - components_info[component_name] = { - component_desc, version, component_path, - binary_checksum.has_value() ? binary_checksum.value() : "/"}; - } - } - }); - - SPDLOG_DEBUG("start to get dirs info"); - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-dirs"}, - [=](int exit_code, const std::string &p_out, const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf configurations exit_code: {} process stdout size: {}", - exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {} process stdout: " - "{}", - p_err, p_out); - return; - } - - auto &configurations_info = info_.ConfigurationsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - SPDLOG_DEBUG("gpgconf info line: {} info size: {}", line, - info_split_list.size()); - - if (info_split_list.size() != 2) continue; - - auto configuration_name = info_split_list[0]; - auto configuration_value = info_split_list[1]; - boost::algorithm::trim(configuration_name); - boost::algorithm::trim(configuration_value); - -#ifdef WINDOWS - // replace some special substrings on windows platform - boost::replace_all(configuration_value, "%3a", ":"); -#endif - - // record gnupg home path - if (configuration_name == "homedir") { - info_.GnuPGHomePath = info_split_list[1]; - } - - { - // try lock - std::unique_lock lock(info_.Lock); - configurations_info[configuration_name] = {configuration_value}; - } - } - }); - - SPDLOG_DEBUG("start to get components info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf check options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--check-options", component.first}, - [=](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} options execute error, process " - "stderr: {} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &options_info = info_.OptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG("component {} options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 6) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5]}; - - boost::algorithm::trim(options_info[configuration_name][0]); - boost::algorithm::trim(options_info[configuration_name][1]); - boost::algorithm::trim(options_info[configuration_name][2]); - boost::algorithm::trim(options_info[configuration_name][3]); - boost::algorithm::trim(options_info[configuration_name][4]); - } - } - }); - } - - SPDLOG_DEBUG("start to get avaliable component options info"); - - for (const auto &component : info_.ComponentsInfo) { - SPDLOG_DEBUG("gpgconf list options ready", "component", component.first); - - if (component.first == "gpgme" || component.first == "gpgconf") continue; - - GpgCommandExecutor::GetInstance().ExecuteConcurrently( - info_.GpgConfPath, {"--list-options", component.first}, - [=](int exit_code, const std::string &p_out, - const std::string &p_err) { - SPDLOG_DEBUG( - "gpgconf {} avaliable options exit_code: {} process stdout " - "size: {} ", - component.first, exit_code, p_out.size()); - - if (exit_code != 0) { - SPDLOG_ERROR( - "gpgconf {} avaliable options execute error, process stderr: " - "{} , process stdout:", - component.first, p_err, p_out); - return; - } - - auto &available_options_info = info_.AvailableOptionsInfo; - - std::vector<std::string> line_split_list; - boost::split(line_split_list, p_out, boost::is_any_of("\n")); - - for (const auto &line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - - SPDLOG_DEBUG( - "component {} avaliable options line: {} info size: {}", - component.first, line, info_split_list.size()); - - if (info_split_list.size() != 10) continue; - - auto configuration_name = info_split_list[0]; - boost::algorithm::trim(configuration_name); - { - // try lock - std::unique_lock lock(info_.Lock); - available_options_info[configuration_name] = { - info_split_list[1], info_split_list[2], info_split_list[3], - info_split_list[4], info_split_list[5], info_split_list[6], - info_split_list[7], info_split_list[8], info_split_list[9]}; - - boost::algorithm::trim( - available_options_info[configuration_name][0]); - boost::algorithm::trim( - available_options_info[configuration_name][1]); - boost::algorithm::trim( - available_options_info[configuration_name][2]); - boost::algorithm::trim( - available_options_info[configuration_name][3]); - boost::algorithm::trim( - available_options_info[configuration_name][4]); - boost::algorithm::trim( - available_options_info[configuration_name][5]); - boost::algorithm::trim( - available_options_info[configuration_name][6]); - boost::algorithm::trim( - available_options_info[configuration_name][7]); - boost::algorithm::trim( - available_options_info[configuration_name][8]); - } - } - }); - } - extend_info_loaded_ = true; - } - - // ensure nothing is changing now - std::shared_lock lock(preload_lock_); - return info_; -} - -std::optional<std::string> GpgContext::check_binary_chacksum( - std::filesystem::path path) { - // check file info and access rights - QFileInfo info(QString::fromStdString(path.u8string())); - if (!info.exists() || !info.isFile() || !info.isReadable()) { - SPDLOG_ERROR("get info for file {} error, exists: {}", - info.filePath().toStdString(), info.exists()); - return {}; - } - - // open and read file - QFile f(info.filePath()); - if (!f.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("open {} to calculate check sum error: {}", path.u8string(), - f.errorString().toStdString()); - return {}; - } - - // read all data from file - auto buffer = f.readAll(); - f.close(); - - auto hash_sha = QCryptographicHash(QCryptographicHash::Sha256); - // md5 - hash_sha.addData(buffer); - auto sha = hash_sha.result().toHex().toStdString(); - SPDLOG_DEBUG("checksum for file {} is {}", path.u8string(), sha); - - return sha.substr(0, 6); -} - -void GpgContext::_ctx_ref_deleter::operator()(gpgme_ctx_t _ctx) { - if (_ctx != nullptr) gpgme_release(_ctx); -} - -} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/GpgContext.h b/src/core/GpgContext.h deleted file mode 100644 index 474530c6..00000000 --- a/src/core/GpgContext.h +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef __SGPGMEPP_CONTEXT_H__ -#define __SGPGMEPP_CONTEXT_H__ - -#include <optional> -#include <string> - -#include "GpgFunctionObject.h" -#include "GpgInfo.h" - -namespace GpgFrontend { - -/** - * @brief - * - */ -struct GpgContextInitArgs { - // make no sense for gpg2 - bool independent_database = false; ///< - std::string db_path = {}; - - bool gpg_alone = false; - std::string gpg_path = {}; - - bool test_mode = false; - bool ascii = true; - bool offline_mode = false; - bool auto_import_missing_key = false; - - bool custom_gpgconf = false; - std::string custom_gpgconf_path; - - bool use_pinentry = false; - - GpgContextInitArgs() = default; -}; - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgContext - : public QObject, - public SingletonFunctionObject<GpgContext> { - Q_OBJECT - public: - /** - * @brief Construct a new Gpg Context object - * - * @param args - */ - explicit GpgContext(const GpgContextInitArgs& args = {}); - - /** - * @brief Construct a new Gpg Context object - * - * @param channel - */ - explicit GpgContext(int channel); - - /** - * @brief Destroy the Gpg Context object - * - */ - ~GpgContext() override = default; - - /** - * @brief - * - * @return true - * @return false - */ - [[nodiscard]] bool good() const; - - /** - * @brief Get the Info object - * - * @return const GpgInfo& - */ - [[nodiscard]] const GpgInfo& GetInfo(bool refresh = false); - - /** - * @brief - * - * @return gpgme_ctx_t - */ - operator gpgme_ctx_t() const { return _ctx_ref.get(); } - - private: - GpgInfo info_{}; ///< - GpgContextInitArgs args_{}; ///< - bool extend_info_loaded_ = false; - std::shared_mutex preload_lock_{}; - - /** - * @brief - * - */ - void post_init_ctx(); - - /** - * @brief - * - * @return std::string - */ - std::string need_user_input_passphrase(); - - /** - * @brief Construct a new std::check component existence object - * - */ - std::optional<std::string> check_binary_chacksum(std::filesystem::path); - - /** - * @brief - * - */ - struct _ctx_ref_deleter { - void operator()(gpgme_ctx_t _ctx); - }; - - using CtxRefHandler = - std::unique_ptr<struct gpgme_context, _ctx_ref_deleter>; ///< - CtxRefHandler _ctx_ref = nullptr; ///< - bool good_ = true; ///< - - signals: - /** - * @brief - * - */ - void SignalNeedUserInputPassphrase(); - - public: - /** - * @brief - * - * @param opaque - * @param uid_hint - * @param passphrase_info - * @param last_was_bad - * @param fd - * @return gpgme_error_t - */ - static gpgme_error_t test_passphrase_cb(void* opaque, const char* uid_hint, - const char* passphrase_info, - int last_was_bad, int fd); - - /** - * @brief - * - * @param opaque - * @param uid_hint - * @param passphrase_info - * @param last_was_bad - * @param fd - * @return gpgme_error_t - */ - static gpgme_error_t custom_passphrase_cb(void* opaque, const char* uid_hint, - const char* passphrase_info, - int last_was_bad, int fd); - - /** - * @brief - * - * @param hook - * @param keyword - * @param args - * @return gpgme_error_t - */ - static gpgme_error_t test_status_cb(void* hook, const char* keyword, - const char* args); - - /** - * @brief Set the Passphrase Cb object - * - * @param func - */ - void SetPassphraseCb(gpgme_passphrase_cb_t func) const; -}; -} // namespace GpgFrontend - -#endif // __SGPGMEPP_CONTEXT_H__
\ No newline at end of file diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 6d782439..1790776e 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,236 +20,376 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgCoreInit.h" -#include <spdlog/async.h> -#include <spdlog/common.h> -#include <spdlog/sinks/rotating_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> +#include <gpgme.h> -#include <filesystem> -#include <string> - -#include "GpgFunctionObject.h" -#include "core/GpgContext.h" +#include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" -#include "function/gpg/GpgAdvancedOperator.h" -#include "spdlog/spdlog.h" -#include "thread/Task.h" -#include "thread/TaskRunner.h" -#include "thread/TaskRunnerGetter.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/function/gpg/GpgAdvancedOperator.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/module/ModuleManager.h" +#include "core/thread/Task.h" +#include "core/thread/TaskRunner.h" +#include "core/thread/TaskRunnerGetter.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/MemoryUtils.h" namespace GpgFrontend { -/** - * @brief setup logging system and do proper initialization - * - */ -void InitCoreLoggingSystem() { - using namespace boost::posix_time; - using namespace boost::gregorian; - - // get the log directory - auto logfile_path = - (GlobalSettingStation::GetInstance().GetLogDir() / "core"); - logfile_path.replace_extension(".log"); - - // sinks - std::vector<spdlog::sink_ptr> sinks; - sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); - sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( - logfile_path.u8string(), 1048576 * 32, 8)); - - // thread pool - spdlog::init_thread_pool(1024, 2); - - // logger - auto core_logger = std::make_shared<spdlog::async_logger>( - "core", begin(sinks), end(sinks), spdlog::thread_pool()); - core_logger->set_pattern( - "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); - -#ifdef DEBUG - core_logger->set_level(spdlog::level::trace); -#else - core_logger->set_level(spdlog::level::info); -#endif +void DestroyGpgFrontendCore() { SingletonStorageCollection::Destroy(); } + +auto VerifyGpgconfPath(const QFileInfo& gnupg_install_fs_path) -> bool { + return gnupg_install_fs_path.isAbsolute() && gnupg_install_fs_path.exists() && + gnupg_install_fs_path.isFile(); +} - // flush policy - core_logger->flush_on(spdlog::level::err); - spdlog::flush_every(std::chrono::seconds(5)); +auto VerifyKeyDatabasePath(const QFileInfo& key_database_fs_path) -> bool { + return key_database_fs_path.isAbsolute() && key_database_fs_path.exists() && + key_database_fs_path.isDir(); +} - // register it as default logger - spdlog::set_default_logger(core_logger); +auto SearchGpgconfPath(const QList<QString>& candidate_paths) -> QString { + for (const auto& path : candidate_paths) { + if (VerifyGpgconfPath(QFileInfo(path))) { + return path; + } + } + return {}; } -void ShutdownCoreLoggingSystem() { -#ifdef WINDOWS - // Under VisualStudio, this must be called before main finishes to workaround - // a known VS issue - spdlog::drop_all(); - spdlog::shutdown(); -#endif +auto SearchKeyDatabasePath(const QList<QString>& candidate_paths) -> QString { + for (const auto& path : candidate_paths) { + GF_CORE_LOG_DEBUG("searh for candidate key database path: {}", path); + if (VerifyKeyDatabasePath(QFileInfo(path))) { + return path; + } + } + return {}; } -void ResetGpgFrontendCore() { reset_gpgfrontend_core(); } +auto InitGpgME() -> bool { + // init gpgme subsystem and get gpgme library version + Module::UpsertRTValue("core", "gpgme.version", + QString(gpgme_check_version(nullptr))); -void init_gpgfrontend_core() { - /* Initialize the locale environment. */ - SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); - // init gpgme subsystem - gpgme_check_version(nullptr); gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); #ifdef LC_MESSAGES gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr)); #endif - // read settings - bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); - - bool auto_import_missing_key = - GlobalSettingStation::GetInstance().LookupSettings( - "network.auto_import_missing_key", false); - - bool use_custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_key_database_path", false); + gpgme_ctx_t p_ctx; + + CheckGpgError(gpgme_new(&p_ctx)); + + // get engine info + auto* engine_info = gpgme_ctx_get_engine_info(p_ctx); + // Check ENV before running + bool find_openpgp = false; + bool find_gpgconf = false; + bool find_cms = false; + + while (engine_info != nullptr) { + if (strcmp(engine_info->version, "1.0.0") == 0) { + engine_info = engine_info->next; + continue; + } + + GF_CORE_LOG_DEBUG( + "gpg context engine info: {} {} {} {}", + gpgme_get_protocol_name(engine_info->protocol), + QString(engine_info->file_name == nullptr ? "null" + : engine_info->file_name), + QString(engine_info->home_dir == nullptr ? "null" + : engine_info->home_dir), + QString(engine_info->version ? "null" : engine_info->version)); + + switch (engine_info->protocol) { + case GPGME_PROTOCOL_OpenPGP: + find_openpgp = true; + + Module::UpsertRTValue("core", "gpgme.engine.openpgp", 1); + Module::UpsertRTValue("core", "gpgme.ctx.app_path", + QString(engine_info->file_name)); + Module::UpsertRTValue("core", "gpgme.ctx.gnupg_version", + QString(engine_info->version)); + Module::UpsertRTValue( + "core", "gpgme.ctx.database_path", + QString(engine_info->home_dir == nullptr ? "default" + : engine_info->home_dir)); + break; + case GPGME_PROTOCOL_CMS: + find_cms = true; + Module::UpsertRTValue("core", "gpgme.engine.cms", 1); + Module::UpsertRTValue("core", "gpgme.ctx.cms_path", + QString(engine_info->file_name)); + + break; + case GPGME_PROTOCOL_GPGCONF: + find_gpgconf = true; + + Module::UpsertRTValue("core", "gpgme.engine.gpgconf", 1); + Module::UpsertRTValue("core", "gpgme.ctx.gpgconf_path", + QString(engine_info->file_name)); + break; + case GPGME_PROTOCOL_ASSUAN: + + Module::UpsertRTValue("core", "gpgme.engine.assuan", 1); + Module::UpsertRTValue("core", "gpgme.ctx.assuan_path", + QString(engine_info->file_name)); + break; + case GPGME_PROTOCOL_G13: + break; + case GPGME_PROTOCOL_UISERVER: + break; + case GPGME_PROTOCOL_SPAWN: + break; + case GPGME_PROTOCOL_DEFAULT: + break; + case GPGME_PROTOCOL_UNKNOWN: + break; + } + engine_info = engine_info->next; + } - std::string custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_key_database_path", std::string{}); + // release gpgme context + gpgme_release(p_ctx); - bool use_custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_gnupg_install_path", false); + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"0.0.0"}); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); - std::string custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_gnupg_install_path", std::string{}); + // conditional check: only support gpg 2.1.x now + if (!(CompareSoftwareVersion(gnupg_version, "2.1.0") >= 0 && find_gpgconf && + find_openpgp && find_cms)) { + GF_CORE_LOG_ERROR("gpgme env check failed, abort"); + return false; + } - bool use_pinentry_as_password_input_dialog = - GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( - "general.use_pinentry_as_password_input_dialog", false); + Module::UpsertRTValue("core", "env.state.gpgme", 1); + return true; +} - SPDLOG_DEBUG("core loaded if use custom key databse path: {}", - use_custom_key_database_path); - SPDLOG_DEBUG("core loaded custom key databse path: {}", - custom_key_database_path); +void InitGpgFrontendCore(CoreInitArgs args) { + // initialize global register table + Module::UpsertRTValue("core", "env.state.gpgme", 0); + Module::UpsertRTValue("core", "env.state.ctx", 0); + Module::UpsertRTValue("core", "env.state.gnupg", 0); + Module::UpsertRTValue("core", "env.state.basic", 0); + Module::UpsertRTValue("core", "env.state.all", 0); + + // initialize locale environment + GF_CORE_LOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); + + // initialize library gpgme + if (!InitGpgME()) { + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("GpgME inilization failed")); + return; + } - // check gpgconf path - std::filesystem::path custom_gnupg_install_fs_path = - custom_gnupg_install_path; + auto* task = new Thread::Task( + [args](const DataObjectPtr&) -> int { + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + // read settings from config file + auto forbid_all_gnupg_connection = + settings.value("network/forbid_all_gnupg_connection", false) + .toBool(); + + auto auto_import_missing_key = + settings.value("network/auto_import_missing_key", false).toBool(); + + auto use_custom_key_database_path = + settings.value("basic/use_custom_key_database_path", false) + .toBool(); + + auto custom_key_database_path = + settings.value("basic/custom_key_database_path", QString{}) + .toString(); + + auto use_custom_gnupg_install_path = + settings.value("basic/use_custom_gnupg_install_path", false) + .toBool(); + + auto custom_gnupg_install_path = + settings.value("basic/custom_gnupg_install_path", QString{}) + .toString(); + + auto use_pinentry_as_password_input_dialog = + settings.value("basic/use_pinentry_as_password_input_dialog", false) + .toBool(); + + GF_CORE_LOG_DEBUG("core loaded if use custom key databse path: {}", + use_custom_key_database_path); + GF_CORE_LOG_DEBUG("core loaded custom key databse path: {}", + custom_key_database_path); + + QString gnupg_install_fs_path; + // user defined + if (use_custom_gnupg_install_path && + !custom_gnupg_install_path.isEmpty()) { + // check gpgconf path + gnupg_install_fs_path = custom_gnupg_install_path; #ifdef WINDOWS - custom_gnupg_install_fs_path /= "gpgconf.exe"; + gnupg_install_fs_path += "/gpgconf.exe"; #else - custom_gnupg_install_fs_path /= "gpgconf"; + gnupg_install_fs_path += "/gpgconf"; #endif - if (!custom_gnupg_install_fs_path.is_absolute() || - !std::filesystem::exists(custom_gnupg_install_fs_path) || - !std::filesystem::is_regular_file(custom_gnupg_install_fs_path)) { - use_custom_gnupg_install_path = false; - SPDLOG_ERROR("core loaded custom gpgconf path is illegal: {}", - custom_gnupg_install_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpgconf path: {}", - custom_gnupg_install_fs_path.u8string()); - } - - // check key database path - std::filesystem::path custom_key_database_fs_path = custom_key_database_path; - if (!custom_key_database_fs_path.is_absolute() || - !std::filesystem::exists(custom_key_database_fs_path) || - !std::filesystem::is_directory(custom_key_database_fs_path)) { - use_custom_key_database_path = false; - SPDLOG_ERROR("core loaded custom gpg key database is illegal: {}", - custom_key_database_fs_path.u8string()); - } else { - SPDLOG_DEBUG("core loaded custom gpg key database path: {}", - custom_key_database_fs_path.u8string()); - } + if (!VerifyGpgconfPath(QFileInfo(gnupg_install_fs_path))) { + use_custom_gnupg_install_path = false; + GF_CORE_LOG_ERROR("core loaded custom gpgconf path is illegal: {}", + gnupg_install_fs_path); + } else { + GF_CORE_LOG_DEBUG("core loaded custom gpgconf path: {}", + gnupg_install_fs_path); + } + } else { +#ifdef MACOS + use_custom_gnupg_install_path = true; + gnupg_install_fs_path = SearchGpgconfPath( + {"/usr/local/bin/gpgconf", "/opt/homebrew/bin/gpgconf"}); + GF_CORE_LOG_DEBUG("core loaded searched gpgconf path: {}", + gnupg_install_fs_path); +#endif + } - // init default channel - auto& default_ctx = GpgFrontend::GpgContext::CreateInstance( - GPGFRONTEND_DEFAULT_CHANNEL, [=]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; + // check key database path + QString key_database_fs_path; + // user defined + if (use_custom_key_database_path && + !custom_key_database_path.isEmpty()) { + key_database_fs_path = custom_key_database_path; + if (VerifyKeyDatabasePath(QFileInfo(key_database_fs_path))) { + GF_CORE_LOG_ERROR( + "core loaded custom gpg key database is illegal: {}", + key_database_fs_path); + } else { + use_custom_key_database_path = true; + GF_CORE_LOG_DEBUG("core loaded custom gpg key database path: {}", + key_database_fs_path); + } + } else { +#ifdef MACOS + use_custom_key_database_path = true; + key_database_fs_path = + SearchKeyDatabasePath({QDir::home().path() + "/.gnupg"}); + GF_CORE_LOG_DEBUG("core loaded searched key database path: {}", + key_database_fs_path); +#endif + } - // set key database path - if (use_custom_key_database_path && !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; + if (args.load_default_gpg_context) { + // init ctx, also checking the basical env + auto& ctx = GpgFrontend::GpgContext::CreateInstance( + kGpgFrontendDefaultChannel, [=]() -> ChannelObjectPtr { + GpgFrontend::GpgContextInitArgs args; + + // set key database path + if (use_custom_key_database_path && + !key_database_fs_path.isEmpty()) { + args.db_path = key_database_fs_path; + } + + // set custom gnupg path + if (use_custom_gnupg_install_path) { + args.custom_gpgconf = true; + args.custom_gpgconf_path = gnupg_install_fs_path; + } + + args.offline_mode = forbid_all_gnupg_connection; + args.auto_import_missing_key = auto_import_missing_key; + args.use_pinentry = use_pinentry_as_password_input_dialog; + + return ConvertToChannelObjectPtr<>( + SecureCreateUniqueObject<GpgContext>( + args, kGpgFrontendDefaultChannel)); + }); + + // exit if failed + if (!ctx.Good()) { + GF_CORE_LOG_ERROR("default gnupg context init error, abort"); + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("GpgME Context inilization failed")); + return -1; + } + Module::UpsertRTValue("core", "env.state.ctx", 1); } - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = custom_gnupg_install_fs_path.u8string(); + if (args.load_default_gpg_context) { + if (!GpgKeyGetter::GetInstance().FlushKeyCache()) { + CoreSignalStation::GetInstance()->SignalBadGnupgEnv( + QObject::tr("Gpg Key Detabase inilization failed")); + }; + } + GF_CORE_LOG_INFO( + "basic env checking finished, " + "including gpgme, ctx, and key infos"); + Module::UpsertRTValue("core", "env.state.basic", 1); + CoreSignalStation::GetInstance()->SignalGoodGnupgEnv(); + + // if gnupg-info-gathering module activated + if (args.gather_external_gnupg_info && + Module::IsModuleAcivate("com.bktus.gpgfrontend.module." + "integrated.gnupg-info-gathering")) { + GF_CORE_LOG_DEBUG( + "module gnupg-info-gathering is activated, " + "loading external gnupg info..."); + + // gather external gnupg info + Module::TriggerEvent( + "GPGFRONTEND_CORE_INITLIZED", + [](const Module::EventIdentifier& /*e*/, + const Module::Event::ListenerIdentifier& l_id, + DataObjectPtr o) { + GF_CORE_LOG_DEBUG( + "received event GPGFRONTEND_CORE_INITLIZED callback " + "from module: {}", + l_id); + + if (l_id == + "com.bktus.gpgfrontend.module.integrated.gnupg-info-" + "gathering") { + GF_CORE_LOG_DEBUG( + "received callback from gnupg-info-gathering "); + + // try to restart all components + GpgFrontend::GpgAdvancedOperator::RestartGpgComponents(); + Module::UpsertRTValue("core", "env.state.gnupg", 1); + + // announce that all checkings were finished + GF_CORE_LOG_INFO( + "all env checking finished, including gpgme, " + "ctx and gnupg"); + Module::UpsertRTValue("core", "env.state.all", 1); + } + }); + } else { + GF_CORE_LOG_DEBUG("gnupg-info-gathering is not activated"); + Module::UpsertRTValue("core", "env.state.all", 1); } + return 0; + }, + "core_init_task"); - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); - - // exit if failed - if (!default_ctx.good()) { - SPDLOG_ERROR("default gnupg context init error"); - }; - - // async init no-ascii channel - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) - ->PostTask( - new Thread::Task([=](Thread::Task::DataObjectPtr data_obj) -> int { - // init non-ascii channel - auto& ctx = GpgFrontend::GpgContext::CreateInstance( - GPGFRONTEND_NON_ASCII_CHANNEL, - [=]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; - args.ascii = false; - - // set key database path - if (use_custom_key_database_path && - !custom_key_database_path.empty()) { - args.db_path = custom_key_database_path; - } - - if (use_custom_gnupg_install_path) { - args.custom_gpgconf = true; - args.custom_gpgconf_path = - custom_gnupg_install_fs_path.u8string(); - } - - args.offline_mode = forbid_all_gnupg_connection; - args.auto_import_missing_key = auto_import_missing_key; - args.use_pinentry = use_pinentry_as_password_input_dialog; - - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); - - if (!ctx.good()) SPDLOG_ERROR("no-ascii channel init error"); - return ctx.good() ? 0 : -1; - })); - - // try to restart all components - GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); -} + QObject::connect(task, &Thread::Task::SignalTaskEnd, []() { -void reset_gpgfrontend_core() { SingletonStorageCollection::GetInstance(true); } + }); -void new_default_settings_channel(int channel) { - GpgFrontend::GpgContext::CreateInstance( - channel, [&]() -> std::unique_ptr<ChannelObject> { - GpgFrontend::GpgContextInitArgs args; - return std::unique_ptr<ChannelObject>(new GpgContext(args)); - }); + // start the thread to check ctx and gnupg state + // it may take a few seconds or minutes + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(task); } } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h index 41e04d60..15f0254d 100644 --- a/src/core/GpgCoreInit.h +++ b/src/core/GpgCoreInit.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,57 +20,33 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGCOREINIT_H -#define GPGFRONTEND_GPGCOREINIT_H +#pragma once #include "GpgConstants.h" namespace GpgFrontend { -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT InitCoreLoggingSystem(); - -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT ShutdownCoreLoggingSystem(); - -/** - * @brief - * - */ -void GPGFRONTEND_CORE_EXPORT ResetGpgFrontendCore(); - -/** - * @brief - * - */ -void init_gpgfrontend_core(); +struct CoreInitArgs { + bool gather_external_gnupg_info; + bool load_default_gpg_context; +}; /** * @brief * */ -void reset_gpgfrontend_core(); +void GPGFRONTEND_CORE_EXPORT DestroyGpgFrontendCore(); /** * @brief * - * @param channel */ -void new_default_settings_channel( - int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL); +void GPGFRONTEND_CORE_EXPORT InitGpgFrontendCore(CoreInitArgs); } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGCOREINIT_H diff --git a/src/core/GpgFrontendCore.cpp b/src/core/GpgFrontendCore.cpp new file mode 100644 index 00000000..2508f4e7 --- /dev/null +++ b/src/core/GpgFrontendCore.cpp @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "core/GpgFrontendCore.h" + +#ifndef MACOS +// mimalloc +#include <mimalloc-new-delete.h> +#endif diff --git a/src/core/GpgFrontendCore.h b/src/core/GpgFrontendCore.h index 0b433b96..14b1f878 100644 --- a/src/core/GpgFrontendCore.h +++ b/src/core/GpgFrontendCore.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,56 +20,33 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGFRONTENDCORE_H -#define GPGFRONTEND_GPGFRONTENDCORE_H +#pragma once -#include "GpgFrontend.h" - -// gnupg -#include <gpgme.h> +// Qt +#include <QtCore> -// std includes -#include <cassert> -#include <filesystem> -#include <functional> -#include <map> -#include <memory> -#include <mutex> -#include <random> -#include <shared_mutex> -#include <stdexcept> -#include <string> -#include <typeinfo> -#include <utility> +// std +#include <cstdint> #include <vector> -// boost includes -#include <boost/date_time.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <boost/filesystem/operations.hpp> -#include <boost/filesystem/path.hpp> -#include <boost/format.hpp> +// spdlog library configuration +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE +#include <spdlog/spdlog.h> -// Qt includes -#include <QtCore> +// logger fmt +#include "log/QtLoggerFmt.h" -// libconfig includes -#include <libconfig.h++> - -// libarchive includes -#include <libarchive/libarchive/archive.h> -#include <libarchive/libarchive/archive_entry.h> +// gpgme library +#include <gpgme.h> -// json includes -#include <nlohmann/json.hpp> +// logbal includes or macroes +#include "GpgFrontend.h" -// dll export macro +// dll export macroes #include "GpgFrontendCoreExport.h" - -#endif // GPGFRONTEND_GPGFRONTENDCORE_H diff --git a/src/core/GpgFunctionObject.cpp b/src/core/GpgFunctionObject.cpp deleted file mode 100644 index 0ddc290c..00000000 --- a/src/core/GpgFunctionObject.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "core/GpgFunctionObject.h" - -#include <cassert> -#include <functional> -#include <memory> -#include <mutex> -#include <shared_mutex> - -void GpgFrontend::ChannelObject::SetChannel(int channel) { - this->channel_ = channel; -} - -int GpgFrontend::ChannelObject::GetChannel() const { return channel_; } - -int GpgFrontend::ChannelObject::GetDefaultChannel() { return _default_channel; } - -void GpgFrontend::SingletonStorage::ReleaseChannel(int channel) { - decltype(instances_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(instances_mutex_); - _it = instances_map_.find(channel); - } - if (_it != instances_map_.end()) instances_map_.erase(_it); -} - -GpgFrontend::ChannelObject* GpgFrontend::SingletonStorage::FindObjectInChannel( - int channel) { - // read instances_map_ - decltype(instances_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(instances_mutex_); - _it = instances_map_.find(channel); - if (_it == instances_map_.end()) { - return nullptr; - } else { - return _it->second.get(); - } - } -} - -std::vector<int> GpgFrontend::SingletonStorage::GetAllChannelId() { - std::vector<int> _channels; - for (const auto& [key, value] : instances_map_) { - _channels.push_back(key); - } - return _channels; -} - -GpgFrontend::ChannelObject* GpgFrontend::SingletonStorage::SetObjectInChannel( - int channel, std::unique_ptr<ChannelObject> p_obj) { - { - SPDLOG_TRACE("set channel: {} instance address: {}", channel, - static_cast<void*>(&instances_map_)); - - assert(p_obj != nullptr); - if (p_obj == nullptr) return nullptr; - - auto raw_obj = p_obj.get(); - p_obj->SetChannel(channel); - { - std::unique_lock<std::shared_mutex> lock(instances_mutex_); - instances_map_.insert({channel, std::move(p_obj)}); - } - return raw_obj; - } -} - -GpgFrontend::SingletonStorage* -GpgFrontend::SingletonStorageCollection::GetSingletonStorage( - const std::type_info& type_id) { - const auto hash = type_id.hash_code(); - - while (true) { - decltype(storages_map_.end()) _it; - { - std::shared_lock<std::shared_mutex> lock(storages_mutex_); - _it = storages_map_.find(hash); - } - if (_it == storages_map_.end()) { - { - std::unique_lock<std::shared_mutex> lock(storages_mutex_); - storages_map_.insert({hash, std::make_unique<SingletonStorage>()}); - } - SPDLOG_TRACE("hash: {} created, storage address: {} type_name: {}", hash, - static_cast<void*>(&storages_map_), type_id.name()); - continue; - } else { - return _it->second.get(); - } - } -} - -GpgFrontend::SingletonStorageCollection* -GpgFrontend::SingletonStorageCollection::GetInstance( - bool force_refresh = false) { - static SingletonStorageCollection* instance = nullptr; - - if (force_refresh || instance == nullptr) { - instance = new SingletonStorageCollection(); - SPDLOG_DEBUG("new single storage collection created: {}", - static_cast<void*>(instance)); - } - - return instance; -} - -GpgFrontend::ChannelObject::ChannelObject() noexcept = default; - -GpgFrontend::ChannelObject::ChannelObject(int channel) : channel_(channel) {} diff --git a/src/core/GpgFunctionObject.h b/src/core/GpgFunctionObject.h deleted file mode 100644 index 9b8c2aa3..00000000 --- a/src/core/GpgFunctionObject.h +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H -#define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H - -#include <mutex> - -#include "GpgConstants.h" - -namespace GpgFrontend { - -/** - * @brief object which in channel system - * - */ -class GPGFRONTEND_CORE_EXPORT ChannelObject { - public: - /** - * @brief Construct a new Default Channel Object object - * - */ - ChannelObject() noexcept; - - /** - * @brief Construct a new Channel Object object - * - * @param channel - */ - ChannelObject(int channel); - - /** - * @brief Get the Default Channel object - * - * @return int - */ - static int GetDefaultChannel(); - - /** - * @brief Get the Channel object - * - * @return int - */ - [[nodiscard]] int GetChannel() const; - - /** - * @brief Set the Channel object - * - * @param channel - */ - void SetChannel(int channel); - - private: - int channel_ = _default_channel; ///< The channel id - static constexpr int _default_channel = 0; ///< The default channel id -}; - -class GPGFRONTEND_CORE_EXPORT SingletonStorage { - public: - /** - * @brief - * - * @param channel - */ - void ReleaseChannel(int channel); - - /** - * @brief - * - * @param channel - * @return T* - */ - ChannelObject* FindObjectInChannel(int channel); - - /** - * @brief Get all the channel ids - * - * @return std::vector<int> - */ - std::vector<int> GetAllChannelId(); - - /** - * @brief Set a new object in channel object - * - * @param channel - * @param p_obj - * @return T* - */ - ChannelObject* SetObjectInChannel(int channel, - std::unique_ptr<ChannelObject> p_obj); - - private: - std::shared_mutex instances_mutex_; ///< mutex for _instances_map - std::map<int, std::unique_ptr<ChannelObject>> - instances_map_; ///< map of singleton instances -}; - -class GPGFRONTEND_CORE_EXPORT SingletonStorageCollection { - public: - /** - * @brief Get the Instance object - * - * @return SingletonStorageCollection* - */ - static SingletonStorageCollection* GetInstance(bool force_refresh); - - /** - * @brief Get the Singleton Storage object - * - * @param singleton_function_object - * @return SingletonStorage* - */ - SingletonStorage* GetSingletonStorage(const std::type_info&); - - private: - std::shared_mutex storages_mutex_; ///< mutex for storages_map_ - std::map<size_t, std::unique_ptr<SingletonStorage>> storages_map_; -}; -/** - * @brief - * - * @tparam T - */ -template <typename T> -class SingletonFunctionObject : public ChannelObject { - public: - /** - * @brief prohibit copy - * - */ - SingletonFunctionObject(const SingletonFunctionObject<T>&) = delete; - - /** - * @brief prohibit copy - * - * @return SingletonFunctionObject& - */ - SingletonFunctionObject& operator=(const SingletonFunctionObject<T>&) = - delete; - - /** - * @brief Get the Instance object - * - * @param channel - * @return T& - */ - static T& GetInstance( - int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL) { - static std::mutex g_channel_mutex_map_lock; - static std::map<int, std::mutex> g_channel_mutex_map; - - { - std::lock_guard<std::mutex> guard(g_channel_mutex_map_lock); - if (g_channel_mutex_map.find(channel) == g_channel_mutex_map.end()) { - g_channel_mutex_map[channel]; - } - } - - static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value, - "T not derived from SingletonFunctionObject<T>"); - - auto* p_storage = - SingletonStorageCollection::GetInstance(false)->GetSingletonStorage( - typeid(T)); - auto* _p_pbj = (T*)(p_storage->FindObjectInChannel(channel)); - - if (_p_pbj == nullptr) { - // lock this channel - std::lock_guard<std::mutex> guard(g_channel_mutex_map[channel]); - - // double check - if ((_p_pbj = (T*)(p_storage->FindObjectInChannel(channel))) != nullptr) - return *_p_pbj; - - // do create object of this channel - auto new_obj = std::unique_ptr<ChannelObject>(new T(channel)); - return *(T*)(p_storage->SetObjectInChannel(channel, std::move(new_obj))); - } else { - return *_p_pbj; - } - } - - /** - * @brief Create a Instance object - * - * @param channel - * @param factory - * @return T& - */ - static T& CreateInstance( - int channel, - std::function<std::unique_ptr<ChannelObject>(void)> factory) { - static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value, - "T not derived from SingletonFunctionObject<T>"); - - auto p_storage = - SingletonStorageCollection::GetInstance(false)->GetSingletonStorage( - typeid(T)); - - auto _p_pbj = (T*)(p_storage->FindObjectInChannel(channel)); - - if (_p_pbj == nullptr) { - return *( - T*)(p_storage->SetObjectInChannel(channel, std::move(factory()))); - } else - return *_p_pbj; - } - - /** - * @brief - * - * @param channel - * @return T& - */ - static void ReleaseChannel(int channel) { - SingletonStorageCollection::GetInstance(false) - ->GetSingletonStorage(typeid(T)) - ->ReleaseChannel(channel); - } - - /** - * @brief Get the Default Channel object - * - * @return int - */ - static int GetDefaultChannel() { return ChannelObject::GetDefaultChannel(); } - - /** - * @brief Get the Channel object - * - * @return int - */ - [[nodiscard]] int GetChannel() const { return ChannelObject::GetChannel(); } - - /** - * @brief Get all the channel ids - * - * @return std::vector<int> - */ - static std::vector<int> GetAllChannelId() { - return SingletonStorageCollection::GetInstance(false) - ->GetSingletonStorage(typeid(T)) - ->GetAllChannelId(); - } - - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject(T&&) = delete; - - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject(const T&) = delete; - - /** - * @brief - * - */ - void operator=(const T&) = delete; - - protected: - /** - * @brief Construct a new Singleton Function Object object - * - */ - SingletonFunctionObject() = default; - - /** - * @brief Construct a new Singleton Function Object object - * - * @param channel - */ - explicit SingletonFunctionObject(int channel) : ChannelObject(channel) {} - - /** - * @brief Destroy the Singleton Function Object object - * - */ - virtual ~SingletonFunctionObject() = default; -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H diff --git a/src/core/GpgGenKeyInfo.cpp b/src/core/GpgGenKeyInfo.cpp deleted file mode 100644 index 290c93c2..00000000 --- a/src/core/GpgGenKeyInfo.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "core/GpgGenKeyInfo.h" - -#include <algorithm> -#include <boost/date_time/gregorian/greg_date.hpp> -#include <boost/date_time/gregorian/greg_duration.hpp> -#include <boost/date_time/gregorian/gregorian_types.hpp> -#include <cassert> -#include <string> -#include <vector> - -void GpgFrontend::GenKeyInfo::SetAlgo( - const GpgFrontend::GenKeyInfo::KeyGenAlgo &m_algo) { - SPDLOG_DEBUG("set algo name: {}", m_algo.first); - // Check algo if supported - std::string algo_args = m_algo.second; - if (standalone_) { - if (!subkey_) { - auto support_algo = GetSupportedKeyAlgoStandalone(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } else { - auto support_algo = GetSupportedSubkeyAlgoStandalone(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } - } else { - if (!subkey_) { - auto support_algo = GetSupportedKeyAlgo(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } else { - auto support_algo = GetSupportedSubkeyAlgo(); - auto it = std::find_if( - support_algo.begin(), support_algo.end(), - [=](const KeyGenAlgo &o) { return o.second == algo_args; }); - // Algo Not Supported - if (it == support_algo.end()) return; - } - } - - // reset all options - reset_options(); - - if (!this->subkey_) { - this->SetAllowCertification(true); - } else { - this->SetAllowCertification(false); - } - - this->allow_change_certification_ = false; - - if (!standalone_) boost::algorithm::to_lower(algo_args); - - if (algo_args == "rsa") { - /** - * RSA is the world’s premier asymmetric cryptographic algorithm, - * and is built on the difficulty of factoring extremely large composites. - * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. - */ - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 4096; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - - } else if (algo_args == "dsa") { - /** - * Algorithm (DSA) as a government standard for digital signatures. - * Originally, it supported key lengths between 512 and 1024 bits. - * Recently, NIST has declared 512-bit keys obsolete: - * now, DSA is available in 1024, 2048 and 3072-bit lengths. - */ - SetAllowEncryption(false); - allow_change_encryption_ = false; - - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 3072; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - - } else if (algo_args == "ed25519") { - /** - * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths - * ranging from 1024 to 4096 bits. - */ - SetAllowEncryption(false); - allow_change_encryption_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } else if (algo_args == "cv25519") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = 1024; - suggest_max_key_size_ = 4096; - suggest_size_addition_step_ = 1024; - SetKeyLength(2048); - } else if (algo_args == "nistp256" || algo_args == "nistp384" || - algo_args == "nistp521") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } else if (algo_args == "brainpoolp256r1") { - SetAllowAuthentication(false); - allow_change_authentication_ = false; - - SetAllowSigning(false); - allow_change_signing_ = false; - - SetAllowCertification(false); - allow_change_certification_ = false; - - suggest_min_key_size_ = -1; - suggest_max_key_size_ = -1; - suggest_size_addition_step_ = -1; - SetKeyLength(-1); - } - - this->algo_ = algo_args; -} - -void GpgFrontend::GenKeyInfo::reset_options() { - allow_change_encryption_ = true; - SetAllowEncryption(true); - - allow_change_certification_ = true; - SetAllowCertification(true); - - allow_change_signing_ = true; - SetAllowSigning(true); - - allow_change_authentication_ = true; - SetAllowAuthentication(true); - - passphrase_.clear(); -} - -std::string GpgFrontend::GenKeyInfo::GetKeySizeStr() const { - if (key_size_ > 0) { - return std::to_string(key_size_); - } else { - return {}; - } -} - -void GpgFrontend::GenKeyInfo::SetKeyLength(int m_key_size) { - if (m_key_size < suggest_min_key_size_ || - m_key_size > suggest_max_key_size_) { - return; - } - GenKeyInfo::key_size_ = m_key_size; -} - -void GpgFrontend::GenKeyInfo::SetExpireTime( - const boost::posix_time::ptime &m_expired) { - using namespace boost::gregorian; - if (!IsNonExpired()) { - GenKeyInfo::expired_ = m_expired; - } -} - -void GpgFrontend::GenKeyInfo::SetNonExpired(bool m_non_expired) { - using namespace boost::posix_time; - if (!m_non_expired) this->expired_ = from_time_t(0); - GenKeyInfo::non_expired_ = m_non_expired; -} - -void GpgFrontend::GenKeyInfo::SetAllowEncryption(bool m_allow_encryption) { - if (allow_change_encryption_) - GenKeyInfo::allow_encryption_ = m_allow_encryption; -} - -void GpgFrontend::GenKeyInfo::SetAllowCertification( - bool m_allow_certification) { - if (allow_change_certification_) - GenKeyInfo::allow_certification_ = m_allow_certification; -} - -GpgFrontend::GenKeyInfo::GenKeyInfo(bool m_is_sub_key, bool m_standalone) - : standalone_(m_standalone), subkey_(m_is_sub_key) { - assert(GetSupportedKeyAlgo().size() > 0); - SetAlgo(GetSupportedKeyAlgo()[0]); -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedKeyAlgo() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_key_algo = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - {"ECDSA", "ED25519"}, - }; - return support_key_algo; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedSubkeyAlgo() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - {"ECDSA", "ED25519"}, - {"ECDH NIST P-256", "NISTP256"}, - {"ECDH NIST P-384", "NISTP384"}, - {"ECDH NIST P-521", "NISTP521"}, - // {"ECDH BrainPool P-256", "BRAINPOOlP256R1"} - }; - return support_subkey_algo; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedKeyAlgoStandalone() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo_standalone = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - }; - return support_subkey_algo_standalone; -} - -const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - &GpgFrontend::GenKeyInfo::GetSupportedSubkeyAlgoStandalone() { - static const std::vector<GpgFrontend::GenKeyInfo::KeyGenAlgo> - support_subkey_algo_standalone = { - {"RSA", "RSA"}, - {"DSA", "DSA"}, - }; - return support_subkey_algo_standalone; -} diff --git a/src/core/GpgInfo.h b/src/core/GpgInfo.h deleted file mode 100644 index f4415af1..00000000 --- a/src/core/GpgInfo.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef GPGFRONTEND_ZH_CN_TS_GPGINFO_H -#define GPGFRONTEND_ZH_CN_TS_GPGINFO_H - -#include <mutex> -#include <string> - -namespace GpgFrontend { -/** - * @brief Use to record some info about gnupg - * - */ -class GpgInfo { - public: - std::string GnupgVersion; ///< version of gnupg - std::string GpgMEVersion; ///< - - std::string AppPath; ///< executable binary path of gnupg - std::string DatabasePath; ///< key database path - std::string GpgConfPath; ///< executable binary path of gpgconf - std::string AssuanPath; ///< executable binary path of assuan - std::string CMSPath; ///< executable binary path of cms - std::string GpgAgentPath; ///< executable binary path of gpg-agent - std::string DirmngrPath; ///< executable binary path of dirmgr - std::string KeyboxdPath; ///< executable binary path of keyboxd - - std::string GnuPGHomePath; ///< value of ---homedir - - std::map<std::string, std::vector<std::string>> ComponentsInfo; ///< - std::map<std::string, std::vector<std::string>> ConfigurationsInfo; ///< - std::map<std::string, std::vector<std::string>> OptionsInfo; ///< - std::map<std::string, std::vector<std::string>> AvailableOptionsInfo; ///< - - std::shared_mutex Lock; -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGINFO_H diff --git a/src/core/GpgModel.h b/src/core/GpgModel.h index d8d4e6fe..72574988 100644 --- a/src/core/GpgModel.h +++ b/src/core/GpgModel.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,38 +20,20 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGMODEL_H -#define GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +#pragma once -#include "core/GpgConstants.h" +// +#include "core/typedef/GpgTypedef.h" + +// #include "core/model/GpgData.h" #include "core/model/GpgKey.h" #include "core/model/GpgSignature.h" -namespace GpgFrontend { - -using KeyId = std::string; ///< -using SubkeyId = std::string; ///< -using KeyIdArgsList = std::vector<KeyId>; ///< -using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>; ///< -using UIDArgsList = std::vector<std::string>; ///< -using UIDArgsListPtr = std::unique_ptr<UIDArgsList>; ///< -using SignIdArgsList = std::vector<std::pair<std::string, std::string>>; ///< -using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>; ///< -using KeyFprArgsListPtr = std::unique_ptr<std::vector<std::string>>; ///< -using KeyArgsList = std::vector<GpgKey>; ///< -using KeyListPtr = std::unique_ptr<KeyArgsList>; ///< -using GpgKeyLinkList = std::list<GpgFrontend::GpgKey>; ///< -using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>; ///< -using KeyPtr = std::unique_ptr<GpgKey>; ///< -using KeyPtrArgsList = const std::initializer_list<KeyPtr>; ///< - -} // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H +// namespace GpgFrontend diff --git a/src/core/common/CoreCommonUtil.cpp b/src/core/common/CoreCommonUtil.cpp deleted file mode 100644 index 93cad60a..00000000 --- a/src/core/common/CoreCommonUtil.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/**
- * Copyright (C) 2021 Saturneric
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend 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 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "CoreCommonUtil.h"
-
-#include <string>
-
-namespace GpgFrontend {
-
-std::unique_ptr<CoreCommonUtil> CoreCommonUtil::instance_ = nullptr; ///<
-
-CoreCommonUtil* CoreCommonUtil::GetInstance() {
- if (instance_ == nullptr) {
- instance_ = std::make_unique<CoreCommonUtil>();
- }
- return instance_.get();
-}
-
-void CoreCommonUtil::SetTempCacheValue(const std::string& key,
- const std::string& value) {
- temp_cache_[key] = value;
-}
-
-std::string CoreCommonUtil::GetTempCacheValue(const std::string& key) {
- std::string temp_cache_value;
- std::swap(temp_cache_value, temp_cache_[key]);
- return temp_cache_value;
-}
-
-void CoreCommonUtil::ResetTempCacheValue(const std::string& key) {
- std::string temp_cache_value;
- std::swap(temp_cache_value, temp_cache_[key]);
-}
-
-} // namespace GpgFrontend
diff --git a/src/core/common/CoreCommonUtil.h b/src/core/common/CoreCommonUtil.h deleted file mode 100644 index 58bb4d40..00000000 --- a/src/core/common/CoreCommonUtil.h +++ /dev/null @@ -1,87 +0,0 @@ -/**
- * Copyright (C) 2021 Saturneric
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend 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 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_CORECOMMONUTIL_H
-#define GPGFRONTEND_CORECOMMONUTIL_H
-
-#include <string>
-
-#include "core/GpgFrontendCore.h"
-
-namespace GpgFrontend {
-
-class GPGFRONTEND_CORE_EXPORT CoreCommonUtil : public QObject {
- Q_OBJECT
- public:
- /**
- * @brief Construct a new Core Common Util object
- *
- */
- static CoreCommonUtil *GetInstance();
-
- /**
- * @brief
- *
- */
- CoreCommonUtil() = default;
-
- /**
- * @brief set a temp cache under a certain key
- *
- */
- void SetTempCacheValue(const std::string &, const std::string &);
-
- /**
- * @brief after get the temp cache, its value will be imediately ease in
- * storage
- *
- * @return std::string
- */
- std::string GetTempCacheValue(const std::string &);
-
- /**
- * @brief imediately ease temp cache in storage
- *
- * @return std::string
- */
- void ResetTempCacheValue(const std::string &);
-
- signals:
-
- /**
- * @brief
- *
- */
- void SignalGnupgNotInstall();
-
- private:
- static std::unique_ptr<CoreCommonUtil> instance_; ///<
- std::map<std::string, std::string> temp_cache_; //<
-};
-
-} // namespace GpgFrontend
-
-#endif // GPGFRONTEND_CORECOMMONUTIL_H
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp index 8aad0500..a4b90698 100644 --- a/src/core/function/ArchiveFileOperator.cpp +++ b/src/core/function/ArchiveFileOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,7 +28,15 @@ #include "ArchiveFileOperator.h" -int copy_data(struct archive *ar, struct archive *aw) { +#include <archive.h> +#include <archive_entry.h> +#include <sys/fcntl.h> + +#include "core/utils/AsyncUtils.h" + +namespace GpgFrontend { + +auto CopyData(struct archive *ar, struct archive *aw) -> int { int r; const void *buff; size_t size; @@ -38,231 +46,217 @@ int copy_data(struct archive *ar, struct archive *aw) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_data_block() failed: {}", - archive_error_string(ar)); + GF_CORE_LOG_ERROR("archive_read_data_block() failed: {}", + archive_error_string(ar)); return (r); } r = archive_write_data_block(aw, buff, size, offset); if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_data_block() failed: {}", - archive_error_string(aw)); + GF_CORE_LOG_ERROR("archive_write_data_block() failed: {}", + archive_error_string(aw)); return (r); } } } -void GpgFrontend::ArchiveFileOperator::CreateArchive( - const std::filesystem::path &base_path, - const std::filesystem::path &archive_path, int compress, - const std::vector<std::filesystem::path> &files) { - SPDLOG_DEBUG("CreateArchive: {}", archive_path.u8string()); - - auto current_base_path_backup = QDir::currentPath(); - QDir::setCurrent(base_path.u8string().c_str()); - - auto relative_archive_path = - std::filesystem::relative(archive_path, base_path); - - std::vector<std::filesystem::path> relative_files; - relative_files.reserve(files.size()); - for (const auto &file : files) { - relative_files.push_back(std::filesystem::relative(file, base_path)); - } - - struct archive *a; - struct archive_entry *entry; - ssize_t len; - int fd; - - SPDLOG_DEBUG("compress: {}", compress); - - a = archive_write_new(); - switch (compress) { -#ifndef NO_BZIP2_CREATE - case 'j': - case 'y': - archive_write_add_filter_bzip2(a); - break; -#endif -#ifndef NO_COMPRESS_CREATE - case 'Z': - archive_write_add_filter_compress(a); - break; -#endif -#ifndef NO_GZIP_CREATE - case 'z': - archive_write_add_filter_gzip(a); - break; -#endif - default: - archive_write_add_filter_none(a); - break; - } - archive_write_set_format_ustar(a); - archive_write_set_format_pax_restricted(a); - - auto u8_filename = relative_archive_path.u8string(); - - if (!u8_filename.empty() && u8_filename == u8"-") - throw std::runtime_error("cannot write to stdout"); - -#ifdef WINDOWS - archive_write_open_filename_w(a, relative_archive_path.wstring().c_str()); -#else - archive_write_open_filename(a, u8_filename.c_str()); -#endif - - for (const auto &file : relative_files) { - struct archive *disk = archive_read_disk_new(); -#ifndef NO_LOOKUP - archive_read_disk_set_standard_lookup(disk); -#endif - int r; - - SPDLOG_DEBUG("reading file: {}", file.u8string()); - -#ifdef WINDOWS - r = archive_read_disk_open_w(disk, file.wstring().c_str()); -#else - r = archive_read_disk_open(disk, file.u8string().c_str()); -#endif - - SPDLOG_DEBUG("read file done: {}", file.u8string()); - - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("{archive_read_disk_open() failed: {}", - archive_error_string(disk)); - throw std::runtime_error("archive_read_disk_open() failed"); - } +struct ArchiveReadClientData { + GFDataExchanger *ex; + std::array<std::byte, 1024> buf; + const std::byte *p_buf = buf.data(); +}; + +auto ArchiveReadCallback(struct archive *, void *client_data, + const void **buffer) -> ssize_t { + auto *rdata = static_cast<ArchiveReadClientData *>(client_data); + *buffer = reinterpret_cast<const void *>(rdata->p_buf); + return rdata->ex->Read(rdata->buf.data(), rdata->buf.size()); +} - for (;;) { - entry = archive_entry_new(); - r = archive_read_next_header2(disk, entry); - - if (r == ARCHIVE_EOF) break; - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_next_header2() failed: {}", - archive_error_string(disk)); - throw std::runtime_error("archive_read_next_header2() failed"); - } - archive_read_disk_descend(disk); - - SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", - archive_entry_pathname_utf8(entry), - archive_entry_size(entry), archive_entry_filetype(entry)); - - r = archive_write_header(a, entry); - if (r < ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_header() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_write_header() failed"); - } - if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal"); - if (r > ARCHIVE_FAILED) { - QByteArray buff; -#ifdef WINDOWS - FileOperator::ReadFile( - QString::fromStdWString(archive_entry_sourcepath_w(entry)), buff); -#else - FileOperator::ReadFile(archive_entry_sourcepath(entry), buff); -#endif - archive_write_data(a, buff.data(), buff.size()); - } - archive_entry_free(entry); - } - archive_read_close(disk); - archive_read_free(disk); - } - archive_write_close(a); - archive_write_free(a); +auto ArchiveWriteCallback(struct archive *, void *client_data, + const void *buffer, size_t length) -> ssize_t { + auto *ex = static_cast<GFDataExchanger *>(client_data); + return ex->Write(static_cast<const std::byte *>(buffer), length); +} - QDir::setCurrent(current_base_path_backup); +auto ArchiveCloseWriteCallback(struct archive *, void *client_data) -> int { + auto *ex = static_cast<GFDataExchanger *>(client_data); + ex->CloseWrite(); + return 0; } -void GpgFrontend::ArchiveFileOperator::ExtractArchive( - const std::filesystem::path &archive_path, - const std::filesystem::path &base_path) { - SPDLOG_DEBUG("ExtractArchive: {}", archive_path.u8string()); +void ArchiveFileOperator::NewArchive2DataExchanger( + const QString &target_directory, std::shared_ptr<GFDataExchanger> exchanger, + const OperationCallback &cb) { + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + std::array<char, 1024> buff{}; + auto ret = 0; + const auto base_path = QDir(QDir(target_directory).absolutePath()); - auto current_base_path_backup = QDir::currentPath(); - QDir::setCurrent(base_path.u8string().c_str()); + auto *archive = archive_write_new(); + archive_write_add_filter_none(archive); + archive_write_set_format_pax_restricted(archive); - struct archive *a; - struct archive *ext; - struct archive_entry *entry; + archive_write_open(archive, exchanger.get(), nullptr, + ArchiveWriteCallback, ArchiveCloseWriteCallback); - a = archive_read_new(); - ext = archive_write_disk_new(); - archive_write_disk_set_options(ext, 0); -#ifndef NO_BZIP2_EXTRACT - archive_read_support_filter_bzip2(a); -#endif -#ifndef NO_GZIP_EXTRACT - archive_read_support_filter_gzip(a); -#endif -#ifndef NO_COMPRESS_EXTRACT - archive_read_support_filter_compress(a); -#endif -#ifndef NO_TAR_EXTRACT - archive_read_support_format_tar(a); -#endif -#ifndef NO_CPIO_EXTRACT - archive_read_support_format_cpio(a); -#endif -#ifndef NO_LOOKUP - archive_write_disk_set_standard_lookup(ext); -#endif + auto *disk = archive_read_disk_new(); + archive_read_disk_set_standard_lookup(disk); - auto filename = archive_path.u8string(); - - if (!filename.empty() && filename == u8"-") { - SPDLOG_ERROR("cannot read from stdin"); - } #ifdef WINDOWS - if (archive_read_open_filename_w(a, archive_path.wstring().c_str(), 10240) != - ARCHIVE_OK) { + auto r = archive_read_disk_open_w( + disk, target_directory.toStdWString().c_str()); #else - if (archive_read_open_filename(a, archive_path.u8string().c_str(), 10240) != - ARCHIVE_OK) { + auto r = archive_read_disk_open(disk, target_directory.toUtf8()); #endif - SPDLOG_ERROR("archive_read_open_filename() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_read_open_filename() failed"); - } - - for (;;) { - int r = archive_read_next_header(a, &entry); - if (r == ARCHIVE_EOF) break; - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_read_next_header() failed: {}", - archive_error_string(a)); - throw std::runtime_error("archive_read_next_header() failed"); - } - SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", - archive_entry_pathname_utf8(entry), archive_entry_size(entry), - archive_entry_filetype(entry)); - r = archive_write_header(ext, entry); - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("archive_write_header() failed: {}", - archive_error_string(ext)); - } else { - r = copy_data(a, ext); - if (r != ARCHIVE_OK) { - SPDLOG_ERROR("copy_data() failed: {}", archive_error_string(ext)); - } - } - } - archive_read_close(a); - archive_read_free(a); - archive_write_close(ext); - archive_write_free(ext); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_disk_open() failed: {}, abort...", + archive_error_string(disk)); + archive_read_free(disk); + archive_write_free(archive); + return -1; + } + + for (;;) { + auto *entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_next_header2() failed, ret: {}, explain: {}", r, + archive_error_string(disk)); + ret = -1; + break; + } + + archive_read_disk_descend(disk); + + // turn absolute path to relative path + archive_entry_set_pathname( + entry, + base_path.relativeFilePath(QString(archive_entry_pathname(entry))) + .toUtf8()); + + r = archive_write_header(archive, entry); + if (r < ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_write_header() failed, ret: {}, explain: {} ", r, + archive_error_string(archive)); + continue; + } + + if (r == ARCHIVE_FATAL) { + GF_CORE_LOG_ERROR( + "archive_write_header() failed, ret: {}, explain: {}, " + "abort ...", + r, archive_error_string(archive)); + ret = -1; + break; + } + + if (r > ARCHIVE_FAILED) { + auto fd = open(archive_entry_sourcepath(entry), O_RDONLY); + auto len = read(fd, buff.data(), buff.size()); + while (len > 0) { + archive_write_data(archive, buff.data(), len); + len = read(fd, buff.data(), buff.size()); + } + close(fd); + } + archive_entry_free(entry); + } + + archive_read_free(disk); + archive_write_free(archive); + return ret; + }, + cb, "archive_write_new"); +} - QDir::setCurrent(current_base_path_backup); +void ArchiveFileOperator::ExtractArchiveFromDataExchanger( + std::shared_ptr<GFDataExchanger> ex, const QString &target_path, + const OperationCallback &cb) { + RunIOOperaAsync( + [=](const DataObjectPtr &data_object) -> GFError { + auto *archive = archive_read_new(); + auto *ext = archive_write_disk_new(); + + auto r = archive_read_support_filter_all(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_support_filter_all(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + r = archive_read_support_format_all(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_read_support_format_all(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + auto rdata = ArchiveReadClientData{}; + rdata.ex = ex.get(); + + r = archive_read_open(archive, &rdata, nullptr, ArchiveReadCallback, + nullptr); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_open(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + r = archive_write_disk_set_options(ext, 0); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR( + "archive_write_disk_set_options(), ret: {}, reason: {}", r, + archive_error_string(archive)); + return r; + } + + for (;;) { + struct archive_entry *entry; + r = archive_read_next_header(archive, &entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_next_header(), ret: {}, reason: {}", + r, archive_error_string(archive)); + break; + } + + archive_entry_set_pathname( + entry, + (target_path + "/" + archive_entry_pathname(entry)).toUtf8()); + + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_write_header(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } else { + r = CopyData(archive, ext); + } + } + + r = archive_read_free(archive); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } + r = archive_write_free(ext); + if (r != ARCHIVE_OK) { + GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r, + archive_error_string(archive)); + } + + return 0; + }, + cb, "archive_read_new"); } -void GpgFrontend::ArchiveFileOperator::ListArchive( - const std::filesystem::path &archive_path) { +void ArchiveFileOperator::ListArchive(const QString &archive_path) { struct archive *a; struct archive_entry *entry; int r; @@ -270,14 +264,16 @@ void GpgFrontend::ArchiveFileOperator::ListArchive( a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); - r = archive_read_open_filename(a, archive_path.u8string().c_str(), + r = archive_read_open_filename(a, archive_path.toUtf8(), 10240); // Note 1 if (r != ARCHIVE_OK) return; while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - SPDLOG_DEBUG("File: {}", archive_entry_pathname(entry)); - SPDLOG_DEBUG("File Path: {}", archive_entry_pathname(entry)); + GF_CORE_LOG_DEBUG("File: {}", archive_entry_pathname(entry)); + GF_CORE_LOG_DEBUG("File Path: {}", archive_entry_pathname(entry)); archive_read_data_skip(a); // Note 2 } r = archive_read_free(a); // Note 3 if (r != ARCHIVE_OK) return; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/ArchiveFileOperator.h b/src/core/function/ArchiveFileOperator.h index 4db5af5f..bfeec0c4 100644 --- a/src/core/function/ArchiveFileOperator.h +++ b/src/core/function/ArchiveFileOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,40 +20,50 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ARCHIVEFILEOPERATOR_H -#define GPGFRONTEND_ARCHIVEFILEOPERATOR_H +#pragma once #include "core/GpgFrontendCore.h" -#include "core/function/FileOperator.h" +#include "core/model/GFDataExchanger.h" +#include "core/typedef/CoreTypedef.h" +#include "core/utils/IOUtils.h" namespace GpgFrontend { -struct ArchiveStruct { - struct archive *archive; - struct archive_entry *entry; - int fd; - bool is_open; - std::string name; -}; - class GPGFRONTEND_CORE_EXPORT ArchiveFileOperator { public: - static void ListArchive(const std::filesystem::path &archive_path); + /** + * @brief + * + * @param archive_path + */ + static void ListArchive(const QString &archive_path); - static void CreateArchive(const std::filesystem::path &base_path, - const std::filesystem::path &archive_path, - int compress, - const std::vector<std::filesystem::path> &files); + /** + * @brief Create a Archive object + * + * @param base_path + * @param archive_path + * @param compress + * @param files + */ + static void NewArchive2DataExchanger(const QString &target_directory, + std::shared_ptr<GFDataExchanger>, + const OperationCallback &cb); - static void ExtractArchive(const std::filesystem::path &archive_path, - const std::filesystem::path &base_path); + /** + * @brief + * + * @param archive_path + * @param base_path + */ + static void ExtractArchiveFromDataExchanger( + std::shared_ptr<GFDataExchanger> fd, const QString &target_path, + const OperationCallback &cb); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ARCHIVEFILEOPERATOR_H diff --git a/src/core/function/CacheManager.cpp b/src/core/function/CacheManager.cpp index d9aead66..719c962d 100644 --- a/src/core/function/CacheManager.cpp +++ b/src/core/function/CacheManager.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -29,119 +29,256 @@ #include "CacheManager.h" #include <algorithm> -#include <boost/format.hpp> -#include <string> +#include <shared_mutex> +#include <utility> -#include "function/DataObjectOperator.h" -#include "spdlog/spdlog.h" +#include "core/function/DataObjectOperator.h" +#include "core/utils/MemoryUtils.h" -GpgFrontend::CacheManager::CacheManager(int channel) - : m_timer_(new QTimer(this)), - SingletonFunctionObject<CacheManager>(channel) { - connect(m_timer_, &QTimer::timeout, this, &CacheManager::flush_cache_storage); - m_timer_->start(15000); +namespace GpgFrontend { - load_all_cache_storage(); -} +template <typename Key, typename Value> +class ThreadSafeMap { + public: + using MapType = std::map<Key, Value>; + using IteratorType = typename MapType::iterator; -void GpgFrontend::CacheManager::SaveCache(std::string key, - const nlohmann::json& value, - bool flush) { - auto data_object_key = get_data_object_key(key); - cache_storage_.insert(key, value); + void insert(const Key& key, const Value& value) { + std::unique_lock lock(mutex_); + (*map_)[key] = value; + } - if (std::find(key_storage_.begin(), key_storage_.end(), key) == - key_storage_.end()) { - SPDLOG_DEBUG("register new key of cache", key); - key_storage_.push_back(key); + auto get(const Key& key) -> std::optional<Value> { + std::shared_lock lock(mutex_); + auto it = map_->find(key); + if (it != map_->end()) { + return it->second; + } + return std::nullopt; } - if (flush) { - flush_cache_storage(); + auto exists(const Key& key) -> bool { + std::shared_lock lock(mutex_); + return map_->count(key) > 0; } -} -nlohmann::json GpgFrontend::CacheManager::LoadCache(std::string key) { - auto data_object_key = get_data_object_key(key); + auto begin() -> IteratorType { return map_mirror_->begin(); } + + auto end() -> IteratorType { return map_mirror_->end(); } - if (!cache_storage_.exists(key)) { - cache_storage_.insert(key, load_cache_storage(key, {})); + auto mirror() -> ThreadSafeMap& { + std::shared_lock lock(mutex_); + *map_mirror_ = *map_; + return *this; } - auto cache = cache_storage_.get(key); - if (cache) - return *cache; - else - return {}; -} + auto remove(QString key) -> bool { + std::unique_lock lock(mutex_); + auto it = map_->find(key); + if (it != map_->end()) { + map_->erase(it); + return true; + } + return false; + } -nlohmann::json GpgFrontend::CacheManager::LoadCache( - std::string key, nlohmann::json default_value) { - auto data_object_key = get_data_object_key(key); - if (!cache_storage_.exists(key)) { - cache_storage_.insert(key, load_cache_storage(key, default_value)); + private: + std::unique_ptr<MapType, SecureObjectDeleter<MapType>> map_mirror_ = + std::move(SecureCreateUniqueObject<MapType>()); + std::unique_ptr<MapType, SecureObjectDeleter<MapType>> map_ = + std::move(SecureCreateUniqueObject<MapType>()); + mutable std::shared_mutex mutex_; +}; + +class CacheManager::Impl : public QObject { + Q_OBJECT + public: + Impl() : flush_timer_(new QTimer(this)) { + connect(flush_timer_, &QTimer::timeout, this, + &Impl::slot_flush_cache_storage); + flush_timer_->start(15000); + + // load data from storage + load_all_cache_storage(); } - auto cache = cache_storage_.get(key); - if (cache) - return *cache; - else - return {}; -} + void SaveDurableCache(QString key, const QJsonDocument& value, bool flush) { + auto data_object_key = get_data_object_key(key); + durable_cache_storage_.insert(key, value); -std::string GpgFrontend::CacheManager::get_data_object_key(std::string key) { - return (boost::format("__cache_data_%1%") % key).str(); -} + if (!key_storage_.contains(key)) { + GF_CORE_LOG_DEBUG("register new key of cache", key); + key_storage_.push_back(key); + } -nlohmann::json GpgFrontend::CacheManager::load_cache_storage( - std::string key, nlohmann::json default_value) { - auto data_object_key = get_data_object_key(key); - auto stored_data = - GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( - data_object_key); + if (flush) slot_flush_cache_storage(); + } - if (stored_data.has_value()) { - return stored_data.value(); - } else { - return default_value; + auto LoadDurableCache(const QString& key) -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + + if (!durable_cache_storage_.exists(key)) { + durable_cache_storage_.insert(key, load_cache_storage(key, {})); + } + + auto cache = durable_cache_storage_.get(key); + if (cache.has_value()) return cache.value(); + return {}; } -} -void GpgFrontend::CacheManager::flush_cache_storage() { - for (auto cache : cache_storage_.mirror()) { - auto key = get_data_object_key(cache.first); - SPDLOG_DEBUG("save cache into filesystem, key {}, value size: {}", key, - cache.second.size()); - GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(key, - cache.second); + auto LoadDurableCache(const QString& key, QJsonDocument default_value) + -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + if (!durable_cache_storage_.exists(key)) { + durable_cache_storage_.insert( + key, load_cache_storage(key, std::move(default_value))); + } + + auto cache = durable_cache_storage_.get(key); + if (cache.has_value()) return cache.value(); + return {}; } - GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(drk_key_, - key_storage_); -} -void GpgFrontend::CacheManager::register_cache_key(std::string key) {} + auto ResetDurableCache(const QString& key) -> bool { + auto data_object_key = get_data_object_key(key); + return durable_cache_storage_.remove(key); + } + + void FlushCacheStorage() { this->slot_flush_cache_storage(); } -void GpgFrontend::CacheManager::load_all_cache_storage() { - SPDLOG_DEBUG("start to load all cache from file system"); - auto stored_data = - GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(drk_key_); + void SaveCache(const QString& key, QString value) { + runtime_cache_storage_.insert(key, new QString(std::move(value))); + } - // get cache data list from file system - nlohmann::json registered_key_list; - if (stored_data.has_value()) { - registered_key_list = std::move(stored_data.value()); + auto LoadCache(const QString& key) -> QString { + auto* value = runtime_cache_storage_.object(key); + if (value == nullptr) return {}; + return *value; } - if (!registered_key_list.is_array()) { + void ResetCache(const QString& key) { runtime_cache_storage_.remove(key); } + + private slots: + + /** + * @brief + * + */ + void slot_flush_cache_storage() { + for (const auto& cache : durable_cache_storage_.mirror()) { + auto key = get_data_object_key(cache.first); + GF_CORE_LOG_TRACE("save cache into filesystem, key {}", key); + GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( + key, QJsonDocument(cache.second)); + } GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( - drk_key_, nlohmann::json::array()); - SPDLOG_ERROR("drk_key_ is not an array, abort."); - return; + drk_key_, QJsonDocument(key_storage_)); } - for (auto key : registered_key_list) { - load_cache_storage(key, {}); + private: + QCache<QString, QString> runtime_cache_storage_; + ThreadSafeMap<QString, QJsonDocument> durable_cache_storage_; + QJsonArray key_storage_; + QTimer* flush_timer_; + const QString drk_key_ = "__cache_manage_data_register_key_list"; + + /** + * @brief Get the data object key object + * + * @param key + * @return QString + */ + static auto get_data_object_key(const QString& key) -> QString { + return QString("__cache_data_%1").arg(key); } - key_storage_ = registered_key_list; -}
\ No newline at end of file + /** + * @brief + * + * @param key + * @param default_value + * @return QJsonObject + */ + static auto load_cache_storage(const QString& key, + QJsonDocument default_value) -> QJsonDocument { + auto data_object_key = get_data_object_key(key); + auto stored_data = + GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( + data_object_key); + + if (stored_data.has_value()) return stored_data.value(); + return default_value; + } + + /** + * @brief + * + */ + void load_all_cache_storage() { + GF_CORE_LOG_DEBUG("start to load all cache from file system"); + auto stored_data = + GpgFrontend::DataObjectOperator::GetInstance().GetDataObject(drk_key_); + + // get cache data list from file system + QJsonArray registered_key_list; + if (stored_data->isArray()) { + registered_key_list = stored_data->array(); + } else { + GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( + drk_key_, QJsonDocument(QJsonArray())); + } + + for (const auto& key : registered_key_list) { + load_cache_storage(key.toString(), {}); + } + + key_storage_ = registered_key_list; + } + + /** + * @brief + * + * @param key + */ + void register_cache_key(const QString& key) {} +}; + +CacheManager::CacheManager(int channel) + : SingletonFunctionObject<CacheManager>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +CacheManager::~CacheManager() { p_->FlushCacheStorage(); } + +void CacheManager::SaveDurableCache(const QString& key, + const QJsonDocument& value, bool flush) { + p_->SaveDurableCache(key, value, flush); +} + +auto CacheManager::LoadDurableCache(const QString& key) -> QJsonDocument { + return p_->LoadDurableCache(key); +} + +auto CacheManager::LoadDurableCache(const QString& key, + QJsonDocument default_value) + -> QJsonDocument { + return p_->LoadDurableCache(key, std::move(default_value)); +} + +auto CacheManager::ResetDurableCache(const QString& key) -> bool { + return p_->ResetDurableCache(key); +} + +void CacheManager::SaveCache(const QString& key, QString value) { + p_->SaveCache(key, std::move(value)); +} + +auto CacheManager::LoadCache(const QString& key) -> QString { + return p_->LoadCache(key); +} + +void CacheManager::ResetCache(const QString& key) { + return p_->ResetCache(key); +} +} // namespace GpgFrontend + +#include "CacheManager.moc"
\ No newline at end of file diff --git a/src/core/function/CacheManager.h b/src/core/function/CacheManager.h index 8234de2a..67e7fd75 100644 --- a/src/core/function/CacheManager.h +++ b/src/core/function/CacheManager.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,94 +20,99 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_CACHEMANAGER_H -#define GPGFRONTEND_CACHEMANAGER_H +#pragma once -#include <string> - -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { -template <typename Key, typename Value> -class ThreadSafeMap { - public: - using MapType = std::map<Key, Value>; - using IteratorType = typename MapType::iterator; - - void insert(const Key& key, const Value& value) { - std::unique_lock lock(mutex_); - map_[key] = value; - } - - std::optional<Value> get(const Key& key) { - std::shared_lock lock(mutex_); - auto it = map_.find(key); - if (it != map_.end()) { - return it->second; - } - return std::nullopt; - } - - bool exists(const Key& key) { - std::shared_lock lock(mutex_); - return map_.count(key) > 0; - } - - IteratorType begin() { return map_mirror_.begin(); } - - IteratorType end() { return map_mirror_.end(); } - - ThreadSafeMap& mirror() { - std::shared_lock lock(mutex_); - map_mirror_ = map_; - return *this; - } - - private: - MapType map_mirror_; - MapType map_; - mutable std::shared_mutex mutex_; -}; - class GPGFRONTEND_CORE_EXPORT CacheManager - : public QObject, - public SingletonFunctionObject<CacheManager> { - Q_OBJECT + : public SingletonFunctionObject<CacheManager> { public: - CacheManager(int channel = SingletonFunctionObject::GetDefaultChannel()); - - void SaveCache(std::string key, const nlohmann::json& value, - bool flush = false); - - nlohmann::json LoadCache(std::string key); - - nlohmann::json LoadCache(std::string key, nlohmann::json default_value); + /** + * @brief Construct a new Cache Manager object + * + * @param channel + */ + explicit CacheManager( + int channel = SingletonFunctionObject::GetDefaultChannel()); + + /** + * @brief Destroy the Cache Manager object + * + */ + ~CacheManager() override; + + /** + * @brief + * + * @param key + * @param value + */ + void SaveCache(const QString& key, QString value); + + /** + * @brief + * + * @param key + * @param value + * @param flush + */ + void SaveDurableCache(const QString& key, const QJsonDocument& value, + bool flush = false); + + /** + * @brief + * + * @param key + * @param value + */ + auto LoadCache(const QString& key) -> QString; + + /** + * @brief + * + * @param key + * @return QJsonDocument + */ + auto LoadDurableCache(const QString& key) -> QJsonDocument; + + /** + * @brief + * + * @param key + * @param default_value + * @return QJsonDocument + */ + auto LoadDurableCache(const QString& key, QJsonDocument default_value) + -> QJsonDocument; + + /** + * @brief + * + * @param key + * @return auto + */ + void ResetCache(const QString& key); + + /** + * @brief + * + * @param key + * @return true + * @return false + */ + auto ResetDurableCache(const QString& key) -> bool; private: - std::string get_data_object_key(std::string key); - - nlohmann::json load_cache_storage(std::string key, - nlohmann::json default_value); - - void load_all_cache_storage(); - - void flush_cache_storage(); - - void register_cache_key(std::string key); - - ThreadSafeMap<std::string, nlohmann::json> cache_storage_; - nlohmann::json key_storage_; - QTimer* m_timer_; - const std::string drk_key_ = "__cache_manage_data_register_key_list"; + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif diff --git a/src/core/function/CharsetOperator.cpp b/src/core/function/CharsetOperator.cpp deleted file mode 100644 index 72c5e72b..00000000 --- a/src/core/function/CharsetOperator.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "core/function/CharsetOperator.h" - -#include <spdlog/spdlog.h> -#include <unicode/ucnv.h> -#include <unicode/ucsdet.h> -#include <unicode/ustring.h> -#include <unicode/utypes.h> - -#include <cstddef> -#include <memory> -#include <string> - -GpgFrontend::CharsetOperator::CharsetInfo GpgFrontend::CharsetOperator::Detect( - const std::string &buffer) { - const UCharsetMatch *ucm; - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector *csd = ucsdet_open(&status); - - status = U_ZERO_ERROR; - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open charset detector: {}", u_errorName(status)); - return {"unknown", "unknown", 0}; - } - - SPDLOG_DEBUG("detecting charset buffer: {} bytes", buffer.size()); - - status = U_ZERO_ERROR; - ucsdet_setText(csd, buffer.data(), buffer.size(), &status); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to set text to charset detector: {}", - u_errorName(status)); - return {"unknown", "unknown", 0}; - } - - status = U_ZERO_ERROR; - ucm = ucsdet_detect(csd, &status); - - if (U_FAILURE(status)) return {"unknown", "unknown", 0}; - - status = U_ZERO_ERROR; - const char *name = ucsdet_getName(ucm, &status); - if (U_FAILURE(status)) return {"unknown", "unknown", 0}; - - status = U_ZERO_ERROR; - int confidence = ucsdet_getConfidence(ucm, &status); - if (U_FAILURE(status)) return {name, "unknown", 0}; - - status = U_ZERO_ERROR; - const char *language = ucsdet_getLanguage(ucm, &status); - if (U_FAILURE(status)) return {name, "unknown", confidence}; - - SPDLOG_DEBUG("Detected charset: {} {} {}", name, language, confidence); - return {name, language, confidence}; -} - -bool GpgFrontend::CharsetOperator::Convert2Utf8(const std::string &buffer, - std::string &out_buffer, - std::string from_charset_name) { - UErrorCode status = U_ZERO_ERROR; - const auto from_encode = std::string("utf-8"); - const auto to_encode = from_charset_name; - - SPDLOG_DEBUG("Converting buffer: {}", buffer.size()); - - // test if the charset is supported - UConverter *conv = ucnv_open(from_encode.c_str(), &status); - ucnv_close(conv); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open converter: {}, from encode: {}", - u_errorName(status), from_encode); - return false; - } - - // test if the charset is supported - conv = ucnv_open(to_encode.c_str(), &status); - ucnv_close(conv); - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to open converter: {}, to encode: {}", - u_errorName(status), to_encode); - return false; - } - - status = U_ZERO_ERROR; - int32_t target_limit = 0, target_capacity = 0; - - target_capacity = - ucnv_convert(from_encode.c_str(), to_encode.c_str(), nullptr, - target_limit, buffer.data(), buffer.size(), &status); - - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - out_buffer.clear(); - out_buffer.resize(target_capacity); - ucnv_convert(from_encode.c_str(), to_encode.c_str(), out_buffer.data(), - out_buffer.size(), buffer.data(), buffer.size(), &status); - } - - if (U_FAILURE(status)) { - SPDLOG_ERROR("failed to convert to utf-8: {}", u_errorName(status)); - return false; - } - - SPDLOG_DEBUG("converted buffer: {} bytes", out_buffer.size()); - return true; -}
\ No newline at end of file diff --git a/src/core/function/CoreSignalStation.cpp b/src/core/function/CoreSignalStation.cpp index f78d417b..8cb84743 100644 --- a/src/core/function/CoreSignalStation.cpp +++ b/src/core/function/CoreSignalStation.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -29,11 +29,12 @@ #include "core/function/CoreSignalStation.h" std::unique_ptr<GpgFrontend::CoreSignalStation> - GpgFrontend::CoreSignalStation::_instance = nullptr; + GpgFrontend::CoreSignalStation::instance = nullptr; -GpgFrontend::CoreSignalStation* GpgFrontend::CoreSignalStation::GetInstance() { - if (_instance == nullptr) { - _instance = std::make_unique<CoreSignalStation>(); +auto GpgFrontend::CoreSignalStation::GetInstance() + -> GpgFrontend::CoreSignalStation* { + if (instance == nullptr) { + instance = std::make_unique<CoreSignalStation>(); } - return _instance.get(); + return instance.get(); } diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h index 7497cab7..e0a11fa3 100644 --- a/src/core/function/CoreSignalStation.h +++ b/src/core/function/CoreSignalStation.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,26 +20,27 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_CORESIGNALSTATION_H -#define GPGFRONTEND_CORESIGNALSTATION_H +#pragma once #include "core/GpgFrontendCore.h" namespace GpgFrontend { +class GpgPassphraseContext; + /** * @brief * */ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { Q_OBJECT - static std::unique_ptr<CoreSignalStation> _instance; + static std::unique_ptr<CoreSignalStation> instance; public: /** @@ -47,7 +48,7 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { * * @return SignalStation* */ - static CoreSignalStation* GetInstance(); + static auto GetInstance() -> CoreSignalStation*; signals: @@ -55,15 +56,25 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { * @brief * */ - void SignalUserInputPassphraseDone(QString passparase); + void SignalNeedUserInputPassphrase(QSharedPointer<GpgPassphraseContext>); + + /** + * @brief + * + */ + void SignalUserInputPassphraseCallback(QSharedPointer<GpgPassphraseContext>); /** * @brief * */ - void SignalNeedUserInputPassphrase(); + void SignalBadGnupgEnv(QString); + + /** + * @brief + * + */ + void SignalGoodGnupgEnv(); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_CORESIGNALSTATION_H diff --git a/src/core/function/DataObjectOperator.cpp b/src/core/function/DataObjectOperator.cpp index 180cef30..e1d8b4da 100644 --- a/src/core/function/DataObjectOperator.cpp +++ b/src/core/function/DataObjectOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -30,143 +30,131 @@ #include <qt-aes/qaesencryption.h> -#include <boost/date_time.hpp> - -#include "core/function/FileOperator.h" #include "core/function/PassphraseGenerator.h" +#include "core/utils/IOUtils.h" + +namespace GpgFrontend { -void GpgFrontend::DataObjectOperator::init_app_secure_key() { - SPDLOG_DEBUG("initializing application secure key"); - FileOperator::WriteFileStd(app_secure_key_path_, - PassphraseGenerator::GetInstance().Generate(256)); - std::filesystem::permissions( - app_secure_key_path_, - std::filesystem::perms::owner_read | std::filesystem::perms::owner_write); +void DataObjectOperator::init_app_secure_key() { + GF_CORE_LOG_INFO("initializing application secure key..."); + WriteFile(app_secure_key_path_, + PassphraseGenerator::GetInstance().Generate(256).toUtf8()); + QFile::setPermissions(app_secure_key_path_, + QFileDevice::ReadOwner | QFileDevice::WriteOwner); } -GpgFrontend::DataObjectOperator::DataObjectOperator(int channel) +DataObjectOperator::DataObjectOperator(int channel) : SingletonFunctionObject<DataObjectOperator>(channel) { - if (!is_directory(app_secure_path_)) create_directory(app_secure_path_); - - if (!exists(app_secure_key_path_)) { - init_app_secure_key(); + if (!QDir(app_secure_path_).exists()) QDir(app_secure_path_).mkpath("."); + if (!QFileInfo(app_secure_key_path_).exists()) init_app_secure_key(); + + QByteArray key; + if (!ReadFile(app_secure_key_path_, key)) { + GF_CORE_LOG_ERROR("failed to read app secure key file: {}", + app_secure_key_path_); + // unsafe mode + key = {}; } - std::string key; - if (!FileOperator::ReadFileStd(app_secure_key_path_.u8string(), key)) { - SPDLOG_ERROR("failed to read app secure key file: {}", - app_secure_key_path_.u8string()); - throw std::runtime_error("failed to read app secure key file"); - } - hash_key_ = QCryptographicHash::hash(QByteArray::fromStdString(key), - QCryptographicHash::Sha256); - SPDLOG_DEBUG("app secure key loaded {} bytes", hash_key_.size()); + hash_key_ = QCryptographicHash::hash(key, QCryptographicHash::Sha256); - if (!exists(app_data_objs_path_)) create_directory(app_data_objs_path_); + if (!QDir(app_data_objs_path_).exists()) { + QDir(app_data_objs_path_).mkpath("."); + } } -std::string GpgFrontend::DataObjectOperator::SaveDataObj( - const std::string& _key, const nlohmann::json& value) { - std::string _hash_obj_key = {}; - if (_key.empty()) { - _hash_obj_key = +auto DataObjectOperator::SaveDataObj(const QString& key, + const QJsonDocument& value) -> QString { + QByteArray hash_obj_key = {}; + if (key.isEmpty()) { + hash_obj_key = QCryptographicHash::hash( - hash_key_ + QByteArray::fromStdString( - PassphraseGenerator::GetInstance().Generate(32) + - to_iso_extended_string( - boost::posix_time::second_clock::local_time())), + hash_key_ + + PassphraseGenerator::GetInstance().Generate(32).toUtf8() + + QDateTime::currentDateTime().toString().toUtf8(), QCryptographicHash::Sha256) - .toHex() - .toStdString(); + .toHex(); } else { - _hash_obj_key = - QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), - QCryptographicHash::Sha256) - .toHex() - .toStdString(); + hash_obj_key = QCryptographicHash::hash(hash_key_ + key.toUtf8(), + QCryptographicHash::Sha256) + .toHex(); } - const auto obj_path = app_data_objs_path_ / _hash_obj_key; - - QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, - QAESEncryption::Padding::ISO); - auto encoded = - encryption.encode(QByteArray::fromStdString(to_string(value)), hash_key_); - - SPDLOG_DEBUG("saving data object {} to {} , size: {} bytes", _hash_obj_key, - obj_path.u8string(), encoded.size()); - - FileOperator::WriteFileStd(obj_path.u8string(), encoded.toStdString()); + const auto target_obj_path = app_data_objs_path_ + "/" + hash_obj_key; + auto encoded_data = + QAESEncryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO) + .encode(value.toJson(), hash_key_); + GF_CORE_LOG_TRACE("saving data object {} to disk {} , size: {} bytes", + hash_obj_key, target_obj_path, encoded_data.size()); + + // recreate if not exists + if (!QDir(app_data_objs_path_).exists()) { + QDir(app_data_objs_path_).mkpath("."); + } - return _key.empty() ? _hash_obj_key : std::string(); + if (!WriteFile(target_obj_path, encoded_data)) { + GF_CORE_LOG_ERROR("failed to write data object to disk: {}", key); + } + return key.isEmpty() ? hash_obj_key : QString(); } -std::optional<nlohmann::json> GpgFrontend::DataObjectOperator::GetDataObject( - const std::string& _key) { +auto DataObjectOperator::GetDataObject(const QString& key) + -> std::optional<QJsonDocument> { try { - SPDLOG_DEBUG("get data object {}", _key); - auto _hash_obj_key = - QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), - QCryptographicHash::Sha256) - .toHex() - .toStdString(); - - const auto obj_path = app_data_objs_path_ / _hash_obj_key; - - if (!std::filesystem::exists(obj_path)) { - SPDLOG_ERROR("data object not found :{}", _key); + GF_CORE_LOG_TRACE("try to get data object from disk, key: {}", key); + auto hash_obj_key = QCryptographicHash::hash(hash_key_ + key.toUtf8(), + QCryptographicHash::Sha256) + .toHex(); + + const auto obj_path = app_data_objs_path_ + "/" + hash_obj_key; + if (!QFileInfo(obj_path).exists()) { + GF_CORE_LOG_WARN("data object not found from disk, key: {}", key); return {}; } - std::string buffer; - if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) { - SPDLOG_ERROR("failed to read data object: {}", _key); + QByteArray encoded_data; + if (!ReadFile(obj_path, encoded_data)) { + GF_CORE_LOG_ERROR("failed to read data object from disk, key: {}", key); return {}; } - SPDLOG_DEBUG("data object found {}", _key); - - auto encoded = QByteArray::fromStdString(buffer); QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); - SPDLOG_DEBUG("decrypting data object {} , hash key size: {}", - encoded.size(), hash_key_.size()); - - auto decoded = - encryption.removePadding(encryption.decode(encoded, hash_key_)); - - SPDLOG_DEBUG("data object decoded: {}", _key); - - return nlohmann::json::parse(decoded.toStdString()); + auto decoded_data = + encryption.removePadding(encryption.decode(encoded_data, hash_key_)); + GF_CORE_LOG_TRACE("data object has been decoded, key: {}, data: {}", key, + decoded_data); + return QJsonDocument::fromJson(decoded_data); } catch (...) { - SPDLOG_ERROR("failed to get data object: {}", _key); + GF_CORE_LOG_ERROR("failed to get data object, caught exception: {}", key); return {}; } } -std::optional<nlohmann::json> -GpgFrontend::DataObjectOperator::GetDataObjectByRef(const std::string& _ref) { +auto DataObjectOperator::GetDataObjectByRef(const QString& _ref) + -> std::optional<QJsonDocument> { if (_ref.size() != 64) return {}; try { - const auto& _hash_obj_key = _ref; - const auto obj_path = app_data_objs_path_ / _hash_obj_key; + const auto& hash_obj_key = _ref; + const auto obj_path = app_data_objs_path_ + "/" + hash_obj_key; - if (!std::filesystem::exists(obj_path)) return {}; + if (!QFileInfo(obj_path).exists()) return {}; - std::string buffer; - if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) return {}; - auto encoded = QByteArray::fromStdString(buffer); + QByteArray encoded_data; + if (!ReadFile(obj_path, encoded_data)) return {}; QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); - auto decoded = - encryption.removePadding(encryption.decode(encoded, hash_key_)); + auto decoded_data = + encryption.removePadding(encryption.decode(encoded_data, hash_key_)); - return nlohmann::json::parse(decoded.toStdString()); + return QJsonDocument::fromJson(decoded_data); } catch (...) { return {}; } } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/DataObjectOperator.h b/src/core/function/DataObjectOperator.h index ae5dc62c..fedbd905 100644 --- a/src/core/function/DataObjectOperator.h +++ b/src/core/function/DataObjectOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,18 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_DATAOBJECTOPERATOR_H -#define GPGFRONTEND_DATAOBJECTOPERATOR_H +#pragma once + +#include <optional> -#include "core/GpgFunctionObject.h" #include "core/function/GlobalSettingStation.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { @@ -45,11 +46,11 @@ class GPGFRONTEND_CORE_EXPORT DataObjectOperator explicit DataObjectOperator( int channel = SingletonFunctionObject::GetDefaultChannel()); - std::string SaveDataObj(const std::string &_key, const nlohmann::json &value); + auto SaveDataObj(const QString &_key, const QJsonDocument &value) -> QString; - std::optional<nlohmann::json> GetDataObject(const std::string &_key); + auto GetDataObject(const QString &_key) -> std::optional<QJsonDocument>; - std::optional<nlohmann::json> GetDataObjectByRef(const std::string &_ref); + auto GetDataObjectByRef(const QString &_ref) -> std::optional<QJsonDocument>; private: /** @@ -60,21 +61,16 @@ class GPGFRONTEND_CORE_EXPORT DataObjectOperator GlobalSettingStation &global_setting_station_ = GlobalSettingStation::GetInstance(); ///< GlobalSettingStation - std::filesystem::path app_secure_path_ = - global_setting_station_.GetAppConfigPath() / - "secure"; ///< Where sensitive information is stored - std::filesystem::path app_secure_key_path_ = - app_secure_path_ / "app.key"; ///< Where the key of data object is stored - std::filesystem::path app_data_objs_path_ = - global_setting_station_.GetAppDataPath() / "data_objs"; ///< Where data - ///< object is - ///< stored + QString app_secure_path_ = + global_setting_station_.GetAppDataPath() + + "/secure"; ///< Where sensitive information is stored + QString app_secure_key_path_ = + app_secure_path_ + + "/app.key"; ///< Where the key of data object is stored + QString app_data_objs_path_ = + global_setting_station_.GetAppDataPath() + "/data_objs"; - std::random_device rd_; ///< Random device - std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister - QByteArray hash_key_; ///< Hash key + QByteArray hash_key_; ///< Hash key }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_DATAOBJECTOPERATOR_H diff --git a/src/core/function/FileOperator.cpp b/src/core/function/FileOperator.cpp deleted file mode 100644 index 41552246..00000000 --- a/src/core/function/FileOperator.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "FileOperator.h" - -bool GpgFrontend::FileOperator::ReadFile(const QString& file_name, - QByteArray& data) { - QFile file(file_name); - if (!file.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); - return false; - } - data = file.readAll(); - file.close(); - return true; -} - -bool GpgFrontend::FileOperator::WriteFile(const QString& file_name, - const QByteArray& data) { - QFile file(file_name); - if (!file.open(QIODevice::WriteOnly)) { - SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); - return false; - } - file.write(data); - file.close(); - return true; -} - -bool GpgFrontend::FileOperator::ReadFileStd( - const std::filesystem::path& file_name, std::string& data) { - QByteArray byte_data; -#ifdef WINDOWS - bool res = ReadFile(QString::fromStdU16String(file_name.u16string()).toUtf8(), - byte_data); -#else - bool res = ReadFile(QString::fromStdString(file_name.u8string()).toUtf8(), - byte_data); -#endif - data = byte_data.toStdString(); - return res; -} - -bool GpgFrontend::FileOperator::WriteFileStd( - const std::filesystem::path& file_name, const std::string& data) { - return WriteFile(QString::fromStdString(file_name.u8string()).toUtf8(), - QByteArray::fromStdString(data)); -} - -std::string GpgFrontend::FileOperator::CalculateHash( - const std::filesystem::path& file_path) { - // Returns empty QByteArray() on failure. - QFileInfo info(QString::fromStdString(file_path.string())); - std::stringstream ss; - - if (info.isFile() && info.isReadable()) { - ss << "[#] " << _("File Hash Information") << std::endl; - ss << " " << _("filename") << _(": ") - << file_path.filename().u8string().c_str() << std::endl; - - QFile f(info.filePath()); - if (f.open(QFile::ReadOnly)) { - // read all data - auto buffer = f.readAll(); - ss << " " << _("file size(bytes)") << _(": ") << buffer.size() - << std::endl; - - // md5 - auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); - hash_md5.addData(buffer); - auto md5 = hash_md5.result().toHex().toStdString(); - SPDLOG_DEBUG("md5 {}", md5); - ss << " " - << "md5" << _(": ") << md5 << std::endl; - - // sha1 - auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); - hash_sha1.addData(buffer); - auto sha1 = hash_sha1.result().toHex().toStdString(); - SPDLOG_DEBUG("sha1 {}", sha1); - ss << " " - << "sha1" << _(": ") << sha1 << std::endl; - - // sha1 - auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); - hash_sha256.addData(buffer); - auto sha256 = hash_sha256.result().toHex().toStdString(); - SPDLOG_DEBUG("sha256 {}", sha256); - ss << " " - << "sha256" << _(": ") << sha256 << std::endl; - - ss << std::endl; - } - } else { - ss << "[#] " << _("Error in Calculating File Hash ") << std::endl; - } - - return ss.str(); -} diff --git a/src/core/function/FileOperator.h b/src/core/function/FileOperator.h deleted file mode 100644 index a727b1de..00000000 --- a/src/core/function/FileOperator.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#ifndef GPGFRONTEND_FILEOPERATOR_H -#define GPGFRONTEND_FILEOPERATOR_H - -#include "core/GpgFrontendCore.h" - -namespace GpgFrontend { - -/** - * @brief provides file operations - * - */ -class GPGFRONTEND_CORE_EXPORT FileOperator { - public: - /** - * @brief read file content using std struct - * - * - * @param file_name file name - * @param data data read from file - * @return - */ - static bool ReadFileStd(const std::filesystem::path &file_name, - std::string &data); - - /** - * @brief write file content using std struct - * - * @param file_name file name - * @param data data to write to file - * @return - */ - static bool WriteFileStd(const std::filesystem::path &file_name, - const std::string &data); - - /** - * @brief read file content - * - * @param file_name file name - * @param data data read from file - * @return true if success - * @return false if failed - */ - static bool ReadFile(const QString &file_name, QByteArray &data); - - /** - * @brief write file content - * - * @param file_name file name - * @param data data to write to file - * @return true if success - * @return false if failed - */ - static bool WriteFile(const QString &file_name, const QByteArray &data); - - /** - * calculate the hash of a file - * @param file_path - * @return - */ - static std::string CalculateHash(const std::filesystem::path &file_path); -}; -} // namespace GpgFrontend - -#endif // GPGFRONTEND_FILEOPERATOR_H diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp index 6b743268..0158e8b3 100644 --- a/src/core/function/GlobalSettingStation.cpp +++ b/src/core/function/GlobalSettingStation.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,136 +28,160 @@ #include "GlobalSettingStation.h" -#include "core/function/FileOperator.h" +#include "core/module/ModuleManager.h" +#include "core/utils/FilesystemUtils.h" + +// macros to find resource files +#if defined(MACOS) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../Resources/") +#define RESOURCE_DIR_PATH(appDir) (appDir / ".." / "Resources") +#elif defined(LINUX) && defined(RELEASE) +#define RESOURCE_DIR(appDir) (appDir + "/../share/") +#define RESOURCE_DIR_PATH(appDir) (appDir / ".." / "share") +#else +#define RESOURCE_DIR(appDir) (appDir) +#define RESOURCE_DIR_PATH(appDir) (appDir) +#endif + +namespace GpgFrontend { + +class GlobalSettingStation::Impl { + public: + /** + * @brief Construct a new Global Setting Station object + * + */ + explicit Impl() noexcept { + GF_CORE_LOG_INFO("app path: {}", GetAppDir()); + GF_CORE_LOG_INFO("app working path: {}", working_path_); + + auto portable_file_path = working_path_ + "/PORTABLE.txt"; + if (QFileInfo(portable_file_path).exists()) { + GF_CORE_LOG_INFO( + "dectected portable mode, reconfiguring config and data path..."); + Module::UpsertRTValue("core", "env.state.portable", 1); + + app_data_path_ = working_path_; + app_log_path_ = app_data_path_ + "/logs"; + app_data_objs_path_ = app_data_path_ + "/data_objs"; + + portable_mode_ = true; + } + + GF_CORE_LOG_INFO("app data path: {}", app_data_path_); + GF_CORE_LOG_INFO("app log path: {}", app_log_path_); -void GpgFrontend::GlobalSettingStation::SyncSettings() noexcept { - using namespace libconfig; - try { - ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("updated ui configuration successfully written to {}", - ui_config_path_.u8string()); + GF_CORE_LOG_INFO("app log files total size: {}", GetLogFilesSize()); + GF_CORE_LOG_INFO("app data objects files total size: {}", + GetDataObjectsFilesSize()); - } catch (const FileIOException &fioex) { - SPDLOG_ERROR("i/o error while writing ui configuration file: {}", - ui_config_path_.u8string()); + if (!QDir(app_data_path_).exists()) QDir(app_data_path_).mkpath("."); + if (!QDir(app_log_path_).exists()) QDir(app_log_path_).mkpath("."); } -} -GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept - : SingletonFunctionObject<GlobalSettingStation>(channel) { - using namespace std::filesystem; - using namespace libconfig; - - SPDLOG_INFO("app path: {}", app_path_.u8string()); - SPDLOG_INFO("app configure path: {}", app_configure_path_.u8string()); - SPDLOG_INFO("app data path: {}", app_data_path_.u8string()); - SPDLOG_INFO("app log path: {}", app_log_path_.u8string()); - SPDLOG_INFO("app locale path: {}", app_locale_path_.u8string()); - SPDLOG_INFO("app conf path: {}", ui_config_path_.u8string()); - - SPDLOG_INFO("app log files total size: {}", GetLogFilesSize()); - SPDLOG_INFO("app data objects files total size: {}", - GetDataObjectsFilesSize()); - - if (!is_directory(app_configure_path_)) create_directory(app_configure_path_); - if (!is_directory(app_data_path_)) create_directory(app_data_path_); - if (!is_directory(app_log_path_)) create_directory(app_log_path_); - if (!is_directory(ui_config_dir_path_)) create_directory(ui_config_dir_path_); - - if (!exists(ui_config_path_)) { - try { - this->ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("user interface configuration successfully written to {}", - ui_config_path_.u8string()); - - } catch (const FileIOException &fioex) { - SPDLOG_DEBUG( - "i/o error while writing UserInterface configuration file {}", - ui_config_path_.u8string()); - } - } else { - try { - this->ui_cfg_.readFile(ui_config_path_.u8string().c_str()); - SPDLOG_DEBUG("user interface configuration successfully read from {}", - ui_config_path_.u8string()); - } catch (const FileIOException &fioex) { - SPDLOG_ERROR("i/o error while reading UserInterface configure file"); - } catch (const ParseException &pex) { - SPDLOG_ERROR("parse error at {} : {} - {}", pex.getFile(), pex.getLine(), - pex.getError()); - } + [[nodiscard]] auto GetSettings() -> QSettings { + if (!portable_mode_) return QSettings(); + return {app_portable_config_path_, QSettings::IniFormat}; } -} -libconfig::Setting & -GpgFrontend::GlobalSettingStation::GetUISettings() noexcept { - return ui_cfg_.getRoot(); -} + [[nodiscard]] auto GetLogFilesSize() const -> QString { + return GetHumanFriendlyFileSize(GetFileSizeByPath(app_log_path_, "*.log")); + } + + [[nodiscard]] auto GetDataObjectsFilesSize() const -> QString { + return GetHumanFriendlyFileSize( + GetFileSizeByPath(app_data_objs_path_, "*")); + } -void GpgFrontend::GlobalSettingStation::init_app_secure_key() {} + void ClearAllLogFiles() const { + DeleteAllFilesByPattern(app_log_path_, "*.log"); + } -int64_t GpgFrontend::GlobalSettingStation::get_files_size_at_path( - std::filesystem::path path, std::string filename_pattern) const { - auto dir = QDir(QString::fromStdString(path.u8string())); - QFileInfoList fileList = dir.entryInfoList( - QStringList() << QString::fromStdString(filename_pattern), QDir::Files); - qint64 totalSize = 0; + void ClearAllDataObjects() const { + DeleteAllFilesByPattern(app_data_objs_path_, "*"); + } - for (const QFileInfo &fileInfo : fileList) { - totalSize += fileInfo.size(); + /** + * @brief Get the App Dir object + * + * @return QString + */ + [[nodiscard]] auto GetAppDir() const -> QString { + return QCoreApplication::applicationDirPath(); } - return totalSize; -} -std::string GpgFrontend::GlobalSettingStation::get_human_readable_size( - int64_t size) const { - double num = size; - QStringList list; - list << "KB" - << "MB" - << "GB" - << "TB"; - - QStringListIterator i(list); - QString unit("bytes"); - - while (num >= 1024.0 && i.hasNext()) { - unit = i.next(); - num /= 1024.0; + /** + * @brief Get the App Data Path object + * + * @return QString + */ + [[nodiscard]] auto GetAppDataPath() const -> QString { + return app_data_path_; } - return (QString().setNum(num, 'f', 2) + " " + unit).toStdString(); + + /** + * @brief Get the Log Dir object + * + * @return QString + */ + [[nodiscard]] auto GetLogDir() const -> QString { return app_log_path_; } + + private: + QString working_path_ = QDir::currentPath(); + + QString app_data_path_ = QString{QStandardPaths::writableLocation( + QStandardPaths::AppLocalDataLocation)}; ///< Program Data Location + + QString app_log_path_ = app_data_path_ + "/logs"; ///< Program Data Location + + QString app_data_objs_path_ = + app_data_path_ + "/data_objs"; ///< Object storage path + + bool portable_mode_ = false; ///< + QString app_portable_config_path_ = + working_path_ + "/config.ini"; ///< take effect only in portable mode + + /** + * @brief + * + */ + void init_app_secure_key() {} +}; + +GlobalSettingStation::GlobalSettingStation(int channel) noexcept + : SingletonFunctionObject<GlobalSettingStation>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +GlobalSettingStation::~GlobalSettingStation() noexcept = default; + +auto GlobalSettingStation::GetSettings() const -> QSettings { + return p_->GetSettings(); } -std::string GpgFrontend::GlobalSettingStation::GetLogFilesSize() const { - return get_human_readable_size( - get_files_size_at_path(app_log_path_, "*.log")); +auto GlobalSettingStation::GetAppDir() const -> QString { + return p_->GetAppDir(); } -std::string GpgFrontend::GlobalSettingStation::GetDataObjectsFilesSize() const { - return get_human_readable_size( - get_files_size_at_path(app_data_objs_path_, "*")); +auto GlobalSettingStation::GetAppDataPath() const -> QString { + return p_->GetAppDataPath(); } -void GpgFrontend::GlobalSettingStation::ClearAllLogFiles() const { - delete_all_files(app_log_path_, "*.log"); +[[nodiscard]] auto GlobalSettingStation::GetLogDir() const -> QString { + return p_->GetLogDir(); } -void GpgFrontend::GlobalSettingStation::ClearAllDataObjects() const { - delete_all_files(app_data_objs_path_, "*"); +auto GlobalSettingStation::GetLogFilesSize() const -> QString { + return p_->GetLogFilesSize(); } -void GpgFrontend::GlobalSettingStation::delete_all_files( - std::filesystem::path path, std::string filename_pattern) const { - auto dir = QDir(QString::fromStdString(path.u8string())); +auto GlobalSettingStation::GetDataObjectsFilesSize() const -> QString { + return p_->GetDataObjectsFilesSize(); +} - // 使用name filters来只选取以.log结尾的文件 - QStringList logFiles = dir.entryList( - QStringList() << QString::fromStdString(filename_pattern), QDir::Files); +void GlobalSettingStation::ClearAllLogFiles() const { p_->ClearAllLogFiles(); } - // 遍历并删除所有符合条件的文件 - for (const auto &file : logFiles) { - QFile::remove(dir.absoluteFilePath(file)); - } +void GlobalSettingStation::ClearAllDataObjects() const { + p_->ClearAllDataObjects(); } -GpgFrontend::GlobalSettingStation::~GlobalSettingStation() noexcept = default; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/GlobalSettingStation.h b/src/core/function/GlobalSettingStation.h index 80780f4b..85ac57b4 100644 --- a/src/core/function/GlobalSettingStation.h +++ b/src/core/function/GlobalSettingStation.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,26 +20,24 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GLOBALSETTINGSTATION_H -#define GPGFRONTEND_GLOBALSETTINGSTATION_H +#pragma once -#include <filesystem> - -#include "GpgFrontendBuildInstallInfo.h" -#include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { /** - * @brief + * @class GlobalSettingStation + * @brief Singleton class for managing global settings in the application. * + * This class handles reading and writing of global settings, as well as + * managing application directories and resource paths. */ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation : public SingletonFunctionObject<GlobalSettingStation> { @@ -58,179 +56,60 @@ class GPGFRONTEND_CORE_EXPORT GlobalSettingStation ~GlobalSettingStation() noexcept override; /** - * @brief - * - * @return libconfig::Setting& - */ - libconfig::Setting &GetUISettings() noexcept; - - /** - * @brief + * @brief Get the Settings object * - * @return libconfig::Setting& + * @return QSettings */ - template <typename T> - T LookupSettings(std::string path, T default_value) noexcept { - T value = default_value; - try { - value = static_cast<T>(GetUISettings().lookup(path)); - } catch (...) { - SPDLOG_WARN("setting not found: {}", path); - } - return value; - } + [[nodiscard]] auto GetSettings() const -> QSettings; /** * @brief Get the App Dir object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetAppDir() const { return app_path_; } - - [[nodiscard]] std::filesystem::path GetAppDataPath() const { - return app_data_path_; - } + [[nodiscard]] auto GetAppDir() const -> QString; /** - * @brief Get the Log Dir object - * - * @return std::filesystem::path + * @brief Gets the application data directory. + * @return Path to the application data directory. */ - [[nodiscard]] std::filesystem::path GetLogDir() const { - return app_log_path_; - } + [[nodiscard]] auto GetAppDataPath() const -> QString; /** - * @brief Get the Standalone Database Dir object - * - * @return std::filesystem::path - */ - [[nodiscard]] std::filesystem::path GetStandaloneDatabaseDir() const { - auto db_path = app_configure_path_ / "db"; - if (!std::filesystem::exists(db_path)) { - std::filesystem::create_directory(db_path); - } - return db_path; - } - - [[nodiscard]] std::filesystem::path GetAppConfigPath() const { - return app_configure_path_; - } - - /** - * @brief Get the Standalone Gpg Bin Dir object + * @brief Get the Log Dir object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetStandaloneGpgBinDir() const { - return app_resource_path_ / "gpg1.4" / "gpg"; - } + [[nodiscard]] auto GetLogDir() const -> QString; /** - * @brief Get the Locale Dir object + * @brief Get the Log Files Size object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetLocaleDir() const { - return app_locale_path_; - } + [[nodiscard]] auto GetLogFilesSize() const -> QString; /** - * @brief Get the Resource Dir object + * @brief Get the Data Objects Files Size object * - * @return std::filesystem::path + * @return QString */ - [[nodiscard]] std::filesystem::path GetResourceDir() const { - return app_resource_path_; - } + [[nodiscard]] auto GetDataObjectsFilesSize() const -> QString; /** - * @brief Get the Certs Dir object + * @brief clear all log files * - * @return std::filesystem::path */ - [[nodiscard]] std::filesystem::path GetCertsDir() const { - return app_resource_path_ / "certs"; - } - - [[nodiscard]] std::string GetLogFilesSize() const; - - [[nodiscard]] std::string GetDataObjectsFilesSize() const; - void ClearAllLogFiles() const; - void ClearAllDataObjects() const; - /** - * @brief sync the settings to the file + * @brief clear all data objects * */ - void SyncSettings() noexcept; + void ClearAllDataObjects() const; private: - std::filesystem::path app_path_ = QCoreApplication::applicationDirPath() - .toStdString(); ///< Program Location - std::filesystem::path app_data_path_ = - QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) - .toStdString(); ///< Program Data Location - std::filesystem::path app_log_path_ = - app_data_path_ / "logs"; ///< Program Data Location - std::filesystem::path app_data_objs_path_ = - app_data_path_ / "data_objs"; ///< Object storage path - -#ifdef LINUX_INSTALL_BUILD - std::filesystem::path app_resource_path_ = - std::filesystem::path(APP_LOCALSTATE_PATH) / - "gpgfrontend"; ///< Program Data Location -#else - std::filesystem::path app_resource_path_ = - RESOURCE_DIR_BOOST_PATH(app_path_); ///< Program Data Location -#endif - -#ifdef LINUX_INSTALL_BUILD - std::filesystem::path app_locale_path_ = - std::string(APP_LOCALE_PATH); ///< Program Data Location -#else - std::filesystem::path app_locale_path_ = - app_resource_path_ / "locales"; ///< Program Data Location -#endif - - std::filesystem::path app_configure_path_ = - QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) - .toStdString(); ///< Program Configure Location - std::filesystem::path ui_config_dir_path_ = - app_configure_path_ / "conf"; ///< Configure File Directory Location - std::filesystem::path ui_config_path_ = - ui_config_dir_path_ / "main.cfg"; ///< Main Configure File Location - - libconfig::Config ui_cfg_; ///< UI Configure File - - /** - * @brief - * - */ - void init_app_secure_key(); - - /** - * @brief - * - */ - int64_t get_files_size_at_path(std::filesystem::path path, - std::string filename_pattern) const; - - /** - * @brief - * - */ - std::string get_human_readable_size(int64_t size) const; - - /** - * @brief - * - */ - void delete_all_files(std::filesystem::path path, - std::string filename_pattern) const; + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GLOBALSETTINGSTATION_H diff --git a/src/core/function/KeyPackageOperator.cpp b/src/core/function/KeyPackageOperator.cpp index 5c917ab8..abb84512 100644 --- a/src/core/function/KeyPackageOperator.cpp +++ b/src/core/function/KeyPackageOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,71 +28,88 @@ #include "KeyPackageOperator.h" -#include "FileOperator.h" -#include "function/PassphraseGenerator.h" -#include "function/gpg/GpgKeyGetter.h" -#include "function/gpg/GpgKeyImportExporter.h" -#include "qt-aes/qaesencryption.h" +#include <qt-aes/qaesencryption.h> + +#include "core/function/KeyPackageOperator.h" +#include "core/function/PassphraseGenerator.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/typedef/CoreTypedef.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" namespace GpgFrontend { -bool KeyPackageOperator::GeneratePassphrase( - const std::filesystem::path& phrase_path, std::string& phrase) { +auto KeyPackageOperator::GeneratePassphrase(const QString& phrase_path, + QString& phrase) -> bool { phrase = PassphraseGenerator::GetInstance().Generate(256); - SPDLOG_DEBUG("generated passphrase: {} bytes", phrase.size()); - return FileOperator::WriteFileStd(phrase_path, phrase); + GF_CORE_LOG_DEBUG("generated passphrase: {} bytes", phrase.size()); + return WriteFile(phrase_path, phrase.toUtf8()); } -bool KeyPackageOperator::GenerateKeyPackage( - const std::filesystem::path& key_package_path, - const std::string& key_package_name, KeyIdArgsListPtr& key_ids, - std::string& phrase, bool secret) { - SPDLOG_DEBUG("generating key package: {}", key_package_name); - - ByteArrayPtr key_export_data = nullptr; - if (!GpgKeyImportExporter::GetInstance().ExportAllKeys( - key_ids, key_export_data, secret)) { - SPDLOG_ERROR("failed to export keys"); - return false; - } - - auto key = QByteArray::fromStdString(phrase); - auto data = QString::fromStdString(*key_export_data).toLocal8Bit().toBase64(); - - auto hash_key = QCryptographicHash::hash(key, QCryptographicHash::Sha256); - QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, - QAESEncryption::Padding::ISO); - auto encoded = encryption.encode(data, hash_key); - - SPDLOG_DEBUG("writing key package: {}", key_package_name); - return FileOperator::WriteFileStd(key_package_path, encoded.toStdString()); +void KeyPackageOperator::GenerateKeyPackage(const QString& key_package_path, + const QString& key_package_name, + const KeyArgsList& keys, + QString& phrase, bool secret, + const OperationCallback& cb) { + GF_CORE_LOG_DEBUG("generating key package: {}", key_package_name); + + GpgKeyImportExporter::GetInstance().ExportKeys( + keys, secret, true, false, false, + [=](GpgError err, const DataObjectPtr& data_obj) { + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + GF_LOG_ERROR("export keys error, reason: {}", + DescribeGpgErrCode(err).second); + cb(-1, data_obj); + return; + } + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GFBuffer>()) { + cb(-1, data_obj); + return; + } + + auto gf_buffer = ExtractParams<GFBuffer>(data_obj, 0); + + auto data = gf_buffer.ConvertToQByteArray().toBase64(); + auto hash_key = QCryptographicHash::hash(phrase.toUtf8(), + QCryptographicHash::Sha256); + QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, + QAESEncryption::Padding::ISO); + auto encoded_data = encryption.encode(data, hash_key); + GF_CORE_LOG_DEBUG("writing key package, name: {}", key_package_name); + + cb(WriteFile(key_package_path, encoded_data) ? 0 : -1, + TransferParams()); + return; + }); } -bool KeyPackageOperator::ImportKeyPackage( - const std::filesystem::path& key_package_path, - const std::filesystem::path& phrase_path, - GpgFrontend::GpgImportInformation& import_info) { - SPDLOG_DEBUG("importing key package: {]", key_package_path.u8string()); +auto KeyPackageOperator::ImportKeyPackage(const QString& key_package_path, + const QString& phrase_path) + -> std::tuple<bool, std::shared_ptr<GpgImportInformation>> { + GF_CORE_LOG_DEBUG("importing key package: {}", key_package_path); - std::string encrypted_data; - FileOperator::ReadFileStd(key_package_path, encrypted_data); + QByteArray encrypted_data; + ReadFile(key_package_path, encrypted_data); - if (encrypted_data.empty()) { - SPDLOG_ERROR("failed to read key package: {}", key_package_path.u8string()); - return false; + if (encrypted_data.isEmpty()) { + GF_CORE_LOG_ERROR("failed to read key package: {}", key_package_path); + return {false, nullptr}; }; - std::string passphrase; - FileOperator::ReadFileStd(phrase_path, passphrase); - SPDLOG_DEBUG("passphrase: {} bytes", passphrase.size()); + QByteArray passphrase; + ReadFile(phrase_path, passphrase); + GF_CORE_LOG_DEBUG("passphrase: {} bytes", passphrase.size()); if (passphrase.size() != 256) { - SPDLOG_ERROR("failed to read passphrase: {}", phrase_path.u8string()); - return false; + GF_CORE_LOG_ERROR("failed to read passphrase: {}", phrase_path); + return {false, nullptr}; } - auto hash_key = QCryptographicHash::hash( - QByteArray::fromStdString(passphrase), QCryptographicHash::Sha256); - auto encoded = QByteArray::fromStdString(encrypted_data); + auto hash_key = + QCryptographicHash::hash(passphrase, QCryptographicHash::Sha256); + auto encoded = encrypted_data; QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); @@ -100,20 +117,30 @@ bool KeyPackageOperator::ImportKeyPackage( auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key)); auto key_data = QByteArray::fromBase64(decoded); - SPDLOG_DEBUG("key data size: {}", key_data.size()); - if (!key_data.startsWith(GpgConstants::PGP_PUBLIC_KEY_BEGIN) && - !key_data.startsWith(GpgConstants::PGP_PRIVATE_KEY_BEGIN)) { - return false; + GF_CORE_LOG_DEBUG("import key package, read key data size: {}", + key_data.size()); + if (!key_data.startsWith(PGP_PUBLIC_KEY_BEGIN) && + !key_data.startsWith(PGP_PRIVATE_KEY_BEGIN)) { + return {false, nullptr}; } - auto key_data_ptr = std::make_unique<ByteArray>(key_data.toStdString()); - import_info = - GpgKeyImportExporter::GetInstance().ImportKey(std::move(key_data_ptr)); - return true; + auto import_info = + GpgKeyImportExporter::GetInstance().ImportKey(GFBuffer(key_data)); + return {true, import_info}; } -std::string KeyPackageOperator::GenerateKeyPackageName() { +auto KeyPackageOperator::GenerateKeyPackageName() -> QString { return generate_key_package_name(); } +/** + * @brief generate key package name + * + * @return QString key package name + */ +auto KeyPackageOperator::generate_key_package_name() -> QString { + return QString("KeyPackage_%1") + .arg(QRandomGenerator::global()->bounded(999, 99999)); +} + } // namespace GpgFrontend diff --git a/src/core/function/KeyPackageOperator.h b/src/core/function/KeyPackageOperator.h index 00b0dbaa..968e14f5 100644 --- a/src/core/function/KeyPackageOperator.h +++ b/src/core/function/KeyPackageOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYPACKAGEOPERATOR_H -#define GPGFRONTEND_KEYPACKAGEOPERATOR_H +#pragma once -#include "core/GpgFrontendCore.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { @@ -48,15 +47,15 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if passphrase was generated and saved * @return false if passphrase was not generated and saved */ - static bool GeneratePassphrase(const std::filesystem::path &phrase_path, - std::string &phrase); + static auto GeneratePassphrase(const QString &phrase_path, QString &phrase) + -> bool; /** * @brief generate the name of the key package * - * @return std::string name of the key package + * @return QString name of the key package */ - static std::string GenerateKeyPackageName(); + static auto GenerateKeyPackageName() -> QString; /** * @brief generate key package @@ -69,10 +68,10 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if key package was generated * @return false if key package was not generated */ - static bool GenerateKeyPackage(const std::filesystem::path &key_package_path, - const std::string &key_package_name, - KeyIdArgsListPtr &key_ids, std::string &phrase, - bool secret); + static void GenerateKeyPackage(const QString &key_package_path, + const QString &key_package_name, + const KeyArgsList &keys, QString &phrase, + bool secret, const OperationCallback &cb); /** * @brief import key package @@ -83,25 +82,16 @@ class GPGFRONTEND_CORE_EXPORT KeyPackageOperator { * @return true if key package was imported * @return false if key package was not imported */ - static bool ImportKeyPackage(const std::filesystem::path &key_package_path, - const std::filesystem::path &phrase_path, - GpgFrontend::GpgImportInformation &import_info); + static auto ImportKeyPackage(const QString &key_package_path, + const QString &phrase_path) + -> std::tuple<bool, std::shared_ptr<GpgImportInformation>>; private: /** * @brief generate key package name * - * @return std::string key package name + * @return QString key package name */ - static std::string generate_key_package_name() { - std::random_device rd_; ///< Random device - auto mt_ = std::mt19937(rd_()); ///< Mersenne twister - - std::uniform_int_distribution<int> dist(999, 99999); - auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); - return file_string.str(); - } + static auto generate_key_package_name() -> QString; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_KEYPACKAGEOPERATOR_H diff --git a/src/core/function/LoggerManager.cpp b/src/core/function/LoggerManager.cpp new file mode 100644 index 00000000..3b88e4f0 --- /dev/null +++ b/src/core/function/LoggerManager.cpp @@ -0,0 +1,155 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "LoggerManager.h" + +#include <spdlog/async.h> +#include <spdlog/common.h> +#include <spdlog/sinks/rotating_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + +#include "core/function/GlobalSettingStation.h" + +namespace GpgFrontend { + +std::shared_ptr<spdlog::logger> LoggerManager::default_logger = nullptr; +spdlog::level::level_enum LoggerManager::default_log_level = + spdlog::level::debug; + +LoggerManager::LoggerManager(int channel) + : SingletonFunctionObject<LoggerManager>(channel) { + spdlog::init_thread_pool(1024, 2); + spdlog::flush_every(std::chrono::seconds(5)); +} + +LoggerManager::~LoggerManager() { +#ifdef WINDOWS + // Under VisualStudio, this must be called before main finishes to workaround + // a known VS issue + spdlog::drop_all(); + spdlog::shutdown(); +#endif + + if (default_logger) default_logger = nullptr; +} + +auto LoggerManager::GetLogger(const QString& id) + -> std::shared_ptr<spdlog::logger> { + auto m_it = logger_map_.find(id); + if (m_it == logger_map_.end()) return GetDefaultLogger(); + return m_it->second; +} + +auto LoggerManager::RegisterAsyncLogger(const QString& id, + spdlog::level::level_enum level) + -> std::shared_ptr<spdlog::logger> { + // get the log directory + auto log_file_path = + GlobalSettingStation::GetInstance().GetLogDir() + "/" + id + ".log"; + + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::rotating_file_sink_mt>( + log_file_path.toUtf8().constData(), 1048576 * 32, 8)); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::async_logger>( + id.toStdString(), begin(sinks), end(sinks), spdlog::thread_pool()); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(level); + + // flush policy +#ifdef DEBUG + logger->flush_on(spdlog::level::trace); +#else + core_logger->flush_on(spdlog::level::err); +#endif + + logger_map_[id] = logger; + return logger; +} + +auto LoggerManager::RegisterSyncLogger(const QString& id, + spdlog::level::level_enum level) + -> std::shared_ptr<spdlog::logger> { + // get the log directory + auto log_file_path = + GlobalSettingStation::GetInstance().GetLogDir() + "/" + id + ".log"; + + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::rotating_file_sink_mt>( + log_file_path.toUtf8().constData(), 1048576 * 32, 8)); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::logger>( + id.toStdString(), begin(sinks), end(sinks)); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(level); + + logger_map_[id] = logger; + return logger; +} + +auto LoggerManager::GetDefaultLogger() -> std::shared_ptr<spdlog::logger> { + if (default_logger == nullptr) { + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(GpgFrontend::SecureCreateSharedObject< + spdlog::sinks::stderr_color_sink_mt>()); + + // logger + auto logger = GpgFrontend::SecureCreateSharedObject<spdlog::logger>( + "default", begin(sinks), end(sinks)); + logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=6n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + + // set the level of logger + logger->set_level(default_log_level); + spdlog::set_default_logger(logger); + default_logger = logger; + } + return default_logger; +} + +void LoggerManager::SetDefaultLogLevel(spdlog::level::level_enum level) { + default_log_level = level; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/LoggerManager.h b/src/core/function/LoggerManager.h new file mode 100644 index 00000000..78fecc3c --- /dev/null +++ b/src/core/function/LoggerManager.h @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/basic/GpgFunctionObject.h" + +namespace spdlog { +class logger; +} + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT LoggerManager + : public SingletonFunctionObject<LoggerManager> { + public: + explicit LoggerManager(int channel); + + ~LoggerManager() override; + + auto RegisterAsyncLogger(const QString& id, spdlog::level::level_enum) + -> std::shared_ptr<spdlog::logger>; + + auto RegisterSyncLogger(const QString& id, spdlog::level::level_enum) + -> std::shared_ptr<spdlog::logger>; + + auto GetLogger(const QString& id) -> std::shared_ptr<spdlog::logger>; + + static auto GetDefaultLogger() -> std::shared_ptr<spdlog::logger>; + + static void SetDefaultLogLevel(spdlog::level::level_enum); + + private: + static spdlog::level::level_enum default_log_level; + static std::shared_ptr<spdlog::logger> default_logger; + + std::map<QString, std::shared_ptr<spdlog::logger>> logger_map_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/PassphraseGenerator.cpp b/src/core/function/PassphraseGenerator.cpp index de963fa1..b7f1e877 100644 --- a/src/core/function/PassphraseGenerator.cpp +++ b/src/core/function/PassphraseGenerator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,10 +20,30 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "PassphraseGenerator.h" + +namespace GpgFrontend { + +auto PassphraseGenerator::Generate(int len) -> QString { + auto file_string = QString("KeyPackage_%1") + .arg(QRandomGenerator::global()->bounded(999, 99999)); + static const char kAlphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + QString tmp_str; + tmp_str.reserve(len); + + for (int i = 0; i < len; ++i) { + tmp_str += kAlphanum[QRandomGenerator::global()->bounded( + static_cast<quint32>(sizeof(kAlphanum)))]; + } + return tmp_str; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/PassphraseGenerator.h b/src/core/function/PassphraseGenerator.h index a61356fe..2e5925b6 100644 --- a/src/core/function/PassphraseGenerator.h +++ b/src/core/function/PassphraseGenerator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,15 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_PASSPHRASEGENERATOR_H -#define GPGFRONTEND_PASSPHRASEGENERATOR_H +#pragma once -#include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" namespace GpgFrontend { @@ -55,29 +53,13 @@ class GPGFRONTEND_CORE_EXPORT PassphraseGenerator * @brief generate passphrase * * @param len length of the passphrase - * @return std::string passphrase + * @return QString passphrase */ - std::string Generate(int len) { - std::uniform_int_distribution<int> dist(999, 99999); - - auto file_string = boost::format("KeyPackage_%1%") % dist(mt_); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - std::string tmp_str; - tmp_str.reserve(len); - - for (int i = 0; i < len; ++i) { - tmp_str += alphanum[dist(mt_) % (sizeof(alphanum) - 1)]; - } - return tmp_str; - } + auto Generate(int len) -> QString; + private: std::random_device rd_; ///< Random device std::mt19937 mt_ = std::mt19937(rd_()); ///< Mersenne twister }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_PASSPHRASEGENERATOR_H diff --git a/src/core/function/SecureMemoryAllocator.cpp b/src/core/function/SecureMemoryAllocator.cpp new file mode 100644 index 00000000..692c36c5 --- /dev/null +++ b/src/core/function/SecureMemoryAllocator.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SecureMemoryAllocator.h" + +#ifndef MACOS +#include <mimalloc.h> +#endif + +namespace GpgFrontend { + +auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* { +#ifndef MACOS + auto* addr = mi_malloc(size); +#else + auto* addr = malloc(size); +#endif + return addr; +} + +auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* { +#ifndef MACOS + auto* addr = mi_realloc(ptr, size); +#else + auto* addr = realloc(ptr, size); +#endif + return addr; +} + +void SecureMemoryAllocator::Deallocate(void* p) { +#ifndef MACOS + mi_free(p); +#else + free(p); +#endif +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/SecureMemoryAllocator.h b/src/core/function/SecureMemoryAllocator.h new file mode 100644 index 00000000..e9f1c1c3 --- /dev/null +++ b/src/core/function/SecureMemoryAllocator.h @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT SecureMemoryAllocator { + public: + static auto Allocate(std::size_t) -> void *; + + static auto Reallocate(void *, std::size_t) -> void *; + + static void Deallocate(void *); +}; + +template <typename T> +struct SecureObjectDeleter { + void operator()(T *ptr) { + if (ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + } + } +}; + +template <typename T> +using SecureUniquePtr = std::unique_ptr<T, SecureObjectDeleter<T>>; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/ChannelObject.cpp b/src/core/function/basic/ChannelObject.cpp new file mode 100644 index 00000000..18449ddb --- /dev/null +++ b/src/core/function/basic/ChannelObject.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "ChannelObject.h" + +#include <iostream> + +namespace GpgFrontend { + +ChannelObject::ChannelObject() noexcept = default; + +ChannelObject::ChannelObject(int channel, QString type) + : channel_(channel), type_(std::move(type)) {} + +#ifdef DEBUG +ChannelObject::~ChannelObject() noexcept { + // using iostream instead of spdlog bacause at this time spdlog may have + // already been destroyed. + QTextStream(stdout) << "releasing channel object: " << this->type_ + << Qt::endl; +} +#else +ChannelObject::~ChannelObject() noexcept = default; +#endif + +void ChannelObject::SetChannel(int channel) { this->channel_ = channel; } + +auto ChannelObject::GetChannel() const -> int { return channel_; } + +auto ChannelObject::GetDefaultChannel() -> int { + return kGpgFrontendDefaultChannel; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/ChannelObject.h b/src/core/function/basic/ChannelObject.h new file mode 100644 index 00000000..27be55c4 --- /dev/null +++ b/src/core/function/basic/ChannelObject.h @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgConstants.h" +#include "core/function/SecureMemoryAllocator.h" +namespace GpgFrontend { + +/** + * @brief object which in channel system is called "channel" + * + */ +class GPGFRONTEND_CORE_EXPORT ChannelObject { + public: + /** + * @brief Construct a new Default Channel Object object + * + */ + ChannelObject() noexcept; + + /** + * @brief Destroy the Channel Object object + * + */ + virtual ~ChannelObject() noexcept; + + /** + * @brief Construct a new Channel Object object + * + * @param channel + */ + explicit ChannelObject(int channel, QString type); + + /** + * @brief Get the Default Channel object + * + * @return int + */ + static auto GetDefaultChannel() -> int; + + /** + * @brief Get the Channel object + * + * @return int + */ + [[nodiscard]] auto GetChannel() const -> int; + + /** + * @brief Set the Channel object + * + * @param channel + */ + void SetChannel(int channel); + + private: + int channel_ = kGpgFrontendDefaultChannel; ///< The channel id + QString type_; +}; + +template <typename Derived> +auto ConvertToChannelObjectPtr( + std::unique_ptr<Derived, SecureObjectDeleter<Derived>> derivedPtr) + -> std::unique_ptr<ChannelObject, SecureObjectDeleter<ChannelObject>> { + static_assert(std::is_base_of_v<ChannelObject, Derived>, + "Derived must be a subclass of ChannelObject"); + + ChannelObject* base_ptr = derivedPtr.release(); + return std::unique_ptr<ChannelObject, SecureObjectDeleter<ChannelObject>>( + base_ptr); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/GpgFunctionObject.cpp b/src/core/function/basic/GpgFunctionObject.cpp new file mode 100644 index 00000000..e9e444f1 --- /dev/null +++ b/src/core/function/basic/GpgFunctionObject.cpp @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgFunctionObject.h" + +#include <map> +#include <mutex> +#include <typeinfo> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/ChannelObject.h" + +struct FunctionObjectTypeLockInfo { + std::map<int, std::mutex> channel_lock_map; + std::mutex type_lock; +}; + +std::mutex g_function_object_mutex_map_lock; +std::map<size_t, FunctionObjectTypeLockInfo> g_function_object_mutex_map; + +namespace GpgFrontend { +auto GetGlobalFunctionObjectChannelLock(const std::type_info& type, int channel) + -> std::mutex& { + std::lock_guard<std::mutex> lock_guard(g_function_object_mutex_map_lock); + auto& channel_map = g_function_object_mutex_map[type.hash_code()]; + return channel_map.channel_lock_map[channel]; +} + +auto GetGlobalFunctionObjectTypeLock(const std::type_info& type) + -> std::mutex& { + std::lock_guard<std::mutex> lock_guard(g_function_object_mutex_map_lock); + auto& channel_map = g_function_object_mutex_map[type.hash_code()]; + return channel_map.type_lock; +} + +/** + * @brief Get the Instance object + * + * @param channel + * @return T& + */ +auto GetChannelObjectInstance(const std::type_info& type, int channel) + -> ChannelObject* { + GF_DEFAULT_LOG_TRACE("try to get instance of type: {} at channel: {}", + type.name(), channel); + + // lock this channel + std::lock_guard<std::mutex> guard( + GetGlobalFunctionObjectChannelLock(type, channel)); + + auto* p_storage = + SingletonStorageCollection::GetInstance(false)->GetSingletonStorage(type); + GF_DEFAULT_LOG_TRACE("get singleton storage result, p_storage: {}", + static_cast<void*>(p_storage)); + + auto* p_pbj = + static_cast<ChannelObject*>(p_storage->FindObjectInChannel(channel)); + GF_DEFAULT_LOG_TRACE("find channel object result, channel {}, p_pbj: {}", + channel, static_cast<void*>(p_pbj)); + + return p_pbj; +} + +auto CreateChannelObjectInstance(const std::type_info& type, int channel, + SecureUniquePtr<ChannelObject> channel_object) + -> ChannelObject* { + // lock this channel + std::lock_guard<std::mutex> guard( + GetGlobalFunctionObjectChannelLock(type, channel)); + + auto* p_storage = + SingletonStorageCollection::GetInstance(false)->GetSingletonStorage(type); + GF_DEFAULT_LOG_TRACE("create channel object, channel {}, type: {}", channel, + type.name()); + + // do create object of this channel + return p_storage->SetObjectInChannel(channel, std::move(channel_object)); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/GpgFunctionObject.h b/src/core/function/basic/GpgFunctionObject.h new file mode 100644 index 00000000..1ea352b6 --- /dev/null +++ b/src/core/function/basic/GpgFunctionObject.h @@ -0,0 +1,194 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <mutex> +#include <stdexcept> + +#include "core/GpgFrontendCoreExport.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/function/basic/SingletonStorageCollection.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +auto GPGFRONTEND_CORE_EXPORT GetChannelObjectInstance( + const std::type_info& type, int channel) -> ChannelObject*; + +auto GPGFRONTEND_CORE_EXPORT CreateChannelObjectInstance( + const std::type_info& type, int channel, + SecureUniquePtr<ChannelObject> channel_object) -> ChannelObject*; + +auto GPGFRONTEND_CORE_EXPORT +GetGlobalFunctionObjectTypeLock(const std::type_info& type) -> std::mutex&; + +/** + * @brief + * + * @tparam T + */ +template <typename T> +class SingletonFunctionObject : public ChannelObject { + public: + /** + * @brief prohibit copy + * + */ + SingletonFunctionObject(const SingletonFunctionObject<T>&) = delete; + + /** + * @brief prohibit copy + * + * @return SingletonFunctionObject& + */ + auto operator=(const SingletonFunctionObject<T>&) + -> SingletonFunctionObject& = delete; + + /** + * @brief Get the Instance object + * + * @param channel + * @return T& + */ + static auto GetInstance(int channel = GpgFrontend::kGpgFrontendDefaultChannel) + -> T& { + static_assert(std::is_base_of_v<SingletonFunctionObject<T>, T>, + "T not derived from SingletonFunctionObject<T>"); + + const auto& type = typeid(T); + std::lock_guard<std::mutex> guard(GetGlobalFunctionObjectTypeLock(type)); + auto* channel_object = GetChannelObjectInstance(type, channel); + if (channel_object == nullptr) { + channel_object = CreateChannelObjectInstance( + type, channel, + ConvertToChannelObjectPtr(SecureCreateUniqueObject<T>(channel))); + } + return *static_cast<T*>(channel_object); + } + + /** + * @brief Create a Instance object + * + * @param channel + * @param factory + * @return T& + */ + static auto CreateInstance( + int channel, const std::function<ChannelObjectPtr(void)>& factory) -> T& { + static_assert(std::is_base_of_v<SingletonFunctionObject<T>, T>, + "T not derived from SingletonFunctionObject<T>"); + + const auto& type = typeid(T); + std::lock_guard<std::mutex> guard(GetGlobalFunctionObjectTypeLock(type)); + return *static_cast<T*>( + CreateChannelObjectInstance(type, channel, factory())); + } + + /** + * @brief + * + * @param channel + * @return T& + */ + static void ReleaseChannel(int channel) { + SingletonStorageCollection::GetInstance(false) + ->GetSingletonStorage(typeid(T)) + ->ReleaseChannel(channel); + } + + /** + * @brief Get the Default Channel object + * + * @return int + */ + static auto GetDefaultChannel() -> int { + return ChannelObject::GetDefaultChannel(); + } + + /** + * @brief Get the Channel object + * + * @return int + */ + [[nodiscard]] auto GetChannel() const -> int { + return ChannelObject::GetChannel(); + } + + /** + * @brief Get all the channel ids + * + * @return std::vector<int> + */ + static auto GetAllChannelId() -> std::vector<int> { + return SingletonStorageCollection::GetInstance(false) + ->GetSingletonStorage(typeid(T)) + ->GetAllChannelId(); + } + + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject(T&&) = delete; + + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject(const T&) = delete; + + /** + * @brief + * + */ + void operator=(const T&) = delete; + + protected: + /** + * @brief Construct a new Singleton Function Object object + * + */ + SingletonFunctionObject() = default; + + /** + * @brief Construct a new Singleton Function Object object + * + * @param channel + */ + explicit SingletonFunctionObject(int channel) + : ChannelObject(channel, typeid(T).name()) {} + + /** + * @brief Destroy the Singleton Function Object object + * + */ + virtual ~SingletonFunctionObject() = default; +}; +} // namespace GpgFrontend diff --git a/src/core/function/basic/SingletonStorage.cpp b/src/core/function/basic/SingletonStorage.cpp new file mode 100644 index 00000000..eab71e0f --- /dev/null +++ b/src/core/function/basic/SingletonStorage.cpp @@ -0,0 +1,133 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SingletonStorage.h" + +#include <shared_mutex> + +#include "core/function/basic/ChannelObject.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend { + +class SingletonStorage::Impl { + public: + void ReleaseChannel(int channel) { + decltype(instances_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(instances_mutex_); + ins_it = instances_map_.find(channel); + } + if (ins_it != instances_map_.end()) instances_map_.erase(ins_it); + } + + auto FindObjectInChannel(int channel) -> GpgFrontend::ChannelObject* { + // read instances_map_ + decltype(instances_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(instances_mutex_); + ins_it = instances_map_.find(channel); + if (ins_it == instances_map_.end()) { + GF_DEFAULT_LOG_TRACE("cannot find channel object, channel: {}", + channel); + return nullptr; + } + return ins_it->second.get(); + } + } + + auto GetAllChannelId() -> std::vector<int> { + std::vector<int> channels; + channels.reserve(instances_map_.size()); + for (const auto& [key, value] : instances_map_) { + channels.push_back(key); + } + return channels; + } + + auto SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> GpgFrontend::ChannelObject* { + GF_DEFAULT_LOG_TRACE( + "set channel object, type: {} in channel: {}, address: {}", + typeid(p_obj.get()).name(), channel, static_cast<void*>(p_obj.get())); + + assert(p_obj != nullptr); + if (p_obj == nullptr) { + GF_DEFAULT_LOG_ERROR( + "cannot set a nullptr as a channel obejct of channel: {}", channel); + return nullptr; + } + + p_obj->SetChannel(channel); + auto* raw_obj = p_obj.get(); + + { + GF_DEFAULT_LOG_TRACE( + "register channel object to instances map, " + "channel: {}, address: {}", + channel, static_cast<void*>(p_obj.get())); + std::unique_lock<std::shared_mutex> lock(instances_mutex_); + instances_map_[channel] = std::move(p_obj); + } + + GF_DEFAULT_LOG_TRACE( + "set channel: {} success, current channel object address: {}", channel, + static_cast<void*>(raw_obj)); + return raw_obj; + } + + private: + std::shared_mutex instances_mutex_; ///< mutex for _instances_map + std::map<int, ChannelObjectPtr> + instances_map_; ///< map of singleton instances +}; + +SingletonStorage::SingletonStorage() noexcept + : p_(SecureCreateUniqueObject<Impl>()) {} + +SingletonStorage::~SingletonStorage() = default; + +void SingletonStorage::ReleaseChannel(int channel) { + p_->ReleaseChannel(channel); +} + +auto SingletonStorage::FindObjectInChannel(int channel) + -> GpgFrontend::ChannelObject* { + return p_->FindObjectInChannel(channel); +} + +auto SingletonStorage::GetAllChannelId() -> std::vector<int> { + return p_->GetAllChannelId(); +} + +auto SingletonStorage::SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> GpgFrontend::ChannelObject* { + return p_->SetObjectInChannel(channel, std::move(p_obj)); +} + +}; // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorage.h b/src/core/function/basic/SingletonStorage.h new file mode 100644 index 00000000..0ef47443 --- /dev/null +++ b/src/core/function/basic/SingletonStorage.h @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/SecureMemoryAllocator.h" + +namespace GpgFrontend { + +class ChannelObject; + +using ChannelObjectPtr = SecureUniquePtr<ChannelObject>; + +class GPGFRONTEND_CORE_EXPORT SingletonStorage { + public: + /** + * @brief + * + */ + SingletonStorage() noexcept; + + /** + * @brief + * + */ + ~SingletonStorage(); + + /** + * @brief + * + * @param channel + */ + void ReleaseChannel(int channel); + + /** + * @brief + * + * @param channel + * @return T* + */ + auto FindObjectInChannel(int channel) -> ChannelObject*; + + /** + * @brief Get all the channel ids + * + * @return std::vector<int> + */ + auto GetAllChannelId() -> std::vector<int>; + + /** + * @brief Set a new object in channel object + * + * @param channel + * @param p_obj + * @return T* + */ + auto SetObjectInChannel(int channel, ChannelObjectPtr p_obj) + -> ChannelObject*; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorageCollection.cpp b/src/core/function/basic/SingletonStorageCollection.cpp new file mode 100644 index 00000000..c22b5242 --- /dev/null +++ b/src/core/function/basic/SingletonStorageCollection.cpp @@ -0,0 +1,124 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SingletonStorageCollection.h" + +#include <memory> +#include <shared_mutex> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/SingletonStorage.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +SecureUniquePtr<SingletonStorageCollection> global_instance = nullptr; + +class SingletonStorageCollection::Impl { + public: + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static auto GetInstance(bool force_refresh) -> SingletonStorageCollection* { + if (force_refresh || global_instance == nullptr) { + global_instance = SecureCreateUniqueObject<SingletonStorageCollection>(); + GF_DEFAULT_LOG_TRACE( + "a new global singleton storage collection created, address: {}", + static_cast<void*>(global_instance.get())); + } + return global_instance.get(); + } + + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static void Destroy() { global_instance = nullptr; } + + /** + * @brief Get the Singleton Storage object + * + * @param singleton_function_object + * @return SingletonStorage* + */ + auto GetSingletonStorage(const std::type_info& type_id) -> SingletonStorage* { + const auto hash = type_id.hash_code(); + + while (true) { + decltype(storages_map_.end()) ins_it; + { + std::shared_lock<std::shared_mutex> lock(storages_mutex_); + ins_it = storages_map_.find(hash); + } + if (ins_it == storages_map_.end()) { + auto storage = SecureCreateUniqueObject<SingletonStorage>(); + GF_DEFAULT_LOG_TRACE( + "hash: {} created, singleton storage address: {} type_name: {}", + hash, static_cast<void*>(storage.get()), type_id.name()); + + { + std::unique_lock<std::shared_mutex> lock(storages_mutex_); + storages_map_.insert({hash, std::move(storage)}); + } + continue; + } + return ins_it->second.get(); + } + } + + private: + std::shared_mutex storages_mutex_; ///< mutex for storages_map_ + std::map<size_t, SingletonStoragePtr> storages_map_; +}; + +SingletonStorageCollection::SingletonStorageCollection() noexcept + : p_(SecureCreateUniqueObject<Impl>()) {} + +SingletonStorageCollection::~SingletonStorageCollection() = default; + +auto GpgFrontend::SingletonStorageCollection::GetInstance(bool force_refresh) + -> GpgFrontend::SingletonStorageCollection* { + return Impl::GetInstance(force_refresh); +} + +void SingletonStorageCollection::Destroy() { + GF_DEFAULT_LOG_TRACE( + "global singleton storage collection is about to destroy, address: {}", + static_cast<void*>(global_instance.get())); + return SingletonStorageCollection::Impl::Destroy(); +} + +auto SingletonStorageCollection::GetSingletonStorage( + const std::type_info& type_id) -> GpgFrontend::SingletonStorage* { + return p_->GetSingletonStorage(type_id); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/basic/SingletonStorageCollection.h b/src/core/function/basic/SingletonStorageCollection.h new file mode 100644 index 00000000..38ced83b --- /dev/null +++ b/src/core/function/basic/SingletonStorageCollection.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/SecureMemoryAllocator.h" + +namespace GpgFrontend { +class SingletonStorage; + +using SingletonStoragePtr = + std::unique_ptr<SingletonStorage, SecureObjectDeleter<SingletonStorage>>; + +class GPGFRONTEND_CORE_EXPORT SingletonStorageCollection { + public: + /** + * @brief + * + */ + SingletonStorageCollection() noexcept; + + /** + * @brief + * + */ + ~SingletonStorageCollection(); + + /** + * @brief Get the Instance object + * + * @return SingletonStorageCollection* + */ + static auto GetInstance(bool force_refresh) -> SingletonStorageCollection*; + + /** + * @brief + * + */ + static void Destroy(); + + /** + * @brief Get the Singleton Storage object + * + * @param singleton_function_object + * @return SingletonStorage* + */ + auto GetSingletonStorage(const std::type_info&) -> SingletonStorage*; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp index 2a3bba42..8b60003c 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.cpp +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2023. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +20,10 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // @@ -32,152 +33,189 @@ #include "GpgAdvancedOperator.h" #include "core/function/gpg/GpgCommandExecutor.h" -#include "spdlog/spdlog.h" - -GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel) - : SingletonFunctionObject(channel) {} - -bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload", "gpg-agent"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - SPDLOG_DEBUG("gpgconf reload exit code: {}", exit_code); - success = true; - } - }); - return success; +#include "core/module/ModuleManager.h" + +void GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache( + OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--reload", "gpg-agent"}, + [=](int exit_code, const QString & /*p_out*/, + const QString & /*p_err*/) { + GF_CORE_LOG_DEBUG("gpgconf reload exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--reload"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - return success; +void GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents( + OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--reload"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf reload exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { - bool success = false; - - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--verbose", "--kill", "all"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - return; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - if (!success) return false; - - success &= StartGpgAgent(); - - success &= StartDirmngr(); - - success &= StartKeyBoxd(); - - return success; +void GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--verbose", "--kill", "all"}, + [=](int exit_code, const QString &p_out, const QString &p_err) { + GF_CORE_LOG_DEBUG("gpgconf --kill all command got exit code: {}", + exit_code); + bool success = true; + if (exit_code != 0) { + success = false; + GF_CORE_LOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + + GF_CORE_LOG_DEBUG("gpgconf --kill --all execute result: {}", success); + if (!success) { + GF_CORE_LOG_ERROR( + "restart all component after core initilized failed"); + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", false); + return; + } + + StartGpgAgent([](int err, DataObjectPtr) { + if (err >= 0) { + Module::UpsertRTValue( + "core", "gpg_advanced_operator.restart_gpg_components", true); + return; + } + }); + }}); } -bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgConfPath, {"--apply-defaults"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - } else { - SPDLOG_ERROR( - "gpgconf execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::ResetConfigures(OperationCallback cb) { + const auto gpgconf_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + GF_CORE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + if (gpgconf_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpgconf path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--apply-defaults"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf apply-defaults exit code: {}", exit_code); + cb(exit_code == 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().GpgAgentPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start gpg-agent successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("gpg-agent already started"); - } else { - SPDLOG_ERROR( - "gpg-agent execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartGpgAgent(OperationCallback cb) { + const auto gpg_agent_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.gpg_agent_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg agent path from rt: {}", gpg_agent_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (gpg_agent_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid gpg agent path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {gpg_agent_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().DirmngrPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start dirmngr successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("dirmngr already started"); - } else { - SPDLOG_ERROR( - "dirmngr execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartDirmngr(OperationCallback cb) { + const auto dirmngr_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.dirmngr_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg dirmngr path from rt: {}", dirmngr_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (dirmngr_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid dirmngr path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {dirmngr_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } -bool GpgFrontend::GpgAdvancedOperator::StartKeyBoxd() { - bool success = false; - GpgFrontend::GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().KeyboxdPath, - {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, - [&](int exit_code, const std::string &p_out, const std::string &p_err) { - if (exit_code == 0) { - success = true; - SPDLOG_INFO("start keyboxd successfully"); - } else if (exit_code == 2) { - success = true; - SPDLOG_INFO("keyboxd already started"); - } else { - SPDLOG_ERROR( - "keyboxd execute error, process stderr: {}, process stdout: {}", - p_err, p_out); - return; - } - }); - - return success; +void GpgFrontend::GpgAdvancedOperator::StartKeyBoxd(OperationCallback cb) { + const auto keyboxd_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.keyboxd_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg keyboxd path from rt: {}", keyboxd_path); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_CORE_LOG_DEBUG("got gnupg home path from rt: {}", home_path); + + if (keyboxd_path.isEmpty()) { + GF_CORE_LOG_ERROR("cannot get valid keyboxd path from rt, abort."); + cb(-1, TransferParams()); + return; + } + + GpgFrontend::GpgCommandExecutor::ExecuteSync( + {keyboxd_path, + {"--homedir", home_path, "--daemon"}, + [=](int exit_code, const QString &, const QString &) { + GF_CORE_LOG_DEBUG("gpgconf daemon exit code: {}", exit_code); + cb(exit_code >= 0 ? 0 : -1, TransferParams()); + }}); } diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h index 5325020a..d6b57095 100644 --- a/src/core/function/gpg/GpgAdvancedOperator.h +++ b/src/core/function/gpg/GpgAdvancedOperator.h @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2023. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,42 +20,31 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // // Created by eric on 07.01.2023. // -#ifndef GPGFRONTEND_GPGADVANCEDOPERATOR_H -#define GPGFRONTEND_GPGADVANCEDOPERATOR_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator - : public SingletonFunctionObject<GpgAdvancedOperator> { +class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator { public: /** - * @brief Construct a new Basic Operator object - * - * @param channel Channel corresponding to the context - */ - explicit GpgAdvancedOperator( - int channel = SingletonFunctionObject::GetDefaultChannel()); - - /** * @brief * * @return true * @return false */ - bool ClearGpgPasswordCache(); + static void ClearGpgPasswordCache(OperationCallback); /** * @brief @@ -63,7 +52,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool ReloadGpgComponents(); + static void ReloadGpgComponents(OperationCallback); /** * @brief @@ -71,7 +60,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool RestartGpgComponents(); + static void RestartGpgComponents(); /** * @brief @@ -79,7 +68,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool ResetConfigures(); + static void ResetConfigures(OperationCallback); /** * @brief @@ -87,7 +76,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartGpgAgent(); + static void StartGpgAgent(OperationCallback); /** * @brief @@ -95,7 +84,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartDirmngr(); + static void StartDirmngr(OperationCallback); /** * @brief @@ -103,13 +92,7 @@ class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator * @return true * @return false */ - bool StartKeyBoxd(); - - private: - GpgContext& ctx_ = GpgContext::GetInstance( - SingletonFunctionObject::GetChannel()); ///< Corresponding context + static void StartKeyBoxd(OperationCallback); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGADVANCEDOPERATOR_H diff --git a/src/core/function/gpg/GpgBasicOperator.cpp b/src/core/function/gpg/GpgBasicOperator.cpp index 71f84907..e5916c77 100644 --- a/src/core/function/gpg/GpgBasicOperator.cpp +++ b/src/core/function/gpg/GpgBasicOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,195 +28,213 @@ #include "GpgBasicOperator.h" -#include <vector> +#include <gpg-error.h> -#include "GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgBasicOperator::GpgBasicOperator(int channel) - : SingletonFunctionObject<GpgBasicOperator>(channel) {} - -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Encrypt( - KeyListPtr keys, GpgFrontend::BypeArrayRef in_buffer, - GpgFrontend::ByteArrayPtr& out_buffer, GpgFrontend::GpgEncrResult& result) { - // gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys->size() + 1]; +namespace GpgFrontend { - int index = 0; - for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); +GpgBasicOperator::GpgBasicOperator(int channel) + : SingletonFunctionObject<GpgBasicOperator>(channel) {} - // Last entry data_in array has to be nullptr - recipients[keys->size()] = nullptr; +void GpgBasicOperator::Encrypt(KeyArgsList keys, GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync([=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); - gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( - ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); - std::swap(result, temp_result); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + data_out.Read2GFBuffer()}); - return err; + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Decrypt( - BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, - GpgFrontend::GpgDecrResult& result) { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - err = check_gpg_error(gpgme_op_decrypt(ctx_, data_in, data_out)); - - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); - - auto temp_result = _new_result(gpgme_op_decrypt_result(ctx_)); - std::swap(result, temp_result); - - return err; +void GpgBasicOperator::Decrypt(GFBuffer in_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_buffer); + GpgData data_out; + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + data_out.Read2GFBuffer()}); + + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Verify( - BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer, - GpgVerifyResult& result) const { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()); - GpgData data_out; - - if (sig_buffer != nullptr && sig_buffer->size() > 0) { - GpgData sig_data(sig_buffer->data(), sig_buffer->size()); - err = check_gpg_error(gpgme_op_verify(ctx_, sig_data, data_in, nullptr)); - } else - err = check_gpg_error(gpgme_op_verify(ctx_, data_in, nullptr, data_out)); - - auto temp_result = _new_result(gpgme_op_verify_result(ctx_)); - std::swap(result, temp_result); - - return err; +void GpgBasicOperator::Verify(GFBuffer in_buffer, GFBuffer sig_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_buffer); + GpgData data_out; + + if (!sig_buffer.Empty()) { + GpgData sig_data(sig_buffer); + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), sig_data, + data_in, nullptr)); + } else { + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), data_in, + nullptr, data_out)); + } + + data_object->Swap({ + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_verify", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgBasicOperator::Sign( - KeyListPtr signers, BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - gpgme_sig_mode_t mode, GpgSignResult& result) { - gpgme_error_t err; - - // Set Singers of this opera - SetSigners(*signers); +void GpgBasicOperator::Sign(KeyArgsList signers, GFBuffer in_buffer, + GpgSignMode mode, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (signers.empty()) return GPG_ERR_CANCELED; - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgError err; - err = check_gpg_error(gpgme_op_sign(ctx_, data_in, data_out, mode)); + // Set Singers of this opera + SetSigners(signers, ascii); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_result = _new_result(gpgme_op_sign_result(ctx_)); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_sign(ctx, data_in, data_out, mode)); - std::swap(result, temp_result); - - return err; + data_object->Swap({GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_sign", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgBasicOperator::DecryptVerify( - BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& decrypt_result, GpgVerifyResult& verify_result) { - gpgme_error_t err; - - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - - err = check_gpg_error(gpgme_op_decrypt_verify(ctx_, data_in, data_out)); +void GpgBasicOperator::DecryptVerify(GFBuffer in_buffer, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + GpgData data_in(in_buffer); + GpgData data_out; - auto temp_decr_result = _new_result(gpgme_op_decrypt_result(ctx_)); - std::swap(decrypt_result, temp_decr_result); + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); - auto temp_verify_result = _new_result(gpgme_op_verify_result(ctx_)); - std::swap(verify_result, temp_verify_result); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + data_out.Read2GFBuffer()}); - return err; + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgBasicOperator::EncryptSign( - KeyListPtr keys, KeyListPtr signers, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, GpgEncrResult& encr_result, - GpgSignResult& sign_result) { - gpgme_error_t err; - SetSigners(*signers); +void GpgBasicOperator::EncryptSign(KeyArgsList keys, KeyArgsList signers, + GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty() || signers.empty()) return GPG_ERR_CANCELED; - // gpgme_encrypt_result_t e_result; - gpgme_key_t recipients[keys->size() + 1]; + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); - // set key for user - int index = 0; - for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key); + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); - // Last entry dataIn array has to be nullptr - recipients[keys->size()] = nullptr; + SetSigners(signers, ascii); - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; + GpgData data_in(in_buffer); + GpgData data_out; - // If the last parameter isnt 0, a private copy of data is made - err = check_gpg_error(gpgme_op_encrypt_sign( - ctx_, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out)); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); +} - auto temp_encr_result = _new_result(gpgme_op_encrypt_result(ctx_)); - swap(encr_result, temp_encr_result); - auto temp_sign_result = _new_result(gpgme_op_sign_result(ctx_)); - swap(sign_result, temp_sign_result); +void GpgBasicOperator::SetSigners(const KeyArgsList& signers, bool ascii) { + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); - return err; -} + gpgme_signers_clear(ctx); -void GpgFrontend::GpgBasicOperator::SetSigners(KeyArgsList& signers) { - gpgme_signers_clear(ctx_); for (const GpgKey& key : signers) { - SPDLOG_DEBUG("key fpr: {}", key.GetFingerprint()); + GF_CORE_LOG_DEBUG("key fpr: {}", key.GetFingerprint()); if (key.IsHasActualSigningCapability()) { - SPDLOG_DEBUG("signer"); - auto error = gpgme_signers_add(ctx_, gpgme_key_t(key)); - check_gpg_error(error); + GF_CORE_LOG_DEBUG("signer"); + auto error = gpgme_signers_add(ctx, gpgme_key_t(key)); + CheckGpgError(error); } } - if (signers.size() != gpgme_signers_count(ctx_)) - SPDLOG_DEBUG("not all signers added"); + if (signers.size() != gpgme_signers_count(ctx_.DefaultContext())) + GF_CORE_LOG_DEBUG("not all signers added"); } -std::unique_ptr<GpgFrontend::KeyArgsList> -GpgFrontend::GpgBasicOperator::GetSigners() { - auto count = gpgme_signers_count(ctx_); +auto GpgBasicOperator::GetSigners(bool ascii) -> std::unique_ptr<KeyArgsList> { + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + + auto count = gpgme_signers_count(ctx); auto signers = std::make_unique<std::vector<GpgKey>>(); - for (auto i = 0u; i < count; i++) { - auto key = GpgKey(gpgme_signers_enum(ctx_, i)); + for (auto i = 0U; i < count; i++) { + auto key = GpgKey(gpgme_signers_enum(ctx, i)); signers->push_back(GpgKey(std::move(key))); } return signers; } -gpg_error_t GpgFrontend::GpgBasicOperator::EncryptSymmetric( - GpgFrontend::ByteArray& in_buffer, GpgFrontend::ByteArrayPtr& out_buffer, - GpgFrontend::GpgEncrResult& result) { - // deepcopy from ByteArray to GpgData - GpgData data_in(in_buffer.data(), in_buffer.size()), data_out; - - gpgme_error_t err = check_gpg_error(gpgme_op_encrypt( - ctx_, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); - - auto temp_data_out = data_out.Read2Buffer(); - std::swap(temp_data_out, out_buffer); - - // TODO(Saturneric): maybe a bug of gpgme - if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) { - auto temp_result = _new_result(gpgme_op_encrypt_result(ctx_)); - std::swap(result, temp_result); - } - - return err; +void GpgBasicOperator::EncryptSymmetric(GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_buffer); + GpgData data_out; + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + data_out.Read2GFBuffer()}); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); } +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgBasicOperator.h b/src/core/function/gpg/GpgBasicOperator.h index 696ac9dc..4b1a2688 100644 --- a/src/core/function/gpg/GpgBasicOperator.h +++ b/src/core/function/gpg/GpgBasicOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,20 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H -#define GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -52,19 +53,13 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator int channel = SingletonFunctionObject::GetDefaultChannel()); /** - * @brief Call the interface provided by gpgme for encryption operation + * @brief * * All incoming data pointers out_buffer will be replaced with new valid * values * - * @param keys list of public keys - * @param in_buffer data that needs to be encrypted - * @param out_buffer encrypted data - * @param result the result of the operation - * @return error code */ - gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, GpgEncrResult& result); + void Encrypt(KeyArgsList, GFBuffer, bool, const GpgOperationCallback&); /** * @brief Call the interface provided by GPGME to symmetrical encryption @@ -72,10 +67,10 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param in_buffer Data for encryption * @param out_buffer Encrypted data * @param result Encrypted results - * @return gpg_error_t + * @return GpgError */ - gpg_error_t EncryptSymmetric(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& result); + void EncryptSymmetric(GFBuffer in_buffer, bool ascii, + const GpgOperationCallback& cb); /** * @@ -90,10 +85,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param sign_result Signature result * @return */ - gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers, - BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgEncrResult& encr_result, - GpgSignResult& sign_result); + void EncryptSign(KeyArgsList keys, KeyArgsList signers, GFBuffer in_buffer, + bool ascii, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for decryption operation @@ -103,8 +96,7 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpgme_error_t Decrypt(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& result); + void Decrypt(GFBuffer in_buffer, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme to perform decryption and @@ -116,9 +108,7 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param verify_result the result of the verifying operation * @return error code */ - gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer, - GpgDecrResult& decrypt_result, - GpgVerifyResult& verify_result); + void DecryptVerify(GFBuffer in_buffer, const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for verification operation @@ -128,8 +118,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpgme_error_t Verify(BypeArrayRef in_buffer, ByteArrayPtr& sig_buffer, - GpgVerifyResult& result) const; + void Verify(GFBuffer in_buffer, GFBuffer sig_buffer, + const GpgOperationCallback& cb); /** * @brief Call the interface provided by gpgme for signing operation @@ -151,9 +141,8 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * @param result the result of the operation * @return error code */ - gpg_error_t Sign(KeyListPtr signers, BypeArrayRef in_buffer, - ByteArrayPtr& out_buffer, gpgme_sig_mode_t mode, - GpgSignResult& result); + void Sign(KeyArgsList signers, GFBuffer in_buffer, GpgSignMode mode, + bool ascii, const GpgOperationCallback& cb); /** * @brief Set the private key for signatures, this operation is a global @@ -161,19 +150,17 @@ class GPGFRONTEND_CORE_EXPORT GpgBasicOperator * * @param keys */ - void SetSigners(KeyArgsList& signers); + void SetSigners(const KeyArgsList& signers, bool ascii); /** * @brief Get a global signature private keys that has been set. * * @return Intelligent pointer pointing to the private key list */ - std::unique_ptr<KeyArgsList> GetSigners(); + auto GetSigners(bool ascii) -> std::unique_ptr<KeyArgsList>; private: GpgContext& ctx_ = GpgContext::GetInstance( SingletonFunctionObject::GetChannel()); ///< Corresponding context }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index 86c47c60..8c994515 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,252 +20,231 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgCommandExecutor.h" -#include "GpgFunctionObject.h" +#include "core/model/DataObject.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" -GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel) - : SingletonFunctionObject<GpgCommandExecutor>(channel) {} +namespace GpgFrontend { -void GpgFrontend::GpgCommandExecutor::Execute( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); +auto BuildTaskFromExecCtx(const GpgCommandExecutor::ExecuteContext &context) + -> Thread::Task * { + const auto &cmd = context.cmd; + const auto &arguments = context.arguments; + const auto &interact_function = context.int_func; + const auto &cmd_executor_callback = context.cb_func; - Thread::Task::TaskCallback result_callback = - [](int rtn, Thread::Task::DataObjectPtr data_object) { - SPDLOG_DEBUG("data object use count: {}", data_object.use_count()); - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); + const QString joined_argument = QStringList::fromVector(arguments).join(" "); + + GF_CORE_LOG_DEBUG("building task: called cmd {} arguments size: {}", cmd, + arguments.size()); - auto exit_code = data_object->PopObject<int>(); - auto process_stdout = data_object->PopObject<std::string>(); - auto process_stderr = data_object->PopObject<std::string>(); - auto callback = data_object->PopObject< - std::function<void(int, std::string, std::string)>>(); + Thread::Task::TaskCallback result_callback = + [cmd, joined_argument](int /*rtn*/, const DataObjectPtr &data_object) { + GF_CORE_LOG_DEBUG( + "data object args count of cmd executor result callback: {}", + data_object->GetObjectSize()); + if (!data_object->Check<int, QString, GpgCommandExecutorCallback>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + return; + } + + auto exit_code = ExtractParams<int>(data_object, 0); + auto process_stdout = ExtractParams<QString>(data_object, 1); + auto callback = + ExtractParams<GpgCommandExecutorCallback>(data_object, 2); // call callback - callback(exit_code, process_stdout, process_stderr); + GF_CORE_LOG_DEBUG( + "calling custom callback from caller of cmd {} {}, " + "exit_code: {}", + cmd, joined_argument, exit_code); + callback(exit_code, process_stdout, {}); }; Thread::Task::TaskRunnable runner = - [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { - SPDLOG_DEBUG("process runner called, data object size: {}", - data_object->GetObjectSize()); + [joined_argument](const DataObjectPtr &data_object) -> int { + GF_CORE_LOG_DEBUG("process runner called, data object size: {}", + data_object->GetObjectSize()); - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); + if (!data_object->Check<QString, QStringList, GpgCommandExecutorInteractor, + GpgCommandExecutorCallback>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + return -1; + } // get arguments - auto cmd = data_object->PopObject<std::string>(); - SPDLOG_DEBUG("get cmd: {}", cmd); - auto arguments = data_object->PopObject<std::vector<std::string>>(); + auto cmd = ExtractParams<QString>(data_object, 0); + auto arguments = ExtractParams<QStringList>(data_object, 1); auto interact_func = - data_object->PopObject<std::function<void(QProcess *)>>(); + ExtractParams<GpgCommandExecutorInteractor>(data_object, 2); + auto callback = ExtractParams<GpgCommandExecutorCallback>(data_object, 3); + // create process auto *cmd_process = new QProcess(); + // move to current thread + // + cmd_process->moveToThread(QThread::currentThread()); + // set process channel mode + // this is to make sure we can get all output from stdout and stderr cmd_process->setProcessChannelMode(QProcess::MergedChannels); + cmd_process->setProgram(cmd); + + // set arguments + QStringList q_arguments; + for (const auto &argument : arguments) { + q_arguments.append(argument); + } + cmd_process->setArguments(q_arguments); - QObject::connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); + QObject::connect( + cmd_process, &QProcess::started, [cmd, joined_argument]() -> void { + GF_CORE_LOG_DEBUG( + "\n== Process Execute Started ==\nCommand: {}\nArguments: " + "{}\n========================", + cmd, joined_argument); + }); QObject::connect( cmd_process, &QProcess::readyReadStandardOutput, [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - SPDLOG_ERROR("error in executing command: {} error: {}", - cmd, error); - }); QObject::connect( - cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), - [=](int, QProcess::ExitStatus status) { - if (status == QProcess::NormalExit) - SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); - else - SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); + cmd_process, &QProcess::errorOccurred, + [=](QProcess::ProcessError error) { + GF_CORE_LOG_ERROR( + "caught error while executing command: {} {}, error: {}", cmd, + joined_argument, error); }); - cmd_process->setProgram(QString::fromStdString(cmd)); - - QStringList q_arguments; - for (const auto &argument : arguments) - q_arguments.append(QString::fromStdString(argument)); - cmd_process->setArguments(q_arguments); - - SPDLOG_DEBUG("process execute ready, cmd: {} {}", cmd, - q_arguments.join(" ").toStdString()); + GF_CORE_LOG_DEBUG( + "\n== Process Execute Ready ==\nCommand: {}\nArguments: " + "{}\n========================", + cmd, joined_argument); cmd_process->start(); cmd_process->waitForFinished(); - std::string process_stdout = - cmd_process->readAllStandardOutput().toStdString(), - process_stderr = - cmd_process->readAllStandardError().toStdString(); + QString process_stdout = cmd_process->readAllStandardOutput(); int exit_code = cmd_process->exitCode(); + GF_CORE_LOG_DEBUG( + "\n==== Process Execution Summary ====\n" + "Command: {}\n" + "Arguments: {}\n" + "Exit Code: {}\n" + "---- Standard Output ----\n" + "{}\n" + "===============================", + cmd, joined_argument, exit_code, process_stdout); + cmd_process->close(); cmd_process->deleteLater(); - // transfer result - SPDLOG_DEBUG("runner append object"); - data_object->AppendObject(std::move(process_stderr)); - data_object->AppendObject(std::move(process_stdout)); - data_object->AppendObject(std::move(exit_code)); - SPDLOG_DEBUG("runner append object done"); - + data_object->Swap({exit_code, process_stdout, callback}); return 0; }; - // data transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - SPDLOG_DEBUG("executor append object"); - data_object->AppendObject(std::move(callback)); - data_object->AppendObject(std::move(interact_func)); - data_object->AppendObject(std::move(arguments)); - data_object->AppendObject(std::move(std::string{cmd})); - SPDLOG_DEBUG("executor append object done"); - - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("Execute/{}", cmd), data_object, + return new Thread::Task( + std::move(runner), QString("GpgCommamdExecutor(%1){%2}").arg(cmd), + TransferParams(cmd, arguments, interact_function, cmd_executor_callback), std::move(result_callback)); +} + +GpgCommandExecutor::ExecuteContext::ExecuteContext( + QString cmd, QList<QString> arguments, GpgCommandExecutorCallback callback, + Module::TaskRunnerPtr task_runner, GpgCommandExecutorInteractor int_func) + : cmd(std::move(cmd)), + arguments(std::move(arguments)), + cb_func(std::move(callback)), + int_func(std::move(int_func)), + task_runner(std::move(task_runner)) {} + +void GpgCommandExecutor::ExecuteSync(ExecuteContext context) { + Thread::Task *task = BuildTaskFromExecCtx(context); QEventLoop looper; - QObject::connect(process_task, &Thread::Task::SignalTaskEnd, &looper, + QObject::connect(task, &Thread::Task::SignalTaskEnd, &looper, &QEventLoop::quit); - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); - + Thread::TaskRunnerPtr target_task_runner = nullptr; + + if (context.task_runner != nullptr) { + target_task_runner = context.task_runner; + } else { + target_task_runner = + GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process); + } + target_task_runner->PostTask(task); + + // to arvoid dead lock issue we need to check if current thread is the same as + // target thread. if it is, we can't call exec() because it will block the + // current thread. + GF_CORE_LOG_TRACE("blocking until gpg command finish..."); // block until task finished // this is to keep reference vaild until task finished looper.exec(); } -void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func) { - SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); - - Thread::Task::TaskCallback result_callback = - [](int rtn, Thread::Task::DataObjectPtr data_object) { - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); - - auto exit_code = data_object->PopObject<int>(); - auto process_stdout = data_object->PopObject<std::string>(); - auto process_stderr = data_object->PopObject<std::string>(); - auto callback = data_object->PopObject< - std::function<void(int, std::string, std::string)>>(); - - // call callback - callback(exit_code, process_stdout, process_stderr); - }; - - Thread::Task::TaskRunnable runner = - [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { - SPDLOG_DEBUG("process runner called, data object size: {}", - data_object->GetObjectSize()); - - if (data_object->GetObjectSize() != 4) - throw std::runtime_error("invalid data object size"); - - SPDLOG_DEBUG("runner pop object"); - // get arguments - auto cmd = data_object->PopObject<std::string>(); - auto arguments = data_object->PopObject<std::vector<std::string>>(); - auto interact_func = - data_object->PopObject<std::function<void(QProcess *)>>(); - SPDLOG_DEBUG("runner pop object done"); - - auto *cmd_process = new QProcess(); - cmd_process->setProcessChannelMode(QProcess::MergedChannels); - - QObject::connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); - QObject::connect( - cmd_process, &QProcess::readyReadStandardOutput, - [interact_func, cmd_process]() { interact_func(cmd_process); }); - QObject::connect(cmd_process, &QProcess::errorOccurred, - [=](QProcess::ProcessError error) { - SPDLOG_ERROR("error in executing command: {} error: {}", - cmd, error); - }); - QObject::connect( - cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), - [=](int, QProcess::ExitStatus status) { - if (status == QProcess::NormalExit) - SPDLOG_DEBUG( - "proceess finished, succeed in executing command: {}, exit " - "status: {}", - cmd, status); - else - SPDLOG_ERROR( - "proceess finished, error in executing command: {}, exit " - "status: {}", - cmd, status); - }); - - cmd_process->setProgram(QString::fromStdString(cmd)); - cmd_process->setProcessChannelMode(QProcess::SeparateChannels); - - QStringList q_arguments; - for (const auto &argument : arguments) - q_arguments.append(QString::fromStdString(argument)); - cmd_process->setArguments(q_arguments); - - SPDLOG_DEBUG("process start ready, cmd: {} {}", cmd, - q_arguments.join(" ").toStdString()); - - cmd_process->start(); - cmd_process->waitForFinished(); - - std::string process_stdout = - cmd_process->readAllStandardOutput().toStdString(), - process_stderr = - cmd_process->readAllStandardError().toStdString(); - int exit_code = cmd_process->exitCode(); - - cmd_process->close(); - cmd_process->deleteLater(); - - // transfer result - SPDLOG_DEBUG("runner append object"); - data_object->AppendObject(std::move(process_stderr)); - data_object->AppendObject(std::move(process_stdout)); - data_object->AppendObject(std::move(exit_code)); - SPDLOG_DEBUG("runner append object done"); - - return 0; - }; - - // data transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - data_object->AppendObject(std::move(callback)); - data_object->AppendObject(std::move(interact_func)); - data_object->AppendObject(std::move(arguments)); - data_object->AppendObject(std::move(std::string{cmd})); - - auto *process_task = new GpgFrontend::Thread::Task( - std::move(runner), fmt::format("ExecuteConcurrently/{}", cmd), - data_object, std::move(result_callback), false); +void GpgCommandExecutor::ExecuteConcurrentlyAsync(ExecuteContexts contexts) { + for (auto &context : contexts) { + const auto &cmd = context.cmd; + GF_CORE_LOG_INFO("gpg concurrently called cmd {}", cmd); + + Thread::Task *task = BuildTaskFromExecCtx(context); + + if (context.task_runner != nullptr) { + context.task_runner->PostTask(task); + } else { + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(task); + } + } +} - GpgFrontend::Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) - ->PostTask(process_task); +void GpgCommandExecutor::ExecuteConcurrentlySync(ExecuteContexts contexts) { + QEventLoop looper; + auto remaining_tasks = contexts.size(); + Thread::TaskRunnerPtr target_task_runner = nullptr; + + for (auto &context : contexts) { + const auto &cmd = context.cmd; + GF_CORE_LOG_DEBUG("gpg concurrently called cmd: {}", cmd); + + Thread::Task *task = BuildTaskFromExecCtx(context); + + QObject::connect(task, &Thread::Task::SignalTaskEnd, [&]() { + --remaining_tasks; + GF_CORE_LOG_DEBUG("remaining tasks: {}", remaining_tasks); + if (remaining_tasks <= 0) { + GF_CORE_LOG_DEBUG("no remaining task, quit"); + looper.quit(); + } + }); + + if (context.task_runner != nullptr) { + target_task_runner = context.task_runner; + } else { + target_task_runner = + GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_External_Process); + } + + target_task_runner->PostTask(task); + } + + GF_CORE_LOG_TRACE("blocking until concurrent gpg commands finish..."); + // block until task finished + // this is to keep reference vaild until task finished + looper.exec(); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h index da0e7a8b..d161406a 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,39 +20,43 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H -#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H +#pragma once -#ifndef WINDOWS -#include <boost/process.hpp> -#endif - -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/thread/Task.h" +#include "core/module/Module.h" namespace GpgFrontend { +using GpgCommandExecutorCallback = std::function<void(int, QString, QString)>; +using GpgCommandExecutorInteractor = std::function<void(QProcess *)>; + /** * @brief Extra commands related to GPG * */ -class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor - : public SingletonFunctionObject<GpgCommandExecutor> { +class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor { public: - /** - * @brief Construct a new Gpg Command Executor object - * - * @param channel Corresponding context - */ - explicit GpgCommandExecutor( - int channel = SingletonFunctionObject::GetDefaultChannel()); + struct ExecuteContext { + QString cmd; + QStringList arguments; + GpgCommandExecutorCallback cb_func; + GpgCommandExecutorInteractor int_func; + Module::TaskRunnerPtr task_runner = nullptr; + + ExecuteContext( + QString cmd, QStringList arguments, + GpgCommandExecutorCallback callback = [](int, const QString &, + const QString &) {}, + Module::TaskRunnerPtr task_runner = nullptr, + GpgCommandExecutorInteractor int_func = [](QProcess *) {}); + }; + + using ExecuteContexts = QList<ExecuteContext>; /** * @brief Excuting a command @@ -60,22 +64,11 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor * @param arguments Command parameters * @param interact_func Command answering function */ - void Execute( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback = - [](int, std::string, std::string) {}, - std::function<void(QProcess *)> interact_func = [](QProcess *) {}); + static void ExecuteSync(ExecuteContext); - void ExecuteConcurrently( - std::string cmd, std::vector<std::string> arguments, - std::function<void(int, std::string, std::string)> callback, - std::function<void(QProcess *)> interact_func = [](QProcess *) {}); + static void ExecuteConcurrentlyAsync(ExecuteContexts); - private: - GpgContext &ctx_ = GpgContext::GetInstance( - SingletonFunctionObject::GetChannel()); ///< Corresponding context + static void ExecuteConcurrentlySync(ExecuteContexts); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp new file mode 100644 index 00000000..104e254f --- /dev/null +++ b/src/core/function/gpg/GpgContext.cpp @@ -0,0 +1,336 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "core/function/gpg/GpgContext.h" + +#include <gpg-error.h> +#include <gpgme.h> + +#include <cassert> +#include <mutex> + +#include "core/function/CoreSignalStation.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/model/GpgPassphraseContext.h" +#include "core/module/ModuleManager.h" +#include "core/utils/CacheUtils.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/MemoryUtils.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +namespace GpgFrontend { + +class GpgContext::Impl { + public: + /** + * Constructor + * Set up gpgme-context, set paths to app-run path + */ + Impl(GpgContext *parent, const GpgContextInitArgs &args) + : parent_(parent), + args_(args), + good_(default_ctx_initialize(args) && binary_ctx_initialize(args)) {} + + ~Impl() { + if (ctx_ref_ != nullptr) { + gpgme_release(ctx_ref_); + } + + if (binary_ctx_ref_ != nullptr) { + gpgme_release(binary_ctx_ref_); + } + } + + [[nodiscard]] auto BinaryContext() const -> gpgme_ctx_t { + return binary_ctx_ref_; + } + + [[nodiscard]] auto DefaultContext() const -> gpgme_ctx_t { return ctx_ref_; } + + [[nodiscard]] auto Good() const -> bool { return good_; } + + auto SetPassphraseCb(const gpgme_ctx_t &ctx, gpgme_passphrase_cb_t cb) + -> bool { + if (gpgme_get_pinentry_mode(ctx) != GPGME_PINENTRY_MODE_LOOPBACK) { + if (CheckGpgError(gpgme_set_pinentry_mode( + ctx, GPGME_PINENTRY_MODE_LOOPBACK)) != GPG_ERR_NO_ERROR) { + return false; + } + } + gpgme_set_passphrase_cb(ctx, cb, reinterpret_cast<void *>(parent_)); + return true; + } + + static auto TestPassphraseCb(void *opaque, const char *uid_hint, + const char *passphrase_info, int last_was_bad, + int fd) -> gpgme_error_t { + size_t res; + QString pass = "abcdefg\n"; + auto pass_len = pass.size(); + + size_t off = 0; + + do { + res = gpgme_io_write(fd, &pass[off], pass_len - off); + if (res > 0) off += res; + } while (res > 0 && off != pass_len); + + return off == pass_len ? 0 : gpgme_error_from_errno(errno); + } + + static auto CustomPassphraseCb(void *hook, const char *uid_hint, + const char *passphrase_info, int prev_was_bad, + int fd) -> gpgme_error_t { + auto context_cache = GetCacheValue("PinentryContext"); + bool ask_for_new = context_cache == "NEW_PASSPHRASE"; + auto context = + QSharedPointer<GpgPassphraseContext>(new GpgPassphraseContext( + uid_hint != nullptr ? uid_hint : "", + passphrase_info != nullptr ? passphrase_info : "", + prev_was_bad != 0, ask_for_new)); + + GF_CORE_LOG_DEBUG( + "custom passphrase cb called, uid: {}, info: {}, last_was_bad: {}", + uid_hint == nullptr ? "<empty>" : QString{uid_hint}, + passphrase_info == nullptr ? "<empty>" : QString{passphrase_info}, + prev_was_bad); + + QEventLoop looper; + QObject::connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalUserInputPassphraseCallback, + &looper, &QEventLoop::quit); + + emit CoreSignalStation::GetInstance()->SignalNeedUserInputPassphrase( + context); + looper.exec(); + + ResetCacheValue("PinentryContext"); + auto passphrase = context->GetPassphrase().toStdString(); + auto passpahrase_size = passphrase.size(); + GF_CORE_LOG_DEBUG("get passphrase from pinentry size: {}", + passpahrase_size); + + size_t res = 0; + if (passpahrase_size > 0) { + size_t off = 0; + do { + res = gpgme_io_write(fd, &passphrase[off], passpahrase_size - off); + if (res > 0) off += res; + } while (res > 0 && off != passpahrase_size); + } + + res += gpgme_io_write(fd, "\n", 1); + + GF_CORE_LOG_DEBUG("custom passphrase cd is about to return, res: {}", res); + return res == passpahrase_size + 1 + ? 0 + : gpgme_error_from_errno(GPG_ERR_CANCELED); + } + + static auto TestStatusCb(void *hook, const char *keyword, const char *args) + -> gpgme_error_t { + GF_CORE_LOG_DEBUG("keyword {}", keyword); + return GPG_ERR_NO_ERROR; + } + + private: + GpgContext *parent_; + GpgContextInitArgs args_{}; ///< + gpgme_ctx_t ctx_ref_ = nullptr; ///< + gpgme_ctx_t binary_ctx_ref_ = nullptr; ///< + bool good_ = true; + std::mutex ctx_ref_lock_; + std::mutex binary_ctx_ref_lock_; + + static auto set_ctx_key_list_mode(const gpgme_ctx_t &ctx) -> bool { + assert(ctx != nullptr); + + const auto gpgme_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", QString{"0.0.0"}); + GF_CORE_LOG_DEBUG("got gpgme version version from rt: {}", gpgme_version); + + if (gpgme_get_keylist_mode(ctx) == 0) { + GF_CORE_LOG_ERROR( + "ctx is not a valid pointer, reported by gpgme_get_keylist_mode"); + return false; + } + + // set keylist mode + return CheckGpgError(gpgme_set_keylist_mode( + ctx, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET | + GPGME_KEYLIST_MODE_SIGS | + GPGME_KEYLIST_MODE_SIG_NOTATIONS | + GPGME_KEYLIST_MODE_WITH_TOFU)) == GPG_ERR_NO_ERROR; + } + + static auto set_ctx_openpgp_engine_info(gpgme_ctx_t ctx) -> bool { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); + const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.database_path", QString{}); + + GF_CORE_LOG_DEBUG("ctx set engine info, db path: {}, app path: {}", + database_path, app_path); + + auto app_path_buffer = app_path.toUtf8(); + auto database_path_buffer = database_path.toUtf8(); + + auto err = gpgme_ctx_set_engine_info( + ctx, gpgme_get_protocol(ctx), + app_path.isEmpty() ? nullptr : app_path_buffer, + database_path.isEmpty() ? nullptr : database_path_buffer); + + assert(CheckGpgError(err) == GPG_ERR_NO_ERROR); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; + + return true; + } + + auto common_ctx_initialize(const gpgme_ctx_t &ctx, + const GpgContextInitArgs &args) -> bool { + assert(ctx != nullptr); + + if (args.custom_gpgconf && !args.custom_gpgconf_path.isEmpty()) { + GF_CORE_LOG_DEBUG("set custom gpgconf path: {}", + args.custom_gpgconf_path); + auto err = + gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_GPGCONF, + args.custom_gpgconf_path.toUtf8(), nullptr); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("set gpg context engine info error: {}", + DescribeGpgErrCode(err).second); + return false; + } + } + + // set context offline mode + GF_CORE_LOG_DEBUG("gpg context offline mode: {}", args_.offline_mode); + gpgme_set_offline(ctx, args_.offline_mode ? 1 : 0); + + // set option auto import missing key + // invalid at offline mode + GF_CORE_LOG_DEBUG("gpg context auto import missing key: {}", + args_.offline_mode); + if (!args.offline_mode && args.auto_import_missing_key) { + if (CheckGpgError(gpgme_set_ctx_flag(ctx, "auto-key-import", "1")) != + GPG_ERR_NO_ERROR) { + return false; + } + } + + if (!set_ctx_key_list_mode(ctx)) { + GF_CORE_LOG_DEBUG("set ctx key list mode failed"); + return false; + } + + // for unit test + if (args_.test_mode) { + if (!SetPassphraseCb(ctx, TestPassphraseCb)) { + GF_CORE_LOG_ERROR("set passphrase cb failed, test"); + return false; + }; + } else if (!args_.use_pinentry) { + if (!SetPassphraseCb(ctx, CustomPassphraseCb)) { + GF_CORE_LOG_DEBUG("set passphrase cb failed, custom"); + return false; + } + } + + // set custom gpg key db path + if (!args_.db_path.isEmpty()) { + Module::UpsertRTValue("core", "gpgme.ctx.database_path", args_.db_path); + } + + if (!set_ctx_openpgp_engine_info(ctx)) { + GF_CORE_LOG_ERROR("set gpgme context openpgp engine info failed"); + return false; + } + + return true; + } + + auto binary_ctx_initialize(const GpgContextInitArgs &args) -> bool { + gpgme_ctx_t p_ctx; + if (auto err = CheckGpgError(gpgme_new(&p_ctx)); err != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("get new gpg context error: {}", + DescribeGpgErrCode(err).second); + return false; + } + assert(p_ctx != nullptr); + binary_ctx_ref_ = p_ctx; + + if (!common_ctx_initialize(binary_ctx_ref_, args)) { + GF_CORE_LOG_ERROR("get new ctx failed, binary"); + return false; + } + + gpgme_set_armor(binary_ctx_ref_, 0); + return true; + } + + auto default_ctx_initialize(const GpgContextInitArgs &args) -> bool { + gpgme_ctx_t p_ctx; + if (CheckGpgError(gpgme_new(&p_ctx)) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR("get new ctx failed, default"); + return false; + } + assert(p_ctx != nullptr); + ctx_ref_ = p_ctx; + + if (!common_ctx_initialize(ctx_ref_, args)) { + return false; + } + + gpgme_set_armor(ctx_ref_, 1); + return true; + } +}; + +GpgContext::GpgContext(int channel) + : SingletonFunctionObject<GpgContext>(channel), + p_(SecureCreateUniqueObject<Impl>(this, GpgContextInitArgs{})) {} + +GpgContext::GpgContext(GpgContextInitArgs args, int channel) + : SingletonFunctionObject<GpgContext>(channel), + p_(SecureCreateUniqueObject<Impl>(this, args)) {} + +auto GpgContext::Good() const -> bool { return p_->Good(); } + +auto GpgContext::BinaryContext() -> gpgme_ctx_t { return p_->BinaryContext(); } + +auto GpgContext::DefaultContext() -> gpgme_ctx_t { + return p_->DefaultContext(); +} + +GpgContext::~GpgContext() = default; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgContext.h b/src/core/function/gpg/GpgContext.h new file mode 100644 index 00000000..d473a341 --- /dev/null +++ b/src/core/function/gpg/GpgContext.h @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/GpgFunctionObject.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +struct GpgContextInitArgs { + QString db_path = {}; ///< + + bool test_mode = false; ///< + bool offline_mode = false; ///< + bool auto_import_missing_key = false; ///< + + bool custom_gpgconf = false; ///< + QString custom_gpgconf_path; ///< + + bool use_pinentry = false; ///< +}; + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT GpgContext + : public SingletonFunctionObject<GpgContext> { + public: + explicit GpgContext(int channel); + + explicit GpgContext(GpgContextInitArgs args, int channel); + + virtual ~GpgContext() override; + + [[nodiscard]] auto Good() const -> bool; + + auto BinaryContext() -> gpgme_ctx_t; + + auto DefaultContext() -> gpgme_ctx_t; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgFileOpera.cpp b/src/core/function/gpg/GpgFileOpera.cpp index 30678cf0..e3d47cf6 100644 --- a/src/core/function/gpg/GpgFileOpera.cpp +++ b/src/core/function/gpg/GpgFileOpera.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,235 +20,353 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "GpgFileOpera.h" -#include <memory> -#include <string> +#include "core/function/ArchiveFileOperator.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/model/GpgData.h" +#include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgKey.h" +#include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" -#include "GpgBasicOperator.h" -#include "GpgConstants.h" -#include "function/FileOperator.h" +namespace GpgFrontend { -GpgFrontend::GpgFileOpera::GpgFileOpera(int channel) +constexpr ssize_t kDataExchangerSize = 8192; + +GpgFileOpera::GpgFileOpera(int channel) : SingletonFunctionObject<GpgFileOpera>(channel) {} -GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile( - KeyListPtr keys, const std::string& in_path, const std::string& out_path, - GpgEncrResult& result, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer = nullptr; - - auto err = GpgBasicOperator::GetInstance(_channel).Encrypt( - std::move(keys), in_buffer, out_buffer, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptFile(std::vector<GpgKey> keys, const QString& in_path, + bool ascii, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx))}); + + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile( - const std::string& in_path, const std::string& out_path, - GpgDecrResult& result) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer; - - auto err = - GpgBasicOperator::GetInstance().Decrypt(in_buffer, out_buffer, result); - - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptDirectory(std::vector<GpgKey> keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgData data_in(ex); + GpgData data_out(out_path, false); + + GF_CORE_LOG_DEBUG("encrypt directory start"); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + data_object->Swap({GpgEncryptResult(gpgme_op_encrypt_result(ctx))}); + + GF_CORE_LOG_DEBUG("encrypt directory finished, err: {}", err); + return err; + }, + cb, "gpgme_op_encrypt", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 data exchanger operation, err: {}", + err); + }); +} + +void GpgFileOpera::DecryptFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext()))}); + + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); +} + +void GpgFileOpera::DecryptArchive(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + ArchiveFileOperator::ExtractArchiveFromDataExchanger( + ex, out_path, [](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG( + "extract archive from data exchanger operation, err: {}", err); + }); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(ex); + + auto err = CheckGpgError( + gpgme_op_decrypt(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap( + {GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext()))}); + return err; + }, + cb, "gpgme_op_decrypt", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys, - const std::string& in_path, - const std::string& out_path, - GpgSignResult& result, - int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer; - - auto err = GpgBasicOperator::GetInstance(_channel).Sign( - std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::SignFile(KeyArgsList keys, const QString& in_path, + bool ascii, const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + // Set Singers of this opera + GpgBasicOperator::GetInstance().SetSigners(keys, ascii); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError( + gpgme_op_sign(ctx, data_in, data_out, GPGME_SIG_MODE_DETACH)); + + data_object->Swap({ + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_sign", "2.1.0"); } -gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile( - const std::string& data_path, const std::string& sign_path, - GpgVerifyResult& result, int _channel) { -#ifdef WINDOWS - auto data_path_std = - std::filesystem::path(QString::fromStdString(data_path).toStdU16String()); - auto sign_path_std = - std::filesystem::path(QString::fromStdString(sign_path).toStdU16String()); -#else - auto data_path_std = std::filesystem::path(data_path); - auto sign_path_std = std::filesystem::path(sign_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(data_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> sign_buffer = nullptr; - if (!sign_path.empty()) { - std::string sign_buffer_str; - if (!FileOperator::ReadFileStd(sign_path_std, sign_buffer_str)) { - throw std::runtime_error("read file error"); - } - sign_buffer = std::make_unique<std::string>(sign_buffer_str); - } - auto err = GpgBasicOperator::GetInstance(_channel).Verify( - in_buffer, sign_buffer, result); - return err; +void GpgFileOpera::VerifyFile(const QString& data_path, + const QString& sign_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(data_path, true); + GpgData data_out; + if (!sign_path.isEmpty()) { + GpgData sig_data(sign_path, true); + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), sig_data, + data_in, nullptr)); + } else { + err = CheckGpgError(gpgme_op_verify(ctx_.DefaultContext(), data_in, + nullptr, data_out)); + } + + data_object->Swap({ + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_verify", "2.1.0"); } -gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile( - KeyListPtr keys, KeyListPtr signer_keys, const std::string& in_path, - const std::string& out_path, GpgEncrResult& encr_res, - GpgSignResult& sign_res, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - std::unique_ptr<std::string> out_buffer = nullptr; - - auto err = GpgBasicOperator::GetInstance(_channel).EncryptSign( - std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res, - sign_res); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; +void GpgFileOpera::EncryptSignFile(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgBasicOperator::GetInstance().SetSigners(signer_keys, ascii); + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); } -gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile( - const std::string& in_path, const std::string& out_path, - GpgDecrResult& decr_res, GpgVerifyResult& verify_res) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer = nullptr; - auto err = GpgBasicOperator::GetInstance().DecryptVerify( - in_buffer, out_buffer, decr_res, verify_res); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write file error"); - }; - - return err; +void GpgFileOpera::EncryptSignDirectory(KeyArgsList keys, + KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + std::vector<gpgme_key_t> recipients(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + recipients.emplace_back(nullptr); + + GpgBasicOperator::GetInstance().SetSigners(signer_keys, ascii); + + GpgData data_in(ex); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + err = CheckGpgError(gpgme_op_encrypt_sign(ctx, recipients.data(), + GPGME_ENCRYPT_ALWAYS_TRUST, + data_in, data_out)); + + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + GpgSignResult(gpgme_op_sign_result(ctx)), + }); + return err; + }, + cb, "gpgme_op_encrypt_sign", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); } -unsigned int GpgFrontend::GpgFileOpera::EncryptFileSymmetric( - const std::string& in_path, const std::string& out_path, - GpgFrontend::GpgEncrResult& result, int _channel) { -#ifdef WINDOWS - auto in_path_std = - std::filesystem::path(QString::fromStdString(in_path).toStdU16String()); - auto out_path_std = - std::filesystem::path(QString::fromStdString(out_path).toStdU16String()); -#else - auto in_path_std = std::filesystem::path(in_path); - auto out_path_std = std::filesystem::path(out_path); -#endif - - std::string in_buffer; - if (!FileOperator::ReadFileStd(in_path_std, in_buffer)) { - throw std::runtime_error("read file error"); - } - - std::unique_ptr<std::string> out_buffer; - auto err = GpgBasicOperator::GetInstance(_channel).EncryptSymmetric( - in_buffer, out_buffer, result); - - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - if (!FileOperator::WriteFileStd(out_path_std, *out_buffer)) { - throw std::runtime_error("write_buffer_to_file error"); - }; - - return err; + +void GpgFileOpera::DecryptVerifyFile(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap({ + GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); +} + +void GpgFileOpera::DecryptVerifyArchive(const QString& in_path, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + ArchiveFileOperator::ExtractArchiveFromDataExchanger( + ex, out_path, [](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("extract archive from ex operation, err: {}", err); + }); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgError err; + + GpgData data_in(in_path, true); + GpgData data_out(ex); + + err = CheckGpgError( + gpgme_op_decrypt_verify(ctx_.DefaultContext(), data_in, data_out)); + + data_object->Swap({ + GpgDecryptResult(gpgme_op_decrypt_result(ctx_.DefaultContext())), + GpgVerifyResult(gpgme_op_verify_result(ctx_.DefaultContext())), + }); + + return err; + }, + cb, "gpgme_op_decrypt_verify", "2.1.0"); +} + +void GpgFileOpera::EncryptFileSymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(in_path, true); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + }); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); +} + +void GpgFileOpera::EncryptDerectorySymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb) { + auto ex = std::make_shared<GFDataExchanger>(kDataExchangerSize); + + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + GpgData data_in(ex); + GpgData data_out(out_path, false); + + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = CheckGpgError(gpgme_op_encrypt( + ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out)); + data_object->Swap({ + GpgEncryptResult(gpgme_op_encrypt_result(ctx)), + }); + + return err; + }, + cb, "gpgme_op_encrypt_symmetric", "2.1.0"); + + ArchiveFileOperator::NewArchive2DataExchanger( + in_path, ex, [=](GFError err, const DataObjectPtr&) { + GF_CORE_LOG_DEBUG("new archive 2 fd operation, err: {}", err); + }); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgFileOpera.h b/src/core/function/gpg/GpgFileOpera.h index dc81bc53..b015ebe9 100644 --- a/src/core/function/gpg/GpgFileOpera.h +++ b/src/core/function/gpg/GpgFileOpera.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,59 +20,87 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGFILEOPERA_H -#define GPGFRONTEND_GPGFILEOPERA_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** - * @brief Executive files related to the basic operations that are provided by - * GpgBasicOperator + * @brief Executive files related to the basic operations of GPG + * * @class class: GpgBasicOperator */ class GPGFRONTEND_CORE_EXPORT GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> { public: + /** + * @brief Construct a new Gpg File Opera object + * + * @param channel + */ explicit GpgFileOpera( int channel = SingletonFunctionObject::GetDefaultChannel()); /** - * @brief Encrypted file + * @brief Encrypted file with public key * * @param keys Used public key * @param in_path The path where the enter file is located * @param out_path The path where the output file is located * @param result Encrypted results - * @param _channel Channel in context + * @param channel Channel in context * @return unsigned int error code */ - static unsigned int EncryptFile(KeyListPtr keys, const std::string& in_path, - const std::string& out_path, - GpgEncrResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptFile(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDirectory(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** - * @brief 运用对称加密算法加密文件 + * @brief Encrypted file symmetrically (with password) * * @param in_path * @param out_path * @param result - * @param _channel + * @param channel * @return unsigned int */ - static unsigned int EncryptFileSymmetric( - const std::string& in_path, const std::string& out_path, - GpgEncrResult& result, int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptFileSymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptDerectorySymmetric(const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** * @brief @@ -82,37 +110,43 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param result * @return GpgError */ - static GpgError DecryptFile(const std::string& in_path, - const std::string& out_path, - GpgDecrResult& result); + void DecryptFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); /** * @brief * + * @param in_path + * @param out_path + * @param cb + */ + void DecryptArchive(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief Sign file with private key + * * @param keys * @param in_path * @param out_path * @param result - * @param _channel + * @param channel * @return GpgError */ - static GpgError SignFile(KeyListPtr keys, const std::string& in_path, - const std::string& out_path, GpgSignResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void SignFile(KeyArgsList keys, const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); /** - * @brief + * @brief Verify file with public key * - * @param data_path - * @param sign_path - * @param result - * @param _channel + * @param data_path The path where the enter file is located + * @param sign_path The path where the signature file is located + * @param result Verify results + * @param channel Channel in context * @return GpgError */ - static GpgError VerifyFile(const std::string& data_path, - const std::string& sign_path, - GpgVerifyResult& result, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void VerifyFile(const QString& data_path, const QString& sign_path, + const GpgOperationCallback& cb); /** * @brief @@ -120,18 +154,28 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param keys * @param signer_keys * @param in_path + * @param ascii * @param out_path - * @param encr_res - * @param sign_res - * @param _channel - * @return GpgError + * @param cb */ - static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys, - const std::string& in_path, - const std::string& out_path, - GpgEncrResult& encr_res, - GpgSignResult& sign_res, - int _channel = GPGFRONTEND_DEFAULT_CHANNEL); + void EncryptSignFile(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, const GpgOperationCallback& cb); + + /** + * @brief + * + * @param keys + * @param signer_keys + * @param in_path + * @param ascii + * @param out_path + * @param cb + */ + void EncryptSignDirectory(KeyArgsList keys, KeyArgsList signer_keys, + const QString& in_path, bool ascii, + const QString& out_path, + const GpgOperationCallback& cb); /** * @brief @@ -142,12 +186,22 @@ class GPGFRONTEND_CORE_EXPORT GpgFileOpera * @param verify_res * @return GpgError */ - static GpgError DecryptVerifyFile(const std::string& in_path, - const std::string& out_path, - GpgDecrResult& decr_res, - GpgVerifyResult& verify_res); + void DecryptVerifyFile(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + /** + * @brief + * + * @param in_path + * @param out_path + * @param cb + */ + void DecryptVerifyArchive(const QString& in_path, const QString& out_path, + const GpgOperationCallback& cb); + + private: + GpgContext& ctx_ = GpgContext::GetInstance( + SingletonFunctionObject::GetChannel()); ///< Corresponding context }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGFILEOPERA_H diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp index ee6d2b09..e22979d7 100644 --- a/src/core/function/gpg/GpgKeyGetter.cpp +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -32,136 +32,212 @@ #include <mutex> #include <shared_mutex> -#include <utility> -#include "GpgConstants.h" -#include "model/GpgKey.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgContext.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgKeyGetter::GpgKeyGetter(int channel) - : SingletonFunctionObject<GpgKeyGetter>(channel) { - SPDLOG_DEBUG("called channel: {}", channel); -} +namespace GpgFrontend { -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr, - bool use_cache) { - // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; +class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { + public: + explicit Impl(int channel) + : SingletonFunctionObject<GpgKeyGetter::Impl>(channel) { + GF_CORE_LOG_DEBUG("called channel: {}", channel); } - gpgme_key_t _p_key = nullptr; - gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 1); - if (_p_key == nullptr) { - SPDLOG_WARN("GpgKeyGetter GetKey Private _p_key Null fpr", fpr); - return GetPubkey(fpr); - } else { - return GpgKey(std::move(_p_key)); - } -} + auto GetKey(const QString& fpr, bool use_cache) -> GpgKey { + // find in cache first + if (use_cache) { + auto key = get_key_in_cache(fpr); + if (key.IsGood()) return key; + } -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey(const std::string& fpr, - bool use_cache) { - // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; + gpgme_key_t p_key = nullptr; + gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 1); + if (p_key == nullptr) { + GF_CORE_LOG_WARN("GpgKeyGetter GetKey Private _p_key Null fpr", fpr); + return GetPubkey(fpr, true); + } + return GpgKey(std::move(p_key)); } - gpgme_key_t _p_key = nullptr; - gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 0); - if (_p_key == nullptr) SPDLOG_WARN("GpgKeyGetter GetKey _p_key Null", fpr); - return GpgKey(std::move(_p_key)); -} + auto GetPubkey(const QString& fpr, bool use_cache) -> GpgKey { + // find in cache first + if (use_cache) { + auto key = get_key_in_cache(fpr); + if (key.IsGood()) return key; + } -GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() { - // get the lock - std::lock_guard<std::mutex> lock(keys_cache_mutex_); + gpgme_key_t p_key = nullptr; + gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 0); + if (p_key == nullptr) + GF_CORE_LOG_WARN("GpgKeyGetter GetKey _p_key Null", fpr); + return GpgKey(std::move(p_key)); + } - auto keys_list = std::make_unique<GpgKeyLinkList>(); + auto FetchKey() -> KeyLinkListPtr { + if (keys_cache_.empty()) { + FlushKeyCache(); + } - for (const auto& [key, value] : keys_cache_) { - keys_list->push_back(value.Copy()); + auto keys_list = std::make_unique<GpgKeyLinkList>(); + + { + // get the lock + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + for (const auto& [key, value] : keys_cache_) { + keys_list->push_back(value); + } + } + return keys_list; } - return keys_list; -} -void GpgFrontend::GpgKeyGetter::FlushKeyCache() { - SPDLOG_DEBUG("called channel id: {}", GetChannel()); + auto FlushKeyCache() -> bool { + GF_CORE_LOG_DEBUG("flush key channel called, channel: {}", GetChannel()); - // clear the keys cache - keys_cache_.clear(); + // clear the keys cache + keys_cache_.clear(); - // init - GpgError err = gpgme_op_keylist_start(ctx_, nullptr, 0); + // init + GpgError err = gpgme_op_keylist_start(ctx_.DefaultContext(), nullptr, 0); - // for debug - assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); + // for debug + assert(CheckGpgError(err) == GPG_ERR_NO_ERROR); - // return when error - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return; + // return when error + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) return false; - { - // get the lock - std::lock_guard<std::mutex> lock(keys_cache_mutex_); - gpgme_key_t key; - while ((err = gpgme_op_keylist_next(ctx_, &key)) == GPG_ERR_NO_ERROR) { - auto gpg_key = GpgKey(std::move(key)); - - // detect if the key is in a smartcard - // if so, try to get full information using gpgme_get_key() - // this maybe a bug in gpgme - if (gpg_key.IsHasCardKey()) { - gpg_key = GetKey(gpg_key.GetId(), false); + { + // get the lock + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + gpgme_key_t key; + while ((err = gpgme_op_keylist_next(ctx_.DefaultContext(), &key)) == + GPG_ERR_NO_ERROR) { + auto gpg_key = GpgKey(std::move(key)); + + // detect if the key is in a smartcard + // if so, try to get full information using gpgme_get_key() + // this maybe a bug in gpgme + if (gpg_key.IsHasCardKey()) { + gpg_key = GetKey(gpg_key.GetId(), false); + } + + keys_cache_.insert({gpg_key.GetId(), std::move(gpg_key)}); } + } + + GF_CORE_LOG_DEBUG("flush key channel cache address: {} object address: {}", + static_cast<void*>(&keys_cache_), + static_cast<void*>(this)); + + // for debug + assert(CheckGpgError2ErrCode(err, GPG_ERR_EOF) == GPG_ERR_EOF); + + err = gpgme_op_keylist_end(ctx_.DefaultContext()); + assert(CheckGpgError2ErrCode(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR); - keys_cache_.insert({gpg_key.GetId(), std::move(gpg_key)}); + GF_CORE_LOG_DEBUG("flush key channel done, channel: {}", GetChannel()); + return true; + } + + auto GetKeys(const KeyIdArgsListPtr& ids) -> KeyListPtr { + auto keys = std::make_unique<KeyArgsList>(); + for (const auto& key_id : *ids) keys->emplace_back(GetKey(key_id, true)); + return keys; + } + + auto GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr { + // get the lock + std::lock_guard<std::mutex> lock(ctx_mutex_); + auto keys_copy = std::make_unique<GpgKeyLinkList>(); + for (const auto& key : *keys) keys_copy->emplace_back(key); + return keys_copy; + } + + auto GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr { + // get the lock + std::lock_guard<std::mutex> lock(ctx_mutex_); + auto keys_copy = std::make_unique<KeyArgsList>(); + for (const auto& key : *keys) keys_copy->emplace_back(key); + return keys_copy; + } + + private: + /** + * @brief Get the gpgme context object + * + */ + GpgContext& ctx_ = + GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); + + /** + * @brief shared mutex for the keys cache + * + */ + mutable std::mutex ctx_mutex_; + + /** + * @brief cache the keys with key id + * + */ + std::map<QString, GpgKey> keys_cache_; + + /** + * @brief shared mutex for the keys cache + * + */ + mutable std::mutex keys_cache_mutex_; + + /** + * @brief Get the Key object + * + * @param id + * @return GpgKey + */ + auto get_key_in_cache(const QString& key_id) -> GpgKey { + std::lock_guard<std::mutex> lock(keys_cache_mutex_); + if (keys_cache_.find(key_id) != keys_cache_.end()) { + std::lock_guard<std::mutex> lock(ctx_mutex_); + // return a copy of the key in cache + return keys_cache_[key_id]; } + + // return a bad key + return {}; } +}; - SPDLOG_DEBUG("cache address: {} object address: {}", - static_cast<void*>(&keys_cache_), static_cast<void*>(this)); +GpgKeyGetter::GpgKeyGetter(int channel) + : SingletonFunctionObject<GpgKeyGetter>(channel), + p_(SecureCreateUniqueObject<Impl>(channel)) { + GF_CORE_LOG_DEBUG("called channel: {}", channel); +} - // for debug - assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); +GpgKeyGetter::~GpgKeyGetter() = default; - err = gpgme_op_keylist_end(ctx_); - assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR); +auto GpgKeyGetter::GetKey(const QString& key_id, bool use_cache) -> GpgKey { + return p_->GetKey(key_id, use_cache); } -GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeys( - const KeyIdArgsListPtr& ids) { - auto keys = std::make_unique<KeyArgsList>(); - for (const auto& id : *ids) keys->emplace_back(GetKey(id)); - return keys; +auto GpgKeyGetter::GetPubkey(const QString& key_id, bool use_cache) -> GpgKey { + return p_->GetPubkey(key_id, use_cache); } -GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( - const GpgFrontend::KeyLinkListPtr& keys) { - // get the lock - std::lock_guard<std::mutex> lock(ctx_mutex_); - auto keys_copy = std::make_unique<GpgKeyLinkList>(); - for (const auto& key : *keys) keys_copy->emplace_back(key.Copy()); - return keys_copy; +auto GpgKeyGetter::FlushKeyCache() -> bool { return p_->FlushKeyCache(); } + +auto GpgKeyGetter::GetKeys(const KeyIdArgsListPtr& ids) -> KeyListPtr { + return p_->GetKeys(ids); } -GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeysCopy( - const GpgFrontend::KeyListPtr& keys) { - // get the lock - std::lock_guard<std::mutex> lock(ctx_mutex_); - auto keys_copy = std::make_unique<KeyArgsList>(); - for (const auto& key : *keys) keys_copy->emplace_back(key.Copy()); - return keys_copy; +auto GpgKeyGetter::GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr { + return p_->GetKeysCopy(keys); } -GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::get_key_in_cache( - const std::string& id) { - std::lock_guard<std::mutex> lock(keys_cache_mutex_); - if (keys_cache_.find(id) != keys_cache_.end()) { - std::lock_guard<std::mutex> lock(ctx_mutex_); - // return a copy of the key in cache - return keys_cache_[id].Copy(); - } - // return a bad key - return GpgKey(); +auto GpgKeyGetter::GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr { + return p_->GetKeysCopy(keys); } + +auto GpgKeyGetter::FetchKey() -> KeyLinkListPtr { return p_->FetchKey(); } + +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyGetter.h b/src/core/function/gpg/GpgKeyGetter.h index c96dbea7..91138623 100644 --- a/src/core/function/gpg/GpgKeyGetter.h +++ b/src/core/function/gpg/GpgKeyGetter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H -#define GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H +#pragma once -#include <mutex> -#include <vector> - -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -50,8 +45,13 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * * @param channel */ - explicit GpgKeyGetter( - int channel = SingletonFunctionObject::GetDefaultChannel()); + explicit GpgKeyGetter(int channel = kGpgFrontendDefaultChannel); + + /** + * @brief Destroy the Gpg Key Getter object + * + */ + ~GpgKeyGetter(); /** * @brief Get the Key object @@ -59,7 +59,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param fpr * @return GpgKey */ - GpgKey GetKey(const std::string& id, bool use_cache = true); + auto GetKey(const QString& key_id, bool use_cache = true) -> GpgKey; /** * @brief Get the Keys object @@ -67,7 +67,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param ids * @return KeyListPtr */ - KeyListPtr GetKeys(const KeyIdArgsListPtr& ids); + auto GetKeys(const KeyIdArgsListPtr& key_ids) -> KeyListPtr; /** * @brief Get the Pubkey object @@ -75,20 +75,20 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param fpr * @return GpgKey */ - GpgKey GetPubkey(const std::string& id, bool use_cache = true); + auto GetPubkey(const QString& key_id, bool use_cache = true) -> GpgKey; /** * @brief Get all the keys by receiving a linked list * * @return KeyLinkListPtr */ - KeyLinkListPtr FetchKey(); + auto FetchKey() -> KeyLinkListPtr; /** * @brief flush the keys in the cache * */ - void FlushKeyCache(); + auto FlushKeyCache() -> bool; /** * @brief Get the Keys Copy object @@ -96,7 +96,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param keys * @return KeyListPtr */ - KeyListPtr GetKeysCopy(const KeyListPtr& keys); + auto GetKeysCopy(const KeyListPtr& keys) -> KeyListPtr; /** * @brief Get the Keys Copy object @@ -104,42 +104,10 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter * @param keys * @return KeyLinkListPtr */ - KeyLinkListPtr GetKeysCopy(const KeyLinkListPtr& keys); + auto GetKeysCopy(const KeyLinkListPtr& keys) -> KeyLinkListPtr; private: - /** - * @brief Get the gpgme context object - * - */ - GpgContext& ctx_ = - GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); - - /** - * @brief shared mutex for the keys cache - * - */ - mutable std::mutex ctx_mutex_; - - /** - * @brief cache the keys with key id - * - */ - std::map<std::string, GpgKey> keys_cache_; - - /** - * @brief shared mutex for the keys cache - * - */ - mutable std::mutex keys_cache_mutex_; - - /** - * @brief Get the Key object - * - * @param id - * @return GpgKey - */ - GpgKey get_key_in_cache(const std::string& id); + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H diff --git a/src/core/function/gpg/GpgKeyImportExporter.cpp b/src/core/function/gpg/GpgKeyImportExporter.cpp index 01349c94..09b51359 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.cpp +++ b/src/core/function/gpg/GpgKeyImportExporter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,79 +28,76 @@ #include "GpgKeyImportExporter.h" -#include <memory> +#include "core/GpgModel.h" +#include "core/model/GpgImportInformation.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/GpgUtils.h" -#include "GpgConstants.h" -#include "GpgKeyGetter.h" +namespace GpgFrontend { -GpgFrontend::GpgKeyImportExporter::GpgKeyImportExporter(int channel) - : SingletonFunctionObject<GpgKeyImportExporter>(channel) {} +GpgKeyImportExporter::GpgKeyImportExporter(int channel) + : SingletonFunctionObject<GpgKeyImportExporter>(channel), + ctx_(GpgContext::GetInstance(SingletonFunctionObject::GetChannel())) {} /** * Import key pair * @param inBuffer input byte array * @return Import information */ -GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExporter::ImportKey( - StdBypeArrayPtr in_buffer) { - if (in_buffer->empty()) return {}; +auto GpgKeyImportExporter::ImportKey(const GFBuffer& in_buffer) + -> std::shared_ptr<GpgImportInformation> { + if (in_buffer.Empty()) return {}; - GpgData data_in(in_buffer->data(), in_buffer->size()); - auto err = check_gpg_error(gpgme_op_import(ctx_, data_in)); + GpgData data_in(in_buffer); + auto err = CheckGpgError(gpgme_op_import(ctx_.DefaultContext(), data_in)); if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; gpgme_import_result_t result; - result = gpgme_op_import_result(ctx_); + result = gpgme_op_import_result(ctx_.DefaultContext()); gpgme_import_status_t status = result->imports; - auto import_info = std::make_unique<GpgImportInformation>(result); + auto import_info = SecureCreateSharedObject<GpgImportInformation>(result); while (status != nullptr) { - GpgImportedKey key; + GpgImportInformation::GpgImportedKey key; key.import_status = static_cast<int>(status->status); key.fpr = status->fpr; - import_info->importedKeys.emplace_back(key); + import_info->imported_keys.emplace_back(key); status = status->next; } - return *import_info; + return import_info; } /** - * Export Key - * @param uid_list key ids - * @param out_buffer output byte array + * Export keys + * @param keys keys used + * @param outBuffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, - ByteArrayPtr& out_buffer, - bool secret) const { - if (uid_list->empty()) return false; +auto GpgKeyImportExporter::ExportKey(const GpgKey& key, bool secret, bool ascii, + bool shortest, bool ssh_mode) const + -> std::tuple<GpgError, GFBuffer> { + if (!key.IsGood()) return {GPG_ERR_CANCELED, {}}; - int _mode = 0; - if (secret) _mode |= GPGME_EXPORT_MODE_SECRET; + int mode = 0; + if (secret) mode |= GPGME_EXPORT_MODE_SECRET; + if (shortest) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (ssh_mode) mode |= GPGME_EXPORT_MODE_SSH; - auto keys = GpgKeyGetter::GetInstance().GetKeys(uid_list); - auto keys_array = new gpgme_key_t[keys->size() + 1]; + std::vector<gpgme_key_t> keys_array; - int index = 0; - for (const auto& key : *keys) { - keys_array[index++] = gpgme_key_t(key); - } - keys_array[index] = nullptr; + // Last entry data_in array has to be nullptr + keys_array.emplace_back(key); + keys_array.emplace_back(nullptr); GpgData data_out; - auto err = gpgme_op_export_keys(ctx_, keys_array, _mode, data_out); - if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return false; - - delete[] keys_array; - - SPDLOG_DEBUG("export keys read_bytes: {}", - gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - - swap(temp_out_buffer, out_buffer); + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = gpgme_op_export_keys(ctx, keys_array.data(), mode, data_out); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; - return true; + GF_CORE_LOG_DEBUG( + "operation of exporting a key finished, ascii: {}, read_bytes: {}", ascii, + gpgme_data_seek(data_out, 0, SEEK_END)); + return {err, data_out.Read2GFBuffer()}; } /** @@ -109,114 +106,36 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, * @param outBuffer output byte array * @return if success */ -bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, - ByteArrayPtr& out_buffer, - bool secret) const { - KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>(); - for (const auto& key : keys) key_ids->push_back(key.GetId()); - return ExportKeys(key_ids, out_buffer, secret); +void GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, bool secret, + bool ascii, bool shortest, bool ssh_mode, + const GpgOperationCallback& cb) const { + RunGpgOperaAsync( + [=](const DataObjectPtr& data_object) -> GpgError { + if (keys.empty()) return GPG_ERR_CANCELED; + + int mode = 0; + if (secret) mode |= GPGME_EXPORT_MODE_SECRET; + if (shortest) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (ssh_mode) mode |= GPGME_EXPORT_MODE_SSH; + + std::vector<gpgme_key_t> keys_array(keys.begin(), keys.end()); + + // Last entry data_in array has to be nullptr + keys_array.emplace_back(nullptr); + + GpgData data_out; + auto* ctx = ascii ? ctx_.DefaultContext() : ctx_.BinaryContext(); + auto err = gpgme_op_export_keys(ctx, keys_array.data(), mode, data_out); + if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return {}; + + GF_CORE_LOG_DEBUG( + "operation of exporting keys finished, ascii: {}, read_bytes: {}", + ascii, gpgme_data_seek(data_out, 0, SEEK_END)); + + data_object->Swap({data_out.Read2GFBuffer()}); + return err; + }, + cb, "gpgme_op_export_keys", "2.1.0"); } -/** - * Export all the keys both private and public keys - * @param uid_list key ids - * @param out_buffer output byte array - * @return if success - */ -bool GpgFrontend::GpgKeyImportExporter::ExportAllKeys( - KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, bool secret) const { - bool result = true; - result = ExportKeys(uid_list, out_buffer, false) & result; - - ByteArrayPtr temp_buffer; - if (secret) { - result = ExportKeys(uid_list, temp_buffer, true) & result; - } - out_buffer->append(*temp_buffer); - return result; -} - -/** - * Export the secret key of a key pair(including subkeys) - * @param key target key pair - * @param outBuffer output byte array - * @return if successful - */ -bool GpgFrontend::GpgKeyImportExporter::ExportSecretKey( - const GpgKey& key, ByteArrayPtr& out_buffer) const { - SPDLOG_DEBUG("export secret key: {}", key.GetId().c_str()); - - gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; - - GpgData data_out; - // export private key to outBuffer - gpgme_error_t err = gpgme_op_export_keys(ctx_, target_key, - GPGME_EXPORT_MODE_SECRET, data_out); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportKey( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), 0, data_out); - - SPDLOG_DEBUG("export keys read_bytes: {}", - gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportKeyOpenSSH( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), GPGME_EXPORT_MODE_SSH, - data_out); - - SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -bool GpgFrontend::GpgKeyImportExporter::ExportSecretKeyShortest( - const GpgFrontend::GpgKey& key, - GpgFrontend::ByteArrayPtr& out_buffer) const { - GpgData data_out; - auto err = gpgme_op_export(ctx_, key.GetId().c_str(), - GPGME_EXPORT_MODE_MINIMAL, data_out); - - SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); - - auto temp_out_buffer = data_out.Read2Buffer(); - std::swap(out_buffer, temp_out_buffer); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; -} - -GpgFrontend::GpgImportInformation::GpgImportInformation() = default; - -GpgFrontend::GpgImportInformation::GpgImportInformation( - gpgme_import_result_t result) { - if (result->unchanged) unchanged = result->unchanged; - if (result->considered) considered = result->considered; - if (result->no_user_id) no_user_id = result->no_user_id; - if (result->imported) imported = result->imported; - if (result->imported_rsa) imported_rsa = result->imported_rsa; - if (result->unchanged) unchanged = result->unchanged; - if (result->new_user_ids) new_user_ids = result->new_user_ids; - if (result->new_sub_keys) new_sub_keys = result->new_sub_keys; - if (result->new_signatures) new_signatures = result->new_signatures; - if (result->new_revocations) new_revocations = result->new_revocations; - if (result->secret_read) secret_read = result->secret_read; - if (result->secret_imported) secret_imported = result->secret_imported; - if (result->secret_unchanged) secret_unchanged = result->secret_unchanged; - if (result->not_imported) not_imported = result->not_imported; -} +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyImportExporter.h b/src/core/function/gpg/GpgKeyImportExporter.h index 6e90f436..14b2b2bf 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.h +++ b/src/core/function/gpg/GpgKeyImportExporter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,67 +20,22 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef _GPGKEYIMPORTEXPORTOR_H -#define _GPGKEYIMPORTEXPORTOR_H +#pragma once -#include <string> - -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { -/** - * @brief - * - */ -class GpgImportedKey { - public: - std::string fpr; ///< - int import_status; ///< -}; - -typedef std::list<GpgImportedKey> GpgImportedKeyList; ///< - -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT GpgImportInformation { - public: - GpgImportInformation(); - - /** - * @brief Construct a new Gpg Import Information object - * - * @param result - */ - explicit GpgImportInformation(gpgme_import_result_t result); - - int considered = 0; ///< - int no_user_id = 0; ///< - int imported = 0; ///< - int imported_rsa = 0; ///< - int unchanged = 0; ///< - int new_user_ids = 0; ///< - int new_sub_keys = 0; ///< - int new_signatures = 0; ///< - int new_revocations = 0; ///< - int secret_read = 0; ///< - int secret_imported = 0; ///< - int secret_unchanged = 0; ///< - int not_imported = 0; ///< - - GpgImportedKeyList importedKeys; ///< -}; +class GpgImportInformation; /** * @brief @@ -103,31 +58,19 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter * @param inBuffer * @return GpgImportInformation */ - GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer); + auto ImportKey(const GFBuffer&) -> std::shared_ptr<GpgImportInformation>; /** * @brief * - * @param uid_list - * @param out_buffer - * @param secret - * @return true - * @return false - */ - bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, - bool secret = false) const; - - /** - * @brief - * - * @param keys - * @param outBuffer + * @param key * @param secret - * @return true - * @return false + * @param ascii + * @return std::tuple<GpgError, GFBuffer> */ - bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer, - bool secret = false) const; + [[nodiscard]] auto ExportKey(const GpgKey& key, bool secret, bool ascii, + bool shortest, bool ssh_mode = false) const + -> std::tuple<GpgError, GFBuffer>; /** * @brief @@ -138,55 +81,12 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter * @return true * @return false */ - bool ExportAllKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, - bool secret) const; - - /** - * @brief - * - * @param key - * @param out_buffer - * @return true - * @return false - */ - bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const; - - /** - * @brief - * - * @param key - * @param out_buffer - * @return true - * @return false - */ - bool ExportKeyOpenSSH(const GpgKey& key, ByteArrayPtr& out_buffer) const; - - /** - * @brief - * - * @param key - * @param outBuffer - * @return true - * @return false - */ - bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const; - - /** - * @brief - * - * @param key - * @param outBuffer - * @return true - * @return false - */ - bool ExportSecretKeyShortest(const GpgKey& key, - ByteArrayPtr& outBuffer) const; + void ExportKeys(const KeyArgsList& keys, bool secret, bool ascii, + bool shortest, bool ssh_mode, + const GpgOperationCallback& cb) const; private: - GpgContext& ctx_ = - GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< + GpgContext& ctx_; }; } // namespace GpgFrontend - -#endif // _GPGKEYIMPORTEXPORTOR_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyManager.cpp b/src/core/function/gpg/GpgKeyManager.cpp index e556eec6..8d7d9a28 100644 --- a/src/core/function/gpg/GpgKeyManager.cpp +++ b/src/core/function/gpg/GpgKeyManager.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,150 +28,146 @@ #include "GpgKeyManager.h" -#include <boost/algorithm/string.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <memory> -#include <string> - -#include "GpgBasicOperator.h" -#include "GpgKeyGetter.h" -#include "spdlog/spdlog.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/GpgUtils.h" GpgFrontend::GpgKeyManager::GpgKeyManager(int channel) : SingletonFunctionObject<GpgKeyManager>(channel) {} -bool GpgFrontend::GpgKeyManager::SignKey( +auto GpgFrontend::GpgKeyManager::SignKey( const GpgFrontend::GpgKey& target, GpgFrontend::KeyArgsList& keys, - const std::string& uid, - const std::unique_ptr<boost::posix_time::ptime>& expires) { - using namespace boost::posix_time; - - GpgBasicOperator::GetInstance().SetSigners(keys); + const QString& uid, const std::unique_ptr<QDateTime>& expires) -> bool { + GpgBasicOperator::GetInstance().SetSigners(keys, true); unsigned int flags = 0; unsigned int expires_time_t = 0; - if (expires == nullptr) + if (expires == nullptr) { flags |= GPGME_KEYSIGN_NOEXPIRE; - else - expires_time_t = to_time_t(*expires); + } else { + expires_time_t = expires->toSecsSinceEpoch(); + } - auto err = check_gpg_error(gpgme_op_keysign( - ctx_, gpgme_key_t(target), uid.c_str(), expires_time_t, flags)); + auto err = CheckGpgError( + gpgme_op_keysign(ctx_.DefaultContext(), static_cast<gpgme_key_t>(target), + uid.toUtf8(), expires_time_t, flags)); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgKeyManager::RevSign( +auto GpgFrontend::GpgKeyManager::RevSign( const GpgFrontend::GpgKey& key, - const GpgFrontend::SignIdArgsListPtr& signature_id) { + const GpgFrontend::SignIdArgsListPtr& signature_id) -> bool { auto& key_getter = GpgKeyGetter::GetInstance(); for (const auto& sign_id : *signature_id) { auto signing_key = key_getter.GetKey(sign_id.first); assert(signing_key.IsGood()); - auto err = check_gpg_error(gpgme_op_revsig(ctx_, gpgme_key_t(key), - gpgme_key_t(signing_key), - sign_id.second.c_str(), 0)); - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) return false; + auto err = CheckGpgError( + gpgme_op_revsig(ctx_.DefaultContext(), gpgme_key_t(key), + gpgme_key_t(signing_key), sign_id.second.toUtf8(), 0)); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) return false; } return true; } -bool GpgFrontend::GpgKeyManager::SetExpire( - const GpgFrontend::GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, - std::unique_ptr<boost::posix_time::ptime>& expires) { - using namespace boost::posix_time; - +auto GpgFrontend::GpgKeyManager::SetExpire(const GpgFrontend::GpgKey& key, + std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<QDateTime>& expires) + -> bool { unsigned long expires_time = 0; - if (expires != nullptr) expires_time = to_time_t(ptime(*expires)); + if (expires != nullptr) expires_time = expires->toSecsSinceEpoch(); const char* sub_fprs = nullptr; - if (subkey != nullptr) sub_fprs = subkey->GetFingerprint().c_str(); + if (subkey != nullptr) sub_fprs = subkey->GetFingerprint().toUtf8(); - auto err = check_gpg_error( - gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, sub_fprs, 0)); + auto err = CheckGpgError(gpgme_op_setexpire(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), + expires_time, sub_fprs, 0)); - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR; + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, - int trust_level) { +auto GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, + int trust_level) -> bool { if (trust_level < 0 || trust_level > 5) { - SPDLOG_ERROR("illegal owner trust level: {}", trust_level); + GF_CORE_LOG_ERROR("illegal owner trust level: {}", trust_level); } - AutomatonNextStateHandler next_state_handler = - [](AutomatonState state, std::string status, std::string args) { - SPDLOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}", - state, status, args); - std::vector<std::string> tokens; - boost::split(tokens, args, boost::is_any_of(" ")); - - switch (state) { - case AS_START: - if (status == "GET_LINE" && args == "keyedit.prompt") - return AS_COMMAND; - return AS_ERROR; - case AS_COMMAND: - if (status == "GET_LINE" && args == "edit_ownertrust.value") { - return AS_VALUE; - } - return AS_ERROR; - case AS_VALUE: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } else if (status == "GET_BOOL" && - args == "edit_ownertrust.set_ultimate.okay") { - return AS_REALLY_ULTIMATE; - } - return AS_ERROR; - case AS_REALLY_ULTIMATE: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } - return AS_ERROR; - case AS_QUIT: - if (status == "GET_LINE" && args == "keyedit.save.okay") { - return AS_SAVE; - } - return AS_ERROR; - case AS_ERROR: - if (status == "GET_LINE" && args == "keyedit.prompt") { - return AS_QUIT; - } - return AS_ERROR; - default: - return AS_ERROR; - }; - }; + AutomatonNextStateHandler next_state_handler = [](AutomatonState state, + QString status, + QString args) { + GF_CORE_LOG_DEBUG("next_state_handler state: {}, gpg_status: {}, args: {}", + state, status, args); + auto tokens = args.split(' '); + + switch (state) { + case AS_START: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_COMMAND; + } + return AS_ERROR; + case AS_COMMAND: + if (status == "GET_LINE" && args == "edit_ownertrust.value") { + return AS_VALUE; + } + return AS_ERROR; + case AS_VALUE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } else if (status == "GET_BOOL" && + args == "edit_ownertrust.set_ultimate.okay") { + return AS_REALLY_ULTIMATE; + } + return AS_ERROR; + case AS_REALLY_ULTIMATE: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } + return AS_ERROR; + case AS_QUIT: + if (status == "GET_LINE" && args == "keyedit.save.okay") { + return AS_SAVE; + } + return AS_ERROR; + case AS_ERROR: + if (status == "GET_LINE" && args == "keyedit.prompt") { + return AS_QUIT; + } + return AS_ERROR; + default: + return AS_ERROR; + }; + }; AutomatonActionHandler action_handler = [trust_level](AutomatonHandelStruct& handler, AutomatonState state) { - SPDLOG_DEBUG("action_handler state: {}", state); + GF_CORE_LOG_DEBUG("action_handler state: {}", state); switch (state) { case AS_COMMAND: - return std::string("trust"); + return QString("trust"); case AS_VALUE: handler.SetSuccess(true); - return std::to_string(trust_level); + return QString::number(trust_level); case AS_REALLY_ULTIMATE: handler.SetSuccess(true); - return std::string("Y"); + return QString("Y"); case AS_QUIT: - return std::string("quit"); + return QString("quit"); case AS_SAVE: handler.SetSuccess(true); - return std::string("Y"); + return QString("Y"); case AS_START: case AS_ERROR: - return std::string(""); + return QString(""); default: - return std::string(""); + return QString(""); } - return std::string(""); + return QString(""); }; auto key_fpr = key.GetFingerprint(); @@ -180,49 +176,43 @@ bool GpgFrontend::GpgKeyManager::SetOwnerTrustLevel(const GpgKey& key, GpgData data_out; - auto err = gpgme_op_interact(ctx_, gpgme_key_t(key), 0, - GpgKeyManager::interactor_cb_fnc, - (void*)&handel_struct, data_out); - if (err != GPG_ERR_NO_ERROR) { - SPDLOG_ERROR("fail to set owner trust level {} to key {}, err: {}", - trust_level, key.GetId(), gpgme_strerror(err)); - } - - return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR && - handel_struct.Success(); + auto err = gpgme_op_interact( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), 0, + GpgKeyManager::interactor_cb_fnc, (void*)&handel_struct, data_out); + return CheckGpgError(err) == GPG_ERR_NO_ERROR && handel_struct.Success(); } -gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, - const char* status, - const char* args, - int fd) { - auto handle_struct = static_cast<AutomatonHandelStruct*>(handle); - std::string status_s = status; - std::string args_s = args; - SPDLOG_DEBUG("cb start status: {}, args: {}, fd: {}, handle struct state: {}", - status_s, args_s, fd, handle_struct->CuurentStatus()); +auto GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, + const char* status, + const char* args, int fd) + -> gpgme_error_t { + auto* handle_struct = static_cast<AutomatonHandelStruct*>(handle); + QString status_s = status; + QString args_s = args; + GF_CORE_LOG_DEBUG( + "cb start status: {}, args: {}, fd: {}, handle struct state: {}", + status_s, args_s, fd, handle_struct->CuurentStatus()); if (status_s == "KEY_CONSIDERED") { - std::vector<std::string> tokens; - boost::split(tokens, args, boost::is_any_of(" ")); + auto tokens = QString(args).split(' '); if (tokens.empty() || tokens[0] != handle_struct->KeyFpr()) { - SPDLOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...", - handle_struct->KeyFpr(), tokens[0]); + GF_CORE_LOG_ERROR("handle struct key fpr {} mismatch token: {}, exit...", + handle_struct->KeyFpr(), tokens[0]); return -1; } return 0; } - if (status_s == "GOT_IT" || status_s.empty()) { - SPDLOG_DEBUG("status GOT_IT, continue..."); + if (status_s == "GOT_IT" || status_s.isEmpty()) { + GF_CORE_LOG_DEBUG("status GOT_IT, continue..."); return 0; } AutomatonState next_state = handle_struct->NextState(status_s, args_s); if (next_state == AS_ERROR) { - SPDLOG_DEBUG("handle struct next state caught error, skipping..."); + GF_CORE_LOG_DEBUG("handle struct next state caught error, skipping..."); return GPG_ERR_FALSE; } @@ -233,10 +223,11 @@ gpgme_error_t GpgFrontend::GpgKeyManager::interactor_cb_fnc(void* handle, // set state and preform action handle_struct->SetStatus(next_state); Command cmd = handle_struct->Action(); - SPDLOG_DEBUG("handle struct action done, next state: {}, action cmd: {}", - next_state, cmd); - if (!cmd.empty()) { - gpgme_io_write(fd, cmd.c_str(), cmd.size()); + GF_CORE_LOG_DEBUG("handle struct action done, next state: {}, action cmd: {}", + next_state, cmd); + if (!cmd.isEmpty()) { + auto btye_array = cmd.toUtf8(); + gpgme_io_write(fd, btye_array, btye_array.size()); gpgme_io_write(fd, "\n", 1); } else if (status_s == "GET_LINE") { // avoid trapping in this state diff --git a/src/core/function/gpg/GpgKeyManager.h b/src/core/function/gpg/GpgKeyManager.h index 62f7baca..8b4d41b2 100644 --- a/src/core/function/gpg/GpgKeyManager.h +++ b/src/core/function/gpg/GpgKeyManager.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,19 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H -#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H +#pragma once #include <functional> -#include <string> -#include "core/GpgContext.h" -#include "core/GpgFunctionObject.h" -#include "core/GpgModel.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -60,8 +58,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @param expires expire date and time of the signature * @return if successful */ - bool SignKey(const GpgKey& target, KeyArgsList& keys, const std::string& uid, - const std::unique_ptr<boost::posix_time::ptime>& expires); + auto SignKey(const GpgKey& target, KeyArgsList& keys, const QString& uid, + const std::unique_ptr<QDateTime>& expires) -> bool; /** * @brief @@ -71,8 +69,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @return true * @return false */ - bool RevSign(const GpgFrontend::GpgKey& key, - const GpgFrontend::SignIdArgsListPtr& signature_id); + auto RevSign(const GpgFrontend::GpgKey& key, + const GpgFrontend::SignIdArgsListPtr& signature_id) -> bool; /** * @brief Set the Expire object @@ -83,21 +81,21 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager * @return true * @return false */ - bool SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, - std::unique_ptr<boost::posix_time::ptime>& expires); + auto SetExpire(const GpgKey& key, std::unique_ptr<GpgSubKey>& subkey, + std::unique_ptr<QDateTime>& expires) -> bool; /** * @brief * * @return */ - bool SetOwnerTrustLevel(const GpgKey& key, int trust_level); + auto SetOwnerTrustLevel(const GpgKey& key, int trust_level) -> bool; private: - static gpgme_error_t interactor_cb_fnc(void* handle, const char* status, - const char* args, int fd); + static auto interactor_cb_fnc(void* handle, const char* status, + const char* args, int fd) -> gpgme_error_t; - using Command = std::string; + using Command = QString; using AutomatonState = enum { AS_START, AS_COMMAND, @@ -113,35 +111,37 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager using AutomatonActionHandler = std::function<Command(AutomatonHandelStruct&, AutomatonState)>; using AutomatonNextStateHandler = - std::function<AutomatonState(AutomatonState, std::string, std::string)>; + std::function<AutomatonState(AutomatonState, QString, QString)>; struct AutomatonHandelStruct { void SetStatus(AutomatonState next_state) { current_state_ = next_state; } - AutomatonState CuurentStatus() { return current_state_; } + auto CuurentStatus() -> AutomatonState { return current_state_; } void SetHandler(AutomatonNextStateHandler next_state_handler, AutomatonActionHandler action_handler) { - next_state_handler_ = next_state_handler; - action_handler_ = action_handler; + next_state_handler_ = std::move(next_state_handler); + action_handler_ = std::move(action_handler); } - AutomatonState NextState(std::string gpg_status, std::string args) { - return next_state_handler_(current_state_, gpg_status, args); + auto NextState(QString gpg_status, QString args) -> AutomatonState { + return next_state_handler_(current_state_, std::move(gpg_status), + std::move(args)); } - Command Action() { return action_handler_(*this, current_state_); } + auto Action() -> Command { return action_handler_(*this, current_state_); } void SetSuccess(bool success) { success_ = success; } - bool Success() { return success_; } + [[nodiscard]] auto Success() const -> bool { return success_; } - std::string KeyFpr() { return key_fpr_; } + auto KeyFpr() -> QString { return key_fpr_; } - AutomatonHandelStruct(std::string key_fpr) : key_fpr_(key_fpr) {} + explicit AutomatonHandelStruct(QString key_fpr) + : key_fpr_(std::move(key_fpr)) {} private: AutomatonState current_state_ = AS_START; AutomatonNextStateHandler next_state_handler_; AutomatonActionHandler action_handler_; bool success_ = false; - std::string key_fpr_; + QString key_fpr_; }; GpgContext& ctx_ = @@ -149,5 +149,3 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyManager }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index d5919cff..d9133905 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,38 +28,42 @@ #include "GpgKeyOpera.h" -#include <boost/asio.hpp> -#include <boost/date_time/posix_time/conversion.hpp> -#include <boost/format.hpp> -#include <boost/process/async_pipe.hpp> -#include <memory> -#include <string> -#include <vector> +#include <gpg-error.h> -#include "GpgCommandExecutor.h" -#include "GpgKeyGetter.h" -#include "core/GpgConstants.h" -#include "core/GpgGenKeyInfo.h" +#include <memory> -GpgFrontend::GpgKeyOpera::GpgKeyOpera(int channel) +#include "core/GpgModel.h" +#include "core/function/gpg/GpgCommandExecutor.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/DataObject.h" +#include "core/model/GpgGenKeyInfo.h" +#include "core/model/GpgGenerateKeyResult.h" +#include "core/module/ModuleManager.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/AsyncUtils.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" + +namespace GpgFrontend { + +GpgKeyOpera::GpgKeyOpera(int channel) : SingletonFunctionObject<GpgKeyOpera>(channel) {} /** * Delete keys * @param uidList key ids */ -void GpgFrontend::GpgKeyOpera::DeleteKeys( - GpgFrontend::KeyIdArgsListPtr key_ids) { +void GpgKeyOpera::DeleteKeys(GpgFrontend::KeyIdArgsListPtr key_ids) { GpgError err; for (const auto& tmp : *key_ids) { auto key = GpgKeyGetter::GetInstance().GetKey(tmp); if (key.IsGood()) { - err = check_gpg_error( - gpgme_op_delete_ext(ctx_, gpgme_key_t(key), - GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); + err = CheckGpgError(gpgme_op_delete_ext( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); assert(gpg_err_code(err) == GPG_ERR_NO_ERROR); } else { - SPDLOG_WARN("GpgKeyOpera DeleteKeys get key failed", tmp); + GF_CORE_LOG_WARN("GpgKeyOpera DeleteKeys get key failed", tmp); } } } @@ -72,26 +76,24 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys( * @param expires date and time * @return if successful */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( - const GpgKey& key, const SubkeyId& subkey_fpr, - std::unique_ptr<boost::posix_time::ptime>& expires) { +auto GpgKeyOpera::SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<QDateTime>& expires) -> GpgError { unsigned long expires_time = 0; if (expires != nullptr) { - using namespace boost::posix_time; - using namespace std::chrono; - expires_time = - to_time_t(*expires) - system_clock::to_time_t(system_clock::now()); + expires_time = QDateTime::currentDateTime().secsTo(*expires); } - SPDLOG_DEBUG(key.GetId(), subkey_fpr, expires_time); - GpgError err; - if (key.GetFingerprint() == subkey_fpr || subkey_fpr.empty()) - err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, nullptr, 0); - else - err = gpgme_op_setexpire(ctx_, gpgme_key_t(key), expires_time, - subkey_fpr.c_str(), 0); + if (key.GetFingerprint() == subkey_fpr || subkey_fpr.isEmpty()) { + err = + gpgme_op_setexpire(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + expires_time, nullptr, 0); + } else { + err = + gpgme_op_setexpire(ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), + expires_time, subkey_fpr.toUtf8(), 0); + } return err; } @@ -102,48 +104,52 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( * @param outputFileName out file name(path) * @return the process doing this job */ -void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( - const GpgKey& key, const std::string& output_file_path) { +void GpgKeyOpera::GenerateRevokeCert(const GpgKey& key, + const QString& output_path) { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); // get all components - GpgCommandExecutor::GetInstance().Execute( - ctx_.GetInfo().AppPath, - {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", - output_file_path, "--gen-revoke", key.GetFingerprint().c_str()}, - [=](int exit_code, const std::string& p_out, const std::string& p_err) { - if (exit_code != 0) { - SPDLOG_ERROR( - "gnupg gen revoke execute error, process stderr: {}, process " - "stdout: {}", - p_err, p_out); - } else { - SPDLOG_DEBUG( - "gnupg gen revoke exit_code: {}, process stdout size: {}", - exit_code, p_out.size()); - } - }, - [](QProcess* proc) -> void { - // Code From Gpg4Win - while (proc->canReadLine()) { - const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - SPDLOG_DEBUG("line: {}", line.toStdString()); - if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.code")) { - proc->write("0\n"); - } else if (line == QLatin1String("[GNUPG:] GET_LINE " - "ask_revocation_reason.text")) { - proc->write("\n"); - } else if (line == QLatin1String( - "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { - // We asked before - proc->write("y\n"); - } else if (line == QLatin1String("[GNUPG:] GET_BOOL " - "ask_revocation_reason.okay")) { - proc->write("y\n"); - } - } - }); + GpgCommandExecutor::ExecuteSync( + {app_path, + {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", output_path, + "--gen-revoke", key.GetFingerprint()}, + [=](int exit_code, const QString& p_out, const QString& p_err) { + if (exit_code != 0) { + GF_CORE_LOG_ERROR( + "gnupg gen revoke execute error, process stderr: {}, process " + "stdout: {}", + p_err, p_out); + } else { + GF_CORE_LOG_DEBUG( + "gnupg gen revoke exit_code: {}, process stdout size: {}", + exit_code, p_out.size()); + } + }, + nullptr, + [](QProcess* proc) -> void { + // Code From Gpg4Win + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + GF_CORE_LOG_DEBUG("line: {}", line.toStdString()); + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.code")) { + proc->write("0\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == + QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_BOOL " + "ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }}); } /** @@ -151,138 +157,199 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( * @param params key generation args * @return error information */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( - const std::unique_ptr<GenKeyInfo>& params, GpgGenKeyResult& result) { - auto userid_utf8 = params->GetUserid(); - const char* userid = userid_utf8.c_str(); - auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); - - SPDLOG_DEBUG("params: {} {}", params->GetAlgo(), params->GetKeySizeStr()); - - const char* algo = algo_utf8.c_str(); - unsigned long expires = 0; - { - using namespace boost::posix_time; - using namespace std::chrono; - expires = to_time_t(ptime(params->GetExpireTime())) - - system_clock::to_time_t(system_clock::now()); - } +void GpgKeyOpera::GenerateKey(const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&ctx = ctx_, params](const DataObjectPtr& data_object) -> GpgError { + auto userid_utf8 = params->GetUserid(); + const char* userid = userid_utf8.toUtf8(); + auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); + + GF_CORE_LOG_DEBUG("params: {} {}", params->GetAlgo(), + params->GetKeySizeStr()); + + auto algo = algo_utf8.toUtf8(); + unsigned long expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + + GpgError err; + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("key generation args: {}", userid, algo, expires, + flags); + err = gpgme_op_createkey(ctx.DefaultContext(), userid, algo, 0, expires, + nullptr, flags); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{ + gpgme_op_genkey_result(ctx.DefaultContext())}}); + } else { + data_object->Swap({GpgGenerateKeyResult{}}); + } - GpgError err; + return CheckGpgError(err); + }, + callback, "gpgme_op_createkey", "2.1.0"); +} - SPDLOG_DEBUG("ctx version, {}", ctx_.GetInfo(false).GnupgVersion); +/** + * Generate a new subkey of a certain key pair + * @param key target key pair + * @param params opera args + * @return error info + */ +void GpgKeyOpera::GenerateSubkey(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [key, &ctx = ctx_, params](const DataObjectPtr&) -> GpgError { + if (!params->IsSubKey()) return GPG_ERR_CANCELED; + + GF_CORE_LOG_DEBUG("generate subkey algo {} key size {}", + params->GetAlgo(), params->GetKeySizeStr()); + + auto algo = (params->GetAlgo() + params->GetKeySizeStr()).toUtf8(); + unsigned long expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("args: {} {} {} {}", key.GetId(), algo, expires, + flags); + + auto err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + expires, flags); + return CheckGpgError(err); + }, + callback, "gpgme_op_createsubkey", "2.1.13"); +} - if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") { - unsigned int flags = 0; +void GpgKeyOpera::GenerateKeyWithSubkey( + const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&ctx = ctx_, params, + subkey_params](const DataObjectPtr& data_object) -> GpgError { + auto userid = params->GetUserid().toUtf8(); + auto algo = (params->GetAlgo() + params->GetKeySizeStr()).toUtf8(); + unsigned long expires = expires = + QDateTime::currentDateTime().secsTo(params->GetExpireTime()); + + GpgError err; + unsigned int flags = 0; + + if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; + if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + + GF_CORE_LOG_DEBUG("key generation args: {}", userid, algo, expires, + flags); + err = gpgme_op_createkey(ctx.DefaultContext(), userid, algo, 0, expires, + nullptr, flags); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + data_object->Swap({GpgGenerateKeyResult{}}); + return err; + } - if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; - if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + auto genkey_result = + GpgGenerateKeyResult{gpgme_op_genkey_result(ctx.DefaultContext())}; - SPDLOG_DEBUG("args: {}", userid, algo, expires, flags); + auto key = + GpgKeyGetter::GetInstance().GetKey(genkey_result.GetFingerprint()); + if (!key.IsGood()) { + GF_CORE_LOG_ERROR("cannot get key which has been generate, fpr: {}", + genkey_result.GetFingerprint()); + return err; + } - err = gpgme_op_createkey(ctx_, userid, algo, 0, expires, nullptr, flags); + if (subkey_params == nullptr || !subkey_params->IsSubKey()) return err; - } else { - std::stringstream ss; - auto param_format = - boost::format{ - "<GnupgKeyParms format=\"internal\">\n" - "Key-Type: %1%\n" - "Key-Usage: sign\n" - "Key-Length: %2%\n" - "Name-Real: %3%\n" - "Name-Comment: %4%\n" - "Name-Email: %5%\n"} % - params->GetAlgo() % params->GetKeyLength() % params->GetName() % - params->GetComment() % params->GetEmail(); - ss << param_format; - - if (!params->IsNonExpired()) { - auto date = params->GetExpireTime().date(); - ss << boost::format{"Expire-Date: %1%\n"} % to_iso_string(date); - } else - ss << boost::format{"Expire-Date: 0\n"}; - if (!params->IsNoPassPhrase()) - ss << boost::format{"Passphrase: %1%\n"} % params->GetPassPhrase(); - - ss << "</GnupgKeyParms>"; - - SPDLOG_DEBUG("params: {}", ss.str()); - - err = gpgme_op_genkey(ctx_, ss.str().c_str(), nullptr, nullptr); - } + GF_CORE_LOG_DEBUG( + "try to generate subkey of key: {}, algo {} key size {}", + key.GetId(), subkey_params->GetAlgo(), + subkey_params->GetKeySizeStr()); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) { - auto temp_result = _new_result(gpgme_op_genkey_result(ctx_)); - std::swap(temp_result, result); - } + algo = (subkey_params->GetAlgo() + subkey_params->GetKeySizeStr()) + .toUtf8(); + expires = + QDateTime::currentDateTime().secsTo(subkey_params->GetExpireTime()); - return check_gpg_error(err); -} + flags = 0; + if (subkey_params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; + if (subkey_params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; + if (subkey_params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; + if (subkey_params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (subkey_params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; -/** - * Generate a new subkey of a certain key pair - * @param key target key pair - * @param params opera args - * @return error info - */ -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( - const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { - if (!params->IsSubKey()) return GPG_ERR_CANCELED; - - SPDLOG_DEBUG("generate subkey algo {} key size {}", params->GetAlgo(), - params->GetKeySizeStr()); - - auto algo_utf8 = (params->GetAlgo() + params->GetKeySizeStr()); - const char* algo = algo_utf8.c_str(); - unsigned long expires = 0; - { - using namespace boost::posix_time; - using namespace std::chrono; - expires = to_time_t(ptime(params->GetExpireTime())) - - system_clock::to_time_t(system_clock::now()); - } - unsigned int flags = 0; + GF_CORE_LOG_DEBUG("subkey generation args: {} {} {} {}", key.GetId(), + algo, expires, flags); - if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; - if (params->IsAllowEncryption()) flags |= GPGME_CREATE_ENCR; - if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; - if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; - if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; - if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; + err = gpgme_op_createsubkey(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), algo, 0, + expires, flags); - SPDLOG_DEBUG("args: {} {} {} {}", key.GetId(), algo, expires, flags); + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + data_object->Swap( + {genkey_result, GpgGenerateKeyResult{gpgme_op_genkey_result( + ctx.DefaultContext())}}); + } else { + data_object->Swap({genkey_result, GpgGenerateKeyResult{}}); + } - auto err = - gpgme_op_createsubkey(ctx_, gpgme_key_t(key), algo, 0, expires, flags); - return check_gpg_error(err); + return CheckGpgError(err); + }, + callback, "gpgme_op_createkey&gpgme_op_createsubkey", "2.1.0"); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( - const GpgFrontend::GpgKey& key) { - if (ctx_.GetInfo(false).GnupgVersion < "2.0.15") { - SPDLOG_ERROR("operator not support"); - return GPG_ERR_NOT_SUPPORTED; - } - auto err = gpgme_op_passwd(ctx_, gpgme_key_t(key), 0); - return check_gpg_error(err); +void GpgKeyOpera::ModifyPassword(const GpgKey& key, + const GpgOperationCallback& callback) { + RunGpgOperaAsync( + [&key, &ctx = ctx_](const DataObjectPtr&) -> GpgError { + return gpgme_op_passwd(ctx.DefaultContext(), + static_cast<gpgme_key_t>(key), 0); + }, + callback, "gpgme_op_passwd", "2.0.15"); } -GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy( - const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) { - if (ctx_.GetInfo(false).GnupgVersion < "2.1.10") { - SPDLOG_ERROR("operator not support"); + +auto GpgKeyOpera::ModifyTOFUPolicy(const GpgKey& key, + gpgme_tofu_policy_t tofu_policy) + -> GpgError { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + if (CompareSoftwareVersion(gnupg_version, "2.1.10") < 0) { + GF_CORE_LOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } - auto err = gpgme_op_tofu_policy(ctx_, gpgme_key_t(key), tofu_policy); - return check_gpg_error(err); + + auto err = gpgme_op_tofu_policy(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), tofu_policy); + return CheckGpgError(err); } -void GpgFrontend::GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { +void GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) { auto keys = std::make_unique<KeyIdArgsList>(); keys->push_back(key_id); DeleteKeys(std::move(keys)); } +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h index 5446bd66..a060af1a 100644 --- a/src/core/function/gpg/GpgKeyOpera.h +++ b/src/core/function/gpg/GpgKeyOpera.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,18 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef _GPGKEYOPERA_H -#define _GPGKEYOPERA_H +#pragma once -#include "core/GpgConstants.h" -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include <functional> + +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** @@ -77,8 +77,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param expires * @return GpgError */ - GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, - std::unique_ptr<boost::posix_time::ptime>& expires); + auto SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr, + std::unique_ptr<QDateTime>& expires) -> GpgError; /** * @brief @@ -86,8 +86,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param key * @param output_file_name */ - void GenerateRevokeCert(const GpgKey& key, - const std::string& output_file_name); + void GenerateRevokeCert(const GpgKey& key, const QString& output_path); /** * @brief @@ -95,7 +94,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param key * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError ModifyPassword(const GpgKey& key); + void ModifyPassword(const GpgKey& key, const GpgOperationCallback&); /** * @brief @@ -104,8 +103,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param tofu_policy * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError ModifyTOFUPolicy(const GpgKey& key, - gpgme_tofu_policy_t tofu_policy); + auto ModifyTOFUPolicy(const GpgKey& key, gpgme_tofu_policy_t tofu_policy) + -> GpgFrontend::GpgError; /** * @brief * @@ -113,8 +112,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param result * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params, - GpgGenKeyResult& result); + void GenerateKey(const std::shared_ptr<GenKeyInfo>&, + const GpgOperationCallback&); /** * @brief @@ -123,13 +122,23 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera * @param params * @return GpgFrontend::GpgError */ - GpgFrontend::GpgError GenerateSubkey( - const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params); + void GenerateSubkey(const GpgKey& key, + const std::shared_ptr<GenKeyInfo>& params, + const GpgOperationCallback&); + + /** + * @brief + * + * @param params + * @param subkey_params + * @param callback + */ + void GenerateKeyWithSubkey(const std::shared_ptr<GenKeyInfo>& params, + const std::shared_ptr<GenKeyInfo>& subkey_params, + const GpgOperationCallback& callback); private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///< }; } // namespace GpgFrontend - -#endif // _GPGKEYOPERA_H
\ No newline at end of file diff --git a/src/core/function/gpg/GpgUIDOperator.cpp b/src/core/function/gpg/GpgUIDOperator.cpp index 7e7a711e..6c0373de 100644 --- a/src/core/function/gpg/GpgUIDOperator.cpp +++ b/src/core/function/gpg/GpgUIDOperator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,44 +28,38 @@ #include "GpgUIDOperator.h" -#include "boost/format.hpp" +#include "core/GpgModel.h" +#include "core/utils/GpgUtils.h" -GpgFrontend::GpgUIDOperator::GpgUIDOperator(int channel) +namespace GpgFrontend { + +GpgUIDOperator::GpgUIDOperator(int channel) : SingletonFunctionObject<GpgUIDOperator>(channel) {} -bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = gpgme_op_adduid(ctx_, gpgme_key_t(key), uid.c_str(), 0); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& uid) -> bool { + auto err = gpgme_op_adduid(ctx_.DefaultContext(), + static_cast<gpgme_key_t>(key), uid.toUtf8(), 0); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::RevUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = - check_gpg_error(gpgme_op_revuid(ctx_, gpgme_key_t(key), uid.c_str(), 0)); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::RevUID(const GpgKey& key, const QString& uid) -> bool { + auto err = CheckGpgError(gpgme_op_revuid( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), uid.toUtf8(), 0)); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::SetPrimaryUID(const GpgFrontend::GpgKey& key, - const std::string& uid) { - auto err = check_gpg_error(gpgme_op_set_uid_flag( - ctx_, gpgme_key_t(key), uid.c_str(), "primary", nullptr)); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) - return true; - else - return false; +auto GpgUIDOperator::SetPrimaryUID(const GpgKey& key, const QString& uid) + -> bool { + auto err = CheckGpgError(gpgme_op_set_uid_flag( + ctx_.DefaultContext(), static_cast<gpgme_key_t>(key), uid.toUtf8(), + "primary", nullptr)); + return CheckGpgError(err) == GPG_ERR_NO_ERROR; } -bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, - const std::string& name, - const std::string& comment, - const std::string& email) { - SPDLOG_DEBUG("new uuid: {} {} {}", name, comment, email); - auto uid = boost::format("%1%(%2%)<%3%>") % name % comment % email; - return AddUID(key, uid.str()); +auto GpgUIDOperator::AddUID(const GpgKey& key, const QString& name, + const QString& comment, const QString& email) + -> bool { + GF_CORE_LOG_DEBUG("new uuid: {} {} {}", name, comment, email); + return AddUID(key, QString("%1(%2)<%3>").arg(name).arg(comment).arg(email)); } + +} // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgUIDOperator.h b/src/core/function/gpg/GpgUIDOperator.h index c4a7d87b..b2cec8bc 100644 --- a/src/core/function/gpg/GpgUIDOperator.h +++ b/src/core/function/gpg/GpgUIDOperator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H -#define GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H +#pragma once -#include "core/GpgContext.h" -#include "core/GpgModel.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { /** @@ -54,7 +53,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid uid args(combine name&comment&email) * @return if successful */ - bool AddUID(const GpgKey& key, const std::string& uid); + auto AddUID(const GpgKey& key, const QString& uid) -> bool; /** * create a new uid in certain key pair @@ -64,8 +63,8 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param email * @return */ - bool AddUID(const GpgKey& key, const std::string& name, - const std::string& comment, const std::string& email); + auto AddUID(const GpgKey& key, const QString& name, const QString& comment, + const QString& email) -> bool; /** * Revoke(Delete) UID from certain key pair @@ -73,7 +72,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid target uid * @return if successful */ - bool RevUID(const GpgKey& key, const std::string& uid); + auto RevUID(const GpgKey& key, const QString& uid) -> bool; /** * Set one of a uid of a key pair as primary @@ -81,7 +80,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator * @param uid target uid * @return if successful */ - bool SetPrimaryUID(const GpgKey& key, const std::string& uid); + auto SetPrimaryUID(const GpgKey& key, const QString& uid) -> bool; private: GpgContext& ctx_ = @@ -89,5 +88,3 @@ class GPGFRONTEND_CORE_EXPORT GpgUIDOperator }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp index d3ec8d6e..5d0ce920 100644 --- a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,70 +28,103 @@ #include "GpgDecryptResultAnalyse.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" GpgFrontend::GpgDecryptResultAnalyse::GpgDecryptResultAnalyse( - GpgError m_error, GpgDecrResult m_result) - : error_(m_error), result_(std::move(m_result)) {} + GpgError m_error, GpgDecryptResult m_result) + : error_(m_error), result_(m_result) {} -void GpgFrontend::GpgDecryptResultAnalyse::do_analyse() { - stream_ << "[#] " << _("Decrypt Operation"); +void GpgFrontend::GpgDecryptResultAnalyse::doAnalyse() { + auto *result = result_.GetRaw(); + + stream_ << "# " << tr("Decrypt Operation") << " "; if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { - stream_ << "[" << _("Success") << "]" << std::endl; + stream_ << "- " << tr("Success") << " " << Qt::endl; } else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); - if (result_ != nullptr && result_->unsupported_algorithm != nullptr) { - stream_ << "------------>" << std::endl; - stream_ << _("Unsupported Algo") << ": " << result_->unsupported_algorithm - << std::endl; + stream_ << "- " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); + if (result != nullptr && result->unsupported_algorithm != nullptr) { + stream_ << Qt::endl; + stream_ << "## " << tr("Unsupported Algo") << ": " + << result->unsupported_algorithm << Qt::endl; } } - if (result_ != nullptr && result_->recipients != nullptr) { - stream_ << "------------>" << std::endl; - if (result_->file_name != nullptr) { - stream_ << _("File Name") << ": " << result_->file_name << std::endl; - stream_ << std::endl; + if (result != nullptr && result->recipients != nullptr) { + stream_ << Qt::endl; + + stream_ << "## " << tr("Gernal State") << ": " << Qt::endl; + + if (result->file_name != nullptr) { + stream_ << "- " << tr("File Name") << ": " << result->file_name + << Qt::endl; + } + stream_ << "- " << tr("MIME") << ": " + << (result->is_mime == 0 ? tr("false") : tr("true")) << Qt::endl; + + stream_ << "- " << tr("Message Integrity Protection") << ": " + << (result->legacy_cipher_nomdc == 0 ? tr("true") : tr("false")) + << Qt::endl; + if (result->legacy_cipher_nomdc == 1) setStatus(0); /// < unsafe situation + + if (result->symkey_algo != nullptr) { + stream_ << "- " << tr("Symmetric Encryption Algorithm") << ": " + << result->symkey_algo << Qt::endl; + } + + if (result->session_key != nullptr) { + stream_ << "- " << tr("Session Key") << ": " << result->session_key + << Qt::endl; } - if (result_->is_mime) { - stream_ << _("MIME") << ": " << _("true") << std::endl; + + stream_ << "- " << tr("German Encryption Standards") << ": " + << (result->is_de_vs == 0 ? tr("false") : tr("true")) << Qt::endl; + + stream_ << Qt::endl << Qt::endl; + + auto *recipient = result->recipients; + auto index = 0; + if (recipient != nullptr) { + stream_ << "## " << tr("Recipient(s)") << ": " << Qt::endl << Qt::endl; } - auto recipient = result_->recipients; - if (recipient != nullptr) stream_ << _("Recipient(s)") << ": " << std::endl; while (recipient != nullptr) { + // check + if (recipient->keyid == nullptr) return; + stream_ << "### " << tr("Recipient") << " [" << ++index << "]: "; print_recipient(stream_, recipient); + stream_ << Qt::endl + << "---------------------------------------" << Qt::endl + << Qt::endl; recipient = recipient->next; } - stream_ << "<------------" << std::endl; + + stream_ << Qt::endl; } - stream_ << std::endl; + stream_ << Qt::endl; } void GpgFrontend::GpgDecryptResultAnalyse::print_recipient( - std::stringstream &stream, gpgme_recipient_t recipient) { - // check - if (recipient->keyid == nullptr) return; - - stream << " {>} " << _("Recipient") << ": "; + QTextStream &stream, gpgme_recipient_t recipient) { auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(recipient->keyid); if (key.IsGood()) { - stream << key.GetName().c_str(); - if (!key.GetEmail().empty()) { - stream << "<" << key.GetEmail().c_str() << ">"; - } + stream << key.GetName(); + if (!key.GetComment().isEmpty()) stream << "(" << key.GetComment() << ")"; + if (!key.GetEmail().isEmpty()) stream << "<" << key.GetEmail() << ">"; } else { - stream << "<" << _("Unknown") << ">"; - set_status(0); + stream << "<" << tr("unknown") << ">"; + setStatus(0); } - stream << std::endl; + stream << Qt::endl; - stream << " " << _("Key ID") << ": " << recipient->keyid << std::endl; - stream << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(recipient->pubkey_algo) << std::endl; + stream << "- " << tr("Key ID") << ": " << recipient->keyid << Qt::endl; + stream << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(recipient->pubkey_algo) << Qt::endl; + stream << "- " << tr("Status") << ": " << gpgme_strerror(recipient->status) + << Qt::endl; } diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.h b/src/core/function/result_analyse/GpgDecryptResultAnalyse.h index 1fc08d1f..c795e025 100644 --- a/src/core/function/result_analyse/GpgDecryptResultAnalyse.h +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H -#define GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/GpgConstants.h" +#include "core/model/GpgDecryptResult.h" namespace GpgFrontend { @@ -40,6 +39,7 @@ namespace GpgFrontend { */ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Decrypt Result Analyse object @@ -47,14 +47,14 @@ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse * @param m_error * @param m_result */ - explicit GpgDecryptResultAnalyse(GpgError m_error, GpgDecrResult m_result); + explicit GpgDecryptResultAnalyse(GpgError m_error, GpgDecryptResult m_result); protected: /** * @brief * */ - void do_analyse() final; + void doAnalyse() final; private: /** @@ -63,12 +63,10 @@ class GPGFRONTEND_CORE_EXPORT GpgDecryptResultAnalyse * @param stream * @param recipient */ - void print_recipient(std::stringstream &stream, gpgme_recipient_t recipient); + void print_recipient(QTextStream &stream, gpgme_recipient_t recipient); - GpgError error_; ///< - GpgDecrResult result_; ///< + GpgError error_; ///< + GpgDecryptResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGDECRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp index 21d37eab..a6b18b0a 100644 --- a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,39 +28,53 @@ #include "GpgEncryptResultAnalyse.h" -GpgFrontend::GpgEncryptResultAnalyse::GpgEncryptResultAnalyse( - GpgError error, GpgEncrResult result) - : error_(error), result_(std::move(result)) {} +#include "core/model/GpgEncryptResult.h" -void GpgFrontend::GpgEncryptResultAnalyse::do_analyse() { - SPDLOG_DEBUG("start encrypt result analyse"); +namespace GpgFrontend { - stream_ << "[#] " << _("Encrypt Operation") << " "; +GpgEncryptResultAnalyse::GpgEncryptResultAnalyse(GpgError error, + GpgEncryptResult result) + : error_(error), result_(result) {} - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); +void GpgEncryptResultAnalyse::doAnalyse() { + stream_ << "# " << tr("Encrypt Operation") << " "; + + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << "- " << tr("Success") << " " << Qt::endl; + } else { + stream_ << "- " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (!~status_) { - stream_ << "------------>" << std::endl; - if (result_ != nullptr) { - stream_ << _("Invalid Recipients") << ": " << std::endl; - auto inv_reci = result_->invalid_recipients; + if ((~status_) == 0) { + stream_ << Qt::endl; + + const auto *result = result_.GetRaw(); + + if (result != nullptr) { + stream_ << "## " << tr("Invalid Recipients") << ": " << Qt::endl + << Qt::endl; + + auto *inv_reci = result->invalid_recipients; + auto index = 0; + while (inv_reci != nullptr) { - stream_ << _("Fingerprint") << ": " << inv_reci->fpr << std::endl; - stream_ << _("Reason") << ": " << gpgme_strerror(inv_reci->reason) - << std::endl; - stream_ << std::endl; + stream_ << "### " << tr("Recipients") << " " << ++index << ": " + << Qt::endl; + stream_ << "- " << tr("Fingerprint") << ": " << inv_reci->fpr + << Qt::endl; + stream_ << "- " << tr("Reason") << ": " + << gpgme_strerror(inv_reci->reason) << Qt::endl; + stream_ << Qt::endl << Qt::endl; inv_reci = inv_reci->next; } } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } - stream_ << std::endl; + stream_ << Qt::endl; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.h b/src/core/function/result_analyse/GpgEncryptResultAnalyse.h index 6811ef06..e9594628 100644 --- a/src/core/function/result_analyse/GpgEncryptResultAnalyse.h +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H -#define GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/GpgConstants.h" +#include "core/model/GpgEncryptResult.h" namespace GpgFrontend { /** @@ -39,6 +38,7 @@ namespace GpgFrontend { */ class GPGFRONTEND_CORE_EXPORT GpgEncryptResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Encrypt Result Analyse object @@ -46,19 +46,17 @@ class GPGFRONTEND_CORE_EXPORT GpgEncryptResultAnalyse * @param error * @param result */ - explicit GpgEncryptResultAnalyse(GpgError error, GpgEncrResult result); + explicit GpgEncryptResultAnalyse(GpgError error, GpgEncryptResult result); protected: /** * @brief * */ - void do_analyse() final; + void doAnalyse() final; private: - GpgError error_; ///< - GpgEncrResult result_; ///< + GpgError error_; ///< + GpgEncryptResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGENCRYPTRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgResultAnalyse.cpp b/src/core/function/result_analyse/GpgResultAnalyse.cpp index 40ba4c3e..4c1f44e7 100644 --- a/src/core/function/result_analyse/GpgResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgResultAnalyse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,19 +28,19 @@ #include "GpgResultAnalyse.h" -const std::string GpgFrontend::GpgResultAnalyse::GetResultReport() const { - return stream_.str(); +auto GpgFrontend::GpgResultAnalyse::GetResultReport() const -> const QString { + return *stream_.string(); } -int GpgFrontend::GpgResultAnalyse::GetStatus() const { return status_; } +auto GpgFrontend::GpgResultAnalyse::GetStatus() const -> int { return status_; } -void GpgFrontend::GpgResultAnalyse::set_status(int m_status) { +void GpgFrontend::GpgResultAnalyse::setStatus(int m_status) { if (m_status < status_) status_ = m_status; } void GpgFrontend::GpgResultAnalyse::Analyse() { if (!analysed_) { - do_analyse(); + doAnalyse(); analysed_ = true; } } diff --git a/src/core/function/result_analyse/GpgResultAnalyse.h b/src/core/function/result_analyse/GpgResultAnalyse.h index e609505f..9958b6a2 100644 --- a/src/core/function/result_analyse/GpgResultAnalyse.h +++ b/src/core/function/result_analyse/GpgResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,21 +20,21 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGRESULTANALYSE_H -#define GPGFRONTEND_GPGRESULTANALYSE_H +#pragma once #include <sstream> -#include <string> -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" + namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { +class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse : public QObject { + Q_OBJECT public: /** * @brief Construct a new Result Analyse object @@ -45,16 +45,16 @@ class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { /** * @brief Get the Result Report object * - * @return const std::string + * @return const QString */ - [[nodiscard]] const std::string GetResultReport() const; + [[nodiscard]] auto GetResultReport() const -> const QString; /** * @brief Get the Status object * * @return int */ - [[nodiscard]] int GetStatus() const; + [[nodiscard]] auto GetStatus() const -> int; /** * @brief @@ -67,20 +67,19 @@ class GPGFRONTEND_CORE_EXPORT GpgResultAnalyse { * @brief * */ - virtual void do_analyse() = 0; + virtual void doAnalyse() = 0; /** * @brief Set the status object * * @param m_status */ - void set_status(int m_status); + void setStatus(int m_status); - std::stringstream stream_; ///< - int status_ = 1; ///< - bool analysed_ = false; ///< + QString buffer_; + QTextStream stream_ = QTextStream(&buffer_); ///< + int status_ = 1; ///< + bool analysed_ = false; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp index e4d1354f..bf429f38 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,88 +28,98 @@ #include "GpgSignResultAnalyse.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/LocalizedUtils.h" -GpgFrontend::GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, - GpgSignResult result) +namespace GpgFrontend { + +GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, GpgSignResult result) : error_(error), result_(std::move(result)) {} -void GpgFrontend::GpgSignResultAnalyse::do_analyse() { - SPDLOG_DEBUG("start sign result analyse"); +void GpgSignResultAnalyse::doAnalyse() { + auto *result = this->result_.GetRaw(); - stream_ << "[#] " << _("Sign Operation") << " "; + stream_ << "# " << tr("Sign Operation") << " "; - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << "- " << tr("Success") << " " << Qt::endl; + } else { + stream_ << "- " << tr("Failed") << " " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (result_ != nullptr && - (result_->signatures != nullptr || result_->invalid_signers != nullptr)) { - SPDLOG_DEBUG("sign result analyse getting result"); - stream_ << "------------>" << std::endl; - auto new_sign = result_->signatures; + if (result != nullptr && + (result->signatures != nullptr || result->invalid_signers != nullptr)) { + stream_ << Qt::endl; + auto *new_sign = result->signatures; + auto index = 0; while (new_sign != nullptr) { - stream_ << "[>]" << _("New Signature") << ": " << std::endl; - - SPDLOG_DEBUG("signers fingerprint: ", new_sign->fpr); - - stream_ << " " << _("Sign Mode") << ": "; - if (new_sign->type == GPGME_SIG_MODE_NORMAL) - stream_ << _("Normal"); - else if (new_sign->type == GPGME_SIG_MODE_CLEAR) - stream_ << _("Clear"); - else if (new_sign->type == GPGME_SIG_MODE_DETACH) - stream_ << _("Detach"); + stream_ << "## " << tr("New Signature") << " [" << ++index + << "]: " << Qt::endl; + + stream_ << "- " << tr("Sign Mode") << ": "; + if (new_sign->type == GPGME_SIG_MODE_NORMAL) { + stream_ << tr("Normal"); + } else if (new_sign->type == GPGME_SIG_MODE_CLEAR) { + stream_ << tr("Clear"); + } else if (new_sign->type == GPGME_SIG_MODE_DETACH) { + stream_ << tr("Detach"); + } - stream_ << std::endl; + stream_ << Qt::endl; - auto singerKey = - GpgFrontend::GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); - if (singerKey.IsGood()) { - stream_ << " " << _("Signer") << ": " - << singerKey.GetUIDs()->front().GetUID() << std::endl; + auto singer_key = GpgKeyGetter::GetInstance().GetKey(new_sign->fpr); + if (singer_key.IsGood()) { + stream_ << "- " << tr("Signer") << ": " + << singer_key.GetUIDs()->front().GetUID() << Qt::endl; } else { - stream_ << " " << _("Signer") << ": " - << "<unknown>" << std::endl; + stream_ << "- " << tr("Signer") << ": " + << "<unknown>" << Qt::endl; } - stream_ << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << std::endl; - stream_ << " " << _("Hash Algo") << ": " - << gpgme_hash_algo_name(new_sign->hash_algo) << std::endl; - stream_ << " " << _("Date") << "(" << _("UTC") << ")" + stream_ << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl; + stream_ << "- " << tr("Hash Algo") << ": " + << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl; + stream_ << "- " << tr("Date") << "(" << tr("UTC") << ")" << ": " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(new_sign->timestamp)) - << std::endl; + << QDateTime::fromSecsSinceEpoch(new_sign->timestamp).toString() + << Qt::endl; + stream_ << "- " << tr("Date") << "(" << tr("Localized") << ")" + << ": " << GetFormatedDateByTimestamp(new_sign->timestamp) + << Qt::endl; - stream_ << std::endl; + stream_ << Qt::endl + << "---------------------------------------" << Qt::endl + << Qt::endl; new_sign = new_sign->next; } - SPDLOG_DEBUG("sign result analyse getting invalid signer"); + auto *invalid_signer = result->invalid_signers; + stream_ << Qt::endl; - auto invalid_signer = result_->invalid_signers; - - if (invalid_signer != nullptr) - stream_ << _("Invalid Signers") << ": " << std::endl; + if (invalid_signer != nullptr) { + stream_ << "## " << tr("Invalid Signers") << ": " << Qt::endl; + } + index = 0; while (invalid_signer != nullptr) { - set_status(0); - stream_ << "[>] " << _("Signer") << ": " << std::endl; - stream_ << " " << _("Fingerprint") << ": " << invalid_signer->fpr - << std::endl; - stream_ << " " << _("Reason") << ": " - << gpgme_strerror(invalid_signer->reason) << std::endl; - stream_ << std::endl; + setStatus(0); + stream_ << "### " << tr("Signer") << " [" << ++index << "]: " << Qt::endl + << Qt::endl; + stream_ << "- " << tr("Fingerprint") << ": " << invalid_signer->fpr + << Qt::endl; + stream_ << "- " << tr("Reason") << ": " + << gpgme_strerror(invalid_signer->reason) << Qt::endl; + stream_ << "---------------------------------------" << Qt::endl; invalid_signer = invalid_signer->next; } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } -}
\ No newline at end of file +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.h b/src/core/function/result_analyse/GpgSignResultAnalyse.h index 43a78942..58a20417 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.h +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGSIGNRESULTANALYSE_H -#define GPGFRONTEND_GPGSIGNRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" +#include "core/model/GpgSignResult.h" namespace GpgFrontend { @@ -38,6 +38,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Sign Result Analyse object @@ -52,7 +53,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { * @brief * */ - void do_analyse(); + void doAnalyse() override; private: GpgError error_; ///< @@ -61,5 +62,3 @@ class GPGFRONTEND_CORE_EXPORT GpgSignResultAnalyse : public GpgResultAnalyse { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSIGNRESULTANALYSE_H diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp index b19db5b2..224aa06b 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,188 +28,200 @@ #include "GpgVerifyResultAnalyse.h" -#include <boost/format.hpp> - #include "GpgFrontend.h" -#include "core/GpgConstants.h" -#include "function/gpg/GpgKeyGetter.h" +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/LocalizedUtils.h" GpgFrontend::GpgVerifyResultAnalyse::GpgVerifyResultAnalyse( GpgError error, GpgVerifyResult result) - : error_(error), result_(std::move(result)) {} + : error_(error), result_(result) {} -void GpgFrontend::GpgVerifyResultAnalyse::do_analyse() { - SPDLOG_DEBUG("started"); +void GpgFrontend::GpgVerifyResultAnalyse::doAnalyse() { + auto *result = this->result_.GetRaw(); - stream_ << "[#] " << _("Verify Operation") << " "; + stream_ << "# " << tr("Verify Operation") << " "; - if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) - stream_ << "[" << _("Success") << "]" << std::endl; - else { - stream_ << "[" << _("Failed") << "] " << gpgme_strerror(error_) - << std::endl; - set_status(-1); + if (gpgme_err_code(error_) == GPG_ERR_NO_ERROR) { + stream_ << " - " << tr("Success") << " " << Qt::endl; + } else { + stream_ << " - " << tr("Failed") << ": " << gpgme_strerror(error_) + << Qt::endl; + setStatus(-1); } - if (result_ != nullptr && result_->signatures != nullptr) { - stream_ << "------------>" << std::endl; - auto sign = result_->signatures; + if (result != nullptr && result->signatures != nullptr) { + stream_ << Qt::endl; + auto *sign = result->signatures; + + stream_ << "-> " << tr("Signed On") << "(" << tr("UTC") << ")" + << " " << QDateTime::fromSecsSinceEpoch(sign->timestamp).toString() + << Qt::endl; - stream_ << "[>] " << _("Signed On") << "(" << _("UTC") << ")" - << " " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(sign->timestamp)) - << std::endl; + stream_ << "-> " << tr("Signed On") << "(" << tr("Localized") << ")" + << " " << GetFormatedDateByTimestamp(sign->timestamp) << Qt::endl; - stream_ << std::endl << "[>] " << _("Signatures List") << ":" << std::endl; + stream_ << Qt::endl << "## " << tr("Signatures List") << ":" << Qt::endl; + stream_ << Qt::endl; - bool canContinue = true; + bool can_continue = true; int count = 1; - while (sign && canContinue) { - stream_ << boost::format(_("Signature [%1%]:")) % count++ << std::endl; + while ((sign != nullptr) && can_continue) { + stream_ << "### " << tr("Signature [%1]:").arg(count++) << Qt::endl; + stream_ << "- " << tr("Status") << ": "; switch (gpg_err_code(sign->status)) { case GPG_ERR_BAD_SIGNATURE: - stream_ << _("A Bad Signature.") << std::endl; + stream_ << tr("A Bad Signature.") << Qt::endl; print_signer(stream_, sign); - stream_ << _("This Signature is invalid.") << std::endl; - canContinue = false; - set_status(-1); + stream_ << tr("This Signature is invalid.") << Qt::endl; + can_continue = false; + setStatus(-1); break; case GPG_ERR_NO_ERROR: - stream_ << _("A") << " "; - if (sign->summary & GPGME_SIGSUM_GREEN) { - stream_ << _("Good") << " "; + stream_ << tr("A") << " "; + if ((sign->summary & GPGME_SIGSUM_GREEN) != 0) { + stream_ << tr("Good") << " "; } - if (sign->summary & GPGME_SIGSUM_RED) { - stream_ << _("Bad") << " "; + if ((sign->summary & GPGME_SIGSUM_RED) != 0) { + stream_ << tr("Bad") << " "; } - if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) { - stream_ << _("Expired") << " "; + if ((sign->summary & GPGME_SIGSUM_SIG_EXPIRED) != 0) { + stream_ << tr("Expired") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_MISSING) { - stream_ << _("Missing Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_MISSING) != 0) { + stream_ << tr("Missing Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) { - stream_ << _("Revoked Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_REVOKED) != 0) { + stream_ << tr("Revoked Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) { - stream_ << _("Expired Key's") << " "; + if ((sign->summary & GPGME_SIGSUM_KEY_EXPIRED) != 0) { + stream_ << tr("Expired Key's") << " "; } - if (sign->summary & GPGME_SIGSUM_CRL_MISSING) { - stream_ << _("Missing CRL's") << " "; + if ((sign->summary & GPGME_SIGSUM_CRL_MISSING) != 0) { + stream_ << tr("Missing CRL's") << " "; } - if (sign->summary & GPGME_SIGSUM_VALID) { - stream_ << _("Signature Fully Valid.") << std::endl; + if ((sign->summary & GPGME_SIGSUM_VALID) != 0) { + stream_ << tr("Signature Fully Valid.") << Qt::endl; } else { - stream_ << _("Signature Not Fully Valid.") << std::endl; - stream_ << _("(May used a subkey to sign)") << std::endl; + stream_ << tr("Signature Not Fully Valid.") << Qt::endl; + stream_ << tr("(Adjust Trust Level to make it Fully Vaild)") + << Qt::endl; } - if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) { - if (!print_signer(stream_, sign)) set_status(0); + if ((sign->status & GPGME_SIGSUM_KEY_MISSING) == 0U) { + if (!print_signer(stream_, sign)) setStatus(0); } else { - stream_ << _("Key is NOT present with ID 0x") << sign->fpr - << std::endl; + stream_ << tr("Key is NOT present with ID 0x") << sign->fpr + << Qt::endl; } - set_status(1); + setStatus(1); break; case GPG_ERR_NO_PUBKEY: - stream_ << _("A signature could NOT be verified due to a Missing Key") - << std::endl; - set_status(-2); + stream_ + << tr("A signature could NOT be verified due to a Missing Key") + << Qt::endl; + setStatus(-2); break; case GPG_ERR_CERT_REVOKED: - stream_ << _("A signature is valid but the key used to verify the " - "signature has been revoked") - << std::endl; + stream_ << tr("A signature is valid but the key used to verify the " + "signature has been revoked") + << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } - set_status(-1); + setStatus(-1); break; case GPG_ERR_SIG_EXPIRED: - stream_ << _("A signature is valid but expired") << std::endl; + stream_ << tr("A signature is valid but expired") << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } - set_status(-1); + setStatus(-1); break; case GPG_ERR_KEY_EXPIRED: - stream_ << _("A signature is valid but the key used to " - "verify the signature has expired.") - << std::endl; + stream_ << tr("A signature is valid but the key used to " + "verify the signature has expired.") + << Qt::endl; if (!print_signer(stream_, sign)) { - set_status(0); + setStatus(0); } break; case GPG_ERR_GENERAL: - stream_ << _("There was some other error which prevented " - "the signature verification.") - << std::endl; + stream_ << tr("There was some other error which prevented " + "the signature verification.") + << Qt::endl; status_ = -1; - canContinue = false; + can_continue = false; break; default: - auto fpr = std::string(sign->fpr); - stream_ << _("Error for key with fingerprint") << " " - << GpgFrontend::beautify_fingerprint(fpr); - set_status(-1); + auto fpr = QString(sign->fpr); + stream_ << tr("Error for key with fingerprint") << " " + << GpgFrontend::BeautifyFingerprint(fpr); + setStatus(-1); } - stream_ << std::endl; + stream_ << Qt::endl; sign = sign->next; } - stream_ << "<------------" << std::endl; + stream_ << Qt::endl; } else { stream_ - << "[>] " - << _("Could not find information that can be used for verification.") - << std::endl; - set_status(0); + << "-> " + << tr("Could not find information that can be used for verification.") + << Qt::endl; + setStatus(0); return; } } -bool GpgFrontend::GpgVerifyResultAnalyse::print_signer( - std::stringstream &stream, gpgme_signature_t sign) { - bool keyFound = true; +auto GpgFrontend::GpgVerifyResultAnalyse::print_signer(QTextStream &stream, + gpgme_signature_t sign) + -> bool { + bool key_found = true; auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(sign->fpr); if (!key.IsGood()) { - stream << " " << _("Signed By") << ": " - << "<" << _("Unknown") << ">" << std::endl; - set_status(0); - keyFound = false; + stream << "- " << tr("Signed By") << ": " + << "<" << tr("Unknown") << ">" << Qt::endl; + setStatus(0); + key_found = false; } else { - stream << " " << _("Signed By") << ": " - << key.GetUIDs()->front().GetUID() << std::endl; + stream << "- " << tr("Signed By") << ": " << key.GetUIDs()->front().GetUID() + << Qt::endl; + } + if (sign->pubkey_algo != 0U) { + stream << "- " << tr("Public Key Algo") << ": " + << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl; + } + if (sign->hash_algo != 0U) { + stream << "- " << tr("Hash Algo") << ": " + << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl; } - if (sign->pubkey_algo) - stream << " " << _("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl; - if (sign->hash_algo) - stream << " " << _("Hash Algo") << ": " - << gpgme_hash_algo_name(sign->hash_algo) << std::endl; - if (sign->timestamp) - stream << " " << _("Date") << "(" << _("UTC") << ")" - << ": " - << boost::posix_time::to_iso_extended_string( - boost::posix_time::from_time_t(sign->timestamp)) - << std::endl; - stream << std::endl; - return keyFound; + if (sign->timestamp != 0U) { + stream << "- " << tr("Date") << "(" << tr("UTC") << ")" + << ": " << QDateTime::fromSecsSinceEpoch(sign->timestamp).toString() + << Qt::endl; + + stream << "- " << tr("Date") << "(" << tr("Localized") << ")" + << ": " << GetFormatedDateByTimestamp(sign->timestamp) << Qt::endl; + } + stream << Qt::endl; + return key_found; } -gpgme_signature_t GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const { - if (result_) - return result_->signatures; - else - return nullptr; +auto GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const + -> gpgme_signature_t { + if (result_.IsGood()) { + return result_.GetRaw()->signatures; + } + return nullptr; } -GpgFrontend::GpgVerifyResult -GpgFrontend::GpgVerifyResultAnalyse::TakeChargeOfResult() { - return std::move(result_); + +auto GpgFrontend::GpgVerifyResultAnalyse::TakeChargeOfResult() + -> GpgFrontend::GpgVerifyResult { + return result_; } diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.h b/src/core/function/result_analyse/GpgVerifyResultAnalyse.h index ce8e03ad..8aa2e41f 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.h +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGVERIFYRESULTANALYSE_H -#define GPGFRONTEND_GPGVERIFYRESULTANALYSE_H +#pragma once #include "GpgResultAnalyse.h" -#include "core/model/GpgKeySignature.h" +#include "core/model/GpgVerifyResult.h" namespace GpgFrontend { /** @@ -38,6 +37,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { + Q_OBJECT public: /** * @brief Construct a new Verify Result Analyse object @@ -52,21 +52,21 @@ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { * * @return gpgme_signature_t */ - gpgme_signature_t GetSignatures() const; + auto GetSignatures() const -> gpgme_signature_t; /** * @brief * * @return GpgVerifyResult */ - GpgVerifyResult TakeChargeOfResult(); + auto TakeChargeOfResult() -> GpgVerifyResult; - private: + protected: /** * @brief * */ - void do_analyse(); + void doAnalyse() final; private: /** @@ -77,12 +77,10 @@ class GPGFRONTEND_CORE_EXPORT GpgVerifyResultAnalyse : public GpgResultAnalyse { * @return true * @return false */ - bool print_signer(std::stringstream &stream, gpgme_signature_t sign); + auto print_signer(QTextStream &stream, gpgme_signature_t sign) -> bool; GpgError error_; ///< GpgVerifyResult result_; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGVERIFYRESULTANALYSE_H diff --git a/src/core/log/QtLoggerFmt.h b/src/core/log/QtLoggerFmt.h new file mode 100644 index 00000000..3cb38160 --- /dev/null +++ b/src/core/log/QtLoggerFmt.h @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +template <> +struct fmt::formatter<QString> { + // Parses format specifications. + constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + auto it = std::find(ctx.begin(), ctx.end(), '}'); + if (it != ctx.end() && *it != '}') { + throw fmt::format_error("invalid format specifier for QString"); + } + return it; + } + + // Formats the QString qstr and writes it to the output. + template <typename FormatContext> + auto format(const QString& qstr, FormatContext& ctx) const + -> decltype(ctx.out()) { + // Convert QString to UTF-8 QString (to handle Unicode characters + // correctly) + QByteArray utf8Str = qstr.toUtf8(); + return fmt::format_to(ctx.out(), "{}", utf8Str.constData()); + } +}; diff --git a/src/core/model/CommonStruct.h b/src/core/model/CommonStruct.h new file mode 100644 index 00000000..d7d09602 --- /dev/null +++ b/src/core/model/CommonStruct.h @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +/** + * @brief + * + */ +template <typename T> +struct GPGFRONTEND_CORE_EXPORT RefDeleter { + void operator()(T* _key) { + gpgme_unre + } +}; + +template <typename T> +using KeyRefHandler = std::unique_ptr<T, RefDeleter<T>>; ///< +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/DataObject.cpp b/src/core/model/DataObject.cpp new file mode 100644 index 00000000..d0e9d141 --- /dev/null +++ b/src/core/model/DataObject.cpp @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "DataObject.h" + +#include <stack> + +namespace GpgFrontend { + +class DataObject::Impl { + public: + Impl() = default; + + Impl(std::initializer_list<std::any> init_list) : params_(init_list) {} + + void AppendObject(const std::any& obj) { params_.push_back(obj); } + + auto GetParameter(size_t index) -> std::any { + if (index >= params_.size()) { + throw std::out_of_range("index out of range"); + } + return params_[index]; + } + + auto GetObjectSize() -> size_t { return params_.size(); } + + private: + std::vector<std::any> params_; +}; + +DataObject::DataObject() : p_(SecureCreateUniqueObject<Impl>()) {} + +DataObject::DataObject(std::initializer_list<std::any> i) + : p_(SecureCreateUniqueObject<Impl>(i)) {} + +DataObject::~DataObject() = default; + +DataObject::DataObject(DataObject&&) noexcept = default; + +auto DataObject::operator[](size_t index) const -> std::any { + return p_->GetParameter(index); +} + +auto DataObject::GetParameter(size_t index) const -> std::any { + return p_->GetParameter(index); +} + +void DataObject::AppendObject(std::any obj) { return p_->AppendObject(obj); } + +auto DataObject::GetObjectSize() const -> size_t { return p_->GetObjectSize(); } + +void DataObject::Swap(DataObject& other) noexcept { std::swap(p_, other.p_); } + +void DataObject::Swap(DataObject&& other) noexcept { p_ = std::move(other.p_); } + +void swap(DataObject& a, DataObject& b) noexcept { a.Swap(b); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/DataObject.h b/src/core/model/DataObject.h new file mode 100644 index 00000000..6b41a051 --- /dev/null +++ b/src/core/model/DataObject.h @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <any> +#include <typeindex> +#include <typeinfo> + +#include "core/GpgFrontendCoreExport.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +class DataObject; +using DataObjectPtr = std::shared_ptr<DataObject>; ///< + +class GPGFRONTEND_CORE_EXPORT DataObject { + public: + DataObject(); + + DataObject(std::initializer_list<std::any>); + + ~DataObject(); + + DataObject(DataObject&&) noexcept; + + auto operator[](size_t index) const -> std::any; + + void AppendObject(std::any); + + [[nodiscard]] auto GetParameter(size_t index) const -> std::any; + + [[nodiscard]] auto GetObjectSize() const -> size_t; + + void Swap(DataObject& other) noexcept; + + void Swap(DataObject&& other) noexcept; + + template <typename... Args> + auto Check() -> bool { + if (sizeof...(Args) != GetObjectSize()) return false; + + std::vector<std::type_info const*> type_list = {&typeid(Args)...}; + for (size_t i = 0; i < type_list.size(); ++i) { + if (std::type_index(*type_list[i]) != + std::type_index((*this)[i].type())) { + GF_CORE_LOG_ERROR( + "value of index {} in data object is type: {}, " + "not expected type: {}", + i, ((*this)[i]).type().name(), type_list[i]->name()); + return false; + } + } + return true; + } + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename... Args> +auto TransferParams(Args&&... args) -> std::shared_ptr<DataObject> { + return GpgFrontend::SecureCreateSharedObject<DataObject>( + DataObject{std::forward<Args>(args)...}); +} + +template <typename T> +auto ExtractParams(const std::shared_ptr<DataObject>& d_o, int index) -> T { + if (!d_o) { + throw std::invalid_argument("nullptr provided for DataObjectPtr"); + } + return std::any_cast<T>(d_o->GetParameter(index)); +} + +void swap(DataObject& a, DataObject& b) noexcept; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFBuffer.cpp b/src/core/model/GFBuffer.cpp new file mode 100644 index 00000000..c65ae689 --- /dev/null +++ b/src/core/model/GFBuffer.cpp @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GFBuffer.h" + +namespace GpgFrontend { + +GFBuffer::GFBuffer() + : buffer_(SecureCreateSharedObject<std::vector<std::byte>>()) {} + +GFBuffer::GFBuffer(const char* c_str) + : buffer_(SecureCreateSharedObject<std::vector<std::byte>>()) { + if (c_str == nullptr) { + return; + } + + size_t const length = std::strlen(c_str); + buffer_->reserve(length); + buffer_->assign(reinterpret_cast<const std::byte*>(c_str), + reinterpret_cast<const std::byte*>(c_str) + length); +} + +GFBuffer::GFBuffer(QByteArray buffer) + : buffer_(SecureCreateSharedObject<std::vector<std::byte>>()) { + std::transform(buffer.begin(), buffer.end(), std::back_inserter(*buffer_), + [](const char c) { return static_cast<std::byte>(c); }); +} + +GFBuffer::GFBuffer(QString str) + : buffer_(SecureCreateSharedObject<std::vector<std::byte>>()) { + std::transform( + str.begin(), str.end(), std::back_inserter(*buffer_), + [](const QChar c) { return static_cast<std::byte>(c.unicode()); }); +} + +auto GFBuffer::operator==(const GFBuffer& o) const -> bool { + return equal(buffer_->begin(), buffer_->end(), o.buffer_->begin()); +} + +auto GFBuffer::Data() const -> std::byte* { return buffer_->data(); } + +void GFBuffer::Resize(size_t size) { buffer_->resize(size); } + +auto GFBuffer::Size() const -> size_t { return buffer_->size(); } + +auto GFBuffer::ConvertToQByteArray() const -> QByteArray { + return QByteArray::fromRawData(reinterpret_cast<const char*>(Data()), + static_cast<qsizetype>(Size())); +} + +auto GFBuffer::Empty() const -> bool { return this->Size() == 0; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFBuffer.h b/src/core/model/GFBuffer.h new file mode 100644 index 00000000..d947401e --- /dev/null +++ b/src/core/model/GFBuffer.h @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GFBuffer { + public: + GFBuffer(); + + explicit GFBuffer(const char* c_str); + + explicit GFBuffer(QByteArray buffer); + + explicit GFBuffer(QString str); + + auto operator==(const GFBuffer& o) const -> bool; + + [[nodiscard]] auto Data() const -> std::byte*; + + void Resize(size_t size); + + [[nodiscard]] auto Size() const -> size_t; + + [[nodiscard]] auto Empty() const -> bool; + + [[nodiscard]] auto ConvertToQByteArray() const -> QByteArray; + + private: + std::shared_ptr<std::vector<std::byte>> buffer_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFDataExchanger.cpp b/src/core/model/GFDataExchanger.cpp new file mode 100644 index 00000000..70a6498e --- /dev/null +++ b/src/core/model/GFDataExchanger.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GFDataExchanger.h" + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +auto GFDataExchanger::Write(const std::byte* buffer, size_t size) -> ssize_t { + if (close_) return -1; + if (size == 0) return 0; + + std::atomic<ssize_t> write_bytes = 0; + std::unique_lock<std::mutex> lock(mutex_); + try { + for (size_t i = 0; i < size; i++) { + if (queue_.size() == queue_max_size_) not_empty_.notify_all(); + not_full_.wait(lock, + [=] { return queue_.size() < queue_max_size_ || close_; }); + if (close_) return -1; + + queue_.push(buffer[i]); + write_bytes++; + } + } catch (...) { + GF_CORE_LOG_ERROR( + "gf data exchanger caught exception when it writes to queue, abort..."); + } + + if (!queue_.empty()) not_empty_.notify_all(); + return write_bytes; +} + +auto GFDataExchanger::Read(std::byte* buffer, size_t size) -> ssize_t { + std::unique_lock<std::mutex> lock(mutex_); + if (size <= 0 || (close_ && queue_.empty())) return 0; + + std::atomic<ssize_t> read_bytes = 0; + for (size_t i = 0; i < size; ++i) { + if (queue_.empty()) not_full_.notify_all(); + not_empty_.wait(lock, [=] { return !queue_.empty() || close_; }); + + if (close_ && queue_.empty()) return 0; + buffer[i] = queue_.front(); + queue_.pop(); + read_bytes++; + } + + if (queue_.size() < queue_max_size_) not_full_.notify_all(); + return read_bytes; +} + +void GFDataExchanger::CloseWrite() { + std::unique_lock<std::mutex> const lock(mutex_); + + close_ = true; + not_full_.notify_all(); + not_empty_.notify_all(); +} + +GFDataExchanger::GFDataExchanger(ssize_t size) : queue_max_size_(size) {} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GFDataExchanger.h b/src/core/model/GFDataExchanger.h new file mode 100644 index 00000000..7d4ab050 --- /dev/null +++ b/src/core/model/GFDataExchanger.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <queue> + +namespace GpgFrontend { + +class GFDataExchanger { + public: + explicit GFDataExchanger(ssize_t size); + + auto Write(const std::byte* buffer, size_t size) -> ssize_t; + + auto Read(std::byte* buffer, size_t size) -> ssize_t; + + void CloseWrite(); + + private: + std::condition_variable not_full_, not_empty_; + std::queue<std::byte> queue_; + std::mutex mutex_; + const ssize_t queue_max_size_; + std::atomic_bool close_ = false; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgData.cpp b/src/core/model/GpgData.cpp index 05f61a46..6ab44994 100644 --- a/src/core/model/GpgData.cpp +++ b/src/core/model/GpgData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,52 +28,129 @@ #include "core/model/GpgData.h" -GpgFrontend::GpgData::GpgData() { +#include <unistd.h> + +#include "core/model/GFDataExchanger.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +constexpr size_t kBufferSize = 32 * 1024; + +auto GFReadExCb(void* handle, void* buffer, size_t size) -> ssize_t { + auto* ex = static_cast<GFDataExchanger*>(handle); + return ex->Read(static_cast<std::byte*>(buffer), size); +} + +auto GFWriteExCb(void* handle, const void* buffer, size_t size) -> ssize_t { + auto* ex = static_cast<GFDataExchanger*>(handle); + return ex->Write(static_cast<const std::byte*>(buffer), size); +} + +void GFReleaseExCb(void* handle) { + auto* ex = static_cast<GFDataExchanger*>(handle); + ex->CloseWrite(); +} + +GpgData::GpgData() { gpgme_data_t data; auto err = gpgme_data_new(&data); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); - data_ref_ = std::unique_ptr<struct gpgme_data, _data_ref_deleter>(data); + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); } -GpgFrontend::GpgData::GpgData(void* buffer, size_t size, bool copy) { +GpgData::GpgData(GFBuffer buffer) : cached_buffer_(buffer) { + gpgme_data_t data; + + auto err = gpgme_data_new_from_mem( + &data, reinterpret_cast<const char*>(buffer.Data()), buffer.Size(), 0); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(const void* buffer, size_t size, bool copy) { gpgme_data_t data; auto err = gpgme_data_new_from_mem(&data, static_cast<const char*>(buffer), size, copy); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); - data_ref_ = std::unique_ptr<struct gpgme_data, _data_ref_deleter>(data); + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); } -/** - * Read gpgme-Data to QByteArray - * mainly from http://basket.kde.org/ (kgpgme.cpp) - */ -#define BUF_SIZE (32 * 1024) +GpgData::GpgData(int fd) : fd_(fd), data_cbs_() { + gpgme_data_t data; + + auto err = gpgme_data_new_from_fd(&data, fd_); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(const QString& path, bool read) { + gpgme_data_t data; + + // support unicode path + QFile file(path); + file.open(read ? QIODevice::ReadOnly : QIODevice::WriteOnly); + fp_ = fdopen(dup(file.handle()), read ? "rb" : "wb"); + + auto err = gpgme_data_new_from_stream(&data, fp_); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::GpgData(std::shared_ptr<GFDataExchanger> ex) + : data_cbs_(), data_ex_(std::move(ex)) { + gpgme_data_t data; + + data_cbs_.read = GFReadExCb; + data_cbs_.write = GFWriteExCb; + data_cbs_.seek = nullptr; + data_cbs_.release = GFReleaseExCb; + + auto err = gpgme_data_new_from_cbs(&data, &data_cbs_, data_ex_.get()); + assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); + + data_ref_ = std::unique_ptr<struct gpgme_data, DataRefDeleter>(data); +} + +GpgData::~GpgData() { + if (fp_ != nullptr) { + fclose(fp_); + } + + if (fd_ >= 0) { + close(fd_); + } +} -GpgFrontend::ByteArrayPtr GpgFrontend::GpgData::Read2Buffer() { +auto GpgData::Read2GFBuffer() -> GFBuffer { gpgme_off_t ret = gpgme_data_seek(*this, 0, SEEK_SET); - ByteArrayPtr out_buffer = std::make_unique<std::string>(); + GFBuffer out_buffer; - if (ret) { - gpgme_error_t err = gpgme_err_code_from_errno(errno); + if (ret != 0) { + const GpgError err = gpgme_err_code_from_errno(errno); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); } else { - char buf[BUF_SIZE + 2]; + std::array<std::byte, kBufferSize + 2> buf; - while ((ret = gpgme_data_read(*this, buf, BUF_SIZE)) > 0) { - const size_t size = out_buffer->size(); - out_buffer->resize(static_cast<int>(size + ret)); - memcpy(out_buffer->data() + size, buf, ret); + while ((ret = gpgme_data_read(*this, buf.data(), kBufferSize)) > 0) { + const size_t size = out_buffer.Size(); + out_buffer.Resize(static_cast<int>(size + ret)); + memcpy(out_buffer.Data() + size, buf.data(), ret); } if (ret < 0) { - gpgme_error_t err = gpgme_err_code_from_errno(errno); + const GpgError err = gpgme_err_code_from_errno(errno); assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR); } } return out_buffer; } -GpgFrontend::GpgData::operator gpgme_data_t() { return data_ref_.get(); }
\ No newline at end of file +GpgData::operator gpgme_data_t() { return data_ref_.get(); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgData.h b/src/core/model/GpgData.h index 816465d3..358ebd19 100644 --- a/src/core/model/GpgData.h +++ b/src/core/model/GpgData.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,27 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef _GPGDATA_H -#define _GPGDATA_H +#pragma once -#include "core/GpgConstants.h" +#include "core/GpgFrontendCoreExport.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/CoreTypedef.h" namespace GpgFrontend { + +class GFDataExchanger; + /** * @brief * */ -class GpgData { +class GPGFRONTEND_CORE_EXPORT GpgData { public: /** * @brief Construct a new Gpg Data object @@ -51,7 +55,40 @@ class GpgData { * @param size * @param copy */ - GpgData(void* buffer, size_t size, bool copy = true); + GpgData(const void* buffer, size_t size, bool copy = true); + + /** + * @brief Construct a new Gpg Data object + * + * @param fd + */ + explicit GpgData(int fd); + + /** + * @brief Construct a new Gpg Data object + * + * @param fd + */ + explicit GpgData(std::shared_ptr<GFDataExchanger>); + + /** + * @brief Construct a new Gpg Data object + * + * @param path + */ + explicit GpgData(const QString& path, bool read); + + /** + * @brief Construct a new Gpg Data object + * + */ + explicit GpgData(GFBuffer); + + /** + * @brief Destroy the Gpg Data object + * + */ + ~GpgData(); /** * @brief @@ -65,23 +102,27 @@ class GpgData { * * @return ByteArrayPtr */ - ByteArrayPtr Read2Buffer(); + auto Read2GFBuffer() -> GFBuffer; private: /** * @brief * */ - struct _data_ref_deleter { + struct DataRefDeleter { void operator()(gpgme_data_t _data) { if (_data != nullptr) gpgme_data_release(_data); } }; - std::unique_ptr<struct gpgme_data, _data_ref_deleter> data_ref_ = - nullptr; ///< + GFBuffer cached_buffer_; + + std::unique_ptr<struct gpgme_data, DataRefDeleter> data_ref_ = nullptr; ///< + FILE* fp_ = nullptr; + int fd_ = -1; + + struct gpgme_data_cbs data_cbs_; + std::shared_ptr<GFDataExchanger> data_ex_; }; } // namespace GpgFrontend - -#endif // _GPGDATA_H
\ No newline at end of file diff --git a/src/core/model/GpgDecryptResult.cpp b/src/core/model/GpgDecryptResult.cpp new file mode 100644 index 00000000..3568bfd9 --- /dev/null +++ b/src/core/model/GpgDecryptResult.cpp @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgDecryptResult.h" + +namespace GpgFrontend { + +GpgDecryptResult::GpgDecryptResult(gpgme_decrypt_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_decrypt_result>( + (gpgme_result_ref(r), r), [](gpgme_decrypt_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgDecryptResult::GpgDecryptResult() = default; + +GpgDecryptResult::~GpgDecryptResult() = default; + +auto GpgDecryptResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgDecryptResult::GetRaw() -> gpgme_decrypt_result_t { + return result_ref_.get(); +} + +auto GpgDecryptResult::Recipients() -> std::vector<GpgRecipient> { + std::vector<GpgRecipient> result; + for (auto* reci = result_ref_->recipients; reci != nullptr; + reci = reci->next) { + try { + result.emplace_back(reci); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_recipients, " + "maybe nullptr of fpr"); + } + } + return result; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgDecryptResult.h b/src/core/model/GpgDecryptResult.h new file mode 100644 index 00000000..8289d97d --- /dev/null +++ b/src/core/model/GpgDecryptResult.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/model/GpgRecipient.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgDecryptResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_decrypt_result_t; + + auto Recipients() -> std::vector<GpgRecipient>; + + explicit GpgDecryptResult(gpgme_decrypt_result_t); + + GpgDecryptResult(); + + virtual ~GpgDecryptResult(); + + private: + std::shared_ptr<struct _gpgme_op_decrypt_result> result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgEncryptResult.cpp b/src/core/model/GpgEncryptResult.cpp new file mode 100644 index 00000000..843cf7eb --- /dev/null +++ b/src/core/model/GpgEncryptResult.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgEncryptResult.h" + +namespace GpgFrontend { +GpgEncryptResult::GpgEncryptResult(gpgme_encrypt_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_encrypt_result>( + (gpgme_result_ref(r), r), [](gpgme_encrypt_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgEncryptResult::GpgEncryptResult() = default; + +GpgEncryptResult::~GpgEncryptResult() = default; + +auto GpgEncryptResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgEncryptResult::GetRaw() -> gpgme_encrypt_result_t { + return result_ref_.get(); +} + +auto GpgEncryptResult::InvalidRecipients() + -> std::vector<std::tuple<QString, GpgError>> { + std::vector<std::tuple<QString, GpgError>> result; + for (auto* invalid_key = result_ref_->invalid_recipients; + invalid_key != nullptr; invalid_key = invalid_key->next) { + try { + result.emplace_back(QString{invalid_key->fpr}, invalid_key->reason); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_recipients, " + "maybe nullptr of fpr"); + } + } + return result; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgEncryptResult.h b/src/core/model/GpgEncryptResult.h new file mode 100644 index 00000000..61fca710 --- /dev/null +++ b/src/core/model/GpgEncryptResult.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgEncryptResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_encrypt_result_t; + + auto InvalidRecipients() -> std::vector<std::tuple<QString, GpgError>>; + + explicit GpgEncryptResult(gpgme_encrypt_result_t); + + GpgEncryptResult(); + + virtual ~GpgEncryptResult(); + + private: + std::shared_ptr<struct _gpgme_op_encrypt_result> result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgGenKeyInfo.cpp b/src/core/model/GpgGenKeyInfo.cpp new file mode 100644 index 00000000..60f76d96 --- /dev/null +++ b/src/core/model/GpgGenKeyInfo.cpp @@ -0,0 +1,486 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgGenKeyInfo.h" + +#include <algorithm> +#include <cassert> + +#include "core/utils/LogUtils.h" + +namespace GpgFrontend { + +void GenKeyInfo::SetAlgo(const QString &t_algo_args) { + auto algo_args = t_algo_args.toLower(); + GF_CORE_LOG_DEBUG("set algo args: {}", algo_args); + + // reset all options + reset_options(); + + if (!this->subkey_) { + this->SetAllowCertification(true); + } else { + this->SetAllowCertification(false); + } + + this->allow_change_certification_ = false; + + if (algo_args == "rsa") { + /** + * RSA is the world’s premier asymmetric cryptographic algorithm, + * and is built on the difficulty of factoring extremely large composites. + * GnuPG supports RSA with key sizes of between 1024 and 4096 bits. + */ + suggest_min_key_size_ = 1024; + suggest_max_key_size_ = 4096; + suggest_size_addition_step_ = 1024; + SetKeyLength(2048); + + } else if (algo_args == "dsa") { + /** + * Algorithm (DSA) as a government standard for digital signatures. + * Originally, it supported key lengths between 512 and 1024 bits. + * Recently, NIST has declared 512-bit keys obsolete: + * now, DSA is available in 1024, 2048 and 3072-bit lengths. + */ + SetAllowEncryption(false); + allow_change_encryption_ = false; + + suggest_min_key_size_ = 1024; + suggest_max_key_size_ = 3072; + suggest_size_addition_step_ = 1024; + SetKeyLength(2048); + + } else if (algo_args == "ed25519") { + /** + * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths + * ranging from 1024 to 4096 bits. + */ + SetAllowEncryption(false); + allow_change_encryption_ = false; + + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else if (algo_args == "cv25519" || algo_args == "nistp256" || + algo_args == "nistp384" || algo_args == "nistp521" || + algo_args == "brainpoolp256r1" || algo_args == "brainpoolp384r1" || + algo_args == "brainpoolp512r1") { + SetAllowAuthentication(false); + allow_change_authentication_ = false; + + SetAllowSigning(false); + allow_change_signing_ = false; + + SetAllowCertification(false); + allow_change_certification_ = false; + + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else { + SPDLOG_ERROR("unsupported gen key algo arguments: {}", algo_args); + return; + } + + this->algo_ = algo_args; +} + +void GenKeyInfo::reset_options() { + allow_change_encryption_ = true; + SetAllowEncryption(true); + + allow_change_certification_ = true; + SetAllowCertification(true); + + allow_change_signing_ = true; + SetAllowSigning(true); + + allow_change_authentication_ = true; + SetAllowAuthentication(true); + + passphrase_.clear(); +} + +auto GenKeyInfo::GetKeySizeStr() const -> QString { + if (key_size_ > 0) { + return QString::number(key_size_); + } + return {}; +} + +void GenKeyInfo::SetKeyLength(int m_key_size) { + if (m_key_size < suggest_min_key_size_ || + m_key_size > suggest_max_key_size_) { + return; + } + GenKeyInfo::key_size_ = m_key_size; +} + +void GenKeyInfo::SetExpireTime(const QDateTime &m_expired) { + if (!IsNonExpired()) { + GenKeyInfo::expired_ = m_expired; + } +} + +void GenKeyInfo::SetNonExpired(bool m_non_expired) { + if (!m_non_expired) this->expired_ = QDateTime::fromSecsSinceEpoch(0); + GenKeyInfo::non_expired_ = m_non_expired; +} + +void GenKeyInfo::SetAllowEncryption(bool m_allow_encryption) { + if (allow_change_encryption_) { + GenKeyInfo::allow_encryption_ = m_allow_encryption; + } +} + +void GenKeyInfo::SetAllowCertification(bool m_allow_certification) { + if (allow_change_certification_) { + GenKeyInfo::allow_certification_ = m_allow_certification; + } +} + +GenKeyInfo::GenKeyInfo(bool m_is_sub_key) : subkey_(m_is_sub_key) { + assert(!GetSupportedKeyAlgo().empty()); + SetAlgo(std::get<0>(GetSupportedKeyAlgo()[0])); +} + +auto GenKeyInfo::GetSupportedKeyAlgo() + -> const std::vector<GenKeyInfo::KeyGenAlgo> & { + static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportKeyAlgo = { + {"RSA", "RSA", ""}, + {"DSA", "DSA", ""}, + {"ECDSA", "ED25519", ""}, + {"ECDSA + ECDH", "ED25519", "CV25519"}, + {"ECDSA + ECDH NIST P-256", "ED25519", "NISTP256"}, + {"ECDSA + ECDH BrainPool P-256", "ED25519", "BRAINPOOlP256R1"}, + }; + return kSupportKeyAlgo; +} + +auto GenKeyInfo::GetSupportedSubkeyAlgo() + -> const std::vector<GenKeyInfo::KeyGenAlgo> & { + static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportSubkeyAlgo = { + {"RSA", "", "RSA"}, + {"DSA", "", "DSA"}, + {"ECDSA", "", "ED25519"}, + {"ECDH", "", "CV25519"}, + {"ECDH NIST P-256", "", "NISTP256"}, + {"ECDH NIST P-384", "", "NISTP384"}, + {"ECDH NIST P-521", "", "NISTP521"}, + {"ECDH BrainPool P-256", "", "BRAINPOOlP256R1"}, + {"ECDH BrainPool P-384", "", "BRAINPOOlP384R1"}, + {"ECDH BrainPool P-512", "", "BRAINPOOlP512R1"}}; + + return kSupportSubkeyAlgo; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsSubKey() const -> bool { return subkey_; } + +/** + * @brief Set the Is Sub Key object + * + * @param m_sub_key + */ +void GenKeyInfo::SetIsSubKey(bool m_sub_key) { + GenKeyInfo::subkey_ = m_sub_key; +} + +/** + * @brief Get the Userid object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetUserid() const -> QString { + return QString("%1(%2)<%3>").arg(name_).arg(comment_).arg(email_); +} + +/** + * @brief Set the Name object + * + * @param m_name + */ +void GenKeyInfo::SetName(const QString &m_name) { this->name_ = m_name; } + +/** + * @brief Set the Email object + * + * @param m_email + */ +void GenKeyInfo::SetEmail(const QString &m_email) { this->email_ = m_email; } + +/** + * @brief Set the Comment object + * + * @param m_comment + */ +void GenKeyInfo::SetComment(const QString &m_comment) { + this->comment_ = m_comment; +} + +/** + * @brief Get the Name object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetName() const -> QString { return name_; } + +/** + * @brief Get the Email object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetEmail() const -> QString { return email_; } + +/** + * @brief Get the Comment object + * + * @return QString + */ +[[nodiscard]] auto GenKeyInfo::GetComment() const -> QString { + return comment_; +} + +/** + * @brief Get the Algo object + * + * @return const QString& + */ +[[nodiscard]] auto GenKeyInfo::GetAlgo() const -> const QString & { + return algo_; +} + +/** + * @brief Get the Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetKeyLength() const -> int { return key_size_; } + +/** + * @brief Get the Expired object + * + * @return const QDateTime& + */ +[[nodiscard]] auto GenKeyInfo::GetExpireTime() const -> const QDateTime & { + return expired_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsNonExpired() const -> bool { + return non_expired_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsNoPassPhrase() const -> bool { + return this->no_passphrase_; +} + +/** + * @brief Set the Non Pass Phrase object + * + * @param m_non_pass_phrase + */ +void GenKeyInfo::SetNonPassPhrase(bool m_non_pass_phrase) { + GenKeyInfo::no_passphrase_ = m_non_pass_phrase; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowSigning() const -> bool { + return allow_signing_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowNoPassPhrase() const -> bool { + return allow_no_pass_phrase_; +} + +/** + * @brief Set the Allow Signing object + * + * @param m_allow_signing + */ +void GenKeyInfo::SetAllowSigning(bool m_allow_signing) { + if (allow_change_signing_) GenKeyInfo::allow_signing_ = m_allow_signing; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowEncryption() const -> bool { + return allow_encryption_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowCertification() const -> bool { + return allow_certification_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowAuthentication() const -> bool { + return allow_authentication_; +} + +/** + * @brief Set the Allow Authentication object + * + * @param m_allow_authentication + */ +void GenKeyInfo::SetAllowAuthentication(bool m_allow_authentication) { + if (allow_change_authentication_) { + GenKeyInfo::allow_authentication_ = m_allow_authentication; + } +} + +/** + * @brief Get the Pass Phrase object + * + * @return const QString& + */ +[[nodiscard]] auto GenKeyInfo::GetPassPhrase() const -> const QString & { + return passphrase_; +} + +/** + * @brief Set the Pass Phrase object + * + * @param m_pass_phrase + */ +void GenKeyInfo::SetPassPhrase(const QString &m_pass_phrase) { + GenKeyInfo::passphrase_ = m_pass_phrase; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeSigning() const -> bool { + return allow_change_signing_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeEncryption() const -> bool { + return allow_change_encryption_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeCertification() const -> bool { + return allow_change_certification_; +} + +/** + * @brief + * + * @return true + * @return false + */ +[[nodiscard]] auto GenKeyInfo::IsAllowChangeAuthentication() const -> bool { + return allow_change_authentication_; +} + +/** + * @brief Get the Suggest Max Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSuggestMaxKeySize() const -> int { + return suggest_max_key_size_; +} + +/** + * @brief Get the Suggest Min Key Size object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSuggestMinKeySize() const -> int { + return suggest_min_key_size_; +} + +/** + * @brief Get the Size Change Step object + * + * @return int + */ +[[nodiscard]] auto GenKeyInfo::GetSizeChangeStep() const -> int { + return suggest_size_addition_step_; +} + +} // namespace GpgFrontend diff --git a/src/core/GpgGenKeyInfo.h b/src/core/model/GpgGenKeyInfo.h index d47b803e..166c6b0f 100644 --- a/src/core/GpgGenKeyInfo.h +++ b/src/core/model/GpgGenKeyInfo.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,78 +20,41 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGGENKEYINFO_H -#define GPGFRONTEND_GPGGENKEYINFO_H - -#include <boost/date_time.hpp> -#include <boost/date_time/gregorian/greg_duration_types.hpp> -#include <boost/format.hpp> -#include <string> -#include <vector> - -#include "GpgFrontend.h" +#pragma once namespace GpgFrontend { class GPGFRONTEND_CORE_EXPORT GenKeyInfo { - bool standalone_ = false; ///< - bool subkey_ = false; ///< - std::string name_; ///< - std::string email_; ///< - std::string comment_; ///< - - std::string algo_; ///< - int key_size_ = 2048; - boost::posix_time::ptime expired_ = - boost::posix_time::second_clock::local_time() + - boost::gregorian::years(2); ///< - bool non_expired_ = false; ///< - - bool no_passphrase_ = false; ///< - bool allow_no_pass_phrase_ = true; ///< - - int suggest_max_key_size_ = 4096; ///< - int suggest_size_addition_step_ = 1024; ///< - int suggest_min_key_size_ = 1024; ///< - - std::string passphrase_; ///< - - using KeyGenAlgo = std::pair<std::string, std::string>; - public: - /** - * @brief Get the Supported Key Algo object - * - * @return const std::vector<std::string>& - */ - static const std::vector<KeyGenAlgo> &GetSupportedKeyAlgo(); + using KeyGenAlgo = std::tuple<QString, QString, QString>; /** - * @brief Get the Supported Subkey Algo object + * @brief Construct a new Gen Key Info object * - * @return const std::vector<std::string>& + * @param m_is_sub_key + * @param m_standalone */ - static const std::vector<KeyGenAlgo> &GetSupportedSubkeyAlgo(); + explicit GenKeyInfo(bool m_is_sub_key = false); /** - * @brief Get the Supported Key Algo Standalone object + * @brief Get the Supported Key Algo object * - * @return const std::vector<std::string>& + * @return const std::vector<QString>& */ - static const std::vector<KeyGenAlgo> &GetSupportedKeyAlgoStandalone(); + static auto GetSupportedKeyAlgo() -> const std::vector<KeyGenAlgo> &; /** - * @brief Get the Supported Subkey Algo Standalone object + * @brief Get the Supported Subkey Algo object * - * @return const std::vector<std::string>& + * @return const std::vector<QString>& */ - static const std::vector<KeyGenAlgo> &GetSupportedSubkeyAlgoStandalone(); + static auto GetSupportedSubkeyAlgo() -> const std::vector<KeyGenAlgo> &; /** * @brief @@ -99,95 +62,91 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsSubKey() const { return subkey_; } + [[nodiscard]] auto IsSubKey() const -> bool; /** * @brief Set the Is Sub Key object * * @param m_sub_key */ - void SetIsSubKey(bool m_sub_key) { GenKeyInfo::subkey_ = m_sub_key; } + void SetIsSubKey(bool m_sub_key); /** * @brief Get the Userid object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUserid() const { - auto uid_format = boost::format("%1%(%2%)<%3%>") % this->name_ % - this->comment_ % this->email_; - return uid_format.str(); - } + [[nodiscard]] auto GetUserid() const -> QString; /** * @brief Set the Name object * * @param m_name */ - void SetName(const std::string &m_name) { this->name_ = m_name; } + void SetName(const QString &m_name); /** * @brief Set the Email object * * @param m_email */ - void SetEmail(const std::string &m_email) { this->email_ = m_email; } + void SetEmail(const QString &m_email); /** * @brief Set the Comment object * * @param m_comment */ - void SetComment(const std::string &m_comment) { this->comment_ = m_comment; } + void SetComment(const QString &m_comment); /** * @brief Get the Name object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const { return name_; } + [[nodiscard]] auto GetName() const -> QString; /** * @brief Get the Email object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const { return email_; } + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief Get the Comment object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const { return comment_; } + [[nodiscard]] auto GetComment() const -> QString; /** * @brief Get the Algo object * - * @return const std::string& + * @return const QString& */ - [[nodiscard]] const std::string &GetAlgo() const { return algo_; } + [[nodiscard]] auto GetAlgo() const -> const QString &; /** * @brief Set the Algo object * * @param m_algo */ - void SetAlgo(const GpgFrontend::GenKeyInfo::KeyGenAlgo &m_algo); + void SetAlgo(const QString &); /** * @brief Get the Key Size Str object * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetKeySizeStr() const; + [[nodiscard]] auto GetKeySizeStr() const -> QString; /** * @brief Get the Key Size object * * @return int */ - [[nodiscard]] int GetKeyLength() const { return key_size_; } + [[nodiscard]] auto GetKeyLength() const -> int; /** * @brief Set the Key Size object @@ -199,18 +158,16 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { /** * @brief Get the Expired object * - * @return const boost::posix_time::ptime& + * @return const QDateTime& */ - [[nodiscard]] const boost::posix_time::ptime &GetExpireTime() const { - return expired_; - } + [[nodiscard]] auto GetExpireTime() const -> const QDateTime &; /** * @brief Set the Expired object * * @param m_expired */ - void SetExpireTime(const boost::posix_time::ptime &m_expired); + void SetExpireTime(const QDateTime &m_expired); /** * @brief @@ -218,7 +175,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsNonExpired() const { return non_expired_; } + [[nodiscard]] auto IsNonExpired() const -> bool; /** * @brief Set the Non Expired object @@ -233,16 +190,14 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsNoPassPhrase() const { return this->no_passphrase_; } + [[nodiscard]] auto IsNoPassPhrase() const -> bool; /** * @brief Set the Non Pass Phrase object * * @param m_non_pass_phrase */ - void SetNonPassPhrase(bool m_non_pass_phrase) { - GenKeyInfo::no_passphrase_ = m_non_pass_phrase; - } + void SetNonPassPhrase(bool m_non_pass_phrase); /** * @brief @@ -250,7 +205,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowSigning() const { return allow_signing_; } + [[nodiscard]] auto IsAllowSigning() const -> bool; /** * @brief @@ -258,18 +213,14 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowNoPassPhrase() const { - return allow_no_pass_phrase_; - } + [[nodiscard]] auto IsAllowNoPassPhrase() const -> bool; /** * @brief Set the Allow Signing object * * @param m_allow_signing */ - void SetAllowSigning(bool m_allow_signing) { - if (allow_change_signing_) GenKeyInfo::allow_signing_ = m_allow_signing; - } + void SetAllowSigning(bool m_allow_signing); /** * @brief @@ -277,7 +228,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowEncryption() const { return allow_encryption_; } + [[nodiscard]] auto IsAllowEncryption() const -> bool; /** * @brief Set the Allow Encryption object @@ -292,9 +243,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowCertification() const { - return allow_certification_; - } + [[nodiscard]] auto IsAllowCertification() const -> bool; /** * @brief Set the Allow Certification object @@ -309,35 +258,28 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowAuthentication() const { - return allow_authentication_; - } + [[nodiscard]] auto IsAllowAuthentication() const -> bool; /** * @brief Set the Allow Authentication object * * @param m_allow_authentication */ - void SetAllowAuthentication(bool m_allow_authentication) { - if (allow_change_authentication_) - GenKeyInfo::allow_authentication_ = m_allow_authentication; - } + void SetAllowAuthentication(bool m_allow_authentication); /** * @brief Get the Pass Phrase object * - * @return const std::string& + * @return const QString& */ - [[nodiscard]] const std::string &GetPassPhrase() const { return passphrase_; } + [[nodiscard]] auto GetPassPhrase() const -> const QString &; /** * @brief Set the Pass Phrase object * * @param m_pass_phrase */ - void SetPassPhrase(const std::string &m_pass_phrase) { - GenKeyInfo::passphrase_ = m_pass_phrase; - } + void SetPassPhrase(const QString &m_pass_phrase); /** * @brief @@ -345,9 +287,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeSigning() const { - return allow_change_signing_; - } + [[nodiscard]] auto IsAllowChangeSigning() const -> bool; /** * @brief @@ -355,9 +295,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeEncryption() const { - return allow_change_encryption_; - } + [[nodiscard]] auto IsAllowChangeEncryption() const -> bool; /** * @brief @@ -365,9 +303,7 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeCertification() const { - return allow_change_certification_; - } + [[nodiscard]] auto IsAllowChangeCertification() const -> bool; /** * @brief @@ -375,38 +311,49 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * @return true * @return false */ - [[nodiscard]] bool IsAllowChangeAuthentication() const { - return allow_change_authentication_; - } + [[nodiscard]] auto IsAllowChangeAuthentication() const -> bool; /** * @brief Get the Suggest Max Key Size object * * @return int */ - [[nodiscard]] int GetSuggestMaxKeySize() const { - return suggest_max_key_size_; - } + [[nodiscard]] auto GetSuggestMaxKeySize() const -> int; /** * @brief Get the Suggest Min Key Size object * * @return int */ - [[nodiscard]] int GetSuggestMinKeySize() const { - return suggest_min_key_size_; - } + [[nodiscard]] auto GetSuggestMinKeySize() const -> int; /** * @brief Get the Size Change Step object * * @return int */ - [[nodiscard]] int GetSizeChangeStep() const { - return suggest_size_addition_step_; - } + [[nodiscard]] auto GetSizeChangeStep() const -> int; private: + bool subkey_ = false; ///< + QString name_; ///< + QString email_; ///< + QString comment_; ///< + + QString algo_; ///< + int key_size_ = 2048; + QDateTime expired_ = QDateTime::currentDateTime().addYears(2); + bool non_expired_ = false; ///< + + bool no_passphrase_ = false; ///< + bool allow_no_pass_phrase_ = true; ///< + + int suggest_max_key_size_ = 4096; ///< + int suggest_size_addition_step_ = 1024; ///< + int suggest_min_key_size_ = 1024; ///< + + QString passphrase_; ///< + bool allow_encryption_ = true; ///< bool allow_change_encryption_ = true; ///< bool allow_certification_ = true; ///< @@ -421,17 +368,6 @@ class GPGFRONTEND_CORE_EXPORT GenKeyInfo { * */ void reset_options(); - - public: - /** - * @brief Construct a new Gen Key Info object - * - * @param m_is_sub_key - * @param m_standalone - */ - explicit GenKeyInfo(bool m_is_sub_key = false, bool m_standalone = false); }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGGENKEYINFO_H diff --git a/src/core/model/GpgGenerateKeyResult.cpp b/src/core/model/GpgGenerateKeyResult.cpp new file mode 100644 index 00000000..f7ebf14e --- /dev/null +++ b/src/core/model/GpgGenerateKeyResult.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgGenerateKeyResult.h" + +#include <gpgme.h> + +namespace GpgFrontend { + +GpgGenerateKeyResult::GpgGenerateKeyResult(gpgme_genkey_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_genkey_result>( + (gpgme_result_ref(r), r), [](gpgme_genkey_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +auto GpgGenerateKeyResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgGenerateKeyResult::GetFingerprint() -> QString const { + return result_ref_->fpr; +} + +GpgGenerateKeyResult::GpgGenerateKeyResult() = default; + +GpgGenerateKeyResult::GpgGenerateKeyResult(const GpgGenerateKeyResult &) = + default; + +auto GpgGenerateKeyResult::operator=(const GpgGenerateKeyResult &) + -> GpgGenerateKeyResult & = default; + +GpgGenerateKeyResult::~GpgGenerateKeyResult() = default; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgGenerateKeyResult.h b/src/core/model/GpgGenerateKeyResult.h new file mode 100644 index 00000000..f312d415 --- /dev/null +++ b/src/core/model/GpgGenerateKeyResult.h @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCore.h" +#include "core/GpgFrontendCoreExport.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgGenerateKeyResult { + public: + auto IsGood() -> bool; + + auto GetFingerprint() -> QString const; + + explicit GpgGenerateKeyResult(gpgme_genkey_result_t); + + GpgGenerateKeyResult(); + + GpgGenerateKeyResult(const GpgGenerateKeyResult &); + + auto operator=(const GpgGenerateKeyResult &) -> GpgGenerateKeyResult &; + + virtual ~GpgGenerateKeyResult(); + + private: + using ResultRefHandler = + std::shared_ptr<struct _gpgme_op_genkey_result>; ///< + + ResultRefHandler result_ref_ = nullptr; ///< +}; + +} // namespace GpgFrontend diff --git a/src/core/model/GpgImportInformation.cpp b/src/core/model/GpgImportInformation.cpp new file mode 100644 index 00000000..cda146de --- /dev/null +++ b/src/core/model/GpgImportInformation.cpp @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgImportInformation.h" + +namespace GpgFrontend { + +GpgImportInformation::GpgImportInformation() = default; + +GpgImportInformation::GpgImportInformation(gpgme_import_result_t result) { + if (result->unchanged != 0) unchanged = result->unchanged; + if (result->considered != 0) considered = result->considered; + if (result->no_user_id != 0) no_user_id = result->no_user_id; + if (result->imported != 0) imported = result->imported; + if (result->imported_rsa != 0) imported_rsa = result->imported_rsa; + if (result->unchanged != 0) unchanged = result->unchanged; + if (result->new_user_ids != 0) new_user_ids = result->new_user_ids; + if (result->new_sub_keys != 0) new_sub_keys = result->new_sub_keys; + if (result->new_signatures != 0) new_signatures = result->new_signatures; + if (result->new_revocations != 0) new_revocations = result->new_revocations; + if (result->secret_read != 0) secret_read = result->secret_read; + if (result->secret_imported != 0) secret_imported = result->secret_imported; + if (result->secret_unchanged != 0) { + secret_unchanged = result->secret_unchanged; + } + if (result->not_imported != 0) not_imported = result->not_imported; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgImportInformation.h b/src/core/model/GpgImportInformation.h new file mode 100644 index 00000000..5f85a338 --- /dev/null +++ b/src/core/model/GpgImportInformation.h @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT GpgImportInformation { + public: + /** + * @brief + * + */ + class GpgImportedKey { + public: + QString fpr; ///< + int import_status; ///< + }; + + using GpgImportedKeyList = std::list<GpgImportedKey>; ///< + + /** + * @brief Construct a new Gpg Import Information object + * + */ + GpgImportInformation(); + + /** + * @brief Construct a new Gpg Import Information object + * + * @param result + */ + explicit GpgImportInformation(gpgme_import_result_t result); + + int considered = 0; ///< + int no_user_id = 0; ///< + int imported = 0; ///< + int imported_rsa = 0; ///< + int unchanged = 0; ///< + int new_user_ids = 0; ///< + int new_sub_keys = 0; ///< + int new_signatures = 0; ///< + int new_revocations = 0; ///< + int secret_read = 0; ///< + int secret_imported = 0; ///< + int secret_unchanged = 0; ///< + int not_imported = 0; ///< + + GpgImportedKeyList imported_keys; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKey.cpp b/src/core/model/GpgKey.cpp index 3a167b81..ab962b5d 100644 --- a/src/core/model/GpgKey.cpp +++ b/src/core/model/GpgKey.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -30,70 +30,80 @@ #include <mutex> -GpgFrontend::GpgKey::GpgKey(gpgme_key_t &&key) : key_ref_(std::move(key)) {} +namespace GpgFrontend { -GpgFrontend::GpgKey::GpgKey(GpgKey &&k) noexcept { swap(key_ref_, k.key_ref_); } +GpgKey::GpgKey(gpgme_key_t &&key) : key_ref_(key) {} -GpgFrontend::GpgKey &GpgFrontend::GpgKey::operator=(GpgKey &&k) noexcept { +GpgKey::GpgKey(GpgKey &&k) noexcept { swap(key_ref_, k.key_ref_); } + +auto GpgKey::operator=(GpgKey &&k) noexcept -> GpgKey & { swap(key_ref_, k.key_ref_); return *this; } -bool GpgFrontend::GpgKey::operator==(const GpgKey &o) const { +GpgKey::GpgKey(const GpgKey &key) { + auto *key_ref = key.key_ref_.get(); + gpgme_key_ref(key_ref); + this->key_ref_ = KeyRefHandler(key_ref); +} + +auto GpgKey::operator=(const GpgKey &key) -> GpgKey & { + if (this == &key) { + return *this; + } + + auto *key_ref = key.key_ref_.get(); + gpgme_key_ref(key_ref); + + this->key_ref_ = KeyRefHandler(key_ref); + return *this; +} + +auto GpgKey::operator==(const GpgKey &o) const -> bool { return o.GetId() == this->GetId(); } -bool GpgFrontend::GpgKey::operator<=(const GpgKey &o) const { +auto GpgKey::operator<=(const GpgKey &o) const -> bool { return this->GetId() < o.GetId(); } -GpgFrontend::GpgKey::operator gpgme_key_t() const { return key_ref_.get(); } +GpgKey::operator gpgme_key_t() const { return key_ref_.get(); } -bool GpgFrontend::GpgKey::IsGood() const { return key_ref_ != nullptr; } +auto GpgKey::IsGood() const -> bool { return key_ref_ != nullptr; } -std::string GpgFrontend::GpgKey::GetId() const { - return key_ref_->subkeys->keyid; -} +auto GpgKey::GetId() const -> QString { return key_ref_->subkeys->keyid; } -std::string GpgFrontend::GpgKey::GetName() const { - return key_ref_->uids->name; -}; +auto GpgKey::GetName() const -> QString { return key_ref_->uids->name; }; -std::string GpgFrontend::GpgKey::GetEmail() const { - return key_ref_->uids->email; -} +auto GpgKey::GetEmail() const -> QString { return key_ref_->uids->email; } -std::string GpgFrontend::GpgKey::GetComment() const { - return key_ref_->uids->comment; -} +auto GpgKey::GetComment() const -> QString { return key_ref_->uids->comment; } -std::string GpgFrontend::GpgKey::GetFingerprint() const { - return key_ref_->fpr; -} +auto GpgKey::GetFingerprint() const -> QString { return key_ref_->fpr; } -std::string GpgFrontend::GpgKey::GetProtocol() const { +auto GpgKey::GetProtocol() const -> QString { return gpgme_get_protocol_name(key_ref_->protocol); } -std::string GpgFrontend::GpgKey::GetOwnerTrust() const { +auto GpgKey::GetOwnerTrust() const -> QString { switch (key_ref_->owner_trust) { case GPGME_VALIDITY_UNKNOWN: - return _("Unknown"); + return tr("Unknown"); case GPGME_VALIDITY_UNDEFINED: - return _("Undefined"); + return tr("Undefined"); case GPGME_VALIDITY_NEVER: - return _("Never"); + return tr("Never"); case GPGME_VALIDITY_MARGINAL: - return _("Marginal"); + return tr("Marginal"); case GPGME_VALIDITY_FULL: - return _("Full"); + return tr("Full"); case GPGME_VALIDITY_ULTIMATE: - return _("Ultimate"); + return tr("Ultimate"); } return "Invalid"; } -int GpgFrontend::GpgKey::GetOwnerTrustLevel() const { +auto GpgKey::GetOwnerTrustLevel() const -> int { switch (key_ref_->owner_trust) { case GPGME_VALIDITY_UNKNOWN: return 0; @@ -111,66 +121,65 @@ int GpgFrontend::GpgKey::GetOwnerTrustLevel() const { return 0; } -std::string GpgFrontend::GpgKey::GetPublicKeyAlgo() const { +auto GpgKey::GetPublicKeyAlgo() const -> QString { return gpgme_pubkey_algo_name(key_ref_->subkeys->pubkey_algo); } -boost::posix_time::ptime GpgFrontend::GpgKey::GetLastUpdateTime() const { - return boost::posix_time::from_time_t( +auto GpgKey::GetLastUpdateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch( static_cast<time_t>(key_ref_->last_update)); } -boost::posix_time::ptime GpgFrontend::GpgKey::GetExpireTime() const { - return boost::posix_time::from_time_t(key_ref_->subkeys->expires); +auto GpgKey::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(key_ref_->subkeys->expires); }; -boost::posix_time::ptime GpgFrontend::GpgKey::GetCreateTime() const { - return boost::posix_time::from_time_t(key_ref_->subkeys->timestamp); +auto GpgKey::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(key_ref_->subkeys->timestamp); }; -unsigned int GpgFrontend::GpgKey::GetPrimaryKeyLength() const { +auto GpgKey::GetPrimaryKeyLength() const -> unsigned int { return key_ref_->subkeys->length; } -bool GpgFrontend::GpgKey::IsHasEncryptionCapability() const { +auto GpgKey::IsHasEncryptionCapability() const -> bool { return key_ref_->can_encrypt; } -bool GpgFrontend::GpgKey::IsHasSigningCapability() const { +auto GpgKey::IsHasSigningCapability() const -> bool { return key_ref_->can_sign; } -bool GpgFrontend::GpgKey::IsHasCertificationCapability() const { +auto GpgKey::IsHasCertificationCapability() const -> bool { return key_ref_->can_certify; } -bool GpgFrontend::GpgKey::IsHasAuthenticationCapability() const { +auto GpgKey::IsHasAuthenticationCapability() const -> bool { return key_ref_->can_authenticate; } -bool GpgFrontend::GpgKey::IsHasCardKey() const { +auto GpgKey::IsHasCardKey() const -> bool { auto subkeys = GetSubKeys(); return std::any_of( subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { return subkey.IsCardKey(); }); } -bool GpgFrontend::GpgKey::IsPrivateKey() const { return key_ref_->secret; } +auto GpgKey::IsPrivateKey() const -> bool { return key_ref_->secret; } -bool GpgFrontend::GpgKey::IsExpired() const { return key_ref_->expired; } +auto GpgKey::IsExpired() const -> bool { return key_ref_->expired; } -bool GpgFrontend::GpgKey::IsRevoked() const { return key_ref_->revoked; } +auto GpgKey::IsRevoked() const -> bool { return key_ref_->revoked; } -bool GpgFrontend::GpgKey::IsDisabled() const { return key_ref_->disabled; } +auto GpgKey::IsDisabled() const -> bool { return key_ref_->disabled; } -bool GpgFrontend::GpgKey::IsHasMasterKey() const { +auto GpgKey::IsHasMasterKey() const -> bool { return key_ref_->subkeys->secret; } -std::unique_ptr<std::vector<GpgFrontend::GpgSubKey>> -GpgFrontend::GpgKey::GetSubKeys() const { +auto GpgKey::GetSubKeys() const -> std::unique_ptr<std::vector<GpgSubKey>> { auto p_keys = std::make_unique<std::vector<GpgSubKey>>(); - auto next = key_ref_->subkeys; + auto *next = key_ref_->subkeys; while (next != nullptr) { p_keys->push_back(GpgSubKey(next)); next = next->next; @@ -178,10 +187,9 @@ GpgFrontend::GpgKey::GetSubKeys() const { return p_keys; } -std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::GetUIDs() - const { +auto GpgKey::GetUIDs() const -> std::unique_ptr<std::vector<GpgUID>> { auto p_uids = std::make_unique<std::vector<GpgUID>>(); - auto uid_next = key_ref_->uids; + auto *uid_next = key_ref_->uids; while (uid_next != nullptr) { p_uids->push_back(GpgUID(uid_next)); uid_next = uid_next->next; @@ -189,32 +197,24 @@ std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::GetUIDs() return p_uids; } -bool GpgFrontend::GpgKey::IsHasActualSigningCapability() const { +auto GpgKey::IsHasActualSigningCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsSecretKey() && - subkey.IsHasSigningCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsSecretKey() && subkey.IsHasSigningCapability() && + !subkey.IsDisabled() && !subkey.IsRevoked() && + !subkey.IsExpired(); + }); } -bool GpgFrontend::GpgKey::IsHasActualAuthenticationCapability() const { +auto GpgKey::IsHasActualAuthenticationCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsSecretKey() && - subkey.IsHasAuthenticationCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsSecretKey() && subkey.IsHasAuthenticationCapability() && + !subkey.IsDisabled() && !subkey.IsRevoked() && + !subkey.IsExpired(); + }); } /** @@ -222,7 +222,7 @@ bool GpgFrontend::GpgKey::IsHasActualAuthenticationCapability() const { * @param key target key * @return if key certify */ -bool GpgFrontend::GpgKey::IsHasActualCertificationCapability() const { +auto GpgKey::IsHasActualCertificationCapability() const -> bool { return IsHasMasterKey() && !IsExpired() && !IsRevoked() && !IsDisabled(); } @@ -231,28 +231,17 @@ bool GpgFrontend::GpgKey::IsHasActualCertificationCapability() const { * @param key target key * @return if key encrypt */ -bool GpgFrontend::GpgKey::IsHasActualEncryptionCapability() const { +auto GpgKey::IsHasActualEncryptionCapability() const -> bool { auto subkeys = GetSubKeys(); - if (std::any_of(subkeys->begin(), subkeys->end(), - [](const GpgSubKey &subkey) -> bool { - return subkey.IsHasEncryptionCapability() && - !subkey.IsDisabled() && !subkey.IsRevoked() && - !subkey.IsExpired(); - })) - return true; - else - return false; -} - -GpgFrontend::GpgKey GpgFrontend::GpgKey::Copy() const { - { - const std::lock_guard<std::mutex> guard(gpgme_key_opera_mutex); - gpgme_key_ref(key_ref_.get()); - } - auto *_new_key_ref = key_ref_.get(); - return GpgKey(std::move(_new_key_ref)); + return std::any_of( + subkeys->begin(), subkeys->end(), [](const GpgSubKey &subkey) -> bool { + return subkey.IsHasEncryptionCapability() && !subkey.IsDisabled() && + !subkey.IsRevoked() && !subkey.IsExpired(); + }); } -void GpgFrontend::GpgKey::_key_ref_deleter::operator()(gpgme_key_t _key) { +void GpgKey::KeyRefDeleter::operator()(gpgme_key_t _key) { if (_key != nullptr) gpgme_key_unref(_key); } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKey.h b/src/core/model/GpgKey.h index fb87b791..70599b99 100644 --- a/src/core/model/GpgKey.h +++ b/src/core/model/GpgKey.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGKEY_H -#define GPGFRONTEND_GPGKEY_H +#pragma once -#include <mutex> - -#include "GpgSubKey.h" -#include "GpgUID.h" +#include "core/model/GpgSubKey.h" +#include "core/model/GpgUID.h" namespace GpgFrontend { @@ -41,6 +38,7 @@ namespace GpgFrontend { * */ class GPGFRONTEND_CORE_EXPORT GpgKey { + Q_DECLARE_TR_FUNCTIONS(GpgKey) public: /** * @brief @@ -48,98 +46,98 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsGood() const; + [[nodiscard]] auto IsGood() const -> bool; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetId() const; + [[nodiscard]] auto GetId() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetProtocol() const; + [[nodiscard]] auto GetProtocol() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetOwnerTrust() const; + [[nodiscard]] auto GetOwnerTrust() const -> QString; /** * @brief * * @return int */ - [[nodiscard]] int GetOwnerTrustLevel() const; + [[nodiscard]] auto GetOwnerTrustLevel() const -> int; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPublicKeyAlgo() const; + [[nodiscard]] auto GetPublicKeyAlgo() const -> QString; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetLastUpdateTime() const; + [[nodiscard]] auto GetLastUpdateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief s * * @return unsigned int */ - [[nodiscard]] unsigned int GetPrimaryKeyLength() const; + [[nodiscard]] auto GetPrimaryKeyLength() const -> unsigned int; /** * @brief @@ -147,7 +145,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasEncryptionCapability() const; + [[nodiscard]] auto IsHasEncryptionCapability() const -> bool; /** * @brief @@ -156,7 +154,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualEncryptionCapability() const; + [[nodiscard]] auto IsHasActualEncryptionCapability() const -> bool; /** * @brief @@ -164,7 +162,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasSigningCapability() const; + [[nodiscard]] auto IsHasSigningCapability() const -> bool; /** * @brief @@ -172,7 +170,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualSigningCapability() const; + [[nodiscard]] auto IsHasActualSigningCapability() const -> bool; /** * @brief @@ -180,7 +178,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCertificationCapability() const; + [[nodiscard]] auto IsHasCertificationCapability() const -> bool; /** * @brief @@ -188,7 +186,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualCertificationCapability() const; + [[nodiscard]] auto IsHasActualCertificationCapability() const -> bool; /** * @brief @@ -196,7 +194,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasAuthenticationCapability() const; + [[nodiscard]] auto IsHasAuthenticationCapability() const -> bool; /** * @brief @@ -204,7 +202,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasActualAuthenticationCapability() const; + [[nodiscard]] auto IsHasActualAuthenticationCapability() const -> bool; /** * @brief @@ -212,7 +210,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCardKey() const; + [[nodiscard]] auto IsHasCardKey() const -> bool; /** * @brief @@ -220,7 +218,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsPrivateKey() const; + [[nodiscard]] auto IsPrivateKey() const -> bool; /** * @brief @@ -228,7 +226,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -236,7 +234,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -244,7 +242,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsDisabled() const; + [[nodiscard]] auto IsDisabled() const -> bool; /** * @brief @@ -252,21 +250,22 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - [[nodiscard]] bool IsHasMasterKey() const; + [[nodiscard]] auto IsHasMasterKey() const -> bool; /** * @brief * * @return std::unique_ptr<std::vector<GpgSubKey>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgSubKey>> GetSubKeys() const; + [[nodiscard]] auto GetSubKeys() const + -> std::unique_ptr<std::vector<GpgSubKey>>; /** * @brief * * @return std::unique_ptr<std::vector<GpgUID>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgUID>> GetUIDs() const; + [[nodiscard]] auto GetUIDs() const -> std::unique_ptr<std::vector<GpgUID>>; /** * @brief Construct a new Gpg Key object @@ -299,7 +298,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * * @param k */ - GpgKey(GpgKey&& k) noexcept; + GpgKey(GpgKey&&) noexcept; /** * @brief @@ -307,7 +306,22 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @param k * @return GpgKey& */ - GpgKey& operator=(GpgKey&& k) noexcept; + auto operator=(GpgKey&&) noexcept -> GpgKey&; + + /** + * @brief Construct a new Gpg Key object + * + * @param k + */ + GpgKey(const GpgKey&); + + /** + * @brief + * + * @param k + * @return GpgKey& + */ + auto operator=(const GpgKey&) -> GpgKey&; /** * @brief @@ -315,7 +329,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @param key * @return GpgKey& */ - GpgKey& operator=(const gpgme_key_t& key) = delete; + auto operator=(const gpgme_key_t&) -> GpgKey& = delete; /** * @brief @@ -324,7 +338,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - bool operator==(const GpgKey& o) const; + auto operator==(const GpgKey&) const -> bool; /** * @brief @@ -333,7 +347,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { * @return true * @return false */ - bool operator<=(const GpgKey& o) const; + auto operator<=(const GpgKey&) const -> bool; /** * @brief @@ -342,30 +356,18 @@ class GPGFRONTEND_CORE_EXPORT GpgKey { */ explicit operator gpgme_key_t() const; - /** - * @brief - * - * @return GpgKey - */ - [[nodiscard]] GpgKey Copy() const; - private: /** * @brief * */ - struct GPGFRONTEND_CORE_EXPORT _key_ref_deleter { + struct GPGFRONTEND_CORE_EXPORT KeyRefDeleter { void operator()(gpgme_key_t _key); }; - using KeyRefHandler = - std::unique_ptr<struct _gpgme_key, _key_ref_deleter>; ///< + using KeyRefHandler = std::unique_ptr<struct _gpgme_key, KeyRefDeleter>; ///< KeyRefHandler key_ref_ = nullptr; ///< - - mutable std::mutex gpgme_key_opera_mutex; // mutex for gpgme key operations }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGKEY_H diff --git a/src/core/model/GpgKeySignature.cpp b/src/core/model/GpgKeySignature.cpp index aa196391..3182000c 100644 --- a/src/core/model/GpgKeySignature.cpp +++ b/src/core/model/GpgKeySignature.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,67 +28,53 @@ #include "core/model/GpgKeySignature.h" -GpgFrontend::GpgKeySignature::GpgKeySignature() = default; +namespace GpgFrontend { -GpgFrontend::GpgKeySignature::~GpgKeySignature() = default; +GpgKeySignature::GpgKeySignature() = default; -GpgFrontend::GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig) +GpgKeySignature::~GpgKeySignature() = default; + +GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig) : signature_ref_(sig, [&](gpgme_key_sig_t signature) {}) {} -GpgFrontend::GpgKeySignature::GpgKeySignature(GpgKeySignature &&) noexcept = +GpgKeySignature::GpgKeySignature(GpgKeySignature &&) noexcept = default; + +GpgKeySignature &GpgKeySignature::operator=(GpgKeySignature &&) noexcept = default; -GpgFrontend::GpgKeySignature &GpgFrontend::GpgKeySignature::operator=( - GpgKeySignature &&) noexcept = default; +bool GpgKeySignature::IsRevoked() const { return signature_ref_->revoked; } -bool GpgFrontend::GpgKeySignature::IsRevoked() const { - return signature_ref_->revoked; -} - -bool GpgFrontend::GpgKeySignature::IsExpired() const { - return signature_ref_->expired; -} +bool GpgKeySignature::IsExpired() const { return signature_ref_->expired; } -bool GpgFrontend::GpgKeySignature::IsInvalid() const { - return signature_ref_->invalid; -} +bool GpgKeySignature::IsInvalid() const { return signature_ref_->invalid; } -bool GpgFrontend::GpgKeySignature::IsExportable() const { +bool GpgKeySignature::IsExportable() const { return signature_ref_->exportable; } -gpgme_error_t GpgFrontend::GpgKeySignature::GetStatus() const { +gpgme_error_t GpgKeySignature::GetStatus() const { return signature_ref_->status; } -std::string GpgFrontend::GpgKeySignature::GetKeyID() const { - return signature_ref_->keyid; -} +QString GpgKeySignature::GetKeyID() const { return signature_ref_->keyid; } -std::string GpgFrontend::GpgKeySignature::GetPubkeyAlgo() const { +QString GpgKeySignature::GetPubkeyAlgo() const { return gpgme_pubkey_algo_name(signature_ref_->pubkey_algo); } -boost::posix_time::ptime GpgFrontend::GpgKeySignature::GetCreateTime() const { - return boost::posix_time::from_time_t(signature_ref_->timestamp); +QDateTime GpgKeySignature::GetCreateTime() const { + return QDateTime::fromSecsSinceEpoch(signature_ref_->timestamp); } -boost::posix_time::ptime GpgFrontend::GpgKeySignature::GetExpireTime() const { - return boost::posix_time::from_time_t(signature_ref_->expires); +QDateTime GpgKeySignature::GetExpireTime() const { + return QDateTime::fromSecsSinceEpoch(signature_ref_->expires); } -std::string GpgFrontend::GpgKeySignature::GetUID() const { - return signature_ref_->uid; -} +QString GpgKeySignature::GetUID() const { return signature_ref_->uid; } -std::string GpgFrontend::GpgKeySignature::GetName() const { - return signature_ref_->name; -} +QString GpgKeySignature::GetName() const { return signature_ref_->name; } -std::string GpgFrontend::GpgKeySignature::GetEmail() const { - return signature_ref_->email; -} +QString GpgKeySignature::GetEmail() const { return signature_ref_->email; } -std::string GpgFrontend::GpgKeySignature::GetComment() const { - return signature_ref_->comment; -}
\ No newline at end of file +QString GpgKeySignature::GetComment() const { return signature_ref_->comment; } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKeySignature.h b/src/core/model/GpgKeySignature.h index 25de2c75..c9ceeccc 100644 --- a/src/core/model/GpgKeySignature.h +++ b/src/core/model/GpgKeySignature.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,15 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGKEYSIGNATURE_H -#define GPGFRONTEND_GPGKEYSIGNATURE_H +#pragma once -#include <boost/date_time.hpp> -#include <string> - -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" /** * @brief @@ -52,7 +48,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -60,7 +56,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -68,7 +64,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsInvalid() const; + [[nodiscard]] auto IsInvalid() const -> bool; /** * @brief @@ -76,70 +72,70 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * @return true * @return false */ - [[nodiscard]] bool IsExportable() const; + [[nodiscard]] auto IsExportable() const -> bool; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetStatus() const; + [[nodiscard]] auto GetStatus() const -> GpgError; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetKeyID() const; + [[nodiscard]] auto GetKeyID() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUID() const; + [[nodiscard]] auto GetUID() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief Construct a new Gpg Key Signature object @@ -177,14 +173,14 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { * * @return GpgKeySignature& */ - GpgKeySignature &operator=(GpgKeySignature &&) noexcept; + auto operator=(GpgKeySignature &&) noexcept -> GpgKeySignature &; /** * @brief * * @return GpgKeySignature& */ - GpgKeySignature &operator=(const GpgKeySignature &) = delete; + auto operator=(const GpgKeySignature &) -> GpgKeySignature & = delete; private: using KeySignatrueRefHandler = @@ -195,5 +191,3 @@ class GPGFRONTEND_CORE_EXPORT GpgKeySignature { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGKEYSIGNATURE_H diff --git a/src/core/model/GpgPassphraseContext.cpp b/src/core/model/GpgPassphraseContext.cpp new file mode 100644 index 00000000..5df3f5a8 --- /dev/null +++ b/src/core/model/GpgPassphraseContext.cpp @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgPassphraseContext.h" + +namespace GpgFrontend { + +GpgPassphraseContext::GpgPassphraseContext(const QString& uids_info, + const QString& passphrase_info, + bool prev_was_bad, bool ask_for_new) + : passphrase_info_(passphrase_info), + uids_info_(uids_info), + prev_was_bad_(prev_was_bad), + ask_for_new_(ask_for_new) {} + +GpgPassphraseContext::GpgPassphraseContext() = default; + +auto GpgPassphraseContext::GetPassphrase() const -> QString { + return passphrase_; +} + +void GpgPassphraseContext::SetPassphrase(const QString& passphrase) { + passphrase_ = passphrase; +} + +auto GpgPassphraseContext::GetUidsInfo() const -> QString { return uids_info_; } + +auto GpgPassphraseContext::GetPassphraseInfo() const -> QString { + return passphrase_info_; +} + +auto GpgPassphraseContext::IsPreWasBad() const -> bool { return prev_was_bad_; } + +auto GpgPassphraseContext::IsAskForNew() const -> bool { return ask_for_new_; } +} // namespace GpgFrontend diff --git a/src/core/model/GpgPassphraseContext.h b/src/core/model/GpgPassphraseContext.h new file mode 100644 index 00000000..2bc1ac75 --- /dev/null +++ b/src/core/model/GpgPassphraseContext.h @@ -0,0 +1,63 @@ + + +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgPassphraseContext : public QObject { + Q_OBJECT + public: + GpgPassphraseContext(const QString& uids_info, const QString& passphrase_info, + bool prev_was_bad, bool ask_for_new); + + GpgPassphraseContext(); + + void SetPassphrase(const QString& passphrase); + + [[nodiscard]] auto GetPassphrase() const -> QString; + + [[nodiscard]] auto GetUidsInfo() const -> QString; + + [[nodiscard]] auto GetPassphraseInfo() const -> QString; + + [[nodiscard]] auto IsPreWasBad() const -> bool; + + [[nodiscard]] auto IsAskForNew() const -> bool; + + private: + QString passphrase_info_; + QString uids_info_; + QString passphrase_; + bool prev_was_bad_; + bool ask_for_new_; +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgRecipient.cpp b/src/core/model/GpgRecipient.cpp new file mode 100644 index 00000000..54de43bc --- /dev/null +++ b/src/core/model/GpgRecipient.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgRecipient.h" + +namespace GpgFrontend { + +GpgRecipient::GpgRecipient() = default; + +GpgRecipient::GpgRecipient(gpgme_recipient_t r) { + this->keyid = QString{r->keyid}; + this->pubkey_algo = QString{gpgme_pubkey_algo_name(r->pubkey_algo)}; + this->status = r->status; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgRecipient.h b/src/core/model/GpgRecipient.h new file mode 100644 index 00000000..a436c1d7 --- /dev/null +++ b/src/core/model/GpgRecipient.h @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +struct GPGFRONTEND_CORE_EXPORT GpgRecipient { + /* The key ID of key for which the text was encrypted. */ + QString keyid; + + /* The public key algorithm of the recipient key. */ + QString pubkey_algo; + + /* The status of the recipient. */ + GpgError status; + + GpgRecipient(); + + explicit GpgRecipient(gpgme_recipient_t r); +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignResult.cpp b/src/core/model/GpgSignResult.cpp new file mode 100644 index 00000000..4a0e5f35 --- /dev/null +++ b/src/core/model/GpgSignResult.cpp @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgSignResult.h" + +namespace GpgFrontend { +GpgSignResult::GpgSignResult(gpgme_sign_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_sign_result>( + (gpgme_result_ref(r), r), [](gpgme_sign_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgSignResult::GpgSignResult() = default; + +GpgSignResult::~GpgSignResult() = default; + +auto GpgSignResult::IsGood() -> bool { return result_ref_ != nullptr; } + +auto GpgSignResult::GetRaw() -> gpgme_sign_result_t { + return result_ref_.get(); +} + +auto GpgSignResult::InvalidSigners() + -> std::vector<std::tuple<QString, GpgError>> { + std::vector<std::tuple<QString, GpgError>> result; + for (auto* invalid_key = result_ref_->invalid_signers; invalid_key != nullptr; + invalid_key = invalid_key->next) { + try { + result.emplace_back(QString{invalid_key->fpr}, invalid_key->reason); + } catch (...) { + GF_CORE_LOG_ERROR( + "caught exception when processing invalid_signers, " + "maybe nullptr of fpr"); + } + } + return result; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignResult.h b/src/core/model/GpgSignResult.h new file mode 100644 index 00000000..ccb0361f --- /dev/null +++ b/src/core/model/GpgSignResult.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgSignResult { + public: + auto IsGood() -> bool; + + auto GetRaw() -> gpgme_sign_result_t; + + auto InvalidSigners() -> std::vector<std::tuple<QString, GpgError>>; + + explicit GpgSignResult(gpgme_sign_result_t); + + GpgSignResult(); + + virtual ~GpgSignResult(); + + private: + std::shared_ptr<struct _gpgme_op_sign_result> result_ref_ = nullptr; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgSignature.cpp b/src/core/model/GpgSignature.cpp index 73f9179d..e2cb7e4b 100644 --- a/src/core/model/GpgSignature.cpp +++ b/src/core/model/GpgSignature.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,21 +28,28 @@ #include "GpgSignature.h" +namespace GpgFrontend { + /** * @brief Construct a new Gpg Signature object * */ -GpgFrontend::GpgSignature::GpgSignature(GpgSignature &&) noexcept = default; +GpgSignature::GpgSignature(GpgSignature &&) noexcept = default; /** * @brief * * @return GpgSignature& */ -GpgFrontend::GpgSignature &GpgFrontend::GpgSignature::operator=( - GpgFrontend::GpgSignature &&) noexcept = default; +auto GpgSignature::operator=(GpgSignature &&) noexcept + -> GpgSignature & = default; -GpgFrontend::GpgSignature::GpgSignature(gpgme_signature_t sig) +/** + * @brief Construct a new Gpg Signature:: Gpg Signature object + * + * @param sig + */ +GpgSignature::GpgSignature(gpgme_signature_t sig) : signature_ref_(sig, [&](gpgme_signature_t signature) {}) {} /** @@ -50,7 +57,7 @@ GpgFrontend::GpgSignature::GpgSignature(gpgme_signature_t sig) * * @return gpgme_validity_t */ -gpgme_validity_t GpgFrontend::GpgSignature::GetValidity() const { +auto GpgSignature::GetValidity() const -> gpgme_validity_t { return signature_ref_->validity; } @@ -59,7 +66,7 @@ gpgme_validity_t GpgFrontend::GpgSignature::GetValidity() const { * * @return gpgme_error_t */ -gpgme_error_t GpgFrontend::GpgSignature::GetStatus() const { +auto GpgSignature::GetStatus() const -> gpgme_error_t { return signature_ref_->status; } @@ -68,52 +75,52 @@ gpgme_error_t GpgFrontend::GpgSignature::GetStatus() const { * * @return gpgme_error_t */ -gpgme_error_t GpgFrontend::GpgSignature::GetSummary() const { +auto GpgSignature::GetSummary() const -> gpgme_error_t { return signature_ref_->summary; } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetPubkeyAlgo() const { +auto GpgSignature::GetPubkeyAlgo() const -> QString { return gpgme_pubkey_algo_name(signature_ref_->pubkey_algo); } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetHashAlgo() const { +auto GpgSignature::GetHashAlgo() const -> QString { return gpgme_hash_algo_name(signature_ref_->hash_algo); } /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ -boost::posix_time::ptime GpgFrontend::GpgSignature::GetCreateTime() const { - return boost::posix_time::from_time_t(signature_ref_->timestamp); +auto GpgSignature::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(signature_ref_->timestamp); } /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ -boost::posix_time::ptime GpgFrontend::GpgSignature::GetExpireTime() const { - return boost::posix_time::from_time_t(signature_ref_->exp_timestamp); +auto GpgSignature::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(signature_ref_->exp_timestamp); } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgSignature::GetFingerprint() const { +auto GpgSignature::GetFingerprint() const -> QString { return signature_ref_->fpr; } @@ -121,10 +128,12 @@ std::string GpgFrontend::GpgSignature::GetFingerprint() const { * @brief Construct a new Gpg Signature object * */ -GpgFrontend::GpgSignature::GpgSignature() = default; +GpgSignature::GpgSignature() = default; /** * @brief Destroy the Gpg Signature object * */ -GpgFrontend::GpgSignature::~GpgSignature() = default; +GpgSignature::~GpgSignature() = default; + +} // namespace GpgFrontend diff --git a/src/core/model/GpgSignature.h b/src/core/model/GpgSignature.h index 2e49c4d7..316b9100 100644 --- a/src/core/model/GpgSignature.h +++ b/src/core/model/GpgSignature.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,15 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGSIGNATURE_H -#define GPGFRONTEND_GPGSIGNATURE_H +#pragma once -#include <boost/date_time/gregorian/greg_date.hpp> -#include <boost/date_time/posix_time/conversion.hpp> - -#include "core/GpgConstants.h" +#include "core/typedef/GpgTypedef.h" namespace GpgFrontend { @@ -47,56 +43,56 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { * * @return gpgme_validity_t */ - [[nodiscard]] gpgme_validity_t GetValidity() const; + [[nodiscard]] auto GetValidity() const -> gpgme_validity_t; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetStatus() const; + [[nodiscard]] auto GetStatus() const -> GpgError; /** * @brief * * @return gpgme_error_t */ - [[nodiscard]] gpgme_error_t GetSummary() const; + [[nodiscard]] auto GetSummary() const -> GpgError; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetHashAlgo() const; + [[nodiscard]] auto GetHashAlgo() const -> QString; /** * @brief Create a time object * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] auto GetExpireTime() const -> QDateTime; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief Construct a new Gpg Signature object @@ -134,14 +130,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { * * @return GpgSignature& */ - GpgSignature &operator=(GpgSignature &&) noexcept; + auto operator=(GpgSignature &&) noexcept -> GpgSignature &; /** * @brief * * @return GpgSignature& */ - GpgSignature &operator=(const GpgSignature &) = delete; + auto operator=(const GpgSignature &) -> GpgSignature & = delete; private: using KeySignatrueRefHandler = @@ -151,5 +147,3 @@ class GPGFRONTEND_CORE_EXPORT GpgSignature { KeySignatrueRefHandler signature_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSIGNATURE_H diff --git a/src/core/model/GpgSubKey.cpp b/src/core/model/GpgSubKey.cpp index e63816b1..eaef1498 100644 --- a/src/core/model/GpgSubKey.cpp +++ b/src/core/model/GpgSubKey.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,84 +20,79 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include "core/model/GpgSubKey.h" +#include "GpgSubKey.h" -GpgFrontend::GpgSubKey::GpgSubKey() = default; +namespace GpgFrontend { -GpgFrontend::GpgSubKey::GpgSubKey(gpgme_subkey_t subkey) - : _subkey_ref(subkey, [&](gpgme_subkey_t subkey) {}) {} +GpgSubKey::GpgSubKey() = default; -GpgFrontend::GpgSubKey::GpgSubKey(GpgSubKey&& o) noexcept { - swap(_subkey_ref, o._subkey_ref); +GpgSubKey::GpgSubKey(gpgme_subkey_t subkey) + : subkey_ref_(subkey, [&](gpgme_subkey_t subkey) {}) {} + +GpgSubKey::GpgSubKey(GpgSubKey&& o) noexcept { + swap(subkey_ref_, o.subkey_ref_); } -GpgFrontend::GpgSubKey& GpgFrontend::GpgSubKey::operator=( - GpgSubKey&& o) noexcept { - swap(_subkey_ref, o._subkey_ref); +auto GpgSubKey::operator=(GpgSubKey&& o) noexcept -> GpgSubKey& { + swap(subkey_ref_, o.subkey_ref_); return *this; }; -bool GpgFrontend::GpgSubKey::operator==(const GpgSubKey& o) const { +auto GpgSubKey::operator==(const GpgSubKey& o) const -> bool { return GetFingerprint() == o.GetFingerprint(); } -std::string GpgFrontend::GpgSubKey::GetID() const { return _subkey_ref->keyid; } +auto GpgSubKey::GetID() const -> QString { return subkey_ref_->keyid; } -std::string GpgFrontend::GpgSubKey::GetFingerprint() const { - return _subkey_ref->fpr; -} +auto GpgSubKey::GetFingerprint() const -> QString { return subkey_ref_->fpr; } -std::string GpgFrontend::GpgSubKey::GetPubkeyAlgo() const { - return gpgme_pubkey_algo_name(_subkey_ref->pubkey_algo); +auto GpgSubKey::GetPubkeyAlgo() const -> QString { + return gpgme_pubkey_algo_name(subkey_ref_->pubkey_algo); } -unsigned int GpgFrontend::GpgSubKey::GetKeyLength() const { - return _subkey_ref->length; +auto GpgSubKey::GetKeyLength() const -> unsigned int { + return subkey_ref_->length; } -bool GpgFrontend::GpgSubKey::IsHasEncryptionCapability() const { - return _subkey_ref->can_encrypt; +auto GpgSubKey::IsHasEncryptionCapability() const -> bool { + return subkey_ref_->can_encrypt; } -bool GpgFrontend::GpgSubKey::IsHasSigningCapability() const { - return _subkey_ref->can_sign; +auto GpgSubKey::IsHasSigningCapability() const -> bool { + return subkey_ref_->can_sign; } -bool GpgFrontend::GpgSubKey::IsHasCertificationCapability() const { - return _subkey_ref->can_certify; +auto GpgSubKey::IsHasCertificationCapability() const -> bool { + return subkey_ref_->can_certify; } -bool GpgFrontend::GpgSubKey::IsHasAuthenticationCapability() const { - return _subkey_ref->can_authenticate; +auto GpgSubKey::IsHasAuthenticationCapability() const -> bool { + return subkey_ref_->can_authenticate; } -bool GpgFrontend::GpgSubKey::IsPrivateKey() const { - return _subkey_ref->secret; -} +auto GpgSubKey::IsPrivateKey() const -> bool { return subkey_ref_->secret; } -bool GpgFrontend::GpgSubKey::IsExpired() const { return _subkey_ref->expired; } +auto GpgSubKey::IsExpired() const -> bool { return subkey_ref_->expired; } -bool GpgFrontend::GpgSubKey::IsRevoked() const { return _subkey_ref->revoked; } +auto GpgSubKey::IsRevoked() const -> bool { return subkey_ref_->revoked; } -bool GpgFrontend::GpgSubKey::IsDisabled() const { - return _subkey_ref->disabled; -} +auto GpgSubKey::IsDisabled() const -> bool { return subkey_ref_->disabled; } -bool GpgFrontend::GpgSubKey::IsSecretKey() const { return _subkey_ref->secret; } +auto GpgSubKey::IsSecretKey() const -> bool { return subkey_ref_->secret; } -bool GpgFrontend::GpgSubKey::IsCardKey() const { - return _subkey_ref->is_cardkey; -} +auto GpgSubKey::IsCardKey() const -> bool { return subkey_ref_->is_cardkey; } -boost::posix_time::ptime GpgFrontend::GpgSubKey::GetCreateTime() const { - return boost::posix_time::from_time_t(_subkey_ref->timestamp); +auto GpgSubKey::GetCreateTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(subkey_ref_->timestamp); } -boost::posix_time::ptime GpgFrontend::GpgSubKey::GetExpireTime() const { - return boost::posix_time::from_time_t(_subkey_ref->expires); +auto GpgSubKey::GetExpireTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(subkey_ref_->expires); } + +} // namespace GpgFrontend diff --git a/src/core/model/GpgSubKey.h b/src/core/model/GpgSubKey.h index 5a86d21d..d8268c34 100644 --- a/src/core/model/GpgSubKey.h +++ b/src/core/model/GpgSubKey.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGSUBKEY_H -#define GPGFRONTEND_GPGSUBKEY_H - -#include <boost/date_time.hpp> -#include <string> - -#include "core/GpgConstants.h" +#pragma once namespace GpgFrontend { @@ -45,30 +39,30 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetID() const; + [[nodiscard]] auto GetID() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetFingerprint() const; + [[nodiscard]] auto GetFingerprint() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetPubkeyAlgo() const; + [[nodiscard]] auto GetPubkeyAlgo() const -> QString; /** * @brief * * @return unsigned int */ - [[nodiscard]] unsigned int GetKeyLength() const; + [[nodiscard]] auto GetKeyLength() const -> unsigned int; /** * @brief @@ -76,7 +70,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasEncryptionCapability() const; + [[nodiscard]] auto IsHasEncryptionCapability() const -> bool; /** * @brief @@ -84,7 +78,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasSigningCapability() const; + [[nodiscard]] auto IsHasSigningCapability() const -> bool; /** * @brief @@ -92,7 +86,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasCertificationCapability() const; + [[nodiscard]] auto IsHasCertificationCapability() const -> bool; /** * @brief @@ -100,7 +94,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsHasAuthenticationCapability() const; + [[nodiscard]] auto IsHasAuthenticationCapability() const -> bool; /** * @brief @@ -108,7 +102,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsPrivateKey() const; + [[nodiscard]] auto IsPrivateKey() const -> bool; /** * @brief @@ -116,7 +110,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsExpired() const; + [[nodiscard]] auto IsExpired() const -> bool; /** * @brief @@ -124,7 +118,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsRevoked() const; + [[nodiscard]] auto IsRevoked() const -> bool; /** * @brief @@ -132,7 +126,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsDisabled() const; + [[nodiscard]] auto IsDisabled() const -> bool; /** * @brief @@ -140,7 +134,7 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsSecretKey() const; + [[nodiscard]] auto IsSecretKey() const -> bool; /** * @brief @@ -148,21 +142,21 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - [[nodiscard]] bool IsCardKey() const; + [[nodiscard]] auto IsCardKey() const -> bool; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetCreateTime() const; + [[nodiscard]] auto GetCreateTime() const -> QDateTime; /** * @brief * - * @return boost::posix_time::ptime + * @return QDateTime */ - [[nodiscard]] boost::posix_time::ptime GetExpireTime() const; + [[nodiscard]] QDateTime GetExpireTime() const; /** * @brief Construct a new Gpg Sub Key object @@ -196,14 +190,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @param o * @return GpgSubKey& */ - GpgSubKey& operator=(GpgSubKey&& o) noexcept; + auto operator=(GpgSubKey&& o) noexcept -> GpgSubKey&; /** * @brief * * @return GpgSubKey& */ - GpgSubKey& operator=(const GpgSubKey&) = delete; + auto operator=(const GpgSubKey&) -> GpgSubKey& = delete; /** * @brief @@ -212,16 +206,14 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey { * @return true * @return false */ - bool operator==(const GpgSubKey& o) const; + auto operator==(const GpgSubKey& o) const -> bool; private: using SubkeyRefHandler = std::unique_ptr<struct _gpgme_subkey, std::function<void(gpgme_subkey_t)>>; ///< - SubkeyRefHandler _subkey_ref = nullptr; ///< + SubkeyRefHandler subkey_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGSUBKEY_H diff --git a/src/core/model/GpgTOFUInfo.cpp b/src/core/model/GpgTOFUInfo.cpp index 84ce1e29..251affc2 100644 --- a/src/core/model/GpgTOFUInfo.cpp +++ b/src/core/model/GpgTOFUInfo.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,39 +28,40 @@ #include "GpgTOFUInfo.h" -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo() = default; +namespace GpgFrontend { -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo(gpgme_tofu_info_t tofu_info) - : _tofu_info_ref(tofu_info, [&](gpgme_tofu_info_t tofu_info) {}) {} +GpgTOFUInfo::GpgTOFUInfo() = default; -GpgFrontend::GpgTOFUInfo::GpgTOFUInfo(GpgTOFUInfo&& o) noexcept { - swap(_tofu_info_ref, o._tofu_info_ref); +GpgTOFUInfo::GpgTOFUInfo(gpgme_tofu_info_t tofu_info) + : tofu_info_ref_(tofu_info, [&](gpgme_tofu_info_t tofu_info) {}) {} + +GpgTOFUInfo::GpgTOFUInfo(GpgTOFUInfo&& o) noexcept { + swap(tofu_info_ref_, o.tofu_info_ref_); } -GpgFrontend::GpgTOFUInfo& GpgFrontend::GpgTOFUInfo::operator=( - GpgTOFUInfo&& o) noexcept { - swap(_tofu_info_ref, o._tofu_info_ref); +auto GpgTOFUInfo::operator=(GpgTOFUInfo&& o) noexcept -> GpgTOFUInfo& { + swap(tofu_info_ref_, o.tofu_info_ref_); return *this; }; -unsigned GpgFrontend::GpgTOFUInfo::GetValidity() const { - return _tofu_info_ref->validity; +auto GpgTOFUInfo::GetValidity() const -> unsigned { + return tofu_info_ref_->validity; } -unsigned GpgFrontend::GpgTOFUInfo::GetPolicy() const { - return _tofu_info_ref->policy; +auto GpgTOFUInfo::GetPolicy() const -> unsigned { + return tofu_info_ref_->policy; } -unsigned long GpgFrontend::GpgTOFUInfo::GetSignCount() const { - return _tofu_info_ref->signcount; +auto GpgTOFUInfo::GetSignCount() const -> unsigned long { + return tofu_info_ref_->signcount; } -unsigned long GpgFrontend::GpgTOFUInfo::GetEncrCount() const { - return _tofu_info_ref->encrcount; +auto GpgTOFUInfo::GetEncrCount() const -> unsigned long { + return tofu_info_ref_->encrcount; } -unsigned long GpgFrontend::GpgTOFUInfo::GetSignFirst() const { - return _tofu_info_ref->signfirst; +auto GpgTOFUInfo::GetSignFirst() const -> unsigned long { + return tofu_info_ref_->signfirst; } /** @@ -68,8 +69,8 @@ unsigned long GpgFrontend::GpgTOFUInfo::GetSignFirst() const { * * @return unsigned long */ -unsigned long GpgFrontend::GpgTOFUInfo::GetSignLast() const { - return _tofu_info_ref->signlast; +auto GpgTOFUInfo::GetSignLast() const -> unsigned long { + return tofu_info_ref_->signlast; } /** @@ -77,15 +78,17 @@ unsigned long GpgFrontend::GpgTOFUInfo::GetSignLast() const { * * @return unsigned long */ -unsigned long GpgFrontend::GpgTOFUInfo::GetEncrLast() const { - return _tofu_info_ref->encrlast; +auto GpgTOFUInfo::GetEncrLast() const -> unsigned long { + return tofu_info_ref_->encrlast; } /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::GpgTOFUInfo::GetDescription() const { - return _tofu_info_ref->description; -}
\ No newline at end of file +auto GpgTOFUInfo::GetDescription() const -> QString { + return tofu_info_ref_->description; +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgTOFUInfo.h b/src/core/model/GpgTOFUInfo.h index b82a4eb2..ec4c49b7 100644 --- a/src/core/model/GpgTOFUInfo.h +++ b/src/core/model/GpgTOFUInfo.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGTOFU_H -#define GPGFRONTEND_GPGTOFU_H - -#include "core/GpgConstants.h" +#pragma once namespace GpgFrontend { /** @@ -43,55 +40,55 @@ class GPGFRONTEND_CORE_EXPORT GpgTOFUInfo { * * @return unsigned */ - [[nodiscard]] unsigned GetValidity() const; + [[nodiscard]] auto GetValidity() const -> unsigned; /** * @brief * * @return unsigned */ - [[nodiscard]] unsigned GetPolicy() const; + [[nodiscard]] auto GetPolicy() const -> unsigned; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignCount() const; + [[nodiscard]] auto GetSignCount() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetEncrCount() const; + [[nodiscard]] auto GetEncrCount() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignFirst() const; + [[nodiscard]] auto GetSignFirst() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetSignLast() const; + [[nodiscard]] auto GetSignLast() const -> unsigned long; /** * @brief * * @return unsigned long */ - [[nodiscard]] unsigned long GetEncrLast() const; + [[nodiscard]] auto GetEncrLast() const -> unsigned long; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetDescription() const; + [[nodiscard]] auto GetDescription() const -> QString; /** * @brief Construct a new Gpg T O F U Info object @@ -125,23 +122,21 @@ class GPGFRONTEND_CORE_EXPORT GpgTOFUInfo { * @param o * @return GpgTOFUInfo& */ - GpgTOFUInfo& operator=(GpgTOFUInfo&& o) noexcept; + auto operator=(GpgTOFUInfo&& o) noexcept -> GpgTOFUInfo&; /** * @brief * * @return GpgTOFUInfo& */ - GpgTOFUInfo& operator=(const GpgTOFUInfo&) = delete; + auto operator=(const GpgTOFUInfo&) -> GpgTOFUInfo& = delete; private: using SubkeyRefHandler = std::unique_ptr<struct _gpgme_tofu_info, std::function<void(gpgme_tofu_info_t)>>; ///< - SubkeyRefHandler _tofu_info_ref = nullptr; ///< + SubkeyRefHandler tofu_info_ref_ = nullptr; ///< }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGTOFU_H diff --git a/src/core/model/GpgUID.cpp b/src/core/model/GpgUID.cpp index d87192c3..e0d9d3a6 100644 --- a/src/core/model/GpgUID.cpp +++ b/src/core/model/GpgUID.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,31 +28,30 @@ #include "core/model/GpgUID.h" -GpgFrontend::GpgUID::GpgUID() = default; +namespace GpgFrontend { -GpgFrontend::GpgUID::GpgUID(gpgme_user_id_t uid) +GpgUID::GpgUID() = default; + +GpgUID::GpgUID(gpgme_user_id_t uid) : uid_ref_(uid, [&](gpgme_user_id_t uid) {}) {} -GpgFrontend::GpgUID::GpgUID(GpgUID &&o) noexcept { swap(uid_ref_, o.uid_ref_); } +GpgUID::GpgUID(GpgUID &&o) noexcept { swap(uid_ref_, o.uid_ref_); } -std::string GpgFrontend::GpgUID::GetName() const { return uid_ref_->name; } +auto GpgUID::GetName() const -> QString { return uid_ref_->name; } -std::string GpgFrontend::GpgUID::GetEmail() const { return uid_ref_->email; } +auto GpgUID::GetEmail() const -> QString { return uid_ref_->email; } -std::string GpgFrontend::GpgUID::GetComment() const { - return uid_ref_->comment; -} +auto GpgUID::GetComment() const -> QString { return uid_ref_->comment; } -std::string GpgFrontend::GpgUID::GetUID() const { return uid_ref_->uid; } +auto GpgUID::GetUID() const -> QString { return uid_ref_->uid; } -bool GpgFrontend::GpgUID::GetRevoked() const { return uid_ref_->revoked; } +auto GpgUID::GetRevoked() const -> bool { return uid_ref_->revoked; } -bool GpgFrontend::GpgUID::GetInvalid() const { return uid_ref_->invalid; } +auto GpgUID::GetInvalid() const -> bool { return uid_ref_->invalid; } -std::unique_ptr<std::vector<GpgFrontend::GpgTOFUInfo>> -GpgFrontend::GpgUID::GetTofuInfos() const { +auto GpgUID::GetTofuInfos() const -> std::unique_ptr<std::vector<GpgTOFUInfo>> { auto infos = std::make_unique<std::vector<GpgTOFUInfo>>(); - auto info_next = uid_ref_->tofu; + auto *info_next = uid_ref_->tofu; while (info_next != nullptr) { infos->push_back(GpgTOFUInfo(info_next)); info_next = info_next->next; @@ -60,13 +59,15 @@ GpgFrontend::GpgUID::GetTofuInfos() const { return infos; } -std::unique_ptr<std::vector<GpgFrontend::GpgKeySignature>> -GpgFrontend::GpgUID::GetSignatures() const { +auto GpgUID::GetSignatures() const + -> std::unique_ptr<std::vector<GpgKeySignature>> { auto sigs = std::make_unique<std::vector<GpgKeySignature>>(); - auto sig_next = uid_ref_->signatures; + auto *sig_next = uid_ref_->signatures; while (sig_next != nullptr) { sigs->push_back(GpgKeySignature(sig_next)); sig_next = sig_next->next; } return sigs; } + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgUID.h b/src/core/model/GpgUID.h index 670c318d..14b4db3f 100644 --- a/src/core/model/GpgUID.h +++ b/src/core/model/GpgUID.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGUID_H -#define GPGFRONTEND_GPGUID_H +#pragma once #include "GpgKeySignature.h" #include "GpgTOFUInfo.h" @@ -42,30 +41,30 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetName() const; + [[nodiscard]] auto GetName() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetEmail() const; + [[nodiscard]] auto GetEmail() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetComment() const; + [[nodiscard]] auto GetComment() const -> QString; /** * @brief * - * @return std::string + * @return QString */ - [[nodiscard]] std::string GetUID() const; + [[nodiscard]] auto GetUID() const -> QString; /** * @brief @@ -73,7 +72,7 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @return true * @return false */ - [[nodiscard]] bool GetRevoked() const; + [[nodiscard]] auto GetRevoked() const -> bool; /** * @brief @@ -81,22 +80,23 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @return true * @return false */ - [[nodiscard]] bool GetInvalid() const; + [[nodiscard]] auto GetInvalid() const -> bool; /** * @brief * * @return std::unique_ptr<std::vector<GpgTOFUInfo>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgTOFUInfo>> GetTofuInfos() const; + [[nodiscard]] auto GetTofuInfos() const + -> std::unique_ptr<std::vector<GpgTOFUInfo>>; /** * @brief * * @return std::unique_ptr<std::vector<GpgKeySignature>> */ - [[nodiscard]] std::unique_ptr<std::vector<GpgKeySignature>> GetSignatures() - const; + [[nodiscard]] auto GetSignatures() const + -> std::unique_ptr<std::vector<GpgKeySignature>>; /** * @brief Construct a new Gpg U I D object @@ -130,14 +130,14 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { * @param o * @return GpgUID& */ - GpgUID &operator=(GpgUID &&o) noexcept; + auto operator=(GpgUID &&o) noexcept -> GpgUID &; /** * @brief * * @return GpgUID& */ - GpgUID &operator=(const GpgUID &) = delete; + auto operator=(const GpgUID &) -> GpgUID & = delete; private: using UidRefHandler = @@ -148,5 +148,3 @@ class GPGFRONTEND_CORE_EXPORT GpgUID { }; } // namespace GpgFrontend - -#endif // GPGFRONTEND_GPGUID_H
\ No newline at end of file diff --git a/src/core/model/GpgVerifyResult.cpp b/src/core/model/GpgVerifyResult.cpp new file mode 100644 index 00000000..75421c69 --- /dev/null +++ b/src/core/model/GpgVerifyResult.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgVerifyResult.h" + +#include "core/model/GpgSignature.h" + +namespace GpgFrontend { +GpgVerifyResult::GpgVerifyResult(gpgme_verify_result_t r) + : result_ref_(std::shared_ptr<struct _gpgme_op_verify_result>( + (gpgme_result_ref(r), r), [](gpgme_verify_result_t p) { + if (p != nullptr) { + gpgme_result_unref(p); + } + })) {} + +GpgVerifyResult::GpgVerifyResult() = default; + +GpgVerifyResult::~GpgVerifyResult() = default; + +auto GpgVerifyResult::IsGood() const -> bool { return result_ref_ != nullptr; } + +auto GpgVerifyResult::GetRaw() const -> gpgme_verify_result_t { + return result_ref_.get(); +} + +auto GpgVerifyResult::GetSignature() const -> std::vector<GpgSignature> { + std::vector<GpgSignature> sigatures; + + auto* signature = result_ref_->signatures; + while (signature != nullptr) { + sigatures.emplace_back(signature); + signature = signature->next; + } + return sigatures; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgVerifyResult.h b/src/core/model/GpgVerifyResult.h new file mode 100644 index 00000000..cae43c10 --- /dev/null +++ b/src/core/model/GpgVerifyResult.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgVerifyResult { + public: + [[nodiscard]] auto IsGood() const -> bool; + + [[nodiscard]] auto GetRaw() const -> gpgme_verify_result_t; + + [[nodiscard]] auto GetSignature() const -> std::vector<GpgSignature>; + + explicit GpgVerifyResult(gpgme_verify_result_t); + + GpgVerifyResult(); + + virtual ~GpgVerifyResult(); + + private: + std::shared_ptr<struct _gpgme_op_verify_result> result_ref_ = nullptr; ///< +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/module/Event.cpp b/src/core/module/Event.cpp new file mode 100644 index 00000000..fab26453 --- /dev/null +++ b/src/core/module/Event.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "Event.h" + +namespace GpgFrontend::Module { + +class Event::Impl { + public: + Impl(QString event_id, std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : event_identifier_(std::move(event_id)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()) { + for (const auto& param : params) { + AddParameter(param); + } + GF_CORE_LOG_DEBUG("create event {}", event_identifier_); + } + + auto operator[](const QString& key) const -> std::optional<ParameterValue> { + auto it_data = data_.find(key); + if (it_data != data_.end()) { + return it_data->second; + } + return std::nullopt; + } + + auto operator==(const Event& other) const -> bool { + return event_identifier_ == other.p_->event_identifier_; + } + + auto operator!=(const Event& other) const -> bool { + return !(*this == other); + } + + auto operator<(const Event& other) const -> bool { + return this->event_identifier_ < other.p_->event_identifier_; + } + + explicit operator QString() const { return event_identifier_; } + + auto GetIdentifier() -> EventIdentifier { return event_identifier_; } + + void AddParameter(const QString& key, const ParameterValue& value) { + data_[key] = value; + } + + void AddParameter(const ParameterInitializer& param) { + AddParameter(param.key, param.value); + } + + void ExecuteCallback(ListenerIdentifier listener_id, + const DataObjectPtr& data_object) { + GF_CORE_LOG_DEBUG("try to execute callback for event {} with listener {}", + event_identifier_, listener_id); + if (callback_) { + GF_CORE_LOG_DEBUG("executing callback for event {} with listener {}", + event_identifier_, listener_id); + if (!QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, event_identifier = event_identifier_, + listener_id, data_object]() { + callback(event_identifier, listener_id, data_object); + })) { + GF_CORE_LOG_ERROR( + "failed to invoke callback for event {} with listener {}", + event_identifier_, listener_id); + } + } + } + + private: + EventIdentifier event_identifier_; + std::map<QString, ParameterValue> data_; + EventCallback callback_; + QThread* callback_thread_ = nullptr; ///< +}; + +Event::Event(const QString& event_id, + std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : p_(SecureCreateUniqueObject<Impl>(event_id, params, + std::move(callback))) {} + +Event::~Event() = default; + +auto Event::Event::operator==(const Event& other) const -> bool { + return this->p_ == other.p_; +} + +auto Event::Event::operator!=(const Event& other) const -> bool { + return this->p_ != other.p_; +} + +auto Event::Event::operator<(const Event& other) const -> bool { + return this->p_ < other.p_; +} + +Event::Event::operator QString() const { return static_cast<QString>(*p_); } + +auto Event::Event::GetIdentifier() -> EventIdentifier { + return p_->GetIdentifier(); +} + +void Event::AddParameter(const QString& key, const ParameterValue& value) { + p_->AddParameter(key, value); +} + +void Event::ExecuteCallback(ListenerIdentifier l_id, DataObjectPtr d_o) { + p_->ExecuteCallback(std::move(l_id), d_o); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Event.h b/src/core/module/Event.h new file mode 100644 index 00000000..92268216 --- /dev/null +++ b/src/core/module/Event.h @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <any> +#include <functional> +#include <optional> + +#include "core/GpgFrontendCore.h" +#include "core/model/DataObject.h" + +namespace GpgFrontend::Module { + +class Event; + +using EventRefrernce = std::shared_ptr<Event>; +using EventIdentifier = QString; +using Evnets = std::vector<Event>; + +class GPGFRONTEND_CORE_EXPORT Event { + public: + using ParameterValue = std::any; + using EventIdentifier = QString; + using ListenerIdentifier = QString; + using EventCallback = + std::function<void(EventIdentifier, ListenerIdentifier, DataObjectPtr)>; + struct ParameterInitializer { + QString key; + ParameterValue value; + }; + + explicit Event(const QString&, + std::initializer_list<ParameterInitializer> = {}, + EventCallback = nullptr); + + ~Event(); + + auto operator[](const QString& key) const -> std::optional<ParameterValue>; + + auto operator==(const Event& other) const -> bool; + + auto operator!=(const Event& other) const -> bool; + + auto operator<(const Event& other) const -> bool; + + auto operator<=(const Event& other) const -> bool; + + explicit operator QString() const; + + auto GetIdentifier() -> EventIdentifier; + + void AddParameter(const QString& key, const ParameterValue& value); + + void ExecuteCallback(ListenerIdentifier, DataObjectPtr); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename... Args> +auto MakeEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb) -> EventRefrernce { + std::initializer_list<Event::ParameterInitializer> params = { + Event::ParameterInitializer{std::forward<Args>(args)}...}; + return GpgFrontend::SecureCreateSharedObject<Event>(event_id, params, e_cb); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalModuleContext.cpp b/src/core/module/GlobalModuleContext.cpp new file mode 100644 index 00000000..50f97334 --- /dev/null +++ b/src/core/module/GlobalModuleContext.cpp @@ -0,0 +1,377 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GlobalModuleContext.h" + +#include <set> +#include <unordered_map> +#include <unordered_set> + +#include "core/module/Event.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "model/DataObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext::Impl { + public: + explicit Impl() { + // Initialize acquired channels with default values. + acquired_channel_.insert(kGpgFrontendDefaultChannel); + acquired_channel_.insert(kGpgFrontendNonAsciiChannel); + } + + auto GetChannel(ModuleRawPtr module) -> int { + // Search for the module in the register table. + auto module_info_opt = + search_module_register_table(module->GetModuleIdentifier()); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR( + "cannot find module id {} at register table, fallbacking to " + "default " + "channel", + module->GetModuleIdentifier()); + return GetDefaultChannel(module); + } + + auto module_info = module_info_opt.value(); + return module_info->channel; + } + + static auto GetDefaultChannel(ModuleRawPtr) -> int { + return kGpgFrontendDefaultChannel; + } + + auto GetTaskRunner(ModuleRawPtr /*module*/) -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetTaskRunner(ModuleIdentifier /*module_id*/) + -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr> { + return default_task_runner_; + } + + auto RegisterModule(const ModulePtr& module) -> bool { + GF_CORE_LOG_DEBUG("attempting to register module: {}", + module->GetModuleIdentifier()); + // Check if the module is null or already registered. + if (module == nullptr || + module_register_table_.find(module->GetModuleIdentifier()) != + module_register_table_.end()) { + GF_CORE_LOG_ERROR( + "module is null or have already registered this module"); + return false; + } + + if (!module->Register()) { + GF_CORE_LOG_ERROR("register module {} failed", + module->GetModuleIdentifier()); + return false; + } + + auto register_info = + GpgFrontend::SecureCreateSharedObject<ModuleRegisterInfo>(); + register_info->module = module; + register_info->channel = acquire_new_unique_channel(); + + // move module to its task runner' thread + register_info->module->setParent(nullptr); + register_info->module->moveToThread( + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->GetThread()); + + // Register the module with its identifier. + module_register_table_[module->GetModuleIdentifier()] = register_info; + + GF_CORE_LOG_DEBUG("successfully registered module: {}", + module->GetModuleIdentifier()); + return true; + } + + auto ActiveModule(ModuleIdentifier module_id) -> bool { + GF_CORE_LOG_DEBUG("attempting to activate module: {}", module_id); + + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + + // try to get module from module info + auto module = module_info->module; + if (module == nullptr) { + GF_CORE_LOG_ERROR( + "module id {} at register table is releated to a null module", + module_id); + return false; + } + + // Activate the module if it is not already active. + if (!module_info->activate) { + module->Active(); + module_info->activate = true; + } + + GF_CORE_LOG_DEBUG("module activation status: {}", module_info->activate); + return module_info->activate; + } + + auto ListenEvent(ModuleIdentifier module_id, EventIdentifier event) -> bool { + GF_CORE_LOG_DEBUG("module: {} is attempting to listen to event {}", + module_id, event); + // Check if the event exists, if not, create it. + auto met_it = module_events_table_.find(event); + if (met_it == module_events_table_.end()) { + module_events_table_[event] = std::unordered_set<ModuleIdentifier>(); + met_it = module_events_table_.find(event); + GF_CORE_LOG_INFO("new event {} of module system created", event); + } + + auto& listeners_set = met_it->second; + // Add the listener (module) to the event. + auto listener_it = listeners_set.find(module_id); + if (listener_it == listeners_set.end()) { + listeners_set.insert(module_id); + } + return true; + } + + auto DeactivateModule(ModuleIdentifier module_id) -> bool { + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + // Activate the module if it is not already deactive. + if (!module_info->activate && module_info->module->Deactive()) { + module_info->activate = false; + } + + return !module_info->activate; + } + + auto TriggerEvent(const EventRefrernce& event) -> bool { + auto event_id = event->GetIdentifier(); + GF_CORE_LOG_DEBUG("attempting to trigger event: {}", event_id); + + // Find the set of listeners associated with the given event in the table + auto met_it = module_events_table_.find(event_id); + if (met_it == module_events_table_.end()) { + // Log a warning if the event is not registered and nobody is listening + GF_CORE_LOG_WARN( + "event {} is not listening by anyone and not registered as well", + event_id); + return false; + } + + // Retrieve the set of listeners for this event + auto& listeners_set = met_it->second; + + // Check if the set of listeners is empty + if (listeners_set.empty()) { + // Log a warning if nobody is listening to this event + GF_CORE_LOG_WARN("event {} is not listening by anyone", + event->GetIdentifier()); + return false; + } + + // Log the number of listeners for this event + GF_CORE_LOG_DEBUG("event {}'s current listeners size: {}", + event->GetIdentifier(), listeners_set.size()); + + // Iterate through each listener and execute the corresponding module + for (const auto& listener_module_id : listeners_set) { + // Search for the module's information in the registration table + auto module_info_opt = search_module_register_table(listener_module_id); + + // Log an error if the module is not found in the registration table + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + listener_module_id); + continue; + } + + // Retrieve the module's information + auto module_info = module_info_opt.value(); + auto module = module_info->module; + + GF_CORE_LOG_DEBUG( + "module {} is listening to event {}, activate state: {}", + module_info->module->GetModuleIdentifier(), event->GetIdentifier(), + module_info->activate); + + // Check if the module is activated + if (!module_info->activate) continue; + + Thread::Task::TaskRunnable const exec_runnerable = + [module, event](DataObjectPtr) -> int { return module->Exec(event); }; + + Thread::Task::TaskCallback const exec_callback = + [listener_module_id, event_id](int code, DataObjectPtr) { + if (code < 0) { + // Log an error if the module execution fails + GF_CORE_LOG_ERROR( + "module {} execution failed of event {}: exec return code {}", + listener_module_id, event_id, code); + } + }; + + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->PostTask(new Thread::Task(exec_runnerable, + QString("event/%1/module/exec/%2") + .arg(event_id) + .arg(listener_module_id), + nullptr, exec_callback)); + } + + // Return true to indicate successful execution of all modules + return true; + } + + auto IsModuleActivated(const ModuleIdentifier& m_id) const -> bool { + auto m = search_module_register_table(m_id); + return m.has_value() && m->get()->activate; + } + + private: + struct ModuleRegisterInfo { + int channel; + ModulePtr module; + bool activate; + }; + + using ModuleRegisterInfoPtr = std::shared_ptr<ModuleRegisterInfo>; + + std::unordered_map<ModuleIdentifier, ModuleRegisterInfoPtr> + module_register_table_; + std::map<EventIdentifier, std::unordered_set<ModuleIdentifier>> + module_events_table_; + + std::set<int> acquired_channel_; + TaskRunnerPtr default_task_runner_; + + auto acquire_new_unique_channel() -> int { + int random_channel = QRandomGenerator::global()->bounded(65535); + // Ensure the acquired channel is unique. + while (acquired_channel_.find(random_channel) != acquired_channel_.end()) { + random_channel = QRandomGenerator::global()->bounded(65535); + } + + // Add the acquired channel to the set. + acquired_channel_.insert(random_channel); + return random_channel; + } + + // Function to search for a module in the register table. + auto search_module_register_table(const ModuleIdentifier& identifier) const + -> std::optional<ModuleRegisterInfoPtr> { + auto mrt_it = module_register_table_.find(identifier); + if (mrt_it == module_register_table_.end()) { + return std::nullopt; + } + return mrt_it->second; + } +}; + +// Constructor for GlobalModuleContext, takes a TaskRunnerPtr as an argument. +GlobalModuleContext::GlobalModuleContext() + : p_(SecureCreateUniqueObject<Impl>()) {} + +GlobalModuleContext::~GlobalModuleContext() = default; + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleRawPtr module) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(module); +} + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(module_id)); +} + +// Function to get the global task runner. +auto GlobalModuleContext::GetGlobalTaskRunner() + -> std::optional<TaskRunnerPtr> { + return p_->GetGlobalTaskRunner(); +} + +auto GlobalModuleContext::RegisterModule(ModulePtr module) -> bool { + return p_->RegisterModule(std::move(module)); +} + +auto GlobalModuleContext::ActiveModule(ModuleIdentifier module_id) -> bool { + return p_->ActiveModule(std::move(module_id)); +} + +auto GlobalModuleContext::ListenEvent(ModuleIdentifier module_id, + EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(module_id), std::move(event)); +} + +auto GlobalModuleContext::DeactivateModule(ModuleIdentifier module_id) -> bool { + return p_->DeactivateModule(std::move(module_id)); +} + +auto GlobalModuleContext::TriggerEvent(EventRefrernce event) -> bool { + return p_->TriggerEvent(std::move(event)); +} + +auto GlobalModuleContext::GetChannel(ModuleRawPtr module) -> int { + return p_->GetChannel(module); +} + +auto GlobalModuleContext::GetDefaultChannel(ModuleRawPtr channel) -> int { + return GlobalModuleContext::Impl::GetDefaultChannel(channel); +} + +auto GlobalModuleContext::IsModuleActivated(ModuleIdentifier m_id) -> bool { + return p_->IsModuleActivated(std::move(m_id)); +} + +} // namespace GpgFrontend::Module diff --git a/src/core/module/GlobalModuleContext.h b/src/core/module/GlobalModuleContext.h new file mode 100644 index 00000000..1c971bb5 --- /dev/null +++ b/src/core/module/GlobalModuleContext.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <optional> + +#include "core/module/Event.h" +#include "core/thread/TaskRunner.h" +#include "function/SecureMemoryAllocator.h" +#include "module/GlobalRegisterTable.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext; +class GlobalRegisterTable; + +class Module; +class ModuleManager; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleRawPtr = Module*; + +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using GRTPtr = std::shared_ptr<GlobalRegisterTable>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT GlobalModuleContext : public QObject { + Q_OBJECT + public: + explicit GlobalModuleContext(); + + ~GlobalModuleContext() override; + + auto GetChannel(ModuleRawPtr) -> int; + + static auto GetDefaultChannel(ModuleRawPtr) -> int; + + auto GetTaskRunner(ModuleRawPtr) -> std::optional<TaskRunnerPtr>; + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr>; + + auto RegisterModule(ModulePtr) -> bool; + + auto ActiveModule(ModuleIdentifier) -> bool; + + auto DeactivateModule(ModuleIdentifier) -> bool; + + auto ListenEvent(ModuleIdentifier, EventIdentifier) -> bool; + + auto TriggerEvent(EventRefrernce) -> bool; + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.cpp b/src/core/module/GlobalRegisterTable.cpp new file mode 100644 index 00000000..c16eba37 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.cpp @@ -0,0 +1,167 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GlobalRegisterTable.h" + +#include <any> +#include <optional> +#include <shared_mutex> +#include <sstream> +#include <unordered_map> +#include <vector> + +#include "function/SecureMemoryAllocator.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalRegisterTable::Impl { + public: + struct RTNode { + std::optional<std::any> value = std::nullopt; + std::unordered_map<QString, SecureUniquePtr<RTNode>> children; + int version = 0; + const std::type_info* type = nullptr; + }; + + explicit Impl(GlobalRegisterTable* parent) : parent_(parent) {} + + auto PublishKV(const Namespace& n, const Key& k, std::any v) -> bool { + QStringList const segments = k.split('.'); + int version = 0; + + { + std::unique_lock lock(lock_); + auto& root_rt_node = + global_register_table_.emplace(n, SecureCreateUniqueObject<RTNode>()) + .first->second; + + RTNode* current = root_rt_node.get(); + for (const QString& segment : segments) { + current = current->children + .emplace(segment, SecureCreateUniqueObject<RTNode>()) + .first->second.get(); + } + + current->value = v; + current->type = &v.type(); + version = ++current->version; + } + + emit parent_->SignalPublish(n, k, version, v); + return true; + } + + auto LookupKV(const Namespace& n, const Key& k) -> std::optional<std::any> { + QStringList const segments = k.split('.'); + + std::optional<std::any> rtn = std::nullopt; + { + std::shared_lock const lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return std::nullopt; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return std::nullopt; + current = it->second.get(); + } + rtn = current->value; + } + return rtn; + } + + auto ListChildKeys(const Namespace& n, const Key& k) -> std::vector<Key> { + QStringList const segments = k.split('.'); + + std::vector<Key> rtn; + { + std::shared_lock lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return {}; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return {}; + current = it->second.get(); + } + + for (auto& it : current->children) { + rtn.emplace_back(it.first); + } + } + return rtn; + } + + auto ListenPublish(QObject* o, const Namespace& n, const Key& k, LPCallback c) + -> bool { + if (o == nullptr) return false; + return QObject::connect(parent_, &GlobalRegisterTable::SignalPublish, o, + [n, k, c](const Namespace& pn, const Key& pk, + int ver, std::any value) { + if (pn == n && pk == k) { + c(pn, pk, ver, std::move(value)); + } + }) == nullptr; + } + + private: + using Table = std::map<Namespace, SecureUniquePtr<RTNode>>; + std::shared_mutex lock_; + GlobalRegisterTable* parent_; + + Table global_register_table_; +}; + +GlobalRegisterTable::GlobalRegisterTable() + : p_(SecureCreateUniqueObject<Impl>(this)) {} + +GlobalRegisterTable::~GlobalRegisterTable() = default; + +auto GlobalRegisterTable::PublishKV(Namespace n, Key k, std::any v) -> bool { + return p_->PublishKV(n, k, v); +} + +auto GlobalRegisterTable::LookupKV(Namespace n, Key v) + -> std::optional<std::any> { + return p_->LookupKV(n, v); +} + +auto GlobalRegisterTable::ListenPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto GlobalRegisterTable::ListChildKeys(Namespace n, Key k) + -> std::vector<Key> { + return p_->ListChildKeys(n, k); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.h b/src/core/module/GlobalRegisterTable.h new file mode 100644 index 00000000..db68c888 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.h @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <any> +#include <functional> +#include <optional> + +#include "function/SecureMemoryAllocator.h" + +namespace GpgFrontend::Module { + +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GlobalRegisterTable : public QObject { + Q_OBJECT + public: + GlobalRegisterTable(); + + ~GlobalRegisterTable() override; + + auto PublishKV(Namespace, Key, std::any) -> bool; + + auto LookupKV(Namespace, Key) -> std::optional<std::any>; + + auto ListenPublish(QObject *, Namespace, Key, LPCallback) -> bool; + + auto ListChildKeys(Namespace n, Key k) -> std::vector<Key>; + + signals: + void SignalPublish(Namespace, Key, int, std::any); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GpgFrontendModuleSystem.h b/src/core/module/GpgFrontendModuleSystem.h new file mode 100644 index 00000000..903aec69 --- /dev/null +++ b/src/core/module/GpgFrontendModuleSystem.h @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <core/GpgFrontendCore.h> +#include <core/module/Event.h> +#include <core/module/Module.h> +#include <core/module/ModuleManager.h>
\ No newline at end of file diff --git a/src/core/module/Module.cpp b/src/core/module/Module.cpp new file mode 100644 index 00000000..cab72a9a --- /dev/null +++ b/src/core/module/Module.cpp @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "Module.h" + +#include "core/module/GlobalModuleContext.h" + +namespace GpgFrontend::Module { + +class Module::Impl { + public: + friend class GlobalModuleContext; + + using ExecCallback = std::function<void(int)>; + + Impl(ModuleRawPtr m_ptr, ModuleIdentifier id, ModuleVersion version, + ModuleMetaData meta_data) + : m_ptr_(m_ptr), + identifier_(std::move(id)), + version_(std::move(version)), + meta_data_(std::move(meta_data)) {} + + auto GetChannel() -> int { return get_gpc()->GetChannel(m_ptr_); } + + auto GetDefaultChannel() -> int { + return get_gpc()->GetDefaultChannel(m_ptr_); + } + + auto GetTaskRunner() -> std::optional<TaskRunnerPtr> { + return get_gpc()->GetTaskRunner(m_ptr_); + } + + auto ListenEvent(EventIdentifier event) -> bool { + return get_gpc()->ListenEvent(GetModuleIdentifier(), std::move(event)); + } + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier { + return identifier_; + } + + void SetGPC(GlobalModuleContext* gpc) { gpc_ = gpc; } + + private: + GlobalModuleContext* gpc_; + Module* m_ptr_; + const ModuleIdentifier identifier_; + const ModuleVersion version_; + const ModuleMetaData meta_data_; + + auto get_gpc() -> GlobalModuleContext* { + if (gpc_ == nullptr) { + throw std::runtime_error("module is not registered by module manager"); + } + return gpc_; + } +}; + +Module::Module(ModuleIdentifier id, ModuleVersion version, + ModuleMetaData meta_data) + : p_(SecureCreateUniqueObject<Impl>(this, id, version, meta_data)) {} + +Module::~Module() = default; + +auto Module::getChannel() -> int { return p_->GetChannel(); } + +auto Module::getDefaultChannel() -> int { return p_->GetDefaultChannel(); } + +auto Module::getTaskRunner() -> TaskRunnerPtr { + return p_->GetTaskRunner().value_or(nullptr); +} + +auto Module::listenEvent(EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(event)); +} + +auto Module::GetModuleIdentifier() const -> ModuleIdentifier { + return p_->GetModuleIdentifier(); +} + +void Module::SetGPC(GlobalModuleContext* gpc) { p_->SetGPC(gpc); } +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Module.h b/src/core/module/Module.h new file mode 100644 index 00000000..2742475e --- /dev/null +++ b/src/core/module/Module.h @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/module/Event.h" +#include "core/thread/TaskRunner.h" + +namespace GpgFrontend::Module { + +class Module; +class GlobalModuleContext; +class ModuleManager; + +using ModuleIdentifier = QString; +using ModuleVersion = QString; +using ModuleMetaData = std::map<QString, QString>; +using ModulePtr = std::shared_ptr<Module>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT Module : public QObject { + Q_OBJECT + public: + Module(ModuleIdentifier, ModuleVersion, ModuleMetaData); + + ~Module(); + + virtual auto Register() -> bool = 0; + + virtual auto Active() -> bool = 0; + + virtual auto Exec(EventRefrernce) -> int = 0; + + virtual auto Deactive() -> bool = 0; + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier; + + void SetGPC(GlobalModuleContext*); + + protected: + auto getChannel() -> int; + + auto getDefaultChannel() -> int; + + auto getTaskRunner() -> TaskRunnerPtr; + + auto listenEvent(EventIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp new file mode 100644 index 00000000..83e7c1ff --- /dev/null +++ b/src/core/module/ModuleManager.cpp @@ -0,0 +1,184 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "ModuleManager.h" + +#include <memory> + +#include "GpgConstants.h" +#include "core/module/GlobalModuleContext.h" +#include "core/module/GlobalRegisterTable.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "function/SecureMemoryAllocator.h" +#include "function/basic/GpgFunctionObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class ModuleManager::Impl { + public: + Impl() + : gmc_(GpgFrontend::SecureCreateUniqueObject<GlobalModuleContext>()), + grt_(GpgFrontend::SecureCreateUniqueObject<GlobalRegisterTable>()) {} + + ~Impl() = default; + + void RegisterModule(const ModulePtr& module) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](GpgFrontend::DataObjectPtr) -> int { + module->SetGPC(gmc_.get()); + gmc_->RegisterModule(module); + return 0; + }, + __func__, nullptr)); + } + + void TriggerEvent(const EventRefrernce& event) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->TriggerEvent(event); + return 0; + }, + __func__, nullptr)); + } + + void ActiveModule(const ModuleIdentifier& identifier) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->ActiveModule(identifier); + return 0; + }, + __func__, nullptr)); + } + + auto GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return gmc_->GetTaskRunner(std::move(module_id)); + } + + auto UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return grt_->PublishKV(n, k, v); + } + + auto RetrieveRTValue(Namespace n, Key k) -> std::optional<std::any> { + return grt_->LookupKV(n, k); + } + + auto ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) -> bool { + return grt_->ListenPublish(o, n, k, c); + } + + auto ListRTChildKeys(const QString& n, const QString& k) -> std::vector<Key> { + return grt_->ListChildKeys(n, k); + } + + auto IsModuleActivated(ModuleIdentifier id) -> bool { + return gmc_->IsModuleActivated(id); + } + + private: + static ModuleMangerPtr global_module_manager; + SecureUniquePtr<GlobalModuleContext> gmc_; + SecureUniquePtr<GlobalRegisterTable> grt_; +}; + +auto IsModuleAcivate(ModuleIdentifier id) -> bool { + return ModuleManager::GetInstance().IsModuleActivated(id); +} + +auto UpsertRTValue(const QString& namespace_, const QString& key, + const std::any& value) -> bool { + return ModuleManager::GetInstance().UpsertRTValue(namespace_, key, + std::any(value)); +} + +auto ListenRTPublishEvent(QObject* o, Namespace n, Key k, LPCallback c) + -> bool { + return ModuleManager::GetInstance().ListenRTPublish(o, n, k, c); +} + +auto ListRTChildKeys(const QString& namespace_, const QString& key) + -> std::vector<Key> { + return ModuleManager::GetInstance().ListRTChildKeys(namespace_, key); +} + +ModuleManager::ModuleManager(int channel) + : SingletonFunctionObject<ModuleManager>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +ModuleManager::~ModuleManager() = default; + +void ModuleManager::RegisterModule(ModulePtr module) { + return p_->RegisterModule(module); +} + +void ModuleManager::TriggerEvent(EventRefrernce event) { + return p_->TriggerEvent(event); +} + +void ModuleManager::ActiveModule(ModuleIdentifier id) { + return p_->ActiveModule(id); +} + +auto ModuleManager::GetTaskRunner(ModuleIdentifier id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(id)); +} + +auto ModuleManager::UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return p_->UpsertRTValue(n, k, v); +} + +auto ModuleManager::RetrieveRTValue(Namespace n, Key k) + -> std::optional<std::any> { + return p_->RetrieveRTValue(n, k); +} + +auto ModuleManager::ListenRTPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto ModuleManager::ListRTChildKeys(const QString& n, const QString& k) + -> std::vector<Key> { + return p_->ListRTChildKeys(n, k); +} + +auto ModuleManager::IsModuleActivated(ModuleIdentifier id) -> bool { + return p_->IsModuleActivated(id); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h new file mode 100644 index 00000000..93b89e95 --- /dev/null +++ b/src/core/module/ModuleManager.h @@ -0,0 +1,179 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <mutex> +#include <vector> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/module/Event.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend::Thread { +class TaskRunner; +} + +namespace GpgFrontend::Module { + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class Event; +class Module; +class GlobalModuleContext; +class ModuleManager; + +using EventRefrernce = std::shared_ptr<Event>; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleMangerPtr = std::shared_ptr<ModuleManager>; +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GPGFRONTEND_CORE_EXPORT ModuleManager + : public SingletonFunctionObject<ModuleManager> { + public: + explicit ModuleManager(int channel); + + virtual ~ModuleManager() override; + + void RegisterModule(ModulePtr); + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + void TriggerEvent(EventRefrernce); + + void ActiveModule(ModuleIdentifier); + + void DeactiveModule(ModuleIdentifier); + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto UpsertRTValue(Namespace, Key, std::any) -> bool; + + auto RetrieveRTValue(Namespace, Key) -> std::optional<std::any>; + + auto ListenRTPublish(QObject*, Namespace, Key, LPCallback) -> bool; + + auto ListRTChildKeys(const QString&, const QString&) -> std::vector<Key>; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename T, typename... Args> +void RegisterModule(Args&&... args) { + ModuleManager::GetInstance().RegisterModule( + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...)); +} + +template <typename T, typename... Args> +void RegisterAndActivateModule(Args&&... args) { + auto& manager = ModuleManager::GetInstance(); + auto module = + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...); + manager.RegisterModule(module); + manager.ActiveModule(module->GetModuleIdentifier()); +} + +template <typename... Args> +void TriggerEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb = nullptr) { + ModuleManager::GetInstance().TriggerEvent( + std::move(MakeEvent(event_id, std::forward<Args>(args)..., e_cb))); +} + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT IsModuleAcivate(ModuleIdentifier) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @param value + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT UpsertRTValue(const QString& namespace_, + const QString& key, + const std::any& value) -> bool; + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT ListenRTPublishEvent(QObject*, Namespace, Key, + LPCallback) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @return std::vector<Key> + */ +auto GPGFRONTEND_CORE_EXPORT ListRTChildKeys(const QString& namespace_, + const QString& key) + -> std::vector<Key>; + +template <typename T> +auto RetrieveRTValueTyped(const QString& namespace_, const QString& key) + -> std::optional<T> { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return std::nullopt; +} + +template <typename T> +auto RetrieveRTValueTypedOrDefault(const QString& namespace_, + const QString& key, const T& defaultValue) + -> T { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return defaultValue; +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/thread/CtxCheckTask.cpp b/src/core/thread/CtxCheckTask.cpp deleted file mode 100644 index 9735fcaa..00000000 --- a/src/core/thread/CtxCheckTask.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. - * - */ - -#include "core/thread/CtxCheckTask.h" - -#include "core/GpgContext.h" -#include "core/GpgCoreInit.h" -#include "core/common/CoreCommonUtil.h" -#include "core/function/gpg/GpgKeyGetter.h" -#include "thread/Task.h" - -GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() : Task("ctx_check_task") { - connect(this, &CtxCheckTask::SignalGnupgNotInstall, - CoreCommonUtil::GetInstance(), - &CoreCommonUtil::SignalGnupgNotInstall); -} - -void GpgFrontend::Thread::CtxCheckTask::Run() { - // Init GpgFrontend Core - init_gpgfrontend_core(); - - // Create & Check Gnupg Context Status - if (!GpgContext::GetInstance().good()) { - emit SignalGnupgNotInstall(); - } - // Try flushing key cache - else - GpgFrontend::GpgKeyGetter::GetInstance().FlushKeyCache(); - - SPDLOG_DEBUG("ctx check task runnable done"); -} diff --git a/src/core/thread/CtxCheckTask.h b/src/core/thread/CtxCheckTask.h deleted file mode 100644 index 06ddfd82..00000000 --- a/src/core/thread/CtxCheckTask.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. - * - */ - -#ifndef GPGFRONTEND_CTXCHECKTRHEAD_H -#define GPGFRONTEND_CTXCHECKTRHEAD_H - -#include "core/GpgFrontendCore.h" -#include "core/thread/Task.h" - -namespace GpgFrontend::Thread { -/** - * @brief - * - */ -class GPGFRONTEND_CORE_EXPORT CtxCheckTask : public Task { - Q_OBJECT - public: - /** - * @brief Construct a new Ctx Check Thread object - * - */ - CtxCheckTask(); - - signals: - /** - * @brief - * - */ - void SignalGnupgNotInstall(); - - protected: - /** - * @brief - * - */ - void Run() override; -}; -} // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_CTXCHECKTRHEAD_H diff --git a/src/core/thread/FileReadTask.cpp b/src/core/thread/FileReadTask.cpp index 73954d28..c757d4c0 100644 --- a/src/core/thread/FileReadTask.cpp +++ b/src/core/thread/FileReadTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,8 +19,10 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ @@ -28,58 +30,51 @@ namespace GpgFrontend::UI { -FileReadTask::FileReadTask(std::string path) : Task("file_read_task") { - connect(this, &FileReadTask::SignalFileBytesReadNext, this, - &FileReadTask::read_bytes); +constexpr size_t kBufferSize = 8192; -#ifdef WINDOWS - std::filesystem::path read_file_path( - QString::fromStdString(path).toStdU16String()); -#else - std::filesystem::path read_file_path( - QString::fromStdString(path).toStdString()); -#endif - read_file_path_ = read_file_path; +FileReadTask::FileReadTask(QString path) + : Task("file_read_task"), read_file_path_(std::move(path)) { + HoldOnLifeCycle(true); + connect(this, &FileReadTask::SignalFileBytesReadNext, this, + &FileReadTask::slot_read_bytes); } -void FileReadTask::Run() { - SetFinishAfterRun(false); - - if (is_regular_file(read_file_path_)) { - SPDLOG_DEBUG("read open file: {}", read_file_path_.u8string()); +auto FileReadTask::Run() -> int { + if (QFileInfo(read_file_path_).isFile()) { + GF_CORE_LOG_DEBUG("read open file: {}", read_file_path_); - target_file_.setFileName( - QString::fromStdString(read_file_path_.u8string())); + target_file_.setFileName(read_file_path_); target_file_.open(QIODevice::ReadOnly); if (!(target_file_.isOpen() && target_file_.isReadable())) { - SPDLOG_ERROR("file not open or not readable"); + GF_CORE_LOG_ERROR("file not open or not readable"); if (target_file_.isOpen()) target_file_.close(); - return; + return -1; } - SPDLOG_DEBUG("started reading: {}", read_file_path_.u8string()); - read_bytes(); + GF_CORE_LOG_DEBUG("started reading: {}", read_file_path_); + slot_read_bytes(); } else { emit SignalFileBytesReadEnd(); } + return 0; } -void FileReadTask::read_bytes() { +void FileReadTask::slot_read_bytes() { QByteArray read_buffer; if (!target_file_.atEnd() && - (read_buffer = target_file_.read(buffer_size_)).size() > 0) { - SPDLOG_DEBUG("read bytes: {}", read_buffer.size()); + (read_buffer = target_file_.read(kBufferSize)).size() > 0) { + GF_CORE_LOG_DEBUG("io thread read bytes: {}", read_buffer.size()); emit SignalFileBytesRead(std::move(read_buffer)); } else { - SPDLOG_DEBUG("read bytes end"); + GF_CORE_LOG_DEBUG("io thread read bytes end"); emit SignalFileBytesReadEnd(); // announce finish task - emit SignalTaskRunnableEnd(0); + emit SignalTaskShouldEnd(0); } } FileReadTask::~FileReadTask() { - SPDLOG_DEBUG("close file: {}", read_file_path_.u8string()); + GF_CORE_LOG_DEBUG("close file: {}", read_file_path_); if (target_file_.isOpen()) target_file_.close(); } diff --git a/src/core/thread/FileReadTask.h b/src/core/thread/FileReadTask.h index d4e61cbe..22be33ef 100644 --- a/src/core/thread/FileReadTask.h +++ b/src/core/thread/FileReadTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,13 +19,14 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_FILEREADTHREAD_H -#define GPGFRONTEND_FILEREADTHREAD_H +#pragma once #include "core/GpgFrontendCore.h" #include "core/thread/Task.h" @@ -39,11 +40,11 @@ namespace GpgFrontend::UI { class GPGFRONTEND_CORE_EXPORT FileReadTask : public GpgFrontend::Thread::Task { Q_OBJECT public: - explicit FileReadTask(std::string path); + explicit FileReadTask(QString path); virtual ~FileReadTask() override; - void Run() override; + int Run() override; signals: void SignalFileBytesRead(QByteArray bytes); @@ -51,15 +52,12 @@ class GPGFRONTEND_CORE_EXPORT FileReadTask : public GpgFrontend::Thread::Task { void SignalFileBytesReadNext(); private: - std::filesystem::path read_file_path_; + QString read_file_path_; QFile target_file_; - const size_t buffer_size_ = 4096; QEventLoop looper; private slots: - void read_bytes(); + void slot_read_bytes(); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_FILEREADTHREAD_H diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index 7173b69e..1d251520 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,209 +19,237 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "core/thread/Task.h" -#include <boost/uuid/uuid.hpp> -#include <boost/uuid/uuid_generators.hpp> -#include <boost/uuid/uuid_io.hpp> -#include <functional> -#include <string> -#include <utility> +#include <qscopedpointer.h> -#include "core/thread/TaskRunner.h" +#include "utils/MemoryUtils.h" -const std::string GpgFrontend::Thread::Task::DEFAULT_TASK_NAME = "default-task"; +namespace GpgFrontend::Thread { -GpgFrontend::Thread::Task::Task(std::string name) - : uuid_(generate_uuid()), name_(name) { - SPDLOG_TRACE("task {}/ created", GetFullID()); - init(); -} +class Task::Impl { + public: + Impl(Task *parent, QString name) + : parent_(parent), uuid_(generate_uuid()), name_(std::move(name)) { + GF_CORE_LOG_TRACE("task {} created", GetFullID()); + init(); + } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, - DataObjectPtr data_object, bool sequency) - : uuid_(generate_uuid()), - name_(name), - runnable_(std::move(runnable)), - callback_(std::move([](int, const std::shared_ptr<DataObject> &) {})), - callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { - SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}", - GetFullID(), static_cast<void *>(callback_thread_)); - init(); -} + Impl(Task *parent, TaskRunnable runnable, QString name, + DataObjectPtr data_object) + : parent_(parent), + uuid_(generate_uuid()), + name_(std::move(name)), + runnable_(std::move(runnable)), + callback_([](int, const DataObjectPtr &) {}), + callback_thread_(QThread::currentThread()), + data_object_(std::move(data_object)) { + GF_CORE_LOG_TRACE("task {} created with runnable, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); + init(); + } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, - DataObjectPtr data_object, - TaskCallback callback, bool sequency) - : uuid_(generate_uuid()), - name_(name), - runnable_(std::move(runnable)), - callback_(std::move(callback)), - callback_thread_(QThread::currentThread()), - data_object_(data_object), - sequency_(sequency) { - init(); - SPDLOG_TRACE( - "task {} created with runnable and callback, callback_thread_: {}", - GetFullID(), static_cast<void *>(callback_thread_)); -} + Impl(Task *parent, TaskRunnable runnable, QString name, + DataObjectPtr data_object, TaskCallback callback) + : parent_(parent), + uuid_(generate_uuid()), + name_(std::move(name)), + runnable_(std::move(runnable)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(std::move(data_object)) { + GF_CORE_LOG_TRACE( + "task {} created with runnable and callback, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); + init(); + } -GpgFrontend::Thread::Task::~Task() { - SPDLOG_TRACE("task {} destroyed", GetFullID()); -} + ~Impl() { GF_CORE_LOG_TRACE("task {} destroyed", GetFullID()); } + + /** + * @brief + * + * @return QString + */ + [[nodiscard]] auto GetFullID() const -> QString { + return uuid_ + "/" + name_; + } + + /** + * @brief + * + * @return QString + */ + [[nodiscard]] auto GetUUID() const -> QString { return uuid_; } + + /** + * @brief + * + * @return int + */ + auto Run() -> int { + GF_CORE_LOG_TRACE("task {} is in classical runnable and callback mode", + GetFullID()); + + if (runnable_) return runnable_(data_object_); + + GF_CORE_LOG_WARN("no runnable in task, do callback operation, task: {}", + GetFullID()); + return 0; + } + + /** + * @brief Set the Finish After Run object + * + * @param finish_after_run + */ + void HoldOnLifeCycle(bool hold_on) { parent_->setAutoDelete(!hold_on); } + + /** + * @brief + * + * @param rtn + */ + void SetRTN(int rtn) { this->rtn_ = rtn; } + + /** + * @brief + * + * @return auto + */ + [[nodiscard]] auto GetRTN() const { return this->rtn_; } + + private: + Task *const parent_; + const QString uuid_; + const QString name_; + TaskRunnable runnable_; ///< + TaskCallback callback_; ///< + int rtn_ = -99; ///< + QThread *callback_thread_ = nullptr; ///< + DataObjectPtr data_object_ = nullptr; ///< + + void init() { + GF_CORE_LOG_TRACE("task {} created, parent: {}, impl: {}", name_, + (void *)parent_, (void *)this); + + // + HoldOnLifeCycle(false); + + // + connect(parent_, &Task::SignalRun, parent_, &Task::slot_exception_safe_run); + + auto *callback_thread = callback_thread_ != nullptr + ? callback_thread_ + : QCoreApplication::instance()->thread(); + // + connect(parent_, &Task::SignalTaskShouldEnd, callback_thread, + [this](int rtn) { + // set task returning code + SetRTN(rtn); + try { + if (callback_) { + GF_CORE_LOG_TRACE( + "task callback {} is starting with runnerable rtn: {}", + GetFullID(), rtn); + + callback_(rtn_, data_object_); + GF_CORE_LOG_TRACE("task callback {} finished, rtn: {}", + GetFullID(), rtn); + } + } catch (...) { + GF_CORE_LOG_ERROR("task {} callback caught exception, rtn: {}", + GetFullID(), rtn); + } + emit parent_->SignalTaskEnd(); + }); + + // + connect(parent_, &Task::SignalTaskEnd, parent_, &Task::deleteLater); + } + + /** + * @brief + * + * @return QString + */ + static auto generate_uuid() -> QString { + return QUuid::createUuid().toString(); + } +}; + +Task::Task(QString name) : p_(new Impl(this, name)) {} + +Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object) + : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object)) {} + +Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object, + TaskCallback callback) + : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object, + callback)) {} + +Task::~Task() = default; /** * @brief * - * @return std::string + * @return QString */ -std::string GpgFrontend::Thread::Task::GetFullID() const { - return uuid_ + "/" + name_; -} - -std::string GpgFrontend::Thread::Task::GetUUID() const { return uuid_; } +QString Task::GetFullID() const { return p_->GetFullID(); } -bool GpgFrontend::Thread::Task::GetSequency() const { return sequency_; } +QString Task::GetUUID() const { return p_->GetUUID(); } -void GpgFrontend::Thread::Task::SetFinishAfterRun( - bool run_callback_after_runnable_finished) { - this->run_callback_after_runnable_finished_ = - run_callback_after_runnable_finished; -} +void Task::HoldOnLifeCycle(bool hold_on) { p_->HoldOnLifeCycle(hold_on); } -void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; } - -void GpgFrontend::Thread::Task::init() { - // after runnable finished, running callback - connect(this, &Task::SignalTaskRunnableEnd, this, - &Task::slot_task_run_callback); -} +void Task::setRTN(int rtn) { p_->SetRTN(rtn); } -void GpgFrontend::Thread::Task::slot_task_run_callback(int rtn) { - SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn); - // set return value - this->SetRTN(rtn); +void Task::SafelyRun() { emit SignalRun(); } - try { - if (callback_) { - if (callback_thread_ == QThread::currentThread()) { - SPDLOG_DEBUG("callback thread is the same thread"); - if (!QMetaObject::invokeMethod(callback_thread_, - [callback = callback_, rtn = rtn_, - data_object = data_object_, this]() { - callback(rtn, data_object); - // do cleaning work - emit SignalTaskEnd(); - })) { - SPDLOG_ERROR("failed to invoke callback"); - } - // just finished, let callack thread to raise SignalTaskEnd - return; - } else { - // waiting for callback to finish - if (!QMetaObject::invokeMethod( - callback_thread_, - [callback = callback_, rtn = rtn_, - data_object = data_object_]() { callback(rtn, data_object); }, - Qt::BlockingQueuedConnection)) { - SPDLOG_ERROR("failed to invoke callback"); - } - } - } - } catch (std::exception &e) { - SPDLOG_ERROR("exception caught: {}", e.what()); - } catch (...) { - SPDLOG_ERROR("unknown exception caught"); - } +int Task::Run() { return p_->Run(); } - // raise signal, announcing this task come to an end - SPDLOG_DEBUG("task {}, starting calling signal SignalTaskEnd", GetFullID()); - emit SignalTaskEnd(); +void Task::run() { + GF_CORE_LOG_TRACE("interface run() of task {} was called by thread: {}", + GetFullID(), QThread::currentThread()->currentThreadId()); + this->SafelyRun(); } -void GpgFrontend::Thread::Task::run() { - SPDLOG_TRACE("task {} starting", GetFullID()); +Task::TaskHandler::TaskHandler(Task *task) : task_(task) {} - // build runnable package for running - auto runnable_package = [=, id = GetFullID()]() { - SPDLOG_DEBUG("task {} runnable start runing", id); - // Run() will set rtn by itself - Run(); - // raise signal to anounce after runnable returned - if (run_callback_after_runnable_finished_) emit SignalTaskRunnableEnd(rtn_); - }; - - if (thread() != QThread::currentThread()) { - SPDLOG_DEBUG("task running thread is not object living thread"); - // if running sequently - if (sequency_) { - // running in another thread, blocking until returned - if (!QMetaObject::invokeMethod(thread(), runnable_package, - Qt::BlockingQueuedConnection)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } else { - // running in another thread, non-blocking - if (!QMetaObject::invokeMethod(thread(), runnable_package)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } - } else { - if (!QMetaObject::invokeMethod(this, runnable_package)) { - SPDLOG_ERROR("qt invoke method failed"); - } - } +void Task::TaskHandler::Start() { + if (task_ != nullptr) task_->SafelyRun(); } -void GpgFrontend::Thread::Task::SlotRun() { run(); } - -void GpgFrontend::Thread::Task::Run() { - if (runnable_) { - SetRTN(runnable_(data_object_)); - } else { - SPDLOG_WARN("no runnable in task, do callback operation"); - } +void Task::TaskHandler::Cancel() { + if (task_ != nullptr) emit task_->SignalTaskEnd(); } -GpgFrontend::Thread::Task::DataObject::Destructor * -GpgFrontend::Thread::Task::DataObject::get_heap_ptr(size_t bytes_size) { - Destructor *dstr_ptr = new Destructor(); - dstr_ptr->p_obj = malloc(bytes_size); - return dstr_ptr; +auto Task::TaskHandler::GetTask() -> Task * { + if (task_ != nullptr) return task_; + return nullptr; } -GpgFrontend::Thread::Task::DataObject::~DataObject() { - if (!data_objects_.empty()) - SPDLOG_WARN("data_objects_ is not empty", - "address:", static_cast<void *>(this)); - while (!data_objects_.empty()) { - free_heap_ptr(data_objects_.top()); - data_objects_.pop(); - } -} +void Task::slot_exception_safe_run() noexcept { + auto rtn = p_->GetRTN(); + try { + GF_CORE_LOG_TRACE("task runnable {} is starting...", GetFullID()); -size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() { - return data_objects_.size(); -} + // Run() will set rtn by itself + rtn = this->Run(); -void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) { - SPDLOG_TRACE("p_obj: {} data object: {}", - static_cast<const void *>(ptr->p_obj), - static_cast<void *>(this)); - if (ptr->destroy != nullptr) { - ptr->destroy(ptr->p_obj); + GF_CORE_LOG_TRACE("task runnable {} finished, rtn: {}", GetFullID()); + } catch (...) { + GF_CORE_LOG_ERROR("exception was caught at task: {}", GetFullID()); } - free(const_cast<void *>(ptr->p_obj)); - delete ptr; -} -std::string GpgFrontend::Thread::Task::generate_uuid() { - return boost::uuids::to_string(boost::uuids::random_generator()()); + // raise signal to anounce after runnable returned + if (this->autoDelete()) emit this->SignalTaskShouldEnd(rtn); } +auto Task::GetRTN() { return p_->GetRTN(); } +} // namespace GpgFrontend::Thread
\ No newline at end of file diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index ce354697..97a14949 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,17 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_TASK_H -#define GPGFRONTEND_TASK_H - -#include <functional> -#include <memory> -#include <stack> -#include <string> -#include <type_traits> -#include <utility> +#pragma once #include "core/GpgFrontendCore.h" +#include "core/function/SecureMemoryAllocator.h" +#include "core/model/DataObject.h" namespace GpgFrontend::Thread { @@ -45,253 +39,136 @@ class TaskRunner; class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { Q_OBJECT public: - class DataObject; - using DataObjectPtr = std::shared_ptr<DataObject>; ///< + friend class TaskRunner; + using TaskRunnable = std::function<int(DataObjectPtr)>; ///< using TaskCallback = std::function<void(int, DataObjectPtr)>; ///< - static const std::string DEFAULT_TASK_NAME; - - friend class TaskRunner; - - /** - * @brief DataObject to be passed to the callback function. - * - */ - class GPGFRONTEND_CORE_EXPORT DataObject { + class TaskHandler { public: - struct Destructor { - const void *p_obj; - void (*destroy)(const void *); - }; - - /** - * @brief Get the Objects Size - * - * @return size_t - */ - size_t GetObjectSize(); - - /** - * @brief - * - * @tparam T - * @param ptr - */ - template <typename T> - void AppendObject(T &&obj) { - SPDLOG_TRACE("append object: {}", static_cast<void *>(this)); - auto *obj_dstr = this->get_heap_ptr(sizeof(T)); - new ((void *)obj_dstr->p_obj) T(std::forward<T>(obj)); + explicit TaskHandler(Task*); - if (std::is_class_v<T>) { - auto destructor = [](const void *x) { - static_cast<const T *>(x)->~T(); - }; - obj_dstr->destroy = destructor; - } else { - obj_dstr->destroy = nullptr; - } + void Start(); - data_objects_.push(obj_dstr); - } + void Cancel(); - /** - * @brief - * - * @tparam T - * @param ptr - */ - template <typename T> - void AppendObject(T *obj) { - SPDLOG_TRACE("called: {}", static_cast<void *>(this)); - auto *obj_dstr = this->get_heap_ptr(sizeof(T)); - auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(*obj)); - if (std::is_class_v<T>) { - SPDLOG_TRACE("is class"); - auto destructor = [](const void *x) { - static_cast<const T *>(x)->~T(); - }; - obj_dstr->destroy = destructor; - } else { - obj_dstr->destroy = nullptr; - } - data_objects_.push(std::move(obj_dstr)); - } - - /** - * @brief - * - * @tparam T - * @return std::shared_ptr<T> - */ - template <typename T> - T PopObject() { - SPDLOG_TRACE("pop object: {}", static_cast<void *>(this)); - if (data_objects_.empty()) throw std::runtime_error("No object to pop"); - auto *obj_dstr = data_objects_.top(); - auto *heap_ptr = (T *)obj_dstr->p_obj; - auto obj = std::move(*(T *)(heap_ptr)); - this->free_heap_ptr(obj_dstr); - data_objects_.pop(); - return obj; - } - - /** - * @brief Destroy the Data Object object - * - */ - ~DataObject(); + auto GetTask() -> Task*; private: - std::stack<Destructor *> data_objects_; ///< - - /** - * @brief Get the heap ptr object - * - * @param bytes_size - * @return void* - */ - Destructor *get_heap_ptr(size_t bytes_size); - - /** - * @brief - * - * @param heap_ptr - */ - void free_heap_ptr(Destructor *); + QPointer<Task> task_; }; /** * @brief Construct a new Task object * */ - Task(std::string name = DEFAULT_TASK_NAME); + explicit Task(QString name); /** * @brief Construct a new Task object * * @param callback The callback function to be executed. */ - explicit Task(TaskRunnable runnable, std::string name = DEFAULT_TASK_NAME, - DataObjectPtr data_object = nullptr, bool sequency = true); + explicit Task(TaskRunnable runnable, QString name, + DataObjectPtr data_object = nullptr); /** * @brief Construct a new Task object * * @param runnable */ - explicit Task( - TaskRunnable runnable, std::string name, DataObjectPtr data, - TaskCallback callback = [](int, const std::shared_ptr<DataObject> &) {}, - bool sequency = true); + explicit Task(TaskRunnable runnable, QString name, DataObjectPtr data, + TaskCallback callback); /** * @brief Destroy the Task object * */ - virtual ~Task() override; + ~Task() override; /** - * @brief Run - run the task + * @brief * + * @return QString */ - virtual void Run(); + [[nodiscard]] auto GetUUID() const -> QString; /** - * @brief + * @brief Get the Full I D object * - * @return std::string + * @return QString */ - std::string GetUUID() const; + [[nodiscard]] auto GetFullID() const -> QString; /** * @brief * - * @return std::string + * @param hold_on */ - std::string GetFullID() const; + void HoldOnLifeCycle(bool hold_on); /** - * @brief + * @brief can be overwrite by subclass * - * @return std::string + * @return int */ - bool GetSequency() const; - - public slots: + virtual auto Run() -> int; /** * @brief * + * @return auto */ - void SlotRun(); + [[nodiscard]] auto GetRTN(); - signals: - /** - * @brief announce runnable finished - * - */ - void SignalTaskRunnableEnd(int rtn); + public slots: /** - * @brief runnable and callabck all finished + * @brief shouldn't be overwrite by subclass * */ - void SignalTaskEnd(); + void SafelyRun(); - protected: - /** - * @brief Set the Finish After Run object - * - * @param finish_after_run - */ - void SetFinishAfterRun(bool finish_after_run); + signals: /** * @brief * - * @param rtn */ - void SetRTN(int rtn); - - private: - const std::string uuid_; - const std::string name_; - const bool sequency_ = true; ///< must run in the same thread - TaskCallback callback_; ///< - TaskRunnable runnable_; ///< - bool run_callback_after_runnable_finished_ = true; ///< - int rtn_ = 0; ///< - QThread *callback_thread_ = nullptr; ///< - DataObjectPtr data_object_ = nullptr; ///< + void SignalRun(); /** * @brief * */ - void init(); + void SignalTaskShouldEnd(int); /** * @brief * */ - virtual void run() override; + void SignalTaskEnd(); + protected: /** * @brief * - * @return std::string + * @param rtn */ - static std::string generate_uuid(); + void setRTN(int rtn); private slots: + /** * @brief * */ - void slot_task_run_callback(int rtn); + void slot_exception_safe_run() noexcept; + + private: + class Impl; + SecureUniquePtr<Impl> p_; + + void run() override; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASK_H
\ No newline at end of file diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index 461d5fb5..8e381384 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,128 +19,132 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "core/thread/TaskRunner.h" #include "core/thread/Task.h" -#include "spdlog/spdlog.h" -GpgFrontend::Thread::TaskRunner::TaskRunner() = default; +namespace GpgFrontend::Thread { + +class TaskRunner::Impl : public QThread { + public: + Impl() : QThread(nullptr) {} -GpgFrontend::Thread::TaskRunner::~TaskRunner() = default; + void PostTask(Task* task) { + if (task == nullptr) { + GF_CORE_LOG_ERROR("task posted is null"); + return; + } -void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { - if (task == nullptr) { - SPDLOG_ERROR("task posted is null"); - return; + task->setParent(nullptr); + task->moveToThread(this); + + GF_CORE_LOG_TRACE("runner starts task: {} at thread: {}", task->GetFullID(), + this->currentThreadId()); + task->SafelyRun(); } - SPDLOG_TRACE("post task: {}", task->GetFullID()); + auto RegisterTask(const QString& name, const Task::TaskRunnable& runnerable, + const Task::TaskCallback& cb, DataObjectPtr params) + -> Task::TaskHandler { + auto* raw_task = new Task(runnerable, name, std::move(params), cb); + raw_task->setParent(nullptr); + raw_task->moveToThread(this); + + connect(raw_task, &Task::SignalRun, this, [this, raw_task]() { + pending_tasks_[raw_task->GetFullID()] = raw_task; + }); - task->setParent(nullptr); - task->moveToThread(this); + connect(raw_task, &Task::SignalTaskEnd, this, [this, raw_task]() { + pending_tasks_.remove(raw_task->GetFullID()); + }); - { - std::lock_guard<std::mutex> lock(tasks_mutex_); - tasks.push(task); + GF_CORE_LOG_TRACE("runner starts task: {} at thread: {}", + raw_task->GetFullID(), this->currentThreadId()); + + return Task::TaskHandler(raw_task); } - quit(); -} -void GpgFrontend::Thread::TaskRunner::PostScheduleTask(Task* task, - size_t seconds) { - if (task == nullptr) return; - // TODO -} + void PostTask(const QString& name, const Task::TaskRunnable& runnerable, + const Task::TaskCallback& cb, DataObjectPtr params) { + PostTask(new Task(runnerable, name, std::move(params), cb)); + } -[[noreturn]] void GpgFrontend::Thread::TaskRunner::run() { - SPDLOG_TRACE("task runner runing, thread id: {}", QThread::currentThreadId()); - while (true) { - if (tasks.empty()) { - SPDLOG_TRACE("no tasks to run, trapping into event loop..."); - exec(); - } else { - SPDLOG_TRACE("start to run task(s), queue size: {}", tasks.size()); - - Task* task = nullptr; - { - std::lock_guard<std::mutex> lock(tasks_mutex_); - task = std::move(tasks.front()); - tasks.pop(); - pending_tasks_.insert({task->GetUUID(), task}); - } - - if (task != nullptr) { - try { - // triger - SPDLOG_TRACE("running task {}, sequency: {}", task->GetFullID(), - task->GetSequency()); - - // when a signal SignalTaskEnd raise, do unregister work - connect(task, &Task::SignalTaskEnd, this, [this, task]() { - unregister_finished_task(task->GetUUID()); - }); - - if (!task->GetSequency()) { - // if it need to run concurrently, we should create a new thread to - // run it. - auto* concurrent_thread = new QThread(nullptr); - task->setParent(nullptr); - task->moveToThread(concurrent_thread); - // start thread - concurrent_thread->start(); - - connect(task, &Task::SignalTaskEnd, concurrent_thread, - &QThread::quit); - // concurrent thread is responsible for deleting the task - connect(concurrent_thread, &QThread::finished, task, - &Task::deleteLater); - } - - // run the task - task->run(); - } catch (const std::exception& e) { - SPDLOG_ERROR("task runner: exception in task {}, exception: {}", - task->GetFullID(), e.what()); - // if any exception caught, destroy the task, remove the task from the - // pending tasks - unregister_finished_task(task->GetUUID()); - } catch (...) { - SPDLOG_ERROR("task runner: unknown exception in task: {}", - task->GetFullID()); - // if any exception caught, destroy the task, remove the task from the - // pending tasks - unregister_finished_task(task->GetUUID()); - } - } + void PostConcurrentTask(Task* task) { + if (task == nullptr) { + GF_CORE_LOG_ERROR("task posted is null"); + return; } + + auto* concurrent_thread = new QThread(this); + + task->setParent(nullptr); + task->moveToThread(concurrent_thread); + + connect(task, &Task::SignalTaskEnd, concurrent_thread, &QThread::quit); + connect(concurrent_thread, &QThread::finished, concurrent_thread, + &QThread::deleteLater); + + concurrent_thread->start(); + + GF_CORE_LOG_TRACE("runner starts task concurrenctly: {}", + task->GetFullID()); + task->SafelyRun(); } -} -/** - * @brief - * - */ -void GpgFrontend::Thread::TaskRunner::unregister_finished_task( - std::string task_uuid) { - SPDLOG_DEBUG("cleaning task {}", task_uuid); - // search in map - auto pending_task = pending_tasks_.find(task_uuid); - if (pending_task == pending_tasks_.end()) { - SPDLOG_ERROR("cannot find task in pending list: {}", task_uuid); - return; - } else { - std::lock_guard<std::mutex> lock(tasks_mutex_); - // if thread runs sequenctly, that means the thread is living in this - // thread, so we can delete it. Or, its living thread need to delete it. - if (pending_task->second->GetSequency()) - pending_task->second->deleteLater(); - pending_tasks_.erase(pending_task); + void PostScheduleTask(Task* task, size_t seconds) { + if (task == nullptr) return; + // TODO } - SPDLOG_DEBUG("clean task {} done", task_uuid); + private: + QMap<QString, Task*> pending_tasks_; +}; + +TaskRunner::TaskRunner() : p_(SecureCreateUniqueObject<Impl>()) {} + +TaskRunner::~TaskRunner() { + if (p_->isRunning()) { + Stop(); + } +} + +void TaskRunner::PostTask(Task* task) { p_->PostTask(task); } + +void TaskRunner::PostTask(const QString& name, const Task::TaskRunnable& runner, + const Task::TaskCallback& cb, DataObjectPtr params) { + p_->PostTask(name, runner, cb, std::move(params)); +} + +void TaskRunner::PostConcurrentTask(Task* task) { + p_->PostConcurrentTask(task); +} + +void TaskRunner::PostScheduleTask(Task* task, size_t seconds) { + p_->PostScheduleTask(task, seconds); +} + +void TaskRunner::Start() { p_->start(); } + +void TaskRunner::Stop() { + p_->quit(); + p_->wait(); +} + +auto TaskRunner::GetThread() -> QThread* { return p_.get(); } + +auto TaskRunner::IsRunning() -> bool { return p_->isRunning(); } + +auto TaskRunner::RegisterTask(const QString& name, + const Task::TaskRunnable& runnable, + const Task::TaskCallback& cb, DataObjectPtr p_pbj) + -> Task::TaskHandler { + return p_->RegisterTask(name, runnable, cb, p_pbj); } +} // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h index 35cd1a30..8a93ad0b 100644 --- a/src/core/thread/TaskRunner.h +++ b/src/core/thread/TaskRunner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,25 +19,22 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_TASKRUNNER_H -#define GPGFRONTEND_TASKRUNNER_H - -#include <cstddef> -#include <mutex> -#include <queue> +#pragma once #include "core/GpgFrontendCore.h" +#include "core/function/SecureMemoryAllocator.h" +#include "core/thread/Task.h" namespace GpgFrontend::Thread { -class Task; - -class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { +class GPGFRONTEND_CORE_EXPORT TaskRunner : public QObject { Q_OBJECT public: /** @@ -50,13 +47,34 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { * @brief Destroy the Task Runner object * */ - virtual ~TaskRunner() override; + ~TaskRunner() override; + + /** + * @brief + * + */ + void Start(); /** * @brief * */ - [[noreturn]] void run() override; + void Stop(); + + /** + * @brief Get the Thread object + * + * @return QThread* + */ + auto GetThread() -> QThread*; + + /** + * @brief + * + * @return true + * @return false + */ + auto IsRunning() -> bool; public slots: @@ -70,23 +88,38 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { /** * @brief * - * @param task - * @param seconds + * @param runner + * @param cb */ - void PostScheduleTask(Task* task, size_t seconds); + void PostTask(const QString&, const Task::TaskRunnable&, + const Task::TaskCallback&, DataObjectPtr); - private: - std::queue<Task*> tasks; ///< The task queue - std::map<std::string, Task*> pending_tasks_; ///< The pending tasks - std::mutex tasks_mutex_; ///< The task queue mutex - QThreadPool thread_pool_{this}; ///< run non-sequency task + /** + * @brief + * + * @return std::tuple<QPointer<Task>, TaskTrigger> + */ + auto RegisterTask(const QString&, const Task::TaskRunnable&, + const Task::TaskCallback&, DataObjectPtr) + -> Task::TaskHandler; + + /** + * @brief + * + * @param task + */ + void PostConcurrentTask(Task* task); /** * @brief * + * @param task + * @param seconds */ - void unregister_finished_task(std::string); + void PostScheduleTask(Task* task, size_t seconds); + + private: + class Impl; + SecureUniquePtr<Impl> p_; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASKRUNNER_H
\ No newline at end of file diff --git a/src/core/thread/TaskRunnerGetter.cpp b/src/core/thread/TaskRunnerGetter.cpp index 186483ec..bdcd89d0 100644 --- a/src/core/thread/TaskRunnerGetter.cpp +++ b/src/core/thread/TaskRunnerGetter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,28 +19,46 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "core/thread/TaskRunnerGetter.h" -GpgFrontend::Thread::TaskRunnerGetter::TaskRunnerGetter(int channel) - : SingletonFunctionObject<TaskRunnerGetter>(channel) {} +#include <mutex> + +#include "core/GpgConstants.h" +#include "core/thread/TaskRunner.h" + +namespace GpgFrontend::Thread { -GpgFrontend::Thread::TaskRunner* -GpgFrontend::Thread::TaskRunnerGetter::GetTaskRunner( - TaskRunnerType runner_type) { +TaskRunnerGetter::TaskRunnerGetter(int) + : SingletonFunctionObject<TaskRunnerGetter>(kGpgFrontendDefaultChannel) {} + +auto TaskRunnerGetter::GetTaskRunner(TaskRunnerType runner_type) + -> TaskRunnerPtr { + std::lock_guard<std::mutex> lock_guard(task_runners_map_lock_); while (true) { auto it = task_runners_.find(runner_type); if (it != task_runners_.end()) { return it->second; - } else { - auto runner = new TaskRunner(); - task_runners_[runner_type] = runner; - runner->start(); - continue; + } + + auto runner = GpgFrontend::SecureCreateSharedObject<TaskRunner>(); + task_runners_[runner_type] = runner; + runner->Start(); + } +} + +void TaskRunnerGetter::StopAllTeakRunner() { + for (const auto& [key, value] : task_runners_) { + if (value->IsRunning()) { + value->Stop(); } } } + +} // namespace GpgFrontend::Thread
\ No newline at end of file diff --git a/src/core/thread/TaskRunnerGetter.h b/src/core/thread/TaskRunnerGetter.h index 80b25c3e..49ed25c0 100644 --- a/src/core/thread/TaskRunnerGetter.h +++ b/src/core/thread/TaskRunnerGetter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,20 +19,25 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_TASKRUNNERGETTER_H -#define GPGFRONTEND_TASKRUNNERGETTER_H +#pragma once + +#include <mutex> #include "core/GpgFrontendCore.h" -#include "core/GpgFunctionObject.h" +#include "core/function/basic/GpgFunctionObject.h" #include "core/thread/TaskRunner.h" namespace GpgFrontend::Thread { +using TaskRunnerPtr = std::shared_ptr<TaskRunner>; + class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter : public GpgFrontend::SingletonFunctionObject<TaskRunnerGetter> { public: @@ -41,18 +46,21 @@ class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter kTaskRunnerType_GPG, kTaskRunnerType_IO, kTaskRunnerType_Network, + kTaskRunnerType_Module, kTaskRunnerType_External_Process, }; - TaskRunnerGetter(int channel = SingletonFunctionObject::GetDefaultChannel()); + explicit TaskRunnerGetter( + int channel = SingletonFunctionObject::GetDefaultChannel()); - TaskRunner *GetTaskRunner( - TaskRunnerType runner_type = kTaskRunnerType_Default); + auto GetTaskRunner(TaskRunnerType runner_type = kTaskRunnerType_Default) + -> TaskRunnerPtr; + + void StopAllTeakRunner(); private: - std::map<TaskRunnerType, TaskRunner *> task_runners_; + std::map<TaskRunnerType, TaskRunnerPtr> task_runners_; + std::mutex task_runners_map_lock_; }; } // namespace GpgFrontend::Thread - -#endif // GPGFRONTEND_TASKRUNNERGETTER_H
\ No newline at end of file diff --git a/src/core/thread/ThreadingModel.h b/src/core/thread/ThreadingModel.h index eb6c9039..2fcc11c8 100644 --- a/src/core/thread/ThreadingModel.h +++ b/src/core/thread/ThreadingModel.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,14 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_THREADINGMODEL_H -#define GPGFRONTEND_THREADINGMODEL_H +#pragma once #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" - -#endif // GPGFRONTEND_THREADINGMODEL_H
\ No newline at end of file diff --git a/src/core/typedef/CoreTypedef.h b/src/core/typedef/CoreTypedef.h new file mode 100644 index 00000000..51c6d11a --- /dev/null +++ b/src/core/typedef/CoreTypedef.h @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/model/DataObject.h" + +namespace GpgFrontend { + +using GFError = uint32_t; +using ByteArray = QByteArray; ///< +using ByteArrayPtr = std::shared_ptr<ByteArray>; ///< +using StdBypeArrayPtr = std::shared_ptr<ByteArray>; ///< +using BypeArrayRef = ByteArray&; ///< +using ConstBypeArrayRef = const ByteArray&; ///< +using BypeArrayConstRef = const ByteArray&; ///< +using StringArgsPtr = std::unique_ptr<std::vector<QString>>; ///< +using StringArgsRef = std::vector<QString>&; ///< + /// + /// + +using OperaRunnable = std::function<GFError(DataObjectPtr)>; +using OperationCallback = std::function<void(GFError, DataObjectPtr)>; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/typedef/GpgTypedef.h b/src/core/typedef/GpgTypedef.h new file mode 100644 index 00000000..cf0887bf --- /dev/null +++ b/src/core/typedef/GpgTypedef.h @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <tuple> + +#include "core/model/DataObject.h" + +namespace GpgFrontend { + +class GpgKey; ///< forward declaration +class GpgSubKey; +class GpgSignature; +class GpgTOFUInfo; + +using GpgError = gpgme_error_t; ///< gpgme error +using GpgErrorCode = gpg_err_code_t; +using GpgErrorDesc = std::pair<QString, QString>; + +using KeyId = QString; ///< +using SubkeyId = QString; ///< +using KeyIdArgsList = std::vector<KeyId>; ///< +using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>; ///< +using UIDArgsList = std::vector<QString>; ///< +using UIDArgsListPtr = std::unique_ptr<UIDArgsList>; ///< +using SignIdArgsList = std::vector<std::pair<QString, QString>>; ///< +using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>; ///< +using KeyFprArgsListPtr = std::unique_ptr<std::vector<QString>>; ///< +using KeyArgsList = std::vector<GpgKey>; ///< +using KeyListPtr = std::shared_ptr<KeyArgsList>; ///< +using GpgKeyLinkList = std::list<GpgKey>; ///< +using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>; ///< +using KeyPtr = std::unique_ptr<GpgKey>; ///< +using KeyPtrArgsList = const std::initializer_list<KeyPtr>; ///< + +using GpgSignMode = gpgme_sig_mode_t; + +using GpgOperaRunnable = std::function<GpgError(DataObjectPtr)>; +using GpgOperationCallback = std::function<void(GpgError, DataObjectPtr)>; +using GpgOperationFuture = std::future<std::tuple<GpgError, DataObjectPtr>>; + +enum GpgOperation { + kENCRYPT, + kDECRYPT, + kSIGN, + kVERIFY, + kENCRYPT_SIGN, + kDECRYPT_VERIFY +}; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.cpp b/src/core/utils/AsyncUtils.cpp new file mode 100644 index 00000000..6100b83d --- /dev/null +++ b/src/core/utils/AsyncUtils.cpp @@ -0,0 +1,103 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "AsyncUtils.h" + +#include "core/module/ModuleManager.h" +#include "core/thread/Task.h" +#include "core/thread/TaskRunnerGetter.h" +#include "core/utils/CommonUtils.h" +#include "model/DataObject.h" + +namespace GpgFrontend { + +auto RunGpgOperaAsync(GpgOperaRunnable runnable, GpgOperationCallback callback, + const QString& operation, const QString& minial_version) + -> Thread::Task::TaskHandler { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", minial_version); + GF_CORE_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); + + if (CompareSoftwareVersion(gnupg_version, "2.0.15") < 0) { + GF_CORE_LOG_ERROR("operator not support"); + callback(GPG_ERR_NOT_SUPPORTED, TransferParams()); + return Thread::Task::TaskHandler(nullptr); + } + + auto handler = + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->RegisterTask( + operation, + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + auto err = runnable(custom_data_object); + data_object->Swap({err, custom_data_object}); + return 0; + }, + [=](int rtn, const DataObjectPtr& data_object) { + if (rtn < 0) { + callback(GPG_ERR_USER_1, + ExtractParams<DataObjectPtr>(data_object, 1)); + } else { + callback(ExtractParams<GpgError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + } + }, + TransferParams()); + handler.Start(); + return handler; +} + +auto RunIOOperaAsync(OperaRunnable runnable, OperationCallback callback, + const QString& operation) -> Thread::Task::TaskHandler { + auto handler = + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_IO) + ->RegisterTask( + operation, + [=](const DataObjectPtr& data_object) -> int { + auto custom_data_object = TransferParams(); + GpgError err = runnable(custom_data_object); + + data_object->Swap({err, custom_data_object}); + return 0; + }, + [=](int rtn, const DataObjectPtr& data_object) { + if (rtn < 0) { + callback(-1, ExtractParams<DataObjectPtr>(data_object, 1)); + } else { + callback(ExtractParams<GFError>(data_object, 0), + ExtractParams<DataObjectPtr>(data_object, 1)); + } + }, + TransferParams()); + handler.Start(); + return handler; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/AsyncUtils.h b/src/core/utils/AsyncUtils.h new file mode 100644 index 00000000..e587fad2 --- /dev/null +++ b/src/core/utils/AsyncUtils.h @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCore.h" +#include "core/thread/Task.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + * @param minial_version + */ +auto GPGFRONTEND_CORE_EXPORT RunGpgOperaAsync(GpgOperaRunnable runnable, + GpgOperationCallback callback, + const QString& operation, + const QString& minial_version) + -> Thread::Task::TaskHandler; + +/** + * @brief + * + * @param runnable + * @param callback + * @param operation + */ +auto GPGFRONTEND_CORE_EXPORT RunIOOperaAsync(OperaRunnable runnable, + OperationCallback callback, + const QString& operation) + -> Thread::Task::TaskHandler; +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CacheUtils.cpp b/src/core/utils/CacheUtils.cpp new file mode 100644 index 00000000..e521870c --- /dev/null +++ b/src/core/utils/CacheUtils.cpp @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "CacheUtils.h" + +#include "core/function/CacheManager.h" + +namespace GpgFrontend { + +void SetCacheValue(const QString& key, QString value) { + CacheManager::GetInstance().SaveCache(key, std::move(value)); +} + +auto GetCacheValue(const QString& key) -> QString { + return CacheManager::GetInstance().LoadCache(key); +} + +void ResetCacheValue(const QString& key) { + CacheManager::GetInstance().ResetCache(key); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CacheUtils.h b/src/core/utils/CacheUtils.h new file mode 100644 index 00000000..48b9ac4b --- /dev/null +++ b/src/core/utils/CacheUtils.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +/** + * @brief set a temp cache under a certain key + * + */ +void GPGFRONTEND_CORE_EXPORT SetCacheValue(const QString &key, QString value); + +/** + * @brief after get the temp cache, its value will be imediately ease in + * storage + * + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetCacheValue(const QString &key) -> QString; + +/** + * @brief imediately ease temp cache in storage + * + * @return QString + */ +void GPGFRONTEND_CORE_EXPORT ResetCacheValue(const QString &); + +} // namespace GpgFrontend diff --git a/src/core/utils/CommonUtils.cpp b/src/core/utils/CommonUtils.cpp new file mode 100644 index 00000000..0b182241 --- /dev/null +++ b/src/core/utils/CommonUtils.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "CommonUtils.h" + +namespace GpgFrontend { + +auto BeautifyFingerprint(QString fingerprint) -> QString { + auto len = fingerprint.size(); + QString buffer; + QTextStream out(&buffer); + decltype(len) count = 0; + while (count < len) { + if ((count != 0U) && ((count % 5) == 0)) out << " "; + out << fingerprint[count]; + count++; + } + return out.readAll(); +} + +auto CompareSoftwareVersion(const QString& a, const QString& b) -> int { + auto remove_prefix = [](const QString& version) { + return version.startsWith('v') ? version.mid(1) : version; + }; + + auto real_version_a = remove_prefix(a); + auto real_version_b = remove_prefix(b); + + QStringList split_a = real_version_a.split('.'); + QStringList split_b = real_version_b.split('.'); + + const auto min_depth = std::min(split_a.size(), split_b.size()); + + for (int i = 0; i < min_depth; ++i) { + int const num_a = split_a[i].toInt(); + int const num_b = split_b[i].toInt(); + + if (num_a != num_b) { + return (num_a > num_b) ? 1 : -1; + } + } + + if (split_a.size() != split_b.size()) { + return (split_a.size() > split_b.size()) ? 1 : -1; + } + + return 0; +} +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CommonUtils.h b/src/core/utils/CommonUtils.h new file mode 100644 index 00000000..a45c6056 --- /dev/null +++ b/src/core/utils/CommonUtils.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/typedef/CoreTypedef.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param fingerprint + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT BeautifyFingerprint(QString fingerprint) + -> QString; + +/** + * @brief + * + * @param a + * @param b + * @return int + */ +auto GPGFRONTEND_CORE_EXPORT CompareSoftwareVersion(const QString& a, + const QString& b) -> int; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/FilesystemUtils.cpp b/src/core/utils/FilesystemUtils.cpp new file mode 100644 index 00000000..9e531955 --- /dev/null +++ b/src/core/utils/FilesystemUtils.cpp @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "FilesystemUtils.h" + +namespace GpgFrontend { + +auto GetOnlyFileNameWithPath(const QString &path) -> QString { + // Create a path object from given string + QFileInfo file_info(path); + // Check if file name in the path object has extension + if (!file_info.fileName().isEmpty()) { + // Fetch the extension from path object and return + return file_info.path() + "/" + file_info.baseName(); + } + // In case of no extension return empty string + return {}; +} + +auto GetFileExtension(const QString &path) -> QString { + return QFileInfo(path).suffix(); +} + +/** + * @brief + * + */ +auto GetFileSizeByPath(const QString &path, const QString &filename_pattern) + -> int64_t { + auto dir = QDir(path); + QFileInfoList const file_list = + dir.entryInfoList(QStringList() << filename_pattern, QDir::Files); + qint64 total_size = 0; + + for (const QFileInfo &file_info : file_list) { + total_size += file_info.size(); + } + return total_size; +} + +/** + * @brief + * + */ +auto GetHumanFriendlyFileSize(int64_t size) -> QString { + auto num = static_cast<double>(size); + QStringList list; + list << "KB" + << "MB" + << "GB" + << "TB"; + + QStringListIterator i(list); + QString unit("bytes"); + + while (num >= 1024.0 && i.hasNext()) { + unit = i.next(); + num /= 1024.0; + } + return (QString().setNum(num, 'f', 2) + " " + unit); +} + +/** + * @brief + * + */ +void DeleteAllFilesByPattern(const QString &path, + const QString &filename_pattern) { + auto dir = QDir(path); + + QStringList const log_files = + dir.entryList(QStringList() << filename_pattern, QDir::Files); + + for (const auto &file : log_files) { + QFile::remove(dir.absoluteFilePath(file)); + } +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/FilesystemUtils.h b/src/core/utils/FilesystemUtils.h new file mode 100644 index 00000000..0b58bbb7 --- /dev/null +++ b/src/core/utils/FilesystemUtils.h @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +/** + * @brief Get the file extension object + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetFileExtension(const QString& path) -> QString; + +/** + * @brief Get the only file name with path object + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetOnlyFileNameWithPath(const QString& path) + -> QString; + +/** + * @brief Get the File Size By Path object + * + * @param path The path of the file + * @param filename_pattern The pattern of the file name, e.g. "*.txt" + * @return int64_t + */ +auto GPGFRONTEND_CORE_EXPORT GetFileSizeByPath( + const QString& path, const QString& filename_pattern) + -> int64_t; + +/** + * @brief Get the Human Readable File Size object + * + * @param size + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetHumanFriendlyFileSize(int64_t size) -> QString; + +/** + * @brief + * + * @param path + * @param filename_pattern + */ +void GPGFRONTEND_CORE_EXPORT DeleteAllFilesByPattern( + const QString& path, const QString& filename_pattern); + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/GpgUtils.cpp b/src/core/utils/GpgUtils.cpp new file mode 100644 index 00000000..75a412e7 --- /dev/null +++ b/src/core/utils/GpgUtils.cpp @@ -0,0 +1,172 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgUtils.h" + +namespace GpgFrontend { + +inline auto Trim(QString& s) -> QString { return s.trimmed(); } + +auto GetGpgmeErrorString(size_t buffer_size, gpgme_error_t err) -> QString { + std::vector<char> buffer(buffer_size); + + gpgme_error_t const ret = gpgme_strerror_r(err, buffer.data(), buffer.size()); + if (ret == ERANGE && buffer_size < 1024) { + return GetGpgmeErrorString(buffer_size * 2, err); + } + + return {buffer.data()}; +} + +auto GetGpgmeErrorString(gpgme_error_t err) -> QString { + return GetGpgmeErrorString(64, err); +} + +auto CheckGpgError(GpgError err) -> GpgError { + auto err_code = gpg_err_code(err); + if (err_code != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_ERROR( + "gpg operation failed [error code: {}], source: {} description: {}", + err_code, gpgme_strsource(err), GetGpgmeErrorString(err)); + } + return err_code; +} + +auto CheckGpgError2ErrCode(GpgError err, GpgError predict) -> GpgErrorCode { + auto err_code = gpg_err_code(err); + if (err_code != gpg_err_code(predict)) { + if (err_code == GPG_ERR_NO_ERROR) { + GF_CORE_LOG_WARN("[Warning {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), + GetGpgmeErrorString(err), GetGpgmeErrorString(predict)); + } else { + GF_CORE_LOG_ERROR("[Error {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), + GetGpgmeErrorString(err), GetGpgmeErrorString(predict)); + } + } + return err_code; +} + +auto DescribeGpgErrCode(GpgError err) -> GpgErrorDesc { + return {gpgme_strsource(err), GetGpgmeErrorString(err)}; +} + +auto CheckGpgError(GpgError err, const QString& /*comment*/) -> GpgError { + if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { + GF_CORE_LOG_WARN("[Error {}] Source: {} description: {}", gpg_err_code(err), + gpgme_strsource(err), GetGpgmeErrorString(err)); + } + return err; +} + +auto TextIsSigned(QString text) -> int { + auto trim_text = Trim(text); + if (trim_text.startsWith(PGP_SIGNED_BEGIN) && + trim_text.endsWith(PGP_SIGNED_END)) { + return 2; + } + if (text.contains(PGP_SIGNED_BEGIN) && text.contains(PGP_SIGNED_END)) { + return 1; + } + return 0; +} + +auto SetExtensionOfOutputFile(const QString& path, GpgOperation opera, + bool ascii) -> QString { + QString new_extension; + QString current_extension = QFileInfo(path).suffix(); + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kSIGN: + case kENCRYPT_SIGN: + new_extension = current_extension + ".asc"; + break; + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + new_extension = current_extension + ".gpg"; + break; + case kSIGN: + new_extension = current_extension + ".sig"; + break; + default: + break; + } + } + + if (!new_extension.isEmpty()) { + return QFileInfo(path).path() + "/" + QFileInfo(path).completeBaseName() + + "." + new_extension; + } + + return path; +} + +auto SetExtensionOfOutputFileForArchive(const QString& path, GpgOperation opera, + bool ascii) -> QString { + QString extension; + + if (ascii) { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension = ".tar.asc"; + break; + default: + break; + } + } else { + switch (opera) { + case kENCRYPT: + case kENCRYPT_SIGN: + extension = ".tar.gpg"; + break; + default: + break; + } + } + + if (!extension.isEmpty()) { + auto last_dot_index = path.lastIndexOf('.'); + if (last_dot_index != -1) { + return path.left(last_dot_index) + extension; + } + return path + extension; + } + + return path; // 如果没有匹配的操作,则返回原始路径 +} + +} // namespace GpgFrontend diff --git a/src/core/utils/GpgUtils.h b/src/core/utils/GpgUtils.h new file mode 100644 index 00000000..e6a466dc --- /dev/null +++ b/src/core/utils/GpgUtils.h @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/typedef/CoreTypedef.h" +#include "core/typedef/GpgTypedef.h" + +namespace GpgFrontend { + +// Error Info Printer + +/** + * @brief + * + * @param err + * @return GpgError + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError(GpgError err) -> GpgError; + +/** + * @brief + * + * @param gpgmeError + * @param comment + * @return GpgError + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError(GpgError gpgmeError, + const QString& comment) -> GpgError; + +/** + * @brief + * + * @param err + * @param predict + * @return gpg_err_code_t + */ +auto GPGFRONTEND_CORE_EXPORT CheckGpgError2ErrCode( + gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR) + -> gpg_err_code_t; + +/** + * @brief + * + * @param err + * @return GpgErrorDesc + */ +auto GPGFRONTEND_CORE_EXPORT DescribeGpgErrCode(GpgError err) -> GpgErrorDesc; + +// Check + +/** + * @brief + * + * @param text + * @return int + */ +auto GPGFRONTEND_CORE_EXPORT TextIsSigned(BypeArrayRef text) -> int; + +/** + * @brief + * + * @param opera + * @param ascii + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFile(const QString& path, + GpgOperation opera, + bool ascii) -> QString; + +/** + * @brief + * + * @param path + * @param opera + * @param ascii + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT SetExtensionOfOutputFileForArchive( + const QString& path, GpgOperation opera, bool ascii) -> QString; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.cpp b/src/core/utils/IOUtils.cpp new file mode 100644 index 00000000..5ca765d9 --- /dev/null +++ b/src/core/utils/IOUtils.cpp @@ -0,0 +1,162 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "IOUtils.h" + +#include "core/GpgModel.h" + +namespace GpgFrontend { + +auto ReadFile(const QString& file_name, QByteArray& data) -> bool { + QFile file(file_name); + if (!file.open(QIODevice::ReadOnly)) { + GF_CORE_LOG_ERROR("failed to open file: {}", file_name); + return false; + } + data = file.readAll(); + file.close(); + return true; +} + +auto WriteFile(const QString& file_name, const QByteArray& data) -> bool { + QFile file(file_name); + if (!file.open(QIODevice::WriteOnly)) { + GF_CORE_LOG_ERROR("failed to open file for writing: {}", file_name); + return false; + } + file.write(data); + file.close(); + return true; +} + +auto ReadFileGFBuffer(const QString& file_name) -> std::tuple<bool, GFBuffer> { + QByteArray byte_data; + const bool res = ReadFile(file_name, byte_data); + + return {res, GFBuffer(byte_data)}; +} + +auto WriteFileGFBuffer(const QString& file_name, GFBuffer data) -> bool { + return WriteFile(file_name, data.ConvertToQByteArray()); +} + +auto CalculateHash(const QString& file_path) -> QString { + // Returns empty QByteArray() on failure. + QFileInfo const info(file_path); + QString buffer; + QTextStream ss(&buffer); + + if (info.isFile() && info.isReadable()) { + ss << "[#] " << QObject::tr("File Hash Information") << Qt::endl; + ss << " " << QObject::tr("filename") << QObject::tr(": ") + << info.fileName() << Qt::endl; + + QFile f(info.filePath()); + if (f.open(QFile::ReadOnly)) { + // read all data + auto buffer = f.readAll(); + ss << " " << QObject::tr("file size(bytes)") << QObject::tr(": ") + << buffer.size() << Qt::endl; + + // md5 + auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); + hash_md5.addData(buffer); + auto md5 = hash_md5.result().toHex(); + GF_CORE_LOG_DEBUG("md5 {}", md5); + ss << " " + << "md5" << QObject::tr(": ") << md5 << Qt::endl; + + // sha1 + auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); + hash_sha1.addData(buffer); + auto sha1 = hash_sha1.result().toHex(); + GF_CORE_LOG_DEBUG("sha1 {}", sha1); + ss << " " + << "sha1" << QObject::tr(": ") << sha1 << Qt::endl; + + // sha1 + auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); + hash_sha256.addData(buffer); + auto sha256 = hash_sha256.result().toHex(); + GF_CORE_LOG_DEBUG("sha256 {}", sha256); + ss << " " + << "sha256" << QObject::tr(": ") << sha256 << Qt::endl; + + ss << Qt::endl; + } + } else { + ss << "[#] " << QObject::tr("Error in Calculating File Hash ") << Qt::endl; + } + + return ss.readAll(); +} + +auto GetTempFilePath() -> QString { + QString const temp_dir = QDir::tempPath(); + QString const filename = QUuid::createUuid().toString() + ".data"; + return temp_dir + "/" + filename; +} + +auto CreateTempFileAndWriteData(const QString& data) -> QString { + auto temp_file = GetTempFilePath(); + WriteFile(temp_file, data.toUtf8()); + return temp_file; +} + +auto TargetFilePreCheck(const QString& path, bool read) + -> std::tuple<bool, QString> { + QFileInfo const file_info(path); + + if (read) { + if (!file_info.exists()) { + return {false, QObject::tr("target path doesn't exists")}; + } + } else { + QFileInfo const path_info(file_info.absolutePath()); + if (!path_info.isWritable()) { + return {false, QObject::tr("do NOT have permission to write path")}; + } + } + + if (read ? !file_info.isReadable() : false) { + return {false, QObject::tr("do NOT have permission to read/write file")}; + } + + return {true, QObject::tr("Success")}; +} + +auto GetFullExtension(const QString& path) -> QString { + QString const filename = QFileInfo(path).fileName(); + + auto const dot_index = filename.indexOf('.'); + if (dot_index == -1) return {}; + + return filename.mid(dot_index); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/IOUtils.h b/src/core/utils/IOUtils.h new file mode 100644 index 00000000..42c663c3 --- /dev/null +++ b/src/core/utils/IOUtils.h @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/model/GFBuffer.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param file_name + * @return GFBuffer + */ +auto GPGFRONTEND_CORE_EXPORT ReadFileGFBuffer(const QString &file_name) + -> std::tuple<bool, GFBuffer>; + +/** + * @brief + * + * @param file_name + * @param data + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT WriteFileGFBuffer(const QString &file_name, + GFBuffer data) -> bool; + +/** + * @brief read file content + * + * @param file_name file name + * @param data data read from file + * @return true if success + * @return false if failed + */ +auto GPGFRONTEND_CORE_EXPORT ReadFile(const QString &file_name, + QByteArray &data) -> bool; + +/** + * @brief write file content + * + * @param file_name file name + * @param data data to write to file + * @return true if success + * @return false if failed + */ +auto GPGFRONTEND_CORE_EXPORT WriteFile(const QString &file_name, + const QByteArray &data) -> bool; + +/** + * calculate the hash of a file + * @param file_path + * @return + */ +auto GPGFRONTEND_CORE_EXPORT CalculateHash(const QString &file_path) -> QString; + +/** + * @brief + * + * @param path + * @param out_buffer + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT WriteBufferToFile(const QString &path, + const QString &out_buffer) + -> bool; + +/** + * @brief + * + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetTempFilePath() -> QString; + +/** + * @brief + * + * @param data + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT CreateTempFileAndWriteData(const QString &data) + -> QString; + +/** + * @brief + * + * @param path + * @param read + * @return std::tuple<bool, QString> + */ +auto GPGFRONTEND_CORE_EXPORT TargetFilePreCheck(const QString &path, bool read) + -> std::tuple<bool, QString>; + +/** + * @brief + * + * @param path + * @return QString + */ +auto GPGFRONTEND_CORE_EXPORT GetFullExtension(QString path) -> QString; + +} // namespace GpgFrontend diff --git a/src/core/function/CharsetOperator.h b/src/core/utils/LocalizedUtils.cpp index 41ce62f4..b8c91039 100644 --- a/src/core/function/CharsetOperator.h +++ b/src/core/utils/LocalizedUtils.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,28 +20,19 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_CHARSETDETECTOR_H -#define GPGFRONTEND_CHARSETDETECTOR_H +#include "LocalizedUtils.h" -#include "core/GpgFrontendCore.h" +#include "core/utils/LogUtils.h" namespace GpgFrontend { -class GPGFRONTEND_CORE_EXPORT CharsetOperator { - public: - using CharsetInfo = std::tuple<std::string, std::string, int>; - - static CharsetInfo Detect(const std::string &buffer); - - static bool Convert2Utf8(const std::string &buffer, std::string &out_buffer, - std::string from_charset_name); -}; +auto GetFormatedDateByTimestamp(time_t timestamp) -> QString { + return QLocale::system().toString(QDateTime::fromSecsSinceEpoch(timestamp)); +} } // namespace GpgFrontend - -#endif // GPGFRONTEND_CHARSETDETECTOR_H diff --git a/src/core/utils/LocalizedUtils.h b/src/core/utils/LocalizedUtils.h new file mode 100644 index 00000000..d7aaf0c8 --- /dev/null +++ b/src/core/utils/LocalizedUtils.h @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +auto GPGFRONTEND_CORE_EXPORT GetFormatedDateByTimestamp(time_t) -> QString; + +}
\ No newline at end of file diff --git a/src/core/utils/LogUtils.cpp b/src/core/utils/LogUtils.cpp new file mode 100644 index 00000000..fbf0c8d3 --- /dev/null +++ b/src/core/utils/LogUtils.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "LogUtils.h" + +#include "core/function/LoggerManager.h" + +namespace GpgFrontend { + +auto GetDefaultLogger() -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetDefaultLogger(); +} + +auto GetCoreLogger() -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetInstance().GetLogger("core"); +} + +auto GetLogger(const QString& id) -> std::shared_ptr<spdlog::logger> { + return LoggerManager::GetInstance().GetLogger(id); +} + +void SetDefaultLogLevel(spdlog::level::level_enum level) { + return LoggerManager::SetDefaultLogLevel(level); +} + +void RegisterAsyncLogger(const QString& id, spdlog::level::level_enum level) { + LoggerManager::GetInstance().RegisterAsyncLogger(id, level); +} + +void RegisterSyncLogger(const QString& id, spdlog::level::level_enum level) { + LoggerManager::GetInstance().RegisterSyncLogger(id, level); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/LogUtils.h b/src/core/utils/LogUtils.h new file mode 100644 index 00000000..d838e830 --- /dev/null +++ b/src/core/utils/LogUtils.h @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend { + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetDefaultLogger() + -> std::shared_ptr<spdlog::logger>; + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetCoreLogger() -> std::shared_ptr<spdlog::logger>; + +/** + * @brief + * + * @return std::shared_ptr<spdlog::logger> + */ +auto GPGFRONTEND_CORE_EXPORT GetLogger(const QString &) + -> std::shared_ptr<spdlog::logger>; + +/** + * @brief Set the Default Log Level object + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT SetDefaultLogLevel(spdlog::level::level_enum); + +/** + * @brief + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT RegisterAsyncLogger(const QString &, + spdlog::level::level_enum); + +/** + * @brief + * + * @return auto + */ +void GPGFRONTEND_CORE_EXPORT RegisterSyncLogger(const QString &, + spdlog::level::level_enum); + +} // namespace GpgFrontend + +#define GF_DEFAULT_LOG_TRACE(...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_DEBUG(...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_INFO(...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_WARN(...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) +#define GF_DEFAULT_LOG_ERROR(...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetDefaultLogger(), __VA_ARGS__) + +#define GF_CORE_LOG_TRACE(...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_DEBUG(...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_INFO(...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_WARN(...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetCoreLogger(), __VA_ARGS__) +#define GF_CORE_LOG_ERROR(...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetCoreLogger(), __VA_ARGS__) + +#define GF_LOG_TRACE(ID, ...) \ + SPDLOG_LOGGER_TRACE(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_DEBUG(ID, ...) \ + SPDLOG_LOGGER_DEBUG(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_INFO(ID, ...) \ + SPDLOG_LOGGER_INFO(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_WARN(ID, ...) \ + SPDLOG_LOGGER_WARN(GpgFrontend::GetLogger(ID), __VA_ARGS__) +#define GF_LOG_ERROR(ID, ...) \ + SPDLOG_LOGGER_ERROR(GpgFrontend::GetLogger(ID), __VA_ARGS__)
\ No newline at end of file diff --git a/src/core/utils/MemoryUtils.cpp b/src/core/utils/MemoryUtils.cpp new file mode 100644 index 00000000..f002fd87 --- /dev/null +++ b/src/core/utils/MemoryUtils.cpp @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "MemoryUtils.h" + +namespace GpgFrontend { + +auto SecureMalloc(std::size_t size) -> void * { + return SecureMemoryAllocator::Allocate(size); +} + +auto SecureRealloc(void *ptr, std::size_t size) -> void * { + return SecureMemoryAllocator::Reallocate(ptr, size); +} + +void SecureFree(void *ptr) { SecureMemoryAllocator::Deallocate(ptr); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/MemoryUtils.h b/src/core/utils/MemoryUtils.h new file mode 100644 index 00000000..76c75fc6 --- /dev/null +++ b/src/core/utils/MemoryUtils.h @@ -0,0 +1,179 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/function/SecureMemoryAllocator.h" + +/* To avoid that a compiler optimizes certain memset calls away, these + macros may be used instead. */ +#define wipememory2(_ptr, _set, _len) \ + do { \ + volatile char *_vptr = (volatile char *)(_ptr); \ + size_t _vlen = (_len); \ + while (_vlen) { \ + *_vptr = (_set); \ + _vptr++; \ + _vlen--; \ + } \ + } while (0) +#define wipememory(_ptr, _len) wipememory2(_ptr, 0, _len) +#define wipe(_ptr, _len) wipememory2(_ptr, 0, _len) + +#define xtoi_1(p) \ + (*(p) <= '9' ? (*(p) - '0') \ + : *(p) <= 'F' ? (*(p) - 'A' + 10) \ + : (*(p) - 'a' + 10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p) + 1)) + +namespace GpgFrontend { + +template <typename T> +class PointerConverter { + public: + explicit PointerConverter(void *ptr) : ptr_(ptr) {} + + auto AsType() const -> T * { return static_cast<T *>(ptr_); } + + private: + void *ptr_; +}; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureMalloc(std::size_t) -> void *; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureRealloc(void *, std::size_t) -> void *; + +/** + * @brief + * + * @tparam T + * @return T* + */ +template <typename T> +auto SecureMallocAsType(std::size_t size) -> T * { + return PointerConverter<T>(SecureMemoryAllocator::Allocate(size)).AsType(); +} + +/** + * @brief + * + * @return void* + */ +template <typename T> +auto SecureReallocAsType(T *ptr, std::size_t size) -> T * { + return PointerConverter<T>(SecureMemoryAllocator::Reallocate(ptr, size)) + .AsType(); +} + +/** + * @brief + * + */ +void GPGFRONTEND_CORE_EXPORT SecureFree(void *); + +template <typename T, typename... Args> +static auto SecureCreateObject(Args &&...args) -> T * { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) return nullptr; + + try { + return new (mem) T(std::forward<Args>(args)...); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T> +static void SecureDestroyObject(T *obj) { + if (!obj) return; + obj->~T(); + SecureMemoryAllocator::Deallocate(obj); +} + +template <typename T, typename... Args> +static auto SecureCreateUniqueObject(Args &&...args) + -> std::unique_ptr<T, SecureObjectDeleter<T>> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + return std::unique_ptr<T, SecureObjectDeleter<T>>( + new (mem) T(std::forward<Args>(args)...)); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T, typename... Args> +auto SecureCreateSharedObject(Args &&...args) -> std::shared_ptr<T> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + T *obj = new (mem) T(std::forward<Args>(args)...); + return std::shared_ptr<T>(obj, [](T *ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + }); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T, typename... Args> +auto SecureCreateQSharedObject(Args &&...args) -> QSharedPointer<T> { + void *mem = SecureMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + T *obj = new (mem) T(std::forward<Args>(args)...); + return QSharedPointer<T>(obj, [](T *ptr) { + ptr->~T(); + SecureMemoryAllocator::Deallocate(ptr); + }); + } catch (...) { + SecureMemoryAllocator::Deallocate(mem); + throw; + } +} + +}; // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/aes/aes_ssl.h b/src/core/utils/aes/aes_ssl.h index e75b68dd..5c3ac935 100644 --- a/src/core/function/aes/aes_ssl.h +++ b/src/core/utils/aes/aes_ssl.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_AES_SSL_H -#define GPGFRONTEND_AES_SSL_H +#pragma once #include <openssl/aes.h> #include <openssl/evp.h> @@ -70,5 +69,3 @@ uint8_t *aes_256_cbc_encrypt(EVP_CIPHER_CTX *e, uint8_t *plaintext, int *len); uint8_t *aes_256_cbc_decrypt(EVP_CIPHER_CTX *e, uint8_t *ciphertext, int *len); } // namespace GpgFrontend::RawAPI - -#endif // GPGFRONTEND_AES_SSL_H diff --git a/src/core/function/aes/aes_ssl_cbc.cpp b/src/core/utils/aes/aes_ssl_cbc.cpp index 3aa80ef5..3aa80ef5 100644 --- a/src/core/function/aes/aes_ssl_cbc.cpp +++ b/src/core/utils/aes/aes_ssl_cbc.cpp diff --git a/src/init.cpp b/src/init.cpp index ddab4add..4f9cf821 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,26 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include <spdlog/async.h> -#include <spdlog/common.h> -#include <spdlog/sinks/rotating_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> +#include "init.h" -#include <filesystem> -#include <string> - -#include "GpgFrontend.h" -#include "GpgFrontendBuildInfo.h" +#include "core/GpgCoreInit.h" #include "core/function/GlobalSettingStation.h" +#include "core/thread/TaskRunnerGetter.h" +#include "core/utils/LogUtils.h" +#include "module/GpgFrontendModuleInit.h" +#include "ui/GpgFrontendUIInit.h" + +// main +#include "GpgFrontendContext.h" +#include "main.h" + +namespace GpgFrontend { #ifdef WINDOWS int setenv(const char *name, const char *value, int overwrite) { @@ -50,66 +53,91 @@ int setenv(const char *name, const char *value, int overwrite) { } #endif -void init_logging_system() { - using namespace boost::posix_time; - using namespace boost::gregorian; - - // sinks - std::vector<spdlog::sink_ptr> sinks; - sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); +void InitLoggingSystem(const GFCxtSPtr &ctx) { + RegisterSyncLogger("core", ctx->log_level); - // thread pool - spdlog::init_thread_pool(1024, 2); + RegisterSyncLogger("main", ctx->log_level); - // logger - auto main_logger = std::make_shared<spdlog::async_logger>( - "main", begin(sinks), end(sinks), spdlog::thread_pool()); - main_logger->set_pattern( - "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + RegisterSyncLogger("module", ctx->log_level); -#ifdef DEBUG - main_logger->set_level(spdlog::level::trace); -#else - main_logger->set_level(spdlog::level::info); -#endif - - // flush policy - main_logger->flush_on(spdlog::level::err); - spdlog::flush_every(std::chrono::seconds(5)); - - // register it as default logger - spdlog::set_default_logger(main_logger); -} - -void shutdown_logging_system() { -#ifdef WINDOWS - // Under VisualStudio, this must be called before main finishes to workaround - // a known VS issue - spdlog::drop_all(); - spdlog::shutdown(); -#endif + if (ctx->load_ui_env) { + // init the logging system for ui + RegisterSyncLogger("ui", ctx->log_level); + } else { + RegisterSyncLogger("test", ctx->log_level); + } } -void init_global_path_env() { +void InitGlobalPathEnv() { // read settings bool use_custom_gnupg_install_path = - GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( - "general.use_custom_gnupg_install_path", false); + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/use_custom_gnupg_install_path", false) + .toBool(); - std::string custom_gnupg_install_path = - GpgFrontend::GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_gnupg_install_path", std::string{}); + QString custom_gnupg_install_path = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/custom_gnupg_install_path") + .toString(); // add custom gnupg install path into env $PATH - if (use_custom_gnupg_install_path && !custom_gnupg_install_path.empty()) { - std::string path_value = getenv("PATH"); - SPDLOG_DEBUG("Current System PATH: {}", path_value); + if (use_custom_gnupg_install_path && !custom_gnupg_install_path.isEmpty()) { + QString path_value = getenv("PATH"); + GF_MAIN_LOG_DEBUG("Current System PATH: {}", path_value); setenv("PATH", - ((std::filesystem::path{custom_gnupg_install_path}).u8string() + - ":" + path_value) - .c_str(), + (QDir(custom_gnupg_install_path).absolutePath() + ":" + path_value) + .toUtf8(), 1); - std::string modified_path_value = getenv("PATH"); - SPDLOG_DEBUG("Modified System PATH: {}", modified_path_value); + QString modified_path_value = getenv("PATH"); + GF_MAIN_LOG_DEBUG("Modified System PATH: {}", modified_path_value); } } + +void InitGlobalBasicalEnv(const GFCxtWPtr &p_ctx, bool gui_mode) { + GFCxtSPtr ctx = p_ctx.lock(); + if (ctx == nullptr) { + return; + } + + // initialize logging system + SetDefaultLogLevel(ctx->log_level); + InitLoggingSystem(ctx); + + // change path to search for related + InitGlobalPathEnv(); + + // init application + ctx->InitApplication(); + + // should load module system first + Module::ModuleInitArgs module_init_args; + module_init_args.log_level = ctx->log_level; + Module::LoadGpgFrontendModules(module_init_args); + + if (ctx->load_ui_env) { + // then preload ui + UI::PreInitGpgFrontendUI(); + } + + CoreInitArgs core_init_args; + core_init_args.gather_external_gnupg_info = ctx->gather_external_gnupg_info; + core_init_args.load_default_gpg_context = ctx->load_default_gpg_context; + + // then load core + InitGpgFrontendCore(core_init_args); +} + +void ShutdownGlobalBasicalEnv(const GFCxtWPtr &p_ctx) { + GFCxtSPtr ctx = p_ctx.lock(); + if (ctx == nullptr) { + return; + } + + Thread::TaskRunnerGetter::GetInstance().StopAllTeakRunner(); + + DestroyGpgFrontendCore(); +} + +} // namespace GpgFrontend diff --git a/src/init.h b/src/init.h new file mode 100644 index 00000000..1481b435 --- /dev/null +++ b/src/init.h @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "GpgFrontendContext.h" + +namespace GpgFrontend { + +/** + * @brief + * + * @param args + */ +void InitLoggingSystem(const GFCxtSPtr &); + +/** + * @brief init global PATH env + * + */ +void InitGlobalPathEnv(); + +/** + * @brief + * + * @param args + */ +void InitGlobalBasicalEnv(const GFCxtWPtr &, bool); + +/** + * @brief + * + * @param p_ctx + */ +void ShutdownGlobalBasicalEnv(const GFCxtWPtr &p_ctx); + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6ceff2a3..eea2e9f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -30,60 +30,13 @@ * \mainpage GpgFrontend Develop Document Main Page */ -#include <csetjmp> -#include <csignal> -#include <cstddef> -#include <cstdlib> -#include <string> +#include <memory> -#include "core/GpgConstants.h" -#include "core/GpgCoreInit.h" -#include "core/function/GlobalSettingStation.h" -#include "spdlog/spdlog.h" -#include "ui/GpgFrontendApplication.h" -#include "ui/GpgFrontendUIInit.h" - -/** - * \brief Store the jump buff and make it possible to recover from a crash. - */ -#ifdef FREEBSD -sigjmp_buf recover_env; -#else -jmp_buf recover_env; -#endif - -constexpr int CRASH_CODE = ~0; ///< - -/** - * @brief handle the signal SIGSEGV - * - * @param sig - */ -extern void handle_signal(int sig); - -/** - * @brief processes before exit the program. - * - */ -extern void before_exit(); - -/** - * @brief initialize the logging system. - * - */ -extern void init_logging_system(); - -/** - * @brief initialize the logging system. - * - */ -extern void shutdown_logging_system(); - -/** - * @brief init global PATH env - * - */ -extern void init_global_path_env(); +#include "GpgFrontendContext.h" +#include "app.h" +#include "cmd.h" +#include "core/utils/MemoryUtils.h" +#include "init.h" /** * @@ -91,93 +44,54 @@ extern void init_global_path_env(); * @param argv * @return */ -int main(int argc, char* argv[]) { -#ifdef RELEASE - // re - signal(SIGSEGV, handle_signal); - signal(SIGFPE, handle_signal); - signal(SIGILL, handle_signal); -#endif +auto main(int argc, char* argv[]) -> int { + GpgFrontend::GFCxtSPtr ctx = + GpgFrontend::SecureCreateSharedObject<GpgFrontend::GpgFrontendContext>( + argc, argv); + ctx->InitApplication(); - // clean something before exit - atexit(before_exit); + auto rtn = 0; // initialize qt resources Q_INIT_RESOURCE(gpgfrontend); - // create qt application - auto* app = - GpgFrontend::UI::GpgFrontendApplication::GetInstance(argc, argv, true); - - // init the logging system for main - init_logging_system(); - - // init the logging system for core - GpgFrontend::InitCoreLoggingSystem(); - - // init the logging system for ui - GpgFrontend::UI::InitUILoggingSystem(); - - // change path to search for related - init_global_path_env(); - - /** - * internationalisation. loop to restart main window - * with changed translation when settings change. - */ - int return_from_event_loop_code; - int restart_count = 0; - - do { -#ifndef WINDOWS - int r = sigsetjmp(recover_env, 1); -#else - int r = setjmp(recover_env); -#endif - if (!r) { - // init ui library - GpgFrontend::UI::InitGpgFrontendUI(app); - - // create main window - return_from_event_loop_code = GpgFrontend::UI::RunGpgFrontendUI(app); - } else { - SPDLOG_ERROR("recover from a crash"); - // when signal is caught, restart the main window - auto* message_box = new QMessageBox( - QMessageBox::Critical, _("A serious error has occurred"), - _("Oh no! GpgFrontend caught a serious error in the software, so " - "it needs to be restarted. If the problem recurs, please " - "manually terminate the program and report the problem to the " - "developer."), - QMessageBox::Ok, nullptr); - message_box->exec(); - return_from_event_loop_code = CRASH_CODE; - } - - restart_count++; - - SPDLOG_DEBUG("restart loop refresh, event loop code: {}, restart count: {}", - return_from_event_loop_code, restart_count); - } while (return_from_event_loop_code == RESTART_CODE && restart_count < 3); - - // shutdown the logging system for ui - GpgFrontend::UI::ShutdownUILoggingSystem(); - - // shutdown the logging system for core - GpgFrontend::ShutdownCoreLoggingSystem(); - - // log for debug - SPDLOG_INFO("GpgFrontend about to exit."); - - // deep restart mode - if (return_from_event_loop_code == DEEP_RESTART_CODE || - return_from_event_loop_code == CRASH_CODE) { - // log for debug - SPDLOG_DEBUG( - "deep restart or cash loop status caught, restart a new application"); - QProcess::startDetached(qApp->arguments()[0], qApp->arguments()); - }; - - // exit the program - return return_from_event_loop_code; + QCommandLineParser parser; + parser.addHelpOption(); + parser.addOptions({ + {{"v", "version"}, "show version information"}, + {{"t", "test"}, "run all unit test cases"}, + {{"l", "log-level"}, + "set log level (trace, debug, info, warn, error)", + "debug"}, + }); + + parser.process(*ctx->GetApp()); + + ctx->log_level = spdlog::level::info; + + if (parser.isSet("v")) { + return GpgFrontend::PrintVersion(); + } + + if (parser.isSet("l")) { + ctx->log_level = GpgFrontend::ParseLogLevel(parser.value("l")); + } + + if (parser.isSet("t")) { + ctx->gather_external_gnupg_info = false; + ctx->load_default_gpg_context = false; + + InitGlobalBasicalEnv(ctx, false); + rtn = RunTest(ctx); + ShutdownGlobalBasicalEnv(ctx); + return rtn; + } + + ctx->gather_external_gnupg_info = true; + ctx->load_default_gpg_context = true; + InitGlobalBasicalEnv(ctx, true); + + rtn = StartApplication(ctx); + ShutdownGlobalBasicalEnv(ctx); + return rtn; } diff --git a/src/main.h b/src/main.h new file mode 100644 index 00000000..d22b2acf --- /dev/null +++ b/src/main.h @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/utils/LogUtils.h" + +#define GF_MAIN_LOG_TRACE(...) GF_LOG_TRACE("main", __VA_ARGS__) +#define GF_MAIN_LOG_DEBUG(...) GF_LOG_DEBUG("main", __VA_ARGS__) +#define GF_MAIN_LOG_INFO(...) GF_LOG_INFO("main", __VA_ARGS__) +#define GF_MAIN_LOG_WARN(...) GF_LOG_WARN("main", __VA_ARGS__) +#define GF_MAIN_LOG_ERROR(...) GF_LOG_ERROR("main", __VA_ARGS__)
\ No newline at end of file diff --git a/src/module/CMakeLists.txt b/src/module/CMakeLists.txt new file mode 100644 index 00000000..b12e207a --- /dev/null +++ b/src/module/CMakeLists.txt @@ -0,0 +1,80 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend 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 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +# define libgpgfrontend_module_sdk +aux_source_directory(sdk MODULE_SDK_SOURCE) + +add_library(gpgfrontend_module_sdk SHARED ${MODULE_SDK_SOURCE}) +set(_export_file_sdk "${CMAKE_CURRENT_SOURCE_DIR}/sdk/GpgFrontendModuleSDKExport.h") +generate_export_header(gpgfrontend_module_sdk EXPORT_FILE_NAME "${_export_file_sdk}") +target_include_directories(gpgfrontend_module_sdk PUBLIC + sdk + ${CMAKE_CURRENT_BINARY_DIR}/gpgfrontend_module_sdk_autogen/include + ${CMAKE_SOURCE_DIR}/third_party/spdlog/include) + +# link module system +target_link_libraries(gpgfrontend_module_sdk + PUBLIC gpgfrontend_core) + +# tracking integrated modules +set(all_integrated_module_libraries "") +file(GLOB children LIST_DIRECTORIES true "integrated/*") +foreach(child ${children}) + if(IS_DIRECTORY ${child}) + get_filename_component(dirName ${child} NAME) + add_subdirectory("integrated/${dirName}") + + string(REPLACE "_module" "" stripped_module ${dirName}) + set(integrated_lib_name "gpgfrontend_integrated_module_${stripped_module}") + list(APPEND all_integrated_module_libraries ${integrated_lib_name}) + endif() +endforeach() + +aux_source_directory(. MODULE_SOURCE) +add_library(gpgfrontend_module SHARED ${MODULE_SOURCE}) + +set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendModuleExport.h") +generate_export_header(gpgfrontend_module EXPORT_FILE_NAME "${_export_file}") + +# set up pch +target_precompile_headers(gpgfrontend_module PUBLIC GpgFrontendModule.h) + +# add ui generator include path +target_include_directories(gpgfrontend_module PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/gpgfrontend_module_autogen/include + ${CMAKE_SOURCE_DIR}/third_party/spdlog/include) + +# link gpgfrontend_module_sdk +target_link_libraries(gpgfrontend_module PRIVATE gpgfrontend_module_sdk) + +# link all integrated modules +message(STATUS "All Module Libraries: ${all_integrated_module_libraries}") +target_link_libraries(gpgfrontend_module PRIVATE ${all_integrated_module_libraries}) + +# using std c++ 17 +target_compile_features(gpgfrontend_module PUBLIC cxx_std_17)
\ No newline at end of file diff --git a/src/module/GpgFrontendModule.h b/src/module/GpgFrontendModule.h new file mode 100644 index 00000000..cf7d8557 --- /dev/null +++ b/src/module/GpgFrontendModule.h @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +/** + * Project internal dependencies + */ +#include "GpgFrontend.h" +#include "GpgFrontendModuleExport.h" +#include "core/GpgFrontendCore.h" diff --git a/src/module/GpgFrontendModuleExport.h b/src/module/GpgFrontendModuleExport.h new file mode 100644 index 00000000..33ecbd3b --- /dev/null +++ b/src/module/GpgFrontendModuleExport.h @@ -0,0 +1,42 @@ + +#ifndef GPGFRONTEND_MODULE_EXPORT_H +#define GPGFRONTEND_MODULE_EXPORT_H + +#ifdef GPGFRONTEND_MODULE_STATIC_DEFINE +# define GPGFRONTEND_MODULE_EXPORT +# define GPGFRONTEND_MODULE_NO_EXPORT +#else +# ifndef GPGFRONTEND_MODULE_EXPORT +# ifdef gpgfrontend_module_EXPORTS + /* We are building this library */ +# define GPGFRONTEND_MODULE_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define GPGFRONTEND_MODULE_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef GPGFRONTEND_MODULE_NO_EXPORT +# define GPGFRONTEND_MODULE_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef GPGFRONTEND_MODULE_DEPRECATED +# define GPGFRONTEND_MODULE_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef GPGFRONTEND_MODULE_DEPRECATED_EXPORT +# define GPGFRONTEND_MODULE_DEPRECATED_EXPORT GPGFRONTEND_MODULE_EXPORT GPGFRONTEND_MODULE_DEPRECATED +#endif + +#ifndef GPGFRONTEND_MODULE_DEPRECATED_NO_EXPORT +# define GPGFRONTEND_MODULE_DEPRECATED_NO_EXPORT GPGFRONTEND_MODULE_NO_EXPORT GPGFRONTEND_MODULE_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef GPGFRONTEND_MODULE_NO_DEPRECATED +# define GPGFRONTEND_MODULE_NO_DEPRECATED +# endif +#endif + +#endif /* GPGFRONTEND_MODULE_EXPORT_H */ diff --git a/src/module/GpgFrontendModuleInit.cpp b/src/module/GpgFrontendModuleInit.cpp new file mode 100644 index 00000000..6f88b9ec --- /dev/null +++ b/src/module/GpgFrontendModuleInit.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgFrontendModuleInit.h" + +#include <core/module/ModuleManager.h> + +#include "core/thread/Task.h" +#include "core/thread/TaskRunnerGetter.h" + +// integrated modules +#include "integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h" +#include "integrated/version_checking_module/VersionCheckingModule.h" +#include "spdlog/common.h" + +namespace GpgFrontend::Module { + +void LoadGpgFrontendModules(ModuleInitArgs) { + // must init at default thread before core + Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( + new Thread::Task( + [](const DataObjectPtr&) -> int { + MODULE_LOG_INFO("loading integrated module..."); + + // VersionCheckingModule + RegisterAndActivateModule< + Integrated::VersionCheckingModule::VersionCheckingModule>(); + + // VersionCheckingModule + RegisterAndActivateModule<Integrated::GnuPGInfoGatheringModule:: + GnuPGInfoGatheringModule>(); + + MODULE_LOG_INFO("load integrated module done."); + return 0; + }, + "modules_system_init_task")); +} + +void ShutdownGpgFrontendModules() {} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/module/GpgFrontendModuleInit.h b/src/module/GpgFrontendModuleInit.h new file mode 100644 index 00000000..a3a8bbd3 --- /dev/null +++ b/src/module/GpgFrontendModuleInit.h @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "module/GpgFrontendModule.h" + +namespace GpgFrontend::Module { + +struct ModuleInitArgs { + spdlog::level::level_enum log_level; +}; + +/** + * @brief init the module library + * + */ +void GPGFRONTEND_MODULE_EXPORT LoadGpgFrontendModules(ModuleInitArgs args); + +/** + * @brief shutdown the module library + * + */ +void GPGFRONTEND_MODULE_EXPORT ShutdownGpgFrontendModules(); + +}; // namespace GpgFrontend::Module diff --git a/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt b/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt new file mode 100644 index 00000000..2a62b08e --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend 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 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering + +aux_source_directory(. INTEGRATED_MODULE_SOURCE) + +# define libgpgfrontend_module +add_library(gpgfrontend_integrated_module_gnupg_info_gathering SHARED ${INTEGRATED_MODULE_SOURCE}) + +# link sdk +target_link_libraries(gpgfrontend_integrated_module_gnupg_info_gathering PRIVATE + gpgfrontend_module_sdk) + +# using std c++ 17 +target_compile_features(gpgfrontend_integrated_module_gnupg_info_gathering PRIVATE cxx_std_17)
\ No newline at end of file diff --git a/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp new file mode 100644 index 00000000..91bf93f5 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp @@ -0,0 +1,358 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GnuPGInfoGatheringModule.h" + +#include <vector> + +#include "GpgInfo.h" +#include "Log.h" +#include "core/function/gpg/GpgCommandExecutor.h" +#include "core/module/ModuleManager.h" + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { + +auto CheckBinaryChacksum(QString path) -> std::optional<QString> { + // check file info and access rights + QFileInfo info(path); + if (!info.exists() || !info.isFile() || !info.isReadable()) { + MODULE_LOG_ERROR("get info for file {} error, exists: {}", info.filePath(), + info.exists()); + return {}; + } + + // open and read file + QFile f(info.filePath()); + if (!f.open(QIODevice::ReadOnly)) { + MODULE_LOG_ERROR("open {} to calculate check sum error: {}", path, + f.errorString()); + return {}; + } + + // read all data from file + auto buffer = f.readAll(); + f.close(); + + auto hash_sha = QCryptographicHash(QCryptographicHash::Sha256); + // md5 + hash_sha.addData(buffer); + return QString(hash_sha.result().toHex()).left(6); +} + +GnuPGInfoGatheringModule::GnuPGInfoGatheringModule() + : Module( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "1.0.0", + ModuleMetaData{{"description", "try to gathering gnupg informations"}, + {"author", "saturneric"}}) {} + +GnuPGInfoGatheringModule::~GnuPGInfoGatheringModule() = default; + +auto GnuPGInfoGatheringModule::Register() -> bool { + MODULE_LOG_DEBUG("gnupg info gathering module registering"); + listenEvent("GPGFRONTEND_CORE_INITLIZED"); + return true; +} + +auto GnuPGInfoGatheringModule::Active() -> bool { + MODULE_LOG_DEBUG("gnupg info gathering module activating"); + return true; +} + +auto GnuPGInfoGatheringModule::Exec(EventRefrernce event) -> int { + MODULE_LOG_DEBUG("gnupg info gathering module executing, event id: {}", + event->GetIdentifier()); + + const auto gpgme_version = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", QString{"0.0.0"}); + MODULE_LOG_DEBUG("got gpgme version from rt: {}", gpgme_version); + + const auto gpgconf_path = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gpgconf_path", QString{}); + MODULE_LOG_DEBUG("got gpgconf path from rt: {}", gpgconf_path); + + MODULE_LOG_DEBUG("start to load extra info at module gnupginfogathering..."); + + // get all components + GpgCommandExecutor::ExecuteSync( + {gpgconf_path, + {"--list-components"}, + [this, gpgme_version, gpgconf_path](int exit_code, const QString &p_out, + const QString &p_err) { + MODULE_LOG_DEBUG( + "gpgconf components exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + MODULE_LOG_ERROR( + "gpgconf execute error, process stderr: {}, " + "process stdout: {}", + p_err, p_out); + return; + } + + std::vector<GpgComponentInfo> component_infos; + GpgComponentInfo c_i_gpgme; + c_i_gpgme.name = "gpgme"; + c_i_gpgme.desc = "GPG Made Easy"; + c_i_gpgme.version = gpgme_version; + c_i_gpgme.path = tr("Embedded In"); + c_i_gpgme.binary_checksum = "/"; + + GpgComponentInfo c_i_gpgconf; + c_i_gpgconf.name = "gpgconf"; + c_i_gpgconf.desc = "GPG Configure"; + c_i_gpgconf.version = "/"; + c_i_gpgconf.path = gpgconf_path; + auto gpgconf_binary_checksum = CheckBinaryChacksum(gpgconf_path); + c_i_gpgconf.binary_checksum = (gpgconf_binary_checksum.has_value() + ? gpgconf_binary_checksum.value() + : QString("/")); + + component_infos.push_back(c_i_gpgme); + component_infos.push_back(c_i_gpgconf); + + auto const jsonlized_gpgme_component_info = c_i_gpgme.Json(); + auto const jsonlized_gpgconf_component_info = c_i_gpgconf.Json(); + UpsertRTValue(GetModuleIdentifier(), "gnupg.components.gpgme", + QJsonDocument(jsonlized_gpgme_component_info).toJson()); + UpsertRTValue( + GetModuleIdentifier(), "gnupg.components.gpgconf", + QJsonDocument(jsonlized_gpgconf_component_info).toJson()); + + auto line_split_list = p_out.split("\n"); + + for (const auto &line : line_split_list) { + auto info_split_list = line.split(":"); + + if (info_split_list.size() != 3) continue; + + auto component_name = info_split_list[0].trimmed(); + auto component_desc = info_split_list[1].trimmed(); + auto component_path = info_split_list[2].trimmed(); + +#ifdef WINDOWS + // replace some special substrings on windows platform + component_path.replace("%3a", ":"); +#endif + + auto binary_checksum = CheckBinaryChacksum(component_path); + + MODULE_LOG_DEBUG( + "gnupg component name: {} desc: {} checksum: {} path: {} ", + component_name, component_desc, + binary_checksum.has_value() ? binary_checksum.value() : "/", + component_path); + + QString version = "/"; + + if (component_name == "gpg") { + version = RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + } + if (component_name == "gpg-agent") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.gpg_agent_path", + QString(component_path)); + } + if (component_name == "dirmngr") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.dirmngr_path", + QString(component_path)); + } + if (component_name == "keyboxd") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.keyboxd_path", + QString(component_path)); + } + + { + GpgComponentInfo c_i; + c_i.name = component_name; + c_i.desc = component_desc; + c_i.version = version; + c_i.path = component_path; + c_i.binary_checksum = + (binary_checksum.has_value() ? binary_checksum.value() + : QString("/")); + + auto const jsonlized_component_info = c_i.Json(); + UpsertRTValue(GetModuleIdentifier(), + QString("gnupg.components.%1").arg(component_name), + QJsonDocument(jsonlized_component_info).toJson()); + + component_infos.push_back(c_i); + } + } + }, + getTaskRunner()}); + + GpgCommandExecutor::ExecuteContexts exec_contexts; + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + gpgconf_path, + {"--list-dirs"}, + [this](int exit_code, const QString &p_out, const QString &p_err) { + MODULE_LOG_DEBUG( + "gpgconf configurations exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + MODULE_LOG_ERROR( + "gpgconf execute error, process stderr: {} process stdout: " + "{}", + p_err, p_out); + return; + } + + auto line_split_list = p_out.split("\n"); + + for (const auto &line : line_split_list) { + auto info_split_list = line.split(":"); + MODULE_LOG_DEBUG("gpgconf info line: {} info size: {}", line, + info_split_list.size()); + + if (info_split_list.size() != 2) continue; + + auto configuration_name = info_split_list[0].trimmed(); + auto configuration_value = info_split_list[1].trimmed(); + +#ifdef WINDOWS + // replace some special substrings on windows platform + configuration_value.replace("%3a", ":"); +#endif + + // record gnupg home path + if (configuration_name == "homedir") { + UpsertRTValue(GetModuleIdentifier(), "gnupg.home_path", + configuration_value); + } + + UpsertRTValue(GetModuleIdentifier(), + QString("gnupg.dirs.%1").arg(configuration_name), + configuration_value); + } + }, + getTaskRunner()}); + + auto components = ListRTChildKeys(GetModuleIdentifier(), "gnupg.components"); + + for (const auto &component : components) { + auto component_info_json = RetrieveRTValueTypedOrDefault( + GetModuleIdentifier(), QString("gnupg.components.%1").arg(component), + QByteArray{}); + + auto jsonlized_component_info = + QJsonDocument::fromJson(component_info_json); + assert(jsonlized_component_info.isObject()); + + auto component_info = GpgComponentInfo(jsonlized_component_info.object()); + MODULE_LOG_DEBUG("gpgconf check options ready, component: {}", + component_info.name); + + if (component_info.name == "gpgme" || component_info.name == "gpgconf") { + continue; + } + + exec_contexts.emplace_back(GpgCommandExecutor::ExecuteContext{ + gpgconf_path, + {"--list-options", component_info.name}, + [this, component_info](int exit_code, const QString &p_out, + const QString &p_err) { + MODULE_LOG_DEBUG( + "gpgconf {} avaliable options exit_code: {} process stdout " + "size: {} ", + component_info.name, exit_code, p_out.size()); + + if (exit_code != 0) { + MODULE_LOG_ERROR( + "gpgconf {} avaliable options execute error, process stderr: " + "{} , process stdout:", + component_info.name, p_err, p_out); + return; + } + + std::vector<GpgOptionsInfo> options_infos; + + auto line_split_list = p_out.split("\n"); + + for (const auto &line : line_split_list) { + auto info_split_list = line.split(":"); + + MODULE_LOG_DEBUG( + "component {} avaliable options line: {} info size: {}", + component_info.name, line, info_split_list.size()); + + if (info_split_list.size() < 10) continue; + + // The format of each line is: + // name:flags:level:description:type:alt-type:argname:default:argdef:value + + auto option_name = info_split_list[0].trimmed(); + auto option_flags = info_split_list[1].trimmed(); + auto option_level = info_split_list[2].trimmed(); + auto option_desc = info_split_list[3].trimmed(); + auto option_type = info_split_list[4].trimmed(); + auto option_alt_type = info_split_list[5].trimmed(); + auto option_argname = info_split_list[6].trimmed(); + auto option_default = info_split_list[7].trimmed(); + auto option_argdef = info_split_list[8].trimmed(); + auto option_value = info_split_list[9].trimmed(); + + GpgOptionsInfo info; + info.name = option_name; + info.flags = option_flags; + info.level = option_level; + info.description = option_desc; + info.type = option_type; + info.alt_type = option_alt_type; + info.argname = option_argname; + info.default_value = option_default; + info.argdef = option_argdef; + info.value = option_value; + + auto const jsonlized_option_info = info.Json(); + UpsertRTValue(GetModuleIdentifier(), + QString("gnupg.components.%1.options.%2") + .arg(component_info.name) + .arg(option_name), + QJsonDocument(jsonlized_option_info).toJson()); + options_infos.push_back(info); + } + }, + getTaskRunner()}); + } + + GpgCommandExecutor::ExecuteConcurrentlySync(exec_contexts); + UpsertRTValue(GetModuleIdentifier(), "gnupg.gathering_done", true); + event->ExecuteCallback(GetModuleIdentifier(), TransferParams(true)); + + MODULE_LOG_DEBUG("gnupg external info gathering done"); + return 0; +} + +auto GnuPGInfoGatheringModule::Deactive() -> bool { return true; } + +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h new file mode 100644 index 00000000..5c228298 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <module/sdk/GpgFrontendModuleSDK.h> + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { + +/** + * @brief Use to record some info about gnupg + * + */ +class GPGFRONTEND_MODULE_SDK_EXPORT GnuPGInfoGatheringModule : public Module { + Q_OBJECT + public: + GnuPGInfoGatheringModule(); + + ~GnuPGInfoGatheringModule() override; + + auto Register() -> bool override; + + auto Active() -> bool override; + + auto Exec(EventRefrernce) -> int override; + + auto Deactive() -> bool override; +}; +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/gnupg_info_gathering_module/GpgInfo.cpp b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.cpp new file mode 100644 index 00000000..2015bc0a --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "module/integrated/gnupg_info_gathering_module/GpgInfo.h" + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { + +GpgOptionsInfo::GpgOptionsInfo(const QJsonObject &j) { + if (const auto v = j["name"]; v.isString()) name = v.toString(); + if (const auto v = j["flags"]; v.isString()) flags = v.toString(); + if (const auto v = j["level"]; v.isString()) level = v.toString(); + if (const auto v = j["description"]; v.isString()) description = v.toString(); + if (const auto v = j["type"]; v.isString()) type = v.toString(); + if (const auto v = j["alt_type"]; v.isString()) alt_type = v.toString(); + if (const auto v = j["argname"]; v.isString()) argname = v.toString(); + if (const auto v = j["default_value"]; v.isString()) + default_value = v.toString(); + if (const auto v = j["argdef"]; v.isString()) argdef = v.toString(); + if (const auto v = j["value"]; v.isString()) value = v.toString(); +} + +auto GpgOptionsInfo::Json() const -> QJsonObject { + QJsonObject j; + j["name"] = name; + j["flags"] = flags; + j["level"] = level; + j["description"] = description; + j["type"] = type; + j["alt_type"] = alt_type; + j["argname"] = argname; + j["default_value"] = default_value; + j["argdef"] = argdef; + j["value"] = value; + return j; +} + +auto GpgComponentInfo::Json() const -> QJsonObject { + QJsonObject j; + j["name"] = name; + j["desc"] = desc; + j["version"] = version; + j["path"] = path; + j["binary_checksum"] = binary_checksum; + return j; +} + +GpgComponentInfo::GpgComponentInfo(const QJsonObject &j) { + if (const auto v = j["name"]; v.isString()) name = v.toString(); + if (const auto v = j["desc"]; v.isString()) desc = v.toString(); + if (const auto v = j["version"]; v.isString()) version = v.toString(); + if (const auto v = j["path"]; v.isString()) path = v.toString(); + if (const auto v = j["binary_checksum"]; v.isString()) + binary_checksum = v.toString(); +} +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/gnupg_info_gathering_module/GpgInfo.h b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.h new file mode 100644 index 00000000..fb12b811 --- /dev/null +++ b/src/module/integrated/gnupg_info_gathering_module/GpgInfo.h @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule { +/** + * @brief Use to record some info about gnupg + * + */ +class GpgInfo { + public: + QString GnuPGHomePath; ///< value of ---homedir + + std::map<QString, std::vector<QString>> ComponentsInfo; ///< + std::map<QString, std::vector<QString>> ConfigurationsInfo; ///< + std::map<QString, std::vector<QString>> OptionsInfo; ///< + std::map<QString, std::vector<QString>> AvailableOptionsInfo; ///< +}; + +/** + * @brief Use to record some info about gnupg components + * + */ +struct GpgComponentInfo { + QString name; + QString desc; + QString version; + QString path; + QString binary_checksum; + + GpgComponentInfo() = default; + + explicit GpgComponentInfo(const QJsonObject &j); + + [[nodiscard]] auto Json() const -> QJsonObject; +}; + +/** + * The format of each line is: + * name:flags:level:description:type:alt-type:argname:default:argdef:value + */ +struct GpgOptionsInfo { + QString name; + QString flags; + QString level; + QString description; + QString type; + QString alt_type; + QString argname; + QString default_value; + QString argdef; + QString value; + + GpgOptionsInfo() = default; + + explicit GpgOptionsInfo(const QJsonObject &j); + + [[nodiscard]] auto Json() const -> QJsonObject; +}; + +} // namespace GpgFrontend::Module::Integrated::GnuPGInfoGatheringModule diff --git a/src/module/integrated/version_checking_module/CMakeLists.txt b/src/module/integrated/version_checking_module/CMakeLists.txt new file mode 100644 index 00000000..0b474ce9 --- /dev/null +++ b/src/module/integrated/version_checking_module/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend 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 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# com.bktus.gpgfrontend.module.integrated.version-checking + +aux_source_directory(. INTEGRATED_MODULE_SOURCE) + +# define libgpgfrontend_module +add_library(gpgfrontend_integrated_module_version_checking SHARED ${INTEGRATED_MODULE_SOURCE}) + +# link sdk +target_link_libraries(gpgfrontend_integrated_module_version_checking PRIVATE + gpgfrontend_module_sdk) + +# link Qt +target_link_libraries(gpgfrontend_integrated_module_version_checking PRIVATE Qt6::Network) + +# using std c++ 17 +target_compile_features(gpgfrontend_integrated_module_version_checking PRIVATE cxx_std_17)
\ No newline at end of file diff --git a/src/module/integrated/version_checking_module/SoftwareVersion.cpp b/src/module/integrated/version_checking_module/SoftwareVersion.cpp new file mode 100644 index 00000000..117212cb --- /dev/null +++ b/src/module/integrated/version_checking_module/SoftwareVersion.cpp @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SoftwareVersion.h" + +#include "core/utils/CommonUtils.h" + +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { + +bool VersionCheckingModule::SoftwareVersion::NeedUpgrade() const { + MODULE_LOG_DEBUG("compair version current {} latest {}, result {}", + current_version, latest_version, + CompareSoftwareVersion(current_version, latest_version)); + + MODULE_LOG_DEBUG("load done: {}, pre-release: {}, draft: {}", loading_done, + latest_prerelease_version_from_remote, + latest_draft_from_remote); + return loading_done && !latest_prerelease_version_from_remote && + !latest_draft_from_remote && + CompareSoftwareVersion(current_version, latest_version) < 0; +} + +bool VersionCheckingModule::SoftwareVersion::VersionWithdrawn() const { + return loading_done && !current_version_publish_in_remote && + current_version_is_a_prerelease && !current_version_is_drafted; +} + +bool VersionCheckingModule::SoftwareVersion::CurrentVersionReleased() const { + return loading_done && current_version_publish_in_remote; +} +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule
\ No newline at end of file diff --git a/src/ui/struct/SoftwareVersion.h b/src/module/integrated/version_checking_module/SoftwareVersion.h index 9d861ef1..43f718fa 100644 --- a/src/ui/struct/SoftwareVersion.h +++ b/src/module/integrated/version_checking_module/SoftwareVersion.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,33 +20,32 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SOFTWAREVERSION_H -#define GPGFRONTEND_SOFTWAREVERSION_H +#pragma once -#include <boost/date_time.hpp> +#include <module/sdk/GpgFrontendModuleSDK.h> -namespace GpgFrontend::UI { +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { /** * @brief * */ struct SoftwareVersion { - std::string latest_version; ///< - std::string current_version; ///< - bool latest_prerelease = false; ///< - bool latest_draft = false; ///< - bool current_prerelease = false; ///< - bool current_draft = false; ///< - bool load_info_done = false; ///< - bool current_version_found = false; ///< - std::string publish_date; ///< - std::string release_note; ///< + QString latest_version; ///< + QString current_version; ///< + bool latest_prerelease_version_from_remote = false; ///< + bool latest_draft_from_remote = false; ///< + bool current_version_is_a_prerelease = false; ///< + bool current_version_is_drafted = false; ///< + bool loading_done = false; ///< + bool current_version_publish_in_remote = false; ///< + QString publish_date; ///< + QString release_note; ///< /** * @brief @@ -54,7 +53,7 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool InfoValid() const { return load_info_done; } + [[nodiscard]] bool InfoValid() const { return loading_done; } /** * @brief @@ -70,7 +69,7 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool VersionWithDrawn() const; + [[nodiscard]] bool VersionWithdrawn() const; /** * @brief @@ -81,8 +80,6 @@ struct SoftwareVersion { [[nodiscard]] bool CurrentVersionReleased() const; private: - static int version_compare(const std::string& a, const std::string& b); + static int version_compare(const QString& a, const QString& b); }; -} // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SOFTWAREVERSION_H +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule diff --git a/src/module/integrated/version_checking_module/VersionCheckTask.cpp b/src/module/integrated/version_checking_module/VersionCheckTask.cpp new file mode 100644 index 00000000..261ab1ca --- /dev/null +++ b/src/module/integrated/version_checking_module/VersionCheckTask.cpp @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "VersionCheckTask.h" + +#include <QMetaType> +#include <QtNetwork> + +#include "GpgFrontendBuildInfo.h" + +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { + +VersionCheckTask::VersionCheckTask() + : Task("version_check_task"), + network_manager_(new QNetworkAccessManager(this)), + current_version_(QString("v") + VERSION_MAJOR + "." + VERSION_MINOR + + "." + VERSION_PATCH) { + HoldOnLifeCycle(true); + qRegisterMetaType<SoftwareVersion>("SoftwareVersion"); + version_.current_version = current_version_; +} + +auto VersionCheckTask::Run() -> int { + MODULE_LOG_DEBUG("current project version: {}", current_version_); + QString latest_version_url = + "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; + + QNetworkRequest latest_request; + latest_request.setUrl(QUrl(latest_version_url)); + latest_reply_ = network_manager_->get(latest_request); + connect(latest_reply_, &QNetworkReply::finished, this, + &VersionCheckTask::slot_parse_latest_version_info); + return 0; +} + +void VersionCheckTask::slot_parse_latest_version_info() { + version_.current_version = current_version_; + + if (latest_reply_ == nullptr || + latest_reply_->error() != QNetworkReply::NoError) { + MODULE_LOG_ERROR("latest version request error"); + version_.latest_version = current_version_; + } else { + latest_reply_bytes_ = latest_reply_->readAll(); + auto latest_reply_json = QJsonDocument::fromJson(latest_reply_bytes_); + + QString latest_version = latest_reply_json["tag_name"].toString(); + MODULE_LOG_INFO("latest version from Github: {}", latest_version); + + QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); + auto version_match = re.match(latest_version); + if (version_match.hasMatch()) { + latest_version = version_match.captured(0); + MODULE_LOG_DEBUG("latest version matched: {}", latest_version); + } else { + latest_version = current_version_; + MODULE_LOG_WARN("latest version unknown"); + } + + bool prerelease = latest_reply_json["prerelease"].toBool(); + bool draft = latest_reply_json["draft"].toBool(); + auto publish_date = latest_reply_json["published_at"].toString(); + auto release_note = latest_reply_json["body"].toString(); + version_.latest_version = latest_version; + version_.latest_prerelease_version_from_remote = prerelease; + version_.latest_draft_from_remote = draft; + version_.publish_date = publish_date; + version_.release_note = release_note; + } + + if (latest_reply_ != nullptr) { + latest_reply_->deleteLater(); + } + + try { + QString current_version_url = + "https://api.github.com/repos/saturneric/gpgfrontend/releases/tags/" + + current_version_; + + QNetworkRequest current_request; + current_request.setUrl(QUrl(current_version_url)); + current_reply_ = network_manager_->get(current_request); + + connect(current_reply_, &QNetworkReply::finished, this, + &VersionCheckTask::slot_parse_current_version_info); + } catch (...) { + MODULE_LOG_ERROR("current version request create error"); + emit SignalTaskShouldEnd(-1); + } +} + +void VersionCheckTask::slot_parse_current_version_info() { + if (current_reply_ == nullptr || + current_reply_->error() != QNetworkReply::NoError) { + if (current_reply_ != nullptr) { + MODULE_LOG_ERROR("current version request network error: {}", + current_reply_->errorString().toStdString()); + } else { + MODULE_LOG_ERROR( + "current version request network error, null reply object"); + } + version_.current_version_publish_in_remote = false; + } else { + version_.current_version_publish_in_remote = true; + current_reply_bytes_ = current_reply_->readAll(); + auto current_reply_json = QJsonDocument::fromJson(current_reply_bytes_); + + if (current_reply_json.isObject()) { + bool current_prerelease = current_reply_json["prerelease"].toBool(); + bool current_draft = current_reply_json["draft"].toBool(); + version_.latest_prerelease_version_from_remote = current_prerelease; + version_.latest_draft_from_remote = current_draft; + + // loading done + version_.loading_done = true; + } else { + MODULE_LOG_WARN("cannot parse data got from github"); + } + } + + MODULE_LOG_DEBUG("current version parse done: {}", + version_.current_version_publish_in_remote); + + if (current_reply_ != nullptr) current_reply_->deleteLater(); + emit SignalUpgradeVersion(version_); + emit SignalTaskShouldEnd(0); +} + +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule diff --git a/src/ui/thread/VersionCheckTask.h b/src/module/integrated/version_checking_module/VersionCheckTask.h index 0dbce17f..f5091819 100644 --- a/src/ui/thread/VersionCheckTask.h +++ b/src/module/integrated/version_checking_module/VersionCheckTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,23 +20,23 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_VERSIONCHECKTHREAD_H -#define GPGFRONTEND_VERSIONCHECKTHREAD_H +#pragma once -#include <memory> -#include <string> +#include <core/thread/Task.h> +#include <module/sdk/GpgFrontendModuleSDK.h> -#include "core/thread/Task.h" -#include "ui/GpgFrontendUI.h" -#include "ui/struct/SoftwareVersion.h" +#include "SoftwareVersion.h" -namespace GpgFrontend::UI { +class QNetworkReply; +class QNetworkAccessManager; + +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { /** * @brief @@ -44,13 +44,12 @@ namespace GpgFrontend::UI { */ class VersionCheckTask : public Thread::Task { Q_OBJECT - public: /** * @brief Construct a new Version Check Thread object * */ - explicit VersionCheckTask(); + VersionCheckTask(); signals: @@ -67,7 +66,7 @@ class VersionCheckTask : public Thread::Task { * */ - void Run() override; + auto Run() -> int override; private slots: @@ -89,10 +88,9 @@ class VersionCheckTask : public Thread::Task { QNetworkReply* latest_reply_ = nullptr; ///< latest version info reply QNetworkReply* current_reply_ = nullptr; ///< current version info reply QNetworkAccessManager* network_manager_; ///< - std::string current_version_; + QString current_version_; SoftwareVersion version_; }; -} // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_VERSIONCHECKTHREAD_H +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule + // GpgFrontend::Module::Custom::IntegradedModule::VersionCheckingModule diff --git a/src/module/integrated/version_checking_module/VersionCheckingModule.cpp b/src/module/integrated/version_checking_module/VersionCheckingModule.cpp new file mode 100644 index 00000000..9b62a9c8 --- /dev/null +++ b/src/module/integrated/version_checking_module/VersionCheckingModule.cpp @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "VersionCheckingModule.h" + +#include "Log.h" +#include "SoftwareVersion.h" +#include "VersionCheckTask.h" +#include "core/module/Module.h" +#include "core/module/ModuleManager.h" + +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { + +VersionCheckingModule::VersionCheckingModule() + : Module("com.bktus.gpgfrontend.module.integrated.version-checking", + "1.0.0", + ModuleMetaData{{"description", "try to check gpgfrontend version"}, + {"author", "saturneric"}}) {} + +VersionCheckingModule::~VersionCheckingModule() = default; + +auto VersionCheckingModule::Register() -> bool { + MODULE_LOG_INFO("version checking module registering"); + listenEvent("APPLICATION_LOADED"); + listenEvent("CHECK_APPLICATION_VERSION"); + return true; +} + +auto VersionCheckingModule::Active() -> bool { + MODULE_LOG_INFO("version checking module activating"); + return true; +} + +auto VersionCheckingModule::Exec(EventRefrernce event) -> int { + MODULE_LOG_INFO("version checking module executing, event id: {}", + event->GetIdentifier()); + + auto* task = new VersionCheckTask(); + connect(task, &VersionCheckTask::SignalUpgradeVersion, this, + &VersionCheckingModule::SignalVersionCheckDone); + connect(this, &VersionCheckingModule::SignalVersionCheckDone, this, + [this, event](SoftwareVersion version) { + SlotVersionCheckDone(std::move(version)); + event->ExecuteCallback(GetModuleIdentifier(), + TransferParams(version.loading_done)); + }); + getTaskRunner()->PostTask(task); + return 0; +} + +auto VersionCheckingModule::Deactive() -> bool { return true; } + +void VersionCheckingModule::SlotVersionCheckDone(SoftwareVersion version) { + MODULE_LOG_DEBUG("registering software information info to rt"); + UpsertRTValue(GetModuleIdentifier(), "version.current_version", + version.current_version); + UpsertRTValue(GetModuleIdentifier(), "version.latest_version", + version.latest_version); + UpsertRTValue(GetModuleIdentifier(), "version.current_version_is_drafted", + version.current_version_is_drafted); + UpsertRTValue(GetModuleIdentifier(), + "version.current_version_is_a_prerelease", + version.current_version_is_a_prerelease); + UpsertRTValue(GetModuleIdentifier(), + "version.current_version_publish_in_remote", + version.current_version_publish_in_remote); + UpsertRTValue(GetModuleIdentifier(), + "version.latest_prerelease_version_from_remote", + version.latest_prerelease_version_from_remote); + UpsertRTValue(GetModuleIdentifier(), "version.need_upgrade", + version.NeedUpgrade()); + UpsertRTValue(GetModuleIdentifier(), "version.current_version_released", + version.CurrentVersionReleased()); + UpsertRTValue(GetModuleIdentifier(), "version.current_a_withdrawn_version", + version.VersionWithdrawn()); + UpsertRTValue(GetModuleIdentifier(), "version.loading_done", + version.loading_done); + MODULE_LOG_DEBUG("register software information to rt done"); +} +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule diff --git a/src/module/integrated/version_checking_module/VersionCheckingModule.h b/src/module/integrated/version_checking_module/VersionCheckingModule.h new file mode 100644 index 00000000..0a215588 --- /dev/null +++ b/src/module/integrated/version_checking_module/VersionCheckingModule.h @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <module/sdk/GpgFrontendModuleSDK.h> + +#include "SoftwareVersion.h" + +namespace GpgFrontend::Module::Integrated::VersionCheckingModule { + +class GPGFRONTEND_MODULE_SDK_EXPORT VersionCheckingModule : public Module { + Q_OBJECT + public: + VersionCheckingModule(); + + ~VersionCheckingModule() override; + + auto Register() -> bool override; + + auto Active() -> bool override; + + auto Exec(EventRefrernce) -> int override; + + auto Deactive() -> bool override; + + signals: + + void SignalVersionCheckDone(SoftwareVersion); + + public slots: + + void SlotVersionCheckDone(SoftwareVersion); +}; +} // namespace GpgFrontend::Module::Integrated::VersionCheckingModule diff --git a/src/module/sdk/Basic.cpp b/src/module/sdk/Basic.cpp new file mode 100644 index 00000000..63859763 --- /dev/null +++ b/src/module/sdk/Basic.cpp @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */
\ No newline at end of file diff --git a/src/module/sdk/Basic.h b/src/module/sdk/Basic.h new file mode 100644 index 00000000..62a547b3 --- /dev/null +++ b/src/module/sdk/Basic.h @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::Module::SDK { + + + + +}
\ No newline at end of file diff --git a/src/module/sdk/Gpg.cpp b/src/module/sdk/Gpg.cpp new file mode 100644 index 00000000..63859763 --- /dev/null +++ b/src/module/sdk/Gpg.cpp @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */
\ No newline at end of file diff --git a/src/core/GpgInfo.cpp b/src/module/sdk/Gpg.h index a77f0ed4..0702632a 100644 --- a/src/core/GpgInfo.cpp +++ b/src/module/sdk/Gpg.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,10 +20,10 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include "core/GpgInfo.h" +#pragma once
\ No newline at end of file diff --git a/src/module/sdk/GpgFrontendModuleSDK.h b/src/module/sdk/GpgFrontendModuleSDK.h new file mode 100644 index 00000000..97769462 --- /dev/null +++ b/src/module/sdk/GpgFrontendModuleSDK.h @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <core/module/GpgFrontendModuleSystem.h> +#include <module/sdk/GpgFrontendModuleSDKExport.h> +#include <module/sdk/Log.h>
\ No newline at end of file diff --git a/src/module/sdk/GpgFrontendModuleSDKExport.h b/src/module/sdk/GpgFrontendModuleSDKExport.h new file mode 100644 index 00000000..a62168bc --- /dev/null +++ b/src/module/sdk/GpgFrontendModuleSDKExport.h @@ -0,0 +1,42 @@ + +#ifndef GPGFRONTEND_MODULE_SDK_EXPORT_H +#define GPGFRONTEND_MODULE_SDK_EXPORT_H + +#ifdef GPGFRONTEND_MODULE_SDK_STATIC_DEFINE +# define GPGFRONTEND_MODULE_SDK_EXPORT +# define GPGFRONTEND_MODULE_SDK_NO_EXPORT +#else +# ifndef GPGFRONTEND_MODULE_SDK_EXPORT +# ifdef gpgfrontend_module_sdk_EXPORTS + /* We are building this library */ +# define GPGFRONTEND_MODULE_SDK_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define GPGFRONTEND_MODULE_SDK_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef GPGFRONTEND_MODULE_SDK_NO_EXPORT +# define GPGFRONTEND_MODULE_SDK_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef GPGFRONTEND_MODULE_SDK_DEPRECATED +# define GPGFRONTEND_MODULE_SDK_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef GPGFRONTEND_MODULE_SDK_DEPRECATED_EXPORT +# define GPGFRONTEND_MODULE_SDK_DEPRECATED_EXPORT GPGFRONTEND_MODULE_SDK_EXPORT GPGFRONTEND_MODULE_SDK_DEPRECATED +#endif + +#ifndef GPGFRONTEND_MODULE_SDK_DEPRECATED_NO_EXPORT +# define GPGFRONTEND_MODULE_SDK_DEPRECATED_NO_EXPORT GPGFRONTEND_MODULE_SDK_NO_EXPORT GPGFRONTEND_MODULE_SDK_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef GPGFRONTEND_MODULE_SDK_NO_DEPRECATED +# define GPGFRONTEND_MODULE_SDK_NO_DEPRECATED +# endif +#endif + +#endif /* GPGFRONTEND_MODULE_SDK_EXPORT_H */ diff --git a/src/before_exit.cpp b/src/module/sdk/Log.cpp index 31c56354..384fac1d 100644 --- a/src/before_exit.cpp +++ b/src/module/sdk/Log.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,17 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include "core/function/GlobalSettingStation.h" +#include "Log.h" -/** - * @brief Actions performed before exiting the application - * - */ -void before_exit() { -} +#include <stdexcept> + +#include "core/function/GlobalSettingStation.h" + +namespace GpgFrontend::Module::SDK {} // namespace GpgFrontend::Module::SDK diff --git a/src/module/sdk/Log.h b/src/module/sdk/Log.h new file mode 100644 index 00000000..0c40a097 --- /dev/null +++ b/src/module/sdk/Log.h @@ -0,0 +1,71 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/utils/LogUtils.h" +#include "module/sdk/GpgFrontendModuleSDK.h" + +#define MODULE_LOG_TRACE(...) GF_LOG_TRACE("module", __VA_ARGS__) +#define MODULE_LOG_DEBUG(...) GF_LOG_DEBUG("module", __VA_ARGS__) +#define MODULE_LOG_INFO(...) GF_LOG_INFO("module", __VA_ARGS__) +#define MODULE_LOG_WARN(...) GF_LOG_WARN("module", __VA_ARGS__) +#define MODULE_LOG_ERROR(...) GF_LOG_ERROR("module", __VA_ARGS__) + +namespace spdlog { +class logger; +} + +namespace GpgFrontend::Module::SDK { + +template <typename... Args> +void ModuleLogTrace(const char* fmt, const Args&... args) { + MODULE_LOG_TRACE(fmt, args...); +} + +template <typename... Args> +void ModuleLogDebug(const char* fmt, const Args&... args) { + MODULE_LOG_DEBUG(fmt, args...); +} + +template <typename... Args> +void ModuleLogInfo(const char* fmt, const Args&... args) { + MODULE_LOG_INFO(fmt, args...); +} + +template <typename... Args> +void ModuleLogWarn(const char* fmt, const Args&... args) { + MODULE_LOG_WARN(fmt, args...); +} + +template <typename... Args> +void ModuleLogError(const char* fmt, const Args&... args) { + MODULE_LOG_ERROR(fmt, args...); +} + +} // namespace GpgFrontend::Module::SDK diff --git a/src/module/sdk/UI.cpp b/src/module/sdk/UI.cpp new file mode 100644 index 00000000..63859763 --- /dev/null +++ b/src/module/sdk/UI.cpp @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */
\ No newline at end of file diff --git a/src/module/sdk/UI.h b/src/module/sdk/UI.h new file mode 100644 index 00000000..0702632a --- /dev/null +++ b/src/module/sdk/UI.h @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once
\ No newline at end of file diff --git a/src/pinentry/CMakeLists.txt b/src/pinentry/CMakeLists.txt new file mode 100644 index 00000000..b31e4f05 --- /dev/null +++ b/src/pinentry/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend 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 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +aux_source_directory(. PINENTRY_SOURCE) + +# capslock +list(APPEND PINENTRY_SOURCE "capslock/capslock.cpp") +if (MINGW) + list(APPEND PINENTRY_SOURCE "capslock/capslock_win.cpp") +else() + list(APPEND PINENTRY_SOURCE "capslock/capslock_unix.cpp") +endif() + +add_library(gpgfrontend_pinentry SHARED ${PINENTRY_SOURCE}) + +target_link_libraries(gpgfrontend_pinentry PUBLIC gpgfrontend_core) + +# link Qt core +target_link_libraries(gpgfrontend_pinentry PUBLIC Qt6::Widgets) + +# spdlog +target_link_libraries(gpgfrontend_pinentry PRIVATE spdlog) + +# using std c++ 17 +target_compile_features(gpgfrontend_pinentry PUBLIC cxx_std_17) + +# link for different platforms +if (MINGW) + message(STATUS "Link GPG Static Library For MINGW") + target_link_libraries(gpgfrontend_pinentry PUBLIC wsock32) +elseif (APPLE) + message(STATUS "Link GPG Static Library For macOS") + target_link_libraries(gpgfrontend_pinentry PUBLIC dl) + if (XCODE_BUILD) + set_target_properties(gpgfrontend_pinentry + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + XCODE_ATTRIBUTE_SKIP_INSTALL "Yes" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}") + endif () +else () + # linux + message(STATUS "Link GPG Static Library For Unix") + target_link_libraries(gpgfrontend_pinentry PUBLIC pthread dl) +endif () diff --git a/src/pinentry/accessibility.cpp b/src/pinentry/accessibility.cpp new file mode 100644 index 00000000..f139832a --- /dev/null +++ b/src/pinentry/accessibility.cpp @@ -0,0 +1,44 @@ +/* accessibility.cpp - Helpers for making pinentry accessible + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "accessibility.h" + +#include <QString> +#include <QWidget> + +namespace Accessibility { + +void setDescription(QWidget *w, const QString &text) { + if (w) { +#ifndef QT_NO_ACCESSIBILITY + w->setAccessibleDescription(text); +#endif + } +} + +void setName(QWidget *w, const QString &text) { + if (w) { +#ifndef QT_NO_ACCESSIBILITY + w->setAccessibleName(text); +#endif + } +} + +} // namespace Accessibility diff --git a/src/pinentry/accessibility.h b/src/pinentry/accessibility.h new file mode 100644 index 00000000..9ef912d6 --- /dev/null +++ b/src/pinentry/accessibility.h @@ -0,0 +1,40 @@ +/* accessibility.h - Helpers for making pinentry accessible + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINENTRY_QT_ACCESSIBILITY_H__ +#define __PINENTRY_QT_ACCESSIBILITY_H__ + +class QString; +class QWidget; + +namespace Accessibility +{ + +/* Wrapper for QWidget::setAccessibleDescription which does nothing if + QT_NO_ACCESSIBILITY is defined. */ +void setDescription(QWidget *w, const QString &text); + +/* Wrapper for QWidget::setAccessibleName which does nothing if + QT_NO_ACCESSIBILITY is defined. */ +void setName(QWidget *w, const QString &text); + +} // namespace Accessibility + +#endif // __PINENTRY_QT_ACCESSIBILITY_H__ diff --git a/src/pinentry/capslock/capslock.cpp b/src/pinentry/capslock/capslock.cpp new file mode 100644 index 00000000..a730c220 --- /dev/null +++ b/src/pinentry/capslock/capslock.cpp @@ -0,0 +1,41 @@ +/* capslock.cpp - Helper to check whether Caps Lock is on + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <QDebug> +#include <QGuiApplication> + +#include "capslock.h" + +CapsLockWatcher::Private::Private(CapsLockWatcher *q) : q{q} { +#ifdef PINENTRY_QT_WAYLAND + if (qApp->platformName() == QLatin1String("wayland")) { + watchWayland(); + } +#endif +} + +CapsLockWatcher::CapsLockWatcher(QObject *parent) + : QObject{parent}, d{new Private{this}} { + if (qApp->platformName() == QLatin1String("wayland")) { +#ifndef PINENTRY_QT_WAYLAND + qWarning() << "CapsLockWatcher was compiled without support for Wayland"; +#endif + } +} diff --git a/src/pinentry/capslock/capslock.h b/src/pinentry/capslock/capslock.h new file mode 100644 index 00000000..138f88cc --- /dev/null +++ b/src/pinentry/capslock/capslock.h @@ -0,0 +1,77 @@ +/* capslock.h - Helper to check whether Caps Lock is on + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINENTRY_QT_CAPSLOCK_H__ +#define __PINENTRY_QT_CAPSLOCK_H__ + +#include <QObject> +#include <memory> + +enum class LockState { Unknown = -1, Off, On }; + +LockState capsLockState(); + +#ifdef PINENTRY_QT_WAYLAND +namespace KWayland { +namespace Client { +class Registry; +class Seat; +} // namespace Client +} // namespace KWayland +#endif + +class CapsLockWatcher : public QObject { + Q_OBJECT + + public: + explicit CapsLockWatcher(QObject *parent = nullptr); + + Q_SIGNALS: + void stateChanged(bool locked); + + private: + class Private; + std::unique_ptr<Private> d; +}; + +class CapsLockWatcher::Private { + public: + explicit Private(CapsLockWatcher *); +#ifdef PINENTRY_QT_WAYLAND + void watchWayland(); +#endif + + private: +#ifdef PINENTRY_QT_WAYLAND + void registry_seatAnnounced(quint32, quint32); + void seat_hasKeyboardChanged(bool); + void keyboard_modifiersChanged(quint32); +#endif + + private: + CapsLockWatcher *const q; + +#ifdef PINENTRY_QT_WAYLAND + KWayland::Client::Registry *registry = nullptr; + KWayland::Client::Seat *seat = nullptr; +#endif +}; + +#endif // __PINENTRY_QT_CAPSLOCK_H__ diff --git a/src/pinentry/capslock/capslock_unix.cpp b/src/pinentry/capslock/capslock_unix.cpp new file mode 100644 index 00000000..e4f4cd17 --- /dev/null +++ b/src/pinentry/capslock/capslock_unix.cpp @@ -0,0 +1,137 @@ +/* capslock_unix.cpp - Helper to check whether Caps Lock is on + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "capslock.h" + +#ifdef PINENTRY_QT_WAYLAND +#include <KWayland/Client/connection_thread.h> +#include <KWayland/Client/keyboard.h> +#include <KWayland/Client/registry.h> +#include <KWayland/Client/seat.h> +#endif + +#include <QGuiApplication> + +#ifdef PINENTRY_QT_X11 +#include <X11/XKBlib.h> + +#include <QX11Info> +#undef Status +#endif + +#include <QDebug> + +#ifdef PINENTRY_QT_WAYLAND +using namespace KWayland::Client; +#endif + +#ifdef PINENTRY_QT_WAYLAND +static bool watchingWayland = false; +#endif + +LockState capsLockState() { + static bool reportUnsupportedPlatform = true; +#ifdef PINENTRY_QT_X11 + if (qApp->platformName() == QLatin1String("xcb")) { + unsigned int state; + XkbGetIndicatorState(QX11Info::display(), XkbUseCoreKbd, &state); + return (state & 0x01) == 1 ? LockState::On : LockState::Off; + } +#endif +#ifdef PINENTRY_QT_WAYLAND + if (qApp->platformName() == QLatin1String("wayland")) { + if (!watchingWayland && reportUnsupportedPlatform) { + qDebug() << "Use CapsLockWatcher for checking for Caps Lock on Wayland"; + } + } else +#endif + if (reportUnsupportedPlatform) { + qWarning() << "Checking for Caps Lock not possible on unsupported platform:" + << qApp->platformName(); + } + reportUnsupportedPlatform = false; + return LockState::Unknown; +} + +#ifdef PINENTRY_QT_WAYLAND +void CapsLockWatcher::Private::watchWayland() { + watchingWayland = true; + auto connection = ConnectionThread::fromApplication(q); + if (!connection) { + qWarning() << "Failed to get connection to Wayland server from QPA"; + return; + } + registry = new Registry{q}; + registry->create(connection); + if (!registry->isValid()) { + qWarning() << "Failed to create valid KWayland registry"; + return; + } + registry->setup(); + + connect(registry, &Registry::seatAnnounced, q, + [this](quint32 name, quint32 version) { + registry_seatAnnounced(name, version); + }); +} + +void CapsLockWatcher::Private::registry_seatAnnounced(quint32 name, + quint32 version) { + Q_ASSERT(registry); + seat = registry->createSeat(name, version, q); + if (!seat->isValid()) { + qWarning() << "Failed to create valid KWayland seat"; + return; + } + + connect(seat, &Seat::hasKeyboardChanged, q, + [this](bool hasKeyboard) { seat_hasKeyboardChanged(hasKeyboard); }); +} + +void CapsLockWatcher::Private::seat_hasKeyboardChanged(bool hasKeyboard) { + Q_ASSERT(seat); + + if (!hasKeyboard) { + qDebug() << "Seat has no keyboard"; + return; + } + + auto keyboard = seat->createKeyboard(q); + if (!keyboard->isValid()) { + qWarning() << "Failed to create valid KWayland keyboard"; + return; + } + + connect(keyboard, &Keyboard::modifiersChanged, q, + [this](quint32, quint32, quint32 locked, quint32) { + keyboard_modifiersChanged(locked); + }); +} + +void CapsLockWatcher::Private::keyboard_modifiersChanged(quint32 locked) { + const bool capsLockIsLocked = (locked & 2u) != 0; + qDebug() << "Caps Lock is locked:" << capsLockIsLocked; + Q_EMIT q->stateChanged(capsLockIsLocked); +} +#endif diff --git a/src/pinentry/capslock/capslock_win.cpp b/src/pinentry/capslock/capslock_win.cpp new file mode 100644 index 00000000..46bc7043 --- /dev/null +++ b/src/pinentry/capslock/capslock_win.cpp @@ -0,0 +1,26 @@ +/* capslock_win.cpp - Helper to check whether Caps Lock is on + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <windows.h> + +#include "capslock.h" + +LockState capsLockState() { + return (GetKeyState(VK_CAPITAL) & 1) ? LockState::On : LockState::Off; +} diff --git a/src/pinentry/focusframe.cpp b/src/pinentry/focusframe.cpp new file mode 100644 index 00000000..c0c9f562 --- /dev/null +++ b/src/pinentry/focusframe.cpp @@ -0,0 +1,72 @@ +/* focusframe.cpp - A focus indicator for labels. + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "focusframe.h" + +#if QT_CONFIG(graphicseffect) +#include <QGraphicsEffect> +#endif +#include <QStyleOptionFocusRect> +#include <QStylePainter> + +static QRect effectiveWidgetRect(const QWidget *w) { + // based on QWidgetPrivate::effectiveRectFor +#if QT_CONFIG(graphicseffect) + const auto *const graphicsEffect = w->graphicsEffect(); + if (graphicsEffect && graphicsEffect->isEnabled()) + return graphicsEffect->boundingRectFor(w->rect()).toAlignedRect(); +#endif // QT_CONFIG(graphicseffect) + return w->rect(); +} + +static QRect clipRect(const QWidget *w) { + // based on QWidgetPrivate::clipRect + if (!w->isVisible()) { + return QRect(); + } + QRect r = effectiveWidgetRect(w); + int ox = 0; + int oy = 0; + while (w && w->isVisible() && !w->isWindow() && w->parentWidget()) { + ox -= w->x(); + oy -= w->y(); + w = w->parentWidget(); + r &= QRect(ox, oy, w->width(), w->height()); + } + return r; +} + +void FocusFrame::paintEvent(QPaintEvent *) { + if (!widget()) { + return; + } + + QStylePainter p{this}; + QStyleOptionFocusRect option; + initStyleOption(&option); + const int vmargin = + style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option); + const int hmargin = + style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option); + const QRect rect = + clipRect(widget()).adjusted(0, 0, hmargin * 2, vmargin * 2); + p.setClipRect(rect); + p.drawPrimitive(QStyle::PE_FrameFocusRect, option); +} diff --git a/src/pinentry/focusframe.h b/src/pinentry/focusframe.h new file mode 100644 index 00000000..3d2231ea --- /dev/null +++ b/src/pinentry/focusframe.h @@ -0,0 +1,36 @@ +/* focusframe.h - A focus indicator for labels. + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FOCUSFRAME_H__ +#define __FOCUSFRAME_H__ + +#include <QFocusFrame> + +class FocusFrame : public QFocusFrame +{ + Q_OBJECT +public: + using QFocusFrame::QFocusFrame; + +protected: + void paintEvent(QPaintEvent *event) override; +}; + +#endif // __FOCUSFRAME_H__ diff --git a/src/pinentry/keyboardfocusindication.cpp b/src/pinentry/keyboardfocusindication.cpp new file mode 100644 index 00000000..d783d981 --- /dev/null +++ b/src/pinentry/keyboardfocusindication.cpp @@ -0,0 +1,43 @@ +/* keyboardfocusindication.cpp - Helper for extended keyboard focus indication. + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "keyboardfocusindication.h" + +#include "focusframe.h" + +#include <QApplication> + +KeyboardFocusIndication::KeyboardFocusIndication(QObject *parent) + : QObject{parent} +{ + connect(qApp, &QApplication::focusChanged, this, &KeyboardFocusIndication::updateFocusFrame); +} + +void KeyboardFocusIndication::updateFocusFrame(QWidget *, QWidget *focusWidget) +{ + if (focusWidget && focusWidget->inherits("QLabel") && focusWidget->window()->testAttribute(Qt::WA_KeyboardFocusChange)) { + if (!focusFrame) { + focusFrame = new FocusFrame{focusWidget}; + } + focusFrame->setWidget(focusWidget); + } else if (focusFrame) { + focusFrame->setWidget(nullptr); + } +} diff --git a/src/pinentry/keyboardfocusindication.h b/src/pinentry/keyboardfocusindication.h new file mode 100644 index 00000000..e86a317e --- /dev/null +++ b/src/pinentry/keyboardfocusindication.h @@ -0,0 +1,42 @@ +/* keyboardfocusindication.h - Helper for extended keyboard focus indication. + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __KEYBOARDFOCUSINDICATION_H__ +#define __KEYBOARDFOCUSINDICATION_H__ + +#include <QObject> +#include <QPointer> +#include <QWidget> + +class FocusFrame; + +class KeyboardFocusIndication : public QObject +{ + Q_OBJECT +public: + KeyboardFocusIndication(QObject *parent); + +private: + void updateFocusFrame(QWidget *, QWidget *); + + QPointer<FocusFrame> focusFrame; +}; + +#endif // __KEYBOARDFOCUSINDICATION_H__ diff --git a/src/pinentry/pinentry.cpp b/src/pinentry/pinentry.cpp new file mode 100644 index 00000000..4a5f1408 --- /dev/null +++ b/src/pinentry/pinentry.cpp @@ -0,0 +1,926 @@ +/* pinentry.c - The PIN entry support library + * Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015, 2016, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY 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 of the License, or + * (at your option) any later version. + * + * PINENTRY 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef WINDOWS +#include <errno.h> +#endif +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#ifndef WINDOWS +#include <sys/utsname.h> +#endif +#ifndef WINDOWS +#include <locale.h> +#endif +#include <limits.h> +#ifdef WINDOWS +#include <windows.h> +#endif + +#include <assuan.h> + +#include "core/utils/MemoryUtils.h" +#include "pinentry.h" + +#ifdef WINDOWS +#define getpid() GetCurrentProcessId() +#endif + +/* Keep the name of our program here. */ +static char this_pgmname[50]; + +struct pinentry pinentry; + +static const char *flavor_flag; + +/* Because gtk_init removes the --display arg from the command lines + * and our command line parser is called after gtk_init (so that it + * does not see gtk specific options) we don't have a way to get hold + * of the --display option. Our solution is to remember --display in + * the call to pinentry_have_display and set it then in our + * parser. */ +static char *remember_display; + +static void pinentry_reset(int use_defaults) { + /* GPG Agent sets these options once when it starts the pinentry. + Don't reset them. */ + int grab = pinentry.grab; + char *ttyname = pinentry.ttyname; + char *ttytype = pinentry.ttytype_l; + char *ttyalert = pinentry.ttyalert; + char *lc_ctype = pinentry.lc_ctype; + char *lc_messages = pinentry.lc_messages; + int allow_external_password_cache = pinentry.allow_external_password_cache; + char *default_ok = pinentry.default_ok; + char *default_cancel = pinentry.default_cancel; + char *default_prompt = pinentry.default_prompt; + char *default_pwmngr = pinentry.default_pwmngr; + char *default_cf_visi = pinentry.default_cf_visi; + char *default_tt_visi = pinentry.default_tt_visi; + char *default_tt_hide = pinentry.default_tt_hide; + char *default_capshint = pinentry.default_capshint; + char *touch_file = pinentry.touch_file; + unsigned long owner_pid = pinentry.owner_pid; + int owner_uid = pinentry.owner_uid; + char *owner_host = pinentry.owner_host; + int constraints_enforce = pinentry.constraints_enforce; + char *constraints_hint_short = pinentry.constraints_hint_short; + char *constraints_hint_long = pinentry.constraints_hint_long; + char *constraints_error_title = pinentry.constraints_error_title; + + /* These options are set from the command line. Don't reset + them. */ + int debug = pinentry.debug; + char *display = pinentry.display; + int parent_wid = pinentry.parent_wid; + + pinentry_color_t color_fg = pinentry.color_fg; + int color_fg_bright = pinentry.color_fg_bright; + pinentry_color_t color_bg = pinentry.color_bg; + pinentry_color_t color_so = pinentry.color_so; + int color_so_bright = pinentry.color_so_bright; + pinentry_color_t color_ok = pinentry.color_ok; + int color_ok_bright = pinentry.color_ok_bright; + pinentry_color_t color_qualitybar = pinentry.color_qualitybar; + int color_qualitybar_bright = pinentry.color_qualitybar_bright; + + int timeout = pinentry.timeout; + + char *invisible_char = pinentry.invisible_char; + + /* Free any allocated memory. */ + if (use_defaults) { + free(pinentry.ttyname); + free(pinentry.ttytype_l); + free(pinentry.ttyalert); + free(pinentry.lc_ctype); + free(pinentry.lc_messages); + free(pinentry.default_ok); + free(pinentry.default_cancel); + free(pinentry.default_prompt); + free(pinentry.default_pwmngr); + free(pinentry.default_cf_visi); + free(pinentry.default_tt_visi); + free(pinentry.default_tt_hide); + free(pinentry.default_capshint); + free(pinentry.touch_file); + free(pinentry.owner_host); + free(pinentry.display); + free(pinentry.constraints_hint_short); + free(pinentry.constraints_hint_long); + free(pinentry.constraints_error_title); + } + + free(pinentry.title); + free(pinentry.description); + free(pinentry.error); + free(pinentry.prompt); + free(pinentry.ok); + free(pinentry.notok); + free(pinentry.cancel); + GpgFrontend::SecureFree(pinentry.pin); + free(pinentry.repeat_passphrase); + free(pinentry.repeat_error_string); + free(pinentry.quality_bar); + free(pinentry.quality_bar_tt); + free(pinentry.formatted_passphrase_hint); + free(pinentry.keyinfo); + free(pinentry.specific_err_info); + + /* Reset the pinentry structure. */ + memset(&pinentry, 0, sizeof(pinentry)); + + /* Restore options without a default we want to preserve. */ + pinentry.invisible_char = invisible_char; + + /* Restore other options or set defaults. */ + + if (use_defaults) { + /* Pinentry timeout in seconds. */ + pinentry.timeout = 60; + + /* Global grab. */ + pinentry.grab = 1; + + pinentry.color_fg = PINENTRY_COLOR_DEFAULT; + pinentry.color_fg_bright = 0; + pinentry.color_bg = PINENTRY_COLOR_DEFAULT; + pinentry.color_so = PINENTRY_COLOR_DEFAULT; + pinentry.color_so_bright = 0; + pinentry.color_ok = PINENTRY_COLOR_DEFAULT; + pinentry.color_ok_bright = 0; + pinentry.color_qualitybar = PINENTRY_COLOR_DEFAULT; + pinentry.color_qualitybar_bright = 0; + + pinentry.owner_uid = -1; + } else /* Restore the options. */ + { + pinentry.grab = grab; + pinentry.ttyname = ttyname; + pinentry.ttytype_l = ttytype; + pinentry.ttyalert = ttyalert; + pinentry.lc_ctype = lc_ctype; + pinentry.lc_messages = lc_messages; + pinentry.allow_external_password_cache = allow_external_password_cache; + pinentry.default_ok = default_ok; + pinentry.default_cancel = default_cancel; + pinentry.default_prompt = default_prompt; + pinentry.default_pwmngr = default_pwmngr; + pinentry.default_cf_visi = default_cf_visi; + pinentry.default_tt_visi = default_tt_visi; + pinentry.default_tt_hide = default_tt_hide; + pinentry.default_capshint = default_capshint; + pinentry.touch_file = touch_file; + pinentry.owner_pid = owner_pid; + pinentry.owner_uid = owner_uid; + pinentry.owner_host = owner_host; + pinentry.constraints_enforce = constraints_enforce; + pinentry.constraints_hint_short = constraints_hint_short; + pinentry.constraints_hint_long = constraints_hint_long; + pinentry.constraints_error_title = constraints_error_title; + + pinentry.debug = debug; + pinentry.display = display; + pinentry.parent_wid = parent_wid; + + pinentry.color_fg = color_fg; + pinentry.color_fg_bright = color_fg_bright; + pinentry.color_bg = color_bg; + pinentry.color_so = color_so; + pinentry.color_so_bright = color_so_bright; + pinentry.color_ok = color_ok; + pinentry.color_ok_bright = color_ok_bright; + pinentry.color_qualitybar = color_qualitybar; + pinentry.color_qualitybar_bright = color_qualitybar_bright; + + pinentry.timeout = timeout; + } +} + +static gpg_error_t pinentry_assuan_reset_handler(assuan_context_t ctx, + char *line) { + (void)ctx; + (void)line; + + pinentry_reset(0); + + return 0; +} + +/* Copy TEXT or TEXTLEN to BUFFER and escape as required. Return a + pointer to the end of the new buffer. Note that BUFFER must be + large enough to keep the entire text; allocataing it 3 times of + TEXTLEN is sufficient. */ +static char *copy_and_escape(char *buffer, const void *text, size_t textlen) { + int i; + const unsigned char *s = (unsigned char *)text; + char *p = buffer; + + for (i = 0; i < textlen; i++) { + if (s[i] < ' ' || s[i] == '+') { + snprintf(p, 4, "%%%02X", s[i]); + p += 3; + } else if (s[i] == ' ') + *p++ = '+'; + else + *p++ = s[i]; + } + return p; +} + +/* Perform percent unescaping in STRING and return the new valid length + of the string. A terminating Nul character is inserted at the end of + the unescaped string. + */ +static size_t do_unescape_inplace(char *s) { + unsigned char *p, *p0; + + p = p0 = (unsigned char *)s; + while (*s) { + if (*s == '%' && s[1] && s[2]) { + s++; + *p++ = xtoi_2(s); + s += 2; + } else + *p++ = *s++; + } + *p = 0; + + return (p - p0); +} + +/* Return a malloced copy of the commandline for PID. If this is not + * possible NULL is returned. */ +#ifndef WINDOWS +static char *get_cmdline(unsigned long pid) { + char buffer[200]; + FILE *fp; + size_t i, n; + + snprintf(buffer, sizeof buffer, "/proc/%lu/cmdline", pid); + + fp = fopen(buffer, "rb"); + if (!fp) return NULL; + n = fread(buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer - 1 && ferror(fp)) { + /* Some error occurred. */ + fclose(fp); + return NULL; + } + fclose(fp); + if (n == 0) return NULL; + /* Arguments are delimited by Nuls. We should do proper quoting but + * that can be a bit complicated, thus we simply replace the Nuls by + * spaces. */ + for (i = 0; i < n; i++) + if (!buffer[i] && i < n - 1) buffer[i] = ' '; + buffer[i] = 0; /* Make sure the last byte is the string terminator. */ + + return strdup(buffer); +} +#endif /*!WINDOWS*/ + +/* Atomically ask the kernel for information about process PID. + * Return a malloc'ed copy of the process name as long as the process + * uid matches UID. If it cannot determine that the process has uid + * UID, it returns NULL. + * + * This is not as informative as get_cmdline, but it verifies that the + * process does belong to the user in question. + */ +#ifndef WINDOWS +static char *get_pid_name_for_uid(unsigned long pid, int uid) { + char buffer[400]; + FILE *fp; + size_t end, n; + char *uidstr; + + snprintf(buffer, sizeof buffer, "/proc/%lu/status", pid); + + fp = fopen(buffer, "rb"); + if (!fp) return NULL; + n = fread(buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer - 1 && ferror(fp)) { + /* Some error occurred. */ + fclose(fp); + return NULL; + } + fclose(fp); + if (n == 0) return NULL; + buffer[n] = 0; + /* Fixme: Is it specified that "Name" is always the first line? For + * robustness I would prefer to have a real parser here. -wk */ + if (strncmp(buffer, "Name:\t", 6)) return NULL; + end = strcspn(buffer + 6, "\n") + 6; + buffer[end] = 0; + + /* check that uid matches what we expect */ + uidstr = strstr(buffer + end + 1, "\nUid:\t"); + if (!uidstr) return NULL; + if (atoi(uidstr + 6) != uid) return NULL; + + return strdup(buffer + 6); +} +#endif /*!WINDOWS*/ + +const char *pinentry_get_pgmname(void) { return this_pgmname; } + +/* Return a malloced string with the title. The caller mus free the + * string. If no title is available or the title string has an error + * NULL is returned. */ +char *pinentry_get_title(pinentry_t pe) { + char *title; + + if (pe->title) title = strdup(pe->title); +#ifndef WINDOWS + else if (pe->owner_pid) { + char buf[200]; + struct utsname utsbuf; + char *pidname = NULL; + char *cmdline = NULL; + + if (pe->owner_host && !uname(&utsbuf) && + !strcmp(utsbuf.nodename, pe->owner_host)) { + pidname = get_pid_name_for_uid(pe->owner_pid, pe->owner_uid); + if (pidname) cmdline = get_cmdline(pe->owner_pid); + } + + if (pe->owner_host && (cmdline || pidname)) + snprintf(buf, sizeof buf, "[%lu]@%s (%s)", pe->owner_pid, pe->owner_host, + cmdline ? cmdline : pidname); + else if (pe->owner_host) + snprintf(buf, sizeof buf, "[%lu]@%s", pe->owner_pid, pe->owner_host); + else + snprintf(buf, sizeof buf, "[%lu] <unknown host>", pe->owner_pid); + free(pidname); + free(cmdline); + title = strdup(buf); + } +#endif /*!WINDOWS*/ + else + title = strdup(this_pgmname); + + return title; +} + +/* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH + because not all backends might be able to return a proper + C-string.). Returns: A value between -100 and 100 to give an + estimate of the passphrase's quality. Negative values are use if + the caller won't even accept that passphrase. Note that we expect + just one data line which should not be escaped in any represent a + numeric signed decimal value. Extra data is currently ignored but + should not be send at all. */ +int pinentry_inq_quality(const QString &passphrase) { + int score = 0; + + score += std::min(40, static_cast<int>(passphrase.length()) * 2); + + bool has_upper = false; + bool has_lower = false; + bool has_digit = false; + bool has_special = false; + for (const auto ch : passphrase) { + if (ch.isUpper()) has_upper = true; + if (ch.isLower()) has_lower = true; + if (ch.isDigit()) has_digit = true; + if (!ch.isLetterOrNumber()) has_special = true; + } + + int const variety_count = + static_cast<int>(has_upper) + static_cast<int>(has_lower) + + static_cast<int>(has_digit) + static_cast<int>(has_special); + score += variety_count * 10; + + for (size_t i = 0; i < passphrase.length() - 1; ++i) { + if (passphrase[i] == passphrase[i + 1]) { + score -= 5; + } + } + + std::unordered_map<QChar, int> char_count; + for (const auto ch : passphrase) { + char_count[ch]++; + } + for (auto &p : char_count) { + if (p.second > 1) { + score -= (p.second - 1) * 3; + } + } + + QString const lower_password = passphrase.toLower(); + if (lower_password.contains("password") || + lower_password.contains("123456")) { + score -= 30; + } + + return std::max(-100, std::min(100, score)); +} + +/* Run a checkpin inquiry */ +char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase, + size_t length) { + assuan_context_t ctx = (assuan_context_t)pin->ctx_assuan; + const char prefix[] = "INQUIRE CHECKPIN "; + char *command; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) return 0; /* Can't run the callback. */ + + if (length > 300) + length = 300; /* Limit so that it definitely fits into an Assuan + line. */ + + command = + GpgFrontend::SecureMallocAsType<char>(strlen(prefix) + 3 * length + 1); + if (!command) return 0; + strcpy(command, prefix); + copy_and_escape(command + strlen(command), passphrase, length); + rc = assuan_write_line(ctx, command); + GpgFrontend::SecureFree(command); + if (rc) { + fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) { + do { + rc = assuan_read_line(ctx, &line, &linelen); + if (rc) { + fprintf(stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + return 0; + } + } while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && + (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' && + (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && + (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue; + gotvalue = 1; + value = strdup(line + 2); + } + + return value; +} + +/* Run a genpin inquiry */ +char *pinentry_inq_genpin(pinentry_t pin) { + assuan_context_t ctx = (assuan_context_t)pin->ctx_assuan; + const char prefix[] = "INQUIRE GENPIN"; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) return 0; /* Can't run the callback. */ + + rc = assuan_write_line(ctx, prefix); + if (rc) { + fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) { + do { + rc = assuan_read_line(ctx, &line, &linelen); + if (rc) { + fprintf(stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + free(value); + return 0; + } + } while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && + (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' && + (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && + (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue; + gotvalue = 1; + value = strdup(line + 2); + } + + return value; +} + +/* Try to make room for at least LEN bytes in the pinentry. Returns + new buffer on success and 0 on failure or when the old buffer is + sufficient. */ +char *pinentry_setbufferlen(pinentry_t pin, int len) { + char *newp; + + if (pin->pin_len) + assert(pin->pin); + else + assert(!pin->pin); + + if (len < 2048) len = 2048; + + if (len <= pin->pin_len) return pin->pin; + + newp = GpgFrontend::SecureReallocAsType<char>(pin->pin, len); + if (newp) { + pin->pin = newp; + pin->pin_len = len; + } else { + GpgFrontend::SecureFree(pin->pin); + pin->pin = 0; + pin->pin_len = 0; + } + return newp; +} + +static void pinentry_setbuffer_clear(pinentry_t pin) { + if (!pin->pin) { + assert(pin->pin_len == 0); + return; + } + + assert(pin->pin_len > 0); + + GpgFrontend::SecureFree(pin->pin); + pin->pin = NULL; + pin->pin_len = 0; +} + +/* passphrase better be alloced with secmem_alloc. */ +void pinentry_setbuffer_use(pinentry_t pin, char *passphrase, int len) { + if (!passphrase) { + assert(len == 0); + pinentry_setbuffer_clear(pin); + + return; + } + + if (passphrase && len == 0) len = strlen(passphrase) + 1; + + if (pin->pin) GpgFrontend::SecureFree(pin->pin); + + pin->pin = passphrase; + pin->pin_len = len; +} + +static struct assuan_malloc_hooks assuan_malloc_hooks = { + GpgFrontend::SecureMalloc, GpgFrontend::SecureRealloc, + GpgFrontend::SecureFree}; + +/* Initialize the secure memory subsystem, drop privileges and return. + Must be called early. */ +void pinentry_init(const char *pgmname) { + /* Store away our name. */ + if (strlen(pgmname) > sizeof this_pgmname - 2) abort(); + strcpy(this_pgmname, pgmname); + + gpgrt_check_version(NULL); + + assuan_set_malloc_hooks(&assuan_malloc_hooks); +} + +/* Simple test to check whether DISPLAY is set or the option --display + was given. Used to decide whether the GUI or curses should be + initialized. */ +int pinentry_have_display(int argc, char **argv) { + int found = 0; + + for (; argc; argc--, argv++) { + if (!strcmp(*argv, "--display")) { + if (argv[1] && !remember_display) { + remember_display = strdup(argv[1]); + if (!remember_display) { +#ifndef WINDOWS + fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); +#endif + exit(EXIT_FAILURE); + } + } + found = 1; + break; + } else if (!strncmp(*argv, "--display=", 10)) { + if (!remember_display) { + remember_display = strdup(*argv + 10); + if (!remember_display) { +#ifndef WINDOWS + fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); +#endif + exit(EXIT_FAILURE); + } + } + found = 1; + break; + } + } + +#ifndef WINDOWS + { + const char *s; + s = getenv("DISPLAY"); + if (s && *s) found = 1; + } +#endif + + return found; +} + +/* Print usage information and and provide strings for help. */ +static const char *my_strusage(int level) { + const char *p; + + switch (level) { + case 11: + p = this_pgmname; + break; + case 12: + p = "pinentry"; + break; + case 13: + p = 0; + break; + case 14: + p = "Copyright (C) 2023 Saturneric"; + break; + case 19: + p = "Please report bugs to <[email protected]>.\n"; + break; + case 1: + case 40: { + static char *str; + + if (!str) { + size_t n = 50 + strlen(this_pgmname); + str = static_cast<char *>(malloc(n)); + if (str) { + snprintf(str, n, "Usage: %s [options] (-h for help)", this_pgmname); + } + } + p = str; + } break; + case 41: + p = "Ask securely for a secret and print it to stdout."; + break; + + case 42: + p = "1"; /* Flag print 40 as part of 41. */ + break; + + default: + p = NULL; + break; + } + return p; +} + +char *parse_color(char *arg, pinentry_color_t *color_p, int *bright_p) { + static struct { + const char *name; + pinentry_color_t color; + } colors[] = { + {"none", PINENTRY_COLOR_NONE}, {"default", PINENTRY_COLOR_DEFAULT}, + {"black", PINENTRY_COLOR_BLACK}, {"red", PINENTRY_COLOR_RED}, + {"green", PINENTRY_COLOR_GREEN}, {"yellow", PINENTRY_COLOR_YELLOW}, + {"blue", PINENTRY_COLOR_BLUE}, {"magenta", PINENTRY_COLOR_MAGENTA}, + {"cyan", PINENTRY_COLOR_CYAN}, {"white", PINENTRY_COLOR_WHITE}}; + + int i; + char *new_arg; + pinentry_color_t color = PINENTRY_COLOR_DEFAULT; + + if (!arg) return NULL; + + new_arg = strchr(arg, ','); + if (new_arg) new_arg++; + + if (bright_p) { + const char *bname[] = {"bright-", "bright", "bold-", "bold"}; + + *bright_p = 0; + for (i = 0; i < sizeof(bname) / sizeof(bname[0]); i++) + if (!strncasecmp(arg, bname[i], strlen(bname[i]))) { + *bright_p = 1; + arg += strlen(bname[i]); + } + } + + for (i = 0; i < sizeof(colors) / sizeof(colors[0]); i++) + if (!strncasecmp(arg, colors[i].name, strlen(colors[i].name))) + color = colors[i].color; + + *color_p = color; + return new_arg; +} + +/* Set the optional flag used with getinfo. */ +void pinentry_set_flavor_flag(const char *string) { flavor_flag = string; } + +static gpg_error_t option_handler(assuan_context_t ctx, const char *key, + const char *value) { + (void)ctx; + + if (!strcmp(key, "no-grab") && !*value) + pinentry.grab = 0; + else if (!strcmp(key, "grab") && !*value) + pinentry.grab = 1; + else if (!strcmp(key, "debug-wait")) { +#ifndef WINDOWS + fprintf(stderr, "%s: waiting for debugger - my pid is %u ...\n", + this_pgmname, (unsigned int)getpid()); + sleep(*value ? atoi(value) : 5); + fprintf(stderr, "%s: ... okay\n", this_pgmname); +#endif + } else if (!strcmp(key, "display")) { + if (pinentry.display) free(pinentry.display); + pinentry.display = strdup(value); + if (!pinentry.display) return gpg_error_from_syserror(); + } else if (!strcmp(key, "ttyname")) { + if (pinentry.ttyname) free(pinentry.ttyname); + pinentry.ttyname = strdup(value); + if (!pinentry.ttyname) return gpg_error_from_syserror(); + } else if (!strcmp(key, "ttytype")) { + if (pinentry.ttytype_l) free(pinentry.ttytype_l); + pinentry.ttytype_l = strdup(value); + if (!pinentry.ttytype_l) return gpg_error_from_syserror(); + } else if (!strcmp(key, "ttyalert")) { + if (pinentry.ttyalert) free(pinentry.ttyalert); + pinentry.ttyalert = strdup(value); + if (!pinentry.ttyalert) return gpg_error_from_syserror(); + } else if (!strcmp(key, "lc-ctype")) { + if (pinentry.lc_ctype) free(pinentry.lc_ctype); + pinentry.lc_ctype = strdup(value); + if (!pinentry.lc_ctype) return gpg_error_from_syserror(); + } else if (!strcmp(key, "lc-messages")) { + if (pinentry.lc_messages) free(pinentry.lc_messages); + pinentry.lc_messages = strdup(value); + if (!pinentry.lc_messages) return gpg_error_from_syserror(); + } else if (!strcmp(key, "owner")) { + long along; + char *endp; + + free(pinentry.owner_host); + pinentry.owner_host = NULL; + pinentry.owner_uid = -1; + pinentry.owner_pid = 0; + + errno = 0; + along = strtol(value, &endp, 10); + if (along && !errno) { + pinentry.owner_pid = (unsigned long)along; + if (*endp) { + errno = 0; + if (*endp == '/') { /* we have a uid */ + endp++; + along = strtol(endp, &endp, 10); + if (along >= 0 && !errno) pinentry.owner_uid = (int)along; + } + if (endp) { + while (*endp == ' ') endp++; + if (*endp) { + pinentry.owner_host = strdup(endp); + for (endp = pinentry.owner_host; *endp && *endp != ' '; endp++) + ; + *endp = 0; + } + } + } + } + } else if (!strcmp(key, "parent-wid")) { + pinentry.parent_wid = atoi(value); + /* FIXME: Use strtol and add some error handling. */ + } else if (!strcmp(key, "touch-file")) { + if (pinentry.touch_file) free(pinentry.touch_file); + pinentry.touch_file = strdup(value); + if (!pinentry.touch_file) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-ok")) { + pinentry.default_ok = strdup(value); + if (!pinentry.default_ok) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-cancel")) { + pinentry.default_cancel = strdup(value); + if (!pinentry.default_cancel) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-prompt")) { + pinentry.default_prompt = strdup(value); + if (!pinentry.default_prompt) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-pwmngr")) { + pinentry.default_pwmngr = strdup(value); + if (!pinentry.default_pwmngr) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-cf-visi")) { + pinentry.default_cf_visi = strdup(value); + if (!pinentry.default_cf_visi) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-tt-visi")) { + pinentry.default_tt_visi = strdup(value); + if (!pinentry.default_tt_visi) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-tt-hide")) { + pinentry.default_tt_hide = strdup(value); + if (!pinentry.default_tt_hide) return gpg_error_from_syserror(); + } else if (!strcmp(key, "default-capshint")) { + pinentry.default_capshint = strdup(value); + if (!pinentry.default_capshint) return gpg_error_from_syserror(); + } else if (!strcmp(key, "allow-external-password-cache") && !*value) { + pinentry.allow_external_password_cache = 1; + pinentry.tried_password_cache = 0; + } else if (!strcmp(key, "allow-emacs-prompt") && !*value) { +#ifdef INSIDE_EMACS + pinentry_enable_emacs_cmd_handler(); +#endif + } else if (!strcmp(key, "invisible-char")) { + if (pinentry.invisible_char) free(pinentry.invisible_char); + pinentry.invisible_char = strdup(value); + if (!pinentry.invisible_char) return gpg_error_from_syserror(); + } else if (!strcmp(key, "formatted-passphrase") && !*value) { + pinentry.formatted_passphrase = 1; + } else if (!strcmp(key, "formatted-passphrase-hint")) { + if (pinentry.formatted_passphrase_hint) + free(pinentry.formatted_passphrase_hint); + pinentry.formatted_passphrase_hint = strdup(value); + if (!pinentry.formatted_passphrase_hint) return gpg_error_from_syserror(); + do_unescape_inplace(pinentry.formatted_passphrase_hint); + } else if (!strcmp(key, "constraints-enforce") && !*value) + pinentry.constraints_enforce = 1; + else if (!strcmp(key, "constraints-hint-short")) { + if (pinentry.constraints_hint_short) free(pinentry.constraints_hint_short); + pinentry.constraints_hint_short = strdup(value); + if (!pinentry.constraints_hint_short) return gpg_error_from_syserror(); + do_unescape_inplace(pinentry.constraints_hint_short); + } else if (!strcmp(key, "constraints-hint-long")) { + if (pinentry.constraints_hint_long) free(pinentry.constraints_hint_long); + pinentry.constraints_hint_long = strdup(value); + if (!pinentry.constraints_hint_long) return gpg_error_from_syserror(); + do_unescape_inplace(pinentry.constraints_hint_long); + } else if (!strcmp(key, "constraints-error-title")) { + if (pinentry.constraints_error_title) + free(pinentry.constraints_error_title); + pinentry.constraints_error_title = strdup(value); + if (!pinentry.constraints_error_title) return gpg_error_from_syserror(); + do_unescape_inplace(pinentry.constraints_error_title); + } else + return gpg_error(GPG_ERR_UNKNOWN_OPTION); + return 0; +} + +/* Note, that it is sufficient to allocate the target string D as + long as the source string S, i.e.: strlen(s)+1; */ +static void strcpy_escaped(char *d, const char *s) { + while (*s) { + if (*s == '%' && s[1] && s[2]) { + s++; + *d++ = xtoi_2(s); + s += 2; + } else + *d++ = *s++; + } + *d = 0; +} + +/* Return a staically allocated string with information on the mode, + * uid, and gid of DEVICE. On error "?" is returned if DEVICE is + * NULL, "-" is returned. */ +static const char *device_stat_string(const char *device) { +#ifdef HAVE_STAT + static char buf[40]; + struct stat st; + + if (!device || !*device) return "-"; + + if (stat(device, &st)) return "?"; /* Error */ + snprintf(buf, sizeof buf, "%lo/%lu/%lu", (unsigned long)st.st_mode, + (unsigned long)st.st_uid, (unsigned long)st.st_gid); + return buf; +#else + return "-"; +#endif +}
\ No newline at end of file diff --git a/src/pinentry/pinentry.h b/src/pinentry/pinentry.h new file mode 100644 index 00000000..80452e93 --- /dev/null +++ b/src/pinentry/pinentry.h @@ -0,0 +1,355 @@ +/* pinentry.h - The interface for the PIN entry support library. + * Copyright (C) 2002, 2003, 2010, 2015, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY 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 of the License, or + * (at your option) any later version. + * + * PINENTRY 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PINENTRY_H +#define PINENTRY_H + +#include <cstdint> + +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif + +typedef enum { + PINENTRY_COLOR_NONE, + PINENTRY_COLOR_DEFAULT, + PINENTRY_COLOR_BLACK, + PINENTRY_COLOR_RED, + PINENTRY_COLOR_GREEN, + PINENTRY_COLOR_YELLOW, + PINENTRY_COLOR_BLUE, + PINENTRY_COLOR_MAGENTA, + PINENTRY_COLOR_CYAN, + PINENTRY_COLOR_WHITE +} pinentry_color_t; + +struct pinentry { + /* The window title, or NULL. (Assuan: "SETTITLE TITLE".) */ + char *title; + /* The description to display, or NULL. (Assuan: "SETDESC + DESC".) */ + char *description; + /* The error message to display, or NULL. (Assuan: "SETERROR + MESSAGE".) */ + char *error; + /* The prompt to display, or NULL. (Assuan: "SETPROMPT + prompt".) */ + char *prompt; + /* The OK button text to display, or NULL. (Assuan: "SETOK + OK".) */ + char *ok; + /* The Not-OK button text to display, or NULL. This is the text for + the alternative option shown by the third button. (Assuan: + "SETNOTOK NOTOK".) */ + char *notok; + /* The Cancel button text to display, or NULL. (Assuan: "SETCANCEL + CANCEL".) */ + char *cancel; + + /* The buffer to store the secret into. */ + char *pin; + /* The length of the buffer. */ + int pin_len; + /* Whether the pin was read from an external cache (1) or entered by + the user (0). */ + int pin_from_cache; + + /* The name of the X display to use if X is available and supported. + (Assuan: "OPTION display DISPLAY".) */ + char *display; + /* The name of the terminal node to open if X not available or + supported. (Assuan: "OPTION ttyname TTYNAME".) */ + char *ttyname; + /* The type of the terminal. (Assuan: "OPTION ttytype TTYTYPE".) */ + char *ttytype_l; + /* Set the alert mode (none, beep or flash). */ + char *ttyalert; + /* The LC_CTYPE value for the terminal. (Assuan: "OPTION lc-ctype + LC_CTYPE".) */ + char *lc_ctype; + /* The LC_MESSAGES value for the terminal. (Assuan: "OPTION + lc-messages LC_MESSAGES".) */ + char *lc_messages; + + /* True if debug mode is requested. */ + int debug; + + /* The number of seconds before giving up while waiting for user input. */ + int timeout; + + /* True if caller should grab the keyboard. (Assuan: "OPTION grab" + or "OPTION no-grab".) */ + int grab; + + /* The PID of the owner or 0 if not known. The owner is the process + * which actually triggered the the pinentry. For example gpg. */ + unsigned long owner_pid; + + /* The numeric uid (user ID) of the owner process or -1 if not + * known. */ + int owner_uid; + + /* The malloced hostname of the owner or NULL. */ + char *owner_host; + + /* The window ID of the parent window over which the pinentry window + should be displayed. (Assuan: "OPTION parent-wid WID".) */ + int parent_wid; + + /* The name of an optional file which will be touched after a curses + entry has been displayed. (Assuan: "OPTION touch-file + FILENAME".) */ + char *touch_file; + + /* The frontend should set this to -1 if the user canceled the + request, and to the length of the PIN stored in pin + otherwise. */ + int result; + + /* The frontend should set this if the NOTOK button was pressed. */ + int canceled; + + /* The frontend should set this to true if an error with the local + conversion occurred. */ + int locale_err; + + /* The frontend should set this to a gpg-error so that commands are + able to return specific error codes. This is an ugly hack due to + the fact that pinentry_cmd_handler_t returns the length of the + passphrase or a negative error code. */ + int specific_err; + + /* The frontend may store a string with the error location here. */ + const char *specific_err_loc; + + /* The frontend may store a malloced string here to emit an ERROR + * status code with this extra info along with SPECIFIC_ERR. */ + char *specific_err_info; + + /* The frontend should set this to true if the window close button + has been used. This flag is used in addition to a regular return + value. */ + int close_button; + + /* The caller should set this to true if only one button is + required. This is useful for notification dialogs where only a + dismiss button is required. */ + int one_button; + + /* Whether this is a CONFIRM pinentry. */ + int confirm; + + /* If true a second prompt for the passphrase is shown and the user + is expected to enter the same passphrase again. Pinentry checks + that both match. (Assuan: "SETREPEAT".) */ + char *repeat_passphrase; + + /* The string to show if a repeated passphrase does not match. + (Assuan: "SETREPEATERROR ERROR".) */ + char *repeat_error_string; + + /* The string to show if a repeated passphrase does match. + (Assuan: "SETREPEATOK STRING".) */ + char *repeat_ok_string; + + /* Set to true if the passphrase has been entered a second time and + matches the first passphrase. */ + int repeat_okay; + + /* If this is not NULL, a passphrase quality indicator is shown. + There will also be an inquiry back to the caller to get an + indication of the quality for the passphrase entered so far. The + string is used as a label for the quality bar. (Assuan: + "SETQUALITYBAR LABEL".) */ + char *quality_bar; + + /* The tooltip to be shown for the qualitybar. Malloced or NULL. + (Assuan: "SETQUALITYBAR_TT TOOLTIP".) */ + char *quality_bar_tt; + + /* If this is not NULL, a generate action should be shown. + There will be an inquiry back to the caller to get such a + PIN. generate action. Malloced or NULL. + (Assuan: "SETGENPIN LABEL" .) */ + char *genpin_label; + + /* The tooltip to be shown for the generate action. Malloced or NULL. + (Assuan: "SETGENPIN_TT TOOLTIP".) */ + char *genpin_tt; + + /* Specifies whether passphrase formatting should be enabled. + (Assuan: "OPTION formatted-passphrase") */ + int formatted_passphrase; + + /* A hint to be shown near the passphrase input field if passphrase + formatting is enabled. Malloced or NULL. + (Assuan: "OPTION formatted-passphrase-hint=HINT".) */ + char *formatted_passphrase_hint; + + /* For the curses pinentry, the color of error messages. */ + pinentry_color_t color_fg; + int color_fg_bright; + pinentry_color_t color_bg; + pinentry_color_t color_so; + int color_so_bright; + pinentry_color_t color_ok; + int color_ok_bright; + pinentry_color_t color_qualitybar; + int color_qualitybar_bright; + + /* Malloced and i18ned default strings or NULL. These strings may + include an underscore character to indicate an accelerator key. + A double underscore represents a plain one. */ + /* (Assuan: "OPTION default-ok OK"). */ + char *default_ok; + /* (Assuan: "OPTION default-cancel CANCEL"). */ + char *default_cancel; + /* (Assuan: "OPTION default-prompt PROMPT"). */ + char *default_prompt; + /* (Assuan: "OPTION default-pwmngr + SAVE_PASSWORD_WITH_PASSWORD_MANAGER?"). */ + char *default_pwmngr; + /* (Assuan: "OPTION default-cf-visi + Do you really want to make your passphrase visible?"). */ + char *default_cf_visi; + /* (Assuan: "OPTION default-tt-visi + Make passphrase visible?"). */ + char *default_tt_visi; + /* (Assuan: "OPTION default-tt-hide + Hide passphrase"). */ + char *default_tt_hide; + /* (Assuan: "OPTION default-capshint + Caps Lock is on"). */ + char *default_capshint; + + /* Whether we are allowed to read the password from an external + cache. (Assuan: "OPTION allow-external-password-cache") */ + int allow_external_password_cache; + + /* We only try the cache once. */ + int tried_password_cache; + + /* A stable identifier for the key. (Assuan: "SETKEYINFO + KEYINFO".) */ + char *keyinfo; + + /* Whether we may cache the password (according to the user). */ + int may_cache_password; + + /* NOTE: If you add any additional fields to this structure, be sure + to update the initializer in pinentry/pinentry.c!!! */ + + /* For the quality indicator and genpin we need to do an inquiry. + Thus we need to save the assuan ctx. */ + void *ctx_assuan; + + /* An UTF-8 string with an invisible character used to override the + default in some pinentries. Only the first character is + used. */ + char *invisible_char; + + /* Whether the passphrase constraints are enforced by gpg-agent. + (Assuan: "OPTION constraints-enforce") */ + int constraints_enforce; + + /* A short translated hint for the user with the constraints for new + passphrases to be displayed near the passphrase input field. + Malloced or NULL. + (Assuan: "OPTION constraints-hint-short=At least 8 characters".) */ + char *constraints_hint_short; + + /* A longer translated hint for the user with the constraints for new + passphrases to be displayed for example as tooltip. Malloced or NULL. + (Assuan: "OPTION constraints-hint-long=The passphrase must ...".) */ + char *constraints_hint_long; + + /* A short translated title for an error dialog informing the user about + unsatisfied passphrase constraints. Malloced or NULL. + (Assuan: "OPTION constraints-error-title=Passphrase Not Allowed".) */ + char *constraints_error_title; +}; +typedef struct pinentry *pinentry_t; + +/* The pinentry command handler type processes the pinentry request + PIN. If PIN->pin is zero, request a confirmation, otherwise a PIN + entry. On confirmation, the function should return TRUE if + confirmed, and FALSE otherwise. On PIN entry, the function should + return -1 if an error occurred or the user cancelled the operation + and 1 otherwise. */ +typedef int (*pinentry_cmd_handler_t)(pinentry_t pin); + +const char *pinentry_get_pgmname(void); + +char *pinentry_get_title(pinentry_t pe); + +/* Run a quality inquiry for PASSPHRASE of LENGTH. */ +int pinentry_inq_quality(const QString &passphrase); + +/* Run a checkpin inquiry for PASSPHRASE of LENGTH. Returns NULL, if the + passphrase satisfies the constraints. Otherwise, returns a malloced error + string. */ +char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase, + std::size_t length); + +/* Run a genpin iquriry. Returns a malloced string or NULL */ +char *pinentry_inq_genpin(pinentry_t pin); + +/* Try to make room for at least LEN bytes for the pin in the pinentry + PIN. Returns new buffer on success and 0 on failure. */ +char *pinentry_setbufferlen(pinentry_t pin, int len); + +/* Use the buffer at BUFFER for PIN->PIN. BUFFER must be NULL or + allocated using secmem_alloc. LEN is the size of the buffer. If + it is unknown, but BUFFER is a NUL terminated string, you pass 0 to + just use strlen(buffer)+1. */ +void pinentry_setbuffer_use(pinentry_t pin, char *buffer, int len); + +/* Initialize the secure memory subsystem, drop privileges and + return. Must be called early. */ +void pinentry_init(const char *pgmname); + +/* Return true if either DISPLAY is set or ARGV contains the string + "--display". */ +int pinentry_have_display(int argc, char **argv); + +/* Parse the command line options. May exit the program if only help + or version output is requested. */ +void pinentry_parse_opts(int argc, char *argv[]); + +/* Set the optional flag used with getinfo. */ +void pinentry_set_flavor_flag(const char *string); + +#ifdef WINDOWS +/* Windows declares sleep as obsolete, but provides a definition for + _sleep but non for the still existing sleep. */ +#define sleep(a) _sleep((a)) +#endif /*WINDOWS*/ + +#if 0 +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* PINENTRY_H */ diff --git a/src/pinentry/pinentry_debug.cpp b/src/pinentry/pinentry_debug.cpp new file mode 100644 index 00000000..9afbcdb3 --- /dev/null +++ b/src/pinentry/pinentry_debug.cpp @@ -0,0 +1,31 @@ +/* pinentry_debug.h - Logging category for pinentry + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "pinentry_debug.h" + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) +Q_LOGGING_CATEGORY(PINENTRY_LOG, "gpg.pinentry", QtWarningMsg) +#else +Q_LOGGING_CATEGORY(PINENTRY_LOG, "gpg.pinentry") +#endif diff --git a/src/pinentry/pinentry_debug.h b/src/pinentry/pinentry_debug.h new file mode 100644 index 00000000..fc8c808a --- /dev/null +++ b/src/pinentry/pinentry_debug.h @@ -0,0 +1,28 @@ +/* pinentry_debug.h - Logging category for pinentry + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINENTRY_QT_DEBUG_H__ +#define __PINENTRY_QT_DEBUG_H__ + +#include <QLoggingCategory> + +Q_DECLARE_LOGGING_CATEGORY(PINENTRY_LOG) + +#endif // __PINENTRY_QT_DEBUG_H__ diff --git a/src/pinentry/pinentryconfirm.cpp b/src/pinentry/pinentryconfirm.cpp new file mode 100644 index 00000000..31d55b5c --- /dev/null +++ b/src/pinentry/pinentryconfirm.cpp @@ -0,0 +1,123 @@ +/* pinentryconfirm.cpp - A QMessageBox with a timeout + * + * Copyright (C) 2011 Ben Kibbey <[email protected]> + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "pinentryconfirm.h" + +#include <QAbstractButton> +#include <QApplication> +#include <QFontMetrics> +#include <QGridLayout> +#include <QLabel> +#include <QSpacerItem> + +#include "accessibility.h" +#include "pinentrydialog.h" + +namespace { +QLabel *messageBoxLabel(QMessageBox *messageBox) { + return messageBox->findChild<QLabel *>(QStringLiteral("qt_msgbox_label")); +} +} // namespace + +PinentryConfirm::PinentryConfirm(Icon icon, const QString &title, + const QString &text, StandardButtons buttons, + QWidget *parent, Qt::WindowFlags flags) + : QMessageBox{icon, title, text, buttons, parent, flags} { + _timer.callOnTimeout(this, &PinentryConfirm::slotTimeout); + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::installActivationObserver(this); + accessibilityActiveChanged(QAccessible::isActive()); +#endif + +#if QT_VERSION >= 0x050000 + /* This is in line with PinentryDialog ctor to have a maximizing + * animation when opening. */ + if (qApp->platformName() != QLatin1String("wayland")) { + setWindowState(Qt::WindowMinimized); + QTimer::singleShot(0, this, [this]() { raiseWindow(this); }); + } +#else + activateWindow(); + raise(); +#endif +} + +PinentryConfirm::~PinentryConfirm() { +#ifndef QT_NO_ACCESSIBILITY + QAccessible::removeActivationObserver(this); +#endif +} + +void PinentryConfirm::setTimeout(std::chrono::seconds timeout) { + _timer.setInterval(timeout); +} + +std::chrono::seconds PinentryConfirm::timeout() const { + return std::chrono::duration_cast<std::chrono::seconds>( + _timer.intervalAsDuration()); +} + +bool PinentryConfirm::timedOut() const { return _timed_out; } + +void PinentryConfirm::showEvent(QShowEvent *event) { + static bool resized; + if (!resized) { + QGridLayout *lay = dynamic_cast<QGridLayout *>(layout()); + if (lay) { + QSize textSize = fontMetrics().size(Qt::TextExpandTabs, text(), + fontMetrics().maxWidth()); + QSpacerItem *horizontalSpacer = + new QSpacerItem(textSize.width() + iconPixmap().width(), 0, + QSizePolicy::Minimum, QSizePolicy::Expanding); + lay->addItem(horizontalSpacer, lay->rowCount(), 1, 1, + lay->columnCount() - 1); + } + resized = true; + } + + QMessageBox::showEvent(event); + + if (timeout() > std::chrono::milliseconds::zero()) { + _timer.setSingleShot(true); + _timer.start(); + } +} + +void PinentryConfirm::slotTimeout() { + QAbstractButton *b = button(QMessageBox::Cancel); + _timed_out = true; + + if (b) { + b->animateClick(); + } +} + +#ifndef QT_NO_ACCESSIBILITY +void PinentryConfirm::accessibilityActiveChanged(bool active) { + // Allow text label to get focus if accessibility is active + const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus; + if (auto label = messageBoxLabel(this)) { + label->setFocusPolicy(focusPolicy); + } +} +#endif diff --git a/src/pinentry/pinentryconfirm.h b/src/pinentry/pinentryconfirm.h new file mode 100644 index 00000000..7be7c268 --- /dev/null +++ b/src/pinentry/pinentryconfirm.h @@ -0,0 +1,63 @@ +/* pinentryconfirm.h - A QMessageBox with a timeout + * + * Copyright (C) 2011 Ben Kibbey <[email protected]> + * Copyright (C) 2022 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PINENTRYCONFIRM_H +#define PINENTRYCONFIRM_H + +#include <QAccessible> +#include <QMessageBox> +#include <QTimer> + +class PinentryConfirm : public QMessageBox +#ifndef QT_NO_ACCESSIBILITY + , public QAccessible::ActivationObserver +#endif +{ + Q_OBJECT +public: + PinentryConfirm(Icon icon, const QString &title, const QString &text, + StandardButtons buttons = NoButton, QWidget *parent = nullptr, + Qt::WindowFlags flags = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); + ~PinentryConfirm() override; + + void setTimeout(std::chrono::seconds timeout); + std::chrono::seconds timeout() const; + + bool timedOut() const; + +protected: + void showEvent(QShowEvent *event) override; + +private Q_SLOTS: + void slotTimeout(); + +private: +#ifndef QT_NO_ACCESSIBILITY + void accessibilityActiveChanged(bool active) override; +#endif + +private: + QTimer _timer; + bool _timed_out = false; +}; + +#endif diff --git a/src/pinentry/pinentrydialog.cpp b/src/pinentry/pinentrydialog.cpp new file mode 100644 index 00000000..a8d85455 --- /dev/null +++ b/src/pinentry/pinentrydialog.cpp @@ -0,0 +1,691 @@ +/* pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry. + * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) + * Copyright 2007 Ingo Klöcker + * Copyright 2016 Intevation GmbH + * Copyright (C) 2021, 2022 g10 Code GmbH + * + * Written by Steffen Hansen <[email protected]>. + * Modified by Andre Heinecke <[email protected]> + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "pinentrydialog.h" + +#include <qnamespace.h> + +#include <QAccessible> +#include <QAction> +#include <QApplication> +#include <QCheckBox> +#include <QDebug> +#include <QDialogButtonBox> +#include <QFontMetrics> +#include <QGridLayout> +#include <QHBoxLayout> +#include <QKeyEvent> +#include <QLabel> +#include <QLineEdit> +#include <QMessageBox> +#include <QPainter> +#include <QPalette> +#include <QProgressBar> +#include <QPushButton> +#include <QRegularExpression> +#include <QStyle> +#include <QVBoxLayout> + +#include "accessibility.h" +#include "capslock/capslock.h" +#include "core/utils/MemoryUtils.h" +#include "pinentry.h" +#include "pinlineedit.h" +#include "util.h" + +#ifdef Q_OS_WIN +#include <windows.h> +#if QT_VERSION >= 0x050700 +#include <QtPlatformHeaders/QWindowsWindowFunctions> +#endif +#endif + +void raiseWindow(QWidget *w) { +#ifdef Q_OS_WIN +#if QT_VERSION >= 0x050700 + QWindowsWindowFunctions::setWindowActivationBehavior( + QWindowsWindowFunctions::AlwaysActivateWindow); +#endif +#endif + w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | + Qt::WindowActive); + w->activateWindow(); + w->raise(); +} + +QPixmap applicationIconPixmap(const QIcon &overlayIcon) { + QPixmap pm = qApp->windowIcon().pixmap(48, 48); + + if (!overlayIcon.isNull()) { + QPainter painter(&pm); + const int emblemSize = 22; + painter.drawPixmap(pm.width() - emblemSize, 0, + overlayIcon.pixmap(emblemSize, emblemSize)); + } + + return pm; +} + +void PinEntryDialog::slotTimeout() { + _timed_out = true; + reject(); +} + +PinEntryDialog::PinEntryDialog(QWidget *parent, const char *name, int timeout, + bool modal, bool enable_quality_bar, + const QString &repeatString, + const QString &visibilityTT, + const QString &hideTT) + : QDialog{parent}, + _have_quality_bar{enable_quality_bar}, + mVisibilityTT{visibilityTT}, + mHideTT{hideTT} { + Q_UNUSED(name) + + if (modal) { + setWindowModality(Qt::ApplicationModal); + setModal(true); + } + + QPalette red_text_palette; + red_text_palette.setColor(QPalette::WindowText, Qt::red); + + auto *const main_layout = new QVBoxLayout{this}; + + auto *const hbox = new QHBoxLayout; + + _icon = new QLabel(this); + _icon->setPixmap(applicationIconPixmap()); + hbox->addWidget(_icon, 0, Qt::AlignVCenter | Qt::AlignLeft); + + auto *const grid = new QGridLayout; + int row = 1; + + _error = new QLabel{this}; + _error->setTextFormat(Qt::PlainText); + _error->setTextInteractionFlags(Qt::TextSelectableByMouse); + _error->setPalette(red_text_palette); + _error->hide(); + grid->addWidget(_error, row, 1, 1, 2); + + row++; + _desc = new QLabel{this}; + _desc->setTextFormat(Qt::PlainText); + _desc->setTextInteractionFlags(Qt::TextSelectableByMouse); + _desc->hide(); + grid->addWidget(_desc, row, 1, 1, 2); + + row++; + mCapsLockHint = new QLabel{this}; + mCapsLockHint->setTextFormat(Qt::PlainText); + mCapsLockHint->setTextInteractionFlags(Qt::TextSelectableByMouse); + mCapsLockHint->setPalette(red_text_palette); + mCapsLockHint->setAlignment(Qt::AlignCenter); + mCapsLockHint->setVisible(false); + grid->addWidget(mCapsLockHint, row, 1, 1, 2); + + row++; + { + _prompt = new QLabel(this); + _prompt->setTextFormat(Qt::PlainText); + _prompt->setTextInteractionFlags(Qt::TextSelectableByMouse); + _prompt->hide(); + grid->addWidget(_prompt, row, 1); + + auto *const l = new QHBoxLayout; + _edit = new PinLineEdit(this); + _edit->setMaxLength(256); + _edit->setMinimumWidth(_edit->fontMetrics().averageCharWidth() * 20 + 48); + _edit->setEchoMode(QLineEdit::Password); + _prompt->setBuddy(_edit); + l->addWidget(_edit, 1); + + if (!repeatString.isNull()) { + mGenerateButton = new QPushButton{this}; + mGenerateButton->setIcon(QIcon(QLatin1String(":password-generate.svg"))); + mGenerateButton->setVisible(false); + l->addWidget(mGenerateButton); + } + grid->addLayout(l, row, 2); + } + + /* Set up the show password action */ + const QIcon visibility_icon = QIcon(QLatin1String(":visibility.svg")); + const QIcon hide_icon = QIcon(QLatin1String(":hint.svg")); +#if QT_VERSION >= 0x050200 + if (!visibility_icon.isNull() && !hide_icon.isNull()) { + mVisiActionEdit = + _edit->addAction(visibility_icon, QLineEdit::TrailingPosition); + mVisiActionEdit->setVisible(false); + mVisiActionEdit->setToolTip(mVisibilityTT); + } else +#endif + { + if (!mVisibilityTT.isNull()) { + row++; + mVisiCB = new QCheckBox{mVisibilityTT, this}; + grid->addWidget(mVisiCB, row, 1, 1, 2, Qt::AlignLeft); + } + } + + row++; + mConstraintsHint = new QLabel{this}; + mConstraintsHint->setTextFormat(Qt::PlainText); + mConstraintsHint->setTextInteractionFlags(Qt::TextSelectableByMouse); + mConstraintsHint->setVisible(false); + grid->addWidget(mConstraintsHint, row, 2); + + row++; + mFormattedPassphraseHintSpacer = new QLabel{this}; + mFormattedPassphraseHintSpacer->setVisible(false); + mFormattedPassphraseHint = new QLabel{this}; + mFormattedPassphraseHint->setTextFormat(Qt::PlainText); + mFormattedPassphraseHint->setTextInteractionFlags(Qt::TextSelectableByMouse); + mFormattedPassphraseHint->setVisible(false); + grid->addWidget(mFormattedPassphraseHintSpacer, row, 1); + grid->addWidget(mFormattedPassphraseHint, row, 2); + + if (!repeatString.isNull()) { + row++; + auto *repeat_label = new QLabel{this}; + repeat_label->setTextFormat(Qt::PlainText); + repeat_label->setTextInteractionFlags(Qt::TextSelectableByMouse); + repeat_label->setText(repeatString); + grid->addWidget(repeat_label, row, 1); + + mRepeat = new PinLineEdit(this); + mRepeat->setMaxLength(256); + mRepeat->setEchoMode(QLineEdit::Password); + repeat_label->setBuddy(mRepeat); + grid->addWidget(mRepeat, row, 2); + + row++; + mRepeatError = new QLabel{this}; + mRepeatError->setTextFormat(Qt::PlainText); + mRepeatError->setTextInteractionFlags(Qt::TextSelectableByMouse); + mRepeatError->setPalette(red_text_palette); + mRepeatError->hide(); + grid->addWidget(mRepeatError, row, 2); + } + + if (enable_quality_bar) { + row++; + _quality_bar_label = new QLabel(this); + _quality_bar_label->setTextFormat(Qt::PlainText); + _quality_bar_label->setTextInteractionFlags(Qt::TextSelectableByMouse); + _quality_bar_label->setAlignment(Qt::AlignVCenter); + grid->addWidget(_quality_bar_label, row, 1); + + _quality_bar = new QProgressBar(this); + _quality_bar->setAlignment(Qt::AlignCenter); + _quality_bar_label->setBuddy(_quality_bar); + grid->addWidget(_quality_bar, row, 2); + } + + hbox->addLayout(grid, 1); + main_layout->addLayout(hbox); + + auto *const buttons = new QDialogButtonBox(this); + buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + _ok = buttons->button(QDialogButtonBox::Ok); + _cancel = buttons->button(QDialogButtonBox::Cancel); + + if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) { + _ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton)); + _cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton)); + } + + main_layout->addStretch(1); + main_layout->addWidget(buttons); + main_layout->setSizeConstraint(QLayout::SetFixedSize); + + if (timeout > 0) { + _timer = new QTimer(this); + connect(_timer, &QTimer::timeout, this, &PinEntryDialog::slotTimeout); + _timer->start(timeout * 1000); + } + + connect(buttons, &QDialogButtonBox::accepted, this, + &PinEntryDialog::onAccept); + connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(_edit, &QLineEdit::textChanged, this, &PinEntryDialog::updateQuality); + connect(_edit, &QLineEdit::textChanged, this, &PinEntryDialog::textChanged); + connect(_edit, &PinLineEdit::backspacePressed, this, + &PinEntryDialog::onBackspace); + if (mGenerateButton != nullptr) { + connect(mGenerateButton, &QPushButton::clicked, this, + &PinEntryDialog::generatePin); + } + if (mVisiActionEdit != nullptr) { + connect(mVisiActionEdit, &QAction::triggered, this, + &PinEntryDialog::toggleVisibility); + } + if (mVisiCB != nullptr) { + connect(mVisiCB, &QCheckBox::toggled, this, + &PinEntryDialog::toggleVisibility); + } + if (mRepeat != nullptr) { + connect(mRepeat, &QLineEdit::textChanged, this, + &PinEntryDialog::textChanged); + } + + auto *caps_lock_watcher = new CapsLockWatcher{this}; + connect(caps_lock_watcher, &CapsLockWatcher::stateChanged, this, + [this](bool locked) { mCapsLockHint->setVisible(locked); }); + + connect(qApp, &QApplication::focusChanged, this, + &PinEntryDialog::focusChanged); + connect(qApp, &QApplication::applicationStateChanged, this, + &PinEntryDialog::checkCapsLock); + checkCapsLock(); + + setAttribute(Qt::WA_DeleteOnClose); + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + + /* This is mostly an issue on Windows where this results + in the pinentry popping up nicely with an animation and + comes to front. It is not ifdefed for Windows only since + window managers on Linux like KWin can also have this + result in an animation when the pinentry is shown and + not just popping it up. + */ + if (qApp->platformName() != QLatin1String("wayland")) { + setWindowState(Qt::WindowMinimized); + QTimer::singleShot(0, this, [this]() { raiseWindow(this); }); + } else { + raiseWindow(this); + } +} + +void PinEntryDialog::keyPressEvent(QKeyEvent *e) { + const auto return_pressed = + (!e->modifiers() && + (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)) || + (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter); + if (return_pressed && _edit->hasFocus() && (mRepeat != nullptr)) { + // if the user pressed Return in the first input field, then move the + // focus to the repeat input field and prevent further event processing + // by QDialog (which would trigger the default button) + mRepeat->setFocus(); + e->ignore(); + return; + } + + QDialog::keyPressEvent(e); +} + +void PinEntryDialog::keyReleaseEvent(QKeyEvent *event) { + QDialog::keyReleaseEvent(event); + checkCapsLock(); +} + +void PinEntryDialog::showEvent(QShowEvent *event) { + QDialog::showEvent(event); + _edit->setFocus(); +} + +void PinEntryDialog::setDescription(const QString &txt) { + _desc->setVisible(!txt.isEmpty()); + _desc->setText(txt); + _icon->setPixmap(applicationIconPixmap()); + setError(QString()); +} + +QString PinEntryDialog::description() const { return _desc->text(); } + +void PinEntryDialog::setError(const QString &txt) { + if (!txt.isNull()) { + _icon->setPixmap( + applicationIconPixmap(QIcon{QStringLiteral(":data-error.svg")})); + } + _error->setText(txt); + _error->setVisible(!txt.isEmpty()); +} + +QString PinEntryDialog::error() const { return _error->text(); } + +void PinEntryDialog::setPin(const QString &txt) { _edit->setPin(txt); } + +QString PinEntryDialog::pin() const { return _edit->pin(); } + +void PinEntryDialog::setPrompt(const QString &txt) { + _prompt->setText(txt); + _prompt->setVisible(!txt.isEmpty()); + if (txt.contains("PIN")) _disable_echo_allowed = false; +} + +QString PinEntryDialog::prompt() const { return _prompt->text(); } + +void PinEntryDialog::setOkText(const QString &txt) { + _ok->setText(txt); + _ok->setVisible(!txt.isEmpty()); +} + +void PinEntryDialog::setCancelText(const QString &txt) { + _cancel->setText(txt); + _cancel->setVisible(!txt.isEmpty()); +} + +void PinEntryDialog::setQualityBar(const QString &txt) { + if (_have_quality_bar) { + _quality_bar_label->setText(txt); + } +} + +void PinEntryDialog::setQualityBarTT(const QString &txt) { + if (_have_quality_bar) { + _quality_bar->setToolTip(txt); + } +} + +void PinEntryDialog::setGenpinLabel(const QString &txt) { + if (mGenerateButton == nullptr) { + return; + } + mGenerateButton->setVisible(!txt.isEmpty()); + if (!txt.isEmpty()) { + Accessibility::setName(mGenerateButton, txt); + } +} + +void PinEntryDialog::setGenpinTT(const QString &txt) { + if (mGenerateButton != nullptr) { + mGenerateButton->setToolTip(txt); + } +} + +void PinEntryDialog::setCapsLockHint(const QString &txt) { + mCapsLockHint->setText(txt); +} + +void PinEntryDialog::setFormattedPassphrase( + const PinEntryDialog::FormattedPassphraseOptions &options) { + mFormatPassphrase = options.formatPassphrase; + mFormattedPassphraseHint->setTextFormat(Qt::RichText); + mFormattedPassphraseHint->setText(QLatin1String("<html>") + + options.hint.toHtmlEscaped() + + QLatin1String("</html>")); + Accessibility::setName(mFormattedPassphraseHint, options.hint); + // toggleFormattedPassphrase(); +} + +void PinEntryDialog::setConstraintsOptions(const ConstraintsOptions &options) { + mEnforceConstraints = options.enforce; + mConstraintsHint->setText(options.shortHint); + if (!options.longHint.isEmpty()) { + mConstraintsHint->setToolTip( + QLatin1String("<html>") + + options.longHint.toHtmlEscaped().replace(QLatin1String("\n\n"), + QLatin1String("<br>")) + + QLatin1String("</html>")); + Accessibility::setDescription(mConstraintsHint, options.longHint); + } + mConstraintsErrorTitle = options.errorTitle; + + mConstraintsHint->setVisible(mEnforceConstraints && + !options.shortHint.isEmpty()); +} + +void PinEntryDialog::toggleFormattedPassphrase() { + const bool enable_formatting = + mFormatPassphrase && _edit->echoMode() == QLineEdit::Normal; + _edit->setFormattedPassphrase(enable_formatting); + if (mRepeat != nullptr) { + mRepeat->setFormattedPassphrase(enable_formatting); + const bool hint_about_to_be_hidden = + mFormattedPassphraseHint->isVisible() && !enable_formatting; + if (hint_about_to_be_hidden) { + // set hint spacer to current height of hint label before hiding the hint + mFormattedPassphraseHintSpacer->setMinimumHeight( + mFormattedPassphraseHint->height()); + mFormattedPassphraseHintSpacer->setVisible(true); + } else if (enable_formatting) { + mFormattedPassphraseHintSpacer->setVisible(false); + } + mFormattedPassphraseHint->setVisible(enable_formatting); + } +} + +void PinEntryDialog::onBackspace() { + cancelTimeout(); + + if (_disable_echo_allowed) { + _edit->setEchoMode(QLineEdit::NoEcho); + if (mRepeat != nullptr) { + mRepeat->setEchoMode(QLineEdit::NoEcho); + } + } +} + +void PinEntryDialog::updateQuality(const QString &txt) { + int length; + int percent; + QPalette pal; + + _disable_echo_allowed = false; + + if (!_have_quality_bar) { + return; + } + + length = txt.length(); + percent = length != 0 ? pinentry_inq_quality(txt) : 0; + if (length == 0) { + _quality_bar->reset(); + } else { + pal = _quality_bar->palette(); + if (percent < 0) { + pal.setColor(QPalette::Highlight, QColor("red")); + percent = -percent; + } else { + pal.setColor(QPalette::Highlight, QColor("green")); + } + _quality_bar->setPalette(pal); + _quality_bar->setValue(percent); + } +} + +void PinEntryDialog::setPinentryInfo(struct pinentry peinfo) { + _pinentry_info = + GpgFrontend::SecureCreateUniqueObject<struct pinentry>(peinfo); +} + +void PinEntryDialog::focusChanged(QWidget *old, QWidget *now) { + // Grab keyboard. It might be a little weird to do it here, but it works! + // Previously this code was in showEvent, but that did not work in Qt4. + if (!_pinentry_info || (_pinentry_info->grab != 0)) { + if (_grabbed && (old != nullptr) && (old == _edit || old == mRepeat)) { + old->releaseKeyboard(); + _grabbed = false; + } + if (!_grabbed && (now != nullptr) && (now == _edit || now == mRepeat)) { + now->grabKeyboard(); + _grabbed = true; + } + } +} + +void PinEntryDialog::textChanged(const QString &text) { + Q_UNUSED(text); + + cancelTimeout(); + + if ((mVisiActionEdit != nullptr) && sender() == _edit) { + mVisiActionEdit->setVisible(!_edit->pin().isEmpty()); + } + if (mGenerateButton != nullptr) { + mGenerateButton->setVisible(_edit->pin().isEmpty() +#ifndef QT_NO_ACCESSIBILITY + && !mGenerateButton->accessibleName().isEmpty() +#endif + ); + } +} + +void PinEntryDialog::generatePin() { + unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info.get())}; + if (pin) { + if (_edit->echoMode() == QLineEdit::Password) { + if (mVisiActionEdit != nullptr) { + mVisiActionEdit->trigger(); + } + if (mVisiCB != nullptr) { + mVisiCB->setChecked(true); + } + } + const auto pin_str = QString::fromUtf8(pin.get()); + _edit->setPin(pin_str); + mRepeat->setPin(pin_str); + // explicitly focus the first input field and select the generated password + _edit->setFocus(); + _edit->selectAll(); + } +} + +void PinEntryDialog::toggleVisibility() { + if (sender() != mVisiCB) { + if (_edit->echoMode() == QLineEdit::Password) { + if (mVisiActionEdit != nullptr) { + mVisiActionEdit->setIcon(QIcon(QLatin1String(":hint.svg"))); + mVisiActionEdit->setToolTip(mHideTT); + } + _edit->setEchoMode(QLineEdit::Normal); + if (mRepeat != nullptr) { + mRepeat->setEchoMode(QLineEdit::Normal); + } + } else { + if (mVisiActionEdit != nullptr) { + mVisiActionEdit->setIcon(QIcon(QLatin1String(":visibility.svg"))); + mVisiActionEdit->setToolTip(mVisibilityTT); + } + _edit->setEchoMode(QLineEdit::Password); + if (mRepeat != nullptr) { + mRepeat->setEchoMode(QLineEdit::Password); + } + } + } else { + if (mVisiCB->isChecked()) { + if (mRepeat != nullptr) { + mRepeat->setEchoMode(QLineEdit::Normal); + } + _edit->setEchoMode(QLineEdit::Normal); + } else { + if (mRepeat != nullptr) { + mRepeat->setEchoMode(QLineEdit::Password); + } + _edit->setEchoMode(QLineEdit::Password); + } + } + toggleFormattedPassphrase(); +} + +QString PinEntryDialog::repeatedPin() const { + if (mRepeat != nullptr) { + return mRepeat->pin(); + } + return QString(); +} + +bool PinEntryDialog::timedOut() const { return _timed_out; } + +void PinEntryDialog::setRepeatErrorText(const QString &err) { + if (mRepeatError != nullptr) { + mRepeatError->setText(err); + } +} + +void PinEntryDialog::cancelTimeout() { + if (_timer != nullptr) { + _timer->stop(); + } +} + +void PinEntryDialog::checkCapsLock() { + const auto state = capsLockState(); + if (state != LockState::Unknown) { + mCapsLockHint->setVisible(state == LockState::On); + } +} + +void PinEntryDialog::onAccept() { + cancelTimeout(); + + if ((mRepeat != nullptr) && mRepeat->pin() != _edit->pin()) { +#ifndef QT_NO_ACCESSIBILITY + if (QAccessible::isActive()) { + QMessageBox::information(this, mRepeatError->text(), + mRepeatError->text()); + } else +#endif + { + mRepeatError->setVisible(true); + } + return; + } + + const auto result = checkConstraints(); + if (result != PassphraseNotOk) { + accept(); + } +} + +PinEntryDialog::PassphraseCheckResult PinEntryDialog::checkConstraints() { + if (!mEnforceConstraints) { + return PassphraseNotChecked; + } + + const auto passphrase = _edit->pin().toUtf8(); + unique_malloced_ptr<char> error{pinentry_inq_checkpin( + _pinentry_info.get(), passphrase.constData(), passphrase.size())}; + + if (!error) { + return PassphraseOk; + } + + const auto message_lines = + QString::fromUtf8(QByteArray::fromPercentEncoding(error.get())) + .split(QChar{'\n'}); + if (message_lines.isEmpty()) { + // shouldn't happen because pinentry_inq_checkpin() either returns NULL or a + // non-empty string + return PassphraseOk; + } + const auto &first_line = message_lines.first(); + const auto index_of_first_non_empty_additional_line = + message_lines.indexOf(QRegularExpression{QStringLiteral(".*\\S.*")}, 1); + const auto additional_lines = + index_of_first_non_empty_additional_line > 0 + ? message_lines.mid(index_of_first_non_empty_additional_line) + .join(QChar{'\n'}) + : QString{}; + QMessageBox message_box{this}; + message_box.setIcon(QMessageBox::Information); + message_box.setWindowTitle(mConstraintsErrorTitle); + message_box.setText(first_line); + message_box.setInformativeText(additional_lines); + message_box.setStandardButtons(QMessageBox::Ok); + message_box.exec(); + return PassphraseNotOk; +} diff --git a/src/pinentry/pinentrydialog.h b/src/pinentry/pinentrydialog.h new file mode 100644 index 00000000..9f405b10 --- /dev/null +++ b/src/pinentry/pinentrydialog.h @@ -0,0 +1,171 @@ +/* pinentrydialog.h - A (not yet) secure Qt 4 dialog for PIN entry. + * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) + * Copyright 2007 Ingo Klöcker + * Copyright 2016 Intevation GmbH + * Copyright (C) 2021, 2022 g10 Code GmbH + * + * Written by Steffen Hansen <[email protected]>. + * Modified by Andre Heinecke <[email protected]> + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINENTRYDIALOG_H__ +#define __PINENTRYDIALOG_H__ + +#include <QAccessible> +#include <QDialog> +#include <QStyle> +#include <QTimer> + +#include "core/function/SecureMemoryAllocator.h" +#include "pinentry.h" + +class QIcon; +class QLabel; +class QPushButton; +class QLineEdit; +class PinLineEdit; +class QString; +class QProgressBar; +class QCheckBox; +class QAction; + +QPixmap applicationIconPixmap(const QIcon &overlayIcon = {}); + +void raiseWindow(QWidget *w); + +class PinEntryDialog : public QDialog { + Q_OBJECT + + Q_PROPERTY(QString description READ description WRITE setDescription) + Q_PROPERTY(QString error READ error WRITE setError) + Q_PROPERTY(QString pin READ pin WRITE setPin) + Q_PROPERTY(QString prompt READ prompt WRITE setPrompt) + public: + struct FormattedPassphraseOptions { + bool formatPassphrase; + QString hint; + }; + struct ConstraintsOptions { + bool enforce; + QString shortHint; + QString longHint; + QString errorTitle; + }; + + explicit PinEntryDialog(QWidget *parent = 0, const char *name = 0, + int timeout = 0, bool modal = false, + bool enable_quality_bar = false, + const QString &repeatString = QString(), + const QString &visibiltyTT = QString(), + const QString &hideTT = QString()); + + void setDescription(const QString &); + QString description() const; + + void setError(const QString &); + QString error() const; + + void setPin(const QString &); + QString pin() const; + + QString repeatedPin() const; + void setRepeatErrorText(const QString &); + + void setPrompt(const QString &); + QString prompt() const; + + void setOkText(const QString &); + void setCancelText(const QString &); + + void setQualityBar(const QString &); + void setQualityBarTT(const QString &); + + void setGenpinLabel(const QString &); + void setGenpinTT(const QString &); + + void setCapsLockHint(const QString &); + + void setFormattedPassphrase(const FormattedPassphraseOptions &options); + + void setConstraintsOptions(const ConstraintsOptions &options); + + void setPinentryInfo(struct pinentry); + + bool timedOut() const; + + protected Q_SLOTS: + void updateQuality(const QString &); + void slotTimeout(); + void textChanged(const QString &); + void focusChanged(QWidget *old, QWidget *now); + void toggleVisibility(); + void onBackspace(); + void generatePin(); + void toggleFormattedPassphrase(); + + protected: + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void showEvent(QShowEvent *event) override; + + private Q_SLOTS: + void cancelTimeout(); + void checkCapsLock(); + void onAccept(); + + private: + enum PassphraseCheckResult { + PassphraseNotChecked = -1, + PassphraseNotOk = 0, + PassphraseOk + }; + PassphraseCheckResult checkConstraints(); + + QLabel *_icon = nullptr; + QLabel *_desc = nullptr; + QLabel *_error = nullptr; + QLabel *_prompt = nullptr; + QLabel *_quality_bar_label = nullptr; + QProgressBar *_quality_bar = nullptr; + PinLineEdit *_edit = nullptr; + PinLineEdit *mRepeat = nullptr; + QLabel *mRepeatError = nullptr; + QPushButton *_ok = nullptr; + QPushButton *_cancel = nullptr; + bool _grabbed = false; + bool _have_quality_bar = false; + bool _timed_out = false; + bool _disable_echo_allowed = true; + bool mEnforceConstraints = false; + bool mFormatPassphrase = false; + + GpgFrontend::SecureUniquePtr<struct pinentry> _pinentry_info = nullptr; + QTimer *_timer = nullptr; + QString mVisibilityTT; + QString mHideTT; + QAction *mVisiActionEdit = nullptr; + QPushButton *mGenerateButton = nullptr; + QCheckBox *mVisiCB = nullptr; + QLabel *mFormattedPassphraseHint = nullptr; + QLabel *mFormattedPassphraseHintSpacer = nullptr; + QLabel *mCapsLockHint = nullptr; + QLabel *mConstraintsHint = nullptr; + QString mConstraintsErrorTitle; +}; + +#endif // __PINENTRYDIALOG_H__ diff --git a/src/pinentry/pinlineedit.cpp b/src/pinentry/pinlineedit.cpp new file mode 100644 index 00000000..9d172b56 --- /dev/null +++ b/src/pinentry/pinlineedit.cpp @@ -0,0 +1,204 @@ +/* pinlineedit.cpp - Modified QLineEdit widget. + * Copyright (C) 2018 Damien Goutte-Gattat + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "pinlineedit.h" + +#include <QClipboard> +#include <QGuiApplication> +#include <QKeyEvent> + +static const int FormattedPassphraseGroupSize = 5; +static const QChar FormattedPassphraseSeparator = QChar::Nbsp; + +namespace { +struct Selection { + bool empty() const { return start < 0 || start >= end; } + int length() const { return empty() ? 0 : end - start; } + + int start; + int end; +}; +} // namespace + +class PinLineEdit::Private { + PinLineEdit *const q; + + public: + Private(PinLineEdit *q) : q{q} {} + + QString formatted(QString text) const { + const int dashCount = text.size() / FormattedPassphraseGroupSize; + text.reserve(text.size() + dashCount); + for (int i = FormattedPassphraseGroupSize; i < text.size(); + i += FormattedPassphraseGroupSize + 1) { + text.insert(i, FormattedPassphraseSeparator); + } + return text; + } + + Selection formattedSelection(Selection selection) const { + if (selection.empty()) { + return selection; + } + return {selection.start + selection.start / FormattedPassphraseGroupSize, + selection.end + (selection.end - 1) / FormattedPassphraseGroupSize}; + } + + QString unformatted(QString text) const { + for (int i = FormattedPassphraseGroupSize; i < text.size(); + i += FormattedPassphraseGroupSize) { + text.remove(i, 1); + } + return text; + } + + Selection unformattedSelection(Selection selection) const { + if (selection.empty()) { + return selection; + } + return { + selection.start - selection.start / (FormattedPassphraseGroupSize + 1), + selection.end - selection.end / (FormattedPassphraseGroupSize + 1)}; + } + + void copyToClipboard() { + if (q->echoMode() != QLineEdit::Normal) { + return; + } + + QString text = q->selectedText(); + if (mFormattedPassphrase) { + text.remove(FormattedPassphraseSeparator); + } + if (!text.isEmpty()) { + QGuiApplication::clipboard()->setText(text); + } + } + + int selectionEnd() { +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + return q->selectionEnd(); +#else + return q->selectionStart() + q->selectedText().size(); +#endif + } + + public: + bool mFormattedPassphrase = false; +}; + +PinLineEdit::PinLineEdit(QWidget *parent) + : QLineEdit(parent), d{new Private{this}} { + connect(this, SIGNAL(textEdited(QString)), this, SLOT(textEdited())); +} + +PinLineEdit::~PinLineEdit() = default; + +void PinLineEdit::setFormattedPassphrase(bool on) { + if (on == d->mFormattedPassphrase) { + return; + } + d->mFormattedPassphrase = on; + Selection selection{selectionStart(), d->selectionEnd()}; + if (d->mFormattedPassphrase) { + setText(d->formatted(text())); + selection = d->formattedSelection(selection); + } else { + setText(d->unformatted(text())); + selection = d->unformattedSelection(selection); + } + if (!selection.empty()) { + setSelection(selection.start, selection.length()); + } +} + +void PinLineEdit::copy() const { d->copyToClipboard(); } + +void PinLineEdit::cut() { + if (hasSelectedText()) { + copy(); + del(); + } +} + +void PinLineEdit::setPin(const QString &pin) { + setText(d->mFormattedPassphrase ? d->formatted(pin) : pin); +} + +QString PinLineEdit::pin() const { + if (d->mFormattedPassphrase) { + return d->unformatted(text()); + } else { + return text(); + } +} + +void PinLineEdit::keyPressEvent(QKeyEvent *e) { + if (e == QKeySequence::Copy) { + copy(); + return; + } else if (e == QKeySequence::Cut) { + if (!isReadOnly() && hasSelectedText()) { + copy(); + del(); + } + return; + } else if (e == QKeySequence::DeleteEndOfLine) { + if (!isReadOnly()) { + setSelection(cursorPosition(), text().size()); + copy(); + del(); + } + return; + } else if (e == QKeySequence::DeleteCompleteLine) { + if (!isReadOnly()) { + setSelection(0, text().size()); + copy(); + del(); + } + return; + } + + QLineEdit::keyPressEvent(e); + + if (e->key() == Qt::Key::Key_Backspace) { + emit backspacePressed(); + } +} + +void PinLineEdit::textEdited() { + if (!d->mFormattedPassphrase) { + return; + } + auto currentText = text(); + // first calculate the cursor position in the reformatted text; the cursor + // is put left of the separators, so that backspace works as expected + auto cursorPos = cursorPosition(); + cursorPos -= QStringView{currentText}.left(cursorPos).count( + FormattedPassphraseSeparator); + cursorPos += std::max(cursorPos - 1, 0) / FormattedPassphraseGroupSize; + // then reformat the text + currentText.remove(FormattedPassphraseSeparator); + currentText = d->formatted(currentText); + // finally, set reformatted text and updated cursor position + setText(currentText); + setCursorPosition(cursorPos); +} diff --git a/src/pinentry/pinlineedit.h b/src/pinentry/pinlineedit.h new file mode 100644 index 00000000..72ac85a5 --- /dev/null +++ b/src/pinentry/pinlineedit.h @@ -0,0 +1,60 @@ +/* pinlineedit.h - Modified QLineEdit widget. + * Copyright (C) 2018 Damien Goutte-Gattat + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _PINLINEEDIT_H_ +#define _PINLINEEDIT_H_ + +#include <QLineEdit> + +class PinLineEdit : public QLineEdit { + Q_OBJECT + + public: + explicit PinLineEdit(QWidget *parent = nullptr); + ~PinLineEdit() override; + + void setPin(const QString &pin); + QString pin() const; + + public Q_SLOTS: + void setFormattedPassphrase(bool on); + void copy() const; + void cut(); + + Q_SIGNALS: + void backspacePressed(); + + protected: + void keyPressEvent(QKeyEvent *) override; + + private: + using QLineEdit::setText; + using QLineEdit::text; + + private Q_SLOTS: + void textEdited(); + + private: + class Private; + std::unique_ptr<Private> d; +}; + +#endif // _PINLINEEDIT_H_ diff --git a/src/pinentry/qti18n.cpp b/src/pinentry/qti18n.cpp new file mode 100644 index 00000000..49c27dd3 --- /dev/null +++ b/src/pinentry/qti18n.cpp @@ -0,0 +1,93 @@ +/* qti18n.cpp - Load qt translations for pinentry. + * Copyright 2021 g10 Code GmbH + * SPDX-FileCopyrightText: 2015 Lukáš Tinkl <[email protected]> + * SPDX-FileCopyrightText: 2021 Ingo Klöcker <[email protected]> + * + * Copied from k18n under the terms of LGPLv2 or later. + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <QCoreApplication> +#include <QDebug> +#include <QLibraryInfo> +#include <QLocale> +#include <QTranslator> + +static bool loadCatalog(const QString &catalog, const QLocale &locale) { + auto translator = new QTranslator(QCoreApplication::instance()); + + if (!translator->load(locale, catalog, QString(), + QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { + qDebug() << "Loading the" << catalog << "catalog failed for locale" + << locale; + delete translator; + return false; + } + QCoreApplication::instance()->installTranslator(translator); + return true; +} + +static bool loadCatalog(const QString &catalog, const QLocale &locale, + const QLocale &fallbackLocale) { + // try to load the catalog for locale + if (loadCatalog(catalog, locale)) { + return true; + } + // if this fails, then try the fallback locale (if it's different from locale) + if (fallbackLocale != locale) { + return loadCatalog(catalog, fallbackLocale); + } + return false; +} + +// load global Qt translation, needed in KDE e.g. by lots of builtin dialogs +// (QColorDialog, QFontDialog) that we use +static void loadTranslation(const QString &localeName, + const QString &fallbackLocaleName) { + const QLocale locale{localeName}; + const QLocale fallbackLocale{fallbackLocaleName}; + // first, try to load the qt_ meta catalog + if (loadCatalog(QStringLiteral("qt_"), locale, fallbackLocale)) { + return; + } + // if loading the meta catalog failed, then try loading the four catalogs + // it depends on, i.e. qtbase, qtscript, qtmultimedia, qtxmlpatterns, + // separately + const auto catalogs = { + QStringLiteral("qtbase_"), + /* QStringLiteral("qtscript_"), + QStringLiteral("qtmultimedia_"), + QStringLiteral("qtxmlpatterns_"), */ + }; + for (const auto &catalog : catalogs) { + loadCatalog(catalog, locale, fallbackLocale); + } +} + +static void load() { + // The way Qt translation system handles plural forms makes it necessary to + // have a translation file which contains only plural forms for `en`. That's + // why we load the `en` translation unconditionally, then load the + // translation for the current locale to overload it. + loadCatalog(QStringLiteral("qt_"), QLocale{QStringLiteral("en")}); + + const QLocale locale = QLocale::system(); + if (locale.name() != QStringLiteral("en")) { + loadTranslation(locale.name(), locale.bcp47Name()); + } +} + +Q_COREAPP_STARTUP_FUNCTION(load) diff --git a/src/pinentry/secmem++.h b/src/pinentry/secmem++.h new file mode 100644 index 00000000..116da880 --- /dev/null +++ b/src/pinentry/secmem++.h @@ -0,0 +1,91 @@ +/* STL allocator for secmem + * Copyright (C) 2008 Marc Mutz <[email protected]> + * + * 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 of the License, or + * (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SECMEM_SECMEMPP_H__ +#define __SECMEM_SECMEMPP_H__ + +#include "../secmem/secmem.h" +#include <cstddef> + +namespace secmem { + + template <typename T> + class alloc { + public: + // type definitions: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + // rebind + template <typename U> + struct rebind { + typedef alloc<U> other; + }; + + // address + pointer address( reference value ) const { + return &value; + } + const_pointer address( const_reference value ) const { + return &value; + } + + // (trivial) ctors and dtors + alloc() {} + alloc( const alloc & ) {} + template <typename U> alloc( const alloc<U> & ) {} + // copy ctor is ok + ~alloc() {} + + // de/allocation + size_type max_size() const { + return secmem_get_max_size(); + } + + pointer allocate( size_type n, void * =0 ) { + return static_cast<pointer>( secmem_malloc( n * sizeof(T) ) ); + } + + void deallocate( pointer p, size_type ) { + secmem_free( p ); + } + + // de/construct + void construct( pointer p, const T & value ) { + void * loc = p; + new (loc)T(value); + } + void destruct( pointer p ) { + p->~T(); + } + }; + + // equality comparison + template <typename T1,typename T2> + bool operator==( const alloc<T1> &, const alloc<T2> & ) { return true; } + template <typename T1, typename T2> + bool operator!=( const alloc<T1> &, const alloc<T2> & ) { return false; } + +} + +#endif /* __SECMEM_SECMEMPP_H__ */ diff --git a/src/pinentry/util.cpp b/src/pinentry/util.cpp new file mode 100644 index 00000000..f1bac4ba --- /dev/null +++ b/src/pinentry/util.cpp @@ -0,0 +1,116 @@ +/* Quintuple Agent + * Copyright (C) 1999 Robert Bihlmeyer <[email protected]> + * + * 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 of the License, or + * (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE 1 + +#include <unistd.h> +#ifndef WINDOWS +# include <errno.h> +#endif +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "util.h" + +#ifndef HAVE_DOSISH_SYSTEM +static int uid_set = 0; +static uid_t real_uid, file_uid; +#endif /*!HAVE_DOSISH_SYSTEM*/ + +/* Write DATA of size BYTES to FD, until all is written or an error + occurs. */ +ssize_t +xwrite(int fd, const void *data, size_t bytes) +{ + char *ptr; + size_t todo; + ssize_t written = 0; + + for (ptr = (char *)data, todo = bytes; todo; ptr += written, todo -= written) + { + do + written = write (fd, ptr, todo); + while ( +#ifdef WINDOWS + 0 +#else + written == -1 && errno == EINTR +#endif + ); + if (written < 0) + break; + } + return written; +} + +#if 0 +extern int debug; + +int +debugmsg(const char *fmt, ...) +{ + va_list va; + int ret; + + if (debug) { + va_start(va, fmt); + fprintf(stderr, "\e[4m"); + ret = vfprintf(stderr, fmt, va); + fprintf(stderr, "\e[24m"); + va_end(va); + return ret; + } else + return 0; +} +#endif + +/* initialize uid variables */ +#ifndef HAVE_DOSISH_SYSTEM +static void +init_uids(void) +{ + real_uid = getuid(); + file_uid = geteuid(); + uid_set = 1; +} +#endif + + +/* drop all additional privileges */ +void +drop_privs(void) +{ +#ifndef HAVE_DOSISH_SYSTEM + if (!uid_set) + init_uids(); + if (real_uid != file_uid) { + if (setuid(real_uid) < 0) { + perror("dropping privileges failed"); + exit(EXIT_FAILURE); + } + file_uid = real_uid; + } +#endif +} diff --git a/src/pinentry/util.h b/src/pinentry/util.h new file mode 100644 index 00000000..e6ad1dad --- /dev/null +++ b/src/pinentry/util.h @@ -0,0 +1,35 @@ +/* util.h - Helper for managing malloced pointers + * Copyright (C) 2021 g10 Code GmbH + * + * Software engineering by Ingo Klöcker <[email protected]> + * + * 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 of the + * License, or (at your option) any later version. + * + * 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 <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINENTRY_QT_UTIL_H__ +#define __PINENTRY_QT_UTIL_H__ + +#include <stdlib.h> + +namespace _detail { +struct FreeDeleter { + void operator()(void *ptr) const { free(ptr); } +}; +} // namespace _detail + +template <class T> +using unique_malloced_ptr = std::unique_ptr<T, _detail::FreeDeleter>; + +#endif // __PINENTRY_QT_UTIL_H__ diff --git a/src/signal.cpp b/src/signal.cpp index da4dfb39..7722c36f 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,46 +20,10 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include <csetjmp> - #include "GpgFrontend.h" - -#ifdef FREEBSD -extern sigjmp_buf recover_env; -#else -extern jmp_buf recover_env; -#endif - -/** - * @brief handle the signal caught. - * - * @param sig signal number - */ -void handle_signal(int sig) { - static int _repeat_handle_num = 1, last_sig = sig; - // SPDLOG_DEBUG("signal caught {}", sig); - std::cout << "signal caught" << sig; - - if (last_sig == sig) - _repeat_handle_num++; - else - _repeat_handle_num = 1, last_sig = sig; - - if (_repeat_handle_num > 3) { - std::cout << "The same signal appears three times," - << "execute the termination operation." << sig; - exit(-1); - } - -#ifndef WINDOWS - siglongjmp(recover_env, 1); -#else - longjmp(recover_env, 1); -#endif -} diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 00000000..c892c6b5 --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (C) 2021 Saturneric <[email protected]> +# +# This file is part of GpgFrontend. +# +# GpgFrontend 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 3 of the License, or +# (at your option) any later version. +# +# GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. +# +# The initial version of the source code is inherited from +# the gpg4usb project, which is under GPL-3.0-or-later. +# +# All the source code of GpgFrontend was modified and released by +# Saturneric <[email protected]> starting on May 12, 2021. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# Set configure for test + +aux_source_directory(./core TEST_SOURCE) +aux_source_directory(. TEST_SOURCE) + +add_library(gpgfrontend_test SHARED ${TEST_SOURCE}) + +set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendTestExport.h") +generate_export_header(gpgfrontend_test EXPORT_FILE_NAME "${_export_file}") + +target_link_libraries(gpgfrontend_test PRIVATE gtest) +target_link_libraries(gpgfrontend_test PRIVATE gpgfrontend_core) +target_link_libraries(gpgfrontend_test PRIVATE spdlog) + +add_test(AllTestsInGpgFrontend gpgfrontend_test) diff --git a/src/test/GpgFrontendCoreExport.h b/src/test/GpgFrontendCoreExport.h new file mode 100644 index 00000000..4d1b2f0b --- /dev/null +++ b/src/test/GpgFrontendCoreExport.h @@ -0,0 +1,42 @@ + +#ifndef GPGFRONTEND_TEST_EXPORT_H +#define GPGFRONTEND_TEST_EXPORT_H + +#ifdef GPGFRONTEND_TEST_STATIC_DEFINE +# define GPGFRONTEND_TEST_EXPORT +# define GPGFRONTEND_TEST_NO_EXPORT +#else +# ifndef GPGFRONTEND_TEST_EXPORT +# ifdef gpgfrontend_test_EXPORTS + /* We are building this library */ +# define GPGFRONTEND_TEST_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define GPGFRONTEND_TEST_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef GPGFRONTEND_TEST_NO_EXPORT +# define GPGFRONTEND_TEST_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED +# define GPGFRONTEND_TEST_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED_EXPORT +# define GPGFRONTEND_TEST_DEPRECATED_EXPORT GPGFRONTEND_TEST_EXPORT GPGFRONTEND_TEST_DEPRECATED +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED_NO_EXPORT +# define GPGFRONTEND_TEST_DEPRECATED_NO_EXPORT GPGFRONTEND_TEST_NO_EXPORT GPGFRONTEND_TEST_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef GPGFRONTEND_TEST_NO_DEPRECATED +# define GPGFRONTEND_TEST_NO_DEPRECATED +# endif +#endif + +#endif /* GPGFRONTEND_TEST_EXPORT_H */ diff --git a/src/test/GpgFrontendTest.cpp b/src/test/GpgFrontendTest.cpp new file mode 100644 index 00000000..95b4179a --- /dev/null +++ b/src/test/GpgFrontendTest.cpp @@ -0,0 +1,113 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgFrontendTest.h" + +#include <gtest/gtest.h> + +#include "core/GpgConstants.h" +#include "core/function/GlobalSettingStation.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/utils/IOUtils.h" + +namespace GpgFrontend::Test { + +auto GenerateRandomString(size_t length) -> QString { + const QString characters = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::random_device random_device; + std::mt19937 generator(random_device()); + std::uniform_int_distribution<> distribution(0, characters.size() - 1); + + QString random_string; + for (size_t i = 0; i < length; ++i) { + random_string += characters[distribution(generator)]; + } + + return random_string; +} + +void ConfigureGpgContext() { + auto db_path = QDir(QDir::tempPath() + "/" + GenerateRandomString(12)); + GF_TEST_LOG_DEBUG("setting up new database path for test case: {}", + db_path.path()); + + if (db_path.exists()) db_path.rmdir("."); + db_path.mkpath("."); + + GpgContext::CreateInstance( + kGpgFrontendDefaultChannel, [=]() -> ChannelObjectPtr { + GpgContextInitArgs args; + args.test_mode = true; + args.offline_mode = true; + args.db_path = db_path.path(); + + return ConvertToChannelObjectPtr<>(SecureCreateUniqueObject<GpgContext>( + args, kGpgFrontendDefaultChannel)); + }); +} + +void ImportPrivateKeys(const QString& data_path, QSettings settings) { + auto key_files = QDir(":/test/key").entryList(); + + for (const auto& key_file : key_files) { + auto [success, gf_buffer] = + ReadFileGFBuffer(QString(":/test/key") + "/" + key_file); + if (success) { + GpgKeyImportExporter::GetInstance(kGpgFrontendDefaultChannel) + .ImportKey(gf_buffer); + } else { + GF_TEST_LOG_ERROR("read from key file failed: {}", key_file); + } + } +} + +void SetupGlobalTestEnv() { + auto app_path = GlobalSettingStation::GetInstance().GetAppDir(); + auto test_path = app_path + "/test"; + auto test_config_path = test_path + "/conf/test.ini"; + auto test_data_path = test_path + "/data"; + + GF_TEST_LOG_INFO("test config file path: {}", test_config_path); + GF_TEST_LOG_INFO("test data file path: {}", test_data_path); + + ImportPrivateKeys(test_data_path, + QSettings(test_config_path, QSettings::IniFormat)); +} + +auto ExecuteAllTestCase(GpgFrontendContext args) -> int { + ConfigureGpgContext(); + SetupGlobalTestEnv(); + + testing::InitGoogleTest(&args.argc, args.argv); + return RUN_ALL_TESTS(); +} + +} // namespace GpgFrontend::Test
\ No newline at end of file diff --git a/src/test/GpgFrontendTest.h b/src/test/GpgFrontendTest.h new file mode 100644 index 00000000..405eee90 --- /dev/null +++ b/src/test/GpgFrontendTest.h @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "GpgFrontendTestExport.h" + +// Core +#include "core/utils/LogUtils.h" + +namespace GpgFrontend::Test { + +struct GpgFrontendContext { + int argc; + char **argv; +}; + +auto GPGFRONTEND_TEST_EXPORT ExecuteAllTestCase(GpgFrontendContext args) -> int; + +#define GF_TEST_LOG_TRACE(...) GF_LOG_TRACE("test", __VA_ARGS__) +#define GF_TEST_LOG_DEBUG(...) GF_LOG_DEBUG("test", __VA_ARGS__) +#define GF_TEST_LOG_INFO(...) GF_LOG_INFO("test", __VA_ARGS__) +#define GF_TEST_LOG_WARN(...) GF_LOG_WARN("test", __VA_ARGS__) +#define GF_TEST_LOG_ERROR(...) GF_LOG_ERROR("test", __VA_ARGS__) + +} // namespace GpgFrontend::Test diff --git a/src/test/GpgFrontendTestExport.h b/src/test/GpgFrontendTestExport.h new file mode 100644 index 00000000..4d1b2f0b --- /dev/null +++ b/src/test/GpgFrontendTestExport.h @@ -0,0 +1,42 @@ + +#ifndef GPGFRONTEND_TEST_EXPORT_H +#define GPGFRONTEND_TEST_EXPORT_H + +#ifdef GPGFRONTEND_TEST_STATIC_DEFINE +# define GPGFRONTEND_TEST_EXPORT +# define GPGFRONTEND_TEST_NO_EXPORT +#else +# ifndef GPGFRONTEND_TEST_EXPORT +# ifdef gpgfrontend_test_EXPORTS + /* We are building this library */ +# define GPGFRONTEND_TEST_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define GPGFRONTEND_TEST_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef GPGFRONTEND_TEST_NO_EXPORT +# define GPGFRONTEND_TEST_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED +# define GPGFRONTEND_TEST_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED_EXPORT +# define GPGFRONTEND_TEST_DEPRECATED_EXPORT GPGFRONTEND_TEST_EXPORT GPGFRONTEND_TEST_DEPRECATED +#endif + +#ifndef GPGFRONTEND_TEST_DEPRECATED_NO_EXPORT +# define GPGFRONTEND_TEST_DEPRECATED_NO_EXPORT GPGFRONTEND_TEST_NO_EXPORT GPGFRONTEND_TEST_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef GPGFRONTEND_TEST_NO_DEPRECATED +# define GPGFRONTEND_TEST_NO_DEPRECATED +# endif +#endif + +#endif /* GPGFRONTEND_TEST_EXPORT_H */ diff --git a/src/test/core/GpgCoreTest.cpp b/src/test/core/GpgCoreTest.cpp new file mode 100644 index 00000000..1d7ddaa0 --- /dev/null +++ b/src/test/core/GpgCoreTest.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgCoreTest.h" + +#include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/utils/IOUtils.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend::Test { + +void GpgCoreTest::TearDown() {} + +void GpgCoreTest::SetUp() {} +} // namespace GpgFrontend::Test diff --git a/src/test/core/GpgCoreTest.h b/src/test/core/GpgCoreTest.h new file mode 100644 index 00000000..26097f2c --- /dev/null +++ b/src/test/core/GpgCoreTest.h @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <gtest/gtest.h> + +namespace GpgFrontend::Test { + +class GpgCoreTest : public ::testing::Test { + public: + void SetUp() override; + + void TearDown() override; +}; + +} // namespace GpgFrontend::Test
\ No newline at end of file diff --git a/src/test/core/GpgCoreTestBasicOpera.cpp b/src/test/core/GpgCoreTestBasicOpera.cpp new file mode 100644 index 00000000..e525afa9 --- /dev/null +++ b/src/test/core/GpgCoreTestBasicOpera.cpp @@ -0,0 +1,373 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgCoreTest.h" +#include "core/GpgModel.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/result_analyse/GpgDecryptResultAnalyse.h" +#include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" +#include "core/utils/GpgUtils.h" + +namespace GpgFrontend::Test { + +TEST_F(GpgCoreTest, CoreEncryptDecrTest) { + std::atomic_bool callback_called_flag{false}; + + auto encrypt_key = GpgKeyGetter::GetInstance().GetPubkey( + "E87C6A2D8D95C818DE93B3AE6A2764F8298DEB29"); + + GpgBasicOperator::GetInstance().Encrypt( + {encrypt_key}, GFBuffer("Hello GpgFrontend!"), true, + [&callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgEncryptResult, GFBuffer>())); + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto encr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_TRUE(result.InvalidRecipients().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().Decrypt( + encr_out_buffer, [&callback_called_flag]( + GpgError err, const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto decr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(d_result.Recipients().empty()); + ASSERT_EQ(d_result.Recipients()[0].keyid, "6A2764F8298DEB29"); + + ASSERT_EQ(decr_out_buffer, GFBuffer("Hello GpgFrontend!")); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreEncryptSymmetricDecrTest) { + std::atomic_bool callback_called_flag{false}; + + auto encrypt_text = GFBuffer("Hello GpgFrontend!"); + + GpgBasicOperator::GetInstance().EncryptSymmetric( + encrypt_text, true, + [&callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgEncryptResult, GFBuffer>())); + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto encr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_TRUE(result.InvalidRecipients().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().Decrypt( + encr_out_buffer, [&callback_called_flag]( + GpgError err, const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto decr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_TRUE(d_result.Recipients().empty()); + ASSERT_EQ(decr_out_buffer, GFBuffer("Hello GpgFrontend!")); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreEncryptDecrTest_KeyNotFound_1) { + std::atomic_bool callback_called_flag{false}; + + auto encr_out_data = GFBuffer( + "-----BEGIN PGP MESSAGE-----\n" + "\n" + "hQEMA6UM/S9sZ32MAQf9Fb6gp6nvgKTQBv2mmjXia6ODXYq6kNeLsPVzLCbHyWOs\n" + "0GDED11R1NksA3EQxFf4fzLkDpbo68r5bWy7c28c99Fr68IRET19Tw6Gu65MQezD\n" + "Rdzo1oVqmK9sfKqOT3+0S2H+suFYw5kfBztMZLVGGl9R9fOXdKcj0fqGs2br3e9D\n" + "ArBFqq07Bae2DD1J8mckWB2x9Uem4vjRiY+vEJcEdAS1N5xu1n7qzzyDgcRcS34X\n" + "PNBQeTrFMc2RS7mnip2DbyZVEjORobhguK6xZyqXXbvFacStGWDLptV3dcCn4JRO\n" + "dIORyt5wugqAtgE4qEGTvr/pJ/oXPw4Wve/trece/9I/AR38vW8ntVmDa/hV75iZ\n" + "4QGAhQ8grD4kq31GHXHUOmBX51XXW9SINmplC8elEx3R460EUZJjjb0OvTih+eZH\n" + "=8n2H\n" + "-----END PGP MESSAGE-----"); + + GpgBasicOperator::GetInstance().Decrypt( + encr_out_data, + [=, &callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto decr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_SECKEY); + ASSERT_FALSE(d_result.Recipients().empty()); + ASSERT_EQ(d_result.Recipients()[0].keyid, "A50CFD2F6C677D8C"); + + // stop waiting + callback_called_flag = true; + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreEncryptDecrTest_KeyNotFound_ResultAnalyse) { + std::atomic_bool callback_called_flag{false}; + + auto encr_out_data = GFBuffer( + "-----BEGIN PGP MESSAGE-----\n" + "\n" + "hQEMA6UM/S9sZ32MAQf9Fb6gp6nvgKTQBv2mmjXia6ODXYq6kNeLsPVzLCbHyWOs\n" + "0GDED11R1NksA3EQxFf4fzLkDpbo68r5bWy7c28c99Fr68IRET19Tw6Gu65MQezD\n" + "Rdzo1oVqmK9sfKqOT3+0S2H+suFYw5kfBztMZLVGGl9R9fOXdKcj0fqGs2br3e9D\n" + "ArBFqq07Bae2DD1J8mckWB2x9Uem4vjRiY+vEJcEdAS1N5xu1n7qzzyDgcRcS34X\n" + "PNBQeTrFMc2RS7mnip2DbyZVEjORobhguK6xZyqXXbvFacStGWDLptV3dcCn4JRO\n" + "dIORyt5wugqAtgE4qEGTvr/pJ/oXPw4Wve/trece/9I/AR38vW8ntVmDa/hV75iZ\n" + "4QGAhQ8grD4kq31GHXHUOmBX51XXW9SINmplC8elEx3R460EUZJjjb0OvTih+eZH\n" + "=8n2H\n" + "-----END PGP MESSAGE-----"); + + GpgBasicOperator::GetInstance().Decrypt( + encr_out_data, + [=, &callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto decr_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_SECKEY); + ASSERT_FALSE(d_result.Recipients().empty()); + ASSERT_EQ(d_result.Recipients()[0].keyid, "A50CFD2F6C677D8C"); + + GpgDecryptResultAnalyse analyse{err, d_result}; + analyse.Analyse(); + ASSERT_EQ(analyse.GetStatus(), -1); + ASSERT_FALSE(analyse.GetResultReport().isEmpty()); + + // stop waiting + callback_called_flag = true; + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) { + std::atomic_bool callback_called_flag{false}; + + auto sign_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_text = GFBuffer("Hello GpgFrontend!"); + + GpgBasicOperator::GetInstance().Sign( + {sign_key}, sign_text, GPGME_SIG_MODE_NORMAL, true, + [&callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgSignResult, GFBuffer>())); + auto result = ExtractParams<GpgSignResult>(data_obj, 0); + auto sign_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_TRUE(result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().Verify( + sign_out_buffer, GFBuffer(), + [&callback_called_flag](GpgError err, + const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgVerifyResult>(data_obj, 0); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(d_result.GetSignature().empty()); + ASSERT_EQ(d_result.GetSignature().at(0).GetFingerprint(), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreSignVerifyDetachTest) { + std::atomic_bool callback_called_flag{false}; + + auto sign_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_text = GFBuffer("Hello GpgFrontend!"); + + GpgBasicOperator::GetInstance().Sign( + {sign_key}, sign_text, GPGME_SIG_MODE_DETACH, true, + [=, &callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgSignResult, GFBuffer>())); + auto result = ExtractParams<GpgSignResult>(data_obj, 0); + auto sign_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_TRUE(result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().Verify( + sign_text, sign_out_buffer, + [&callback_called_flag](GpgError err, + const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgVerifyResult>(data_obj, 0); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(d_result.GetSignature().empty()); + ASSERT_EQ(d_result.GetSignature().at(0).GetFingerprint(), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreSignVerifyClearTest) { + std::atomic_bool callback_called_flag{false}; + + auto sign_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_text = GFBuffer("Hello GpgFrontend!"); + + GpgBasicOperator::GetInstance().Sign( + {sign_key}, sign_text, GPGME_SIG_MODE_CLEAR, true, + [&callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgSignResult, GFBuffer>())); + auto result = ExtractParams<GpgSignResult>(data_obj, 0); + auto sign_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + ASSERT_TRUE(result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().Verify( + sign_out_buffer, GFBuffer(), + [&callback_called_flag](GpgError err, + const DataObjectPtr& data_obj) { + auto verify_reult = ExtractParams<GpgVerifyResult>(data_obj, 0); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(verify_reult.GetSignature().empty()); + ASSERT_EQ(verify_reult.GetSignature().at(0).GetFingerprint(), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) { + std::atomic_bool callback_called_flag{false}; + + auto encrypt_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_key = GpgKeyGetter::GetInstance().GetKey( + "8933EB283A18995F45D61DAC021D89771B680FFB"); + auto encrypt_text = GFBuffer("Hello GpgFrontend!"); + + ASSERT_TRUE(sign_key.IsPrivateKey()); + ASSERT_TRUE(sign_key.IsHasActualSigningCapability()); + + GpgBasicOperator::GetInstance().EncryptSign( + {encrypt_key}, {sign_key}, encrypt_text, true, + [&callback_called_flag](GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE( + (data_obj->Check<GpgEncryptResult, GpgSignResult, GFBuffer>())); + auto encr_result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 1); + auto encr_out_buffer = ExtractParams<GFBuffer>(data_obj, 2); + ASSERT_TRUE(encr_result.InvalidRecipients().empty()); + ASSERT_TRUE(sign_result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgBasicOperator::GetInstance().DecryptVerify( + encr_out_buffer, [&callback_called_flag]( + GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE( + (data_obj + ->Check<GpgDecryptResult, GpgVerifyResult, GFBuffer>())); + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto verify_reult = ExtractParams<GpgVerifyResult>(data_obj, 1); + auto decr_out_buffer = ExtractParams<GFBuffer>(data_obj, 2); + + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + ASSERT_FALSE(decrypt_result.Recipients().empty()); + ASSERT_EQ(decr_out_buffer, GFBuffer("Hello GpgFrontend!")); + + ASSERT_EQ(decrypt_result.Recipients()[0].keyid, + "F89C95A05088CC93"); + ASSERT_FALSE(verify_reult.GetSignature().empty()); + ASSERT_EQ(verify_reult.GetSignature().at(0).GetFingerprint(), + "8933EB283A18995F45D61DAC021D89771B680FFB"); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +} // namespace GpgFrontend::Test diff --git a/src/test/core/GpgCoreTestFileBasicOpera.cpp b/src/test/core/GpgCoreTestFileBasicOpera.cpp new file mode 100644 index 00000000..029ff6fc --- /dev/null +++ b/src/test/core/GpgCoreTestFileBasicOpera.cpp @@ -0,0 +1,239 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GpgCoreTest.h" +#include "core/GpgModel.h" +#include "core/function/basic/ChannelObject.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/function/gpg/GpgFileOpera.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/result_analyse/GpgDecryptResultAnalyse.h" +#include "core/model/GpgDecryptResult.h" +#include "core/model/GpgEncryptResult.h" +#include "core/model/GpgSignResult.h" +#include "core/model/GpgVerifyResult.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" + +namespace GpgFrontend::Test { + +TEST_F(GpgCoreTest, CoreFileEncryptDecrTest) { + std::atomic_bool callback_called_flag{false}; + + auto encrypt_key = GpgKeyGetter::GetInstance().GetPubkey( + "E87C6A2D8D95C818DE93B3AE6A2764F8298DEB29"); + auto input_file = CreateTempFileAndWriteData("Hello GpgFrontend!"); + auto output_file = GetTempFilePath(); + + GpgFileOpera::GetInstance().EncryptFile( + {encrypt_key}, input_file, true, output_file, + [output_file, &callback_called_flag](GpgError err, + const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgEncryptResult>())); + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + ASSERT_TRUE(result.InvalidRecipients().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + auto decrpypt_output_file = GetTempFilePath(); + GpgFileOpera::GetInstance().DecryptFile( + output_file, decrpypt_output_file, + [decrpypt_output_file, &callback_called_flag]( + GpgError err, const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgDecryptResult>(data_obj, 0); + + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(d_result.Recipients().empty()); + ASSERT_EQ(d_result.Recipients()[0].keyid, "6A2764F8298DEB29"); + + const auto [read_success, buffer] = + ReadFileGFBuffer(decrpypt_output_file); + ASSERT_TRUE(read_success); + ASSERT_EQ(buffer, GFBuffer("Hello GpgFrontend!")); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreFileEncryptSymmetricDecrTest) { + std::atomic_bool callback_called_flag{false}; + + auto input_file = CreateTempFileAndWriteData("Hello GpgFrontend!"); + auto output_file = GetTempFilePath(); + + GpgFileOpera::GetInstance().EncryptFileSymmetric( + input_file, true, output_file, + [&callback_called_flag, output_file](GpgError err, + const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgEncryptResult>())); + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + ASSERT_TRUE(result.InvalidRecipients().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + auto decrpypt_output_file = GetTempFilePath(); + GpgFileOpera::GetInstance().DecryptFile( + output_file, decrpypt_output_file, + [&callback_called_flag, decrpypt_output_file]( + GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgDecryptResult>())); + + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_TRUE(decrypt_result.Recipients().empty()); + + const auto [read_success, buffer] = + ReadFileGFBuffer(decrpypt_output_file); + ASSERT_TRUE(read_success); + ASSERT_EQ(buffer, GFBuffer("Hello GpgFrontend!")); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreFileSignVerifyNormalTest) { + std::atomic_bool callback_called_flag{false}; + + auto sign_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto input_file = CreateTempFileAndWriteData("Hello GpgFrontend!"); + auto output_file = GetTempFilePath(); + + GpgFileOpera::GetInstance().SignFile( + {sign_key}, input_file, true, output_file, + [&callback_called_flag, input_file, output_file]( + GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgSignResult>())); + auto result = ExtractParams<GpgSignResult>(data_obj, 0); + ASSERT_TRUE(result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + GpgFileOpera::GetInstance().VerifyFile( + input_file, output_file, + [&callback_called_flag](GpgError err, + const DataObjectPtr& data_obj) { + auto d_result = ExtractParams<GpgVerifyResult>(data_obj, 0); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + ASSERT_FALSE(d_result.GetSignature().empty()); + ASSERT_EQ(d_result.GetSignature().at(0).GetFingerprint(), + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, CoreFileEncryptSignDecrVerifyTest) { + std::atomic_bool callback_called_flag{false}; + + auto encrypt_key = GpgKeyGetter::GetInstance().GetPubkey( + "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1"); + auto sign_key = GpgKeyGetter::GetInstance().GetKey( + "8933EB283A18995F45D61DAC021D89771B680FFB"); + auto input_file = CreateTempFileAndWriteData("Hello GpgFrontend!"); + auto output_file = GetTempFilePath(); + + ASSERT_TRUE(sign_key.IsPrivateKey()); + ASSERT_TRUE(sign_key.IsHasActualSigningCapability()); + + GpgFileOpera::GetInstance().EncryptSignFile( + {encrypt_key}, {sign_key}, input_file, true, output_file, + [&callback_called_flag, output_file](GpgError err, + const DataObjectPtr& data_obj) { + ASSERT_TRUE((data_obj->Check<GpgEncryptResult, GpgSignResult>())); + auto encr_result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 1); + ASSERT_TRUE(encr_result.InvalidRecipients().empty()); + ASSERT_TRUE(sign_result.InvalidSigners().empty()); + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + auto decrpypt_output_file = GetTempFilePath(); + GpgFileOpera::GetInstance().DecryptVerifyFile( + output_file, decrpypt_output_file, + [&callback_called_flag, decrpypt_output_file]( + GpgError err, const DataObjectPtr& data_obj) { + ASSERT_TRUE( + (data_obj->Check<GpgDecryptResult, GpgVerifyResult>())); + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto verify_reult = ExtractParams<GpgVerifyResult>(data_obj, 1); + + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + ASSERT_FALSE(decrypt_result.Recipients().empty()); + ASSERT_EQ(decrypt_result.Recipients()[0].keyid, + "F89C95A05088CC93"); + ASSERT_FALSE(verify_reult.GetSignature().empty()); + ASSERT_EQ(verify_reult.GetSignature().at(0).GetFingerprint(), + "8933EB283A18995F45D61DAC021D89771B680FFB"); + + const auto [read_success, buffer] = + ReadFileGFBuffer(decrpypt_output_file); + ASSERT_TRUE(read_success); + ASSERT_EQ(buffer, GFBuffer("Hello GpgFrontend!")); + + // stop waiting + callback_called_flag = true; + }); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +} // namespace GpgFrontend::Test diff --git a/src/test/core/GpgCoreTestImportExport.cpp b/src/test/core/GpgCoreTestImportExport.cpp new file mode 100644 index 00000000..faf8b58a --- /dev/null +++ b/src/test/core/GpgCoreTestImportExport.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include <string> +#include <vector> + +#include "GpgCoreTest.h" +#include "core/GpgConstants.h" + +namespace GpgFrontend::Test { + +// TEST_F(GpgCoreTest, CoreExportSecretTest) {} + +} // namespace GpgFrontend::Test
\ No newline at end of file diff --git a/src/test/core/GpgCoreTestKeyModel.cpp b/src/test/core/GpgCoreTestKeyModel.cpp new file mode 100644 index 00000000..cf1fd9ea --- /dev/null +++ b/src/test/core/GpgCoreTestKeyModel.cpp @@ -0,0 +1,181 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include <gtest/gtest.h> + +#include "GpgCoreTest.h" +#include "core/function/gpg/GpgContext.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/GpgData.h" +#include "core/model/GpgKey.h" +#include "core/utils/GpgUtils.h" + +namespace GpgFrontend::Test { + +TEST_F(GpgCoreTest, CoreInitTest) { + auto& ctx = GpgContext::GetInstance(kGpgFrontendDefaultChannel); + auto& ctx_default = GpgContext::GetInstance(); + ASSERT_TRUE(ctx.Good()); + ASSERT_TRUE(ctx_default.Good()); +} + +TEST_F(GpgCoreTest, GpgDataTest) { + auto data_buff = QString( + "cqEh8fyKWtmiXrW2zzlszJVGJrpXDDpzgP7ZELGxhfZYFi8rMrSVKDwrpFZBSWMG"); + + GpgData data(data_buff.data(), data_buff.size()); + + auto out_buffer = data.Read2GFBuffer(); + ASSERT_EQ(out_buffer.Size(), 64); +} + +TEST_F(GpgCoreTest, GpgKeyTest) { + auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); + ASSERT_TRUE(key.IsGood()); + ASSERT_TRUE(key.IsPrivateKey()); + ASSERT_TRUE(key.IsHasMasterKey()); + + ASSERT_FALSE(key.IsDisabled()); + ASSERT_FALSE(key.IsRevoked()); + + ASSERT_EQ(key.GetProtocol(), "OpenPGP"); + + ASSERT_EQ(key.GetSubKeys()->size(), 2); + ASSERT_EQ(key.GetUIDs()->size(), 1); + + ASSERT_TRUE(key.IsHasCertificationCapability()); + ASSERT_FALSE(key.IsHasEncryptionCapability()); + ASSERT_TRUE(key.IsHasSigningCapability()); + ASSERT_FALSE(key.IsHasAuthenticationCapability()); + ASSERT_FALSE(key.IsHasActualCertificationCapability()); + ASSERT_FALSE(key.IsHasActualEncryptionCapability()); + ASSERT_FALSE(key.IsHasActualSigningCapability()); + ASSERT_FALSE(key.IsHasActualAuthenticationCapability()); + + ASSERT_EQ(key.GetName(), "GpgFrontendTest"); + ASSERT_TRUE(key.GetComment().isEmpty()); + ASSERT_EQ(key.GetEmail(), "[email protected]"); + ASSERT_EQ(key.GetId(), "81704859182661FB"); + ASSERT_EQ(key.GetFingerprint(), "9490795B78F8AFE9F93BD09281704859182661FB"); + ASSERT_EQ(key.GetExpireTime(), + QDateTime::fromString("20230905T040000", Qt::ISODate)); + ASSERT_EQ(key.GetPublicKeyAlgo(), "RSA"); + ASSERT_EQ(key.GetPrimaryKeyLength(), 3072); + ASSERT_EQ(key.GetLastUpdateTime(), + QDateTime::fromString("19700101T000000", Qt::ISODate)); + ASSERT_EQ(key.GetCreateTime(), + QDateTime::fromString("20210905T060153", Qt::ISODate)); + + ASSERT_EQ(key.GetOwnerTrust(), "Unknown"); + + ASSERT_EQ(key.IsExpired(), + key.GetExpireTime() < QDateTime::currentDateTime()); +} + +TEST_F(GpgCoreTest, GpgSubKeyTest) { + auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); + auto sub_keys = key.GetSubKeys(); + ASSERT_EQ(sub_keys->size(), 2); + + auto& sub_key = sub_keys->back(); + + ASSERT_FALSE(sub_key.IsRevoked()); + ASSERT_FALSE(sub_key.IsDisabled()); + ASSERT_EQ(sub_key.GetCreateTime(), + QDateTime::fromString("20210905T060153", Qt::ISODate)); + + ASSERT_FALSE(sub_key.IsCardKey()); + ASSERT_TRUE(sub_key.IsPrivateKey()); + ASSERT_EQ(sub_key.GetID(), "2B36803235B5E25B"); + ASSERT_EQ(sub_key.GetFingerprint(), + "50D37E8F8EE7340A6794E0592B36803235B5E25B"); + ASSERT_EQ(sub_key.GetKeyLength(), 3072); + ASSERT_EQ(sub_key.GetPubkeyAlgo(), "RSA"); + ASSERT_FALSE(sub_key.IsHasCertificationCapability()); + ASSERT_FALSE(sub_key.IsHasAuthenticationCapability()); + ASSERT_FALSE(sub_key.IsHasSigningCapability()); + ASSERT_TRUE(sub_key.IsHasEncryptionCapability()); + ASSERT_EQ(key.GetExpireTime(), + QDateTime::fromString("20230905T040000", Qt::ISODate)); + + ASSERT_EQ(sub_key.IsExpired(), + sub_key.GetExpireTime() < QDateTime::currentDateTime()); +} + +TEST_F(GpgCoreTest, GpgUIDTest) { + auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); + auto uids = key.GetUIDs(); + ASSERT_EQ(uids->size(), 1); + auto& uid = uids->front(); + + ASSERT_EQ(uid.GetName(), "GpgFrontendTest"); + ASSERT_TRUE(uid.GetComment().isEmpty()); + ASSERT_EQ(uid.GetEmail(), "[email protected]"); + ASSERT_EQ(uid.GetUID(), "GpgFrontendTest <[email protected]>"); + ASSERT_FALSE(uid.GetInvalid()); + ASSERT_FALSE(uid.GetRevoked()); +} + +TEST_F(GpgCoreTest, GpgKeySignatureTest) { + auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); + auto uids = key.GetUIDs(); + ASSERT_EQ(uids->size(), 1); + auto& uid = uids->front(); + + auto signatures = uid.GetSignatures(); + ASSERT_EQ(signatures->size(), 1); + auto& signature = signatures->front(); + + ASSERT_EQ(signature.GetName(), "GpgFrontendTest"); + ASSERT_TRUE(signature.GetComment().isEmpty()); + ASSERT_EQ(signature.GetEmail(), "[email protected]"); + ASSERT_EQ(signature.GetKeyID(), "81704859182661FB"); + ASSERT_EQ(signature.GetPubkeyAlgo(), "RSA"); + + ASSERT_FALSE(signature.IsRevoked()); + ASSERT_FALSE(signature.IsInvalid()); + ASSERT_EQ(CheckGpgError(signature.GetStatus()), GPG_ERR_NO_ERROR); + ASSERT_EQ(signature.GetUID(), + "GpgFrontendTest <[email protected]>"); +} + +TEST_F(GpgCoreTest, GpgKeyGetterTest) { + auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) + .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); + ASSERT_TRUE(key.IsGood()); + auto keys = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).FetchKey(); + + EXPECT_GT(keys->size(), 0); + ASSERT_TRUE(find(keys->begin(), keys->end(), key) != keys->end()); +} + +} // namespace GpgFrontend::Test
\ No newline at end of file diff --git a/src/test/core/GpgCoreTestKeygen.cpp b/src/test/core/GpgCoreTestKeygen.cpp new file mode 100644 index 00000000..57e7cbb9 --- /dev/null +++ b/src/test/core/GpgCoreTestKeygen.cpp @@ -0,0 +1,212 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include <gtest/gtest.h> +#include <qeventloop.h> + +#include <cstddef> + +#include "GpgCoreTest.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgKeyOpera.h" +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/model/GpgGenKeyInfo.h" +#include "core/model/GpgGenerateKeyResult.h" +#include "core/model/GpgKey.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend::Test { + +TEST_F(GpgCoreTest, GenerateKeyTest) { + auto keygen_info = SecureCreateSharedObject<GenKeyInfo>(); + keygen_info->SetName("foo_0"); + keygen_info->SetEmail("[email protected]"); + keygen_info->SetComment(""); + keygen_info->SetKeyLength(1024); + keygen_info->SetAlgo(std::get<1>(keygen_info->GetSupportedKeyAlgo()[0])); + keygen_info->SetNonExpired(true); + keygen_info->SetNonPassPhrase(true); + + std::atomic_bool callback_called_flag{false}; + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel) + .GenerateKey(keygen_info, [&callback_called_flag]( + GpgError err, + const DataObjectPtr& data_object) { + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + ASSERT_EQ(data_object->GetObjectSize(), 1); + ASSERT_TRUE(data_object->Check<GpgGenerateKeyResult>()); + + auto result = ExtractParams<GpgGenerateKeyResult>(data_object, 0); + ASSERT_TRUE(result.IsGood()); + auto fpr = result.GetFingerprint(); + + auto key = + GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).GetKey(fpr); + ASSERT_TRUE(key.IsGood()); + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel).DeleteKey(fpr); + + callback_called_flag = true; + ASSERT_FALSE(fpr.isEmpty()); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, GenerateKeyTest_1) { + auto keygen_info = SecureCreateSharedObject<GenKeyInfo>(); + keygen_info->SetName("foo_1"); + keygen_info->SetEmail("[email protected]"); + keygen_info->SetComment("hello gpgfrontend"); + keygen_info->SetAlgo(std::get<1>(keygen_info->GetSupportedKeyAlgo()[0])); + keygen_info->SetKeyLength(4096); + keygen_info->SetNonExpired(false); + keygen_info->SetExpireTime( + QDateTime::currentDateTime().addSecs(static_cast<qint64>(24 * 3600))); + keygen_info->SetNonPassPhrase(false); + + std::atomic_bool callback_called_flag{false}; + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel) + .GenerateKey(keygen_info, [&callback_called_flag]( + GpgError err, + const DataObjectPtr& data_object) { + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + ASSERT_EQ(data_object->GetObjectSize(), 1); + ASSERT_TRUE(data_object->Check<GpgGenerateKeyResult>()); + + auto result = ExtractParams<GpgGenerateKeyResult>(data_object, 0); + ASSERT_TRUE(result.IsGood()); + auto fpr = result.GetFingerprint(); + + auto key = + GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).GetKey(fpr); + ASSERT_TRUE(key.IsGood()); + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel).DeleteKey(fpr); + + callback_called_flag = true; + ASSERT_FALSE(fpr.isEmpty()); + }); + + int retry_count = 2000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, GenerateKeyTest_4) { + auto keygen_info = SecureCreateSharedObject<GenKeyInfo>(); + keygen_info->SetName("foo_2"); + keygen_info->SetEmail("[email protected]"); + keygen_info->SetComment(""); + keygen_info->SetAlgo(std::get<1>(keygen_info->GetSupportedKeyAlgo()[1])); + keygen_info->SetNonExpired(true); + keygen_info->SetNonPassPhrase(false); + + std::atomic_bool callback_called_flag{false}; + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel) + .GenerateKey(keygen_info, [&callback_called_flag]( + GpgError err, + const DataObjectPtr& data_object) { + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + auto result = ExtractParams<GpgGenerateKeyResult>(data_object, 0); + ASSERT_TRUE(result.IsGood()); + auto fpr = result.GetFingerprint(); + + auto key = + GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).GetKey(fpr); + ASSERT_TRUE(key.IsGood()); + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel).DeleteKey(fpr); + + callback_called_flag = true; + ASSERT_FALSE(fpr.isEmpty()); + }); + + int retry_count = 2000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +TEST_F(GpgCoreTest, GenerateKeyTest_5) { + auto keygen_info = SecureCreateSharedObject<GenKeyInfo>(); + keygen_info->SetName("foo_3"); + keygen_info->SetEmail("[email protected]"); + keygen_info->SetComment(""); + keygen_info->SetAlgo(std::get<1>(keygen_info->GetSupportedKeyAlgo()[2])); + keygen_info->SetNonExpired(true); + keygen_info->SetNonPassPhrase(false); + + std::atomic_bool callback_called_flag{false}; + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel) + .GenerateKey(keygen_info, [&callback_called_flag]( + GpgError err, + const DataObjectPtr& data_object) { + ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR); + + auto result = ExtractParams<GpgGenerateKeyResult>(data_object, 0); + ASSERT_TRUE(result.IsGood()); + auto fpr = result.GetFingerprint(); + + auto key = + GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).GetKey(fpr); + ASSERT_TRUE(key.IsGood()); + + GpgKeyOpera::GetInstance(kGpgFrontendDefaultChannel).DeleteKey(fpr); + + callback_called_flag = true; + ASSERT_FALSE(fpr.isEmpty()); + }); + + int retry_count = 1000; + while (!callback_called_flag && retry_count-- > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + ASSERT_TRUE(callback_called_flag); +} + +} // namespace GpgFrontend::Test diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index ba72c49a..c9c27462 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,5 +1,4 @@ -# -# Copyright (C) 2021 Saturneric +# Copyright (C) 2021 Saturneric <[email protected]> # # This file is part of GpgFrontend. # @@ -20,10 +19,11 @@ # the gpg4usb project, which is under GPL-3.0-or-later. # # All the source code of GpgFrontend was modified and released by -# Saturneric<[email protected]> starting on May 12, 2021. +# Saturneric <[email protected]> starting on May 12, 2021. # # SPDX-License-Identifier: GPL-3.0-or-later + # tracking source files aux_source_directory(. UI_SOURCE) aux_source_directory(dialog/keypair_details UI_SOURCE) @@ -38,6 +38,7 @@ aux_source_directory(struct UI_SOURCE) aux_source_directory(dialog/import_export UI_SOURCE) aux_source_directory(dialog/gnupg UI_SOURCE) aux_source_directory(dialog UI_SOURCE) +aux_source_directory(function UI_SOURCE) # define libgpgfrontend_ui set(CMAKE_CXX_VISIBILITY_PRESET hidden) @@ -47,17 +48,15 @@ set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendUIExport.h") generate_export_header(gpgfrontend_ui EXPORT_FILE_NAME "${_export_file}") # link Qt -if(Qt6_DIR) - target_link_libraries(gpgfrontend_ui - Qt6::Network Qt6::PrintSupport Qt6::Widgets Qt6::Test Qt6::Core5Compat Qt6::Core) -else() - target_link_libraries(gpgfrontend_ui - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) -endif() +target_link_libraries(gpgfrontend_ui + Qt6::Network Qt6::PrintSupport Qt6::Test Qt6::Core5Compat) + # link gpgfrontend_core -target_link_libraries(gpgfrontend_ui - gpgfrontend_core) +target_link_libraries(gpgfrontend_ui gpgfrontend_core) + +# link buddled pinentry +target_link_libraries(gpgfrontend_ui gpgfrontend_pinentry) # set up pch target_precompile_headers(gpgfrontend_ui PUBLIC GpgFrontendUI.h) diff --git a/src/ui/GpgFrontendApplication.cpp b/src/ui/GpgFrontendApplication.cpp index 3697adde..1304aad5 100644 --- a/src/ui/GpgFrontendApplication.cpp +++ b/src/ui/GpgFrontendApplication.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,8 +19,10 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ @@ -35,62 +37,49 @@ namespace GpgFrontend::UI { GpgFrontendApplication::GpgFrontendApplication(int &argc, char *argv[]) : QApplication(argc, argv) { #ifndef MACOS - this->setWindowIcon(QIcon(":gpgfrontend.png")); + this->setWindowIcon(QIcon(":/icons/gpgfrontend.png")); #endif // set the extra information of the build - this->setApplicationVersion(BUILD_VERSION); - this->setApplicationName(PROJECT_NAME); - this->setQuitOnLastWindowClosed(true); + GpgFrontendApplication::setApplicationVersion(BUILD_VERSION); + GpgFrontendApplication::setApplicationName(PROJECT_NAME); + GpgFrontendApplication::setApplicationDisplayName(PROJECT_NAME); + GpgFrontendApplication::setOrganizationName(PROJECT_NAME); + GpgFrontendApplication::setQuitOnLastWindowClosed(true); // don't show icons in menus - this->setAttribute(Qt::AA_DontShowIconsInMenus); + GpgFrontendApplication::setAttribute(Qt::AA_DontShowIconsInMenus); // unicode in source QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8")); } -GpgFrontendApplication *GpgFrontendApplication::GetInstance(int argc, - char *argv[], - bool new_instance) { - static GpgFrontendApplication *instance = nullptr; - static int static_argc = argc; - static char **static_argv = argv; - - if (new_instance || !instance) { - if (instance != nullptr) { - SPDLOG_DEBUG("old application exists, quitting..."); - instance->quit(); - delete instance; - } - SPDLOG_DEBUG("creating new application instance, argc: {}", argc); - instance = new GpgFrontendApplication(static_argc, static_argv); - } - return instance; -} - bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) { - bool app_done = true; +#ifdef RELEASE try { - app_done = QApplication::notify(receiver, event); + return QApplication::notify(receiver, event); } catch (const std::exception &ex) { - SPDLOG_ERROR("exception caught in notify: {}", ex.what()); - QMessageBox::information(nullptr, _("Standard Exception Thrown"), - _("Oops, an standard exception was thrown " - "during the running of the " - "program. This is not a serious problem, it may " - "be the negligence of the programmer, " - "please report this problem if you can.")); + GF_UI_LOG_ERROR("exception was caught in notify: {}", ex.what()); + QMessageBox::information( + nullptr, tr("Standard Exception Thrown"), + tr("Oops, an standard exception was thrown " + "during the running of the " + "program. This is not a serious problem, it may " + "be the negligence of the programmer, " + "please report this problem if you can.")); } catch (...) { - SPDLOG_ERROR("unknown exception caught in notify"); + GF_UI_LOG_ERROR("unknown exception was caught in notify"); QMessageBox::information( - nullptr, _("Unhandled Exception Thrown"), - _("Oops, an unhandled exception was thrown " - "during the running of the program. This is not a " - "serious problem, it may be the negligence of the programmer, " - "please report this problem if you can.")); + nullptr, tr("Unhandled Exception Thrown"), + tr("Oops, an unhandled exception was thrown " + "during the running of the program. This is not a " + "serious problem, it may be the negligence of the programmer, " + "please report this problem if you can.")); } - return app_done; + return -1; +#else + return QApplication::notify(receiver, event); +#endif } } // namespace GpgFrontend::UI diff --git a/src/ui/GpgFrontendApplication.h b/src/ui/GpgFrontendApplication.h index 06338bb6..1ec782cf 100644 --- a/src/ui/GpgFrontendApplication.h +++ b/src/ui/GpgFrontendApplication.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,16 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "ui/GpgFrontendUI.h" -#ifndef GPGFRONTEND_GPGFRONTENDAPPLICATION_H -#define GPGFRONTEND_GPGFRONTENDAPPLICATION_H +#pragma once namespace GpgFrontend::UI { @@ -48,15 +49,6 @@ class GPGFRONTEND_UI_EXPORT GpgFrontendApplication : public QApplication { */ ~GpgFrontendApplication() override = default; - /** - * @brief Get the GpgFrontend Application object - * - * @return GpgFrontendApplication* - */ - static GpgFrontendApplication *GetInstance(int argc = 0, - char *argv[] = nullptr, - bool new_instance = false); - protected: /** * @brief @@ -68,5 +60,3 @@ class GPGFRONTEND_UI_EXPORT GpgFrontendApplication : public QApplication { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GPGFRONTENDAPPLICATION_H
\ No newline at end of file diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h index 4389aa41..b3115795 100644 --- a/src/ui/GpgFrontendUI.h +++ b/src/ui/GpgFrontendUI.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,37 +20,29 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGFRONTENDUI_H -#define GPGFRONTEND_GPGFRONTENDUI_H +#pragma once /** * Basic dependency */ -#include <QtCore> -#include <QtNetwork> -#include <QtPrintSupport> #include <QtWidgets> -#include <optional> -/** - * Project internal dependencies - */ +// Core #include "GpgFrontend.h" #include "core/GpgFrontendCore.h" -#include "core/GpgModel.h" -#include "core/thread/ThreadingModel.h" -#include "ui/GpgFrontendUIExport.h" +#include "core/utils/LogUtils.h" -/** - * 3rd party dependencies - */ - -#include <qt-aes/qaesencryption.h> +// UI +#include "ui/GpgFrontendUIExport.h" -#endif // GPGFRONTEND_GPGFRONTENDUI_H +#define GF_UI_LOG_TRACE(...) GF_LOG_TRACE("ui", __VA_ARGS__) +#define GF_UI_LOG_DEBUG(...) GF_LOG_DEBUG("ui", __VA_ARGS__) +#define GF_UI_LOG_INFO(...) GF_LOG_INFO("ui", __VA_ARGS__) +#define GF_UI_LOG_WARN(...) GF_LOG_WARN("ui", __VA_ARGS__) +#define GF_UI_LOG_ERROR(...) GF_LOG_ERROR("ui", __VA_ARGS__) diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp index bfe4d828..c7f54286 100644 --- a/src/ui/GpgFrontendUIInit.cpp +++ b/src/ui/GpgFrontendUIInit.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,76 +28,109 @@ #include "GpgFrontendUIInit.h" -#include <spdlog/async.h> -#include <spdlog/common.h> -#include <spdlog/sinks/rotating_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> - -#include <string> +#include <clocale> #include "core/GpgConstants.h" +#include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" -#include "core/thread/CtxCheckTask.h" -#include "core/thread/TaskRunnerGetter.h" -#include "spdlog/spdlog.h" -#include "ui/SignalStation.h" +#include "core/module/ModuleManager.h" +#include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/main_window/MainWindow.h" -#if !defined(RELEASE) && defined(WINDOWS) -#include "core/function/GlobalSettingStation.h" -#endif - namespace GpgFrontend::UI { -extern void init_logging_system(); -extern void init_locale(); +extern void InitLocale(); + +void WaitEnvCheckingProcess() { + GF_UI_LOG_DEBUG("need to waiting for env checking process"); + + // create and show loading window before starting the main window + auto* waiting_dialog = new QProgressDialog(); + waiting_dialog->setMaximum(0); + waiting_dialog->setMinimum(0); + auto* waiting_dialog_label = new QLabel( + QObject::tr("Loading Gnupg Info...") + "<br /><br />" + + QObject::tr("If this process is too slow, please set the key " + "server address appropriately in the gnupg configuration " + "file (depending " + "on the network situation in your country or region).")); + waiting_dialog_label->setWordWrap(true); + waiting_dialog->setLabel(waiting_dialog_label); + waiting_dialog->resize(420, 120); + QApplication::connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalGoodGnupgEnv, waiting_dialog, + [=]() { + GF_UI_LOG_DEBUG("gpg env loaded successfuly"); + waiting_dialog->finished(0); + waiting_dialog->deleteLater(); + }); + + // new local event looper + QEventLoop looper; + QApplication::connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalGoodGnupgEnv, &looper, + &QEventLoop::quit); + + QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() { + GF_UI_LOG_DEBUG("cancel clicked on wairing dialog"); + QApplication::quit(); + exit(0); + }); + + auto env_state = + Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0); + GF_UI_LOG_DEBUG("ui is ready to wating for env initialized, env_state: {}", + env_state); + + // check twice to avoid some unlucky sitations + if (env_state == 1) { + GF_UI_LOG_DEBUG("env state turned initialized before the looper start"); + waiting_dialog->finished(0); + waiting_dialog->deleteLater(); + return; + } + + // show the loading window + waiting_dialog->setModal(true); + waiting_dialog->setFocus(); + waiting_dialog->show(); + + // block the main thread until the gpg context is loaded + looper.exec(); +} + +void PreInitGpgFrontendUI() { CommonUtils::GetInstance(); } -void InitGpgFrontendUI(QApplication* app) { +void InitGpgFrontendUI(QApplication* /*app*/) { // init locale - init_locale(); - -#if !defined(RELEASE) && defined(WINDOWS) - // css - std::filesystem::path css_path = - GpgFrontend::GlobalSettingStation::GetInstance().GetResourceDir() / - "css" / "default.qss"; - QFile file(css_path.u8string().c_str()); - file.open(QFile::ReadOnly); - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); -#endif + InitLocale(); // init signal station - SignalStation::GetInstance(); + UISignalStation::GetInstance(); // init common utils CommonUtils::GetInstance(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + // application proxy configure - bool proxy_enable = - GlobalSettingStation::GetInstance().LookupSettings("proxy.enable", false); + bool proxy_enable = settings.value("proxy/enable", false).toBool(); // if enable proxy for application if (proxy_enable) { try { - std::string proxy_type = - GlobalSettingStation::GetInstance().LookupSettings("proxy.proxy_type", - std::string{}); - std::string proxy_host = - GlobalSettingStation::GetInstance().LookupSettings("proxy.proxy_host", - std::string{}); - int proxy_port = - GlobalSettingStation::GetInstance().LookupSettings("proxy.port", 0); - std::string proxy_username = - GlobalSettingStation::GetInstance().LookupSettings("proxy.username", - std::string{}); - std::string proxy_password = - GlobalSettingStation::GetInstance().LookupSettings("proxy.password", - std::string{}); - SPDLOG_DEBUG("proxy settings: type {}, host {}, port: {}", proxy_type, - proxy_host, proxy_port); + QString proxy_type = + settings.value("proxy/proxy_type", QString{}).toString(); + QString proxy_host = + settings.value("proxy/proxy_host", QString{}).toString(); + int proxy_port = settings.value("prox/port", 0).toInt(); + QString proxy_username = + settings.value("proxy/username", QString{}).toString(); + QString proxy_password = + settings.value("proxy/password", QString{}).toString(); + GF_UI_LOG_DEBUG("proxy settings: type {}, host {}, port: {}", proxy_type, + proxy_host, proxy_port); QNetworkProxy::ProxyType proxy_type_qt = QNetworkProxy::NoProxy; if (proxy_type == "HTTP") { @@ -112,19 +145,21 @@ void InitGpgFrontendUI(QApplication* app) { QNetworkProxy proxy; if (proxy_type_qt != QNetworkProxy::DefaultProxy) { proxy.setType(proxy_type_qt); - proxy.setHostName(QString::fromStdString(proxy_host)); + proxy.setHostName(proxy_host); proxy.setPort(proxy_port); - if (!proxy_username.empty()) - proxy.setUser(QString::fromStdString(proxy_username)); - if (!proxy_password.empty()) - proxy.setPassword(QString::fromStdString(proxy_password)); + if (!proxy_username.isEmpty()) { + proxy.setUser(proxy_username); + } + if (!proxy_password.isEmpty()) { + proxy.setPassword(proxy_password); + } } else { proxy.setType(proxy_type_qt); } QNetworkProxy::setApplicationProxy(proxy); } catch (...) { - SPDLOG_ERROR("setting operation error: proxy setings"); + GF_UI_LOG_ERROR("setting operation error: proxy setings"); // no proxy by default QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); } @@ -133,196 +168,60 @@ void InitGpgFrontendUI(QApplication* app) { QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); } - // create the thread to load the gpg context - auto* init_ctx_task = new Thread::CtxCheckTask(); - - // create and show loading window before starting the main window - auto* waiting_dialog = new QProgressDialog(); - waiting_dialog->setMaximum(0); - waiting_dialog->setMinimum(0); - auto waiting_dialog_label = - new QLabel(QString(_("Loading Gnupg Info...")) + "<br /><br />" + - _("If this process is too slow, please set the key " - "server address appropriately in the gnupg configuration " - "file (depending " - "on the network situation in your country or region).")); - waiting_dialog_label->setWordWrap(true); - waiting_dialog->setLabel(waiting_dialog_label); - waiting_dialog->resize(420, 120); - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, - waiting_dialog, [=]() { - SPDLOG_DEBUG("gpg context loaded"); - waiting_dialog->finished(0); - waiting_dialog->deleteLater(); - }); - - app->connect(waiting_dialog, &QProgressDialog::canceled, [=]() { - SPDLOG_DEBUG("cancel clicked"); - app->quit(); - exit(0); - }); - - // show the loading window - waiting_dialog->setModal(true); - waiting_dialog->setFocus(); - waiting_dialog->show(); - - // new local event looper - QEventLoop looper; - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, &looper, - &QEventLoop::quit); - - // start the thread to load the gpg context - Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( - init_ctx_task); + if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0) == + 0) { + WaitEnvCheckingProcess(); + } - // block the main thread until the gpg context is loaded - looper.exec(); + qRegisterMetaType<QSharedPointer<GpgPassphraseContext> >( + "QSharedPointer<GpgPassphraseContext>"); } -int RunGpgFrontendUI(QApplication* app) { +auto RunGpgFrontendUI(QApplication* app) -> int { // create main window and show it auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>(); // pre-check, if application need to restart if (CommonUtils::GetInstance()->isApplicationNeedRestart()) { - SPDLOG_DEBUG("application need to restart, before mian window init"); - return DEEP_RESTART_CODE; - } else { - main_window->Init(); - SPDLOG_DEBUG("main window inited"); - main_window->show(); + GF_UI_LOG_DEBUG("application need to restart, before mian window init"); + return kDeepRestartCode; } + // init main window + main_window->Init(); + + // show main windows + GF_UI_LOG_DEBUG("main window is ready to show"); + main_window->show(); + // start the main event loop return app->exec(); } -void InitUILoggingSystem() { - using namespace boost::posix_time; - using namespace boost::gregorian; - - // get the log directory - auto logfile_path = (GlobalSettingStation::GetInstance().GetLogDir() / "ui"); - logfile_path.replace_extension(".log"); - - // sinks - std::vector<spdlog::sink_ptr> sinks; - sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); - sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( - logfile_path.u8string(), 1048576 * 32, 32)); - - // thread pool - spdlog::init_thread_pool(1024, 2); - - // logger - auto ui_logger = std::make_shared<spdlog::async_logger>( - "ui", begin(sinks), end(sinks), spdlog::thread_pool()); - ui_logger->set_pattern( - "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); - -#ifdef DEBUG - ui_logger->set_level(spdlog::level::trace); -#else - ui_logger->set_level(spdlog::level::info); -#endif - - // flush policy - ui_logger->flush_on(spdlog::level::err); - spdlog::flush_every(std::chrono::seconds(5)); - - // register it as default logger - spdlog::set_default_logger(ui_logger); -} - -void ShutdownUILoggingSystem() { -#ifdef WINDOWS - // Under VisualStudio, this must be called before main finishes to workaround - // a known VS issue - spdlog::drop_all(); - spdlog::shutdown(); -#endif -} +void GPGFRONTEND_UI_EXPORT DestroyGpgFrontendUI() {} /** * @brief setup the locale and load the translations * */ -void init_locale() { +void InitLocale() { // get the instance of the GlobalSettingStation - auto& settings = - GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); - - // create general settings if not exist - if (!settings.exists("general") || - settings.lookup("general").getType() != libconfig::Setting::TypeGroup) - settings.add("general", libconfig::Setting::TypeGroup); - - // set system default at first - auto& general = settings["general"]; - if (!general.exists("lang")) - general.add("lang", libconfig::Setting::TypeString) = ""; - - // sync the settings to the file - GpgFrontend::GlobalSettingStation::GetInstance().SyncSettings(); - - SPDLOG_DEBUG("current system locale: {}", setlocale(LC_ALL, nullptr)); + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); // read from settings file - std::string lang; - if (!general.lookupValue("lang", lang)) { - SPDLOG_ERROR(_("could not read properly from configure file")); - }; - - SPDLOG_DEBUG("lang from settings: {}", lang); - SPDLOG_DEBUG("project name: {}", PROJECT_NAME); - SPDLOG_DEBUG("locales path: {}", - GpgFrontend::GlobalSettingStation::GetInstance() - .GetLocaleDir() - .u8string()); - -#ifndef WINDOWS - if (!lang.empty()) { - std::string lc = lang + ".UTF-8"; - - // set LC_ALL - auto* locale_name = setlocale(LC_ALL, lc.c_str()); - if (locale_name == nullptr) SPDLOG_WARN("set LC_ALL failed, lc: {}", lc); - auto language = getenv("LANGUAGE"); - // set LANGUAGE - std::string language_env = language == nullptr ? "en" : language; - language_env.insert(0, lang + ":"); - SPDLOG_DEBUG("language env: {}", language_env); - if (setenv("LANGUAGE", language_env.c_str(), 1)) { - SPDLOG_WARN("set LANGUAGE {} failed", language_env); - }; - } -#else - if (!lang.empty()) { - std::string lc = lang; - - // set LC_ALL - auto* locale_name = setlocale(LC_ALL, lc.c_str()); - if (locale_name == nullptr) SPDLOG_WARN("set LC_ALL failed, lc: {}", lc); - - auto language = getenv("LANGUAGE"); - // set LANGUAGE - std::string language_env = language == nullptr ? "en" : language; - language_env.insert(0, lang + ":"); - language_env.insert(0, "LANGUAGE="); - SPDLOG_DEBUG("language env: {}", language_env); - if (putenv(language_env.c_str())) { - SPDLOG_WARN("set LANGUAGE {} failed", language_env); - }; + auto lang = settings.value("basic/lang").toString(); + GF_UI_LOG_INFO("current system locale: {}", QLocale().name()); + GF_UI_LOG_INFO("current custom locale settings: {}", lang); + + auto target_locale = lang.isEmpty() ? QLocale() : QLocale(lang); + auto* translator = new QTranslator(QCoreApplication::instance()); + if (translator->load(target_locale, QLatin1String(PROJECT_NAME), + QLatin1String("."), QLatin1String(":/i18n"), + QLatin1String(".qm"))) { + GF_UI_LOG_INFO("load target translation file done"); + QCoreApplication::installTranslator(translator); } -#endif - - bindtextdomain(PROJECT_NAME, GpgFrontend::GlobalSettingStation::GetInstance() - .GetLocaleDir() - .u8string() - .c_str()); - bind_textdomain_codeset(PROJECT_NAME, "utf-8"); - textdomain(PROJECT_NAME); } } // namespace GpgFrontend::UI diff --git a/src/ui/GpgFrontendUIInit.h b/src/ui/GpgFrontendUIInit.h index 0e68aa57..fd62f3f6 100644 --- a/src/ui/GpgFrontendUIInit.h +++ b/src/ui/GpgFrontendUIInit.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,42 +20,39 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GPGFRONTENDUIINIT_H -#define GPGFRONTEND_GPGFRONTENDUIINIT_H +#pragma once #include "GpgFrontendUI.h" namespace GpgFrontend::UI { /** - * @brief init the UI library + * @brief * */ -void GPGFRONTEND_UI_EXPORT InitGpgFrontendUI(QApplication *); +void GPGFRONTEND_UI_EXPORT PreInitGpgFrontendUI(); /** - * @brief - * + * @brief init the UI library + * */ -void GPGFRONTEND_UI_EXPORT InitUILoggingSystem(); +void GPGFRONTEND_UI_EXPORT InitGpgFrontendUI(QApplication *); /** - * @brief - * + * @brief init the UI library + * */ -void GPGFRONTEND_UI_EXPORT ShutdownUILoggingSystem(); +void GPGFRONTEND_UI_EXPORT DestroyGpgFrontendUI(); /** * @brief run main window */ -int GPGFRONTEND_UI_EXPORT RunGpgFrontendUI(QApplication *); +auto GPGFRONTEND_UI_EXPORT RunGpgFrontendUI(QApplication *) -> int; }; // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GPGFRONTENDUIINIT_H diff --git a/src/ui/UISignalStation.cpp b/src/ui/UISignalStation.cpp new file mode 100644 index 00000000..8357cb06 --- /dev/null +++ b/src/ui/UISignalStation.cpp @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "UISignalStation.h" + +namespace GpgFrontend::UI { + +std::unique_ptr<UISignalStation> UISignalStation::instance = nullptr; + +auto UISignalStation::GetInstance() -> UISignalStation* { + if (instance == nullptr) { + instance = std::unique_ptr<UISignalStation>(new UISignalStation()); + } + return instance.get(); +} + +UISignalStation::UISignalStation() = default; + +} // namespace GpgFrontend::UI diff --git a/src/ui/SignalStation.h b/src/ui/UISignalStation.h index 17e866f5..aee61300 100644 --- a/src/ui/SignalStation.h +++ b/src/ui/UISignalStation.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,27 +20,29 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SIGNALSTATION_H -#define GPGFRONTEND_SIGNALSTATION_H +#pragma once -#include "ui/GpgFrontendUI.h" #include "ui/widgets/InfoBoardWidget.h" +namespace GpgFrontend { +class GpgPassphraseContext; +} + namespace GpgFrontend::UI { /** * @brief * */ -class SignalStation : public QObject { +class UISignalStation : public QObject { Q_OBJECT - static std::unique_ptr<SignalStation> _instance; + static std::unique_ptr<UISignalStation> instance; public: /** @@ -48,7 +50,7 @@ class SignalStation : public QObject { * * @return SignalStation* */ - static SignalStation* GetInstance(); + static auto GetInstance() -> UISignalStation*; signals: /** @@ -90,21 +92,22 @@ class SignalStation : public QObject { * @brief * */ - void SignalUserInputPassphraseDone(QString passparase); + void SignalNeedUserInputPassphrase(QSharedPointer<GpgPassphraseContext>); /** * @brief * */ - void SignalNeedUserInputPassphrase(); + void SignalUserInputPassphraseCallback(QSharedPointer<GpgPassphraseContext>); /** * @brief * */ void SignalRestartApplication(int); + + private: + UISignalStation(); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SIGNALSTATION_H diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 7e236c02..751b1f03 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,25 +28,28 @@ #include "UserInterfaceUtils.h" -#include <string> -#include <utility> +#include <gpg-error.h> +#include <qdialog.h> + +#include <QtNetwork> #include <vector> #include "core/GpgConstants.h" -#include "core/common/CoreCommonUtil.h" -#include "core/function/CacheManager.h" #include "core/function/CoreSignalStation.h" -#include "core/function/FileOperator.h" -#include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/GpgImportInformation.h" +#include "core/module/ModuleManager.h" #include "core/thread/Task.h" -#include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" -#include "dialog/gnupg/GnuPGControllerDialog.h" -#include "spdlog/spdlog.h" -#include "ui/SignalStation.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" +#include "ui/UISignalStation.h" #include "ui/dialog/WaitingDialog.h" +#include "ui/dialog/gnupg/GnuPGControllerDialog.h" +#include "ui/struct/CacheObject.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/KeyServerSO.h" #include "ui/widgets/TextEdit.h" namespace GpgFrontend::UI { @@ -58,7 +61,7 @@ void show_verify_details(QWidget *parent, InfoBoardWidget *info_board, GpgError error, const GpgVerifyResult &verify_result) { // take out result info_board->ResetOptionActionsMenu(); - info_board->AddOptionalAction(_("Show Verify Details"), [=]() { + info_board->AddOptionalAction(QObject::tr("Show Verify Details"), [=]() { VerifyDetailsDialog(parent, error, verify_result); }); } @@ -67,17 +70,18 @@ void import_unknown_key_from_keyserver( QWidget *parent, const GpgVerifyResultAnalyse &verify_res) { QMessageBox::StandardButton reply; reply = QMessageBox::question( - parent, _("Public key not found locally"), - _("There is no target public key content in local for GpgFrontend to " - "gather enough information about this Signature. Do you want to " - "import the public key from Keyserver now?"), + parent, QObject::tr("Public key not found locally"), + QObject::tr( + "There is no target public key content in local for GpgFrontend to " + "gather enough information about this Signature. Do you want to " + "import the public key from Keyserver now?"), QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { - auto dialog = KeyServerImportDialog(true, parent); + auto dialog = KeyServerImportDialog(parent); auto key_ids = std::make_unique<KeyIdArgsList>(); auto *signature = verify_res.GetSignatures(); while (signature != nullptr) { - SPDLOG_DEBUG("signature fpr: {}", signature->fpr); + GF_UI_LOG_DEBUG("signature fpr: {}", signature->fpr); key_ids->push_back(signature->fpr); signature = signature->next; } @@ -87,15 +91,14 @@ void import_unknown_key_from_keyserver( } void refresh_info_board(InfoBoardWidget *info_board, int status, - const std::string &report_text) { - if (status < 0) - info_board->SlotRefresh(QString::fromStdString(report_text), - INFO_ERROR_CRITICAL); - else if (status > 0) - info_board->SlotRefresh(QString::fromStdString(report_text), INFO_ERROR_OK); - else - info_board->SlotRefresh(QString::fromStdString(report_text), - INFO_ERROR_WARN); + const QString &report_text) { + if (status < 0) { + info_board->SlotRefresh(report_text, INFO_ERROR_CRITICAL); + } else if (status > 0) { + info_board->SlotRefresh(report_text, INFO_ERROR_OK); + } else { + info_board->SlotRefresh(report_text, INFO_ERROR_WARN); + } } void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board, @@ -116,12 +119,11 @@ void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board, result_analyse_a.GetResultReport() + result_analyse_b.GetResultReport()); } -void process_operation(QWidget *parent, const std::string &waiting_title, +void process_operation(QWidget *parent, const QString &waiting_title, const Thread::Task::TaskRunnable func, const Thread::Task::TaskCallback callback, - Thread::Task::DataObjectPtr data_object) { - auto *dialog = - new WaitingDialog(QString::fromStdString(waiting_title), parent); + DataObjectPtr data_object) { + auto *dialog = new WaitingDialog(waiting_title, parent); auto *process_task = new Thread::Task(std::move(func), waiting_title, data_object, std::move(callback)); @@ -146,7 +148,7 @@ void process_operation(QWidget *parent, const std::string &waiting_title, looper.exec(); } -CommonUtils *CommonUtils::GetInstance() { +auto CommonUtils::GetInstance() -> CommonUtils * { if (instance_ == nullptr) { instance_ = std::make_unique<CommonUtils>(); } @@ -154,109 +156,154 @@ CommonUtils *CommonUtils::GetInstance() { } CommonUtils::CommonUtils() : QWidget(nullptr) { - connect(CoreCommonUtil::GetInstance(), &CoreCommonUtil::SignalGnupgNotInstall, - this, &CommonUtils::SignalGnupgNotInstall); + connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalBadGnupgEnv, this, + &CommonUtils::SignalBadGnupgEnv); connect(this, &CommonUtils::SignalKeyStatusUpdated, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); connect(this, &CommonUtils::SignalKeyDatabaseRefreshDone, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone); - connect(this, &CommonUtils::SignalUserInputPassphraseDone, - CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalUserInputPassphraseDone); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone); // directly connect to SignalKeyStatusUpdated // to avoid the delay of signal emitting // when the key database is refreshed - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh, this, &CommonUtils::slot_update_key_status); - connect(CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalNeedUserInputPassphrase, this, - &CommonUtils::slot_popup_passphrase_input_dialog); - connect(this, &CommonUtils::SignalRestartApplication, - SignalStation::GetInstance(), - &SignalStation::SignalRestartApplication); + UISignalStation::GetInstance(), + &UISignalStation::SignalRestartApplication); - connect(SignalStation::GetInstance(), - &SignalStation::SignalRestartApplication, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalRestartApplication, this, &CommonUtils::SlotRestartApplication); - connect(this, &CommonUtils::SignalGnupgNotInstall, this, [=]() { - QMessageBox msgBox; - msgBox.setText(_("GnuPG Context Loading Failed")); - msgBox.setInformativeText( - _("Gnupg(gpg) is not installed correctly, please follow " - "<a href='https://www.gpgfrontend.bktus.com/#/" - "faq?id=how-to-deal-with-39env-loading-failed39'>this notes</a>" - " in FAQ to install Gnupg and then open " - "GpgFrontend. Or, you can open GnuPG Controller to set a custom " - "GnuPG " - "which GpgFrontend should use. Then, GpgFrontend will restart.")); - msgBox.setStandardButtons(QMessageBox::Open | QMessageBox::Cancel); - msgBox.setDefaultButton(QMessageBox::Save); - int ret = msgBox.exec(); - - switch (ret) { - case QMessageBox::Open: - (new GnuPGControllerDialog(this))->exec(); - // restart application when loop start - application_need_to_restart_at_once_ = true; - // restart application, core and ui - emit SignalRestartApplication(DEEP_RESTART_CODE); - break; - case QMessageBox::Cancel: - // close application - emit SignalRestartApplication(0); - break; - default: - // close application - emit SignalRestartApplication(0); - break; - } + connect(this, &CommonUtils::SignalBadGnupgEnv, this, + [=](const QString &reason) { + QMessageBox msg_box; + msg_box.setText(tr("GnuPG Context Loading Failed")); + msg_box.setInformativeText( + tr("Gnupg(gpg) is not installed correctly, please follow " + "<a href='https://www.gpgfrontend.bktus.com/#/" + "faq?id=how-to-deal-with-39env-loading-failed39'>this " + "notes</a> in FAQ to install Gnupg and then open " + "GpgFrontend. <br />" + "Or, you can open GnuPG Controller to set a " + "custom GnuPG which GpgFrontend should use. Then, " + "GpgFrontend will restart. <br /><br />" + "Breif Reason: %1") + .arg(reason)); + msg_box.setStandardButtons(QMessageBox::Open | QMessageBox::Cancel); + msg_box.setDefaultButton(QMessageBox::Save); + int ret = msg_box.exec(); + + switch (ret) { + case QMessageBox::Open: + (new GnuPGControllerDialog(this))->exec(); + // restart application when loop start + application_need_to_restart_at_once_ = true; + // restart application, core and ui + emit SignalRestartApplication(kDeepRestartCode); + break; + case QMessageBox::Cancel: + // close application + emit SignalRestartApplication(0); + break; + default: + // close application + emit SignalRestartApplication(0); + break; + } + }); +} + +void CommonUtils::WaitForOpera(QWidget *parent, + const QString &waiting_dialog_title, + const OperaWaitingCb &opera) { + QEventLoop looper; + QPointer<WaitingDialog> const dialog = + new WaitingDialog(waiting_dialog_title, parent); + connect(dialog, &QDialog::finished, &looper, &QEventLoop::quit); + connect(dialog, &QDialog::finished, dialog, &QDialog::deleteLater); + dialog->show(); + + QTimer::singleShot(64, parent, [=]() { + opera([dialog]() { + if (dialog != nullptr) { + GF_UI_LOG_DEBUG("called operating waiting cb, dialog: {}", + static_cast<void *>(dialog)); + dialog->close(); + dialog->accept(); + } + }); }); + + looper.exec(); } -void CommonUtils::SlotImportKeys(QWidget *parent, - const std::string &in_buffer) { - GpgImportInformation result = GpgKeyImportExporter::GetInstance().ImportKey( - std::make_unique<ByteArray>(in_buffer)); +void CommonUtils::RaiseMessageBox(QWidget *parent, GpgError err) { + GpgErrorDesc desc = DescribeGpgErrCode(err); + GpgErrorCode err_code = CheckGpgError2ErrCode(err); + + if (err_code == GPG_ERR_NO_ERROR) { + QMessageBox::information(parent, tr("Success"), + tr("Gpg Operation succeed.")); + } else { + RaiseFailureMessageBox(parent, err); + } +} + +void CommonUtils::RaiseFailureMessageBox(QWidget *parent, GpgError err) { + GpgErrorDesc desc = DescribeGpgErrCode(err); + GpgErrorCode err_code = CheckGpgError2ErrCode(err); + + QMessageBox::critical(parent, tr("Failure"), + tr("Gpg Operation failed.\n\nError code: %1\nSource: " + " %2\nDescription: %3") + .arg(err_code) + .arg(desc.first) + .arg(desc.second)); +} + +void CommonUtils::SlotImportKeys(QWidget *parent, const QString &in_buffer) { + auto info = + GpgKeyImportExporter::GetInstance().ImportKey(GFBuffer(in_buffer)); emit SignalKeyStatusUpdated(); - new KeyImportDetailDialog(result, false, parent); + + (new KeyImportDetailDialog(info, parent))->exec(); } void CommonUtils::SlotImportKeyFromFile(QWidget *parent) { - QString file_name = QFileDialog::getOpenFileName( - this, _("Open Key"), QString(), - QString(_("Key Files")) + " (*.asc *.txt);;" + _("Keyring files") + - " (*.gpg);;All Files (*)"); + auto file_name = QFileDialog::getOpenFileName(this, tr("Open Key"), QString(), + tr("Key Files")) + + " (*.asc *.txt);;" + tr("Keyring files") + + " (*.gpg);;All Files (*)"; if (!file_name.isNull()) { QByteArray key_buffer; - if (!FileOperator::ReadFile(file_name, key_buffer)) { - QMessageBox::critical(nullptr, _("File Open Failed"), - _("Failed to open file: ") + file_name); + if (!ReadFile(file_name, key_buffer)) { + QMessageBox::critical(nullptr, tr("File Open Failed"), + tr("Failed to open file: ") + file_name); return; } - SlotImportKeys(parent, key_buffer.toStdString()); + SlotImportKeys(parent, key_buffer); } } void CommonUtils::SlotImportKeyFromKeyServer(QWidget *parent) { - auto dialog = new KeyServerImportDialog(false, parent); + auto *dialog = new KeyServerImportDialog(parent); dialog->show(); } void CommonUtils::SlotImportKeyFromClipboard(QWidget *parent) { QClipboard *cb = QApplication::clipboard(); - SlotImportKeys(parent, - cb->text(QClipboard::Clipboard).toUtf8().toStdString()); + SlotImportKeys(parent, cb->text(QClipboard::Clipboard)); } void CommonUtils::SlotExecuteCommand( - const std::string &cmd, const QStringList &arguments, + const QString &cmd, const QStringList &arguments, const std::function<void(QProcess *)> &interact_func) { QEventLoop looper; auto *cmd_process = new QProcess(&looper); @@ -267,21 +314,21 @@ void CommonUtils::SlotExecuteCommand( &QEventLoop::quit); connect(cmd_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit); connect(cmd_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("process started"); }); + []() -> void { GF_UI_LOG_DEBUG("process started"); }); connect(cmd_process, &QProcess::readyReadStandardOutput, [interact_func, cmd_process]() { interact_func(cmd_process); }); connect(cmd_process, &QProcess::errorOccurred, this, - [=]() -> void { SPDLOG_ERROR("error in process"); }); + [=]() -> void { GF_UI_LOG_ERROR("error in process"); }); connect(cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [=](int, QProcess::ExitStatus status) { if (status == QProcess::NormalExit) - SPDLOG_DEBUG("succeed in executing command: {}", cmd); + GF_UI_LOG_DEBUG("succeed in executing command: {}", cmd); else - SPDLOG_WARN("error in executing command: {}", cmd); + GF_UI_LOG_WARN("error in executing command: {}", cmd); }); - cmd_process->setProgram(QString::fromStdString(cmd)); + cmd_process->setProgram(cmd); cmd_process->setArguments(arguments); cmd_process->start(); looper.exec(); @@ -291,7 +338,7 @@ void CommonUtils::SlotExecuteGpgCommand( const QStringList &arguments, const std::function<void(QProcess *)> &interact_func) { QEventLoop looper; - auto dialog = new WaitingDialog(_("Processing"), nullptr); + auto dialog = new WaitingDialog(tr("Processing"), nullptr); dialog->show(); auto *gpg_process = new QProcess(&looper); gpg_process->setProcessChannelMode(QProcess::MergedChannels); @@ -304,29 +351,32 @@ void CommonUtils::SlotExecuteGpgCommand( &WaitingDialog::deleteLater); connect(gpg_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit); connect(gpg_process, &QProcess::started, - []() -> void { SPDLOG_DEBUG("gpg process started"); }); + []() -> void { GF_UI_LOG_DEBUG("gpg process started"); }); connect(gpg_process, &QProcess::readyReadStandardOutput, [interact_func, gpg_process]() { interact_func(gpg_process); }); connect(gpg_process, &QProcess::errorOccurred, this, [=]() -> void { - SPDLOG_ERROR("Error in Process"); + GF_UI_LOG_ERROR("Error in Process"); dialog->close(); - QMessageBox::critical(nullptr, _("Failure"), - _("Failed to execute command.")); + QMessageBox::critical(nullptr, tr("Failure"), + tr("Failed to execute command.")); }); connect(gpg_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, [=](int, QProcess::ExitStatus status) { dialog->close(); if (status == QProcess::NormalExit) - QMessageBox::information(nullptr, _("Success"), - _("Succeed in executing command.")); + QMessageBox::information(nullptr, tr("Success"), + tr("Succeed in executing command.")); else - QMessageBox::information(nullptr, _("Warning"), - _("Finished executing command.")); + QMessageBox::information(nullptr, tr("Warning"), + tr("Finished executing command.")); }); - gpg_process->setProgram( - GpgContext::GetInstance().GetInfo(false).AppPath.c_str()); + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); + GF_UI_LOG_DEBUG("got gnupg app path from rt: {}", app_path); + + gpg_process->setProgram(app_path); gpg_process->setArguments(arguments); gpg_process->start(); looper.exec(); @@ -336,51 +386,33 @@ void CommonUtils::SlotExecuteGpgCommand( void CommonUtils::SlotImportKeyFromKeyServer( const KeyIdArgsList &key_ids, const ImportCallbackFunctiopn &callback) { - // target key server that we need to import key from it - std::string target_keyserver; - - try { - auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); - SettingsObject key_server_json("key_server"); - - // get key servers from settings - const auto key_server_list = - key_server_json.Check("server_list", nlohmann::json::array()); - if (key_server_list.empty()) { - throw std::runtime_error("No key server configured"); - } - - const int target_key_server_index = - key_server_json.Check("default_server", 0); - if (target_key_server_index >= key_server_list.size()) { - throw std::runtime_error("default_server index out of range"); - } - target_keyserver = - key_server_list[target_key_server_index].get<std::string>(); - - SPDLOG_DEBUG("set target key server to default Key Server: {}", - target_keyserver); - } catch (...) { - SPDLOG_ERROR(_("Cannot read default_keyserver From Settings")); - QMessageBox::critical(nullptr, _("Default Keyserver Not Found"), - _("Cannot read default keyserver from your settings, " - "please set a default keyserver first")); + auto target_keyserver = + KeyServerSO(SettingsObject("key_server")).GetTargetServer(); + if (target_keyserver.isEmpty()) { + QMessageBox::critical( + nullptr, tr("Default Keyserver Not Found"), + tr("Cannot read default keyserver from your settings, " + "please set a default keyserver first")); return; } + GF_UI_LOG_DEBUG("set target key server to default Key Server: {}", + target_keyserver); - auto thread = QThread::create([target_keyserver, key_ids, callback]() { - QUrl target_keyserver_url(target_keyserver.c_str()); + auto *thread = QThread::create([target_keyserver, key_ids, callback]() { + QUrl target_keyserver_url(target_keyserver); auto network_manager = std::make_unique<QNetworkAccessManager>(); // LOOP - decltype(key_ids.size()) current_index = 1, all_index = key_ids.size(); + decltype(key_ids.size()) current_index = 1; + decltype(key_ids.size()) all_index = key_ids.size(); + for (const auto &key_id : key_ids) { // New Req Url - QUrl req_url( - target_keyserver_url.scheme() + "://" + target_keyserver_url.host() + - "/pks/lookup?op=get&search=0x" + key_id.c_str() + "&options=mr"); + QUrl req_url(target_keyserver_url.scheme() + "://" + + target_keyserver_url.host() + + "/pks/lookup?op=get&search=0x" + key_id + "&options=mr"); - SPDLOG_DEBUG("request url: {}", req_url.toString().toStdString()); + GF_UI_LOG_DEBUG("request url: {}", req_url.toString().toStdString()); // Waiting for reply QNetworkReply *reply = network_manager->get(QNetworkRequest(req_url)); @@ -388,41 +420,35 @@ void CommonUtils::SlotImportKeyFromKeyServer( connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); - // Get Data - auto key_data = reply->readAll(); - auto key_data_ptr = - std::make_unique<ByteArray>(key_data.data(), key_data.size()); - // Detect status - std::string status; + QString status; auto error = reply->error(); if (error != QNetworkReply::NoError) { switch (error) { case QNetworkReply::ContentNotFoundError: - status = _("Key Not Found"); + status = tr("Key Not Found"); break; case QNetworkReply::TimeoutError: - status = _("Timeout"); + status = tr("Timeout"); break; case QNetworkReply::HostNotFoundError: - status = _("Key Server Not Found"); + status = tr("Key Server Not Found"); break; default: - status = _("Connection Error"); + status = tr("Connection Error"); } } reply->deleteLater(); // Try importing - GpgImportInformation result = - GpgKeyImportExporter::GetInstance().ImportKey( - std::move(key_data_ptr)); + auto result = GpgKeyImportExporter::GetInstance().ImportKey( + GFBuffer(reply->readAll())); - if (result.imported == 1) { - status = _("The key has been updated"); + if (result->imported == 1) { + status = tr("The key has been updated"); } else { - status = _("No need to update the key"); + status = tr("No need to update the key"); } callback(key_id, status, current_index, all_index); current_index++; @@ -433,8 +459,8 @@ void CommonUtils::SlotImportKeyFromKeyServer( } void CommonUtils::slot_update_key_status() { - auto refresh_task = new Thread::Task( - [](Thread::Task::DataObjectPtr) -> int { + auto *refresh_task = new Thread::Task( + [](DataObjectPtr) -> int { // flush key cache for all GpgKeyGetter Intances. for (const auto &channel_id : GpgKeyGetter::GetAllChannelId()) { GpgKeyGetter::GetInstance(channel_id).FlushKeyCache(); @@ -443,33 +469,15 @@ void CommonUtils::slot_update_key_status() { }, "update_key_database_task"); connect(refresh_task, &Thread::Task::SignalTaskEnd, this, - &CommonUtils::SignalKeyDatabaseRefreshDone, - Qt::BlockingQueuedConnection); + &CommonUtils::SignalKeyDatabaseRefreshDone); // post the task to the default task runner Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( refresh_task); } -void CommonUtils::slot_popup_passphrase_input_dialog() { - auto *dialog = new QInputDialog(QApplication::activeWindow(), Qt::Dialog); - dialog->setModal(true); - dialog->setWindowTitle(_("Password Input Dialog")); - dialog->setInputMode(QInputDialog::TextInput); - dialog->setTextEchoMode(QLineEdit::Password); - dialog->setLabelText(_("Please Input The Password")); - dialog->resize(500, 80); - dialog->exec(); - - QString password = dialog->textValue(); - dialog->deleteLater(); - - // send signal - emit SignalUserInputPassphraseDone(password); -} - void CommonUtils::SlotRestartApplication(int code) { - SPDLOG_DEBUG("application need restart, code: {}", code); + GF_UI_LOG_DEBUG("application need restart, code: {}", code); if (code == 0) { std::exit(0); @@ -482,41 +490,39 @@ bool CommonUtils::isApplicationNeedRestart() { return application_need_to_restart_at_once_; } -bool CommonUtils::KeyExistsinFavouriteList(const GpgKey &key) { +auto CommonUtils::KeyExistsinFavouriteList(const GpgKey &key) -> bool { // load cache - auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair"); - if (!key_array.is_array()) { - CacheManager::GetInstance().SaveCache("favourite_key_pair", - nlohmann::json::array()); - } + auto json_data = CacheObject("favourite_key_pair"); + if (!json_data.isArray()) json_data.setArray(QJsonArray()); + + auto key_array = json_data.array(); return std::find(key_array.begin(), key_array.end(), key.GetFingerprint()) != key_array.end(); } void CommonUtils::AddKey2Favourtie(const GpgKey &key) { - auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair"); - if (!key_array.is_array()) { - CacheManager::GetInstance().SaveCache("favourite_key_pair", - nlohmann::json::array()); - } + auto json_data = CacheObject("favourite_key_pair"); + QJsonArray key_array; + if (json_data.isArray()) key_array = json_data.array(); + key_array.push_back(key.GetFingerprint()); - CacheManager::GetInstance().SaveCache("favourite_key_pair", key_array, true); + json_data.setArray(key_array); } void CommonUtils::RemoveKeyFromFavourite(const GpgKey &key) { - auto key_array = CacheManager::GetInstance().LoadCache("favourite_key_pair"); - if (!key_array.is_array()) { - CacheManager::GetInstance().SaveCache("favourite_key_pair", - nlohmann::json::array(), true); - return; - } - auto it = std::find(key_array.begin(), key_array.end(), key.GetFingerprint()); - if (it != key_array.end()) { - auto rm_it = - std::remove(key_array.begin(), key_array.end(), key.GetFingerprint()); - key_array.erase(rm_it, key_array.end()); - CacheManager::GetInstance().SaveCache("favourite_key_pair", key_array); + auto json_data = CacheObject("favourite_key_pair"); + QJsonArray key_array; + if (json_data.isArray()) key_array = json_data.array(); + + QString fingerprint = key.GetFingerprint(); + QJsonArray new_key_array; + for (auto &&item : key_array) { + if (item.isString() && item.toString() != fingerprint) { + new_key_array.append(item); + } } + + json_data.setArray(new_key_array); } } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h index 59c803b9..39a4633e 100644 --- a/src/ui/UserInterfaceUtils.h +++ b/src/ui/UserInterfaceUtils.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,20 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_USER_INTERFACE_UTILS_H -#define GPGFRONTEND_USER_INTERFACE_UTILS_H +#pragma once + +#include <qwidget.h> -#include "core/GpgModel.h" #include "core/function/result_analyse/GpgVerifyResultAnalyse.h" #include "core/model/GpgKey.h" +#include "core/thread/ThreadingModel.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" namespace GpgFrontend { @@ -43,6 +45,9 @@ namespace GpgFrontend::UI { class InfoBoardWidget; class TextEdit; +using OperaWaitingHd = std::function<void()>; +using OperaWaitingCb = const std::function<void(OperaWaitingHd)>; + /** * @brief * @@ -71,7 +76,7 @@ void import_unknown_key_from_keyserver( * @param report_text */ void refresh_info_board(InfoBoardWidget* info_board, int status, - const std::string& report_text); + const QString& report_text); /** * @brief @@ -103,10 +108,10 @@ void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, * @param func */ void process_operation( - QWidget* parent, const std::string& waiting_title, + QWidget* parent, const QString& waiting_title, GpgFrontend::Thread::Task::TaskRunnable func, GpgFrontend::Thread::Task::TaskCallback callback = nullptr, - Thread::Task::DataObjectPtr data_object = nullptr); + DataObjectPtr data_object = nullptr); /** * @brief @@ -115,8 +120,8 @@ void process_operation( * @param key_id * @param key_server */ -void import_key_from_keyserver(QWidget* parent, const std::string& key_id, - const std::string& key_server); +void import_key_from_keyserver(QWidget* parent, const QString& key_id, + const QString& key_server); /** * @brief @@ -129,8 +134,8 @@ class CommonUtils : public QWidget { * @brief * */ - using ImportCallbackFunctiopn = std::function<void( - const std::string&, const std::string&, size_t, size_t)>; + using ImportCallbackFunctiopn = + std::function<void(const QString&, const QString&, size_t, size_t)>; /** * @brief Construct a new Common Utils object @@ -148,57 +153,67 @@ class CommonUtils : public QWidget { /** * @brief * + * @param err */ - bool isApplicationNeedRestart(); + static void WaitForOpera(QWidget* parent, const QString&, + const OperaWaitingCb&); /** * @brief * + * @param err */ - bool KeyExistsinFavouriteList(const GpgKey& key); + static void RaiseMessageBox(QWidget* parent, GpgError err); /** * @brief * + * @param err */ - void AddKey2Favourtie(const GpgKey& key); + static void RaiseFailureMessageBox(QWidget* parent, GpgError err); /** * @brief * */ - void RemoveKeyFromFavourite(const GpgKey& key); + bool isApplicationNeedRestart(); - signals: /** * @brief * */ - void SignalKeyStatusUpdated(); + bool KeyExistsinFavouriteList(const GpgKey& key); /** * @brief * */ - void SignalGnupgNotInstall(); + void AddKey2Favourtie(const GpgKey& key); /** - * @brief emit when the key database is refreshed + * @brief * */ - void SignalKeyDatabaseRefreshDone(); + void RemoveKeyFromFavourite(const GpgKey& key); + signals: /** * @brief * */ - void SignalNeedUserInputPassphrase(); + void SignalKeyStatusUpdated(); /** * @brief * */ - void SignalUserInputPassphraseDone(QString passphrase); + void SignalBadGnupgEnv(QString); + + /** + * @brief emit when the key database is refreshed + * + */ + void SignalKeyDatabaseRefreshDone(); /** * @brief @@ -213,7 +228,7 @@ class CommonUtils : public QWidget { * @param parent * @param in_buffer */ - void SlotImportKeys(QWidget* parent, const std::string& in_buffer); + void SlotImportKeys(QWidget* parent, const QString& in_buffer); /** * @brief @@ -263,7 +278,7 @@ class CommonUtils : public QWidget { * @param arguments * @param interact_func */ - void SlotExecuteCommand(const std::string& cmd, const QStringList& arguments, + void SlotExecuteCommand(const QString& cmd, const QStringList& arguments, const std::function<void(QProcess*)>& interact_func); /** @@ -280,17 +295,9 @@ class CommonUtils : public QWidget { */ void slot_update_key_status(); - /** - * @brief - * - */ - void slot_popup_passphrase_input_dialog(); - private: static std::unique_ptr<CommonUtils> instance_; ///< bool application_need_to_restart_at_once_ = false; }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_USER_INTERFACE_UTILS_H diff --git a/src/ui/dialog/GeneralDialog.cpp b/src/ui/dialog/GeneralDialog.cpp index d4b6613e..386573a3 100644 --- a/src/ui/dialog/GeneralDialog.cpp +++ b/src/ui/dialog/GeneralDialog.cpp @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,17 +20,21 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ #include "GeneralDialog.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/WindowStateSO.h" + +namespace GpgFrontend { -GpgFrontend::UI::GeneralDialog::GeneralDialog(std::string name, QWidget *parent) - : name_(std::move(name)), QDialog(parent) { +GpgFrontend::UI::GeneralDialog::GeneralDialog(QString name, QWidget *parent) + : QDialog(parent), name_(std::move(name)) { slot_restore_settings(); connect(this, &QDialog::finished, this, &GeneralDialog::slot_save_settings); } @@ -42,37 +46,37 @@ void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept { update_rect_cache(); SettingsObject general_windows_state(name_ + "_dialog_state"); - bool window_save = general_windows_state.Check("window_save", false); + auto window_state = WindowStateSO(general_windows_state); // Restore window size & location - if (window_save) { - int x = general_windows_state.Check("window_pos").Check("x", 0), - y = general_windows_state.Check("window_pos").Check("y", 0); - SPDLOG_DEBUG("stored dialog pos, x: {}, y: {}", x, y); + if (window_state.window_save) { + int x = window_state.x; + int y = window_state.y; + GF_UI_LOG_DEBUG("stored dialog pos, x: {}, y: {}", x, y); QPoint relative_pos = {x, y}; QPoint pos = parent_rect_.topLeft() + relative_pos; - SPDLOG_DEBUG("relative dialog pos, x: {}, y: {}", relative_pos.x(), - relative_pos.y()); + GF_UI_LOG_DEBUG("relative dialog pos, x: {}, y: {}", relative_pos.x(), + relative_pos.y()); - int width = general_windows_state.Check("window_size").Check("width", 0), - height = - general_windows_state.Check("window_size").Check("height", 0); - SPDLOG_DEBUG("stored dialog size, width: {}, height: {}", width, height); + int width = window_state.width; + int height = window_state.height; + GF_UI_LOG_DEBUG("stored dialog size, width: {}, height: {}", width, + height); - QRect target_rect_ = {pos.x(), pos.y(), width, height}; - SPDLOG_DEBUG("dialog stored target rect, width: {}, height: {}", width, - height); + QRect target_rect = {pos.x(), pos.y(), width, height}; + GF_UI_LOG_DEBUG("dialog stored target rect, width: {}, height: {}", width, + height); // check for valid - if (width > 0 && height > 0 && screen_rect_.contains(target_rect_)) { - this->setGeometry(target_rect_); + if (width > 0 && height > 0 && screen_rect_.contains(target_rect)) { + this->setGeometry(target_rect); this->rect_restored_ = true; } } } catch (...) { - SPDLOG_ERROR("error at restoring settings"); + GF_UI_LOG_ERROR("error at restoring settings"); } } @@ -82,24 +86,26 @@ void GpgFrontend::UI::GeneralDialog::slot_save_settings() noexcept { update_rect_cache(); - SPDLOG_DEBUG("dialog pos, x: {}, y: {}", rect_.x(), rect_.y()); - SPDLOG_DEBUG("dialog size, width: {}, height: {}", rect_.width(), - rect_.height()); + GF_UI_LOG_DEBUG("dialog pos, x: {}, y: {}", rect_.x(), rect_.y()); + GF_UI_LOG_DEBUG("dialog size, width: {}, height: {}", rect_.width(), + rect_.height()); // window position relative to parent auto relative_pos = rect_.topLeft() - parent_rect_.topLeft(); - SPDLOG_DEBUG("store dialog pos, x: {}, y: {}", relative_pos.x(), - relative_pos.y()); + GF_UI_LOG_DEBUG("store dialog pos, x: {}, y: {}", relative_pos.x(), + relative_pos.y()); - general_windows_state["window_pos"]["x"] = relative_pos.x(); - general_windows_state["window_pos"]["y"] = relative_pos.y(); + WindowStateSO window_state; + window_state.x = relative_pos.x(); + window_state.y = relative_pos.y(); + window_state.width = rect_.width(); + window_state.height = rect_.height(); + window_state.window_save = true; - general_windows_state["window_size"]["width"] = rect_.width(); - general_windows_state["window_size"]["height"] = rect_.height(); - general_windows_state["window_save"] = true; + general_windows_state.Store(window_state.Json()); } catch (...) { - SPDLOG_ERROR(name_, "error"); + GF_UI_LOG_ERROR("general dialog: {}, caught exception", name_); } } @@ -108,8 +114,8 @@ void GpgFrontend::UI::GeneralDialog::setPosCenterOfScreen() { int screen_width = screen_rect_.width(); int screen_height = screen_rect_.height(); - SPDLOG_DEBUG("dialog current screen available geometry", screen_width, - screen_height); + GF_UI_LOG_DEBUG("dialog current screen available geometry", screen_width, + screen_height); // update rect of current dialog rect_ = this->geometry(); @@ -126,14 +132,14 @@ void GpgFrontend::UI::GeneralDialog::movePosition2CenterOfParent() { update_rect_cache(); // log for debug - SPDLOG_DEBUG("parent pos x: {} y: {}", parent_rect_.x(), parent_rect_.y()); - SPDLOG_DEBUG("parent size width: {}, height: {}", parent_rect_.width(), - parent_rect_.height()); - SPDLOG_DEBUG("parent center pos x: {}, y: {}", parent_rect_.center().x(), - parent_rect_.center().y()); - SPDLOG_DEBUG("dialog pos x: {} y: {}", rect_.x(), rect_.y()); - SPDLOG_DEBUG("dialog size width: {} height: {}", rect_.width(), - rect_.height()); + GF_UI_LOG_DEBUG("parent pos x: {} y: {}", parent_rect_.x(), parent_rect_.y()); + GF_UI_LOG_DEBUG("parent size width: {}, height: {}", parent_rect_.width(), + parent_rect_.height()); + GF_UI_LOG_DEBUG("parent center pos x: {}, y: {}", parent_rect_.center().x(), + parent_rect_.center().y()); + GF_UI_LOG_DEBUG("dialog pos x: {} y: {}", rect_.x(), rect_.y()); + GF_UI_LOG_DEBUG("dialog size width: {} height: {}", rect_.width(), + rect_.height()); if (parent_rect_.topLeft() != QPoint{0, 0} && parent_rect_.size() != QSize{0, 0}) { @@ -143,8 +149,9 @@ void GpgFrontend::UI::GeneralDialog::movePosition2CenterOfParent() { QPoint target_position = parent_rect_.center() - QPoint(rect_.width() / 2, rect_.height() / 2); - SPDLOG_DEBUG("update position to parent's center, target pos, x:{}, y: {}", - target_position.x(), target_position.y()); + GF_UI_LOG_DEBUG( + "update position to parent's center, target pos, x:{}, y: {}", + target_position.x(), target_position.y()); this->move(target_position); } else { @@ -191,18 +198,22 @@ void GpgFrontend::UI::GeneralDialog::update_rect_cache() { * @brief * */ -bool GpgFrontend::UI::GeneralDialog::isRectRestored() { return rect_restored_; } +auto GpgFrontend::UI::GeneralDialog::isRectRestored() -> bool { + return rect_restored_; +} /** * @brief * */ void GpgFrontend::UI::GeneralDialog::showEvent(QShowEvent *event) { - SPDLOG_DEBUG("General Dialog named {} is about to show, caught show event", - name_); + GF_UI_LOG_DEBUG("General Dialog named {} is about to show, caught show event", + name_); // default position strategy if (!isRectRestored()) movePosition2CenterOfParent(); - QWidget::showEvent(event); -}
\ No newline at end of file + QDialog::showEvent(event); +} + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/ui/dialog/GeneralDialog.h b/src/ui/dialog/GeneralDialog.h index dc42fb6b..604c8475 100644 --- a/src/ui/dialog/GeneralDialog.h +++ b/src/ui/dialog/GeneralDialog.h @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,13 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ -#ifndef GPGFRONTEND_GENERALDIALOG_H -#define GPGFRONTEND_GENERALDIALOG_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -38,7 +38,7 @@ class GeneralDialog : public QDialog { * * @param name */ - explicit GeneralDialog(std::string name, QWidget* parent = nullptr); + explicit GeneralDialog(QString name, QWidget* parent = nullptr); /** * @@ -86,12 +86,10 @@ class GeneralDialog : public QDialog { */ void update_rect_cache(); - std::string name_; ///< + QString name_; ///< QRect rect_; QRect parent_rect_; QRect screen_rect_; bool rect_restored_ = false; }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GENERALDIALOG_H diff --git a/src/ui/dialog/QuitDialog.cpp b/src/ui/dialog/QuitDialog.cpp index 87b1c1e1..6dd5674e 100755 --- a/src/ui/dialog/QuitDialog.cpp +++ b/src/ui/dialog/QuitDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,13 +28,11 @@ #include "QuitDialog.h" -#include <boost/format.hpp> - namespace GpgFrontend::UI { QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs) : GeneralDialog("quit_dialog", parent) { - setWindowTitle(_("Unsaved Files")); + setWindowTitle(tr("Unsaved Files")); setModal(true); discarded_ = false; @@ -77,52 +75,54 @@ QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs) /* * Warnbox with icon and text */ - auto pixmap = QPixmap(":error.png"); + auto pixmap = QPixmap(":/icons/error.png"); pixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); auto* warn_icon = new QLabel(); warn_icon->setPixmap(pixmap); - const auto info = - boost::format(_("%1% files contain unsaved information.<br/>Save the " - "changes before closing?")) % - std::to_string(row); - auto* warn_label = new QLabel(QString::fromStdString(info.str())); - auto* warnBoxLayout = new QHBoxLayout(); - warnBoxLayout->addWidget(warn_icon); - warnBoxLayout->addWidget(warn_label); - warnBoxLayout->setAlignment(Qt::AlignLeft); - auto* warnBox = new QWidget(this); - warnBox->setLayout(warnBoxLayout); + const auto info = tr("%1 files contain unsaved information.<br/>Save the " + "changes before closing?") + .arg(row); + auto* warn_label = new QLabel(info); + auto* warn_box_layout = new QHBoxLayout(); + warn_box_layout->addWidget(warn_icon); + warn_box_layout->addWidget(warn_label); + warn_box_layout->setAlignment(Qt::AlignLeft); + auto* warn_box = new QWidget(this); + warn_box->setLayout(warn_box_layout); /* * Two labels on top and under the filelist */ - auto* checkLabel = new QLabel(_("Check the files you want to save:")); + auto* check_label = new QLabel(tr("Check the files you want to save:")); auto* note_label = new QLabel( - "<b>" + QString(_("Note")) + ":</b>" + - _("If you don't save these files, all changes are lost.") + "<br/>"); + "<b>" + tr("Note") + ":</b>" + + tr("If you don't save these files, all changes are lost.") + "<br/>"); /* * Buttonbox */ - auto* buttonBox = + auto* button_box = new QDialogButtonBox(QDialogButtonBox::Discard | QDialogButtonBox::Save | QDialogButtonBox::Cancel); - connect(buttonBox, &QDialogButtonBox::accepted, this, &QuitDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QuitDialog::reject); - QPushButton* btnNoKey = buttonBox->button(QDialogButtonBox::Discard); - connect(btnNoKey, &QPushButton::clicked, this, &QuitDialog::slot_my_discard); + connect(button_box, &QDialogButtonBox::accepted, this, &QuitDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, this, &QuitDialog::reject); + QPushButton* btn_no_key = button_box->button(QDialogButtonBox::Discard); + connect(btn_no_key, &QPushButton::clicked, this, + &QuitDialog::slot_my_discard); /* * Set the layout */ auto* vbox = new QVBoxLayout(); - vbox->addWidget(warnBox); - vbox->addWidget(checkLabel); + vbox->addWidget(warn_box); + vbox->addWidget(check_label); vbox->addWidget(m_fileList_); vbox->addWidget(note_label); - vbox->addWidget(buttonBox); + vbox->addWidget(button_box); this->setLayout(vbox); + + this->movePosition2CenterOfParent(); } void QuitDialog::slot_my_discard() { @@ -130,16 +130,16 @@ void QuitDialog::slot_my_discard() { reject(); } -bool QuitDialog::IsDiscarded() const { return discarded_; } +auto QuitDialog::IsDiscarded() const -> bool { return discarded_; } -QList<int> QuitDialog::GetTabIdsToSave() { - QList<int> tabIdsToSave; +auto QuitDialog::GetTabIdsToSave() -> QList<int> { + QList<int> tab_ids_to_save; for (int i = 0; i < m_fileList_->rowCount(); i++) { if (m_fileList_->item(i, 0)->checkState() == Qt::Checked) { - tabIdsToSave << m_fileList_->item(i, 2)->text().toInt(); + tab_ids_to_save << m_fileList_->item(i, 2)->text().toInt(); } } - return tabIdsToSave; + return tab_ids_to_save; } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/QuitDialog.h b/src/ui/dialog/QuitDialog.h index 2fd9e382..0c25c2c8 100755 --- a/src/ui/dialog/QuitDialog.h +++ b/src/ui/dialog/QuitDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __QUITDIALOG_H__ -#define __QUITDIALOG_H__ +#pragma once #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -56,14 +55,14 @@ class QuitDialog : public GeneralDialog { * @return true * @return false */ - [[nodiscard]] bool IsDiscarded() const; + [[nodiscard]] auto IsDiscarded() const -> bool; /** * @brief Get the Tab Ids To Save object * * @return QList<int> */ - QList<int> GetTabIdsToSave(); + auto GetTabIdsToSave() -> QList<int>; private slots: @@ -79,5 +78,3 @@ class QuitDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __QUITDIALOG_H__ diff --git a/src/ui/dialog/SignersPicker.cpp b/src/ui/dialog/SignersPicker.cpp index 8969618e..378a58c7 100644 --- a/src/ui/dialog/SignersPicker.cpp +++ b/src/ui/dialog/SignersPicker.cpp @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,21 +20,23 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ #include "SignersPicker.h" +#include "core/GpgModel.h" #include "ui/widgets/KeyList.h" namespace GpgFrontend::UI { SignersPicker::SignersPicker(QWidget* parent) : GeneralDialog(typeid(SignersPicker).name(), parent) { - auto confirm_button = new QPushButton(_("Confirm")); - auto cancel_button = new QPushButton(_("Cancel")); + auto* confirm_button = new QPushButton(tr("Confirm")); + auto* cancel_button = new QPushButton(tr("Cancel")); connect(confirm_button, &QPushButton::clicked, [=]() { this->accepted_ = true; }); @@ -42,9 +44,9 @@ SignersPicker::SignersPicker(QWidget* parent) connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject); /*Setup KeyList*/ - key_list_ = new KeyList(false, this); + key_list_ = new KeyList(0U, this); key_list_->AddListGroupTab( - _("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY, + tr("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage, [](const GpgKey& key, const KeyTable&) -> bool { return key.IsHasActualSigningCapability(); @@ -52,13 +54,13 @@ SignersPicker::SignersPicker(QWidget* parent) key_list_->SlotRefresh(); auto* vbox2 = new QVBoxLayout(); - vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": ")); + vbox2->addWidget(new QLabel(tr("Select Signer(s)") + ": ")); vbox2->addWidget(key_list_); vbox2->addWidget(new QLabel( QString( - _("Please select one or more private keys you use for signing.")) + + tr("Please select one or more private keys you use for signing.")) + "\n" + - _("If no key is selected, the default key will be used for signing."))); + tr("If no key is selected, the default key will be used for signing."))); vbox2->addWidget(confirm_button); vbox2->addWidget(cancel_button); vbox2->addStretch(0); @@ -68,15 +70,17 @@ SignersPicker::SignersPicker(QWidget* parent) Qt::CustomizeWindowHint); this->setModal(true); - this->setWindowTitle("Signers Picker"); + this->setWindowTitle(tr("Signers Picker")); this->setMinimumWidth(480); + + movePosition2CenterOfParent(); this->show(); } -GpgFrontend::KeyIdArgsListPtr SignersPicker::GetCheckedSigners() { +auto SignersPicker::GetCheckedSigners() -> GpgFrontend::KeyIdArgsListPtr { return key_list_->GetPrivateChecked(); } -bool SignersPicker::GetStatus() const { return this->accepted_; } +auto SignersPicker::GetStatus() const -> bool { return this->accepted_; } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/SignersPicker.h b/src/ui/dialog/SignersPicker.h index 5533f9d8..c7e1bfa5 100644 --- a/src/ui/dialog/SignersPicker.h +++ b/src/ui/dialog/SignersPicker.h @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ -#ifndef GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H -#define GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H +#pragma once #include "GpgFrontendUI.h" +#include "core/typedef/GpgTypedef.h" #include "ui/dialog//GeneralDialog.h" namespace GpgFrontend::UI { @@ -55,7 +56,7 @@ class SignersPicker : public GeneralDialog { * * @return GpgFrontend::KeyIdArgsListPtr */ - GpgFrontend::KeyIdArgsListPtr GetCheckedSigners(); + KeyIdArgsListPtr GetCheckedSigners(); /** * @@ -69,5 +70,3 @@ class SignersPicker : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H diff --git a/src/ui/dialog/WaitingDialog.cpp b/src/ui/dialog/WaitingDialog.cpp index b0888581..9c9a91d4 100644 --- a/src/ui/dialog/WaitingDialog.cpp +++ b/src/ui/dialog/WaitingDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,7 +28,7 @@ #include "WaitingDialog.h" -#include "dialog/GeneralDialog.h" +#include "ui/dialog/GeneralDialog.h" namespace GpgFrontend::UI { @@ -36,23 +36,20 @@ WaitingDialog::WaitingDialog(const QString& title, QWidget* parent) : GeneralDialog("WaitingDialog", parent) { auto* pb = new QProgressBar(); pb->setRange(0, 0); - pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + pb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); pb->setTextVisible(false); auto* layout = new QVBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); layout->addWidget(pb); this->setLayout(layout); this->setModal(true); - this->raise(); this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); this->setWindowTitle(title); this->setAttribute(Qt::WA_DeleteOnClose); - this->setFixedSize(240, 42); + this->movePosition2CenterOfParent(); this->show(); } diff --git a/src/ui/dialog/WaitingDialog.h b/src/ui/dialog/WaitingDialog.h index c8193cba..d042c215 100644 --- a/src/ui/dialog/WaitingDialog.h +++ b/src/ui/dialog/WaitingDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __UI_WAITING_DIALOG_H__ -#define __UI_WAITING_DIALOG_H__ +#pragma once #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -51,5 +50,3 @@ class WaitingDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __UI_WAITING_DIALOG_H__ diff --git a/src/ui/dialog/Wizard.cpp b/src/ui/dialog/Wizard.cpp index 77f07559..89ebee27 100644 --- a/src/ui/dialog/Wizard.cpp +++ b/src/ui/dialog/Wizard.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,6 +28,7 @@ #include "Wizard.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" namespace GpgFrontend::UI { @@ -40,15 +41,17 @@ Wizard::Wizard(QWidget* parent) : QWizard(parent) { #ifndef Q_WS_MAC setWizardStyle(ModernStyle); #endif - setWindowTitle(_("First Start Wizard")); + setWindowTitle(tr("First Start Wizard")); // http://www.flickr.com/photos/laureenp/6141822934/ - setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg")); - setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png")); - setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png")); - - int next_page_id = GlobalSettingStation::GetInstance().LookupSettings( - "wizard.next_page", -1); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/keys2.jpg")); + setPixmap(QWizard::LogoPixmap, QPixmap(":/icons/logo_small.png")); + setPixmap(QWizard::BannerPixmap, QPixmap(":/icons/banner.png")); + + int next_page_id = GlobalSettingStation::GetInstance() + .GetSettings() + .value("wizard.next_page", -1) + .toInt(); setStartId(next_page_id); connect(this, &Wizard::accepted, this, &Wizard::slot_wizard_accepted); @@ -57,19 +60,10 @@ Wizard::Wizard(QWidget* parent) : QWizard(parent) { void Wizard::slot_wizard_accepted() { // Don't show is mapped to show -> negation try { - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - if (!settings.exists("wizard")) { - settings.add("wizard", libconfig::Setting::TypeGroup); - } - auto& wizard = settings["wizard"]; - if (!wizard.exists("show_wizard")) { - wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = false; - } else { - wizard["show_wizard"] = false; - } - GlobalSettingStation::GetInstance().SyncSettings(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + settings.setValue("wizard/show_wizard", false); } catch (...) { - SPDLOG_ERROR("setting operation error"); + GF_UI_LOG_ERROR("setting operation error"); } if (field("openHelp").toBool()) { emit SignalOpenHelp("docu.html#content"); @@ -77,19 +71,20 @@ void Wizard::slot_wizard_accepted() { } IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { - setTitle(_("Getting Started...")); - setSubTitle(_("... with GpgFrontend")); + setTitle(tr("Getting Started...")); + setSubTitle(tr("... with GpgFrontend")); auto* topLabel = new QLabel( - QString(_("Welcome to use GpgFrontend for decrypting and signing text or " - "file!")) + + QString( + tr("Welcome to use GpgFrontend for decrypting and signing text or " + "file!")) + " <br><br><a href='https://gpgfrontend.bktus.com'>GpgFrontend</a> " + - _("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and " - "Installation-Free OpenPGP Crypto Tool.") + - _("For brief information have a look at the") + + tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and " + "Installation-Free OpenPGP Crypto Tool.") + + tr("For brief information have a look at the") + " <a href='https://gpgfrontend.bktus.com/index.html#/overview'>" + - _("Overview") + "</a> (" + - _("by clicking the link, the page will open in the web browser") + + tr("Overview") + "</a> (" + + tr("by clicking the link, the page will open in the web browser") + "). <br>"); topLabel->setTextFormat(Qt::RichText); topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); @@ -97,18 +92,16 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { topLabel->setWordWrap(true); // QComboBox for language selection - auto* langLabel = - new QLabel(_("If it supports the language currently being used in your " - "system, GpgFrontend will automatically set it.")); - langLabel->setWordWrap(true); + auto* lang_label = + new QLabel(tr("If it supports the language currently being used in your " + "system, GpgFrontend will automatically set it.")); + lang_label->setWordWrap(true); // set layout and add widgets auto* layout = new QVBoxLayout; layout->addWidget(topLabel); layout->addStretch(); -#ifdef MULTI_LANG_SUPPORT - layout->addWidget(langLabel); -#endif + layout->addWidget(lang_label); setLayout(layout); } @@ -116,60 +109,56 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { int IntroPage::nextId() const { return Wizard::Page_Choose; } ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) { - setTitle(_("Choose your action...")); - setSubTitle(_("...by clicking on the appropriate link.")); - - auto* keygenLabel = new QLabel( - QString(_( - "If you have never used GpgFrontend before and also don't own a gpg " - "key yet you " - "may possibly want to read how to")) + - " <a " - "href=\"https://gpgfrontend.bktus.com/index.html#/manual/" + setTitle(tr("Choose your action...")); + setSubTitle(tr("...by clicking on the appropriate link.")); + + auto* keygen_label = new QLabel( + tr("If you have never used GpgFrontend before and also don't own a gpg " + "key yet you may possibly want to read how to") + + " <a href=\"https://gpgfrontend.bktus.com/index.html#/manual/" "generate-key\">" + - _("Generate Key") + "</a><hr>"); - keygenLabel->setTextFormat(Qt::RichText); - keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - keygenLabel->setOpenExternalLinks(true); - keygenLabel->setWordWrap(true); - - auto* encrDecyTextLabel = new QLabel( - QString(_( - "If you want to learn how to encrypt, decrypt, sign and verify text, " - "you can read ")) + + tr("Generate Key") + "</a><hr>"); + keygen_label->setTextFormat(Qt::RichText); + keygen_label->setTextInteractionFlags(Qt::TextBrowserInteraction); + keygen_label->setOpenExternalLinks(true); + keygen_label->setWordWrap(true); + + auto* encr_decy_text_label = new QLabel( + tr("If you want to learn how to encrypt, decrypt, sign and verify text, " + "you can read ") + "<a " "href=\"https://gpgfrontend.bktus.com/index.html#/manual/" "encrypt-decrypt-text\">" + - _("Encrypt & Decrypt Text") + "</a> " + _("or") + + tr("Encrypt & Decrypt Text") + "</a> " + tr("or") + " <a " "href=\"https://gpgfrontend.bktus.com/index.html#/manual/" "sign-verify-text\">" + - _("Sign & Verify Text") + "</a><hr>"); + tr("Sign & Verify Text") + "</a><hr>"); - encrDecyTextLabel->setTextFormat(Qt::RichText); - encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - encrDecyTextLabel->setOpenExternalLinks(true); - encrDecyTextLabel->setWordWrap(true); + encr_decy_text_label->setTextFormat(Qt::RichText); + encr_decy_text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); + encr_decy_text_label->setOpenExternalLinks(true); + encr_decy_text_label->setWordWrap(true); - auto* signVerifyTextLabel = - new QLabel(QString(_("If you want to operate file, you can read ")) + + auto* sign_verify_text_label = + new QLabel(tr("If you want to operate file, you can read ") + "<a " "href=\"https://gpgfrontend.bktus.com/index.html#/manual/" "encrypt-decrypt-file\">" + - _("Encrypt & Sign File") + "</a> " + _("or") + + tr("Encrypt & Sign File") + "</a> " + tr("or") + " <a " "href=\"https://gpgfrontend.bktus.com/index.html#/manual/" "sign-verify-file\">" + - _("Sign & Verify File") + "</a><hr>"); - signVerifyTextLabel->setTextFormat(Qt::RichText); - signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - signVerifyTextLabel->setOpenExternalLinks(true); - signVerifyTextLabel->setWordWrap(true); + tr("Sign & Verify File") + "</a><hr>"); + sign_verify_text_label->setTextFormat(Qt::RichText); + sign_verify_text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); + sign_verify_text_label->setOpenExternalLinks(true); + sign_verify_text_label->setWordWrap(true); auto* layout = new QVBoxLayout(); - layout->addWidget(keygenLabel); - layout->addWidget(encrDecyTextLabel); - layout->addWidget(signVerifyTextLabel); + layout->addWidget(keygen_label); + layout->addWidget(encr_decy_text_label); + layout->addWidget(sign_verify_text_label); setLayout(layout); next_page_ = Wizard::Page_Conclusion; } @@ -186,33 +175,33 @@ void ChoosePage::slot_jump_page(const QString& page) { } KeyGenPage::KeyGenPage(QWidget* parent) : QWizardPage(parent) { - setTitle(_("Create a keypair...")); - setSubTitle(_("...for decrypting and signing messages")); - auto* topLabel = new QLabel( - _("You should create a new keypair." - "The pair consists of a public and a private key.<br>" - "Other users can use the public key to encrypt messages for you " - "and verify messages signed by you." - "You can use the private key to decrypt and sign messages.<br>" - "For more information have a look at the offline tutorial (which then " - "is shown in the main window):")); - topLabel->setWordWrap(true); - auto* linkLabel = new QLabel( + setTitle(tr("Create a keypair...")); + setSubTitle(tr("...for decrypting and signing messages")); + auto* top_label = new QLabel( + tr("You should create a new keypair." + "The pair consists of a public and a private key.<br>" + "Other users can use the public key to encrypt messages for you " + "and verify messages signed by you." + "You can use the private key to decrypt and sign messages.<br>" + "For more information have a look at the offline tutorial (which then " + "is shown in the main window):")); + top_label->setWordWrap(true); + auto* link_label = new QLabel( "<a href=" "docu_keygen.html#content" ">" + - QString(_("Offline tutorial")) + "</a>"); + tr("Offline tutorial") + "</a>"); - auto* createKeyButtonBox = new QWidget(this); - auto* createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox); - auto* createKeyButton = new QPushButton(_("Create New Key")); - createKeyButtonBoxLayout->addWidget(createKeyButton); - createKeyButtonBoxLayout->addStretch(1); + auto* create_key_button_box = new QWidget(this); + auto* create_key_button_box_layout = new QHBoxLayout(create_key_button_box); + auto* create_key_button = new QPushButton(tr("Create New Key")); + create_key_button_box_layout->addWidget(create_key_button); + create_key_button_box_layout->addStretch(1); auto* layout = new QVBoxLayout(); - layout->addWidget(topLabel); - layout->addWidget(linkLabel); - layout->addWidget(createKeyButtonBox); - connect(createKeyButton, &QPushButton::clicked, this, + layout->addWidget(top_label); + layout->addWidget(link_label); + layout->addWidget(create_key_button_box); + connect(create_key_button, &QPushButton::clicked, this, &KeyGenPage::slot_generate_key_dialog); setLayout(layout); @@ -226,17 +215,17 @@ void KeyGenPage::slot_generate_key_dialog() { } ConclusionPage::ConclusionPage(QWidget* parent) : QWizardPage(parent) { - setTitle(_("Ready.")); - setSubTitle(_("Have fun with GpgFrontend!")); + setTitle(tr("Ready.")); + setSubTitle(tr("Have fun with GpgFrontend!")); auto* bottomLabel = new QLabel( - QString(_("You are ready to use GpgFrontend now.<br><br>")) + + tr("You are ready to use GpgFrontend now.<br><br>") + "<a " "href=\"https://saturneric.github.io/GpgFrontend/index.html#/" "overview\">" + - _("The Online Document") + "</a>" + - _(" will get you started with GpgFrontend. Anytime you encounter " - "problems, please try to find help from the documentation") + + tr("The Online Document") + "</a>" + + tr(" will get you started with GpgFrontend. Anytime you encounter " + "problems, please try to find help from the documentation") + "<br>"); bottomLabel->setTextFormat(Qt::RichText); @@ -244,10 +233,10 @@ ConclusionPage::ConclusionPage(QWidget* parent) : QWizardPage(parent) { bottomLabel->setOpenExternalLinks(true); bottomLabel->setWordWrap(true); - open_help_check_box_ = new QCheckBox(_("Open offline help.")); + open_help_check_box_ = new QCheckBox(tr("Open offline help.")); open_help_check_box_->setChecked(true); - dont_show_wizard_checkbox_ = new QCheckBox(_("Dont show the wizard again.")); + dont_show_wizard_checkbox_ = new QCheckBox(tr("Dont show the wizard again.")); dont_show_wizard_checkbox_->setChecked(true); registerField("showWizard", dont_show_wizard_checkbox_); diff --git a/src/ui/dialog/Wizard.h b/src/ui/dialog/Wizard.h index 879dc5d9..fbc33d5e 100644 --- a/src/ui/dialog/Wizard.h +++ b/src/ui/dialog/Wizard.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef WIZARD_H -#define WIZARD_H +#pragma once #include "core/GpgConstants.h" #include "main_window/KeyMgmt.h" @@ -185,5 +184,3 @@ class ConclusionPage : public QWizardPage { }; } // namespace GpgFrontend::UI - -#endif diff --git a/src/ui/dialog/details/SignatureDetailsDialog.cpp b/src/ui/dialog/details/SignatureDetailsDialog.cpp index a3ad03b3..baf8bd4b 100644 --- a/src/ui/dialog/details/SignatureDetailsDialog.cpp +++ b/src/ui/dialog/details/SignatureDetailsDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * diff --git a/src/ui/dialog/details/SignatureDetailsDialog.h b/src/ui/dialog/details/SignatureDetailsDialog.h index 7b01d054..405c11dd 100644 --- a/src/ui/dialog/details/SignatureDetailsDialog.h +++ b/src/ui/dialog/details/SignatureDetailsDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SIGNATUREDETAILSDIALOG_H -#define GPGFRONTEND_SIGNATUREDETAILSDIALOG_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -35,5 +34,3 @@ class SignatureDetailsDialog : public QDialog { Q_OBJECT public: }; - -#endif // GPGFRONTEND_SIGNATUREDETAILSDIALOG_H diff --git a/src/ui/dialog/details/VerifyDetailsDialog.cpp b/src/ui/dialog/details/VerifyDetailsDialog.cpp index 307d404a..cea34607 100644 --- a/src/ui/dialog/details/VerifyDetailsDialog.cpp +++ b/src/ui/dialog/details/VerifyDetailsDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,14 +28,14 @@ #include "VerifyDetailsDialog.h" -#include <boost/format.hpp> +#include "core/GpgModel.h" namespace GpgFrontend::UI { VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent, GpgError error, GpgVerifyResult result) - : QDialog(parent), m_result_(std::move(result)), error_(error) { - this->setWindowTitle(_("Signatures Details")); + : QDialog(parent), m_result_(result), error_(error) { + this->setWindowTitle(tr("Signatures Details")); main_layout_ = new QHBoxLayout(); this->setLayout(main_layout_); @@ -47,7 +47,7 @@ VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent, GpgError error, void VerifyDetailsDialog::slot_refresh() { m_vbox_ = new QWidget(); - auto* mVboxLayout = new QVBoxLayout(m_vbox_); + auto* m_vbox_layout = new QVBoxLayout(m_vbox_); main_layout_->addWidget(m_vbox_); // Button Box for close button @@ -55,47 +55,38 @@ void VerifyDetailsDialog::slot_refresh() { connect(button_box_, &QDialogButtonBox::rejected, this, &VerifyDetailsDialog::close); - auto sign = m_result_->signatures; + auto signatures = m_result_.GetSignature(); - if (sign == nullptr) { - mVboxLayout->addWidget(new QLabel(_("No valid input found"))); - mVboxLayout->addWidget(button_box_); + if (signatures.empty()) { + m_vbox_layout->addWidget(new QLabel(tr("No valid input found"))); + m_vbox_layout->addWidget(button_box_); return; } // Get timestamp of signature of current text - QDateTime timestamp; -#ifdef GPGFRONTEND_GUI_QT6 - timestamp.setSecsSinceEpoch(sign->timestamp); -#else - timestamp.setTime_t(sign->timestamp); -#endif + QDateTime timestamp = signatures[0].GetCreateTime(); // Set the title widget depending on sign status - if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) { - mVboxLayout->addWidget(new QLabel(_("Error Validating signature"))); + if (gpg_err_code(signatures[0].GetStatus()) == GPG_ERR_BAD_SIGNATURE) { + m_vbox_layout->addWidget(new QLabel(tr("Error Validating signature"))); } else if (input_signature_ != nullptr) { - const auto info = (boost::format(_("File was signed on %1%")) % - QLocale::system().toString(timestamp).toStdString()) - .str() + - "<br/>" + _("It Contains") + ": " + "<br/><br/>"; - mVboxLayout->addWidget(new QLabel(info.c_str())); + const auto info = + tr("File was signed on %1").arg(QLocale::system().toString(timestamp)) + + "<br/>" + tr("It Contains") + ": " + "<br/><br/>"; + m_vbox_layout->addWidget(new QLabel(info)); } else { - const auto info = (boost::format(_("Signed on %1%")) % - QLocale::system().toString(timestamp).toStdString()) - .str() + - "<br/>" + _("It Contains") + ": " + "<br/><br/>"; - mVboxLayout->addWidget(new QLabel(info.c_str())); + const auto info = + tr("Signed on %1").arg(QLocale::system().toString(timestamp)) + + "<br/>" + tr("It Contains") + ": " + "<br/><br/>"; + m_vbox_layout->addWidget(new QLabel(info)); } // Add information box for every single key - while (sign) { - GpgSignature signature(sign); - auto* sign_box = new VerifyKeyDetailBox(signature, this); - sign = sign->next; - mVboxLayout->addWidget(sign_box); + for (const auto& signature : signatures) { + auto* detail_box = new VerifyKeyDetailBox(signature, this); + m_vbox_layout->addWidget(detail_box); } - mVboxLayout->addWidget(button_box_); + m_vbox_layout->addWidget(button_box_); } } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/details/VerifyDetailsDialog.h b/src/ui/dialog/details/VerifyDetailsDialog.h index 5bc09884..7b684e07 100644 --- a/src/ui/dialog/details/VerifyDetailsDialog.h +++ b/src/ui/dialog/details/VerifyDetailsDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,15 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __VERIFYDETAILSDIALOG_H__ -#define __VERIFYDETAILSDIALOG_H__ +#pragma once +#include "core/function/result_analyse/GpgResultAnalyse.h" +#include "core/model/GpgVerifyResult.h" #include "ui/GpgFrontendUI.h" #include "ui/widgets/PlainTextEditorPage.h" #include "ui/widgets/VerifyKeyDetailBox.h" @@ -70,5 +71,3 @@ class VerifyDetailsDialog : public QDialog { }; } // namespace GpgFrontend::UI - -#endif // __VERIFYDETAILSDIALOG_H__ diff --git a/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp b/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp index 9214a4fd..fbf018ca 100644 --- a/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp +++ b/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,8 +28,10 @@ #include "GnuPGControllerDialog.h" -#include "SignalStation.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" +#include "core/module/ModuleManager.h" +#include "ui/UISignalStation.h" #include "ui/dialog/GeneralDialog.h" #include "ui_GnuPGControllerDialog.h" @@ -37,34 +39,34 @@ namespace GpgFrontend::UI { GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) : GeneralDialog("GnuPGControllerDialog", parent), - ui_(std::make_shared<Ui_GnuPGControllerDialog>()) { + ui_(GpgFrontend::SecureCreateSharedObject<Ui_GnuPGControllerDialog>()) { ui_->setupUi(this); - ui_->generalBox->setTitle(_("General")); - ui_->keyDatabaseGroupBox->setTitle(_("Key Database")); - ui_->advanceGroupBox->setTitle(_("Advanced")); + ui_->generalBox->setTitle(tr("General")); + ui_->keyDatabaseGroupBox->setTitle(tr("Key Database")); + ui_->advanceGroupBox->setTitle(tr("Advanced")); - ui_->asciiModeCheckBox->setText(_("No ASCII Mode")); + ui_->asciiModeCheckBox->setText(tr("No ASCII Mode")); ui_->usePinentryAsPasswordInputDialogCheckBox->setText( - _("Use Pinentry as Password Input Dialog")); - ui_->useCustomGnuPGInstallPathCheckBox->setText(_("Use Custom GnuPG")); - ui_->useCustomGnuPGInstallPathButton->setText(_("Select GnuPG Path")); + tr("Use Pinentry as Password Input Dialog")); + ui_->useCustomGnuPGInstallPathCheckBox->setText(tr("Use Custom GnuPG")); + ui_->useCustomGnuPGInstallPathButton->setText(tr("Select GnuPG Path")); ui_->keyDatabseUseCustomCheckBox->setText( - _("Use Custom GnuPG Key Database Path")); + tr("Use Custom GnuPG Key Database Path")); ui_->customKeyDatabasePathSelectButton->setText( - _("Select Key Database Path")); + tr("Select Key Database Path")); // tips ui_->customGnuPGPathTipsLabel->setText( - _("Tips: please select a directroy where \"gpgconf\" is located in.")); + tr("Tips: please select a directroy where \"gpgconf\" is located in.")); ui_->restartTipsLabel->setText( - _("Tips: notice that modify any of these settings will cause an " - "Application restart.")); + tr("Tips: notice that modify any of these settings will cause an " + "Application restart.")); // announce main window connect(this, &GnuPGControllerDialog::SignalRestartNeeded, - SignalStation::GetInstance(), - &SignalStation::SignalRestartApplication); + UISignalStation::GetInstance(), + &UISignalStation::SignalRestartApplication); connect(ui_->keyDatabseUseCustomCheckBox, &QCheckBox::stateChanged, this, [=](int state) { @@ -90,32 +92,27 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) [=]() { QString selected_custom_key_database_path = QFileDialog::getExistingDirectory( - this, _("Open Directory"), {}, + this, tr("Open Directory"), {}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - SPDLOG_DEBUG("key databse path selected: {}", - selected_custom_key_database_path.toStdString()); + GF_UI_LOG_DEBUG("key databse path selected: {}", + selected_custom_key_database_path); if (!check_custom_gnupg_key_database_path( - selected_custom_key_database_path.toStdString())) { + selected_custom_key_database_path)) { return; } - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - auto& general = settings["general"]; + auto settings = GlobalSettingStation::GetInstance().GetSettings(); // update settings - if (!general.exists("custom_key_database_path")) - general.add("custom_key_database_path", - libconfig::Setting::TypeString) = - selected_custom_key_database_path.toStdString(); - else { - general["custom_key_database_path"] = - selected_custom_key_database_path.toStdString(); + if (!settings.contains("basic/custom_key_database_path")) { + settings.setValue("basic/custom_key_database_path", + selected_custom_key_database_path); } // announce the restart - this->slot_set_restart_needed(DEEP_RESTART_CODE); + this->slot_set_restart_needed(kDeepRestartCode); // update ui this->slot_update_custom_key_database_path_label( @@ -126,33 +123,25 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) ui_->useCustomGnuPGInstallPathButton, &QPushButton::clicked, this, [=]() { QString selected_custom_gnupg_install_path = QFileDialog::getExistingDirectory( - this, _("Open Directory"), {}, + this, tr("Open Directory"), {}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - SPDLOG_DEBUG("gnupg install path selected: {}", - selected_custom_gnupg_install_path.toStdString()); + GF_UI_LOG_DEBUG("gnupg install path selected: {}", + selected_custom_gnupg_install_path); // notify the user and precheck - if (!check_custom_gnupg_path( - selected_custom_gnupg_install_path.toStdString())) { + if (!check_custom_gnupg_path(selected_custom_gnupg_install_path)) { return; } - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - auto& general = settings["general"]; - - // update settings - if (!general.exists("custom_gnupg_install_path")) - general.add("custom_gnupg_install_path", - libconfig::Setting::TypeString) = - selected_custom_gnupg_install_path.toStdString(); - else { - general["custom_gnupg_install_path"] = - selected_custom_gnupg_install_path.toStdString(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + if (!settings.contains("basic/custom_gnupg_install_path")) { + settings.setValue("basic/custom_gnupg_install_path", + selected_custom_gnupg_install_path); } // announce the restart - this->slot_set_restart_needed(DEEP_RESTART_CODE); + this->slot_set_restart_needed(kDeepRestartCode); // update ui this->slot_update_custom_gnupg_install_path_label( @@ -162,7 +151,7 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) connect(ui_->usePinentryAsPasswordInputDialogCheckBox, &QCheckBox::stateChanged, this, [=](int state) { // announce the restart - this->slot_set_restart_needed(DEEP_RESTART_CODE); + this->slot_set_restart_needed(kDeepRestartCode); }); #ifndef MACOS @@ -180,20 +169,16 @@ GnuPGControllerDialog::GnuPGControllerDialog(QWidget* parent) connect(this, &QDialog::finished, this, &GnuPGControllerDialog::deleteLater); #endif - setWindowTitle(_("GnuPG Controller")); + setWindowTitle(tr("GnuPG Controller")); set_settings(); } void GnuPGControllerDialog::SlotAccept() { apply_settings(); - SPDLOG_DEBUG("gnupg controller apply done"); - - // write settings to filesystem - GlobalSettingStation::GetInstance().SyncSettings(); - - SPDLOG_DEBUG("restart needed: {}", get_restart_needed()); - if (get_restart_needed()) { + GF_UI_LOG_DEBUG("gnupg controller apply done"); + GF_UI_LOG_DEBUG("restart needed: {}", get_restart_needed()); + if (get_restart_needed() != 0) { emit SignalRestartNeeded(get_restart_needed()); } close(); @@ -202,30 +187,34 @@ void GnuPGControllerDialog::SlotAccept() { void GnuPGControllerDialog::slot_update_custom_key_database_path_label( int state) { // announce the restart - this->slot_set_restart_needed(DEEP_RESTART_CODE); + this->slot_set_restart_needed(kDeepRestartCode); + + const auto database_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.database_path", QString{}); + GF_UI_LOG_DEBUG("got gpgme.ctx.database_path from rt: {}", database_path); if (state != Qt::CheckState::Checked) { - ui_->currentKeyDatabasePathLabel->setText(QString::fromStdString( - GpgContext::GetInstance().GetInfo(false).DatabasePath)); + ui_->currentKeyDatabasePathLabel->setText(database_path); // hide label (not necessary to show the default path) this->ui_->currentKeyDatabasePathLabel->setHidden(true); } else { // read from settings file - std::string custom_key_database_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_key_database_path", std::string{}); + QString custom_key_database_path = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/custom_key_database_path") + .toString(); - SPDLOG_DEBUG("selected_custom_key_database_path from settings: {}", - custom_key_database_path); + GF_UI_LOG_DEBUG("selected_custom_key_database_path from settings: {}", + custom_key_database_path); // notify the user check_custom_gnupg_key_database_path(custom_key_database_path); // set label value - if (!custom_key_database_path.empty()) { - ui_->currentKeyDatabasePathLabel->setText( - QString::fromStdString(custom_key_database_path)); + if (!custom_key_database_path.isEmpty()) { + ui_->currentKeyDatabasePathLabel->setText(custom_key_database_path); this->ui_->currentKeyDatabasePathLabel->setHidden(false); } else { this->ui_->currentKeyDatabasePathLabel->setHidden(true); @@ -236,30 +225,36 @@ void GnuPGControllerDialog::slot_update_custom_key_database_path_label( void GnuPGControllerDialog::slot_update_custom_gnupg_install_path_label( int state) { // announce the restart - this->slot_set_restart_needed(DEEP_RESTART_CODE); + this->slot_set_restart_needed(kDeepRestartCode); + + const auto home_path = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.home_path", QString{}); + GF_UI_LOG_DEBUG("got gnupg home path from rt: {}", home_path); if (state != Qt::CheckState::Checked) { - ui_->currentCustomGnuPGInstallPathLabel->setText(QString::fromStdString( - GpgContext::GetInstance().GetInfo(false).GnuPGHomePath)); + ui_->currentCustomGnuPGInstallPathLabel->setText(home_path); // hide label (not necessary to show the default path) this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(true); } else { // read from settings file - std::string custom_gnupg_install_path = - GlobalSettingStation::GetInstance().LookupSettings( - "general.custom_gnupg_install_path", std::string{}); + QString custom_gnupg_install_path = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/custom_gnupg_install_path") + .toString(); - SPDLOG_DEBUG("custom_gnupg_install_path from settings: {}", - custom_gnupg_install_path); + GF_UI_LOG_DEBUG("custom_gnupg_install_path from settings: {}", + custom_gnupg_install_path); // notify the user check_custom_gnupg_path(custom_gnupg_install_path); // set label value - if (!custom_gnupg_install_path.empty()) { + if (!custom_gnupg_install_path.isEmpty()) { ui_->currentCustomGnuPGInstallPathLabel->setText( - QString::fromStdString(custom_gnupg_install_path)); + custom_gnupg_install_path); this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(false); } else { this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(true); @@ -268,47 +263,39 @@ void GnuPGControllerDialog::slot_update_custom_gnupg_install_path_label( } void GnuPGControllerDialog::set_settings() { - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - - try { - bool non_ascii_when_export = - settings.lookup("general.non_ascii_when_export"); - SPDLOG_DEBUG("non_ascii_when_export: {}", non_ascii_when_export); - if (non_ascii_when_export) - ui_->asciiModeCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: non_ascii_when_export"); - } - - try { - bool use_custom_key_database_path = - settings.lookup("general.use_custom_key_database_path"); - if (use_custom_key_database_path) - ui_->keyDatabseUseCustomCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: use_custom_key_database_path"); + auto& settings_station = GlobalSettingStation::GetInstance(); + + bool non_ascii_when_export = settings_station.GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + GF_UI_LOG_DEBUG("non_ascii_when_export: {}", non_ascii_when_export); + if (non_ascii_when_export) ui_->asciiModeCheckBox->setCheckState(Qt::Checked); + + bool const use_custom_key_database_path = + settings_station.GetSettings() + .value("basic/use_custom_key_database_path", false) + .toBool(); + if (use_custom_key_database_path) { + ui_->keyDatabseUseCustomCheckBox->setCheckState(Qt::Checked); } this->slot_update_custom_key_database_path_label( ui_->keyDatabseUseCustomCheckBox->checkState()); - try { - bool use_custom_gnupg_install_path = - settings.lookup("general.use_custom_gnupg_install_path"); - if (use_custom_gnupg_install_path) - ui_->useCustomGnuPGInstallPathCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: use_custom_gnupg_install_path"); + bool const use_custom_gnupg_install_path = + settings_station.GetSettings() + .value("basic/use_custom_gnupg_install_path", false) + .toBool(); + if (use_custom_gnupg_install_path) { + ui_->useCustomGnuPGInstallPathCheckBox->setCheckState(Qt::Checked); } - try { - bool use_pinentry_as_password_input_dialog = - settings.lookup("general.use_pinentry_as_password_input_dialog"); - if (use_pinentry_as_password_input_dialog) - ui_->usePinentryAsPasswordInputDialogCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR( - "setting operation error: use_pinentry_as_password_input_dialog"); + bool const use_pinentry_as_password_input_dialog = + settings_station.GetSettings() + .value("basic/use_pinentry_as_password_input_dialog", false) + .toBool(); + if (use_pinentry_as_password_input_dialog) { + ui_->usePinentryAsPasswordInputDialogCheckBox->setCheckState(Qt::Checked); } this->slot_update_custom_gnupg_install_path_label( @@ -318,48 +305,17 @@ void GnuPGControllerDialog::set_settings() { } void GnuPGControllerDialog::apply_settings() { - auto& settings = - GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("general") || - settings.lookup("general").getType() != libconfig::Setting::TypeGroup) - settings.add("general", libconfig::Setting::TypeGroup); - - auto& general = settings["general"]; - - if (!general.exists("non_ascii_when_export")) - general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) = - ui_->asciiModeCheckBox->isChecked(); - else { - general["non_ascii_when_export"] = ui_->asciiModeCheckBox->isChecked(); - } - - if (!general.exists("use_custom_key_database_path")) - general.add("use_custom_key_database_path", - libconfig::Setting::TypeBoolean) = - ui_->keyDatabseUseCustomCheckBox->isChecked(); - else { - general["use_custom_key_database_path"] = - ui_->keyDatabseUseCustomCheckBox->isChecked(); - } - - if (!general.exists("use_custom_gnupg_install_path")) - general.add("use_custom_gnupg_install_path", - libconfig::Setting::TypeBoolean) = - ui_->useCustomGnuPGInstallPathCheckBox->isChecked(); - else { - general["use_custom_gnupg_install_path"] = - ui_->useCustomGnuPGInstallPathCheckBox->isChecked(); - } - - if (!general.exists("use_pinentry_as_password_input_dialog")) - general.add("use_pinentry_as_password_input_dialog", - libconfig::Setting::TypeBoolean) = - ui_->usePinentryAsPasswordInputDialogCheckBox->isChecked(); - else { - general["use_pinentry_as_password_input_dialog"] = - ui_->usePinentryAsPasswordInputDialogCheckBox->isChecked(); - } + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); + + settings.setValue("basic/non_ascii_when_export", + ui_->asciiModeCheckBox->isChecked()); + settings.setValue("basic/use_custom_key_database_path", + ui_->keyDatabseUseCustomCheckBox->isChecked()); + settings.setValue("basic/use_custom_gnupg_install_path", + ui_->useCustomGnuPGInstallPathCheckBox->isChecked()); + settings.setValue("basic/use_pinentry_as_password_input_dialog", + ui_->usePinentryAsPasswordInputDialogCheckBox->isChecked()); } int GnuPGControllerDialog::get_restart_needed() const { @@ -370,60 +326,56 @@ void GnuPGControllerDialog::slot_set_restart_needed(int mode) { this->restart_needed_ = mode; } -bool GnuPGControllerDialog::check_custom_gnupg_path(std::string path) { - QString path_qstr = QString::fromStdString(path); - - if (path_qstr.isEmpty()) { - QMessageBox::critical(this, _("Illegal GnuPG Path"), - _("Target GnuPG Path is empty.")); +bool GnuPGControllerDialog::check_custom_gnupg_path(QString path) { + if (path.isEmpty()) { + QMessageBox::critical(this, tr("Illegal GnuPG Path"), + tr("Target GnuPG Path is empty.")); return false; } - QFileInfo dir_info(path_qstr); + QFileInfo dir_info(path); if (!dir_info.exists() || !dir_info.isReadable() || !dir_info.isDir()) { QMessageBox::critical( - this, _("Illegal GnuPG Path"), - _("Target GnuPG Path is not an exists readable directory.")); + this, tr("Illegal GnuPG Path"), + tr("Target GnuPG Path is not an exists readable directory.")); return false; } - QDir dir(path_qstr); + QDir dir(path); if (!dir.isAbsolute()) { - QMessageBox::critical(this, _("Illegal GnuPG Path"), - _("Target GnuPG Path is not an absolute path.")); + QMessageBox::critical(this, tr("Illegal GnuPG Path"), + tr("Target GnuPG Path is not an absolute path.")); } #ifdef WINDOWS - QFileInfo gpgconf_info(path_qstr + "/gpgconf.exe"); + QFileInfo gpgconf_info(path + "/gpgconf.exe"); #else - QFileInfo gpgconf_info(path_qstr + "/gpgconf"); + QFileInfo gpgconf_info(path + "/gpgconf"); #endif if (!gpgconf_info.exists() || !gpgconf_info.isExecutable() || !gpgconf_info.isFile()) { QMessageBox::critical( - this, _("Illegal GnuPG Path"), - _("Target GnuPG Path contains no \"gpgconf\" executable.")); + this, tr("Illegal GnuPG Path"), + tr("Target GnuPG Path contains no \"gpgconf\" executable.")); return false; } return true; } -bool GnuPGControllerDialog::check_custom_gnupg_key_database_path( - std::string path) { - QString selected_custom_key_database_path = QString::fromStdString(path); - - if (selected_custom_key_database_path.isEmpty()) { - QMessageBox::critical(this, _("Illegal GnuPG Key Database Path"), - _("Target GnuPG Key Database Path is empty.")); +auto GnuPGControllerDialog::check_custom_gnupg_key_database_path(QString path) + -> bool { + if (path.isEmpty()) { + QMessageBox::critical(this, tr("Illegal GnuPG Key Database Path"), + tr("Target GnuPG Key Database Path is empty.")); return false; } - QFileInfo dir_info(selected_custom_key_database_path); + QFileInfo dir_info(path); if (!dir_info.exists() || !dir_info.isReadable() || !dir_info.isDir()) { - QMessageBox::critical(this, _("Illegal GnuPG Key Database Path"), - _("Target GnuPG Key Database Path is not an " - "exists readable directory.")); + QMessageBox::critical(this, tr("Illegal GnuPG Key Database Path"), + tr("Target GnuPG Key Database Path is not an " + "exists readable directory.")); return false; } diff --git a/src/ui/dialog/gnupg/GnuPGControllerDialog.h b/src/ui/dialog/gnupg/GnuPGControllerDialog.h index 9d53cf46..201801dc 100644 --- a/src/ui/dialog/gnupg/GnuPGControllerDialog.h +++ b/src/ui/dialog/gnupg/GnuPGControllerDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,14 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GNUPGCONTROLLERDIALOGLOG_H -#define GPGFRONTEND_GNUPGCONTROLLERDIALOGLOG_H +#pragma once -#include <string> -#include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" class Ui_GnuPGControllerDialog; @@ -94,16 +91,34 @@ class GnuPGControllerDialog : public GeneralDialog { * @return true * @return false */ - int get_restart_needed() const; + [[nodiscard]] auto get_restart_needed() const -> int; + /** + * @brief Set the settings object + * + */ void set_settings(); + /** + * @brief + * + */ void apply_settings(); - bool check_custom_gnupg_path(std::string); + /** + * @brief + * + * @return true + * @return false + */ + auto check_custom_gnupg_path(QString) -> bool; - bool check_custom_gnupg_key_database_path(std::string); + /** + * @brief + * + * @return true + * @return false + */ + auto check_custom_gnupg_key_database_path(QString) -> bool; }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GNUPGCONTROLLERDIALOGLOG_H diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp index 111a77af..e4a189a3 100644 --- a/src/ui/dialog/help/AboutDialog.cpp +++ b/src/ui/dialog/help/AboutDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -30,17 +30,18 @@ #include <openssl/opensslv.h> +#include <any> + #include "GpgFrontendBuildInfo.h" #include "core/function/GlobalSettingStation.h" -#include "core/thread/TaskRunnerGetter.h" +#include "core/module/ModuleManager.h" #include "ui/dialog/help/GnupgTab.h" -#include "ui/thread/VersionCheckTask.h" namespace GpgFrontend::UI { AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) : GeneralDialog(typeid(AboutDialog).name(), parent) { - this->setWindowTitle(QString(_("About")) + " " + qApp->applicationName()); + this->setWindowTitle(tr("About") + " " + qApp->applicationName()); auto* tab_widget = new QTabWidget; auto* info_tab = new InfoTab(); @@ -48,70 +49,68 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) auto* translators_tab = new TranslatorsTab(); update_tab_ = new UpdateTab(); - tab_widget->addTab(info_tab, _("About GpgFrontend")); - tab_widget->addTab(gnupg_tab, _("GnuPG")); - tab_widget->addTab(translators_tab, _("Translators")); - tab_widget->addTab(update_tab_, _("Update")); + tab_widget->addTab(info_tab, tr("About GpgFrontend")); + tab_widget->addTab(gnupg_tab, tr("GnuPG")); + tab_widget->addTab(translators_tab, tr("Translators")); + tab_widget->addTab(update_tab_, tr("Update")); connect(tab_widget, &QTabWidget::currentChanged, this, - [&](int index) { SPDLOG_DEBUG("current index: {}", index); }); + [&](int index) { GF_UI_LOG_DEBUG("current index: {}", index); }); if (defaultIndex < tab_widget->count() && defaultIndex >= 0) { tab_widget->setCurrentIndex(defaultIndex); } - auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(buttonBox, &QDialogButtonBox::accepted, this, &AboutDialog::close); + auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(button_box, &QDialogButtonBox::accepted, this, &AboutDialog::close); - auto* mainLayout = new QVBoxLayout; - mainLayout->addWidget(tab_widget); - mainLayout->addWidget(buttonBox); - setLayout(mainLayout); + auto* main_layout = new QVBoxLayout; + main_layout->addWidget(tab_widget); + main_layout->addWidget(button_box); + setLayout(main_layout); this->resize(550, 650); this->setMinimumWidth(450); this->show(); } -void AboutDialog::showEvent(QShowEvent* ev) { - QDialog::showEvent(ev); - update_tab_->getLatestVersion(); -} +void AboutDialog::showEvent(QShowEvent* ev) { QDialog::showEvent(ev); } InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { - auto* pixmap = new QPixmap(":gpgfrontend-logo.png"); + const auto gpgme_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.version", QString{"2.0.0"}); + GF_UI_LOG_DEBUG("got gpgme version from rt: {}", gpgme_version); + + auto* pixmap = new QPixmap(":/icons/gpgfrontend-logo.png"); auto* text = new QString( "<center><h2>" + qApp->applicationName() + "</h2></center>" + "<center><b>" + qApp->applicationVersion() + "</b></center>" + "<center>" + GIT_VERSION + "</center>" + "<br><center>" + - _("GpgFrontend is an easy-to-use, compact, cross-platform, " - "and installation-free GnuPG Frontend." - "It visualizes most of the common operations of GnuPG." - "GpgFrontend is licensed under the GPLv3") + + tr("GpgFrontend is an easy-to-use, compact, cross-platform, " + "and installation-free GnuPG Frontend." + "It visualizes most of the common operations of GnuPG." + "GpgFrontend is licensed under the GPLv3") + "<br><br>" "<b>" + - _("Developer:") + "</b><br>" + "Saturneric" + "<br><br>" + - _("If you have any questions or suggestions, raise an issue at") + + tr("Developer:") + "</b><br>" + "Saturneric" + "<br><br>" + + tr("If you have any questions or suggestions, raise an issue at") + "<br/>" " <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> " + - _("or send a mail to my mailing list at") + " <a " + + tr("or send a mail to my mailing list at") + " <a " + "href=\"mailto:[email protected]\">[email protected]</a>." + "<br><br> " + - _("Built with Qt") + " " + qVersion() + ", " + OPENSSL_VERSION_TEXT + - " " + _("and") + " " + "GPGME" + " " + - GpgFrontend::GpgContext::GetInstance() - .GetInfo(false) - .GpgMEVersion.c_str() + - "<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>"); + tr("Built with Qt") + " " + qVersion() + ", " + OPENSSL_VERSION_TEXT + + " " + tr("and") + " " + "GPGME" + " " + gpgme_version + "<br>" + + tr("Built at") + " " + BUILD_TIMESTAMP + "</center>"); auto* layout = new QGridLayout(); - auto* pixmapLabel = new QLabel(); - pixmapLabel->setPixmap(*pixmap); - layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); - auto* aboutLabel = new QLabel(); - aboutLabel->setText(*text); - aboutLabel->setWordWrap(true); - aboutLabel->setOpenExternalLinks(true); - layout->addWidget(aboutLabel, 1, 0, 1, -1); + auto* pixmap_label = new QLabel(); + pixmap_label->setPixmap(*pixmap); + layout->addWidget(pixmap_label, 0, 0, 1, -1, Qt::AlignCenter); + auto* about_label = new QLabel(); + about_label->setText(*text); + about_label->setWordWrap(true); + about_label->setOpenExternalLinks(true); + layout->addWidget(about_label, 1, 0, 1, -1); layout->addItem( new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1, 1, 1); @@ -120,30 +119,18 @@ InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { } TranslatorsTab::TranslatorsTab(QWidget* parent) : QWidget(parent) { - QFile translators_qfile; - auto translators_file = - GlobalSettingStation::GetInstance().GetResourceDir() / "TRANSLATORS"; - translators_qfile.setFileName(translators_file.u8string().c_str()); -#ifdef LINUX - if (!translators_qfile.exists()) { - translators_qfile.setFileName("/usr/local/share/GpgFrontend/TRANSLATORS"); - } -#endif - - translators_qfile.open(QIODevice::ReadOnly); - QByteArray in_buffer = translators_qfile.readAll(); - - auto* label = new QLabel(in_buffer); + QFile translators_file(":/TRANSLATORS"); + translators_file.open(QIODevice::ReadOnly); + auto* label = new QLabel(translators_file.readAll()); auto* main_layout = new QVBoxLayout(this); main_layout->addWidget(label); main_layout->addStretch(); - auto notice_label = new QLabel( - _("If you think there are any problems with the translation, why not " - "participate in the translation work? If you want to participate, " - "please " - "read the document or contact me via email."), + auto* notice_label = new QLabel( + tr("If you think there are any problems with the translation, why not " + "participate in the translation work? If you want to participate, " + "please read the document or contact me via email."), this); notice_label->setWordWrap(true); main_layout->addWidget(notice_label); @@ -152,30 +139,29 @@ TranslatorsTab::TranslatorsTab(QWidget* parent) : QWidget(parent) { } UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) { - auto* pixmap = new QPixmap(":gpgfrontend-logo.png"); + auto* pixmap = new QPixmap(":/icons/gpgfrontend-logo.png"); auto* layout = new QGridLayout(); auto* pixmap_label = new QLabel(); pixmap_label->setPixmap(*pixmap); layout->addWidget(pixmap_label, 0, 0, 1, -1, Qt::AlignCenter); - current_version_ = "v" + QString::number(VERSION_MAJOR) + "." + - QString::number(VERSION_MINOR) + "." + - QString::number(VERSION_PATCH); + current_version_ = + QString("v") + VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_PATCH; - auto tips_label = new QLabel(); + auto* tips_label = new QLabel(); tips_label->setText( "<center>" + - QString(_("It is recommended that you always check the version " - "of GpgFrontend and upgrade to the latest version.")) + + tr("It is recommended that you always check the version " + "of GpgFrontend and upgrade to the latest version.") + "</center><center>" + - _("New versions not only represent new features, but " - "also often represent functional and security fixes.") + + tr("New versions not only represent new features, but " + "also often represent functional and security fixes.") + "</center>"); tips_label->setWordWrap(true); current_version_label_ = new QLabel(); - current_version_label_->setText("<center>" + QString(_("Current Version")) + - _(": ") + "<b>" + current_version_ + + current_version_label_->setText("<center>" + tr("Current Version") + + tr(": ") + "<b>" + current_version_ + "</b></center>"); current_version_label_->setWordWrap(true); @@ -203,59 +189,95 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) { setLayout(layout); } -void UpdateTab::getLatestVersion() { - this->pb_->setHidden(false); +void UpdateTab::showEvent(QShowEvent* event) { + QWidget::showEvent(event); + GF_UI_LOG_DEBUG("loading version loading info from rt"); + + auto is_loading_done = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.loading_done", false); + + if (!is_loading_done) { + Module::ListenRTPublishEvent( + this, "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.loading_done", + [=](Module::Namespace, Module::Key, int, std::any) { + GF_UI_LOG_DEBUG( + "versionchecking version.loading_done changed, calling slot " + "version upgrade"); + this->slot_show_version_status(); + }); + Module::TriggerEvent("CHECK_APPLICATION_VERSION"); + } else { + slot_show_version_status(); + } +} - SPDLOG_DEBUG("try to get latest version"); +void UpdateTab::slot_show_version_status() { + GF_UI_LOG_DEBUG("loading version info from rt"); + this->pb_->setHidden(true); - auto* version_task = new VersionCheckTask(); + auto is_loading_done = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.loading_done", false); - connect(version_task, &VersionCheckTask::SignalUpgradeVersion, this, - &UpdateTab::slot_show_version_status); + if (!is_loading_done) { + GF_UI_LOG_DEBUG("version info loading havn't been done yet."); + return; + } - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network) - ->PostTask(version_task); -} + auto is_need_upgrade = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.need_upgrade", false); -void UpdateTab::slot_show_version_status(const SoftwareVersion& version) { - this->pb_->setHidden(true); - latest_version_label_->setText( - "<center><b>" + QString(_("Latest Version From Github")) + ": " + - version.latest_version.c_str() + "</b></center>"); + auto is_current_a_withdrawn_version = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.current_a_withdrawn_version", false); + + auto is_current_version_released = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.current_version_released", false); + + auto latest_version = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.latest_version", QString{}); + + latest_version_label_->setText("<center><b>" + + tr("Latest Version From Github") + ": " + + latest_version + "</b></center>"); - if (version.NeedUpgrade()) { + if (is_need_upgrade) { upgrade_label_->setText( "<center>" + - QString(_("The current version is less than the latest version on " - "github.")) + - "</center><center>" + _("Please click") + + tr("The current version is less than the latest version on " + "github.") + + "</center><center>" + tr("Please click") + " <a " "href=\"https://www.gpgfrontend.bktus.com/#/downloads\">" + - _("Here") + "</a> " + _("to download the latest stable version.") + + tr("Here") + "</a> " + tr("to download the latest stable version.") + "</center>"); upgrade_label_->show(); - } else if (version.VersionWithDrawn()) { + } else if (is_current_a_withdrawn_version) { upgrade_label_->setText( "<center>" + - QString(_("This version has serious problems and has been withdrawn. " - "Please stop using it immediately.")) + - "</center><center>" + _("Please click") + + tr("This version has serious problems and has been withdrawn. " + "Please stop using it immediately.") + + "</center><center>" + tr("Please click") + " <a " "href=\"https://github.com/saturneric/GpgFrontend/releases\">" + - _("Here") + "</a> " + _("to download the latest stable version.") + + tr("Here") + "</a> " + tr("to download the latest stable version.") + "</center>"); upgrade_label_->show(); - } else if (!version.CurrentVersionReleased()) { + } else if (!is_current_version_released) { upgrade_label_->setText( "<center>" + - QString(_("This version has not been released yet, it may be a beta " - "version. If you are not a tester and care about version " - "stability, please do not use this version.")) + - "</center><center>" + _("Please click") + + tr("This version has not been released yet, it may be a beta " + "version. If you are not a tester and care about version " + "stability, please do not use this version.") + + "</center><center>" + tr("Please click") + " <a " "href=\"https://www.gpgfrontend.bktus.com/#/downloads\">" + - _("Here") + "</a> " + _("to download the latest stable version.") + + tr("Here") + "</a> " + tr("to download the latest stable version.") + "</center>"); upgrade_label_->show(); } diff --git a/src/ui/dialog/help/AboutDialog.h b/src/ui/dialog/help/AboutDialog.h index 6d7ce265..b7871a29 100644 --- a/src/ui/dialog/help/AboutDialog.h +++ b/src/ui/dialog/help/AboutDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __ABOUTDIALOG_H__ -#define __ABOUTDIALOG_H__ +#pragma once -#include "core/GpgContext.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" -#include "ui/struct/SoftwareVersion.h" namespace GpgFrontend::UI { @@ -89,11 +86,8 @@ class UpdateTab : public QWidget { */ explicit UpdateTab(QWidget* parent = nullptr); - /** - * @brief Get the Latest Version object - * - */ - void getLatestVersion(); + protected: + void showEvent(QShowEvent* event) override; private slots: /** @@ -101,7 +95,7 @@ class UpdateTab : public QWidget { * * @param version */ - void slot_show_version_status(const SoftwareVersion& version); + void slot_show_version_status(); signals: /** @@ -141,5 +135,3 @@ class AboutDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __ABOUTDIALOG_H__ diff --git a/src/ui/dialog/help/GnupgTab.cpp b/src/ui/dialog/help/GnupgTab.cpp index 996d4ad9..28f1acfe 100644 --- a/src/ui/dialog/help/GnupgTab.cpp +++ b/src/ui/dialog/help/GnupgTab.cpp @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +20,10 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // @@ -31,21 +32,20 @@ #include "GnupgTab.h" -#include <shared_mutex> - -#include "ui/UserInterfaceUtils.h" +#include "core/module/ModuleManager.h" #include "ui_GnuPGInfo.h" GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_GnuPGInfo>()) { + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_GnuPGInfo>()) { ui_->setupUi(this); QStringList components_column_titles; - components_column_titles << _("Name") << _("Description") << _("Version") - << _("Checksum") << _("Binary Path"); + components_column_titles << tr("Name") << tr("Description") << tr("Version") + << tr("Checksum") << tr("Binary Path"); - ui_->tabWidget->setTabText(0, _("Components")); - ui_->tabWidget->setTabText(1, _("Configurations")); + ui_->tabWidget->setTabText(0, tr("Components")); + ui_->tabWidget->setTabText(1, tr("Configurations")); ui_->componentDetailsTable->setColumnCount(components_column_titles.length()); ui_->componentDetailsTable->setHorizontalHeaderLabels( @@ -55,7 +55,9 @@ GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) QAbstractItemView::SelectRows); QStringList configurations_column_titles; - configurations_column_titles << _("Key") << _("Value"); + configurations_column_titles << tr("Component") << tr("Group") << tr("Key") + << tr("Description") << tr("Default Value") + << tr("Value"); ui_->configurationDetailsTable->setColumnCount( configurations_column_titles.length()); @@ -79,34 +81,61 @@ GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) } void GpgFrontend::UI::GnupgTab::process_software_info() { - auto& ctx_info = GpgContext::GetInstance().GetInfo(); + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + GF_UI_LOG_DEBUG("got gnupg version from rt: {}", gnupg_version); - ui_->gnupgVersionLabel->setText(QString::fromStdString( - fmt::format("Version: {}", ctx_info.GnupgVersion))); + ui_->gnupgVersionLabel->setText( + QString::fromStdString(fmt::format("Version: {}", gnupg_version))); - ui_->componentDetailsTable->setRowCount(ctx_info.ComponentsInfo.size()); + auto components = Module::ListRTChildKeys( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + "gnupg.components"); + GF_UI_LOG_DEBUG("got gnupg components from rt, size: {}", components.size()); - int row = 0; - for (const auto& info : ctx_info.ComponentsInfo) { - if (info.second.size() != 4) continue; + ui_->componentDetailsTable->setRowCount(components.size()); - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); + int row = 0; + for (auto& component : components) { + auto component_info_json_bytes = Module::RetrieveRTValueTypedOrDefault( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + QString("gnupg.components.%1").arg(component), QByteArray{}); + GF_UI_LOG_DEBUG("got gnupg component {} info from rt", component); + + auto component_info_json = + QJsonDocument::fromJson(component_info_json_bytes); + if (!component_info_json.isObject()) { + GF_UI_LOG_WARN("illegal gnupg component info, json: {}", + QString(component_info_json_bytes)); + continue; + } + + auto component_info = component_info_json.object(); + if (!component_info.contains("name")) { + GF_UI_LOG_WARN( + "illegal gnupg component info. it doesn't have a name, json: {}", + QString(component_info_json_bytes)); + continue; + } + + auto* tmp0 = new QTableWidgetItem(component_info["name"].toString()); tmp0->setTextAlignment(Qt::AlignCenter); ui_->componentDetailsTable->setItem(row, 0, tmp0); - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); + auto* tmp1 = new QTableWidgetItem(component_info["desc"].toString()); tmp1->setTextAlignment(Qt::AlignCenter); ui_->componentDetailsTable->setItem(row, 1, tmp1); - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info.second[1])); + auto* tmp2 = new QTableWidgetItem(component_info["version"].toString()); tmp2->setTextAlignment(Qt::AlignCenter); ui_->componentDetailsTable->setItem(row, 2, tmp2); - auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info.second[3])); + auto* tmp3 = + new QTableWidgetItem(component_info["binary_checksum"].toString()); tmp3->setTextAlignment(Qt::AlignCenter); ui_->componentDetailsTable->setItem(row, 3, tmp3); - auto* tmp4 = new QTableWidgetItem(QString::fromStdString(info.second[2])); + auto* tmp4 = new QTableWidgetItem(component_info["path"].toString()); tmp4->setTextAlignment(Qt::AlignLeft); ui_->componentDetailsTable->setItem(row, 4, tmp4); @@ -115,23 +144,96 @@ void GpgFrontend::UI::GnupgTab::process_software_info() { ui_->componentDetailsTable->resizeColumnsToContents(); - ui_->configurationDetailsTable->setRowCount( - ctx_info.ConfigurationsInfo.size()); - + // calcualte the total row number of configuration table row = 0; - for (const auto& info : ctx_info.ConfigurationsInfo) { - if (info.second.size() != 1) continue; - - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); - tmp0->setTextAlignment(Qt::AlignCenter); - ui_->configurationDetailsTable->setItem(row, 0, tmp0); - - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); - tmp1->setTextAlignment(Qt::AlignCenter); - ui_->configurationDetailsTable->setItem(row, 1, tmp1); - - row++; + for (auto& component : components) { + auto options = Module::ListRTChildKeys( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + QString("gnupg.components.%1.options").arg(component)); + for (auto& option : options) { + const auto option_info_json = + QJsonDocument::fromJson(Module::RetrieveRTValueTypedOrDefault( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + QString("gnupg.components.%1.options.%2") + .arg(component) + .arg(option), + QByteArray{})); + + if (!option_info_json.isObject()) continue; + + auto option_info = option_info_json.object(); + if (!option_info.contains("name") || option_info["flags"] == "1") { + continue; + } + row++; + } } + ui_->configurationDetailsTable->setRowCount(row); - ui_->configurationDetailsTable->resizeColumnsToContents(); + row = 0; + QString configuration_group; + for (auto& component : components) { + auto options = Module::ListRTChildKeys( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + QString("gnupg.components.%1.options").arg(component)); + + for (auto& option : options) { + auto option_info_json_bytes = Module::RetrieveRTValueTypedOrDefault( + "com.bktus.gpgfrontend.module.integrated.gnupg-info-gathering", + QString("gnupg.components.%1.options.%2").arg(component).arg(option), + QByteArray{}); + GF_UI_LOG_DEBUG("got gnupg component's option {} info from rt, info: {}", + component, option_info_json_bytes); + + auto option_info_json = QJsonDocument::fromJson(option_info_json_bytes); + + if (!option_info_json.isObject()) { + GF_UI_LOG_WARN("illegal gnupg option info, json: {}", + QString(option_info_json_bytes)); + continue; + } + + auto option_info = option_info_json.object(); + if (!option_info.contains("name")) { + GF_UI_LOG_WARN( + "illegal gnupg configuation info. it doesn't have a name, json: {}", + QString(option_info_json_bytes)); + continue; + } + + if (option_info["flags"] == "1") { + configuration_group = option_info["name"].toString(); + continue; + } + + auto* tmp0 = new QTableWidgetItem(component); + tmp0->setTextAlignment(Qt::AlignCenter); + ui_->configurationDetailsTable->setItem(row, 0, tmp0); + + auto* tmp1 = new QTableWidgetItem(configuration_group); + tmp1->setTextAlignment(Qt::AlignCenter); + ui_->configurationDetailsTable->setItem(row, 1, tmp1); + + auto* tmp2 = new QTableWidgetItem(option_info["name"].toString()); + tmp2->setTextAlignment(Qt::AlignCenter); + ui_->configurationDetailsTable->setItem(row, 2, tmp2); + + auto* tmp3 = new QTableWidgetItem(option_info["description"].toString()); + + tmp3->setTextAlignment(Qt::AlignLeft); + ui_->configurationDetailsTable->setItem(row, 3, tmp3); + + auto* tmp4 = + new QTableWidgetItem(option_info["default_value"].toString()); + tmp4->setTextAlignment(Qt::AlignLeft); + ui_->configurationDetailsTable->setItem(row, 4, tmp4); + + auto* tmp5 = new QTableWidgetItem(option_info["value"].toString()); + tmp5->setTextAlignment(Qt::AlignLeft); + ui_->configurationDetailsTable->setItem(row, 5, tmp5); + + row++; + } + } + // ui_->configurationDetailsTable->resizeColumnsToContents(); } diff --git a/src/ui/dialog/help/GnupgTab.h b/src/ui/dialog/help/GnupgTab.h index 9195dee0..9e6191db 100644 --- a/src/ui/dialog/help/GnupgTab.h +++ b/src/ui/dialog/help/GnupgTab.h @@ -1,7 +1,7 @@ -/* - * Copyright (c) 2022. Saturneric +/** + * Copyright (C) 2021 Saturneric <[email protected]> * - * This file is part of GpgFrontend. + * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,19 +20,19 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later + * */ // // Created by eric on 2022/7/23. // -#ifndef GPGFRONTEND_GNUPGTAB_H -#define GPGFRONTEND_GNUPGTAB_H +#pragma once -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "ui/GpgFrontendUI.h" class Ui_GnuPGInfo; @@ -53,5 +53,3 @@ class GnupgTab : public QWidget { void process_software_info(); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GNUPGTAB_H diff --git a/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp b/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp index b58d09c1..7c740063 100644 --- a/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp +++ b/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,31 +28,30 @@ #include "ExportKeyPackageDialog.h" -#include <boost/format.hpp> - +#include "core/GpgModel.h" #include "core/function/KeyPackageOperator.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "ui/UserInterfaceUtils.h" #include "ui_ExportKeyPackageDialog.h" GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog( KeyIdArgsListPtr key_ids, QWidget* parent) : GeneralDialog(typeid(ExportKeyPackageDialog).name(), parent), - ui_(std::make_shared<Ui_exportKeyPackageDialog>()), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_exportKeyPackageDialog>()), key_ids_(std::move(key_ids)) { ui_->setupUi(this); - ui_->nameValueLabel->setText( - KeyPackageOperator::GenerateKeyPackageName().c_str()); + ui_->nameValueLabel->setText(KeyPackageOperator::GenerateKeyPackageName()); connect(ui_->gnerateNameButton, &QPushButton::clicked, this, [=]() { - ui_->nameValueLabel->setText( - KeyPackageOperator::GenerateKeyPackageName().c_str()); + ui_->nameValueLabel->setText(KeyPackageOperator::GenerateKeyPackageName()); }); connect(ui_->setOutputPathButton, &QPushButton::clicked, this, [=]() { auto file_name = QFileDialog::getSaveFileName( - this, _("Export Key Package"), ui_->nameValueLabel->text() + ".gfepack", - QString(_("Key Package")) + " (*.gfepack);;All Files (*)"); + this, tr("Export Key Package"), + ui_->nameValueLabel->text() + ".gfepack", + tr("Key Package") + " (*.gfepack);;All Files (*)"); // check path if (file_name.isEmpty()) return; @@ -62,18 +61,17 @@ GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog( connect(ui_->generatePassphraseButton, &QPushButton::clicked, this, [=]() { auto file_name = QFileDialog::getSaveFileName( - this, _("Export Key Package Passphrase"), + this, tr("Export Key Package Passphrase"), ui_->nameValueLabel->text() + ".key", - QString(_("Key File")) + " (*.key);;All Files (*)"); + tr("Key File") + " (*.key);;All Files (*)"); // check path if (file_name.isEmpty()) return; - if (!KeyPackageOperator::GeneratePassphrase(file_name.toStdString(), - passphrase_)) { + if (!KeyPackageOperator::GeneratePassphrase(file_name, passphrase_)) { QMessageBox::critical( - this, _("Error"), - _("An error occurred while generating the passphrase file.")); + this, tr("Error"), + tr("An error occurred while generating the passphrase file.")); return; } ui_->passphraseValueLabel->setText(file_name); @@ -82,71 +80,87 @@ GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog( connect(ui_->button_box_, &QDialogButtonBox::accepted, this, [=]() { if (ui_->outputPathLabel->text().isEmpty()) { QMessageBox::critical( - this, _("Forbidden"), - _("Please select an output path before exporting.")); + this, tr("Forbidden"), + tr("Please select an output path before exporting.")); return; } if (ui_->passphraseValueLabel->text().isEmpty()) { QMessageBox::critical( - this, _("Forbidden"), - _("Please generate a password to protect your key before exporting, " - "it is very important. Don't forget to back up your password in a " - "safe place.")); + this, tr("Forbidden"), + tr("Please generate a password to protect your key before exporting, " + "it is very important. Don't forget to back up your password in a " + "safe place.")); return; } // get suitable key ids - auto key_id_exported = std::make_unique<KeyIdArgsList>(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids_); - for (const auto& key : *keys) { - if (ui_->noPublicKeyCheckBox->isChecked() && !key.IsPrivateKey()) - continue; - key_id_exported->push_back(key.GetId()); + auto keys_new_end = + std::remove_if(keys->begin(), keys->end(), [this](const auto& key) { + return ui_->noPublicKeyCheckBox->isChecked() && !key.IsPrivateKey(); + }); + keys->erase(keys_new_end, keys->end()); + + if (keys->empty()) { + QMessageBox::critical(this, tr("Error"), + tr("No key is suitable to export.")); + return; } - if (KeyPackageOperator::GenerateKeyPackage( - ui_->outputPathLabel->text().toStdString(), - ui_->nameValueLabel->text().toStdString(), key_id_exported, - passphrase_, ui_->includeSecretKeyCheckBox->isChecked())) { - QMessageBox::information( - this, _("Success"), - QString( - _("The Key Package has been successfully generated and has been " - "protected by encryption algorithms(AES-256-ECB). You can " - "safely transfer your Key Package.")) + - "<br /><br />" + "<b>" + - _("But the key file cannot be leaked under any " - "circumstances. Please delete the Key Package and key file as " - "soon " - "as possible after completing the transfer operation.") + - "</b>"); - accept(); - } else { - QMessageBox::critical( - this, _("Error"), - _("An error occurred while exporting the key package.")); - } + CommonUtils::WaitForOpera( + this, tr("Generating"), [this, keys](const OperaWaitingHd& op_hd) { + KeyPackageOperator::GenerateKeyPackage( + ui_->outputPathLabel->text(), ui_->nameValueLabel->text(), *keys, + passphrase_, ui_->includeSecretKeyCheckBox->isChecked(), + [=](GFError err, const DataObjectPtr&) { + // stop waiting + op_hd(); + + if (err >= 0) { + QMessageBox::information( + this, tr("Success"), + QString( + tr("The Key Package has been successfully generated " + "and has been protected by encryption " + "algorithms(AES-256-ECB). You can safely transfer " + "your Key Package.")) + + "<br /><br />" + "<b>" + + tr("But the key file cannot be leaked under any " + "circumstances. Please delete the Key Package and " + "key file as soon as possible after completing " + "the " + "transfer " + "operation.") + + "</b>"); + accept(); + } else { + QMessageBox::critical( + this, tr("Error"), + tr("An error occurred while exporting the key package.")); + } + }); + }); }); connect(ui_->button_box_, &QDialogButtonBox::rejected, this, [=]() { this->close(); }); - ui_->nameLabel->setText(_("Key Package Name")); - ui_->selectOutputPathLabel->setText(_("Output Path")); - ui_->passphraseLabel->setText(_("Passphrase")); + ui_->nameLabel->setText(tr("Key Package Name")); + ui_->selectOutputPathLabel->setText(tr("Output Path")); + ui_->passphraseLabel->setText(tr("Passphrase")); ui_->tipsLabel->setText( - _("Tips: You can use Key Package to safely and conveniently transfer " - "your public and private keys between devices.")); - ui_->generatePassphraseButton->setText(_("Generate and Save Passphrase")); - ui_->gnerateNameButton->setText(_("Generate Key Package Name")); - ui_->setOutputPathButton->setText(_("Select Output Path")); + tr("Tips: You can use Key Package to safely and conveniently transfer " + "your public and private keys between devices.")); + ui_->generatePassphraseButton->setText(tr("Generate and Save Passphrase")); + ui_->gnerateNameButton->setText(tr("Generate Key Package Name")); + ui_->setOutputPathButton->setText(tr("Select Output Path")); ui_->includeSecretKeyCheckBox->setText( - _("Include secret key (Think twice before acting)")); + tr("Include secret key (Think twice before acting)")); ui_->noPublicKeyCheckBox->setText( - _("Exclude keys that do not have a private key")); + tr("Exclude keys that do not have a private key")); setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle(_("Export As Key Package")); + setWindowTitle(tr("Export As Key Package")); } diff --git a/src/ui/dialog/import_export/ExportKeyPackageDialog.h b/src/ui/dialog/import_export/ExportKeyPackageDialog.h index c5f9a2b1..abf7a84c 100644 --- a/src/ui/dialog/import_export/ExportKeyPackageDialog.h +++ b/src/ui/dialog/import_export/ExportKeyPackageDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H -#define GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H +#pragma once #include "GpgFrontendUI.h" +#include "core/typedef/GpgTypedef.h" #include "ui/dialog/GeneralDialog.h" class Ui_exportKeyPackageDialog; @@ -55,8 +55,6 @@ class ExportKeyPackageDialog : public GeneralDialog { private: std::shared_ptr<Ui_exportKeyPackageDialog> ui_; ///< KeyIdArgsListPtr key_ids_; ///< - std::string passphrase_; ///< + QString passphrase_; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp index 32ae63fa..720fa883 100644 --- a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp +++ b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,21 +28,19 @@ #include "KeyImportDetailDialog.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/GpgImportInformation.h" namespace GpgFrontend::UI { -KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result, - bool automatic, QWidget* parent) +KeyImportDetailDialog::KeyImportDetailDialog( + std::shared_ptr<GpgImportInformation> result, QWidget* parent) : GeneralDialog(typeid(KeyImportDetailDialog).name(), parent), m_result_(std::move(result)) { // If no key for import found, just show a message - if (m_result_.considered == 0) { - if (automatic) - QMessageBox::information(parent, _("Key Update Details"), - _("No keys found")); - else - QMessageBox::information(parent, _("Key Import Details"), - _("No keys found to import")); + if (m_result_->considered == 0) { + QMessageBox::information(parent, tr("Key Import Details"), + tr("No keys found to import")); emit finished(0); this->close(); this->deleteLater(); @@ -57,18 +55,13 @@ KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result, mv_box->addWidget(button_box_); this->setLayout(mv_box); - if (automatic) - this->setWindowTitle(_("Key Update Details")); - else - this->setWindowTitle(_("Key Import Details")); - - auto pos = QPoint(100, 100); - if (parent) pos += parent->pos(); - this->move(pos); + this->setWindowTitle(tr("Key Import Details")); this->setMinimumSize(QSize(600, 300)); this->adjustSize(); + movePosition2CenterOfParent(); + this->setModal(true); this->show(); } @@ -76,54 +69,53 @@ KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result, void KeyImportDetailDialog::create_general_info_box() { // GridBox for general import information - general_info_box_ = new QGroupBox(_("General key info")); - auto* generalInfoBoxLayout = new QGridLayout(general_info_box_); + general_info_box_ = new QGroupBox(tr("General key info")); + auto* general_info_box_layout = new QGridLayout(general_info_box_); - generalInfoBoxLayout->addWidget(new QLabel(QString(_("Considered")) + ": "), - 1, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.considered)), 1, 1); + general_info_box_layout->addWidget(new QLabel(tr("Considered") + ": "), 1, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->considered)), 1, 1); int row = 2; - if (m_result_.unchanged != 0) { - generalInfoBoxLayout->addWidget( - new QLabel(QString(_("Public unchanged")) + ": "), row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.unchanged)), row, 1); + if (m_result_->unchanged != 0) { + general_info_box_layout->addWidget( + new QLabel(tr("Public unchanged") + ": "), row, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->unchanged)), row, 1); row++; } - if (m_result_.imported != 0) { - generalInfoBoxLayout->addWidget(new QLabel(QString(_("Imported")) + ": "), - row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.imported)), row, 1); + if (m_result_->imported != 0) { + general_info_box_layout->addWidget(new QLabel(tr("Imported") + ": "), row, + 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->imported)), row, 1); row++; } - if (m_result_.not_imported != 0) { - generalInfoBoxLayout->addWidget( - new QLabel(QString(_("Not Imported")) + ": "), row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.not_imported)), row, 1); + if (m_result_->not_imported != 0) { + general_info_box_layout->addWidget(new QLabel(tr("Not Imported") + ": "), + row, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->not_imported)), row, 1); row++; } - if (m_result_.secret_read != 0) { - generalInfoBoxLayout->addWidget( - new QLabel(QString(_("Private Read")) + ": "), row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.secret_read)), row, 1); + if (m_result_->secret_read != 0) { + general_info_box_layout->addWidget(new QLabel(tr("Private Read") + ": "), + row, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->secret_read)), row, 1); row++; } - if (m_result_.secret_imported != 0) { - generalInfoBoxLayout->addWidget( - new QLabel(QString(_("Private Imported")) + ": "), row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.secret_imported)), row, 1); + if (m_result_->secret_imported != 0) { + general_info_box_layout->addWidget( + new QLabel(tr("Private Imported") + ": "), row, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->secret_imported)), row, 1); row++; } - if (m_result_.secret_unchanged != 0) { - generalInfoBoxLayout->addWidget( - new QLabel(QString(_("Private Unchanged")) + ": "), row, 0); - generalInfoBoxLayout->addWidget( - new QLabel(QString::number(m_result_.secret_unchanged)), row, 1); + if (m_result_->secret_unchanged != 0) { + general_info_box_layout->addWidget( + new QLabel(tr("Private Unchanged") + ": "), row, 0); + general_info_box_layout->addWidget( + new QLabel(QString::number(m_result_->secret_unchanged)), row, 1); } } @@ -135,24 +127,22 @@ void KeyImportDetailDialog::create_keys_table() { // Nothing is selectable keys_table_->setSelectionMode(QAbstractItemView::NoSelection); - QStringList headerLabels; - headerLabels << _("Name") << _("Email") << _("Status") << _("Fingerprint"); + QStringList header_labels; + header_labels << tr("Name") << tr("Email") << tr("Status") + << tr("Fingerprint"); keys_table_->verticalHeader()->hide(); - keys_table_->setHorizontalHeaderLabels(headerLabels); + keys_table_->setHorizontalHeaderLabels(header_labels); int row = 0; - for (const auto& imp_key : m_result_.importedKeys) { + for (const auto& imp_key : m_result_->imported_keys) { keys_table_->setRowCount(row + 1); - GpgKey key = GpgKeyGetter::GetInstance().GetKey(imp_key.fpr); + auto key = GpgKeyGetter::GetInstance().GetKey(imp_key.fpr); if (!key.IsGood()) continue; - keys_table_->setItem( - row, 0, new QTableWidgetItem(QString::fromStdString(key.GetName()))); - keys_table_->setItem( - row, 1, new QTableWidgetItem(QString::fromStdString(key.GetEmail()))); + keys_table_->setItem(row, 0, new QTableWidgetItem(key.GetName())); + keys_table_->setItem(row, 1, new QTableWidgetItem(key.GetEmail())); keys_table_->setItem( row, 2, new QTableWidgetItem(get_status_string(imp_key.import_status))); - keys_table_->setItem( - row, 3, new QTableWidgetItem(QString::fromStdString(imp_key.fpr))); + keys_table_->setItem(row, 3, new QTableWidgetItem(imp_key.fpr)); row++; } keys_table_->horizontalHeader()->setSectionResizeMode( @@ -165,27 +155,27 @@ QString KeyImportDetailDialog::get_status_string(int key_status) { QString status_string; // keystatus is greater than 15, if key is private if (key_status > 15) { - status_string.append(_("Private")); + status_string.append(tr("Private")); key_status = key_status - 16; } else { - status_string.append(_("Public")); + status_string.append(tr("Public")); } if (key_status == 0) { - status_string.append(", " + QString(_("Unchanged"))); + status_string.append(", " + tr("Unchanged")); } else { if (key_status == 1) { - status_string.append(", " + QString(_("New Key"))); + status_string.append(", " + tr("New Key")); } else { if (key_status > 7) { - status_string.append(", " + QString(_("New Subkey"))); + status_string.append(", " + tr("New Subkey")); return status_string; } if (key_status > 3) { - status_string.append(", " + QString(_("New Signature"))); + status_string.append(", " + tr("New Signature")); return status_string; } if (key_status > 1) { - status_string.append(", " + QString(_("New UID"))); + status_string.append(", " + tr("New UID")); return status_string; } } diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.h b/src/ui/dialog/import_export/KeyImportDetailDialog.h index 06f44e94..db355570 100644 --- a/src/ui/dialog/import_export/KeyImportDetailDialog.h +++ b/src/ui/dialog/import_export/KeyImportDetailDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,20 +20,21 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEYIMPORTDETAILSDIALOG_H__ -#define __KEYIMPORTDETAILSDIALOG_H__ +#pragma once -#include "core/GpgContext.h" #include "core/function/gpg/GpgKeyImportExporter.h" -#include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" +namespace GpgFrontend { +class GpgImportInformation; +} + namespace GpgFrontend::UI { /** @@ -51,8 +52,8 @@ class KeyImportDetailDialog : public GeneralDialog { * @param automatic * @param parent */ - KeyImportDetailDialog(GpgImportInformation result, bool automatic, - QWidget* parent = nullptr); + explicit KeyImportDetailDialog(std::shared_ptr<GpgImportInformation> result, + QWidget* parent = nullptr); private: /** @@ -85,8 +86,7 @@ class KeyImportDetailDialog : public GeneralDialog { QGroupBox* general_info_box_{}; ///< QGroupBox* key_info_box_{}; ///< QDialogButtonBox* button_box_{}; ///< - GpgImportInformation m_result_; ///< + + std::shared_ptr<GpgImportInformation> m_result_; ///< }; } // namespace GpgFrontend::UI - -#endif // __KEYIMPORTDETAILSDIALOG_H__ diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.cpp b/src/ui/dialog/import_export/KeyServerImportDialog.cpp index cf4fbe55..49438c44 100644 --- a/src/ui/dialog/import_export/KeyServerImportDialog.cpp +++ b/src/ui/dialog/import_export/KeyServerImportDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -29,169 +29,115 @@ #include "KeyServerImportDialog.h" #include <QRegExp> -#include <string> -#include <utility> +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyImportExporter.h" -#include "thread/KeyServerImportTask.h" -#include "ui/SignalStation.h" +#include "ui/UISignalStation.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/KeyServerSO.h" +#include "ui/thread/KeyServerImportTask.h" #include "ui/thread/KeyServerSearchTask.h" namespace GpgFrontend::UI { -KeyServerImportDialog::KeyServerImportDialog(bool automatic, QWidget* parent) - : GeneralDialog("key_server_import_dialog", parent), - m_automatic_(automatic) { - // Layout for messagebox - auto* message_layout = new QHBoxLayout(); - - bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); - +KeyServerImportDialog::KeyServerImportDialog(QWidget* parent) + : GeneralDialog("key_server_import_dialog", parent) { + auto forbid_all_gnupg_connection = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("network/forbid_all_gnupg_connection", false) + .toBool(); if (forbid_all_gnupg_connection) { QMessageBox::critical(this, "Forbidden", "GnuPG is in offline mode now."); this->close(); this->deleteLater(); } - if (automatic) { - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - } else { - // Buttons - - close_button_ = new QPushButton(_("Close")); - connect(close_button_, &QPushButton::clicked, this, - &KeyServerImportDialog::close); - import_button_ = new QPushButton(_("Import ALL")); - connect(import_button_, &QPushButton::clicked, this, - &KeyServerImportDialog::slot_import); - import_button_->setDisabled(true); - search_button_ = new QPushButton(_("Search")); - connect(search_button_, &QPushButton::clicked, this, - &KeyServerImportDialog::slot_search); - - // Line edits for search string - search_label_ = new QLabel(QString(_("Search String")) + _(": ")); - search_line_edit_ = new QLineEdit(); - - // combobox for keyserver list - key_server_label_ = new QLabel(QString(_("Key Server")) + _(": ")); - key_server_combo_box_ = create_comboBox(); - - // table containing the keys found - create_keys_table(); - message_ = new QLabel(); - message_->setFixedHeight(24); - icon_ = new QLabel(); - icon_->setFixedHeight(24); - - message_layout->addWidget(icon_); - message_layout->addWidget(message_); - message_layout->addStretch(); - } + // Buttons + close_button_ = new QPushButton(tr("Close")); + connect(close_button_, &QPushButton::clicked, this, + &KeyServerImportDialog::close); + import_button_ = new QPushButton(tr("Import ALL")); + connect(import_button_, &QPushButton::clicked, this, + &KeyServerImportDialog::slot_import); + import_button_->setDisabled(true); + search_button_ = new QPushButton(tr("Search")); + connect(search_button_, &QPushButton::clicked, this, + &KeyServerImportDialog::slot_search); + + // Line edits for search string + search_label_ = new QLabel(tr("Search String") + tr(": ")); + search_line_edit_ = new QLineEdit(); + + // combobox for keyserver list + key_server_label_ = new QLabel(tr("Key Server") + tr(": ")); + key_server_combo_box_ = create_combo_box(); + + // table containing the keys found + create_keys_table(); + message_ = new QLabel(); + message_->setFixedHeight(24); + icon_ = new QLabel(); + icon_->setFixedHeight(24); + + // Layout for messagebox + message_layout_ = new QHBoxLayout(); + message_layout_->addWidget(icon_); + message_layout_->addWidget(message_); + message_layout_->addStretch(); // Network Waiting waiting_bar_ = new QProgressBar(); waiting_bar_->setVisible(false); waiting_bar_->setRange(0, 0); waiting_bar_->setFixedWidth(200); - message_layout->addWidget(waiting_bar_); - - auto* mainLayout = new QGridLayout; - - // 自动化调用界面布局 - if (automatic) { - mainLayout->addLayout(message_layout, 0, 0, 1, 3); - } else { - mainLayout->addWidget(search_label_, 1, 0); - mainLayout->addWidget(search_line_edit_, 1, 1); - mainLayout->addWidget(search_button_, 1, 2); - mainLayout->addWidget(key_server_label_, 2, 0); - mainLayout->addWidget(key_server_combo_box_, 2, 1); - mainLayout->addWidget(keys_table_, 3, 0, 1, 3); - mainLayout->addLayout(message_layout, 4, 0, 1, 3); - - // Layout for import and close button - auto* buttonsLayout = new QHBoxLayout; - buttonsLayout->addStretch(); - buttonsLayout->addWidget(import_button_); - buttonsLayout->addWidget(close_button_); - mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3); - } - - this->setLayout(mainLayout); - if (automatic) - this->setWindowTitle(_("Update Keys from Keyserver")); - else - this->setWindowTitle(_("Import Keys from Keyserver")); - - if (automatic) { - this->setFixedSize(240, 42); - } + auto* main_layout = new QGridLayout(); + + main_layout->addWidget(search_label_, 1, 0); + main_layout->addWidget(search_line_edit_, 1, 1); + main_layout->addWidget(search_button_, 1, 2); + main_layout->addWidget(key_server_label_, 2, 0); + main_layout->addWidget(key_server_combo_box_, 2, 1); + main_layout->addWidget(keys_table_, 3, 0, 1, 3); + main_layout->addWidget(waiting_bar_, 4, 0, 1, 3); + main_layout->addLayout(message_layout_, 5, 0, 1, 3); + + // Layout for import and close button + auto* buttons_layout = new QHBoxLayout(); + buttons_layout->addStretch(); + buttons_layout->addWidget(import_button_); + buttons_layout->addWidget(close_button_); + main_layout->addLayout(buttons_layout, 6, 0, 1, 3); + + this->setLayout(main_layout); + this->setWindowTitle(tr("Import Keys from Keyserver")); this->setModal(true); - connect(this, &KeyServerImportDialog::SignalKeyImported, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); -} - -KeyServerImportDialog::KeyServerImportDialog(QWidget* parent) - : GeneralDialog("key_server_import_dialog", parent), m_automatic_(true) { - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); - - // Network Waiting - waiting_bar_ = new QProgressBar(); - waiting_bar_->setVisible(false); - waiting_bar_->setRange(0, 0); - waiting_bar_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - waiting_bar_->setTextVisible(false); - - // Layout for messagebox - auto* layout = new QHBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(waiting_bar_); - - key_server_combo_box_ = create_comboBox(); + movePosition2CenterOfParent(); - this->setLayout(layout); - this->setWindowTitle(_("Update Keys from Keyserver")); - this->setFixedSize(240, 42); - this->setModal(true); + connect(this, &KeyServerImportDialog::SignalKeyImported, + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); } -QComboBox* KeyServerImportDialog::create_comboBox() { - auto* comboBox = new QComboBox; - comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); +auto KeyServerImportDialog::create_combo_box() -> QComboBox* { + auto* combo_box = new QComboBox; + combo_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); try { - SettingsObject key_server_json("key_server"); - - const auto key_server_list = - key_server_json.Check("server_list", nlohmann::json::array()); - + KeyServerSO key_server(SettingsObject("general_settings_state")); + const auto& key_server_list = key_server.server_list; for (const auto& key_server : key_server_list) { - const auto key_server_str = key_server.get<std::string>(); - comboBox->addItem(key_server_str.c_str()); + combo_box->addItem(key_server); } - - int default_key_server_index = key_server_json.Check("default_server", 0); - if (default_key_server_index >= key_server_list.size()) { - throw std::runtime_error("default_server index out of range"); - } - std::string default_key_server = - key_server_list[default_key_server_index].get<std::string>(); - - comboBox->setCurrentText(default_key_server.c_str()); + combo_box->setCurrentText(key_server.GetTargetServer()); } catch (...) { - SPDLOG_ERROR("setting operation error", "server_list", "default_server"); + GF_UI_LOG_ERROR("setting operation error", "server_list", "default_server"); } - return comboBox; + return combo_box; } void KeyServerImportDialog::create_keys_table() { @@ -206,7 +152,7 @@ void KeyServerImportDialog::create_keys_table() { keys_table_->setSelectionMode(QAbstractItemView::SingleSelection); QStringList labels; - labels << _("UID") << _("Creation date") << _("KeyID") << _("Tag"); + labels << tr("UID") << tr("Creation date") << tr("KeyID") << tr("Tag"); keys_table_->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::ResizeToContents); keys_table_->setHorizontalHeaderLabels(labels); @@ -217,27 +163,24 @@ void KeyServerImportDialog::create_keys_table() { } void KeyServerImportDialog::set_message(const QString& text, bool error) { - if (m_automatic_) return; - message_->setText(text); if (error) { - icon_->setPixmap( - QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); + icon_->setPixmap(QPixmap(":/icons/error.png") + .scaled(QSize(24, 24), Qt::KeepAspectRatio)); } else { icon_->setPixmap( - QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); + QPixmap(":/icons/info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio)); } } void KeyServerImportDialog::slot_search() { if (search_line_edit_->text().isEmpty()) { - set_message("<h4>" + QString(_("Text is empty.")) + "</h4>", false); + set_message("<h4>" + tr("Text is empty.") + "</h4>", false); return; } - auto* task = new KeyServerSearchTask( - key_server_combo_box_->currentText().toStdString(), - search_line_edit_->text().toStdString()); + auto* task = new KeyServerSearchTask(key_server_combo_box_->currentText(), + search_line_edit_->text()); connect(task, &KeyServerSearchTask::SignalKeyServerSearchResult, this, &KeyServerImportDialog::slot_search_finished); @@ -267,7 +210,7 @@ void KeyServerImportDialog::slot_search() { void KeyServerImportDialog::slot_search_finished( QNetworkReply::NetworkError error, QByteArray buffer) { - SPDLOG_DEBUG("search result {} {}", error, buffer.size()); + GF_UI_LOG_DEBUG("search result {} {}", error, buffer.size()); keys_table_->clearContents(); keys_table_->setRowCount(0); @@ -275,20 +218,20 @@ void KeyServerImportDialog::slot_search_finished( auto stream = QTextStream(buffer); if (error != QNetworkReply::NoError) { - SPDLOG_DEBUG("error from reply: {}", error); + GF_UI_LOG_DEBUG("error from reply: {}", error); switch (error) { case QNetworkReply::ContentNotFoundError: - set_message(_("Not Key Found"), true); + set_message(tr("Not Key Found"), true); break; case QNetworkReply::TimeoutError: - set_message(_("Timeout"), true); + set_message(tr("Timeout"), true); break; case QNetworkReply::HostNotFoundError: - set_message(_("Key Server Not Found"), true); + set_message(tr("Key Server Not Found"), true); break; default: - set_message(_("Connection Error"), true); + set_message(tr("Connection Error"), true); } return; } @@ -297,36 +240,32 @@ void KeyServerImportDialog::slot_search_finished( auto text = stream.readLine(1024); if (text.contains("Too many responses")) { - set_message( - "<h4>" + QString(_("Too many responses from keyserver!")) + "</h4>", - true); + set_message("<h4>" + tr("Too many responses from keyserver!") + "</h4>", + true); return; } else if (text.contains("No keys found")) { // if string looks like hex string, search again with 0x prepended QRegExp rx("[0-9A-Fa-f]*"); QString query = search_line_edit_->text(); if (rx.exactMatch(query)) { - set_message( - "<h4>" + - QString(_("No keys found, input may be kexId, retrying search " - "with 0x.")) + - "</h4>", - true); + set_message("<h4>" + + tr("No keys found, input may be kexId, retrying search " + "with 0x.") + + "</h4>", + true); search_line_edit_->setText(query.prepend("0x")); this->slot_search(); return; - } else { - set_message( - "<h4>" + QString(_("No keys found containing the search string!")) + - "</h4>", - true); - return; } + set_message( + "<h4>" + tr("No keys found containing the search string!") + "</h4>", + true); + return; + } else if (text.contains("Insufficiently specific words")) { - set_message("<h4>" + - QString(_("Insufficiently specific search string!")) + - "</h4>", - true); + set_message( + "<h4>" + tr("Insufficiently specific search string!") + "</h4>", + true); return; } else { set_message(text, true); @@ -359,12 +298,10 @@ void KeyServerImportDialog::slot_search_finished( new QTableWidgetItem(QString("expired"))); } if (flags.contains("r")) { - keys_table_->setItem(row, 3, - new QTableWidgetItem(QString(_("revoked")))); + keys_table_->setItem(row, 3, new QTableWidgetItem(tr("revoked"))); } if (flags.contains("d")) { - keys_table_->setItem(row, 3, - new QTableWidgetItem(QString(_("disabled")))); + keys_table_->setItem(row, 3, new QTableWidgetItem(tr("disabled"))); } } @@ -377,14 +314,9 @@ void KeyServerImportDialog::slot_search_finished( uid->setText(line2[1]); keys_table_->setItem(row, 0, uid); } -#ifdef GPGFRONTEND_GUI_QT6 auto* creation_date = new QTableWidgetItem(QDateTime::fromSecsSinceEpoch(line[4].toInt()) .toString("dd. MMM. yyyy")); -#else - auto* creation_date = new QTableWidgetItem( - QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy")); -#endif keys_table_->setItem(row, 1, creation_date); auto* keyid = new QTableWidgetItem(line[1]); keys_table_->setItem(row, 2, keyid); @@ -414,8 +346,7 @@ void KeyServerImportDialog::slot_search_finished( } set_message( QString("<h4>") + - QString(_("%1 keys found. Double click a key to import it.")) - .arg(row) + + tr("%1 keys found. Double click a key to import it.").arg(row) + "</h4>", false); } @@ -425,142 +356,74 @@ void KeyServerImportDialog::slot_search_finished( } void KeyServerImportDialog::slot_import() { - std::vector<std::string> key_ids; + std::vector<QString> key_ids; const int row_count = keys_table_->rowCount(); for (int i = 0; i < row_count; ++i) { if (keys_table_->item(i, 2)->isSelected()) { QString keyid = keys_table_->item(i, 2)->text(); - key_ids.push_back(keyid.toStdString()); + key_ids.push_back(keyid); } } - if (!key_ids.empty()) - SlotImport(key_ids, key_server_combo_box_->currentText().toStdString()); + if (!key_ids.empty()) { + SlotImport(key_ids, key_server_combo_box_->currentText()); + } } void KeyServerImportDialog::SlotImport(const KeyIdArgsListPtr& keys) { // keyserver host url - std::string target_keyserver; + QString target_keyserver; if (key_server_combo_box_ != nullptr) { - target_keyserver = key_server_combo_box_->currentText().toStdString(); + target_keyserver = key_server_combo_box_->currentText(); } - if (target_keyserver.empty()) { - try { - SettingsObject key_server_json("key_server"); - const auto key_server_list = - key_server_json.Check("server_list", nlohmann::json::array()); - - int default_key_server_index = key_server_json.Check("default_server", 0); - if (default_key_server_index >= key_server_list.size()) { - throw std::runtime_error("default_server index out of range"); - } - std::string default_key_server = - key_server_list[default_key_server_index].get<std::string>(); - - target_keyserver = default_key_server; - } catch (...) { - SPDLOG_ERROR("setting operation error", "server_list", "default_server"); - QMessageBox::critical( - nullptr, _("Default Keyserver Not Found"), - _("Cannot read default keyserver from your settings, " - "please set a default keyserver first")); - return; - } + if (target_keyserver.isEmpty()) { + KeyServerSO key_server(SettingsObject("general_settings_state")); + target_keyserver = key_server.GetTargetServer(); } - std::vector<std::string> key_ids; + std::vector<QString> key_ids; for (const auto& key_id : *keys) { key_ids.push_back(key_id); } SlotImport(key_ids, target_keyserver); } -void KeyServerImportDialog::SlotImport(std::vector<std::string> key_ids, - std::string keyserver_url) { - auto* task = new KeyServerImportTask(keyserver_url, key_ids); +void KeyServerImportDialog::SlotImport(std::vector<QString> key_ids, + QString keyserver_url) { + auto* task = + new KeyServerImportTask(std::move(keyserver_url), std::move(key_ids)); connect(task, &KeyServerImportTask::SignalKeyServerImportResult, this, &KeyServerImportDialog::slot_import_finished); + set_loading(true); Thread::TaskRunnerGetter::GetInstance() .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network) ->PostTask(task); } void KeyServerImportDialog::slot_import_finished( - QNetworkReply::NetworkError error, QByteArray buffer) { - if (error != QNetworkReply::NoError) { - SPDLOG_ERROR("Error From Reply", buffer.toStdString()); - if (!m_automatic_) { - switch (error) { - case QNetworkReply::ContentNotFoundError: - set_message(_("Key Not Found"), true); - break; - case QNetworkReply::TimeoutError: - set_message(_("Timeout"), true); - break; - case QNetworkReply::HostNotFoundError: - set_message(_("Key Server Not Found"), true); - break; - default: - set_message(_("Connection Error"), true); - } - } else { - switch (error) { - case QNetworkReply::ContentNotFoundError: - QMessageBox::critical(nullptr, _("Key Not Found"), - QString(_("key not found in the Keyserver"))); - break; - case QNetworkReply::TimeoutError: - QMessageBox::critical(nullptr, _("Timeout"), "Connection timeout"); - break; - case QNetworkReply::HostNotFoundError: - QMessageBox::critical(nullptr, _("Host Not Found"), - "cannot resolve the default Keyserver"); - break; - default: - QMessageBox::critical(nullptr, _("Connection Error"), - _("General Connection Error")); - } - } - if (m_automatic_) { - setWindowFlags(Qt::Window | Qt::WindowTitleHint | - Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); - } - return; - } + bool success, QString err_msg, QByteArray buffer, + std::shared_ptr<GpgImportInformation> info) { + set_loading(false); - this->import_keys( - std::make_unique<ByteArray>(buffer.constData(), buffer.length())); - - if (!m_automatic_) { - set_message(QString("<h4>") + _("Key Imported") + "</h4>", false); + if (!success) { + GF_UI_LOG_ERROR("Error From Reply", buffer.toStdString()); + set_message(err_msg, true); + return; } -} -void KeyServerImportDialog::import_keys(ByteArrayPtr in_data) { - GpgImportInformation result = - GpgKeyImportExporter::GetInstance().ImportKey(std::move(in_data)); + set_message(tr("Key Imported"), false); // refresh the key database emit SignalKeyImported(); - QWidget* _parent = qobject_cast<QWidget*>(parent()); - if (m_automatic_) { - auto dialog = new KeyImportDetailDialog(result, true, _parent); - dialog->show(); - this->accept(); - } else { - auto dialog = new KeyImportDetailDialog(result, false, this); - dialog->exec(); - } + // show details + (new KeyImportDetailDialog(std::move(info), this))->exec(); } void KeyServerImportDialog::set_loading(bool status) { waiting_bar_->setVisible(status); - if (!m_automatic_) { - icon_->setVisible(!status); - message_->setVisible(!status); - } + if (status) set_message(tr("Processing ..."), false); } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.h b/src/ui/dialog/import_export/KeyServerImportDialog.h index fd912bdd..6a7ddfdd 100644 --- a/src/ui/dialog/import_export/KeyServerImportDialog.h +++ b/src/ui/dialog/import_export/KeyServerImportDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,22 +20,19 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEY_SERVER_IMPORT_DIALOG_H__ -#define __KEY_SERVER_IMPORT_DIALOG_H__ +#pragma once -#include <string> +#include <QtNetwork> #include "KeyImportDetailDialog.h" -#include "core/GpgContext.h" -#include "ui/GpgFrontendUI.h" +#include "core/typedef/CoreTypedef.h" #include "ui/dialog/GeneralDialog.h" -#include "ui/widgets/KeyList.h" namespace GpgFrontend::UI { @@ -53,13 +50,6 @@ class KeyServerImportDialog : public GeneralDialog { * @param automatic * @param parent */ - KeyServerImportDialog(bool automatic, QWidget* parent); - - /** - * @brief Construct a new Key Server Import Dialog object - * - * @param parent - */ explicit KeyServerImportDialog(QWidget* parent); public slots: @@ -77,8 +67,7 @@ class KeyServerImportDialog : public GeneralDialog { * @param keyIds * @param keyserverUrl */ - void SlotImport(std::vector<std::string> key_ids_list, - std::string keyserver_url); + void SlotImport(std::vector<QString> key_ids_list, QString keyserver_url); signals: @@ -108,8 +97,8 @@ class KeyServerImportDialog : public GeneralDialog { * * @param keyid */ - void slot_import_finished(QNetworkReply::NetworkError error, - QByteArray buffer); + void slot_import_finished(bool success, QString err_msg, QByteArray buffer, + std::shared_ptr<GpgImportInformation> info); /** * @brief @@ -160,9 +149,9 @@ class KeyServerImportDialog : public GeneralDialog { * * @return QComboBox* */ - QComboBox* create_comboBox(); + QComboBox* create_combo_box(); - bool m_automatic_ = false; ///< + QHBoxLayout* message_layout_; ///< QLineEdit* search_line_edit_{}; ///< QComboBox* key_server_combo_box_{}; ///< @@ -178,5 +167,3 @@ class KeyServerImportDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __KEY_SERVER_IMPORT_DIALOG_H__ diff --git a/src/ui/dialog/import_export/KeyUploadDialog.cpp b/src/ui/dialog/import_export/KeyUploadDialog.cpp index 5e05da2d..903b2e14 100644 --- a/src/ui/dialog/import_export/KeyUploadDialog.cpp +++ b/src/ui/dialog/import_export/KeyUploadDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,12 +28,15 @@ #include "KeyUploadDialog.h" -#include <algorithm> +#include <QtNetwork> -#include "core/function/GlobalSettingStation.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/utils/GpgUtils.h" +#include "ui/UserInterfaceUtils.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/KeyServerSO.h" namespace GpgFrontend::UI { @@ -53,77 +56,72 @@ KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, this->setLayout(layout); this->setModal(true); - this->setWindowTitle(_("Uploading Public Key")); + this->setWindowTitle(tr("Uploading Public Key")); this->setFixedSize(240, 42); - this->setPosCenterOfScreen(); + this->movePosition2CenterOfParent(); + this->setAttribute(Qt::WA_DeleteOnClose); } void KeyUploadDialog::SlotUpload() { - auto out_data = std::make_unique<ByteArray>(); - GpgKeyImportExporter::GetInstance().ExportKeys(*m_keys_, out_data); - slot_upload_key_to_server(*out_data); - - // Done - this->hide(); - this->close(); + GpgKeyImportExporter::GetInstance().ExportKeys( + *m_keys_, false, true, false, false, + [=](GpgError err, const DataObjectPtr& data_obj) { + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GFBuffer>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + // Done + this->hide(); + this->close(); + return; + } + + auto gf_buffer = ExtractParams<GFBuffer>(data_obj, 0); + slot_upload_key_to_server(gf_buffer); + + // Done + this->hide(); + this->close(); + }); } void KeyUploadDialog::slot_upload_key_to_server( - const GpgFrontend::ByteArray& keys_data) { - std::string target_keyserver; - - try { - SettingsObject key_server_json("key_server"); - - const auto key_server_list = - key_server_json.Check("server_list", nlohmann::json::array()); - - int default_key_server_index = key_server_json.Check("default_server", 0); - if (default_key_server_index >= key_server_list.size()) { - throw std::runtime_error("default_server index out of range"); - } - - target_keyserver = - key_server_list[default_key_server_index].get<std::string>(); + const GpgFrontend::GFBuffer& keys_data) { + KeyServerSO key_server(SettingsObject("general_settings_state")); + auto target_keyserver = key_server.GetTargetServer(); - SPDLOG_DEBUG("set target key server to default key server: {}", - target_keyserver); - - } catch (...) { - SPDLOG_ERROR(_("Cannot read default_keyserver From Settings")); - QMessageBox::critical(nullptr, _("Default Keyserver Not Found"), - _("Cannot read default keyserver from your settings, " - "please set a default keyserver first")); - return; - } - - QUrl req_url(QString::fromStdString(target_keyserver + "/pks/add")); - auto qnam = new QNetworkAccessManager(this); + QUrl req_url(target_keyserver + "/pks/add"); + auto* qnam = new QNetworkAccessManager(this); // Building Post Data - QByteArray postData; + QByteArray post_data; - auto data = std::string(keys_data); + auto data = keys_data.ConvertToQByteArray(); - boost::algorithm::replace_all(data, "\n", "%0A"); - boost::algorithm::replace_all(data, "\r", "%0D"); - boost::algorithm::replace_all(data, "(", "%28"); - boost::algorithm::replace_all(data, ")", "%29"); - boost::algorithm::replace_all(data, "/", "%2F"); - boost::algorithm::replace_all(data, ":", "%3A"); - boost::algorithm::replace_all(data, "+", "%2B"); - boost::algorithm::replace_all(data, "=", "%3D"); - boost::algorithm::replace_all(data, " ", "+"); + data.replace("\n", "%0A"); + data.replace("\r", "%0D"); + data.replace("(", "%28"); + data.replace(")", "%29"); + data.replace("/", "%2F"); + data.replace(":", "%3A"); + data.replace("+", "%2B"); + data.replace("=", "%3D"); + data.replace(" ", "+"); QNetworkRequest request(req_url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - postData.append("keytext").append("=").append( - QString::fromStdString(data).toUtf8()); + post_data.append("keytext").append("=").append(data); // Send Post Data - QNetworkReply* reply = qnam->post(request, postData); + QNetworkReply* reply = qnam->post(request, post_data); connect(reply, &QNetworkReply::finished, this, &KeyUploadDialog::slot_upload_finished); @@ -136,34 +134,33 @@ void KeyUploadDialog::slot_upload_key_to_server( void KeyUploadDialog::slot_upload_finished() { auto* reply = qobject_cast<QNetworkReply*>(sender()); + this->close(); QByteArray response = reply->readAll(); - SPDLOG_DEBUG("response: {}", response.toStdString()); + GF_UI_LOG_DEBUG("response: {}", response.toStdString()); auto error = reply->error(); if (error != QNetworkReply::NoError) { - SPDLOG_DEBUG("error from reply: {}", reply->errorString().toStdString()); + GF_UI_LOG_DEBUG("error from reply: {}", reply->errorString().toStdString()); QString message; switch (error) { case QNetworkReply::ContentNotFoundError: - message = _("Key Not Found"); + message = tr("Key Not Found"); break; case QNetworkReply::TimeoutError: - message = _("Timeout"); + message = tr("Timeout"); break; case QNetworkReply::HostNotFoundError: - message = _("Key Server Not Found"); + message = tr("Key Server Not Found"); break; default: - message = _("Connection Error"); + message = tr("Connection Error"); } - QMessageBox::critical(this, "Upload Failed", message); + QMessageBox::critical(this->parentWidget(), tr("Upload Failed"), message); return; - } else { - QMessageBox::information(this, _("Upload Success"), - _("Upload Public Key Successfully")); - SPDLOG_DEBUG("success while contacting keyserver!"); } - reply->deleteLater(); + + QMessageBox::information(this->parentWidget(), tr("Upload Success"), + tr("Upload Public Key Successfully")); } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/import_export/KeyUploadDialog.h b/src/ui/dialog/import_export/KeyUploadDialog.h index d621f33a..042989e5 100644 --- a/src/ui/dialog/import_export/KeyUploadDialog.h +++ b/src/ui/dialog/import_export/KeyUploadDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYUPLOADWIDGET_H -#define GPGFRONTEND_KEYUPLOADWIDGET_H +#pragma once -#include "core/GpgContext.h" +#include "core/model/GFBuffer.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -65,7 +65,7 @@ class KeyUploadDialog : public GeneralDialog { * * @param keys_data */ - void slot_upload_key_to_server(const GpgFrontend::ByteArray& keys_data); + void slot_upload_key_to_server(const GFBuffer&); /** * @brief @@ -79,5 +79,3 @@ class KeyUploadDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYUPLOADWIDGET_H diff --git a/src/ui/dialog/key_generate/KeygenDialog.cpp b/src/ui/dialog/key_generate/KeygenDialog.cpp index 02e0d1c8..0f6c19d8 100644 --- a/src/ui/dialog/key_generate/KeygenDialog.cpp +++ b/src/ui/dialog/key_generate/KeygenDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,13 +28,15 @@ #include "KeygenDialog.h" -#include <qobject.h> - -#include "core/common/CoreCommonUtil.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "dialog/WaitingDialog.h" -#include "ui/SignalStation.h" +#include "core/model/DataObject.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/CacheUtils.h" +#include "core/utils/GpgUtils.h" +#include "ui/UISignalStation.h" +#include "ui/UserInterfaceUtils.h" namespace GpgFrontend::UI { @@ -43,64 +45,62 @@ KeyGenDialog::KeyGenDialog(QWidget* parent) button_box_ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - bool longer_expiration_date = - GlobalSettingStation::GetInstance().LookupSettings( - "general.longer_expiration_date", false); - - bool use_pinentry_as_password_input_dialog = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_pinentry_as_password_input_dialog", false); - - use_pinentry_ = use_pinentry_as_password_input_dialog; + bool const longer_expiration_date = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/longer_expiration_date", false) + .toBool(); max_date_time_ = longer_expiration_date ? QDateTime::currentDateTime().toLocalTime().addYears(30) : QDateTime::currentDateTime().toLocalTime().addYears(2); - this->setWindowTitle(_("Generate Key")); - this->setModal(true); - - connect(this, &KeyGenDialog::SignalKeyGenerated, SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + connect(this, &KeyGenDialog::SignalKeyGenerated, + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); generate_key_dialog(); + + this->setWindowTitle(tr("Generate Key")); + this->setAttribute(Qt::WA_DeleteOnClose); + this->setModal(true); } void KeyGenDialog::generate_key_dialog() { key_usage_group_box_ = create_key_usage_group_box(); - auto* groupGrid = new QGridLayout(this); - groupGrid->addWidget(create_basic_info_group_box(), 0, 0); - groupGrid->addWidget(key_usage_group_box_, 1, 0); + auto* group_grid = new QGridLayout(this); + group_grid->addWidget(create_basic_info_group_box(), 0, 0); + group_grid->addWidget(key_usage_group_box_, 1, 0); - auto* nameList = new QWidget(this); - nameList->setLayout(groupGrid); + auto* name_list = new QWidget(this); + name_list->setLayout(group_grid); auto* vbox2 = new QVBoxLayout(); - vbox2->addWidget(nameList); + vbox2->addWidget(name_list); vbox2->addWidget(error_label_); vbox2->addWidget(button_box_); this->setLayout(vbox2); set_signal_slot(); - refresh_widgets_state(); } void KeyGenDialog::slot_key_gen_accept() { - std::stringstream error_stream; + QString buffer; + QTextStream error_stream(&buffer); /** * check for errors in keygen dialog input */ if ((name_edit_->text()).size() < 5) { - error_stream << " " << _("Name must contain at least five characters.") - << std::endl; + error_stream << " " << tr("Name must contain at least five characters.") + << '\n'; } if (email_edit_->text().isEmpty() || !check_email_address(email_edit_->text())) { - error_stream << " " << _("Please give a email address.") << std::endl; + error_stream << " " << tr("Please give a email address.") << '\n'; } /** @@ -108,81 +108,71 @@ void KeyGenDialog::slot_key_gen_accept() { * in the future) */ if (date_edit_->dateTime() > max_date_time_) { - error_stream << " " << _("Expiration time too long.") << std::endl; - } - - if (!use_pinentry_ && passphrase_edit_->isEnabled() && - passphrase_edit_->text().size() == 0) { - error_stream << " " << _("Password is empty.") << std::endl; + error_stream << " " << tr("Expiration time too long.") << '\n'; } - auto err_string = error_stream.str(); - - if (err_string.empty()) { + auto err_string = error_stream.readAll(); + if (err_string.isEmpty()) { /** * create the string for key generation */ - gen_key_info_->SetName(name_edit_->text().toStdString()); - gen_key_info_->SetEmail(email_edit_->text().toStdString()); - gen_key_info_->SetComment(comment_edit_->text().toStdString()); + gen_key_info_->SetName(name_edit_->text()); + gen_key_info_->SetEmail(email_edit_->text()); + gen_key_info_->SetComment(comment_edit_->text()); gen_key_info_->SetKeyLength(key_size_spin_box_->value()); - if (expire_check_box_->checkState()) { - gen_key_info_->SetNonExpired(true); - } else { -#ifdef GPGFRONTEND_GUI_QT6 - gen_key_info_->SetExpireTime(boost::posix_time::from_time_t( - date_edit_->dateTime().toSecsSinceEpoch())); -#else - gen_key_info_->SetExpireTime( - boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t())); -#endif - } - - if (!use_pinentry_ && !gen_key_info_->IsNoPassPhrase()) { - CoreCommonUtil::GetInstance()->SetTempCacheValue( - "__key_passphrase", this->passphrase_edit_->text().toStdString()); + if (no_pass_phrase_check_box_->checkState() != 0U) { + gen_key_info_->SetNonPassPhrase(true); + if (gen_subkey_info_ != nullptr) { + gen_subkey_info_->SetNonPassPhrase(true); + } } - GpgGenKeyResult result; - gpgme_error_t error = false; - auto thread = QThread::create([&]() { - error = GpgKeyOpera::GetInstance().GenerateKey(gen_key_info_, result); - }); - thread->start(); - - auto* dialog = new WaitingDialog(_("Generating"), this); - dialog->show(); - - while (thread->isRunning()) { - QCoreApplication::processEvents(); + if (expire_check_box_->checkState() != 0U) { + gen_key_info_->SetNonExpired(true); + if (gen_subkey_info_ != nullptr) gen_subkey_info_->SetNonExpired(true); + } else { + gen_key_info_->SetExpireTime(date_edit_->dateTime()); + if (gen_subkey_info_ != nullptr) { + gen_subkey_info_->SetExpireTime(date_edit_->dateTime()); + } } - dialog->close(); - - if (!use_pinentry_ && !gen_key_info_->IsNoPassPhrase()) { - CoreCommonUtil::GetInstance()->ResetTempCacheValue("__key_passphrase"); + if (!GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/use_pinentry_as_password_input_dialog", false) + .toBool() && + !no_pass_phrase_check_box_->isChecked()) { + SetCacheValue("PinentryContext", "NEW_PASSPHRASE"); } - SPDLOG_DEBUG("generate done"); - - if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { - auto* msg_box = new QMessageBox(qobject_cast<QWidget*>(this->parent())); - msg_box->setAttribute(Qt::WA_DeleteOnClose); - msg_box->setStandardButtons(QMessageBox::Ok); - msg_box->setWindowTitle(_("Success")); - msg_box->setText(_("The new key pair has been generated.")); - msg_box->setModal(true); - msg_box->open(); - - SPDLOG_DEBUG("generate success"); - - emit SignalKeyGenerated(); - this->close(); - } else { - QMessageBox::critical(this, _("Failure"), _("Key generation failed.")); - } + CommonUtils::WaitForOpera( + this, tr("Generating"), + [this, gen_key_info = this->gen_key_info_](const OperaWaitingHd& hd) { + GpgKeyOpera::GetInstance().GenerateKeyWithSubkey( + gen_key_info, gen_subkey_info_, + [this, hd](GpgError err, const DataObjectPtr&) { + // stop showing waiting dialog + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + CommonUtils::RaiseMessageBox(this->parentWidget() != nullptr + ? this->parentWidget() + : this, + err); + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + emit SignalKeyGenerated(); + } + }); + }); + + this->done(0); } else { /** @@ -192,36 +182,30 @@ void KeyGenDialog::slot_key_gen_accept() { QPalette error = error_label_->palette(); error.setColor(QPalette::Window, "#ff8080"); error_label_->setPalette(error); - error_label_->setText(err_string.c_str()); + error_label_->setText(err_string); this->show(); } } -void KeyGenDialog::slot_expire_box_changed() { - if (expire_check_box_->checkState()) { - date_edit_->setEnabled(false); - } else { - date_edit_->setEnabled(true); - } -} +void KeyGenDialog::slot_expire_box_changed() {} QGroupBox* KeyGenDialog::create_key_usage_group_box() { - auto* groupBox = new QGroupBox(this); + auto* group_box = new QGroupBox(this); auto* grid = new QGridLayout(this); - groupBox->setTitle(_("Key Usage")); + group_box->setTitle(tr("Key Usage")); - auto* encrypt = new QCheckBox(_("Encryption"), groupBox); + auto* encrypt = new QCheckBox(tr("Encryption"), group_box); encrypt->setTristate(false); - auto* sign = new QCheckBox(_("Signing"), groupBox); + auto* sign = new QCheckBox(tr("Signing"), group_box); sign->setTristate(false); - auto* cert = new QCheckBox(_("Certification"), groupBox); + auto* cert = new QCheckBox(tr("Certification"), group_box); cert->setTristate(false); - auto* auth = new QCheckBox(_("Authentication"), groupBox); + auto* auth = new QCheckBox(tr("Authentication"), group_box); auth->setTristate(false); key_usage_check_boxes_.push_back(encrypt); @@ -234,9 +218,9 @@ QGroupBox* KeyGenDialog::create_key_usage_group_box() { grid->addWidget(cert, 1, 0); grid->addWidget(auth, 1, 1); - groupBox->setLayout(grid); + group_box->setLayout(grid); - return groupBox; + return group_box; } void KeyGenDialog::slot_encryption_box_changed(int state) { @@ -272,64 +256,100 @@ void KeyGenDialog::slot_authentication_box_changed(int state) { } void KeyGenDialog::slot_activated_key_type(int index) { - SPDLOG_DEBUG("key type index changed: {}", index); + GF_UI_LOG_DEBUG("key type index changed: {}", index); // check - assert(gen_key_info_->GetSupportedKeyAlgo().size() > index); - gen_key_info_->SetAlgo(gen_key_info_->GetSupportedKeyAlgo()[index]); + assert(gen_key_info_->GetSupportedKeyAlgo().size() > + static_cast<size_t>(index)); + + const auto [name, key_algo, subkey_algo] = + gen_key_info_->GetSupportedKeyAlgo()[index]; + GF_UI_LOG_DEBUG("target key algo changed, name: {}, key: {}, subkey: {}", + name, key_algo, subkey_algo); + + assert(!key_algo.isEmpty()); + gen_key_info_->SetAlgo(key_algo); + + if (!subkey_algo.isEmpty()) { + if (gen_subkey_info_ == nullptr) { + gen_subkey_info_ = SecureCreateSharedObject<GenKeyInfo>(true); + } + gen_subkey_info_->SetAlgo(subkey_algo); + } else { + gen_subkey_info_ = nullptr; + } + refresh_widgets_state(); } void KeyGenDialog::refresh_widgets_state() { - if (gen_key_info_->IsAllowEncryption()) + if (gen_key_info_->IsAllowEncryption()) { key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeEncryption()) + if (gen_key_info_->IsAllowChangeEncryption()) { key_usage_check_boxes_[0]->setDisabled(false); - else + } else { key_usage_check_boxes_[0]->setDisabled(true); + } - if (gen_key_info_->IsAllowSigning()) + if (gen_key_info_->IsAllowSigning()) { key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeSigning()) + if (gen_key_info_->IsAllowChangeSigning()) { key_usage_check_boxes_[1]->setDisabled(false); - else + } else { key_usage_check_boxes_[1]->setDisabled(true); + } - if (gen_key_info_->IsAllowCertification()) + if (gen_key_info_->IsAllowCertification()) { key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeCertification()) + if (gen_key_info_->IsAllowChangeCertification()) { key_usage_check_boxes_[2]->setDisabled(false); - else + } else { key_usage_check_boxes_[2]->setDisabled(true); + } - if (gen_key_info_->IsAllowAuthentication()) + if (gen_key_info_->IsAllowAuthentication()) { key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeAuthentication()) + if (gen_key_info_->IsAllowChangeAuthentication()) { key_usage_check_boxes_[3]->setDisabled(false); - else + } else { key_usage_check_boxes_[3]->setDisabled(true); + } - if (gen_key_info_->IsAllowNoPassPhrase()) + if (gen_key_info_->IsAllowNoPassPhrase()) { no_pass_phrase_check_box_->setDisabled(false); - else + } else { no_pass_phrase_check_box_->setDisabled(true); + } - key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(), - gen_key_info_->GetSuggestMaxKeySize()); - key_size_spin_box_->setValue(gen_key_info_->GetKeyLength()); - key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep()); + if (gen_key_info_->GetSuggestMinKeySize() == -1 || + gen_key_info_->GetSuggestMaxKeySize() == -1) { + key_size_spin_box_->setDisabled(true); + key_size_spin_box_->setRange(0, 0); + key_size_spin_box_->setValue(0); + key_size_spin_box_->setSingleStep(0); + } else { + key_size_spin_box_->setDisabled(false); + key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(), + gen_key_info_->GetSuggestMaxKeySize()); + key_size_spin_box_->setValue(gen_key_info_->GetKeyLength()); + key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep()); + } } void KeyGenDialog::set_signal_slot() { @@ -338,8 +358,9 @@ void KeyGenDialog::set_signal_slot() { connect(button_box_, &QDialogButtonBox::rejected, this, &KeyGenDialog::reject); - connect(expire_check_box_, &QCheckBox::stateChanged, this, - &KeyGenDialog::slot_expire_box_changed); + connect(expire_check_box_, &QCheckBox::stateChanged, this, [this]() { + date_edit_->setDisabled(expire_check_box_->checkState() != 0U); + }); connect(key_usage_check_boxes_[0], &QCheckBox::stateChanged, this, &KeyGenDialog::slot_encryption_box_changed); @@ -356,7 +377,9 @@ void KeyGenDialog::set_signal_slot() { connect(no_pass_phrase_check_box_, &QCheckBox::stateChanged, this, [this](int state) -> void { gen_key_info_->SetNonPassPhrase(state != 0); - passphrase_edit_->setDisabled(state != 0); + if (gen_subkey_info_ != nullptr) { + gen_subkey_info_->SetNonPassPhrase(state != 0); + } }); } @@ -371,10 +394,9 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { comment_edit_ = new QLineEdit(this); key_size_spin_box_ = new QSpinBox(this); key_type_combo_box_ = new QComboBox(this); - passphrase_edit_ = new QLineEdit(this); - for (auto& algo : GenKeyInfo::GetSupportedKeyAlgo()) { - key_type_combo_box_->addItem(QString::fromStdString(algo.first)); + for (const auto& algo : GenKeyInfo::GetSupportedKeyAlgo()) { + key_type_combo_box_->addItem(std::get<0>(algo)); } if (!GenKeyInfo::GetSupportedKeyAlgo().empty()) { key_type_combo_box_->setCurrentIndex(0); @@ -391,24 +413,19 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { expire_check_box_ = new QCheckBox(this); expire_check_box_->setCheckState(Qt::Unchecked); - passphrase_edit_->setEchoMode(QLineEdit::Password); - passphrase_edit_->setHidden(use_pinentry_); - no_pass_phrase_check_box_ = new QCheckBox(this); no_pass_phrase_check_box_->setCheckState(Qt::Unchecked); auto* vbox1 = new QGridLayout; - vbox1->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0); - vbox1->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0); - vbox1->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0); - vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 3, 0); - vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 3, 3); - vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 4, 0); - vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 5, 0); - if (!use_pinentry_) - vbox1->addWidget(new QLabel(QString(_("Password")) + ": "), 6, 0); - vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase"))), 6, 3); + vbox1->addWidget(new QLabel(tr("Name") + ": "), 0, 0); + vbox1->addWidget(new QLabel(tr("Email Address") + ": "), 1, 0); + vbox1->addWidget(new QLabel(tr("Comment") + ": "), 2, 0); + vbox1->addWidget(new QLabel(tr("Expiration Date") + ": "), 3, 0); + vbox1->addWidget(new QLabel(tr("Never Expire") + ": "), 3, 3); + vbox1->addWidget(new QLabel(tr("KeySize (in Bit)") + ": "), 4, 0); + vbox1->addWidget(new QLabel(tr("Key Type") + ": "), 5, 0); + vbox1->addWidget(new QLabel(tr("Non Pass Phrase")), 6, 0); vbox1->addWidget(name_edit_, 0, 1, 1, 3); vbox1->addWidget(email_edit_, 1, 1, 1, 3); @@ -417,14 +434,13 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { vbox1->addWidget(expire_check_box_, 3, 2); vbox1->addWidget(key_size_spin_box_, 4, 1); vbox1->addWidget(key_type_combo_box_, 5, 1); - if (!use_pinentry_) vbox1->addWidget(passphrase_edit_, 6, 1); - vbox1->addWidget(no_pass_phrase_check_box_, 6, 2); + vbox1->addWidget(no_pass_phrase_check_box_, 6, 1); - auto basicInfoGroupBox = new QGroupBox(); - basicInfoGroupBox->setLayout(vbox1); - basicInfoGroupBox->setTitle(_("Basic Information")); + auto* basic_info_group_box = new QGroupBox(); + basic_info_group_box->setLayout(vbox1); + basic_info_group_box->setTitle(tr("Basic Information")); - return basicInfoGroupBox; + return basic_info_group_box; } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/key_generate/KeygenDialog.h b/src/ui/dialog/key_generate/KeygenDialog.h index 31b5f9c7..ceab3d46 100644 --- a/src/ui/dialog/key_generate/KeygenDialog.h +++ b/src/ui/dialog/key_generate/KeygenDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,16 +19,19 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEYGENDIALOG_H__ -#define __KEYGENDIALOG_H__ +#pragma once + +#include <memory> -#include "core/GpgContext.h" -#include "core/GpgGenKeyInfo.h" +#include "core/model/GpgGenKeyInfo.h" +#include "core/utils/MemoryUtils.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -86,24 +89,25 @@ class KeyGenDialog : public GeneralDialog { */ QStringList error_messages_; ///< List of errors occurring when checking ///< entries of line edits - std::unique_ptr<GenKeyInfo> gen_key_info_ = - std::make_unique<GenKeyInfo>(); ///< - QDialogButtonBox* button_box_; ///< Box for standard buttons - QLabel* error_label_{}; ///< Label containing error message - QLineEdit* name_edit_{}; ///< Line edit for the keys name - QLineEdit* email_edit_{}; ///< Line edit for the keys email - QLineEdit* comment_edit_{}; ///< Line edit for the keys comment - QLineEdit* passphrase_edit_{}; ///< - QSpinBox* key_size_spin_box_{}; ///< Spinbox for the keys size (in bit) - QComboBox* key_type_combo_box_{}; ///< Combobox for Key type - QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date - QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire + + std::shared_ptr<GenKeyInfo> gen_key_info_ = + SecureCreateSharedObject<GenKeyInfo>(); ///< + std::shared_ptr<GenKeyInfo> gen_subkey_info_ = nullptr; ///< + + QDialogButtonBox* button_box_; ///< Box for standard buttons + QLabel* error_label_{}; ///< Label containing error message + QLineEdit* name_edit_{}; ///< Line edit for the keys name + QLineEdit* email_edit_{}; ///< Line edit for the keys email + QLineEdit* comment_edit_{}; ///< Line edit for the keys comment + QSpinBox* key_size_spin_box_{}; ///< Spinbox for the keys size (in bit) + QComboBox* key_type_combo_box_{}; ///< Combobox for Key type + QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date + QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire QCheckBox* no_pass_phrase_check_box_{}; QGroupBox* key_usage_group_box_{}; ///< Group of Widgets detecting the usage ///< of the Key QDateTime max_date_time_; ///< std::vector<QCheckBox*> key_usage_check_boxes_; ///< ENCR, SIGN, CERT, AUTH - bool use_pinentry_ = false; /** * @brief @@ -182,5 +186,3 @@ class KeyGenDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __KEYGENDIALOG_H__ diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp index abf17c67..eecf2a1d 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,21 +19,25 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "SubkeyGenerateDialog.h" #include <cassert> +#include <cstddef> -#include "core/common/CoreCommonUtil.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "ui/SignalStation.h" -#include "ui/dialog/WaitingDialog.h" +#include "core/utils/CacheUtils.h" +#include "core/utils/GpgUtils.h" +#include "ui/UISignalStation.h" +#include "ui/UserInterfaceUtils.h" namespace GpgFrontend::UI { @@ -41,14 +45,10 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) : GeneralDialog(typeid(SubkeyGenerateDialog).name(), parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { bool longer_expiration_date = - GlobalSettingStation::GetInstance().LookupSettings( - "general.longer_expiration_date", false); - - bool use_pinentry_as_password_input_dialog = - GlobalSettingStation::GetInstance().LookupSettings( - "general.use_pinentry_as_password_input_dialog", false); - - use_pinentry_ = use_pinentry_as_password_input_dialog; + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/longer_expiration_date", false) + .toBool(); max_date_time_ = longer_expiration_date ? QDateTime::currentDateTime().toLocalTime().addYears(30) @@ -63,9 +63,10 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) group_grid->addWidget(create_basic_info_group_box(), 0, 0); group_grid->addWidget(key_usage_group_box_, 1, 0); - auto* tipps_label = new QLabel( - QString(_("Tipps: if the key pair has a passphrase, the subkey's " - "passphrase must be equal to it."))); + auto* tipps_label = + new QLabel(tr("Tipps: if the key pair has a passphrase, the subkey's " + "passphrase must be equal to it.")); + tipps_label->setWordWrap(true); group_grid->addWidget(tipps_label); auto* name_list = new QWidget(this); @@ -76,34 +77,31 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) vbox2->addWidget(error_label_); vbox2->addWidget(button_box_); - this->setWindowTitle(_("Generate New Subkey")); + this->setWindowTitle(tr("Generate New Subkey")); this->setLayout(vbox2); + this->setAttribute(Qt::WA_DeleteOnClose); this->setModal(true); - connect(this, &SubkeyGenerateDialog::SignalSubKeyGenerated, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); - set_signal_slot(); refresh_widgets_state(); } QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() { - auto* groupBox = new QGroupBox(this); + auto* group_box = new QGroupBox(this); auto* grid = new QGridLayout(this); - groupBox->setTitle(_("Key Usage")); + group_box->setTitle(tr("Key Usage")); - auto* encrypt = new QCheckBox(_("Encryption"), groupBox); + auto* encrypt = new QCheckBox(tr("Encryption"), group_box); encrypt->setTristate(false); - auto* sign = new QCheckBox(_("Signing"), groupBox); + auto* sign = new QCheckBox(tr("Signing"), group_box); sign->setTristate(false); - auto* cert = new QCheckBox(_("Certification"), groupBox); + auto* cert = new QCheckBox(tr("Certification"), group_box); cert->setTristate(false); - auto* auth = new QCheckBox(_("Authentication"), groupBox); + auto* auth = new QCheckBox(tr("Authentication"), group_box); auth->setTristate(false); key_usage_check_boxes_.push_back(encrypt); @@ -116,9 +114,9 @@ QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() { grid->addWidget(cert, 1, 0); grid->addWidget(auth, 1, 1); - groupBox->setLayout(grid); + group_box->setLayout(grid); - return groupBox; + return group_box; } QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { @@ -126,10 +124,9 @@ QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { key_size_spin_box_ = new QSpinBox(this); key_type_combo_box_ = new QComboBox(this); no_pass_phrase_check_box_ = new QCheckBox(this); - passphrase_edit_ = new QLineEdit(this); - for (auto& algo : GenKeyInfo::GetSupportedSubkeyAlgo()) { - key_type_combo_box_->addItem(QString::fromStdString(algo.first)); + for (const auto& algo : GenKeyInfo::GetSupportedSubkeyAlgo()) { + key_type_combo_box_->addItem(std::get<0>(algo)); } if (!GenKeyInfo::GetSupportedSubkeyAlgo().empty()) { key_type_combo_box_->setCurrentIndex(0); @@ -146,31 +143,25 @@ QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { expire_check_box_ = new QCheckBox(this); expire_check_box_->setCheckState(Qt::Unchecked); - passphrase_edit_->setEchoMode(QLineEdit::Password); - passphrase_edit_->setHidden(use_pinentry_); - auto* vbox1 = new QGridLayout; - vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 0, 0); - vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0); - vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 2, 0); - vbox1->addWidget(new QLabel(QString(_("Never Expire"))), 2, 3); - if (!use_pinentry_) - vbox1->addWidget(new QLabel(QString(_("Password")) + ": "), 3, 0); - vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase"))), 3, 3); + vbox1->addWidget(new QLabel(tr("Key Type") + ": "), 0, 0); + vbox1->addWidget(new QLabel(tr("KeySize (in Bit)") + ": "), 1, 0); + vbox1->addWidget(new QLabel(tr("Expiration Date") + ": "), 2, 0); + vbox1->addWidget(new QLabel(tr("Never Expire")), 2, 3); + vbox1->addWidget(new QLabel(tr("Non Pass Phrase")), 3, 0); vbox1->addWidget(key_type_combo_box_, 0, 1); vbox1->addWidget(key_size_spin_box_, 1, 1); vbox1->addWidget(date_edit_, 2, 1); vbox1->addWidget(expire_check_box_, 2, 2); - if (!use_pinentry_) vbox1->addWidget(passphrase_edit_, 3, 1); - vbox1->addWidget(no_pass_phrase_check_box_, 3, 2); + vbox1->addWidget(no_pass_phrase_check_box_, 3, 1); - auto basicInfoGroupBox = new QGroupBox(); - basicInfoGroupBox->setLayout(vbox1); - basicInfoGroupBox->setTitle(_("Basic Information")); + auto* basic_info_group_box = new QGroupBox(); + basic_info_group_box->setLayout(vbox1); + basic_info_group_box->setTitle(tr("Basic Information")); - return basicInfoGroupBox; + return basic_info_group_box; } void SubkeyGenerateDialog::set_signal_slot() { @@ -197,12 +188,11 @@ void SubkeyGenerateDialog::set_signal_slot() { connect(no_pass_phrase_check_box_, &QCheckBox::stateChanged, this, [this](int state) -> void { gen_key_info_->SetNonPassPhrase(state != 0); - passphrase_edit_->setDisabled(state != 0); }); } void SubkeyGenerateDialog::slot_expire_box_changed() { - if (expire_check_box_->checkState()) { + if (expire_check_box_->checkState() != 0U) { date_edit_->setEnabled(false); } else { date_edit_->setEnabled(true); @@ -210,124 +200,116 @@ void SubkeyGenerateDialog::slot_expire_box_changed() { } void SubkeyGenerateDialog::refresh_widgets_state() { - if (gen_key_info_->IsAllowEncryption()) + if (gen_key_info_->IsAllowEncryption()) { key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeEncryption()) + if (gen_key_info_->IsAllowChangeEncryption()) { key_usage_check_boxes_[0]->setDisabled(false); - else + } else { key_usage_check_boxes_[0]->setDisabled(true); + } - if (gen_key_info_->IsAllowSigning()) + if (gen_key_info_->IsAllowSigning()) { key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeSigning()) + if (gen_key_info_->IsAllowChangeSigning()) { key_usage_check_boxes_[1]->setDisabled(false); - else + } else { key_usage_check_boxes_[1]->setDisabled(true); + } - if (gen_key_info_->IsAllowCertification()) + if (gen_key_info_->IsAllowCertification()) { key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeCertification()) + if (gen_key_info_->IsAllowChangeCertification()) { key_usage_check_boxes_[2]->setDisabled(false); - else + } else { key_usage_check_boxes_[2]->setDisabled(true); + } - if (gen_key_info_->IsAllowAuthentication()) + if (gen_key_info_->IsAllowAuthentication()) { key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked); - else + } else { key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked); + } - if (gen_key_info_->IsAllowChangeAuthentication()) + if (gen_key_info_->IsAllowChangeAuthentication()) { key_usage_check_boxes_[3]->setDisabled(false); - else + } else { key_usage_check_boxes_[3]->setDisabled(true); + } - key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(), - gen_key_info_->GetSuggestMaxKeySize()); - key_size_spin_box_->setValue(gen_key_info_->GetKeyLength()); - key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep()); + if (gen_key_info_->GetSuggestMinKeySize() == -1 || + gen_key_info_->GetSuggestMaxKeySize() == -1) { + key_size_spin_box_->setDisabled(true); + key_size_spin_box_->setRange(0, 0); + key_size_spin_box_->setValue(0); + key_size_spin_box_->setSingleStep(0); + } else { + key_size_spin_box_->setDisabled(false); + key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(), + gen_key_info_->GetSuggestMaxKeySize()); + key_size_spin_box_->setValue(gen_key_info_->GetKeyLength()); + key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep()); + } } void SubkeyGenerateDialog::slot_key_gen_accept() { - std::stringstream err_stream; + QString buffer; + QTextStream err_stream(&buffer); /** * primary keys should have a reasonable expiration date (no more than 2 years * in the future) */ if (date_edit_->dateTime() > QDateTime::currentDateTime().addYears(2)) { - err_stream << " " << _("Expiration time no more than 2 years.") << " "; + err_stream << " " << tr("Expiration time no more than 2 years.") << " "; } - if (!use_pinentry_ && passphrase_edit_->isEnabled() && - passphrase_edit_->text().size() == 0) { - err_stream << " " << _("Password is empty.") << std::endl; - } - - auto err_string = err_stream.str(); + auto err_string = err_stream.readAll(); - if (err_string.empty()) { + if (err_string.isEmpty()) { gen_key_info_->SetKeyLength(key_size_spin_box_->value()); - if (expire_check_box_->checkState()) { + if (expire_check_box_->checkState() != 0U) { gen_key_info_->SetNonExpired(true); } else { -#ifdef GPGFRONTEND_GUI_QT6 - gen_key_info_->SetExpireTime(boost::posix_time::from_time_t( - date_edit_->dateTime().toSecsSinceEpoch())); -#else - gen_key_info_->SetExpireTime( - boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t())); -#endif - } - - if (!use_pinentry_ && !gen_key_info_->IsNoPassPhrase()) { - CoreCommonUtil::GetInstance()->SetTempCacheValue( - "__key_passphrase", this->passphrase_edit_->text().toStdString()); + gen_key_info_->SetExpireTime(date_edit_->dateTime()); } - GpgError error; - // TODO: remove plain qt thread usage - auto thread = QThread::create([&]() { - SPDLOG_DEBUG("thread started"); - error = GpgKeyOpera::GetInstance().GenerateSubkey(key_, gen_key_info_); - }); - thread->start(); - - auto* waiting_dialog = new WaitingDialog(_("Generating"), this); - waiting_dialog->show(); - - while (thread->isRunning()) { - QCoreApplication::processEvents(); - } - waiting_dialog->close(); - - if (!use_pinentry_ && !gen_key_info_->IsNoPassPhrase()) { - CoreCommonUtil::GetInstance()->ResetTempCacheValue("__key_passphrase"); - } - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) { - auto* msg_box = new QMessageBox(qobject_cast<QWidget*>(this->parent())); - msg_box->setAttribute(Qt::WA_DeleteOnClose); - msg_box->setStandardButtons(QMessageBox::Ok); - msg_box->setWindowTitle(_("Success")); - msg_box->setText(_("The new subkey has been generated.")); - msg_box->setModal(true); - msg_box->open(); - - emit SignalSubKeyGenerated(); - this->close(); - } else { - QMessageBox::critical(this, _("Failure"), _("Failed to generate key.")); - } + CommonUtils::WaitForOpera( + this, tr("Generating"), + [this, key = this->key_, + gen_key_info = this->gen_key_info_](const OperaWaitingHd& hd) { + GpgKeyOpera::GetInstance().GenerateSubkey( + key, gen_key_info, + [this, hd](GpgError err, const DataObjectPtr&) { + // stop showing waiting dialog + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + CommonUtils::RaiseMessageBox(this, err); + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + emit UISignalStation::GetInstance() + ->SignalKeyDatabaseRefresh(); + } + }); + }); + this->done(0); } else { /** @@ -337,7 +319,7 @@ void SubkeyGenerateDialog::slot_key_gen_accept() { QPalette error = error_label_->palette(); error.setColor(QPalette::Window, "#ff8080"); error_label_->setPalette(error); - error_label_->setText(err_string.c_str()); + error_label_->setText(err_string); this->show(); } @@ -376,11 +358,13 @@ void SubkeyGenerateDialog::slot_authentication_box_changed(int state) { } void SubkeyGenerateDialog::slot_activated_key_type(int index) { - SPDLOG_DEBUG("key type index changed: {}", index); + GF_UI_LOG_DEBUG("key type index changed: {}", index); // check - assert(gen_key_info_->GetSupportedSubkeyAlgo().size() > index); - gen_key_info_->SetAlgo(gen_key_info_->GetSupportedSubkeyAlgo()[index]); + assert(gen_key_info_->GetSupportedSubkeyAlgo().size() > + static_cast<size_t>(index)); + gen_key_info_->SetAlgo( + std::get<2>(gen_key_info_->GetSupportedSubkeyAlgo()[index])); refresh_widgets_state(); } diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.h b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h index 2b88bd61..be39669c 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.h +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,16 +19,22 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SUBKEYGENERATEDIALOG_H -#define GPGFRONTEND_SUBKEYGENERATEDIALOG_H +#pragma once + +#include <memory> -#include "core/GpgContext.h" -#include "core/GpgGenKeyInfo.h" +#include "core/function/gpg/GpgContext.h" +#include "core/model/GpgGenKeyInfo.h" +#include "core/model/GpgKey.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/MemoryUtils.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -49,18 +55,11 @@ class SubkeyGenerateDialog : public GeneralDialog { */ explicit SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent); - signals: - /** - * @brief - * - */ - void SignalSubKeyGenerated(); - private: GpgKey key_; ///< - std::unique_ptr<GenKeyInfo> gen_key_info_ = - std::make_unique<GenKeyInfo>(true); ///< + std::shared_ptr<GenKeyInfo> gen_key_info_ = + SecureCreateSharedObject<GenKeyInfo>(true); ///< QGroupBox* key_usage_group_box_{}; QDialogButtonBox* button_box_; ///< Box for standard buttons @@ -70,11 +69,9 @@ class SubkeyGenerateDialog : public GeneralDialog { QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire QCheckBox* no_pass_phrase_check_box_{}; ///< Checkbox, if key should expire - QLineEdit* passphrase_edit_{}; std::vector<QCheckBox*> key_usage_check_boxes_; ///< ENCR, SIGN, CERT, AUTH QDateTime max_date_time_; ///< - bool use_pinentry_ = false; /** * @brief Create a key usage group box object @@ -151,5 +148,3 @@ class SubkeyGenerateDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SUBKEYGENERATEDIALOG_H diff --git a/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp b/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp index 9ac60a73..6908592b 100644 --- a/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp +++ b/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,32 +28,33 @@ #include "KeyDetailsDialog.h" -#include "KeyPairDetailTab.h" -#include "KeyPairOperaTab.h" -#include "KeyPairSubkeyTab.h" -#include "KeyPairUIDTab.h" +#include "core/GpgModel.h" +#include "ui/dialog/keypair_details/KeyPairDetailTab.h" +#include "ui/dialog/keypair_details/KeyPairOperaTab.h" +#include "ui/dialog/keypair_details/KeyPairSubkeyTab.h" +#include "ui/dialog/keypair_details/KeyPairUIDTab.h" namespace GpgFrontend::UI { KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent) : GeneralDialog(typeid(KeyDetailsDialog).name(), parent) { tab_widget_ = new QTabWidget(); tab_widget_->addTab(new KeyPairDetailTab(key.GetId(), tab_widget_), - _("KeyPair")); - tab_widget_->addTab(new KeyPairUIDTab(key.GetId(), tab_widget_), _("UIDs")); + tr("KeyPair")); + tab_widget_->addTab(new KeyPairUIDTab(key.GetId(), tab_widget_), tr("UIDs")); tab_widget_->addTab(new KeyPairSubkeyTab(key.GetId(), tab_widget_), - _("Subkeys")); + tr("Subkeys")); tab_widget_->addTab(new KeyPairOperaTab(key.GetId(), tab_widget_), - _("Operations")); + tr("Operations")); - auto* mainLayout = new QVBoxLayout; - mainLayout->addWidget(tab_widget_); + auto* main_layout = new QVBoxLayout; + main_layout->addWidget(tab_widget_); #ifdef MACOS setAttribute(Qt::WA_LayoutUsesWidgetRect); #endif this->setAttribute(Qt::WA_DeleteOnClose, true); - this->setLayout(mainLayout); - this->setWindowTitle(_("Key Details")); + this->setLayout(main_layout); + this->setWindowTitle(tr("Key Details")); this->setModal(true); this->show(); diff --git a/src/ui/dialog/keypair_details/KeyDetailsDialog.h b/src/ui/dialog/keypair_details/KeyDetailsDialog.h index 1ddcda00..1c72ce98 100644 --- a/src/ui/dialog/keypair_details/KeyDetailsDialog.h +++ b/src/ui/dialog/keypair_details/KeyDetailsDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEYDETAILSDIALOG_H__ -#define __KEYDETAILSDIALOG_H__ +#pragma once -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -45,5 +45,3 @@ class KeyDetailsDialog : public GeneralDialog { QTabWidget* tab_widget_{}; }; } // namespace GpgFrontend::UI - -#endif // __KEYDETAILSDIALOG_H__ diff --git a/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp index 18dd1967..cd3c0f29 100644 --- a/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp +++ b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,16 +19,19 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "KeyNewUIDDialog.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgUIDOperator.h" -#include "ui/SignalStation.h" +#include "ui/UISignalStation.h" namespace GpgFrontend::UI { KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent) @@ -44,9 +47,9 @@ KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent) error_label_ = new QLabel(); auto gridLayout = new QGridLayout(); - gridLayout->addWidget(new QLabel(_("Name")), 0, 0); - gridLayout->addWidget(new QLabel(_("Email")), 1, 0); - gridLayout->addWidget(new QLabel(_("Comment")), 2, 0); + gridLayout->addWidget(new QLabel(tr("Name")), 0, 0); + gridLayout->addWidget(new QLabel(tr("Email")), 1, 0); + gridLayout->addWidget(new QLabel(tr("Comment")), 2, 0); gridLayout->addWidget(name_, 0, 1); gridLayout->addWidget(email_, 1, 1); @@ -54,7 +57,7 @@ KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent) gridLayout->addWidget(create_button_, 3, 0, 1, 2); gridLayout->addWidget( - new QLabel(_("Notice: The New UID Created will be set as Primary.")), 4, + new QLabel(tr("Notice: The New UID Created will be set as Primary.")), 4, 0, 1, 2); gridLayout->addWidget(error_label_, 5, 0, 1, 2); @@ -62,37 +65,38 @@ KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent) &KeyNewUIDDialog::slot_create_new_uid); this->setLayout(gridLayout); - this->setWindowTitle(_("Create New UID")); + this->setWindowTitle(tr("Create New UID")); this->setAttribute(Qt::WA_DeleteOnClose, true); this->setModal(true); connect(this, &KeyNewUIDDialog::SignalUIDCreated, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); } void KeyNewUIDDialog::slot_create_new_uid() { - std::stringstream error_stream; + QString buffer; + QTextStream error_stream(&buffer); /** * check for errors in keygen dialog input */ if ((name_->text()).size() < 5) { - error_stream << " " << _("Name must contain at least five characters.") - << std::endl; + error_stream << " " << tr("Name must contain at least five characters.") + << Qt::endl; } if (email_->text().isEmpty() || !check_email_address(email_->text())) { - error_stream << " " << _("Please give a email address.") << std::endl; + error_stream << " " << tr("Please give a email address.") << Qt::endl; } - auto error_string = error_stream.str(); - if (error_string.empty()) { + auto error_string = error_stream.readAll(); + if (error_string.isEmpty()) { if (GpgUIDOperator::GetInstance().AddUID( - m_key_, name_->text().toStdString(), comment_->text().toStdString(), - email_->text().toStdString())) { + m_key_, name_->text(), comment_->text(), email_->text())) { emit finished(1); emit SignalUIDCreated(); - } else + } else { emit finished(-1); + } } else { /** @@ -102,7 +106,7 @@ void KeyNewUIDDialog::slot_create_new_uid() { QPalette error = error_label_->palette(); error.setColor(QPalette::Window, "#ff8080"); error_label_->setPalette(error); - error_label_->setText(error_string.c_str()); + error_label_->setText(error_string); this->show(); } diff --git a/src/ui/dialog/keypair_details/KeyNewUIDDialog.h b/src/ui/dialog/keypair_details/KeyNewUIDDialog.h index 291b59c4..ab1bb5e1 100644 --- a/src/ui/dialog/keypair_details/KeyNewUIDDialog.h +++ b/src/ui/dialog/keypair_details/KeyNewUIDDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,18 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYNEWUIDDIALOG_H -#define GPGFRONTEND_KEYNEWUIDDIALOG_H +#pragma once -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" +#include "core/model/GpgKey.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -84,5 +87,3 @@ class KeyNewUIDDialog : public GeneralDialog { bool check_email_address(const QString& str); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYNEWUIDDIALOG_H diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp index 578e3279..a91b5fd4 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,29 +19,28 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "KeyPairDetailTab.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" -#include "core/function/gpg/GpgKeyImportExporter.h" #include "core/model/GpgKey.h" -#include "dialog/WaitingDialog.h" -#include "ui/SignalStation.h" +#include "core/utils/CommonUtils.h" +#include "ui/UISignalStation.h" namespace GpgFrontend::UI { -KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) +KeyPairDetailTab::KeyPairDetailTab(const QString& key_id, QWidget* parent) : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { - SPDLOG_DEBUG(key_.GetEmail(), key_.IsPrivateKey(), key_.IsHasMasterKey(), - key_.GetSubKeys()->front().IsPrivateKey()); - - owner_box_ = new QGroupBox(_("Owner")); - key_box_ = new QGroupBox(_("Primary Key")); - fingerprint_box_ = new QGroupBox(_("Fingerprint")); - additional_uid_box_ = new QGroupBox(_("Additional UIDs")); + owner_box_ = new QGroupBox(tr("Owner")); + key_box_ = new QGroupBox(tr("Primary Key")); + fingerprint_box_ = new QGroupBox(tr("Fingerprint")); + additional_uid_box_ = new QGroupBox(tr("Additional UIDs")); name_var_label_ = new QLabel(); name_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); @@ -65,56 +64,52 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) primary_key_exist_var_label_ = new QLabel(); auto* mvbox = new QVBoxLayout(); - auto* vboxKD = new QGridLayout(); - auto* vboxOD = new QGridLayout(); - - vboxOD->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0); - vboxOD->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0); - vboxOD->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0); - vboxOD->addWidget(name_var_label_, 0, 1); - vboxOD->addWidget(email_var_label_, 1, 1); - vboxOD->addWidget(comment_var_label_, 2, 1); - - vboxKD->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); - vboxKD->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0); - vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); - vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0); - vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0); - vboxKD->addWidget(new QLabel(QString(_("Owner Trust Level")) + ": "), 5, 0); - vboxKD->addWidget(new QLabel(QString(_("Create Date (Local Time)")) + ": "), - 6, 0); - vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 7, - 0); - vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "), - 8, 0); - vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 9, - 0); + auto* vbox_kd = new QGridLayout(); + auto* vbox_od = new QGridLayout(); + + vbox_od->addWidget(new QLabel(tr("Name") + ": "), 0, 0); + vbox_od->addWidget(new QLabel(tr("Email Address") + ": "), 1, 0); + vbox_od->addWidget(new QLabel(tr("Comment") + ": "), 2, 0); + vbox_od->addWidget(name_var_label_, 0, 1); + vbox_od->addWidget(email_var_label_, 1, 1); + vbox_od->addWidget(comment_var_label_, 2, 1); + + vbox_kd->addWidget(new QLabel(tr("Key ID") + ": "), 0, 0); + vbox_kd->addWidget(new QLabel(tr("Algorithm") + ": "), 1, 0); + vbox_kd->addWidget(new QLabel(tr("Key Size") + ": "), 2, 0); + vbox_kd->addWidget(new QLabel(tr("Nominal Usage") + ": "), 3, 0); + vbox_kd->addWidget(new QLabel(tr("Actual Usage") + ": "), 4, 0); + vbox_kd->addWidget(new QLabel(tr("Owner Trust Level") + ": "), 5, 0); + vbox_kd->addWidget(new QLabel(tr("Create Date (Local Time)") + ": "), 6, 0); + vbox_kd->addWidget(new QLabel(tr("Expires on (Local Time)") + ": "), 7, 0); + vbox_kd->addWidget(new QLabel(tr("Last Update (Local Time)") + ": "), 8, 0); + vbox_kd->addWidget(new QLabel(tr("Primary Key Existence") + ": "), 9, 0); key_id_var_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - vboxKD->addWidget(key_id_var_label, 0, 1, 1, 1); - vboxKD->addWidget(algorithm_var_label_, 1, 1, 1, 2); - vboxKD->addWidget(key_size_var_label_, 2, 1, 1, 2); - vboxKD->addWidget(usage_var_label_, 3, 1, 1, 2); - vboxKD->addWidget(actual_usage_var_label_, 4, 1, 1, 2); - vboxKD->addWidget(owner_trust_var_label_, 5, 1, 1, 2); - vboxKD->addWidget(created_var_label_, 6, 1, 1, 2); - vboxKD->addWidget(expire_var_label_, 7, 1, 1, 2); - vboxKD->addWidget(last_update_var_label_, 8, 1, 1, 2); - vboxKD->addWidget(primary_key_exist_var_label_, 9, 1, 1, 2); - - auto* copyKeyIdButton = new QPushButton(_("Copy")); - copyKeyIdButton->setFlat(true); - copyKeyIdButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); - vboxKD->addWidget(copyKeyIdButton, 0, 2); - connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() { + vbox_kd->addWidget(key_id_var_label, 0, 1, 1, 1); + vbox_kd->addWidget(algorithm_var_label_, 1, 1, 1, 2); + vbox_kd->addWidget(key_size_var_label_, 2, 1, 1, 2); + vbox_kd->addWidget(usage_var_label_, 3, 1, 1, 2); + vbox_kd->addWidget(actual_usage_var_label_, 4, 1, 1, 2); + vbox_kd->addWidget(owner_trust_var_label_, 5, 1, 1, 2); + vbox_kd->addWidget(created_var_label_, 6, 1, 1, 2); + vbox_kd->addWidget(expire_var_label_, 7, 1, 1, 2); + vbox_kd->addWidget(last_update_var_label_, 8, 1, 1, 2); + vbox_kd->addWidget(primary_key_exist_var_label_, 9, 1, 1, 2); + + auto* copy_key_id_button = new QPushButton(tr("Copy")); + copy_key_id_button->setFlat(true); + copy_key_id_button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + vbox_kd->addWidget(copy_key_id_button, 0, 2); + connect(copy_key_id_button, &QPushButton::clicked, this, [=]() { QString fpr = key_id_var_label->text().trimmed(); QClipboard* cb = QApplication::clipboard(); cb->setText(fpr); }); - owner_box_->setLayout(vboxOD); + owner_box_->setLayout(vbox_od); mvbox->addWidget(owner_box_); - key_box_->setLayout(vboxKD); + key_box_->setLayout(vbox_kd); mvbox->addWidget(key_box_); fingerprint_var_label_ = new QLabel(); @@ -122,26 +117,26 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) fingerprint_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); fingerprint_var_label_->setStyleSheet("margin-left: 0; margin-right: 5;"); fingerprint_var_label_->setAlignment(Qt::AlignCenter); - auto* hboxFP = new QHBoxLayout(); + auto* hbox_fp = new QHBoxLayout(); - hboxFP->addStretch(); - hboxFP->addWidget(fingerprint_var_label_); + hbox_fp->addStretch(); + hbox_fp->addWidget(fingerprint_var_label_); - auto* copyFingerprintButton = new QPushButton(_("Copy")); - copyFingerprintButton->setFlat(true); - copyFingerprintButton->setToolTip(_("copy fingerprint to clipboard")); - connect(copyFingerprintButton, &QPushButton::clicked, this, + auto* copy_fingerprint_button = new QPushButton(tr("Copy")); + copy_fingerprint_button->setFlat(true); + copy_fingerprint_button->setToolTip(tr("copy fingerprint to clipboard")); + connect(copy_fingerprint_button, &QPushButton::clicked, this, &KeyPairDetailTab::slot_copy_fingerprint); - hboxFP->addWidget(copyFingerprintButton); - hboxFP->addStretch(); + hbox_fp->addWidget(copy_fingerprint_button); + hbox_fp->addStretch(); - fingerprint_box_->setLayout(hboxFP); + fingerprint_box_->setLayout(hbox_fp); mvbox->addWidget(fingerprint_box_); mvbox->addStretch(); auto* expBox = new QHBoxLayout(); - QPixmap pixmap(":warning.png"); + QPixmap pixmap(":/icons/warning.png"); exp_label_ = new QLabel(); icon_label_ = new QLabel(); @@ -156,8 +151,8 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) mvbox->setContentsMargins(0, 0, 0, 0); // when key database updated - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, &KeyPairDetailTab::slot_refresh_key); slot_refresh_key_info(); @@ -175,7 +170,7 @@ void KeyPairDetailTab::slot_copy_fingerprint() { void KeyPairDetailTab::slot_refresh_key_info() { // Show the situation that primary key not exists. primary_key_exist_var_label_->setText( - key_.IsHasMasterKey() ? _("Exists") : _("Not Exists")); + key_.IsHasMasterKey() ? tr("Exists") : tr("Not Exists")); if (!key_.IsHasMasterKey()) { auto palette_expired = primary_key_exist_var_label_->palette(); palette_expired.setColor(primary_key_exist_var_label_->foregroundRole(), @@ -189,89 +184,81 @@ void KeyPairDetailTab::slot_refresh_key_info() { } if (key_.IsExpired()) { - auto paletteExpired = expire_var_label_->palette(); - paletteExpired.setColor(expire_var_label_->foregroundRole(), Qt::red); - expire_var_label_->setPalette(paletteExpired); + auto palette_expired = expire_var_label_->palette(); + palette_expired.setColor(expire_var_label_->foregroundRole(), Qt::red); + expire_var_label_->setPalette(palette_expired); } else { - auto paletteValid = expire_var_label_->palette(); - paletteValid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen); - expire_var_label_->setPalette(paletteValid); + auto palette_valid = expire_var_label_->palette(); + palette_valid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen); + expire_var_label_->setPalette(palette_valid); } - name_var_label_->setText(QString::fromStdString(key_.GetName())); - email_var_label_->setText(QString::fromStdString(key_.GetEmail())); + name_var_label_->setText(key_.GetName()); + email_var_label_->setText(key_.GetEmail()); - comment_var_label_->setText(QString::fromStdString(key_.GetComment())); - key_id_var_label->setText(QString::fromStdString(key_.GetId())); + comment_var_label_->setText(key_.GetComment()); + key_id_var_label->setText(key_.GetId()); - std::stringstream usage_steam; + QString buffer; + QTextStream usage_steam(&buffer); - if (key_.IsHasCertificationCapability()) - usage_steam << _("Certificate") << " "; - if (key_.IsHasEncryptionCapability()) usage_steam << _("Encrypt") << " "; - if (key_.IsHasSigningCapability()) usage_steam << _("Sign") << " "; - if (key_.IsHasAuthenticationCapability()) usage_steam << _("Auth") << " "; + if (key_.IsHasCertificationCapability()) { + usage_steam << tr("Certificate") << " "; + } + if (key_.IsHasEncryptionCapability()) usage_steam << tr("Encrypt") << " "; + if (key_.IsHasSigningCapability()) usage_steam << tr("Sign") << " "; + if (key_.IsHasAuthenticationCapability()) usage_steam << tr("Auth") << " "; - usage_var_label_->setText(usage_steam.str().c_str()); + usage_var_label_->setText(usage_steam.readAll()); - std::stringstream actual_usage_steam; + QString buffer_2; + QTextStream actual_usage_steam(&buffer_2); - if (key_.IsHasActualCertificationCapability()) - actual_usage_steam << _("Certificate") << " "; - if (key_.IsHasActualEncryptionCapability()) - actual_usage_steam << _("Encrypt") << " "; - if (key_.IsHasActualSigningCapability()) - actual_usage_steam << _("Sign") << " "; - if (key_.IsHasActualAuthenticationCapability()) - actual_usage_steam << _("Auth") << " "; + if (key_.IsHasActualCertificationCapability()) { + actual_usage_steam << tr("Certificate") << " "; + } + if (key_.IsHasActualEncryptionCapability()) { + actual_usage_steam << tr("Encrypt") << " "; + } + if (key_.IsHasActualSigningCapability()) { + actual_usage_steam << tr("Sign") << " "; + } + if (key_.IsHasActualAuthenticationCapability()) { + actual_usage_steam << tr("Auth") << " "; + } - actual_usage_var_label_->setText( - QString::fromStdString(actual_usage_steam.str())); - owner_trust_var_label_->setText(QString::fromStdString(key_.GetOwnerTrust())); + actual_usage_var_label_->setText(actual_usage_steam.readAll()); + owner_trust_var_label_->setText(key_.GetOwnerTrust()); - std::string key_size_val, key_expire_val, key_create_time_val, key_algo_val, - key_last_update_val; + QString key_size_val; + QString key_expire_val; + QString key_create_time_val; + QString key_algo_val; + QString key_last_update_val; - key_size_val = std::to_string(key_.GetPrimaryKeyLength()); + key_size_val = QString::number(key_.GetPrimaryKeyLength()); - if (to_time_t(boost::posix_time::ptime(key_.GetExpireTime())) == 0) { - expire_var_label_->setText(_("Never Expire")); + if (key_.GetExpireTime().toSecsSinceEpoch() == 0) { + expire_var_label_->setText(tr("Never Expire")); } else { -#ifdef GPGFRONTEND_GUI_QT6 - expire_var_label_->setText(QLocale::system().toString( - QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetExpireTime())))); -#else - expire_var_label_->setText(QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(key_.GetExpireTime())))); -#endif + expire_var_label_->setText( + QLocale::system().toString((key_.GetExpireTime()))); } key_algo_val = key_.GetPublicKeyAlgo(); -#ifdef GPGFRONTEND_GUI_QT6 - created_var_label_->setText(QLocale::system().toString( - QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetCreateTime())))); -#else - created_var_label_->setText(QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(key_.GetCreateTime())))); -#endif + created_var_label_->setText(QLocale::system().toString(key_.GetCreateTime())); - if (to_time_t(boost::posix_time::ptime(key_.GetLastUpdateTime())) == 0) { - last_update_var_label_->setText(_("No Data")); + if (key_.GetLastUpdateTime().toSecsSinceEpoch() == 0) { + last_update_var_label_->setText(tr("No Data")); } else { -#ifdef GPGFRONTEND_GUI_QT6 - last_update_var_label_->setText(QLocale::system().toString( - QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetLastUpdateTime())))); -#else - last_update_var_label_->setText(QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(key_.GetLastUpdateTime())))); -#endif + last_update_var_label_->setText( + QLocale::system().toString(key_.GetLastUpdateTime())); } - key_size_var_label_->setText(key_size_val.c_str()); - algorithm_var_label_->setText(key_algo_val.c_str()); - fingerprint_var_label_->setText( - beautify_fingerprint(key_.GetFingerprint()).c_str()); + key_size_var_label_->setText(key_size_val); + algorithm_var_label_->setText(key_algo_val); + fingerprint_var_label_->setText(BeautifyFingerprint(key_.GetFingerprint())); icon_label_->hide(); exp_label_->hide(); @@ -279,12 +266,12 @@ void KeyPairDetailTab::slot_refresh_key_info() { if (key_.IsExpired()) { icon_label_->show(); exp_label_->show(); - exp_label_->setText(_("Warning: The primary key has expired.")); + exp_label_->setText(tr("Warning: The primary key has expired.")); } if (key_.IsRevoked()) { icon_label_->show(); exp_label_->show(); - exp_label_->setText(_("Warning: The primary key has been revoked.")); + exp_label_->setText(tr("Warning: The primary key has been revoked.")); } } diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.h b/src/ui/dialog/keypair_details/KeyPairDetailTab.h index efa3269c..b12f108c 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.h +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,16 +19,17 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYPAIRDETAILTAB_H -#define GPGFRONTEND_KEYPAIRDETAILTAB_H +#pragma once #include "KeySetExpireDateDialog.h" -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/import_export/KeyServerImportDialog.h" #include "ui/dialog/import_export/KeyUploadDialog.h" @@ -91,10 +92,7 @@ class KeyPairDetailTab : public QWidget { * @param key_id * @param parent */ - explicit KeyPairDetailTab(const std::string& key_id, - QWidget* parent = nullptr); + explicit KeyPairDetailTab(const QString& key_id, QWidget* parent = nullptr); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYPAIRDETAILTAB_H diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index c5d0670a..5b0f4642 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,8 +19,10 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ @@ -29,43 +31,46 @@ #include "KeySetExpireDateDialog.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyImportExporter.h" -#include "core/function/gpg/GpgKeyManager.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "ui/SignalStation.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" +#include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/import_export/KeyUploadDialog.h" +#include "ui/function/SetOwnerTrustLevel.h" namespace GpgFrontend::UI { -KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent) +KeyPairOperaTab::KeyPairOperaTab(const QString& key_id, QWidget* parent) : QWidget(parent), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { // Set Menu CreateOperaMenu(); - auto m_vbox = new QVBoxLayout(this); + auto* m_vbox = new QVBoxLayout(this); - auto* opera_key_box = new QGroupBox(_("General Operations")); + auto* opera_key_box = new QGroupBox(tr("General Operations")); auto* vbox_p_k = new QVBoxLayout(); - auto export_h_box_layout = new QHBoxLayout(); + auto* export_h_box_layout = new QHBoxLayout(); vbox_p_k->addLayout(export_h_box_layout); - auto* export_public_button = new QPushButton(_("Export Public Key")); + auto* export_public_button = new QPushButton(tr("Export Public Key")); export_h_box_layout->addWidget(export_public_button); connect(export_public_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_export_public_key); if (m_key_.IsPrivateKey()) { - auto* export_private_button = new QPushButton(_("Export Private Key")); + auto* export_private_button = new QPushButton(tr("Export Private Key")); export_private_button->setStyleSheet("text-align:center;"); export_private_button->setMenu(secret_key_export_opera_menu_); export_h_box_layout->addWidget(export_private_button); if (m_key_.IsHasMasterKey()) { auto* edit_expires_button = - new QPushButton(_("Modify Expiration Datetime (Primary Key)")); + new QPushButton(tr("Modify Expiration Datetime (Primary Key)")); connect(edit_expires_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_modify_edit_datetime); - auto* edit_password_button = new QPushButton(_("Modify Password")); + auto* edit_password_button = new QPushButton(tr("Modify Password")); connect(edit_password_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_modify_password); @@ -74,21 +79,17 @@ KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent) } } - auto advance_h_box_layout = new QHBoxLayout(); + auto* advance_h_box_layout = new QHBoxLayout(); + + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); - // get settings - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); // read settings - bool forbid_all_gnupg_connection = false; - try { - forbid_all_gnupg_connection = - settings.lookup("network.forbid_all_gnupg_connection"); - } catch (...) { - SPDLOG_ERROR("setting operation error: forbid_all_gnupg_connection"); - } + bool forbid_all_gnupg_connection = + settings.value("network/forbid_all_gnupg_connection").toBool(); auto* key_server_opera_button = - new QPushButton(_("Key Server Operation (Pubkey)")); + new QPushButton(tr("Key Server Operation (Pubkey)")); key_server_opera_button->setStyleSheet("text-align:center;"); key_server_opera_button->setMenu(key_server_opera_menu_); key_server_opera_button->setDisabled(forbid_all_gnupg_connection); @@ -96,18 +97,18 @@ KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent) if (m_key_.IsPrivateKey() && m_key_.IsHasMasterKey()) { auto* revoke_cert_gen_button = - new QPushButton(_("Generate Revoke Certificate")); + new QPushButton(tr("Generate Revoke Certificate")); connect(revoke_cert_gen_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_gen_revoke_cert); advance_h_box_layout->addWidget(revoke_cert_gen_button); } - auto* modify_tofu_button = new QPushButton(_("Modify TOFU Policy")); + auto* modify_tofu_button = new QPushButton(tr("Modify TOFU Policy")); connect(modify_tofu_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_modify_tofu_policy); auto* set_owner_trust_level_button = - new QPushButton(_("Set Owner Trust Level")); + new QPushButton(tr("Set Owner Trust Level")); connect(set_owner_trust_level_button, &QPushButton::clicked, this, &KeyPairOperaTab::slot_set_owner_trust_level); @@ -123,53 +124,56 @@ KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent) // set up signal connect(this, &KeyPairOperaTab::SignalKeyDatabaseRefresh, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); } void KeyPairOperaTab::CreateOperaMenu() { key_server_opera_menu_ = new QMenu(this); - auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this); - connect(uploadKeyPair, &QAction::triggered, this, + auto* upload_key_pair = + new QAction(tr("Upload Key Pair to Key Server"), this); + connect(upload_key_pair, &QAction::triggered, this, &KeyPairOperaTab::slot_upload_key_to_server); - if (!(m_key_.IsPrivateKey() && m_key_.IsHasMasterKey())) - uploadKeyPair->setDisabled(true); + if (!(m_key_.IsPrivateKey() && m_key_.IsHasMasterKey())) { + upload_key_pair->setDisabled(true); + } - auto* updateKeyPair = new QAction(_("Sync Key Pair From Key Server"), this); - connect(updateKeyPair, &QAction::triggered, this, + auto* update_key_pair = + new QAction(tr("Sync Key Pair From Key Server"), this); + connect(update_key_pair, &QAction::triggered, this, &KeyPairOperaTab::slot_update_key_from_server); // when a key has primary key, it should always upload to keyserver. if (m_key_.IsHasMasterKey()) { - updateKeyPair->setDisabled(true); + update_key_pair->setDisabled(true); } - key_server_opera_menu_->addAction(uploadKeyPair); - key_server_opera_menu_->addAction(updateKeyPair); + key_server_opera_menu_->addAction(upload_key_pair); + key_server_opera_menu_->addAction(update_key_pair); secret_key_export_opera_menu_ = new QMenu(this); - auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this); - connect(exportFullSecretKey, &QAction::triggered, this, + auto* export_full_secret_key = + new QAction(tr("Export Full Secret Key"), this); + connect(export_full_secret_key, &QAction::triggered, this, &KeyPairOperaTab::slot_export_private_key); - if (!m_key_.IsPrivateKey()) exportFullSecretKey->setDisabled(true); + if (!m_key_.IsPrivateKey()) export_full_secret_key->setDisabled(true); - auto* exportShortestSecretKey = - new QAction(_("Export Shortest Secret Key"), this); - connect(exportShortestSecretKey, &QAction::triggered, this, + auto* export_shortest_secret_key = + new QAction(tr("Export Shortest Secret Key"), this); + connect(export_shortest_secret_key, &QAction::triggered, this, &KeyPairOperaTab::slot_export_short_private_key); - secret_key_export_opera_menu_->addAction(exportFullSecretKey); - secret_key_export_opera_menu_->addAction(exportShortestSecretKey); + secret_key_export_opera_menu_->addAction(export_full_secret_key); + secret_key_export_opera_menu_->addAction(export_shortest_secret_key); } void KeyPairOperaTab::slot_export_public_key() { - ByteArrayPtr keyArray = nullptr; - - if (!GpgKeyImportExporter::GetInstance().ExportKey(m_key_, keyArray)) { - QMessageBox::critical(this, _("Error"), - _("An error occurred during the export operation.")); + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance().ExportKey(m_key_, false, true, false); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); return; } @@ -183,18 +187,15 @@ void KeyPairOperaTab::slot_export_public_key() { #endif std::replace(file_string.begin(), file_string.end(), ' ', '_'); - auto file_name = - QFileDialog::getSaveFileName( - this, _("Export Key To File"), QString::fromStdString(file_string), - QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)") - .toStdString(); + auto file_name = QFileDialog::getSaveFileName( + this, tr("Export Key To File"), file_string, + tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - if (file_name.empty()) return; + if (file_name.isEmpty()) return; - if (!write_buffer_to_file(file_name, *keyArray)) { - QMessageBox::critical( - this, _("Export Error"), - QString(_("Couldn't open %1 for writing")).arg(file_name.c_str())); + if (!WriteFileGFBuffer(file_name, gf_buffer)) { + QMessageBox::critical(this, tr("Export Error"), + tr("Couldn't open %1 for writing").arg(file_name)); return; } } @@ -202,26 +203,23 @@ void KeyPairOperaTab::slot_export_public_key() { void KeyPairOperaTab::slot_export_short_private_key() { // Show a information box with explanation about private key int ret = QMessageBox::information( - this, _("Exporting short private Key"), - "<h3>" + QString(_("You are about to export your")) + - "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" + - _("This is NOT your Public Key, so DON'T give it away.") + "<br />" + - _("Do you REALLY want to export your PRIVATE KEY in a Minimum " - "Size?") + + this, tr("Exporting short private Key"), + "<h3>" + tr("You are about to export your") + "<font color=\"red\">" + + tr(" PRIVATE KEY ") + "</font>!</h3>\n" + + tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" + + tr("Do you REALLY want to export your PRIVATE KEY in a Minimum " + "Size?") + "<br />" + - _("For OpenPGP keys it removes all signatures except for the latest " - "self-signatures."), + tr("For OpenPGP keys it removes all signatures except for the latest " + "self-signatures."), QMessageBox::Cancel | QMessageBox::Ok); // export key, if ok was clicked if (ret == QMessageBox::Ok) { - ByteArrayPtr keyArray = nullptr; - - if (!GpgKeyImportExporter::GetInstance().ExportSecretKeyShortest( - m_key_, keyArray)) { - QMessageBox::critical( - this, _("Error"), - _("An error occurred during the export operation.")); + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance().ExportKey(m_key_, true, true, true); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); return; } @@ -235,18 +233,15 @@ void KeyPairOperaTab::slot_export_short_private_key() { #endif std::replace(file_string.begin(), file_string.end(), ' ', '_'); - auto file_name = - QFileDialog::getSaveFileName( - this, _("Export Key To File"), QString::fromStdString(file_string), - QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)") - .toStdString(); + auto file_name = QFileDialog::getSaveFileName( + this, tr("Export Key To File"), file_string, + tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - if (file_name.empty()) return; + if (file_name.isEmpty()) return; - if (!write_buffer_to_file(file_name, *keyArray)) { - QMessageBox::critical( - this, _("Export Error"), - QString(_("Couldn't open %1 for writing")).arg(file_name.c_str())); + if (!WriteFileGFBuffer(file_name, gf_buffer)) { + QMessageBox::critical(this, tr("Export Error"), + tr("Couldn't open %1 for writing").arg(file_name)); return; } } @@ -255,22 +250,19 @@ void KeyPairOperaTab::slot_export_short_private_key() { void KeyPairOperaTab::slot_export_private_key() { // Show a information box with explanation about private key int ret = QMessageBox::information( - this, _("Exporting private Key"), - "<h3>" + QString(_("You are about to export your")) + - "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" + - _("This is NOT your Public Key, so DON'T give it away.") + "<br />" + - _("Do you REALLY want to export your PRIVATE KEY?"), + this, tr("Exporting private Key"), + "<h3>" + tr("You are about to export your") + "<font color=\"red\">" + + tr(" PRIVATE KEY ") + "</font>!</h3>\n" + + tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" + + tr("Do you REALLY want to export your PRIVATE KEY?"), QMessageBox::Cancel | QMessageBox::Ok); // export key, if ok was clicked if (ret == QMessageBox::Ok) { - ByteArrayPtr keyArray = nullptr; - - if (!GpgKeyImportExporter::GetInstance().ExportSecretKey(m_key_, - keyArray)) { - QMessageBox::critical( - this, _("Error"), - _("An error occurred during the export operation.")); + auto [err, gf_buffer] = GpgKeyImportExporter::GetInstance().ExportKey( + m_key_, true, true, false); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); return; } @@ -284,25 +276,22 @@ void KeyPairOperaTab::slot_export_private_key() { #endif std::replace(file_string.begin(), file_string.end(), ' ', '_'); - auto file_name = - QFileDialog::getSaveFileName( - this, _("Export Key To File"), QString::fromStdString(file_string), - QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)") - .toStdString(); + auto file_name = QFileDialog::getSaveFileName( + this, tr("Export Key To File"), file_string, + tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - if (file_name.empty()) return; + if (file_name.isEmpty()) return; - if (!write_buffer_to_file(file_name, *keyArray)) { - QMessageBox::critical( - this, _("Export Error"), - QString(_("Couldn't open %1 for writing")).arg(file_name.c_str())); + if (!WriteFileGFBuffer(file_name, gf_buffer)) { + QMessageBox::critical(this, tr("Export Error"), + tr("Couldn't open %1 for writing").arg(file_name)); return; } } } void KeyPairOperaTab::slot_modify_edit_datetime() { - auto dialog = new KeySetExpireDateDialog(m_key_.GetId(), this); + auto* dialog = new KeySetExpireDateDialog(m_key_.GetId(), this); dialog->show(); } @@ -323,106 +312,71 @@ void KeyPairOperaTab::slot_update_key_from_server() { } void KeyPairOperaTab::slot_gen_revoke_cert() { - auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates")); + auto literal = QString("%1 (*.rev)").arg(tr("Revocation Certificates")); QString m_output_file_name; - QFileDialog dialog(this, "Generate revocation certificate", QString(), +#ifndef WINDOWS + auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" + + m_key_.GetId() + ").rev"; +#else + auto file_string = m_key_.GetName() + "[" + m_key_.GetEmail() + "](" + + m_key_.GetId() + ").rev"; +#endif + + QFileDialog dialog(this, tr("Generate revocation certificate"), file_string, literal); dialog.setDefaultSuffix(".rev"); dialog.setAcceptMode(QFileDialog::AcceptSave); - if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front(); + if (dialog.exec() != 0) m_output_file_name = dialog.selectedFiles().front(); if (!m_output_file_name.isEmpty()) { - GpgKeyOpera::GetInstance().GenerateRevokeCert( - m_key_, m_output_file_name.toStdString()); + GpgKeyOpera::GetInstance().GenerateRevokeCert(m_key_, m_output_file_name); } } void KeyPairOperaTab::slot_modify_password() { - auto err = GpgKeyOpera::GetInstance().ModifyPassword(m_key_); - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) { - QMessageBox::critical(this, _("Not Successful"), - QString(_("Modify password not successfully."))); - } + GpgKeyOpera::GetInstance().ModifyPassword( + m_key_, [this](GpgError err, const DataObjectPtr&) { + CommonUtils::RaiseMessageBox(this, err); + }); } void KeyPairOperaTab::slot_modify_tofu_policy() { QStringList items; - items << _("Policy Auto") << _("Policy Good") << _("Policy Bad") - << _("Policy Ask") << _("Policy Unknown"); + items << tr("Policy Auto") << tr("Policy Good") << tr("Policy Bad") + << tr("Policy Ask") << tr("Policy Unknown"); bool ok; QString item = QInputDialog::getItem( - this, _("Modify TOFU Policy(Default is Auto)"), - _("Policy for the Key Pair:"), items, 0, false, &ok); + this, tr("Modify TOFU Policy(Default is Auto)"), + tr("Policy for the Key Pair:"), items, 0, false, &ok); if (ok && !item.isEmpty()) { - SPDLOG_DEBUG("selected policy: {}", item.toStdString()); + GF_UI_LOG_DEBUG("selected policy: {}", item.toStdString()); gpgme_tofu_policy_t tofu_policy = GPGME_TOFU_POLICY_AUTO; - if (item == _("Policy Auto")) { + if (item == tr("Policy Auto")) { tofu_policy = GPGME_TOFU_POLICY_AUTO; - } else if (item == _("Policy Good")) { + } else if (item == tr("Policy Good")) { tofu_policy = GPGME_TOFU_POLICY_GOOD; - } else if (item == _("Policy Bad")) { + } else if (item == tr("Policy Bad")) { tofu_policy = GPGME_TOFU_POLICY_BAD; - } else if (item == _("Policy Ask")) { + } else if (item == tr("Policy Ask")) { tofu_policy = GPGME_TOFU_POLICY_ASK; - } else if (item == _("Policy Unknown")) { + } else if (item == tr("Policy Unknown")) { tofu_policy = GPGME_TOFU_POLICY_UNKNOWN; } auto err = GpgKeyOpera::GetInstance().ModifyTOFUPolicy(m_key_, tofu_policy); - if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) { - QMessageBox::critical(this, _("Not Successful"), - QString(_("Modify TOFU policy not successfully."))); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + QMessageBox::critical(this, tr("Not Successful"), + tr("Modify TOFU policy not successfully.")); } } } void KeyPairOperaTab::slot_set_owner_trust_level() { - QStringList items; - - items << _("Unknown") << _("Undefined") << _("Never") << _("Marginal") - << _("Full") << _("Ultimate"); - bool ok; - QString item = QInputDialog::getItem(this, _("Modify Owner Trust Level"), - _("Trust for the Key Pair:"), items, - m_key_.GetOwnerTrustLevel(), false, &ok); - - if (ok && !item.isEmpty()) { - SPDLOG_DEBUG("selected policy: {}", item.toStdString()); - int trust_level = 0; // Unknown Level - if (item == _("Ultimate")) { - trust_level = 5; - } else if (item == _("Full")) { - trust_level = 4; - } else if (item == _("Marginal")) { - trust_level = 3; - } else if (item == _("Never")) { - trust_level = 2; - } else if (item == _("Undefined")) { - trust_level = 1; - } - - if (trust_level == 0) { - QMessageBox::warning( - this, _("Warning"), - QString(_("Owner Trust Level cannot set to Unknown level, automately " - "changing it into Undefined level."))); - trust_level = 1; - } - - bool status = - GpgKeyManager::GetInstance().SetOwnerTrustLevel(m_key_, trust_level); - if (!status) { - QMessageBox::critical(this, _("Failed"), - QString(_("Modify Owner Trust Level failed."))); - } else { - QMessageBox::information(this, _("Success"), - QString(_("Set Owner Trust Level successful."))); - // update key database and refresh ui - emit SignalKeyDatabaseRefresh(); - } - } + auto* function = new SetOwnerTrustLevel(this); + function->Exec(m_key_.GetId()); + function->deleteLater(); } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h index 0c4a7916..100d4a69 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.h +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,17 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYPAIROPERATAB_H -#define GPGFRONTEND_KEYPAIROPERATAB_H +#pragma once #include "core/function/gpg/GpgKeyGetter.h" +#include "core/model/GpgKey.h" #include "ui/GpgFrontendUI.h" namespace GpgFrontend::UI { @@ -40,7 +42,7 @@ class KeyPairOperaTab : public QWidget { * @param key_id * @param parent */ - KeyPairOperaTab(const std::string& key_id, QWidget* parent); + KeyPairOperaTab(const QString& key_id, QWidget* parent); /** * @brief Create a Opera Menu object @@ -122,5 +124,3 @@ class KeyPairOperaTab : public QWidget { QMenu* secret_key_export_opera_menu_{}; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYPAIROPERATAB_H diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index 9c243a39..3f973fae 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,57 +28,52 @@ #include "KeyPairSubkeyTab.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" -#include "ui/SignalStation.h" +#include "core/utils/CommonUtils.h" +#include "ui/UISignalStation.h" namespace GpgFrontend::UI { -KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent) +KeyPairSubkeyTab::KeyPairSubkeyTab(const QString& key_id, QWidget* parent) : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { - SPDLOG_DEBUG(key_.GetEmail(), key_.IsPrivateKey(), key_.IsHasMasterKey(), - key_.GetSubKeys()->front().IsPrivateKey()); - create_subkey_list(); create_subkey_opera_menu(); - list_box_ = new QGroupBox(_("Subkey List")); - detail_box_ = new QGroupBox(_("Detail of Selected Subkey")); + list_box_ = new QGroupBox(tr("Subkey List")); + detail_box_ = new QGroupBox(tr("Detail of Selected Subkey")); - auto uidButtonsLayout = new QGridLayout(); + auto* uid_buttons_layout = new QGridLayout(); - auto addSubkeyButton = new QPushButton(_("Generate A New Subkey")); + auto* add_subkey_button = new QPushButton(tr("Generate A New Subkey")); if (!key_.IsPrivateKey() || !key_.IsHasMasterKey()) { - addSubkeyButton->setDisabled(true); - setHidden(addSubkeyButton); + add_subkey_button->setDisabled(true); + setHidden(add_subkey_button); } - uidButtonsLayout->addWidget(addSubkeyButton, 0, 1); - - auto* baseLayout = new QVBoxLayout(); - - auto subkeyListLayout = new QGridLayout(); - subkeyListLayout->addWidget(subkey_list_, 0, 0); - subkeyListLayout->addLayout(uidButtonsLayout, 1, 0); - subkeyListLayout->setContentsMargins(0, 10, 0, 0); - - auto* subkeyDetailLayout = new QGridLayout(); - - subkeyDetailLayout->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); - subkeyDetailLayout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, - 0); - subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, - 0); - subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0); - subkeyDetailLayout->addWidget( - new QLabel(QString(_("Expires On (Local Time)")) + ": "), 4, 0); - subkeyDetailLayout->addWidget( - new QLabel(QString(_("Create Date (Local Time)")) + ": "), 5, 0); - subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6, - 0); - subkeyDetailLayout->addWidget( - new QLabel(QString(_("Key in Smart Card")) + ": "), 7, 0); - subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 8, - 0); + uid_buttons_layout->addWidget(add_subkey_button, 0, 1); + + auto* base_layout = new QVBoxLayout(); + + auto* subkey_list_layout = new QGridLayout(); + subkey_list_layout->addWidget(subkey_list_, 0, 0); + subkey_list_layout->addLayout(uid_buttons_layout, 1, 0); + subkey_list_layout->setContentsMargins(0, 10, 0, 0); + + auto* subkey_detail_layout = new QGridLayout(); + + subkey_detail_layout->addWidget(new QLabel(tr("Key ID") + ": "), 0, 0); + subkey_detail_layout->addWidget(new QLabel(tr("Algorithm") + ": "), 1, 0); + subkey_detail_layout->addWidget(new QLabel(tr("Key Size") + ": "), 2, 0); + subkey_detail_layout->addWidget(new QLabel(tr("Usage") + ": "), 3, 0); + subkey_detail_layout->addWidget( + new QLabel(tr("Expires On (Local Time)") + ": "), 4, 0); + subkey_detail_layout->addWidget( + new QLabel(tr("Create Date (Local Time)") + ": "), 5, 0); + subkey_detail_layout->addWidget(new QLabel(tr("Existence") + ": "), 6, 0); + subkey_detail_layout->addWidget(new QLabel(tr("Key in Smart Card") + ": "), 7, + 0); + subkey_detail_layout->addWidget(new QLabel(tr("Fingerprint") + ": "), 8, 0); key_id_var_label_ = new QLabel(this); key_size_var_label_ = new QLabel(this); @@ -90,49 +85,49 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent) fingerprint_var_label_ = new QLabel(this); card_key_label_ = new QLabel(this); - subkeyDetailLayout->addWidget(key_id_var_label_, 0, 1, 1, 1); - subkeyDetailLayout->addWidget(key_size_var_label_, 2, 1, 1, 2); - subkeyDetailLayout->addWidget(expire_var_label_, 4, 1, 1, 2); - subkeyDetailLayout->addWidget(algorithm_var_label_, 1, 1, 1, 2); - subkeyDetailLayout->addWidget(created_var_label_, 5, 1, 1, 2); - subkeyDetailLayout->addWidget(usage_var_label_, 3, 1, 1, 2); - subkeyDetailLayout->addWidget(master_key_exist_var_label_, 6, 1, 1, 2); - subkeyDetailLayout->addWidget(card_key_label_, 7, 1, 1, 2); - subkeyDetailLayout->addWidget(fingerprint_var_label_, 8, 1, 1, 2); - - auto* copyKeyIdButton = new QPushButton(_("Copy")); - copyKeyIdButton->setFlat(true); - subkeyDetailLayout->addWidget(copyKeyIdButton, 0, 2); - connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() { + subkey_detail_layout->addWidget(key_id_var_label_, 0, 1, 1, 1); + subkey_detail_layout->addWidget(key_size_var_label_, 2, 1, 1, 2); + subkey_detail_layout->addWidget(expire_var_label_, 4, 1, 1, 2); + subkey_detail_layout->addWidget(algorithm_var_label_, 1, 1, 1, 2); + subkey_detail_layout->addWidget(created_var_label_, 5, 1, 1, 2); + subkey_detail_layout->addWidget(usage_var_label_, 3, 1, 1, 2); + subkey_detail_layout->addWidget(master_key_exist_var_label_, 6, 1, 1, 2); + subkey_detail_layout->addWidget(card_key_label_, 7, 1, 1, 2); + subkey_detail_layout->addWidget(fingerprint_var_label_, 8, 1, 1, 2); + + auto* copy_key_id_button = new QPushButton(tr("Copy")); + copy_key_id_button->setFlat(true); + subkey_detail_layout->addWidget(copy_key_id_button, 0, 2); + connect(copy_key_id_button, &QPushButton::clicked, this, [=]() { QString fpr = key_id_var_label_->text().trimmed(); QClipboard* cb = QApplication::clipboard(); cb->setText(fpr); }); - list_box_->setLayout(subkeyListLayout); + list_box_->setLayout(subkey_list_layout); list_box_->setContentsMargins(0, 12, 0, 0); - detail_box_->setLayout(subkeyDetailLayout); + detail_box_->setLayout(subkey_detail_layout); - baseLayout->addWidget(list_box_); - baseLayout->addWidget(detail_box_); - baseLayout->addStretch(); + base_layout->addWidget(list_box_); + base_layout->addWidget(detail_box_); + base_layout->addStretch(); - connect(addSubkeyButton, &QPushButton::clicked, this, + connect(add_subkey_button, &QPushButton::clicked, this, &KeyPairSubkeyTab::slot_add_subkey); connect(subkey_list_, &QTableWidget::itemSelectionChanged, this, &KeyPairSubkeyTab::slot_refresh_subkey_detail); // key database refresh signal - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, &KeyPairSubkeyTab::slot_refresh_key_info); - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, &KeyPairSubkeyTab::slot_refresh_subkey_list); - baseLayout->setContentsMargins(0, 0, 0, 0); + base_layout->setContentsMargins(0, 0, 0, 0); - setLayout(baseLayout); + setLayout(base_layout); setAttribute(Qt::WA_DeleteOnClose, true); slot_refresh_subkey_list(); @@ -157,8 +152,8 @@ void KeyPairSubkeyTab::create_subkey_list() { subkey_list_->setAlternatingRowColors(true); QStringList labels; - labels << _("Subkey ID") << _("Key Size") << _("Algo") - << _("Create Date (UTC)") << _("Expire Date (UTC)"); + labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date") + << tr("Expire Date"); subkey_list_->setHorizontalHeaderLabels(labels); subkey_list_->horizontalHeader()->setStretchLastSection(false); @@ -176,13 +171,13 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { this->buffered_subkeys_.push_back(std::move(sub_key)); } - SPDLOG_DEBUG("buffered_subkeys_ refreshed size", - this->buffered_subkeys_.size()); + GF_UI_LOG_DEBUG("buffered_subkeys_ refreshed size", + this->buffered_subkeys_.size()); subkey_list_->setRowCount(buffered_subkeys_.size()); for (const auto& subkeys : buffered_subkeys_) { - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(subkeys.GetID())); + auto* tmp0 = new QTableWidgetItem(subkeys.GetID()); tmp0->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 0, tmp0); @@ -190,21 +185,18 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { tmp1->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 1, tmp1); - auto* tmp2 = - new QTableWidgetItem(QString::fromStdString(subkeys.GetPubkeyAlgo())); + auto* tmp2 = new QTableWidgetItem(subkeys.GetPubkeyAlgo()); tmp2->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 2, tmp2); - auto* tmp3 = new QTableWidgetItem( - QString::fromStdString(to_iso_string(subkeys.GetCreateTime()))); + auto* tmp3 = new QTableWidgetItem(subkeys.GetCreateTime().toString()); tmp3->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 3, tmp3); - auto* tmp4 = new QTableWidgetItem( - boost::posix_time::to_time_t( - boost::posix_time::ptime(subkeys.GetExpireTime())) == 0 - ? _("Never Expire") - : QString::fromStdString(to_iso_string(subkeys.GetExpireTime()))); + auto* tmp4 = + new QTableWidgetItem(subkeys.GetExpireTime().toSecsSinceEpoch() == 0 + ? tr("Never Expire") + : subkeys.GetExpireTime().toString()); tmp4->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 4, tmp4); @@ -214,12 +206,12 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { } } - SPDLOG_DEBUG("subkey_list_ item {} refreshed", row); + GF_UI_LOG_DEBUG("subkey_list_ item {} refreshed", row); row++; } - SPDLOG_DEBUG("subkey_list_ refreshed"); + GF_UI_LOG_DEBUG("subkey_list_ refreshed"); if (subkey_list_->rowCount() > 0) { subkey_list_->selectRow(0); @@ -227,67 +219,55 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { } void KeyPairSubkeyTab::slot_add_subkey() { - auto dialog = new SubkeyGenerateDialog(key_.GetId(), this); + auto* dialog = new SubkeyGenerateDialog(key_.GetId(), this); dialog->show(); } void KeyPairSubkeyTab::slot_refresh_subkey_detail() { - auto& subkey = get_selected_subkey(); + const auto& subkey = get_selected_subkey(); - key_id_var_label_->setText(QString::fromStdString(subkey.GetID())); + key_id_var_label_->setText(subkey.GetID()); key_size_var_label_->setText(QString::number(subkey.GetKeyLength())); - time_t subkey_time_t = boost::posix_time::to_time_t( - boost::posix_time::ptime(subkey.GetExpireTime())); + time_t subkey_time_t = subkey.GetExpireTime().toSecsSinceEpoch(); -#ifdef GPGFRONTEND_GUI_QT6 - expire_var_label_->setText( - subkey_time_t == 0 - ? _("Never Expires") - : QLocale::system().toString(QDateTime::fromSecsSinceEpoch( - to_time_t(subkey.GetExpireTime())))); -#else expire_var_label_->setText( - subkey_time_t == 0 ? _("Never Expires") - : QLocale::system().toString(QDateTime::fromTime_t( - to_time_t(subkey.GetExpireTime())))); -#endif + subkey_time_t == 0 ? tr("Never Expires") + : QLocale::system().toString(subkey.GetExpireTime())); + if (subkey_time_t != 0 && - subkey.GetExpireTime() < boost::posix_time::second_clock::local_time()) { - auto paletteExpired = expire_var_label_->palette(); - paletteExpired.setColor(expire_var_label_->foregroundRole(), Qt::red); - expire_var_label_->setPalette(paletteExpired); + subkey.GetExpireTime() < QDateTime::currentDateTime()) { + auto palette_expired = expire_var_label_->palette(); + palette_expired.setColor(expire_var_label_->foregroundRole(), Qt::red); + expire_var_label_->setPalette(palette_expired); } else { - auto paletteValid = expire_var_label_->palette(); - paletteValid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen); - expire_var_label_->setPalette(paletteValid); + auto palette_valid = expire_var_label_->palette(); + palette_valid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen); + expire_var_label_->setPalette(palette_valid); } - algorithm_var_label_->setText(QString::fromStdString(subkey.GetPubkeyAlgo())); -#ifdef GPGFRONTEND_GUI_QT6 - created_var_label_->setText(QLocale::system().toString( - QDateTime::fromSecsSinceEpoch(to_time_t(subkey.GetCreateTime())))); -#else - created_var_label_->setText(QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(subkey.GetCreateTime())))); -#endif + algorithm_var_label_->setText(subkey.GetPubkeyAlgo()); + created_var_label_->setText( + QLocale::system().toString(subkey.GetCreateTime())); - std::stringstream usage_steam; + QString buffer; + QTextStream usage_steam(&buffer); - if (subkey.IsHasCertificationCapability()) - usage_steam << _("Certificate") << " "; - if (subkey.IsHasEncryptionCapability()) usage_steam << _("Encrypt") << " "; - if (subkey.IsHasSigningCapability()) usage_steam << _("Sign") << " "; - if (subkey.IsHasAuthenticationCapability()) usage_steam << _("Auth") << " "; + if (subkey.IsHasCertificationCapability()) { + usage_steam << tr("Certificate") << " "; + } + if (subkey.IsHasEncryptionCapability()) usage_steam << tr("Encrypt") << " "; + if (subkey.IsHasSigningCapability()) usage_steam << tr("Sign") << " "; + if (subkey.IsHasAuthenticationCapability()) usage_steam << tr("Auth") << " "; - usage_var_label_->setText(usage_steam.str().c_str()); + usage_var_label_->setText(usage_steam.readAll()); // Show the situation that secret key not exists. - master_key_exist_var_label_->setText(subkey.IsSecretKey() ? _("Exists") - : _("Not Exists")); + master_key_exist_var_label_->setText(subkey.IsSecretKey() ? tr("Exists") + : tr("Not Exists")); // Show the situation if key in a smart card. - card_key_label_->setText(subkey.IsCardKey() ? _("Yes") : _("No")); + card_key_label_->setText(subkey.IsCardKey() ? tr("Yes") : tr("No")); if (!subkey.IsSecretKey()) { auto palette_expired = master_key_exist_var_label_->palette(); @@ -311,23 +291,22 @@ void KeyPairSubkeyTab::slot_refresh_subkey_detail() { card_key_label_->setPalette(palette_valid); } - fingerprint_var_label_->setText( - QString::fromStdString(beautify_fingerprint(subkey.GetFingerprint()))); + fingerprint_var_label_->setText(BeautifyFingerprint(subkey.GetFingerprint())); } void KeyPairSubkeyTab::create_subkey_opera_menu() { subkey_opera_menu_ = new QMenu(this); - auto* editSubkeyAct = new QAction(_("Edit Expire Date")); - connect(editSubkeyAct, &QAction::triggered, this, + auto* edit_subkey_act = new QAction(tr("Edit Expire Date")); + connect(edit_subkey_act, &QAction::triggered, this, &KeyPairSubkeyTab::slot_edit_subkey); - subkey_opera_menu_->addAction(editSubkeyAct); + subkey_opera_menu_->addAction(edit_subkey_act); } void KeyPairSubkeyTab::slot_edit_subkey() { - SPDLOG_DEBUG("fpr {}", get_selected_subkey().GetFingerprint()); + GF_UI_LOG_DEBUG("fpr {}", get_selected_subkey().GetFingerprint()); - auto dialog = new KeySetExpireDateDialog( + auto* dialog = new KeySetExpireDateDialog( key_.GetId(), get_selected_subkey().GetFingerprint(), this); dialog->show(); } @@ -340,7 +319,7 @@ void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent* event) { } } -const GpgSubKey& KeyPairSubkeyTab::get_selected_subkey() { +auto KeyPairSubkeyTab::get_selected_subkey() -> const GpgSubKey& { int row = 0; for (int i = 0; i < subkey_list_->rowCount(); i++) { diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h index a93ebca5..c179c3e9 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,17 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYPAIRSUBKEYTAB_H -#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H +#pragma once #include "KeySetExpireDateDialog.h" -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/key_generate/SubkeyGenerateDialog.h" @@ -46,7 +45,7 @@ class KeyPairSubkeyTab : public QWidget { * @param key * @param parent */ - KeyPairSubkeyTab(const std::string& key, QWidget* parent); + KeyPairSubkeyTab(const QString& key, QWidget* parent); private: /** @@ -135,5 +134,3 @@ class KeyPairSubkeyTab : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYPAIRSUBKEYTAB_H diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp index d55e44d8..fe2f5f02 100644 --- a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,22 +19,25 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "KeyPairUIDTab.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyManager.h" #include "core/function/gpg/GpgUIDOperator.h" -#include "ui/SignalStation.h" +#include "ui/UISignalStation.h" #include "ui/widgets/TOFUInfoPage.h" namespace GpgFrontend::UI { -KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent) +KeyPairUIDTab::KeyPairUIDTab(const QString& key_id, QWidget* parent) : QWidget(parent), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { create_uid_list(); create_sign_list(); @@ -42,58 +45,58 @@ KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent) create_uid_popup_menu(); create_sign_popup_menu(); - auto uidButtonsLayout = new QGridLayout(); + auto* uid_buttons_layout = new QGridLayout(); - auto addUIDButton = new QPushButton(_("New UID")); - auto manageUIDButton = new QPushButton(_("UID Management")); + auto* add_uid_button = new QPushButton(tr("New UID")); + auto* manage_uid_button = new QPushButton(tr("UID Management")); if (m_key_.IsHasMasterKey()) { - manageUIDButton->setMenu(manage_selected_uid_menu_); + manage_uid_button->setMenu(manage_selected_uid_menu_); } else { - manageUIDButton->setDisabled(true); + manage_uid_button->setDisabled(true); } - uidButtonsLayout->addWidget(addUIDButton, 0, 1); - uidButtonsLayout->addWidget(manageUIDButton, 0, 2); + uid_buttons_layout->addWidget(add_uid_button, 0, 1); + uid_buttons_layout->addWidget(manage_uid_button, 0, 2); - auto grid_layout = new QGridLayout(); + auto* grid_layout = new QGridLayout(); grid_layout->addWidget(uid_list_, 0, 0); - grid_layout->addLayout(uidButtonsLayout, 1, 0); + grid_layout->addLayout(uid_buttons_layout, 1, 0); grid_layout->setContentsMargins(0, 10, 0, 0); - auto uid_group_box = new QGroupBox(); + auto* uid_group_box = new QGroupBox(); uid_group_box->setLayout(grid_layout); - uid_group_box->setTitle(_("UIDs")); + uid_group_box->setTitle(tr("UIDs")); - auto tofu_group_box = new QGroupBox(); - auto tofu_vbox_layout = new QVBoxLayout(); + auto* tofu_group_box = new QGroupBox(); + auto* tofu_vbox_layout = new QVBoxLayout(); tofu_group_box->setLayout(tofu_vbox_layout); - tofu_group_box->setTitle(_("TOFU")); + tofu_group_box->setTitle(tr("TOFU")); #if !defined(RELEASE) tofu_tabs_ = new QTabWidget(this); tofu_vbox_layout->addWidget(tofu_tabs_); #endif - auto sign_grid_layout = new QGridLayout(); + auto* sign_grid_layout = new QGridLayout(); sign_grid_layout->addWidget(sig_list_, 0, 0); sign_grid_layout->setContentsMargins(0, 10, 0, 0); - auto sign_group_box = new QGroupBox(); + auto* sign_group_box = new QGroupBox(); sign_group_box->setLayout(sign_grid_layout); - sign_group_box->setTitle(_("Signature of Selected UID")); + sign_group_box->setTitle(tr("Signature of Selected UID")); - auto vboxLayout = new QVBoxLayout(); - vboxLayout->addWidget(uid_group_box); + auto* vbox_layout = new QVBoxLayout(); + vbox_layout->addWidget(uid_group_box); #if !defined(RELEASE) // Function needed testing - vboxLayout->addWidget(tofu_group_box); + vbox_layout->addWidget(tofu_group_box); #endif - vboxLayout->addWidget(sign_group_box); + vbox_layout->addWidget(sign_group_box); - vboxLayout->setContentsMargins(0, 0, 0, 0); + vbox_layout->setContentsMargins(0, 0, 0, 0); - connect(addUIDButton, &QPushButton::clicked, this, + connect(add_uid_button, &QPushButton::clicked, this, &KeyPairUIDTab::slot_add_uid); connect(uid_list_, &QTableWidget::itemSelectionChanged, this, &KeyPairUIDTab::slot_refresh_tofu_info); @@ -101,15 +104,15 @@ KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent) &KeyPairUIDTab::slot_refresh_sig_list); // Key Database Refresh - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, &KeyPairUIDTab::slot_refresh_key); connect(this, &KeyPairUIDTab::SignalUpdateUIDInfo, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); - setLayout(vboxLayout); + setLayout(vbox_layout); setAttribute(Qt::WA_DeleteOnClose, true); slot_refresh_uid_list(); @@ -134,7 +137,7 @@ void KeyPairUIDTab::create_uid_list() { uid_list_->setAlternatingRowColors(true); QStringList labels; - labels << _("Select") << _("Name") << _("Email") << _("Comment"); + labels << tr("Select") << tr("Name") << tr("Email") << tr("Comment"); uid_list_->setHorizontalHeaderLabels(labels); uid_list_->horizontalHeader()->setStretchLastSection(true); } @@ -157,8 +160,8 @@ void KeyPairUIDTab::create_sign_list() { sig_list_->setAlternatingRowColors(true); QStringList labels; - labels << _("Key ID") << _("Name") << _("Email") << _("Create Date (UTC)") - << _("Expired Date (UTC)"); + labels << tr("Key ID") << tr("Name") << tr("Email") << tr("Create Date") + << tr("Expired Date"); sig_list_->setHorizontalHeaderLabels(labels); sig_list_->horizontalHeader()->setStretchLastSection(false); } @@ -181,13 +184,13 @@ void KeyPairUIDTab::slot_refresh_uid_list() { uid_list_->setRowCount(buffered_uids_.size()); for (const auto& uid : buffered_uids_) { - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(uid.GetUID())); + auto* tmp0 = new QTableWidgetItem(uid.GetName()); uid_list_->setItem(row, 1, tmp0); - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(uid.GetUID())); + auto* tmp1 = new QTableWidgetItem(uid.GetEmail()); uid_list_->setItem(row, 2, tmp1); - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(uid.GetUID())); + auto* tmp2 = new QTableWidgetItem(uid.GetComment()); uid_list_->setItem(row, 3, tmp2); auto* tmp3 = new QTableWidgetItem(QString::number(row)); @@ -217,15 +220,15 @@ void KeyPairUIDTab::slot_refresh_uid_list() { void KeyPairUIDTab::slot_refresh_tofu_info() { if (this->tofu_tabs_ == nullptr) return; - int uidRow = 0; + int uid_row = 0; tofu_tabs_->clear(); for (const auto& uid : buffered_uids_) { // Only Show Selected UID Signatures - if (!uid_list_->item(uidRow++, 0)->isSelected()) { + if (!uid_list_->item(uid_row++, 0)->isSelected()) { continue; } auto tofu_infos = uid.GetTofuInfos(); - SPDLOG_DEBUG("tofu info size: {}", tofu_infos->size()); + GF_UI_LOG_DEBUG("tofu info size: {}", tofu_infos->size()); if (tofu_infos->empty()) { tofu_tabs_->hide(); } else { @@ -234,16 +237,17 @@ void KeyPairUIDTab::slot_refresh_tofu_info() { int index = 1; for (const auto& tofu_info : *tofu_infos) { tofu_tabs_->addTab(new TOFUInfoPage(tofu_info, this), - QString(_("TOFU %1")).arg(index++)); + tr("TOFU %1").arg(index++)); } } } void KeyPairUIDTab::slot_refresh_sig_list() { - int uidRow = 0, sigRow = 0; + int uid_row = 0; + int sig_row = 0; for (const auto& uid : buffered_uids_) { // Only Show Selected UID Signatures - if (!uid_list_->item(uidRow++, 0)->isSelected()) { + if (!uid_list_->item(uid_row++, 0)->isSelected()) { continue; } @@ -259,52 +263,34 @@ void KeyPairUIDTab::slot_refresh_sig_list() { sig_list_->setRowCount(buffered_signatures_.size()); for (const auto& sig : buffered_signatures_) { - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(sig.GetKeyID())); - sig_list_->setItem(sigRow, 0, tmp0); + auto* tmp0 = new QTableWidgetItem(sig.GetKeyID()); + sig_list_->setItem(sig_row, 0, tmp0); if (gpgme_err_code(sig.GetStatus()) == GPG_ERR_NO_PUBKEY) { auto* tmp2 = new QTableWidgetItem("<Unknown>"); - sig_list_->setItem(sigRow, 1, tmp2); + sig_list_->setItem(sig_row, 1, tmp2); auto* tmp3 = new QTableWidgetItem("<Unknown>"); - sig_list_->setItem(sigRow, 2, tmp3); + sig_list_->setItem(sig_row, 2, tmp3); } else { - auto* tmp2 = - new QTableWidgetItem(QString::fromStdString(sig.GetName())); - sig_list_->setItem(sigRow, 1, tmp2); + auto* tmp2 = new QTableWidgetItem(sig.GetName()); + sig_list_->setItem(sig_row, 1, tmp2); - auto* tmp3 = - new QTableWidgetItem(QString::fromStdString(sig.GetEmail())); - sig_list_->setItem(sigRow, 2, tmp3); + auto* tmp3 = new QTableWidgetItem(sig.GetEmail()); + sig_list_->setItem(sig_row, 2, tmp3); } -#ifdef GPGFRONTEND_GUI_QT6 - auto* tmp4 = new QTableWidgetItem(QLocale::system().toString( - QDateTime::fromSecsSinceEpoch(to_time_t(sig.GetCreateTime())))); -#else - auto* tmp4 = new QTableWidgetItem(QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(sig.GetCreateTime())))); -#endif - sig_list_->setItem(sigRow, 3, tmp4); + auto* tmp4 = + new QTableWidgetItem(QLocale::system().toString(sig.GetCreateTime())); + sig_list_->setItem(sig_row, 3, tmp4); -#ifdef GPGFRONTEND_GUI_QT6 - auto* tmp5 = new QTableWidgetItem( - boost::posix_time::to_time_t( - boost::posix_time::ptime(sig.GetExpireTime())) == 0 - ? _("Never Expires") - : QLocale::system().toString(QDateTime::fromSecsSinceEpoch( - to_time_t(sig.GetExpireTime())))); -#else auto* tmp5 = new QTableWidgetItem( - boost::posix_time::to_time_t( - boost::posix_time::ptime(sig.GetExpireTime())) == 0 - ? _("Never Expires") - : QLocale::system().toString( - QDateTime::fromTime_t(to_time_t(sig.GetExpireTime())))); -#endif + sig.GetExpireTime().toSecsSinceEpoch() == 0 + ? tr("Never Expires") + : QLocale::system().toString(sig.GetExpireTime())); tmp5->setTextAlignment(Qt::AlignCenter); - sig_list_->setItem(sigRow, 4, tmp5); + sig_list_->setItem(sig_row, 4, tmp5); - sigRow++; + sig_row++; } break; @@ -316,21 +302,22 @@ void KeyPairUIDTab::slot_add_sign() { if (selected_uids->empty()) { QMessageBox::information( - nullptr, _("Invalid Operation"), - _("Please select one or more UIDs before doing this operation.")); + nullptr, tr("Invalid Operation"), + tr("Please select one or more UIDs before doing this operation.")); return; } - auto keySignDialog = + auto* key_sign_dialog = new KeyUIDSignDialog(m_key_, std::move(selected_uids), this); - keySignDialog->show(); + key_sign_dialog->show(); } -UIDArgsListPtr KeyPairUIDTab::get_uid_checked() { +auto KeyPairUIDTab::get_uid_checked() -> UIDArgsListPtr { auto selected_uids = std::make_unique<UIDArgsList>(); for (int i = 0; i < uid_list_->rowCount(); i++) { - if (uid_list_->item(i, 0)->checkState() == Qt::Checked) + if (uid_list_->item(i, 0)->checkState() == Qt::Checked) { selected_uids->push_back(buffered_uids_[i].GetUID()); + } } return selected_uids; } @@ -338,33 +325,34 @@ UIDArgsListPtr KeyPairUIDTab::get_uid_checked() { void KeyPairUIDTab::create_manage_uid_menu() { manage_selected_uid_menu_ = new QMenu(this); - auto* signUIDAct = new QAction(_("Sign Selected UID(s)"), this); - connect(signUIDAct, &QAction::triggered, this, &KeyPairUIDTab::slot_add_sign); - auto* delUIDAct = new QAction(_("Delete Selected UID(s)"), this); - connect(delUIDAct, &QAction::triggered, this, &KeyPairUIDTab::slot_del_uid); + auto* sign_uid_act = new QAction(tr("Sign Selected UID(s)"), this); + connect(sign_uid_act, &QAction::triggered, this, + &KeyPairUIDTab::slot_add_sign); + auto* del_uid_act = new QAction(tr("Delete Selected UID(s)"), this); + connect(del_uid_act, &QAction::triggered, this, &KeyPairUIDTab::slot_del_uid); if (m_key_.IsHasMasterKey()) { - manage_selected_uid_menu_->addAction(signUIDAct); - manage_selected_uid_menu_->addAction(delUIDAct); + manage_selected_uid_menu_->addAction(sign_uid_act); + manage_selected_uid_menu_->addAction(del_uid_act); } } void KeyPairUIDTab::slot_add_uid() { - auto keyNewUIDDialog = new KeyNewUIDDialog(m_key_.GetId(), this); - connect(keyNewUIDDialog, &KeyNewUIDDialog::finished, this, + auto* key_new_uid_dialog = new KeyNewUIDDialog(m_key_.GetId(), this); + connect(key_new_uid_dialog, &KeyNewUIDDialog::finished, this, &KeyPairUIDTab::slot_add_uid_result); - connect(keyNewUIDDialog, &KeyNewUIDDialog::finished, keyNewUIDDialog, + connect(key_new_uid_dialog, &KeyNewUIDDialog::finished, key_new_uid_dialog, &KeyPairUIDTab::deleteLater); - keyNewUIDDialog->show(); + key_new_uid_dialog->show(); } void KeyPairUIDTab::slot_add_uid_result(int result) { if (result == 1) { - QMessageBox::information(nullptr, _("Successful Operation"), - _("Successfully added a new UID.")); + QMessageBox::information(nullptr, tr("Successful Operation"), + tr("Successfully added a new UID.")); } else if (result == -1) { - QMessageBox::critical(nullptr, _("Operation Failed"), - _("An error occurred during the operation.")); + QMessageBox::critical(nullptr, tr("Operation Failed"), + tr("An error occurred during the operation.")); } } @@ -373,34 +361,33 @@ void KeyPairUIDTab::slot_del_uid() { if (selected_uids->empty()) { QMessageBox::information( - nullptr, _("Invalid Operation"), - _("Please select one or more UIDs before doing this operation.")); + nullptr, tr("Invalid Operation"), + tr("Please select one or more UIDs before doing this operation.")); return; } QString keynames; for (auto& uid : *selected_uids) { - keynames.append(QString::fromStdString(uid)); + keynames.append(uid); keynames.append("<br/>"); } int ret = QMessageBox::warning( - this, _("Deleting UIDs"), + this, tr("Deleting UIDs"), "<b>" + QString( - _("Are you sure that you want to delete the following UIDs?")) + + tr("Are you sure that you want to delete the following UIDs?")) + "</b><br/><br/>" + keynames + +"<br/>" + - _("The action can not be undone."), + tr("The action can not be undone."), QMessageBox::No | QMessageBox::Yes); if (ret == QMessageBox::Yes) { for (const auto& uid : *selected_uids) { - SPDLOG_DEBUG("uid: {}", uid); + GF_UI_LOG_DEBUG("uid: {}", uid); if (!GpgUIDOperator::GetInstance().RevUID(m_key_, uid)) { QMessageBox::critical( - nullptr, _("Operation Failed"), - QString(_("An error occurred during the delete %1 operation.")) - .arg(uid.c_str())); + nullptr, tr("Operation Failed"), + tr("An error occurred during the delete %1 operation.").arg(uid)); } } emit SignalUpdateUIDInfo(); @@ -411,37 +398,37 @@ void KeyPairUIDTab::slot_set_primary_uid() { auto selected_uids = get_uid_selected(); if (selected_uids->empty()) { - auto emptyUIDMsg = new QMessageBox(); - emptyUIDMsg->setText("Please select one UID before doing this operation."); - emptyUIDMsg->exec(); + auto* empty_uid_msg = new QMessageBox(); + empty_uid_msg->setText( + "Please select one UID before doing this operation."); + empty_uid_msg->exec(); return; } QString keynames; - keynames.append(QString::fromStdString(selected_uids->front())); + keynames.append(selected_uids->front()); keynames.append("<br/>"); int ret = QMessageBox::warning( - this, _("Set Primary UID"), - "<b>" + - QString(_("Are you sure that you want to set the Primary UID to?")) + + this, tr("Set Primary UID"), + "<b>" + tr("Are you sure that you want to set the Primary UID to?") + "</b><br/><br/>" + keynames + +"<br/>" + - _("The action can not be undone."), + tr("The action can not be undone."), QMessageBox::No | QMessageBox::Yes); if (ret == QMessageBox::Yes) { if (!GpgUIDOperator::GetInstance().SetPrimaryUID(m_key_, selected_uids->front())) { - QMessageBox::critical(nullptr, _("Operation Failed"), - _("An error occurred during the operation.")); + QMessageBox::critical(nullptr, tr("Operation Failed"), + tr("An error occurred during the operation.")); } else { emit SignalUpdateUIDInfo(); } } } -UIDArgsListPtr KeyPairUIDTab::get_uid_selected() { +auto KeyPairUIDTab::get_uid_selected() -> UIDArgsListPtr { auto uids = std::make_unique<UIDArgsList>(); for (int i = 0; i < uid_list_->rowCount(); i++) { if (uid_list_->item(i, 0)->isSelected()) { @@ -451,7 +438,7 @@ UIDArgsListPtr KeyPairUIDTab::get_uid_selected() { return uids; } -SignIdArgsListPtr KeyPairUIDTab::get_sign_selected() { +auto KeyPairUIDTab::get_sign_selected() -> SignIdArgsListPtr { auto signatures = std::make_unique<SignIdArgsList>(); for (int i = 0; i < sig_list_->rowCount(); i++) { if (sig_list_->item(i, 0)->isSelected()) { @@ -465,20 +452,20 @@ SignIdArgsListPtr KeyPairUIDTab::get_sign_selected() { void KeyPairUIDTab::create_uid_popup_menu() { uid_popup_menu_ = new QMenu(this); - auto* serPrimaryUIDAct = new QAction(_("Set As Primary"), this); - connect(serPrimaryUIDAct, &QAction::triggered, this, + auto* ser_primary_uid_act = new QAction(tr("Set As Primary"), this); + connect(ser_primary_uid_act, &QAction::triggered, this, &KeyPairUIDTab::slot_set_primary_uid); - auto* signUIDAct = new QAction(_("Sign UID"), this); - connect(signUIDAct, &QAction::triggered, this, + auto* sign_uid_act = new QAction(tr("Sign UID"), this); + connect(sign_uid_act, &QAction::triggered, this, &KeyPairUIDTab::slot_add_sign_single); - auto* delUIDAct = new QAction(_("Delete UID"), this); - connect(delUIDAct, &QAction::triggered, this, + auto* del_uid_act = new QAction(tr("Delete UID"), this); + connect(del_uid_act, &QAction::triggered, this, &KeyPairUIDTab::slot_del_uid_single); if (m_key_.IsHasMasterKey()) { - uid_popup_menu_->addAction(serPrimaryUIDAct); - uid_popup_menu_->addAction(signUIDAct); - uid_popup_menu_->addAction(delUIDAct); + uid_popup_menu_->addAction(ser_primary_uid_act); + uid_popup_menu_->addAction(sign_uid_act); + uid_popup_menu_->addAction(del_uid_act); } } @@ -494,43 +481,43 @@ void KeyPairUIDTab::slot_add_sign_single() { if (selected_uids->empty()) { QMessageBox::information( - nullptr, _("Invalid Operation"), - _("Please select one UID before doing this operation.")); + nullptr, tr("Invalid Operation"), + tr("Please select one UID before doing this operation.")); return; } - auto keySignDialog = + auto* key_sign_dialog = new KeyUIDSignDialog(m_key_, std::move(selected_uids), this); - keySignDialog->show(); + key_sign_dialog->show(); } void KeyPairUIDTab::slot_del_uid_single() { auto selected_uids = get_uid_selected(); if (selected_uids->empty()) { QMessageBox::information( - nullptr, _("Invalid Operation"), - _("Please select one UID before doing this operation.")); + nullptr, tr("Invalid Operation"), + tr("Please select one UID before doing this operation.")); return; } QString keynames; - keynames.append(QString::fromStdString(selected_uids->front())); + keynames.append(selected_uids->front()); keynames.append("<br/>"); int ret = QMessageBox::warning( - this, _("Deleting UID"), + this, tr("Deleting UID"), "<b>" + QString( - _("Are you sure that you want to delete the following uid?")) + + tr("Are you sure that you want to delete the following uid?")) + "</b><br/><br/>" + keynames + +"<br/>" + - _("The action can not be undone."), + tr("The action can not be undone."), QMessageBox::No | QMessageBox::Yes); if (ret == QMessageBox::Yes) { if (!GpgUIDOperator::GetInstance().RevUID(m_key_, selected_uids->front())) { - QMessageBox::critical(nullptr, _("Operation Failed"), - _("An error occurred during the operation.")); + QMessageBox::critical(nullptr, tr("Operation Failed"), + tr("An error occurred during the operation.")); } else { emit SignalUpdateUIDInfo(); } @@ -540,18 +527,19 @@ void KeyPairUIDTab::slot_del_uid_single() { void KeyPairUIDTab::create_sign_popup_menu() { sign_popup_menu_ = new QMenu(this); - auto* delSignAct = new QAction(_("Delete(Revoke) Key Signature"), this); - connect(delSignAct, &QAction::triggered, this, &KeyPairUIDTab::slot_del_sign); + auto* del_sign_act = new QAction(tr("Delete(Revoke) Key Signature"), this); + connect(del_sign_act, &QAction::triggered, this, + &KeyPairUIDTab::slot_del_sign); - sign_popup_menu_->addAction(delSignAct); + sign_popup_menu_->addAction(del_sign_act); } void KeyPairUIDTab::slot_del_sign() { auto selected_signs = get_sign_selected(); if (selected_signs->empty()) { QMessageBox::information( - nullptr, _("Invalid Operation"), - _("Please select one Key Signature before doing this operation.")); + nullptr, tr("Invalid Operation"), + tr("Please select one Key Signature before doing this operation.")); return; } @@ -559,30 +547,29 @@ void KeyPairUIDTab::slot_del_sign() { .GetKey(selected_signs->front().first) .IsGood()) { QMessageBox::critical( - nullptr, _("Invalid Operation"), - _("To delete the signature, you need to have its corresponding public " - "key in the local database.")); + nullptr, tr("Invalid Operation"), + tr("To delete the signature, you need to have its corresponding public " + "key in the local database.")); return; } QString keynames; - keynames.append(QString::fromStdString(selected_signs->front().second)); + keynames.append(selected_signs->front().second); keynames.append("<br/>"); - int ret = - QMessageBox::warning(this, _("Deleting Key Signature"), - "<b>" + - QString(_("Are you sure that you want to delete " - "the following signature?")) + - "</b><br/><br/>" + keynames + +"<br/>" + - _("The action can not be undone."), - QMessageBox::No | QMessageBox::Yes); + int ret = QMessageBox::warning(this, tr("Deleting Key Signature"), + "<b>" + + tr("Are you sure that you want to delete " + "the following signature?") + + "</b><br/><br/>" + keynames + +"<br/>" + + tr("The action can not be undone."), + QMessageBox::No | QMessageBox::Yes); if (ret == QMessageBox::Yes) { if (!GpgKeyManager::GetInstance().RevSign(m_key_, selected_signs)) { - QMessageBox::critical(nullptr, _("Operation Failed"), - _("An error occurred during the operation.")); + QMessageBox::critical(nullptr, tr("Operation Failed"), + tr("An error occurred during the operation.")); } } } diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.h b/src/ui/dialog/keypair_details/KeyPairUIDTab.h index fae8f9f2..3655511d 100644 --- a/src/ui/dialog/keypair_details/KeyPairUIDTab.h +++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,17 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYPAIRUIDTAB_H -#define GPGFRONTEND_KEYPAIRUIDTAB_H +#pragma once #include "KeyNewUIDDialog.h" #include "KeyUIDSignDialog.h" -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "ui/GpgFrontendUI.h" namespace GpgFrontend::UI { @@ -46,7 +45,7 @@ class KeyPairUIDTab : public QWidget { * @param key_id * @param parent */ - KeyPairUIDTab(const std::string& key_id, QWidget* parent); + KeyPairUIDTab(const QString& key_id, QWidget* parent); signals: @@ -203,5 +202,3 @@ class KeyPairUIDTab : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYPAIRUIDTAB_H diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp index 89d2ce74..22d1db2a 100644 --- a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp +++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,12 +28,11 @@ #include "KeySetExpireDateDialog.h" -#include <utility> - #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "ui/SignalStation.h" +#include "core/utils/GpgUtils.h" +#include "ui/UISignalStation.h" #include "ui_ModifiedExpirationDateTime.h" namespace GpgFrontend::UI { @@ -41,49 +40,46 @@ namespace GpgFrontend::UI { KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id, QWidget* parent) : GeneralDialog(typeid(KeySetExpireDateDialog).name(), parent), - ui_(std::make_shared<Ui_ModifiedExpirationDateTime>()), + ui_(GpgFrontend::SecureCreateSharedObject< + Ui_ModifiedExpirationDateTime>()), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { init(); } KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id, - std::string subkey_fpr, + QString subkey_fpr, QWidget* parent) : GeneralDialog(typeid(KeySetExpireDateDialog).name(), parent), - ui_(std::make_shared<Ui_ModifiedExpirationDateTime>()), + ui_(GpgFrontend::SecureCreateSharedObject< + Ui_ModifiedExpirationDateTime>()), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)), m_subkey_(std::move(subkey_fpr)) { init(); } void KeySetExpireDateDialog::slot_confirm() { - SPDLOG_DEBUG("called: {} {}", ui_->dateEdit->date().toString().toStdString(), - ui_->timeEdit->time().toString().toStdString()); + GF_UI_LOG_DEBUG("called: {} {}", + ui_->dateEdit->date().toString().toStdString(), + ui_->timeEdit->time().toString().toStdString()); auto datetime = QDateTime(ui_->dateEdit->date(), ui_->timeEdit->time()); - std::unique_ptr<boost::posix_time::ptime> expires = nullptr; + std::unique_ptr<QDateTime> expires = nullptr; if (ui_->noExpirationCheckBox->checkState() == Qt::Unchecked) { -#ifdef GPGFRONTEND_GUI_QT6 - expires = std::make_unique<boost::posix_time::ptime>( - boost::posix_time::from_time_t( - datetime.toLocalTime().toSecsSinceEpoch())); -#else - expires = std::make_unique<boost::posix_time::ptime>( - boost::posix_time::from_time_t(datetime.toLocalTime().toTime_t())); -#endif - SPDLOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, - to_iso_string(*expires)); + expires = std::make_unique<QDateTime>(datetime.toLocalTime()); + + GF_UI_LOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, + expires->toSecsSinceEpoch()); } else { - SPDLOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, "Non Expired"); + GF_UI_LOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, "Non Expired"); } auto err = GpgKeyOpera::GetInstance().SetExpire(m_key_, m_subkey_, expires); - if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) { + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { auto* msg_box = new QMessageBox(qobject_cast<QWidget*>(this->parent())); msg_box->setAttribute(Qt::WA_DeleteOnClose); msg_box->setStandardButtons(QMessageBox::Ok); - msg_box->setWindowTitle(_("Success")); - msg_box->setText(_("The expire date of the key pair has been updated.")); + msg_box->setWindowTitle(tr("Success")); + msg_box->setText(tr("The expire date of the key pair has been updated.")); msg_box->setModal(true); msg_box->open(); @@ -92,24 +88,19 @@ void KeySetExpireDateDialog::slot_confirm() { this->close(); } else { QMessageBox::critical( - this, _("Failure"), - _("Failed to update the expire date of the key pair.")); + this, tr("Failure"), + tr("Failed to update the expire date of the key pair.")); } } void KeySetExpireDateDialog::init() { ui_->setupUi(this); - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); - bool longer_expiration_date = false; - try { - longer_expiration_date = settings.lookup("general.longer_expiration_date"); - SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date); - - } catch (...) { - SPDLOG_ERROR("setting operation error: longer_expiration_date"); - } + bool longer_expiration_date = longer_expiration_date = + settings.value("basic/longer_expiration_date").toBool(); auto max_date_time = longer_expiration_date @@ -122,13 +113,8 @@ void KeySetExpireDateDialog::init() { ui_->dateEdit->setMinimumDateTime(min_date_time); // set default date time to expire date time -#ifdef GPGFRONTEND_GUI_QT6 - auto current_expire_time = - QDateTime::fromSecsSinceEpoch(to_time_t(m_key_.GetExpireTime())); -#else - auto current_expire_time = - QDateTime::fromTime_t(to_time_t(m_key_.GetExpireTime())); -#endif + auto current_expire_time = m_key_.GetExpireTime(); + ui_->dateEdit->setDateTime(current_expire_time); ui_->timeEdit->setDateTime(current_expire_time); @@ -137,16 +123,25 @@ void KeySetExpireDateDialog::init() { connect(ui_->button_box_, &QDialogButtonBox::accepted, this, &KeySetExpireDateDialog::slot_confirm); connect(this, &KeySetExpireDateDialog::SignalKeyExpireDateUpdated, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); - - ui_->titleLabel->setText(_("Modified Expiration Date (Local Time)")); - ui_->label->setText( - _("Tips: For the sake of security, the key is valid for up to two years. " - "If you are an expert user, please unlock it for a longer time in the " - "settings.")); - ui_->noExpirationCheckBox->setText(_("No Expiration")); - this->setWindowTitle(_("Modified Expiration Date")); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); + + if (m_key_.GetExpireTime().toSecsSinceEpoch() == 0) { + ui_->noExpirationCheckBox->setCheckState(Qt::Checked); + } else { + ui_->dateEdit->setDateTime(m_key_.GetExpireTime()); + ui_->timeEdit->setDateTime(m_key_.GetExpireTime()); + } + + ui_->titleLabel->setText(tr("Modified Expiration Date (Local Time)")); + ui_->label->setText(tr( + "Tips: For the sake of security, the key is valid for up to two years. " + "If you are an expert user, please unlock it for a longer time in the " + "settings.")); + ui_->noExpirationCheckBox->setText(tr("No Expiration")); + this->setWindowTitle(tr("Modified Expiration Date")); + this->setAttribute(Qt::WA_DeleteOnClose); + this->setModal(true); } void KeySetExpireDateDialog::slot_non_expired_checked(int state) { diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h index 3cd6cd01..633840ac 100644 --- a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h +++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,18 +20,17 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H -#define GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H +#pragma once -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "core/model/GpgKey.h" -#include "core/model/GpgSubKey.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -58,7 +57,7 @@ class KeySetExpireDateDialog : public GeneralDialog { * @param subkey_fpr * @param parent */ - explicit KeySetExpireDateDialog(const KeyId& key_id, std::string subkey_fpr, + explicit KeySetExpireDateDialog(const KeyId& key_id, QString subkey_fpr, QWidget* parent = nullptr); signals: @@ -95,5 +94,3 @@ class KeySetExpireDateDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp index 12da3284..ba12f232 100644 --- a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp +++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,16 +19,19 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "KeyUIDSignDialog.h" +#include "core/GpgModel.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyManager.h" -#include "ui/SignalStation.h" +#include "ui/UISignalStation.h" namespace GpgFrontend::UI { @@ -40,15 +43,12 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, const auto key_id = m_key_.GetId(); m_key_list_ = new KeyList(KeyMenuAbility::NONE, this); m_key_list_->AddListGroupTab( - _("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY, + tr("Signers"), "signers", KeyListRow::ONLY_SECRET_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress, [key_id](const GpgKey& key, const KeyTable&) -> bool { - if (key.IsDisabled() || !key.IsHasCertificationCapability() || - !key.IsHasMasterKey() || key.IsExpired() || key.IsRevoked() || - key_id == key.GetId()) - return false; - else - return true; + return !(key.IsDisabled() || !key.IsHasCertificationCapability() || + !key.IsHasMasterKey() || key.IsExpired() || key.IsRevoked() || + key_id == key.GetId()); }); m_key_list_->SlotRefresh(); @@ -83,7 +83,7 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, layout->addWidget(m_key_list_, 0, 0); layout->addWidget(sign_key_button_, 2, 0, Qt::AlignRight); - timeLayout->addWidget(new QLabel(_("Expire Date")), 0, 0); + timeLayout->addWidget(new QLabel(tr("Expire Date")), 0, 0); timeLayout->addWidget(expires_edit_, 0, 1); timeLayout->addWidget(non_expire_check_, 0, 2); layout->addLayout(timeLayout, 1, 0); @@ -93,14 +93,14 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, this->setLayout(layout); this->setModal(true); - this->setWindowTitle(_("Sign For Key's UID(s)")); + this->setWindowTitle(tr("Sign For Key's UID(s)")); this->adjustSize(); setAttribute(Qt::WA_DeleteOnClose, true); connect(this, &KeyUIDSignDialog::SignalKeyUIDSignUpdate, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); } void KeyUIDSignDialog::slot_sign_key(bool clicked) { @@ -108,29 +108,23 @@ void KeyUIDSignDialog::slot_sign_key(bool clicked) { auto key_ids = m_key_list_->GetChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - SPDLOG_DEBUG("key info got"); -#ifdef GPGFRONTEND_GUI_QT6 - auto expires = - std::make_unique<boost::posix_time::ptime>(boost::posix_time::from_time_t( - expires_edit_->dateTime().toSecsSinceEpoch())); -#else - auto expires = std::make_unique<boost::posix_time::ptime>( - boost::posix_time::from_time_t(expires_edit_->dateTime().toTime_t())); -#endif - - SPDLOG_DEBUG("sign start"); + GF_UI_LOG_DEBUG("key info got"); + auto expires = std::make_unique<QDateTime>(expires_edit_->dateTime()); + + GF_UI_LOG_DEBUG("sign start"); for (const auto& uid : *m_uids_) { - SPDLOG_DEBUG("sign uid: {}", uid); + GF_UI_LOG_DEBUG("sign uid: {}", uid); // Sign For mKey if (!GpgKeyManager::GetInstance().SignKey(m_key_, *keys, uid, expires)) { QMessageBox::critical( - nullptr, _("Unsuccessful Operation"), - QString(_("Signature operation failed for UID %1")).arg(uid.c_str())); + nullptr, tr("Unsuccessful Operation"), + tr("Signature operation failed for UID %1").arg(uid)); } } - QMessageBox::information(nullptr, _("Operation Complete"), - _("The signature operation of the UID is complete")); + QMessageBox::information( + nullptr, tr("Operation Complete"), + tr("The signature operation of the UID is complete")); this->close(); emit SignalKeyUIDSignUpdate(); } diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.h b/src/ui/dialog/keypair_details/KeyUIDSignDialog.h index bfaff6d2..35d722ad 100644 --- a/src/ui/dialog/keypair_details/KeyUIDSignDialog.h +++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,16 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYUIDSIGNDIALOG_H -#define GPGFRONTEND_KEYUIDSIGNDIALOG_H +#pragma once -#include "core/GpgContext.h" +#include "core/function/gpg/GpgContext.h" #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" #include "ui/widgets/KeyList.h" @@ -74,5 +75,3 @@ class KeyUIDSignDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYUIDSIGNDIALOG_H diff --git a/src/ui/dialog/settings/SettingsAdvanced.cpp b/src/ui/dialog/settings/SettingsAdvanced.cpp deleted file mode 100644 index 9a02f473..00000000 --- a/src/ui/dialog/settings/SettingsAdvanced.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "SettingsAdvanced.h" - -#include "core/function/GlobalSettingStation.h" - -namespace GpgFrontend::UI { - -AdvancedTab::AdvancedTab(QWidget* parent) : QWidget(parent) { - auto* stegano_box = new QGroupBox(_("Show Steganography Options")); - auto* stegano_box_layout = new QHBoxLayout(); - stegano_check_box_ = new QCheckBox(_("Show Steganography Options."), this); - stegano_box_layout->addWidget(stegano_check_box_); - stegano_box->setLayout(stegano_box_layout); - - auto* pubkey_exchange_box = new QGroupBox(_("Pubkey Exchange")); - auto* pubkey_exchange_box_layout = new QHBoxLayout(); - auto_pubkey_exchange_check_box_ = - new QCheckBox(_("Auto Pubkey Exchange"), this); - pubkey_exchange_box_layout->addWidget(auto_pubkey_exchange_check_box_); - pubkey_exchange_box->setLayout(pubkey_exchange_box_layout); - - auto* main_layout = new QVBoxLayout; - main_layout->addWidget(stegano_box); - main_layout->addWidget(pubkey_exchange_box); - SetSettings(); - main_layout->addStretch(1); - setLayout(main_layout); -} - -void AdvancedTab::SetSettings() { - int stegano_checked = GlobalSettingStation::GetInstance().LookupSettings( - "advanced.stegano_checked", false); - if (stegano_checked) stegano_check_box_->setCheckState(Qt::Checked); - - int auto_pubkey_exchange_checked = - GlobalSettingStation::GetInstance().LookupSettings( - "advanced.auto_pubkey_exchange_checked", false); - if (auto_pubkey_exchange_checked) - auto_pubkey_exchange_check_box_->setCheckState(Qt::Checked); -} - -void AdvancedTab::ApplySettings() { - auto& settings = - GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("advanced") || - settings.lookup("advanced").getType() != libconfig::Setting::TypeGroup) - settings.add("advanced", libconfig::Setting::TypeGroup); - - auto& advanced = settings["advanced"]; - - if (!advanced.exists("stegano_checked")) - advanced.add("stegano_checked", libconfig::Setting::TypeBoolean) = - stegano_check_box_->isChecked(); - else { - advanced["stegano_checked"] = stegano_check_box_->isChecked(); - } - - if (!advanced.exists("auto_pubkey_exchange_checked")) - advanced.add("auto_pubkey_exchange_checked", - libconfig::Setting::TypeBoolean) = - auto_pubkey_exchange_check_box_->isChecked(); - else { - advanced["auto_pubkey_exchange_checked"] = - auto_pubkey_exchange_check_box_->isChecked(); - } -} - -} // namespace GpgFrontend::UI diff --git a/src/ui/dialog/settings/SettingsAppearance.cpp b/src/ui/dialog/settings/SettingsAppearance.cpp index b5fbc6a3..d4f97c4c 100644 --- a/src/ui/dialog/settings/SettingsAppearance.cpp +++ b/src/ui/dialog/settings/SettingsAppearance.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,36 +28,37 @@ #include "SettingsAppearance.h" -#include "core/function/GlobalSettingStation.h" +#include "core/utils/MemoryUtils.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/AppearanceSO.h" #include "ui_AppearanceSettings.h" namespace GpgFrontend::UI { AppearanceTab::AppearanceTab(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_AppearanceSettings>()) { + : QWidget(parent), ui_(SecureCreateSharedObject<Ui_AppearanceSettings>()) { ui_->setupUi(this); - ui_->iconSizeBox->setTitle(_("Icon Size")); - ui_->smallRadioButton->setText(_("small")); - ui_->mediumRadioButton->setText(_("medium")); - ui_->largeRadioButton->setText(_("large")); + ui_->iconSizeBox->setTitle(tr("Icon Size")); + ui_->smallRadioButton->setText(tr("small")); + ui_->mediumRadioButton->setText(tr("medium")); + ui_->largeRadioButton->setText(tr("large")); - ui_->iconStyleBox->setTitle(_("Icon Style")); - ui_->justTextRadioButton->setText(_("just text")); - ui_->justIconRadioButton->setText(_("just icons")); - ui_->textAndIconsRadioButton->setText(_("text and icons")); + ui_->iconStyleBox->setTitle(tr("Icon Style")); + ui_->justTextRadioButton->setText(tr("just text")); + ui_->justIconRadioButton->setText(tr("just icons")); + ui_->textAndIconsRadioButton->setText(tr("text and icons")); - ui_->windowStateBox->setTitle(_("Window State")); + ui_->windowStateBox->setTitle(tr("Window State")); ui_->windowStateCheckBox->setText( - _("Save window size and position on exit.")); + tr("Save window size and position on exit.")); - ui_->textEditorBox->setTitle(_("Text Editor")); - ui_->fontSizeTextEditorLabel->setText(_("Font Size in Text Editor")); + ui_->textEditorBox->setTitle(tr("Text Editor")); + ui_->fontSizeTextEditorLabel->setText(tr("Font Size in Text Editor")); - ui_->informationBoardBox->setTitle(_("Information Board")); + ui_->informationBoardBox->setTitle(tr("Information Board")); ui_->fontSizeInformationBoardLabel->setText( - _("Font Size in Information Board")); + tr("Font Size in Information Board")); icon_size_group_ = new QButtonGroup(this); icon_size_group_->addButton(ui_->smallRadioButton, 1); @@ -73,12 +74,10 @@ AppearanceTab::AppearanceTab(QWidget* parent) } void AppearanceTab::SetSettings() { - SettingsObject general_settings_state("general_settings_state"); - - int width = general_settings_state.Check("icon_size").Check("width", 24), - height = general_settings_state.Check("icon_size").Check("height", 24); + AppearanceSO appearance(SettingsObject("general_settings_state")); - auto icon_size = QSize(width, height); + auto icon_size = + QSize(appearance.tool_bar_icon_width, appearance.tool_bar_icon_height); switch (icon_size.width()) { case 12: @@ -90,14 +89,12 @@ void AppearanceTab::SetSettings() { case 32: ui_->largeRadioButton->setChecked(true); break; + default: + ui_->smallRadioButton->setChecked(true); + break; } - // icon_style - int s_icon_style = - general_settings_state.Check("icon_style", Qt::ToolButtonTextUnderIcon); - auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); - - switch (icon_style) { + switch (appearance.tool_bar_button_style) { case Qt::ToolButtonTextOnly: ui_->justTextRadioButton->setChecked(true); break; @@ -111,24 +108,26 @@ void AppearanceTab::SetSettings() { break; } - bool window_save = general_settings_state.Check("window_save", true); - if (window_save) ui_->windowStateCheckBox->setCheckState(Qt::Checked); + if (appearance.save_window_state) { + ui_->windowStateCheckBox->setCheckState(Qt::Checked); + } - auto info_board_info_font_size = - general_settings_state.Check("info_board").Check("font_size", 10); - if (info_board_info_font_size < 9 || info_board_info_font_size > 18) + auto info_board_info_font_size = appearance.info_board_font_size; + if (info_board_info_font_size < 9 || info_board_info_font_size > 18) { info_board_info_font_size = 10; + } ui_->fontSizeInformationBoardSpinBox->setValue(info_board_info_font_size); - auto text_editor_info_font_size = - general_settings_state.Check("text_editor").Check("font_size", 10); - if (text_editor_info_font_size < 9 || text_editor_info_font_size > 18) + auto text_editor_info_font_size = appearance.text_editor_font_size; + if (text_editor_info_font_size < 9 || text_editor_info_font_size > 18) { text_editor_info_font_size = 10; + } ui_->fontSizeTextEditorLabelSpinBox->setValue(text_editor_info_font_size); } void AppearanceTab::ApplySettings() { SettingsObject general_settings_state("general_settings_state"); + AppearanceSO appearance(general_settings_state); int icon_size = 24; switch (icon_size_group_->checkedId()) { @@ -143,8 +142,8 @@ void AppearanceTab::ApplySettings() { break; } - general_settings_state["icon_size"]["width"] = icon_size; - general_settings_state["icon_size"]["height"] = icon_size; + appearance.tool_bar_icon_height = icon_size; + appearance.tool_bar_icon_width = icon_size; auto icon_style = Qt::ToolButtonTextUnderIcon; switch (icon_style_group_->checkedId()) { @@ -157,17 +156,19 @@ void AppearanceTab::ApplySettings() { case 3: icon_style = Qt::ToolButtonTextUnderIcon; break; + default: + icon_style = Qt::ToolButtonTextOnly; + break; } + appearance.tool_bar_button_style = icon_style; - general_settings_state["icon_style"] = icon_style; - - general_settings_state["window_save"] = ui_->windowStateCheckBox->isChecked(); - - general_settings_state["info_board"]["font_size"] = + appearance.save_window_state = ui_->windowStateCheckBox->isChecked(); + appearance.info_board_font_size = ui_->fontSizeInformationBoardSpinBox->value(); - - general_settings_state["text_editor"]["font_size"] = + appearance.text_editor_font_size = ui_->fontSizeTextEditorLabelSpinBox->value(); + + general_settings_state.Store(appearance.ToJson()); } } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/settings/SettingsAppearance.h b/src/ui/dialog/settings/SettingsAppearance.h index 8a38c666..6d426934 100644 --- a/src/ui/dialog/settings/SettingsAppearance.h +++ b/src/ui/dialog/settings/SettingsAppearance.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSAPPEARANCE_H -#define GPGFRONTEND_SETTINGSAPPEARANCE_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -61,7 +60,7 @@ class AppearanceTab : public QWidget { private: std::shared_ptr<Ui_AppearanceSettings> ui_; ///< - QButtonGroup* icon_style_group_; ///< + QButtonGroup* icon_style_group_; ///< QButtonGroup* icon_size_group_; signals: @@ -75,5 +74,3 @@ class AppearanceTab : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SETTINGSAPPEARANCE_H diff --git a/src/ui/dialog/settings/SettingsDialog.cpp b/src/ui/dialog/settings/SettingsDialog.cpp index d484207a..a1ac1885 100644 --- a/src/ui/dialog/settings/SettingsDialog.cpp +++ b/src/ui/dialog/settings/SettingsDialog.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,13 +28,13 @@ #include "SettingsDialog.h" -#include "SettingsAdvanced.h" -#include "SettingsAppearance.h" -#include "SettingsGeneral.h" -#include "SettingsKeyServer.h" -#include "SettingsNetwork.h" #include "core/GpgConstants.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" +#include "ui/dialog/settings/SettingsAppearance.h" +#include "ui/dialog/settings/SettingsGeneral.h" +#include "ui/dialog/settings/SettingsKeyServer.h" +#include "ui/dialog/settings/SettingsNetwork.h" #include "ui/main_window/MainWindow.h" namespace GpgFrontend::UI { @@ -47,14 +47,14 @@ SettingsDialog::SettingsDialog(QWidget* parent) key_server_tab_ = new KeyserverTab(); network_tab_ = new NetworkTab(); - auto* mainLayout = new QVBoxLayout; - mainLayout->addWidget(tab_widget_); - mainLayout->stretch(0); + auto* main_layout = new QVBoxLayout(); + main_layout->addWidget(tab_widget_); + main_layout->stretch(0); - tab_widget_->addTab(general_tab_, _("General")); - tab_widget_->addTab(appearance_tab_, _("Appearance")); - tab_widget_->addTab(key_server_tab_, _("Key Server")); - tab_widget_->addTab(network_tab_, _("Network")); + tab_widget_->addTab(general_tab_, tr("General")); + tab_widget_->addTab(appearance_tab_, tr("Appearance")); + tab_widget_->addTab(key_server_tab_, tr("Key Server")); + tab_widget_->addTab(network_tab_, tr("Network")); #ifndef MACOS button_box_ = @@ -65,14 +65,14 @@ SettingsDialog::SettingsDialog(QWidget* parent) &SettingsDialog::reject); mainLayout->addWidget(button_box_); mainLayout->stretch(0); - setWindowTitle(_("Settings")); + setWindowTitle(tr("Settings")); #else connect(this, &QDialog::finished, this, &SettingsDialog::SlotAccept); connect(this, &QDialog::finished, this, &SettingsDialog::deleteLater); - setWindowTitle(_("Preference")); + setWindowTitle(tr("Preference")); #endif - setLayout(mainLayout); + setLayout(main_layout); // slots for handling the restart needed member this->slot_set_restart_needed(0); @@ -80,16 +80,17 @@ SettingsDialog::SettingsDialog(QWidget* parent) // restart ui connect(general_tab_, &GeneralTab::SignalRestartNeeded, this, [=](bool needed) { - if (needed && restart_needed_ < RESTART_CODE) { - this->restart_needed_ = RESTART_CODE; + if (needed && restart_needed_ < kRestartCode) { + this->restart_needed_ = kRestartCode; } }); // restart core and ui connect(general_tab_, &GeneralTab::SignalDeepRestartNeeded, this, [=](bool needed) { - if (needed && restart_needed_ < DEEP_RESTART_CODE) - this->restart_needed_ = DEEP_RESTART_CODE; + if (needed && restart_needed_ < kDeepRestartCode) { + this->restart_needed_ = kDeepRestartCode; + } }); // announce main window @@ -101,7 +102,9 @@ SettingsDialog::SettingsDialog(QWidget* parent) this->show(); } -int SettingsDialog::get_restart_needed() const { return this->restart_needed_; } +auto SettingsDialog::get_restart_needed() const -> int { + return this->restart_needed_; +} void SettingsDialog::slot_set_restart_needed(int mode) { this->restart_needed_ = mode; @@ -113,44 +116,31 @@ void SettingsDialog::SlotAccept() { key_server_tab_->ApplySettings(); network_tab_->ApplySettings(); - SPDLOG_DEBUG("apply done"); - - // write settings to filesystem - GlobalSettingStation::GetInstance().SyncSettings(); - - SPDLOG_DEBUG("restart needed: {}", get_restart_needed()); - if (get_restart_needed()) { + GF_UI_LOG_DEBUG("restart needed: {}", get_restart_needed()); + if (get_restart_needed() != 0) { emit SignalRestartNeeded(get_restart_needed()); } close(); } -QHash<QString, QString> SettingsDialog::ListLanguages() { +auto SettingsDialog::ListLanguages() -> QHash<QString, QString> { QHash<QString, QString> languages; + languages.insert(QString(), tr("System Default")); - languages.insert(QString(), _("System Default")); - - auto locale_path = GlobalSettingStation::GetInstance().GetLocaleDir(); + QStringList filenames = QDir(QLatin1String(":/i18n")).entryList(); + for (const auto& file : filenames) { + GF_UI_LOG_DEBUG("get locale from locale directory: {}", file.toStdString()); - auto locale_dir = QDir(QString::fromStdString(locale_path.string())); - QStringList file_names = locale_dir.entryList(QStringList("*")); + auto start = file.indexOf('.') + 1; + auto end = file.lastIndexOf('.'); + if (start < 0 || end < 0 || start >= end) continue; - for (int i = 0; i < file_names.size(); ++i) { - QString locale = file_names[i]; - SPDLOG_DEBUG("locale: {}", locale.toStdString()); - if (locale == "." || locale == "..") continue; + auto locale = file.mid(start, end - start); + QLocale const q_locale(locale); + if (q_locale.nativeTerritoryName().isEmpty()) continue; - // this works in qt 4.8 - QLocale q_locale(locale); - if (q_locale.nativeCountryName().isEmpty()) continue; -#if QT_VERSION < 0x040800 - QString language = - QLocale::languageToString(q_locale.language()) + " (" + locale + - ")"; //+ " (" + QLocale::languageToString(q_locale.language()) + ")"; -#else auto language = q_locale.nativeLanguageName() + " (" + locale + ")"; -#endif - languages.insert(locale, language); + languages.insert(q_locale.name(), language); } return languages; } diff --git a/src/ui/dialog/settings/SettingsDialog.h b/src/ui/dialog/settings/SettingsDialog.h index d28013f4..e59cd611 100644 --- a/src/ui/dialog/settings/SettingsDialog.h +++ b/src/ui/dialog/settings/SettingsDialog.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __SETTINGSDIALOG_H__ -#define __SETTINGSDIALOG_H__ +#pragma once #include "ui/GpgFrontendUI.h" #include "ui/dialog/GeneralDialog.h" @@ -108,5 +107,3 @@ class SettingsDialog : public GeneralDialog { }; } // namespace GpgFrontend::UI - -#endif // __SETTINGSDIALOG_H__ diff --git a/src/ui/dialog/settings/SettingsGeneral.cpp b/src/ui/dialog/settings/SettingsGeneral.cpp index be5190dd..44c66e10 100644 --- a/src/ui/dialog/settings/SettingsGeneral.cpp +++ b/src/ui/dialog/settings/SettingsGeneral.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,224 +28,126 @@ #include "SettingsGeneral.h" -#include "core/GpgContext.h" - -#ifdef MULTI_LANG_SUPPORT #include "SettingsDialog.h" -#endif - +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" #include "ui_GeneralSettings.h" namespace GpgFrontend::UI { GeneralTab::GeneralTab(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_GeneralSettings>()) { + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_GeneralSettings>()) { ui_->setupUi(this); - ui_->cacheBox->setTitle(_("Cache")); - ui_->saveCheckedKeysCheckBox->setText( - _("Save checked private keys on exit and restore them on next start.")); + ui_->cacheBox->setTitle(tr("Cache")); ui_->clearGpgPasswordCacheCheckBox->setText( - _("Clear gpg password cache when closing GpgFrontend.")); + tr("Clear gpg password cache when closing GpgFrontend.")); ui_->restoreTextEditorPageCheckBox->setText( - _("Automatically restore unsaved Text Editor pages after an application " - "crash.")); + tr("Automatically restore unsaved Text Editor pages after an application " + "crash.")); - ui_->importConfirmationBox->setTitle(_("Operation")); + ui_->importConfirmationBox->setTitle(tr("Operation")); ui_->longerKeyExpirationDateCheckBox->setText( - _("Enable to use longer key expiration date.")); + tr("Enable to use longer key expiration date.")); ui_->importConfirmationCheckBox->setText( - _("Import files dropped on the Key List without confirmation.")); + tr("Import files dropped on the Key List without confirmation.")); - ui_->langBox->setTitle(_("Language")); + ui_->langBox->setTitle(tr("Language")); ui_->langNoteLabel->setText( - "<b>" + QString(_("NOTE")) + _(": ") + "</b>" + - _("GpgFrontend will restart automatically if you change the language!")); - - ui_->dataBox->setTitle(_("Data")); - ui_->clearAllLogFilesButton->setText(QString::fromStdString( - (boost::format(_("Clear All Log (Total Size: %s)")) % - GlobalSettingStation::GetInstance().GetLogFilesSize()) - .str())); - ui_->clearAllDataObjectsButton->setText(QString::fromStdString( - (boost::format(_("Clear All Data Objects (Total Size: %s)")) % - GlobalSettingStation::GetInstance().GetDataObjectsFilesSize()) - .str())); - -#ifdef MULTI_LANG_SUPPORT + "<b>" + tr("NOTE") + tr(": ") + "</b>" + + tr("GpgFrontend will restart automatically if you change the language!")); + + ui_->dataBox->setTitle(tr("Data")); + ui_->clearAllLogFilesButton->setText( + tr("Clear All Log (Total Size: %1)") + .arg(GlobalSettingStation::GetInstance().GetLogFilesSize())); + ui_->clearAllDataObjectsButton->setText( + tr("Clear All Data Objects (Total Size: %1)") + .arg(GlobalSettingStation::GetInstance().GetDataObjectsFilesSize())); + lang_ = SettingsDialog::ListLanguages(); for (const auto& l : lang_) { ui_->langSelectBox->addItem(l); } connect(ui_->langSelectBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &GeneralTab::slot_language_changed); -#endif connect(ui_->clearAllLogFilesButton, &QPushButton::clicked, this, [=]() { GlobalSettingStation::GetInstance().ClearAllLogFiles(); - ui_->clearAllLogFilesButton->setText(QString::fromStdString( - (boost::format(_("Clear All Log (Total Size: %s)")) % - GlobalSettingStation::GetInstance().GetLogFilesSize()) - .str())); + ui_->clearAllLogFilesButton->setText( + tr("Clear All Log (Total Size: %1)") + .arg(GlobalSettingStation::GetInstance().GetLogFilesSize())); }); connect(ui_->clearAllDataObjectsButton, &QPushButton::clicked, this, [=]() { QMessageBox::StandardButton reply; reply = QMessageBox::question( - this, _("Confirm"), - _("Are you sure you want to clear all data objects?\nThis will result " - "in " - "loss of all cached form positions, statuses, key servers, etc."), + this, tr("Confirm"), + tr("Are you sure you want to clear all data objects?\nThis will result " + "in loss of all cached form positions, statuses, key servers, etc."), QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { GlobalSettingStation::GetInstance().ClearAllDataObjects(); - ui_->clearAllDataObjectsButton->setText(QString::fromStdString( - (boost::format(_("Clear All Data Objects (Total Size: %s)")) % - GlobalSettingStation::GetInstance().GetDataObjectsFilesSize()) - .str())); + ui_->clearAllDataObjectsButton->setText( + tr("Clear All Data Objects (Total Size: %1)") + .arg(GlobalSettingStation::GetInstance() + .GetDataObjectsFilesSize())); } }); SetSettings(); } -/********************************** - * Read the settings from config - * and set the buttons and checkboxes - * appropriately - **********************************/ void GeneralTab::SetSettings() { - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - - try { - bool save_key_checked = settings.lookup("general.save_key_checked"); - if (save_key_checked) - ui_->saveCheckedKeysCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: save_key_checked"); - } - - try { - bool clear_gpg_password_cache = - settings.lookup("general.clear_gpg_password_cache"); - if (clear_gpg_password_cache) - ui_->clearGpgPasswordCacheCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: clear_gpg_password_cache"); - } - - try { - bool restore_text_editor_page = - settings.lookup("general.restore_text_editor_page"); - if (restore_text_editor_page) - ui_->restoreTextEditorPageCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: restore_text_editor_page"); - } - - try { - bool longer_expiration_date = - settings.lookup("general.longer_expiration_date"); - SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date); - if (longer_expiration_date) - ui_->longerKeyExpirationDateCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: longer_expiration_date"); - } - -#ifdef MULTI_LANG_SUPPORT - try { - std::string lang_key = settings.lookup("general.lang"); - QString lang_value = lang_.value(lang_key.c_str()); - SPDLOG_DEBUG("lang settings current: {}", lang_value.toStdString()); - if (!lang_.empty()) { - ui_->langSelectBox->setCurrentIndex( - ui_->langSelectBox->findText(lang_value)); - } else { - ui_->langSelectBox->setCurrentIndex(0); - } - } catch (...) { - SPDLOG_ERROR("setting operation error: lang"); - } -#endif - - try { - bool confirm_import_keys = settings.lookup("general.confirm_import_keys"); - SPDLOG_DEBUG("confirm_import_keys: {}", confirm_import_keys); - if (confirm_import_keys) - ui_->importConfirmationCheckBox->setCheckState(Qt::Checked); - } catch (...) { - SPDLOG_ERROR("setting operation error: confirm_import_keys"); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + + bool clear_gpg_password_cache = + settings.value("basic/clear_gpg_password_cache", true).toBool(); + ui_->clearGpgPasswordCacheCheckBox->setCheckState( + clear_gpg_password_cache ? Qt::Checked : Qt::Unchecked); + + bool restore_text_editor_page = + settings.value("basic/restore_text_editor_page", true).toBool(); + ui_->restoreTextEditorPageCheckBox->setCheckState( + restore_text_editor_page ? Qt::Checked : Qt::Unchecked); + + bool longer_expiration_date = + settings.value("basic/longer_expiration_date", false).toBool(); + ui_->longerKeyExpirationDateCheckBox->setCheckState( + longer_expiration_date ? Qt::Checked : Qt::Unchecked); + + bool confirm_import_keys = + settings.value("basic/confirm_import_keys", false).toBool(); + ui_->importConfirmationCheckBox->setCheckState( + confirm_import_keys ? Qt::Checked : Qt::Unchecked); + + QString lang_key = settings.value("basic/lang").toString(); + QString lang_value = lang_.value(lang_key); + GF_UI_LOG_DEBUG("lang settings current: {}", lang_value.toStdString()); + if (!lang_.empty()) { + ui_->langSelectBox->setCurrentIndex( + ui_->langSelectBox->findText(lang_value)); + } else { + ui_->langSelectBox->setCurrentIndex(0); } } -/*********************************** - * get the values of the buttons and - * write them to settings-file - *************************************/ void GeneralTab::ApplySettings() { - auto& settings = - GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("general") || - settings.lookup("general").getType() != libconfig::Setting::TypeGroup) - settings.add("general", libconfig::Setting::TypeGroup); - - auto& general = settings["general"]; - - if (!general.exists("longer_expiration_date")) - general.add("longer_expiration_date", libconfig::Setting::TypeBoolean) = - ui_->longerKeyExpirationDateCheckBox->isChecked(); - else { - general["longer_expiration_date"] = - ui_->longerKeyExpirationDateCheckBox->isChecked(); - } - - if (!general.exists("save_key_checked")) - general.add("save_key_checked", libconfig::Setting::TypeBoolean) = - ui_->saveCheckedKeysCheckBox->isChecked(); - else { - general["save_key_checked"] = ui_->saveCheckedKeysCheckBox->isChecked(); - } - - if (!general.exists("clear_gpg_password_cache")) - general.add("clear_gpg_password_cache", libconfig::Setting::TypeBoolean) = - ui_->clearGpgPasswordCacheCheckBox->isChecked(); - else { - general["clear_gpg_password_cache"] = - ui_->saveCheckedKeysCheckBox->isChecked(); - } - - if (!general.exists("restore_text_editor_page")) - general.add("restore_text_editor_page", libconfig::Setting::TypeBoolean) = - ui_->restoreTextEditorPageCheckBox->isChecked(); - else { - general["restore_text_editor_page"] = - ui_->restoreTextEditorPageCheckBox->isChecked(); - } - -#ifdef MULTI_LANG_SUPPORT - if (!general.exists("lang")) - general.add("lang", libconfig::Setting::TypeBoolean) = - lang_.key(ui_->langSelectBox->currentText()).toStdString(); - else { - general["lang"] = - lang_.key(ui_->langSelectBox->currentText()).toStdString(); - } -#endif - - if (!general.exists("confirm_import_keys")) - general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) = - ui_->importConfirmationCheckBox->isChecked(); - else { - general["confirm_import_keys"] = - ui_->importConfirmationCheckBox->isChecked(); - } + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); + + settings.setValue("basic/longer_expiration_date", + ui_->longerKeyExpirationDateCheckBox->isChecked()); + settings.setValue("basic/clear_gpg_password_cache", + ui_->clearGpgPasswordCacheCheckBox->isChecked()); + settings.setValue("basic/restore_text_editor_page", + ui_->restoreTextEditorPageCheckBox->isChecked()); + settings.setValue("basic/confirm_import_keys", + ui_->importConfirmationCheckBox->isChecked()); + settings.setValue("basic/lang", lang_.key(ui_->langSelectBox->currentText())); } -#ifdef MULTI_LANG_SUPPORT void GeneralTab::slot_language_changed() { emit SignalRestartNeeded(true); } -#endif } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/settings/SettingsGeneral.h b/src/ui/dialog/settings/SettingsGeneral.h index be145b1f..284843d4 100644 --- a/src/ui/dialog/settings/SettingsGeneral.h +++ b/src/ui/dialog/settings/SettingsGeneral.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSGENERAL_H -#define GPGFRONTEND_SETTINGSGENERAL_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -81,25 +80,16 @@ class GeneralTab : public QWidget { private: std::shared_ptr<Ui_GeneralSettings> ui_; ///< - -#ifdef MULTI_LANG_SUPPORT - QHash<QString, QString> lang_; ///< -#endif - - std::vector<std::string> key_ids_list_; ///< - - KeyList* m_key_list_{}; ///< + QHash<QString, QString> lang_; ///< + std::vector<QString> key_ids_list_; ///< + KeyList* m_key_list_{}; ///< private slots: -#ifdef MULTI_LANG_SUPPORT /** * @brief * */ void slot_language_changed(); -#endif }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SETTINGSGENERAL_H diff --git a/src/ui/dialog/settings/SettingsKeyServer.cpp b/src/ui/dialog/settings/SettingsKeyServer.cpp index 83bd2c80..5613ed45 100644 --- a/src/ui/dialog/settings/SettingsKeyServer.cpp +++ b/src/ui/dialog/settings/SettingsKeyServer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,17 +28,21 @@ #include "SettingsKeyServer.h" +#include <cstddef> + #include "core/function/GlobalSettingStation.h" #include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/KeyServerSO.h" #include "ui/thread/ListedKeyServerTestTask.h" #include "ui_KeyServerSettings.h" namespace GpgFrontend::UI { KeyserverTab::KeyserverTab(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_KeyServerSettings>()) { + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_KeyServerSettings>()) { ui_->setupUi(this); ui_->keyServerListTable->setSizeAdjustPolicy( QAbstractScrollArea::AdjustToContents); @@ -48,25 +52,25 @@ KeyserverTab::KeyserverTab(QWidget* parent) connect(ui_->testKeyServerButton, &QPushButton::clicked, this, &KeyserverTab::slot_test_listed_key_server); - ui_->keyServerListGroupBox->setTitle(_("Keyserver List")); - ui_->operationsGroupBox->setTitle(_("Operations")); + ui_->keyServerListGroupBox->setTitle(tr("Keyserver List")); + ui_->operationsGroupBox->setTitle(tr("Operations")); - ui_->keyServerListTable->horizontalHeaderItem(0)->setText(_("Default")); + ui_->keyServerListTable->horizontalHeaderItem(0)->setText(tr("Default")); ui_->keyServerListTable->horizontalHeaderItem(1)->setText( - _("Keyserver Address")); - ui_->keyServerListTable->horizontalHeaderItem(2)->setText(_("Security")); - ui_->keyServerListTable->horizontalHeaderItem(3)->setText(_("Available")); + tr("Keyserver Address")); + ui_->keyServerListTable->horizontalHeaderItem(2)->setText(tr("Security")); + ui_->keyServerListTable->horizontalHeaderItem(3)->setText(tr("Available")); - ui_->addKeyServerPushButton->setText(_("Add")); - ui_->testKeyServerButton->setText(_("Test Listed Keyserver")); + ui_->addKeyServerPushButton->setText(tr("Add")); + ui_->testKeyServerButton->setText(tr("Test Listed Keyserver")); ui_->tipsLabel->setText( - _("Tips: Please Double-click table item to edit it.")); - ui_->actionDelete_Selected_Key_Server->setText(_("Delete Selected")); + tr("Tips: Please Double-click table item to edit it.")); + ui_->actionDelete_Selected_Key_Server->setText(tr("Delete Selected")); ui_->actionDelete_Selected_Key_Server->setToolTip( - _("Delete Selected Key Server")); - ui_->actionSet_As_Default->setText(_("Set As Default")); - ui_->actionSet_As_Default->setToolTip(_("Set As Default")); + tr("Delete Selected Key Server")); + ui_->actionSet_As_Default->setText(tr("Set As Default")); + ui_->actionSet_As_Default->setToolTip(tr("Set As Default")); popup_menu_ = new QMenu(this); popup_menu_->addAction(ui_->actionSet_As_Default); @@ -74,7 +78,7 @@ KeyserverTab::KeyserverTab(QWidget* parent) connect(ui_->keyServerListTable, &QTableWidget::itemChanged, [=](QTableWidgetItem* item) { - SPDLOG_DEBUG("item edited: {}", item->column()); + GF_UI_LOG_DEBUG("item edited: {}", item->column()); if (item->column() != 1) return; const auto row_size = ui_->keyServerListTable->rowCount(); // Update Actions @@ -115,30 +119,18 @@ KeyserverTab::KeyserverTab(QWidget* parent) } void KeyserverTab::SetSettings() { - try { - SettingsObject key_server_json("key_server"); - - const auto key_server_list = - key_server_json.Check("server_list", nlohmann::json::array()); + KeyServerSO key_server(SettingsObject("key_server")); - for (const auto& key_server : key_server_list) { - const auto key_server_str = key_server.get<std::string>(); - this->key_server_str_list_.append(key_server_str.c_str()); - } + if (key_server.server_list.empty()) key_server.ResetDefaultServerList(); + for (const auto& key_server : key_server.server_list) { + this->key_server_str_list_.append(key_server); + } - int default_key_server_index = key_server_json.Check("default_server", 0); - if (default_key_server_index >= key_server_list.size()) { - throw std::runtime_error("default_server index out of range"); - } - std::string default_key_server = - key_server_list[default_key_server_index].get<std::string>(); - - if (!key_server_str_list_.contains(default_key_server.c_str())) - key_server_str_list_.append(default_key_server.c_str()); - default_key_server_ = QString::fromStdString(default_key_server); - } catch (const std::exception& e) { - SPDLOG_ERROR("Error reading key-server settings: ", e.what()); + const auto default_key_server = key_server.GetTargetServer(); + if (!key_server_str_list_.contains(default_key_server)) { + key_server_str_list_.append(default_key_server); } + default_key_server_ = default_key_server; } void KeyserverTab::slot_add_key_server() { @@ -148,47 +140,47 @@ void KeyserverTab::slot_add_key_server() { ; } else if (target_url.startsWith("http://")) { QMessageBox::warning( - this, _("Insecure keyserver address"), - _("For security reasons, using HTTP as the communication protocol " - "with " - "the key server is not recommended. It is recommended to use " - "HTTPS.")); + this, tr("Insecure keyserver address"), + tr("For security reasons, using HTTP as the communication protocol " + "with " + "the key server is not recommended. It is recommended to use " + "HTTPS.")); } key_server_str_list_.append(ui_->addKeyServerEdit->text()); } else { auto ret = QMessageBox::warning( - this, _("Warning"), - _("You may not use HTTPS or HTTP as the protocol for communicating " - "with the key server, which may not be wrong. But please check the " - "address you entered again to make sure it is correct. Are you " - "sure " - "that want to add it into the keyserver list?"), + this, tr("Warning"), + tr("You may not use HTTPS or HTTP as the protocol for communicating " + "with the key server, which may not be wrong. But please check the " + "address you entered again to make sure it is correct. Are you " + "sure " + "that want to add it into the keyserver list?"), QMessageBox::Ok | QMessageBox::Cancel); - if (ret == QMessageBox::Cancel) - return; - else - key_server_str_list_.append(ui_->addKeyServerEdit->text()); + if (ret == QMessageBox::Cancel) return; + key_server_str_list_.append(ui_->addKeyServerEdit->text()); } slot_refresh_table(); } void KeyserverTab::ApplySettings() { SettingsObject key_server_json("key_server"); - key_server_json["server_list"] = nlohmann::json::array(); - auto& key_server_list = key_server_json["server_list"]; + KeyServerSO key_server; + auto& key_server_list = key_server.server_list; const auto list_size = key_server_str_list_.size(); for (int i = 0; i < list_size; i++) { const auto key_server = key_server_str_list_[i]; - if (default_key_server_ == key_server) + if (default_key_server_ == key_server) { key_server_json["default_server"] = i; - key_server_list.insert(key_server_list.end(), key_server.toStdString()); + } + key_server_list << key_server; } + key_server_json.Store(key_server.ToJson()); } void KeyserverTab::slot_refresh_table() { - SPDLOG_INFO("start refreshing key server table"); + GF_UI_LOG_INFO("start refreshing key server table"); ui_->keyServerListTable->blockSignals(true); ui_->keyServerListTable->setRowCount(key_server_str_list_.size()); @@ -205,13 +197,13 @@ void KeyserverTab::slot_refresh_table() { tmp2->setTextAlignment(Qt::AlignCenter); ui_->keyServerListTable->setItem(index, 1, tmp2); - auto* tmp3 = new QTableWidgetItem(server.startsWith("https") ? _("true") - : _("false")); + auto* tmp3 = new QTableWidgetItem(server.startsWith("https") ? tr("true") + : tr("false")); tmp3->setTextAlignment(Qt::AlignCenter); ui_->keyServerListTable->setItem(index, 2, tmp3); tmp3->setFlags(tmp3->flags() ^ Qt::ItemIsEditable); - auto* tmp4 = new QTableWidgetItem(_("unknown")); + auto* tmp4 = new QTableWidgetItem(tr("unknown")); tmp4->setTextAlignment(Qt::AlignCenter); ui_->keyServerListTable->setItem(index, 3, tmp4); tmp4->setFlags(tmp3->flags() ^ Qt::ItemIsEditable); @@ -225,7 +217,7 @@ void KeyserverTab::slot_refresh_table() { } void KeyserverTab::slot_test_listed_key_server() { - auto timeout = QInputDialog::getInt(this, _("Set TCP Timeout"), + auto timeout = QInputDialog::getInt(this, tr("Set TCP Timeout"), tr("timeout(ms): "), 2500, 200, 16000); QStringList urls; @@ -243,17 +235,17 @@ void KeyserverTab::slot_test_listed_key_server() { this, [=](std::vector<ListedKeyServerTestTask::KeyServerTestResultType> result) { - const auto row_size = ui_->keyServerListTable->rowCount(); + const size_t row_size = ui_->keyServerListTable->rowCount(); if (result.size() != row_size) return; ui_->keyServerListTable->blockSignals(true); - for (int i = 0; i < row_size; i++) { + for (size_t i = 0; i < row_size; i++) { const auto status = result[i]; - auto status_iem = ui_->keyServerListTable->item(i, 3); - if (status == ListedKeyServerTestTask::kTestResultType_Success) { - status_iem->setText(_("Reachable")); + auto* status_iem = ui_->keyServerListTable->item(i, 3); + if (status == ListedKeyServerTestTask::kTEST_RESULT_TYPE_SUCCESS) { + status_iem->setText(tr("Reachable")); status_iem->setForeground(QBrush(QColor::fromRgb(0, 255, 0))); } else { - status_iem->setText(_("Not Reachable")); + status_iem->setText(tr("Not Reachable")); status_iem->setForeground(QBrush(QColor::fromRgb(255, 0, 0))); } } @@ -264,11 +256,11 @@ void KeyserverTab::slot_test_listed_key_server() { auto* waiting_dialog = new QProgressDialog(this); waiting_dialog->setMaximum(0); waiting_dialog->setMinimum(0); - auto waiting_dialog_label = - new QLabel(QString(_("Test Key Server Connection...")) + "<br /><br />" + - _("This test only tests the network connectivity of the key " - "server. Passing the test does not mean that the key server " - "is functionally available.")); + auto* waiting_dialog_label = new QLabel( + tr("Test Key Server Connection...") + "<br /><br />" + + tr("This test only tests the network connectivity of the key " + "server. Passing the test does not mean that the key server " + "is functionally available.")); waiting_dialog_label->setWordWrap(true); waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); diff --git a/src/ui/dialog/settings/SettingsKeyServer.h b/src/ui/dialog/settings/SettingsKeyServer.h index f983e69b..ae5a3181 100644 --- a/src/ui/dialog/settings/SettingsKeyServer.h +++ b/src/ui/dialog/settings/SettingsKeyServer.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSKEYSERVER_H -#define GPGFRONTEND_SETTINGSKEYSERVER_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -107,5 +106,3 @@ class KeyserverTab : public QWidget { void contextMenuEvent(QContextMenuEvent* event) override; }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SETTINGSKEYSERVER_H diff --git a/src/ui/dialog/settings/SettingsNetwork.cpp b/src/ui/dialog/settings/SettingsNetwork.cpp index 0713856d..c7e1e9f6 100644 --- a/src/ui/dialog/settings/SettingsNetwork.cpp +++ b/src/ui/dialog/settings/SettingsNetwork.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -33,7 +33,8 @@ #include "ui_NetworkSettings.h" GpgFrontend::UI::NetworkTab::NetworkTab(QWidget *parent) - : QWidget(parent), ui_(std::make_shared<Ui_NetworkSettings>()) { + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_NetworkSettings>()) { ui_->setupUi(this); connect(ui_->enableProxyCheckBox, &QCheckBox::stateChanged, this, @@ -67,207 +68,97 @@ GpgFrontend::UI::NetworkTab::NetworkTab(QWidget *parent) connect(ui_->checkProxyConnectionButton, &QPushButton::clicked, this, &NetworkTab::slot_test_proxy_connection_result); - ui_->proxyGroupBox->setTitle(_("Proxy")); - ui_->capabilityGroupBox->setTitle(_("Network Ability")); - ui_->operationsGroupBox->setTitle(_("Operations")); + ui_->proxyGroupBox->setTitle(tr("Proxy")); + ui_->capabilityGroupBox->setTitle(tr("Network Ability")); + ui_->operationsGroupBox->setTitle(tr("Operations")); - ui_->enableProxyCheckBox->setText(_("Enable Proxy")); - ui_->proxyServerPortLabel->setText(_("Port")); + ui_->enableProxyCheckBox->setText(tr("Enable Proxy")); + ui_->proxyServerPortLabel->setText(tr("Port")); - ui_->proxyServerAddressLabel->setText(_("Host Address")); - ui_->proxyServerPortLabel->setText(_("Port")); - ui_->proxyTypeLabel->setText(_("Proxy Type")); - ui_->usernameLabel->setText(_("Username")); - ui_->passwordLabel->setText(_("Password")); + ui_->proxyServerAddressLabel->setText(tr("Host Address")); + ui_->proxyServerPortLabel->setText(tr("Port")); + ui_->proxyTypeLabel->setText(tr("Proxy Type")); + ui_->usernameLabel->setText(tr("Username")); + ui_->passwordLabel->setText(tr("Password")); ui_->checkProxyConnectionButton->setText( - _("Apply Proxy Settings and Check Proxy Connection")); + tr("Apply Proxy Settings and Check Proxy Connection")); ui_->forbidALLGnuPGNetworkConnectionCheckBox->setText( - _("Forbid all GnuPG network connection.")); + tr("Forbid all GnuPG network connection.")); ui_->prohibitUpdateCheck->setText( - _("Prohibit checking for version updates when the program starts.")); + tr("Prohibit checking for version updates when the program starts.")); ui_->autoImportMissingKeyCheckBox->setText( - _("Automatically import a missing key for signature verification.")); + tr("Automatically import a missing key for signature verification.")); ui_->networkAbilityTipsLabel->setText( - _("Tips: These Option Changes take effect only after the " - "application restart.")); + tr("Tips: These Option Changes take effect only after the " + "application restart.")); SetSettings(); } void GpgFrontend::UI::NetworkTab::SetSettings() { - auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); - try { - std::string proxy_host = settings.lookup("proxy.proxy_host"); - ui_->proxyServerAddressEdit->setText(proxy_host.c_str()); - } catch (...) { - SPDLOG_ERROR("setting operation error: proxy_host"); - } + QString proxy_host = settings.value("proxy/proxy_host").toString(); + ui_->proxyServerAddressEdit->setText(proxy_host); + QString username = settings.value("proxy/username").toString(); + ui_->usernameEdit->setText(username); + QString password = settings.value("proxy/password").toString(); + ui_->passwordEdit->setText(password); - try { - std::string std_username = settings.lookup("proxy.username"); - ui_->usernameEdit->setText(std_username.c_str()); - } catch (...) { - SPDLOG_ERROR("setting operation error: username"); - } + int port = settings.value("proxy/port", 0).toInt(); + ui_->portSpin->setValue(port); - try { - std::string std_password = settings.lookup("proxy.password"); - ui_->passwordEdit->setText(std_password.c_str()); - } catch (...) { - SPDLOG_ERROR("setting operation error: password"); - } + ui_->proxyTypeComboBox->setCurrentText("HTTP"); - try { - int port = settings.lookup("proxy.port"); - ui_->portSpin->setValue(port); - } catch (...) { - SPDLOG_ERROR("setting operation error: port"); - } + QString proxy_type = settings.value("proxy/proxy_type").toString(); + ui_->proxyTypeComboBox->setCurrentText(proxy_type); - ui_->proxyTypeComboBox->setCurrentText("HTTP"); - try { - std::string proxy_type = settings.lookup("proxy.proxy_type"); - ui_->proxyTypeComboBox->setCurrentText(proxy_type.c_str()); - } catch (...) { - SPDLOG_ERROR("setting operation error: proxy_type"); - } switch_ui_proxy_type(ui_->proxyTypeComboBox->currentText()); ui_->enableProxyCheckBox->setCheckState(Qt::Unchecked); - try { - bool proxy_enable = settings.lookup("proxy.enable"); - if (proxy_enable) - ui_->enableProxyCheckBox->setCheckState(Qt::Checked); - else - ui_->enableProxyCheckBox->setCheckState(Qt::Unchecked); - } catch (...) { - SPDLOG_ERROR("setting operation error: proxy_enable"); - } - ui_->forbidALLGnuPGNetworkConnectionCheckBox->setCheckState(Qt::Unchecked); - try { - bool forbid_all_gnupg_connection = - settings.lookup("network.forbid_all_gnupg_connection"); - if (forbid_all_gnupg_connection) - ui_->forbidALLGnuPGNetworkConnectionCheckBox->setCheckState(Qt::Checked); - else - ui_->forbidALLGnuPGNetworkConnectionCheckBox->setCheckState( - Qt::Unchecked); - } catch (...) { - SPDLOG_ERROR("setting operation error: forbid_all_gnupg_connection"); - } + bool proxy_enable = settings.value("proxy/enable", false).toBool(); + ui_->enableProxyCheckBox->setCheckState(proxy_enable ? Qt::Checked + : Qt::Unchecked); - ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked); - try { - bool prohibit_update_checking = - settings.lookup("network.prohibit_update_checking"); - if (prohibit_update_checking) - ui_->prohibitUpdateCheck->setCheckState(Qt::Checked); - else - ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked); - } catch (...) { - SPDLOG_ERROR("setting operation error: prohibit_update_checking"); - } + bool forbid_all_gnupg_connection = + settings.value("network/forbid_all_gnupg_connection").toBool(); + ui_->forbidALLGnuPGNetworkConnectionCheckBox->setCheckState( + forbid_all_gnupg_connection ? Qt::Checked : Qt::Unchecked); - ui_->autoImportMissingKeyCheckBox->setCheckState(Qt::Unchecked); - try { - bool auto_import_missing_key = - settings.lookup("network.auto_import_missing_key"); - if (auto_import_missing_key) - ui_->autoImportMissingKeyCheckBox->setCheckState(Qt::Checked); - else - ui_->autoImportMissingKeyCheckBox->setCheckState(Qt::Unchecked); - } catch (...) { - SPDLOG_ERROR("setting operation error: auto_import_missing_key"); - } + bool prohibit_update_checking = + settings.value("network/prohibit_update_checking").toBool(); + ui_->prohibitUpdateCheck->setCheckState( + prohibit_update_checking ? Qt::Checked : Qt::Unchecked); + + bool auto_import_missing_key = + settings.value("network/auto_import_missing_key", true).toBool(); + ui_->autoImportMissingKeyCheckBox->setCheckState( + auto_import_missing_key ? Qt::Checked : Qt::Unchecked); switch_ui_enabled(ui_->enableProxyCheckBox->isChecked()); switch_ui_proxy_type(ui_->proxyTypeComboBox->currentText()); } void GpgFrontend::UI::NetworkTab::ApplySettings() { - auto &settings = - GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("proxy") || - settings.lookup("proxy").getType() != libconfig::Setting::TypeGroup) - settings.add("proxy", libconfig::Setting::TypeGroup); - - auto &proxy = settings["proxy"]; - - if (!proxy.exists("proxy_host")) - proxy.add("proxy_host", libconfig::Setting::TypeString) = - ui_->proxyServerAddressEdit->text().toStdString(); - else { - proxy["proxy_host"] = ui_->proxyServerAddressEdit->text().toStdString(); - } - - if (!proxy.exists("username")) - proxy.add("username", libconfig::Setting::TypeString) = - ui_->usernameEdit->text().toStdString(); - else { - proxy["username"] = ui_->usernameEdit->text().toStdString(); - } - - if (!proxy.exists("password")) - proxy.add("password", libconfig::Setting::TypeString) = - ui_->passwordEdit->text().toStdString(); - else { - proxy["password"] = ui_->passwordEdit->text().toStdString(); - } - - if (!proxy.exists("port")) - proxy.add("port", libconfig::Setting::TypeInt) = ui_->portSpin->value(); - else { - proxy["port"] = ui_->portSpin->value(); - } - - if (!proxy.exists("proxy_type")) - proxy.add("proxy_type", libconfig::Setting::TypeString) = - ui_->proxyTypeComboBox->currentText().toStdString(); - else { - proxy["proxy_type"] = ui_->proxyTypeComboBox->currentText().toStdString(); - } - - if (!proxy.exists("enable")) - proxy.add("enable", libconfig::Setting::TypeBoolean) = - ui_->enableProxyCheckBox->isChecked(); - else { - proxy["enable"] = ui_->enableProxyCheckBox->isChecked(); - } - - if (!settings.exists("network") || - settings.lookup("network").getType() != libconfig::Setting::TypeGroup) - settings.add("network", libconfig::Setting::TypeGroup); - - auto &network = settings["network"]; - - if (!network.exists("forbid_all_gnupg_connection")) - network.add("forbid_all_gnupg_connection", - libconfig::Setting::TypeBoolean) = - ui_->forbidALLGnuPGNetworkConnectionCheckBox->isChecked(); - else { - network["forbid_all_gnupg_connection"] = - ui_->forbidALLGnuPGNetworkConnectionCheckBox->isChecked(); - } - - if (!network.exists("prohibit_update_checking")) - network.add("prohibit_update_checking", libconfig::Setting::TypeBoolean) = - ui_->prohibitUpdateCheck->isChecked(); - else { - network["prohibit_update_checking"] = ui_->prohibitUpdateCheck->isChecked(); - } - - if (!network.exists("auto_import_missing_key")) - network.add("auto_import_missing_key", libconfig::Setting::TypeBoolean) = - ui_->autoImportMissingKeyCheckBox->isChecked(); - else { - network["auto_import_missing_key"] = - ui_->autoImportMissingKeyCheckBox->isChecked(); - } + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); + + settings.setValue("proxy/proxy_host", ui_->proxyServerAddressEdit->text()); + settings.setValue("proxy/username", ui_->usernameEdit->text()); + settings.setValue("proxy/password", ui_->passwordEdit->text()); + settings.setValue("proxy/port", ui_->portSpin->value()); + settings.setValue("proxy/proxy_type", ui_->proxyTypeComboBox->currentText()); + settings.setValue("proxy/enable", ui_->enableProxyCheckBox->isChecked()); + + settings.setValue("network/forbid_all_gnupg_connection", + ui_->forbidALLGnuPGNetworkConnectionCheckBox->isChecked()); + settings.setValue("network/prohibit_update_checking", + ui_->prohibitUpdateCheck->isChecked()); + settings.setValue("network/auto_import_missing_key", + ui_->autoImportMissingKeyCheckBox->isChecked()); apply_proxy_settings(); } @@ -276,7 +167,7 @@ void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() { apply_proxy_settings(); bool ok; - auto url = QInputDialog::getText(this, _("Test Server Url Accessibility"), + auto url = QInputDialog::getText(this, tr("Test Server Url Accessibility"), tr("Server Url"), QLineEdit::Normal, "https://", &ok); if (ok && !url.isEmpty()) { @@ -286,14 +177,15 @@ void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() { SignalProxyConnectionTestResult, this, [=](const QString &result) { if (result == "Reachable") { - QMessageBox::information(this, _("Success"), - _("Successfully connect to the target " - "server through the proxy server.")); + QMessageBox::information( + this, tr("Success"), + tr("Successfully connect to the target " + "server through the proxy server.")); } else { QMessageBox::critical( - this, _("Failed"), - _("Unable to connect to the target server through the " - "proxy server. Proxy settings may be invalid.")); + this, tr("Failed"), + tr("Unable to connect to the target server through the " + "proxy server. Proxy settings may be invalid.")); } }); @@ -302,9 +194,10 @@ void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() { waiting_dialog->setMaximum(0); waiting_dialog->setMinimum(0); auto waiting_dialog_label = new QLabel( - QString(_("Test Proxy Server Connection...")) + "<br /><br />" + - _("Is using your proxy settings to access the url. Note that this test " - "operation will apply your proxy settings to the entire software.")); + tr("Test Proxy Server Connection...") + "<br /><br />" + + tr("Is using your proxy settings to access the url. Note that this " + "test " + "operation will apply your proxy settings to the entire software.")); waiting_dialog_label->setWordWrap(true); waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); diff --git a/src/ui/dialog/settings/SettingsNetwork.h b/src/ui/dialog/settings/SettingsNetwork.h index d4c0d00d..4335dff7 100644 --- a/src/ui/dialog/settings/SettingsNetwork.h +++ b/src/ui/dialog/settings/SettingsNetwork.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,15 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSNETWORK_H -#define GPGFRONTEND_SETTINGSNETWORK_H +#pragma once + +#include <QtNetwork> #include "ui/GpgFrontendUI.h" @@ -90,5 +91,3 @@ class NetworkTab : public QWidget { void switch_ui_proxy_type(const QString& type_text); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SETTINGSNETWORK_H diff --git a/src/ui/function/GenerateRevokeCertification.cpp b/src/ui/function/GenerateRevokeCertification.cpp new file mode 100644 index 00000000..b1089d45 --- /dev/null +++ b/src/ui/function/GenerateRevokeCertification.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GenerateRevokeCertification.h" + +#include "core/function/gpg/GpgCommandExecutor.h" +#include "core/model/GpgKey.h" +#include "core/module/ModuleManager.h" + +namespace GpgFrontend::UI { + +GenerateRevokeCertification::GenerateRevokeCertification(QWidget* parent) + : QWidget(parent) {} + +auto GenerateRevokeCertification::Exec(const GpgKey& key, + const QString& output_path) -> int { + const auto app_path = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.app_path", QString{}); + // get all components + GpgCommandExecutor::ExecuteSync( + {app_path, + {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o", + std::move(output_path), "--gen-revoke", key.GetFingerprint()}, + [=](int exit_code, const QString& p_out, const QString& p_err) { + if (exit_code != 0) { + GF_UI_LOG_ERROR( + "gnupg gen revoke execute error, process stderr: {}, process " + "stdout: {}", + p_err, p_out); + } else { + GF_UI_LOG_DEBUG( + "gnupg gen revoke exit_code: {}, process stdout size: {}", + exit_code, p_out.size()); + } + }, + nullptr, + [](QProcess* proc) -> void { + // Code From Gpg4Win + while (proc->canReadLine()) { + const QString line = QString::fromUtf8(proc->readLine()).trimmed(); + GF_UI_LOG_DEBUG("line: {}", line.toStdString()); + if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.code")) { + proc->write("0\n"); + } else if (line == QLatin1String("[GNUPG:] GET_LINE " + "ask_revocation_reason.text")) { + proc->write("\n"); + } else if (line == + QLatin1String( + "[GNUPG:] GET_BOOL openfile.overwrite.okay")) { + // We asked before + proc->write("y\n"); + } else if (line == QLatin1String("[GNUPG:] GET_BOOL " + "ask_revocation_reason.okay")) { + proc->write("y\n"); + } + } + }}); + return 0; +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/SignalStation.cpp b/src/ui/function/GenerateRevokeCertification.h index c1f1238f..edc0161b 100644 --- a/src/ui/SignalStation.cpp +++ b/src/ui/function/GenerateRevokeCertification.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,25 +20,25 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include "SignalStation.h" +#pragma once -#include "UserInterfaceUtils.h" +#include "core/GpgModel.h" +#include "ui/GpgFrontendUI.h" namespace GpgFrontend::UI { -std::unique_ptr<SignalStation> SignalStation::_instance = nullptr; +class GenerateRevokeCertification : public QWidget { + Q_OBJECT + public: + explicit GenerateRevokeCertification(QWidget* parent); -SignalStation* SignalStation::GetInstance() { - if (_instance == nullptr) { - _instance = std::make_unique<SignalStation>(); - } - return _instance.get(); -} + auto Exec(const GpgKey& key, const QString& output_path) -> int; +}; } // namespace GpgFrontend::UI diff --git a/src/ui/function/RaisePinentry.cpp b/src/ui/function/RaisePinentry.cpp new file mode 100644 index 00000000..64e10c48 --- /dev/null +++ b/src/ui/function/RaisePinentry.cpp @@ -0,0 +1,122 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "RaisePinentry.h" + +#include "core/function/CoreSignalStation.h" +#include "core/model/GpgPassphraseContext.h" +#include "core/utils/CacheUtils.h" +#include "pinentry/pinentrydialog.h" + +namespace GpgFrontend::UI { + +auto FindTopMostWindow(QWidget* fallback) -> QWidget* { + QList<QWidget*> top_widgets = QApplication::topLevelWidgets(); + foreach (QWidget* widget, top_widgets) { + if (widget->isActiveWindow()) { + GF_UI_LOG_TRACE("find a topmost widget, address: {}", + static_cast<void*>(widget)); + return widget; + } + } + return fallback; +} + +RaisePinentry::RaisePinentry(QWidget* parent, + QSharedPointer<GpgPassphraseContext> context) + : QWidget(parent), context_(std::move(context)) {} + +auto RaisePinentry::Exec() -> int { + GF_UI_LOG_DEBUG( + "setting pinetry's arguments, context uids: {}, passphrase info: {}, " + "prev_was_bad: {}", + context_->GetUidsInfo().toStdString(), + context_->GetPassphraseInfo().toStdString(), context_->IsPreWasBad()); + + bool ask_for_new = context_->IsAskForNew() && + context_->GetPassphraseInfo().isEmpty() && + context_->GetUidsInfo().isEmpty(); + + auto* pinentry = + new PinEntryDialog(FindTopMostWindow(this), 0, 15, true, ask_for_new, + ask_for_new ? tr("Repeat PIN:") : QString(), + tr("Show passphrase"), tr("Hide passphrase")); + + if (context_->IsPreWasBad()) { + pinentry->setError(tr("Given PIN was wrong. Please retry.")); + } + + pinentry->setPrompt(tr("PIN:")); + + if (!context_->GetUidsInfo().isEmpty()) { + pinentry->setDescription(QString("Please provide PIN of Key:\n%1\n") + .arg(context_->GetUidsInfo())); + } + + struct pinentry pinentry_info; + pinentry->setPinentryInfo(pinentry_info); + + pinentry->setRepeatErrorText(tr("Passphrases do not match")); + pinentry->setGenpinLabel(QString("")); + pinentry->setGenpinTT(QString("")); + pinentry->setCapsLockHint(tr("Caps Lock is on")); + pinentry->setFormattedPassphrase({false, QString()}); + pinentry->setConstraintsOptions({false, QString(), QString(), QString()}); + + pinentry->setWindowTitle(tr("Buddled Pinentry")); + + /* If we reuse the same dialog window. */ + pinentry->setPin(QString()); + pinentry->setOkText(tr("Confirm")); + pinentry->setCancelText(tr("Cancel")); + + GF_UI_LOG_DEBUG("buddled pinentry is ready to start..."); + connect(pinentry, &PinEntryDialog::finished, this, + [pinentry, this](int result) { + bool ret = result != 0; + GF_UI_LOG_DEBUG("buddled pinentry finished, ret: {}", ret); + + if (!ret) { + emit CoreSignalStation::GetInstance() + ->SignalUserInputPassphraseCallback({}); + return -1; + } + + auto pin = pinentry->pin().toUtf8(); + + context_->SetPassphrase(pin); + emit CoreSignalStation::GetInstance() + ->SignalUserInputPassphraseCallback(context_); + return 0; + }); + connect(pinentry, &PinEntryDialog::finished, this, &QWidget::deleteLater); + + pinentry->open(); + return 0; +} +} // namespace GpgFrontend::UI diff --git a/src/ui/dialog/settings/SettingsAdvanced.h b/src/ui/function/RaisePinentry.h index c1a3d5a6..40175dfd 100644 --- a/src/ui/dialog/settings/SettingsAdvanced.h +++ b/src/ui/function/RaisePinentry.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,36 +20,41 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSADVANCED_H -#define GPGFRONTEND_SETTINGSADVANCED_H +#pragma once #include "ui/GpgFrontendUI.h" +namespace GpgFrontend { +class GpgPassphraseContext; +} + namespace GpgFrontend::UI { -class AdvancedTab : public QWidget { - Q_OBJECT +class RaisePinentry : public QWidget { + Q_OBJECT public: - explicit AdvancedTab(QWidget* parent = nullptr); - - void SetSettings(); - - void ApplySettings(); + /** + * @brief Construct a new Raise Pinentry object + * + * @param parent + */ + explicit RaisePinentry(QWidget *parent, QSharedPointer<GpgPassphraseContext>); + + /** + * @brief + * + * @return int + */ + auto Exec() -> int; private: - QCheckBox* stegano_check_box_; - QCheckBox* auto_pubkey_exchange_check_box_; - - signals: - - void SignalRestartNeeded(bool needed); + QSharedPointer<GpgPassphraseContext> context_; }; -} // namespace GpgFrontend::UI -#endif // GPGFRONTEND_SETTINGSADVANCED_H +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/function/SetOwnerTrustLevel.cpp b/src/ui/function/SetOwnerTrustLevel.cpp new file mode 100644 index 00000000..360abfce --- /dev/null +++ b/src/ui/function/SetOwnerTrustLevel.cpp @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SetOwnerTrustLevel.h" + +#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgKeyManager.h" +#include "ui/UISignalStation.h" + +namespace GpgFrontend::UI { + +SetOwnerTrustLevel::SetOwnerTrustLevel(QWidget* parent) : QWidget(parent) {} + +auto SetOwnerTrustLevel::Exec(const QString& key_id) -> bool { + if (key_id.isEmpty()) { + return false; + } + + auto key = GpgKeyGetter::GetInstance().GetKey(key_id); + + QStringList items; + + items << tr("Unknown") << tr("Undefined") << tr("Never") << tr("Marginal") + << tr("Full") << tr("Ultimate"); + bool ok; + QString item = QInputDialog::getItem(this, tr("Modify Owner Trust Level"), + tr("Trust for the Key Pair:"), items, + key.GetOwnerTrustLevel(), false, &ok); + + if (ok && !item.isEmpty()) { + GF_UI_LOG_DEBUG("selected owner trust policy: {}", item.toStdString()); + int trust_level = 0; // Unknown Level + if (item == tr("Ultimate")) { + trust_level = 5; + } else if (item == tr("Full")) { + trust_level = 4; + } else if (item == tr("Marginal")) { + trust_level = 3; + } else if (item == tr("Never")) { + trust_level = 2; + } else if (item == tr("Undefined")) { + trust_level = 1; + } + + if (trust_level == 0) { + QMessageBox::warning( + this, tr("Warning"), + QString( + tr("Owner Trust Level cannot set to Unknown level, automately " + "changing it into Undefined level."))); + trust_level = 1; + } + + bool status = + GpgKeyManager::GetInstance().SetOwnerTrustLevel(key, trust_level); + if (!status) { + QMessageBox::critical(this, tr("Failed"), + tr("Modify Owner Trust Level failed.")); + return false; + } + + // update key database and refresh ui + emit UISignalStation::GetInstance()->SignalKeyDatabaseRefresh(); + return true; + } + + return false; +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/function/SetOwnerTrustLevel.h b/src/ui/function/SetOwnerTrustLevel.h new file mode 100644 index 00000000..e33f787b --- /dev/null +++ b/src/ui/function/SetOwnerTrustLevel.h @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class SetOwnerTrustLevel : public QWidget { + Q_OBJECT + public: + /** + * @brief Set the Owner Trust Level object + * + * @param parent + */ + explicit SetOwnerTrustLevel(QWidget* parent); + + /** + * @brief + * + * @param key_id + * @return true + * @return false + */ + auto Exec(const QString& key_id) -> bool; +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/main_window/GeneralMainWindow.cpp b/src/ui/main_window/GeneralMainWindow.cpp index 0acedec6..2eb9f2a4 100644 --- a/src/ui/main_window/GeneralMainWindow.cpp +++ b/src/ui/main_window/GeneralMainWindow.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,20 +28,25 @@ #include "GeneralMainWindow.h" -#include <utility> - #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/AppearanceSO.h" +#include "ui/struct/settings/WindowStateSO.h" + +namespace GpgFrontend::UI { -GpgFrontend::UI::GeneralMainWindow::GeneralMainWindow(std::string name, +class GeneralWindowState {}; + +GpgFrontend::UI::GeneralMainWindow::GeneralMainWindow(QString name, QWidget *parent) - : name_(std::move(name)), QMainWindow(parent) { + : QMainWindow(parent), name_(std::move(name)) { slot_restore_settings(); } GpgFrontend::UI::GeneralMainWindow::~GeneralMainWindow() = default; void GpgFrontend::UI::GeneralMainWindow::closeEvent(QCloseEvent *event) { - SPDLOG_DEBUG("main window close event caught, event type: {}", event->type()); + GF_UI_LOG_DEBUG("main window close event caught, event type: {}", + event->type()); slot_save_settings(); QMainWindow::closeEvent(event); @@ -49,34 +54,23 @@ void GpgFrontend::UI::GeneralMainWindow::closeEvent(QCloseEvent *event) { void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { try { - SettingsObject general_windows_state(name_ + "_state"); + WindowStateSO window_state(SettingsObject(name_ + "_state")); - std::string window_state = general_windows_state.Check( - "window_state", saveState().toBase64().toStdString()); - SPDLOG_DEBUG("restore main window state: {}", window_state); + GF_UI_LOG_DEBUG("restore main window state: {}", + window_state.window_state_data); // state sets pos & size of dock-widgets this->restoreState( - QByteArray::fromBase64(QByteArray::fromStdString(window_state))); - - bool window_save = general_windows_state.Check("window_save", true); - - // Restore window size & location - if (window_save) { - int x = general_windows_state.Check("window_pos").Check("x", 100), - y = general_windows_state.Check("window_pos").Check("y", 100); - - pos_ = {x, y}; - - int width = - general_windows_state.Check("window_size").Check("width", 800), - height = - general_windows_state.Check("window_size").Check("height", 450); + QByteArray::fromBase64(window_state.window_state_data.toUtf8())); - size_ = {width, height}; + // restore window size & location + if (window_state.window_save) { + pos_ = {window_state.x, window_state.y}; + size_ = {window_state.width, window_state.height}; if (this->parent() != nullptr) { - SPDLOG_DEBUG("parent address: {}", static_cast<void *>(this->parent())); + GF_UI_LOG_DEBUG("parent address: {}", + static_cast<void *>(this->parent())); QPoint parent_pos = {0, 0}; QSize parent_size = {0, 0}; @@ -93,10 +87,11 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { parent_size = parent_window->size(); } - SPDLOG_DEBUG("parent pos x: {} y: {}", parent_pos.x(), parent_pos.y()); + GF_UI_LOG_DEBUG("parent pos x: {} y: {}", parent_pos.x(), + parent_pos.y()); - SPDLOG_DEBUG("parent size width: {} height: {}", parent_size.width(), - parent_size.height()); + GF_UI_LOG_DEBUG("parent size width: {} height: {}", parent_size.width(), + parent_size.height()); if (parent_pos != QPoint{0, 0}) { QPoint parent_center{parent_pos.x() + parent_size.width() / 2, @@ -112,59 +107,42 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { } // appearance - SettingsObject general_settings_state("general_settings_state"); + AppearanceSO appearance(SettingsObject("general_settings_state")); - int width = general_settings_state.Check("icon_size").Check("width", 24), - height = general_settings_state.Check("icon_size").Check("height", 24); - SPDLOG_DEBUG("icon size: {} {}", width, height); - - icon_size_ = {width, height}; - font_size_ = general_settings_state.Check("font_size", 10); + icon_size_ = {appearance.tool_bar_icon_width, + appearance.tool_bar_icon_height}; + font_size_ = appearance.info_board_font_size; this->setIconSize(icon_size_); - - // icon_style - int s_icon_style = - general_settings_state.Check("icon_style", Qt::ToolButtonTextUnderIcon); - this->setToolButtonStyle(static_cast<Qt::ToolButtonStyle>(s_icon_style)); + this->setToolButtonStyle(appearance.tool_bar_button_style); icon_style_ = toolButtonStyle(); } catch (...) { - SPDLOG_ERROR(name_, "error"); + GF_UI_LOG_ERROR("gernal main window: {}, caught exception", name_); } } void GpgFrontend::UI::GeneralMainWindow::slot_save_settings() noexcept { try { - SPDLOG_DEBUG("save main window state, name: {}", name_); + GF_UI_LOG_DEBUG("save main window state, name: {}", name_); SettingsObject general_windows_state(name_ + "_state"); - // window position and size - general_windows_state["window_state"] = - saveState().toBase64().toStdString(); - general_windows_state["window_pos"]["x"] = pos().x(); - general_windows_state["window_pos"]["y"] = pos().y(); - - // update size of current dialog + // update geo of current dialog size_ = this->size(); + pos_ = this->pos(); - general_windows_state["window_size"]["width"] = size_.width(); - general_windows_state["window_size"]["height"] = size_.height(); - general_windows_state["window_save"] = true; - - SettingsObject general_settings_state("general_settings_state"); - - // icon size - general_settings_state["icon_size"]["width"] = icon_size_.width(); - general_settings_state["icon_size"]["height"] = icon_size_.height(); - - // font size - general_settings_state["font_size"] = font_size_; - - // tool button style - general_settings_state["icon_style"] = this->toolButtonStyle(); + WindowStateSO window_state; + window_state.x = pos_.x(); + window_state.y = pos_.y(); + window_state.width = size_.width(); + window_state.height = size_.height(); + window_state.window_save = true; + window_state.window_state_data = this->saveState().toBase64(); + general_windows_state.Store(window_state.Json()); } catch (...) { - SPDLOG_ERROR(name_, "error"); + GF_UI_LOG_ERROR("gernal main window: {}, caught exception", name_); } } + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/main_window/GeneralMainWindow.h b/src/ui/main_window/GeneralMainWindow.h index 8995883a..e1ff31bb 100644 --- a/src/ui/main_window/GeneralMainWindow.h +++ b/src/ui/main_window/GeneralMainWindow.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_GENERALMAINWINDOW_H -#define GPGFRONTEND_GENERALMAINWINDOW_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -42,7 +41,7 @@ class GeneralMainWindow : public QMainWindow { * * @param name */ - explicit GeneralMainWindow(std::string name, QWidget* parent = nullptr); + explicit GeneralMainWindow(QString name, QWidget* parent = nullptr); /** * @@ -72,10 +71,8 @@ class GeneralMainWindow : public QMainWindow { void slot_save_settings() noexcept; private: - std::string name_; ///< - QPoint pos_; ///< - QSize size_; ///< + QString name_; ///< + QPoint pos_; ///< + QSize size_; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_GENERALMAINWINDOW_H diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp index 47b0dcb0..3f22265e 100644 --- a/src/ui/main_window/KeyMgmt.cpp +++ b/src/ui/main_window/KeyMgmt.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,14 +28,16 @@ #include "KeyMgmt.h" -#include <utility> - #include "core/function/GlobalSettingStation.h" #include "core/function/KeyPackageOperator.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "ui/SignalStation.h" +#include "core/model/GpgImportInformation.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" +#include "function/SetOwnerTrustLevel.h" +#include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/import_export/ExportKeyPackageDialog.h" #include "ui/dialog/key_generate/SubkeyGenerateDialog.h" @@ -48,10 +50,12 @@ KeyMgmt::KeyMgmt(QWidget* parent) /* the list of Keys available*/ key_list_ = new KeyList(KeyMenuAbility::ALL, this); - key_list_->AddListGroupTab(_("All"), "all", KeyListRow::SECRET_OR_PUBLIC_KEY); + key_list_->AddListGroupTab(tr("All"), "all", + KeyListRow::SECRET_OR_PUBLIC_KEY); key_list_->AddListGroupTab( - _("Only Public Key"), "only_public_key", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Only Public Key"), "only_public_key", + KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -60,7 +64,8 @@ KeyMgmt::KeyMgmt(QWidget* parent) }); key_list_->AddListGroupTab( - _("Has Private Key"), "has_private_key", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Has Private Key"), "has_private_key", + KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -69,7 +74,7 @@ KeyMgmt::KeyMgmt(QWidget* parent) }); key_list_->AddListGroupTab( - _("No Primary Key"), "no_primary_key", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("No Primary Key"), "no_primary_key", KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -78,7 +83,7 @@ KeyMgmt::KeyMgmt(QWidget* parent) }); key_list_->AddListGroupTab( - _("Revoked"), "revoked", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Revoked"), "revoked", KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -86,7 +91,7 @@ KeyMgmt::KeyMgmt(QWidget* parent) }); key_list_->AddListGroupTab( - _("Expired"), "expired", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Expired"), "expired", KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -94,9 +99,10 @@ KeyMgmt::KeyMgmt(QWidget* parent) }); setCentralWidget(key_list_); - key_list_->SetDoubleClickedAction([this](const GpgKey& key, QWidget* parent) { - new KeyDetailsDialog(key, this); - }); + key_list_->SetDoubleClickedAction( + [this](const GpgKey& key, QWidget* /*parent*/) { + new KeyDetailsDialog(key, this); + }); key_list_->SlotRefresh(); @@ -110,168 +116,195 @@ KeyMgmt::KeyMgmt(QWidget* parent) this->statusBar()->show(); - setWindowTitle(_("KeyPair Management")); + setWindowTitle(tr("KeyPair Management")); + setMinimumSize(QSize(600, 400)); key_list_->AddMenuAction(generate_subkey_act_); key_list_->AddMenuAction(delete_selected_keys_act_); key_list_->AddSeparator(); + key_list_->AddMenuAction(set_owner_trust_of_key_act_); + key_list_->AddSeparator(); key_list_->AddMenuAction(show_key_details_act_); - connect(this, &KeyMgmt::SignalKeyStatusUpdated, SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); - connect(SignalStation::GetInstance(), &SignalStation::SignalRefreshStatusBar, - this, [=](const QString& message, int timeout) { + connect(this, &KeyMgmt::SignalKeyStatusUpdated, + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalRefreshStatusBar, this, + [=](const QString& message, int timeout) { statusBar()->showMessage(message, timeout); }); } void KeyMgmt::create_actions() { - open_key_file_act_ = new QAction(_("Open"), this); - open_key_file_act_->setShortcut(QKeySequence(_("Ctrl+O"))); - open_key_file_act_->setToolTip(_("Open Key File")); + open_key_file_act_ = new QAction(tr("Open"), this); + open_key_file_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_O)); + open_key_file_act_->setToolTip(tr("Open Key File")); connect(open_key_file_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromFile(this); }); - close_act_ = new QAction(_("Close"), this); - close_act_->setShortcut(QKeySequence(_("Ctrl+Q"))); - close_act_->setIcon(QIcon(":exit.png")); - close_act_->setToolTip(_("Close")); + close_act_ = new QAction(tr("Close"), this); + close_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q)); + close_act_->setIcon(QIcon(":/icons/exit.png")); + close_act_->setToolTip(tr("Close")); connect(close_act_, &QAction::triggered, this, &KeyMgmt::close); - generate_key_pair_act_ = new QAction(_("New Keypair"), this); - generate_key_pair_act_->setShortcut(QKeySequence(_("Ctrl+N"))); - generate_key_pair_act_->setIcon(QIcon(":key_generate.png")); - generate_key_pair_act_->setToolTip(_("Generate KeyPair")); + generate_key_pair_act_ = new QAction(tr("New Keypair"), this); + generate_key_pair_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); + generate_key_pair_act_->setIcon(QIcon(":/icons/key_generate.png")); + generate_key_pair_act_->setToolTip(tr("Generate KeyPair")); connect(generate_key_pair_act_, &QAction::triggered, this, &KeyMgmt::SlotGenerateKeyDialog); - generate_subkey_act_ = new QAction(_("New Subkey"), this); - generate_subkey_act_->setShortcut(QKeySequence(_("Ctrl+Shift+N"))); - generate_subkey_act_->setIcon(QIcon(":key_generate.png")); - generate_subkey_act_->setToolTip(_("Generate Subkey For Selected KeyPair")); + generate_subkey_act_ = new QAction(tr("New Subkey"), this); + generate_subkey_act_->setShortcut( + QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N)); + generate_subkey_act_->setIcon(QIcon(":/icons/key_generate.png")); + generate_subkey_act_->setToolTip(tr("Generate Subkey For Selected KeyPair")); connect(generate_subkey_act_, &QAction::triggered, this, &KeyMgmt::SlotGenerateSubKey); - import_key_from_file_act_ = new QAction(_("File"), this); - import_key_from_file_act_->setIcon(QIcon(":import_key_from_file.png")); - import_key_from_file_act_->setToolTip(_("Import New Key From File")); + import_key_from_file_act_ = new QAction(tr("File"), this); + import_key_from_file_act_->setIcon(QIcon(":/icons/import_key_from_file.png")); + import_key_from_file_act_->setToolTip(tr("Import New Key From File")); connect(import_key_from_file_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromFile(this); }); - import_key_from_clipboard_act_ = new QAction(_("Clipboard"), this); + import_key_from_clipboard_act_ = new QAction(tr("Clipboard"), this); import_key_from_clipboard_act_->setIcon( - QIcon(":import_key_from_clipboard.png")); + QIcon(":/icons/import_key_from_clipboard.png")); import_key_from_clipboard_act_->setToolTip( - _("Import New Key From Clipboard")); + tr("Import New Key From Clipboard")); connect(import_key_from_clipboard_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromClipboard(this); }); - bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); + bool const forbid_all_gnupg_connection = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("network/forbid_all_gnupg_connection", false) + .toBool(); - import_key_from_key_server_act_ = new QAction(_("Keyserver"), this); + import_key_from_key_server_act_ = new QAction(tr("Keyserver"), this); import_key_from_key_server_act_->setIcon( - QIcon(":import_key_from_server.png")); + QIcon(":/icons/import_key_from_server.png")); import_key_from_key_server_act_->setToolTip( - _("Import New Key From Keyserver")); + tr("Import New Key From Keyserver")); import_key_from_key_server_act_->setDisabled(forbid_all_gnupg_connection); - connect(import_key_from_key_server_act_, &QAction::triggered, this, [&]() { + connect(import_key_from_key_server_act_, &QAction::triggered, this, [this]() { CommonUtils::GetInstance()->SlotImportKeyFromKeyServer(this); }); - import_keys_from_key_package_act_ = new QAction(_("Key Package"), this); - import_keys_from_key_package_act_->setIcon(QIcon(":key_package.png")); + import_keys_from_key_package_act_ = new QAction(tr("Key Package"), this); + import_keys_from_key_package_act_->setIcon(QIcon(":/icons/key_package.png")); import_keys_from_key_package_act_->setToolTip( - _("Import Key(s) From a Key Package")); + tr("Import Key(s) From a Key Package")); connect(import_keys_from_key_package_act_, &QAction::triggered, this, &KeyMgmt::SlotImportKeyPackage); - export_key_to_clipboard_act_ = new QAction(_("Export To Clipboard"), this); - export_key_to_clipboard_act_->setIcon(QIcon(":export_key_to_clipboard.png")); + export_key_to_clipboard_act_ = new QAction(tr("Export To Clipboard"), this); + export_key_to_clipboard_act_->setIcon( + QIcon(":/icons/export_key_to_clipboard.png")); export_key_to_clipboard_act_->setToolTip( - _("Export Selected Key(s) To Clipboard")); + tr("Export Checked Key(s) To Clipboard")); connect(export_key_to_clipboard_act_, &QAction::triggered, this, &KeyMgmt::SlotExportKeyToClipboard); - export_key_to_file_act_ = new QAction(_("Export To Key Package"), this); - export_key_to_file_act_->setIcon(QIcon(":key_package.png")); + export_key_to_file_act_ = new QAction(tr("Export As Key Package"), this); + export_key_to_file_act_->setIcon(QIcon(":/icons/key_package.png")); export_key_to_file_act_->setToolTip( - _("Export Checked Key(s) To a Key Package")); + tr("Export Checked Key(s) To a Key Package")); connect(export_key_to_file_act_, &QAction::triggered, this, &KeyMgmt::SlotExportKeyToKeyPackage); - export_key_as_open_ssh_format_ = new QAction(_("Export As OpenSSH"), this); - export_key_as_open_ssh_format_->setIcon(QIcon(":ssh-key.png")); + export_key_as_open_ssh_format_ = new QAction(tr("Export As OpenSSH"), this); + export_key_as_open_ssh_format_->setIcon(QIcon(":/icons/ssh-key.png")); export_key_as_open_ssh_format_->setToolTip( - _("Export Selected Key(s) As OpenSSH Format to File")); + tr("Export Checked Key As OpenSSH Format to File")); connect(export_key_as_open_ssh_format_, &QAction::triggered, this, &KeyMgmt::SlotExportAsOpenSSHFormat); - delete_selected_keys_act_ = new QAction(_("Delete Selected Key(s)"), this); - delete_selected_keys_act_->setToolTip(_("Delete the Selected keys")); + delete_selected_keys_act_ = new QAction(tr("Delete Selected Key(s)"), this); + delete_selected_keys_act_->setToolTip(tr("Delete the Selected keys")); connect(delete_selected_keys_act_, &QAction::triggered, this, &KeyMgmt::SlotDeleteSelectedKeys); - delete_checked_keys_act_ = new QAction(_("Delete Checked Key(s)"), this); - delete_checked_keys_act_->setToolTip(_("Delete the Checked keys")); - delete_checked_keys_act_->setIcon(QIcon(":button_delete.png")); + delete_checked_keys_act_ = new QAction(tr("Delete Checked Key(s)"), this); + delete_checked_keys_act_->setToolTip(tr("Delete the Checked keys")); + delete_checked_keys_act_->setIcon(QIcon(":/icons/button_delete.png")); connect(delete_checked_keys_act_, &QAction::triggered, this, &KeyMgmt::SlotDeleteCheckedKeys); - show_key_details_act_ = new QAction(_("Show Key Details"), this); - show_key_details_act_->setToolTip(_("Show Details for this Key")); + show_key_details_act_ = new QAction(tr("Show Key Details"), this); + show_key_details_act_->setToolTip(tr("Show Details for this Key")); connect(show_key_details_act_, &QAction::triggered, this, &KeyMgmt::SlotShowKeyDetails); + + set_owner_trust_of_key_act_ = new QAction(tr("Set Owner Trust Level"), this); + set_owner_trust_of_key_act_->setToolTip(tr("Set Owner Trust Level")); + set_owner_trust_of_key_act_->setData(QVariant("set_owner_trust_level")); + connect(set_owner_trust_of_key_act_, &QAction::triggered, this, [this]() { + auto keys_selected = key_list_->GetSelected(); + if (keys_selected->empty()) return; + + auto* function = new SetOwnerTrustLevel(this); + function->Exec(keys_selected->front()); + function->deleteLater(); + }); } void KeyMgmt::create_menus() { - file_menu_ = menuBar()->addMenu(_("File")); + file_menu_ = menuBar()->addMenu(tr("File")); file_menu_->addAction(open_key_file_act_); file_menu_->addAction(close_act_); - key_menu_ = menuBar()->addMenu(_("Key")); - generate_key_menu_ = key_menu_->addMenu(_("Generate Key")); + key_menu_ = menuBar()->addMenu(tr("Key")); + generate_key_menu_ = key_menu_->addMenu(tr("Generate Key")); generate_key_menu_->addAction(generate_key_pair_act_); generate_key_menu_->addAction(generate_subkey_act_); - import_key_menu_ = key_menu_->addMenu(_("Import Key")); + import_key_menu_ = key_menu_->addMenu(tr("Import Key")); import_key_menu_->addAction(import_key_from_file_act_); import_key_menu_->addAction(import_key_from_clipboard_act_); import_key_menu_->addAction(import_key_from_key_server_act_); import_key_menu_->addAction(import_keys_from_key_package_act_); - key_menu_->addAction(export_key_to_file_act_); - key_menu_->addAction(export_key_to_clipboard_act_); - key_menu_->addAction(export_key_as_open_ssh_format_); + export_key_menu_ = key_menu_->addMenu(tr("Export Key")); + export_key_menu_->addAction(export_key_to_file_act_); + export_key_menu_->addAction(export_key_to_clipboard_act_); + export_key_menu_->addAction(export_key_as_open_ssh_format_); key_menu_->addSeparator(); key_menu_->addAction(delete_checked_keys_act_); } void KeyMgmt::create_tool_bars() { - QToolBar* key_tool_bar = addToolBar(_("Key")); + QToolBar* key_tool_bar = addToolBar(tr("Key")); key_tool_bar->setObjectName("keytoolbar"); // genrate key pair key_tool_bar->addAction(generate_key_pair_act_); + key_tool_bar->addSeparator(); // add button with popup menu for import - auto* tool_button = new QToolButton(this); - tool_button->setMenu(import_key_menu_); - tool_button->setPopupMode(QToolButton::InstantPopup); - tool_button->setIcon(QIcon(":key_import.png")); - tool_button->setToolTip(_("Import key")); - tool_button->setText(_("Import Key")); - tool_button->setToolButtonStyle(icon_style_); - key_tool_bar->addWidget(tool_button); + auto* import_tool_button = new QToolButton(this); + import_tool_button->setMenu(import_key_menu_); + import_tool_button->setPopupMode(QToolButton::InstantPopup); + import_tool_button->setIcon(QIcon(":/icons/key_import.png")); + import_tool_button->setToolTip(tr("Import key")); + import_tool_button->setText(tr("Import Key")); + import_tool_button->setToolButtonStyle(icon_style_); + key_tool_bar->addWidget(import_tool_button); + + auto* export_tool_button = new QToolButton(this); + export_tool_button->setMenu(export_key_menu_); + export_tool_button->setPopupMode(QToolButton::InstantPopup); + export_tool_button->setIcon(QIcon(":/icons/key_export.png")); + export_tool_button->setToolTip(tr("Export key")); + export_tool_button->setText(tr("Export Key")); + export_tool_button->setToolButtonStyle(icon_style_); + key_tool_bar->addWidget(export_tool_button); - key_tool_bar->addSeparator(); key_tool_bar->addAction(delete_checked_keys_act_); - key_tool_bar->addSeparator(); - key_tool_bar->addAction(export_key_to_file_act_); - key_tool_bar->addAction(export_key_to_clipboard_act_); - key_tool_bar->addAction(export_key_as_open_ssh_format_); } void KeyMgmt::SlotDeleteSelectedKeys() { @@ -293,19 +326,17 @@ void KeyMgmt::delete_keys_with_warning(KeyIdArgsListPtr uidList) { for (const auto& key_id : *uidList) { auto key = GpgKeyGetter::GetInstance().GetKey(key_id); if (!key.IsGood()) continue; - keynames.append(QString::fromStdString(key.GetName())); + keynames.append(key.GetName()); keynames.append("<i> <"); - keynames.append(QString::fromStdString(key.GetEmail())); + keynames.append(key.GetEmail()); keynames.append("> </i><br/>"); } - int ret = QMessageBox::warning( - this, _("Deleting Keys"), - "<b>" + - QString( - _("Are you sure that you want to delete the following keys?")) + + int const ret = QMessageBox::warning( + this, tr("Deleting Keys"), + "<b>" + tr("Are you sure that you want to delete the following keys?") + "</b><br/><br/>" + keynames + +"<br/>" + - _("The action can not be undone."), + tr("The action can not be undone."), QMessageBox::No | QMessageBox::Yes); if (ret == QMessageBox::Yes) { @@ -321,7 +352,7 @@ void KeyMgmt::SlotShowKeyDetails() { auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } @@ -332,133 +363,193 @@ void KeyMgmt::SlotExportKeyToKeyPackage() { auto keys_checked = key_list_->GetChecked(); if (keys_checked->empty()) { QMessageBox::critical( - this, _("Forbidden"), - _("Please check some keys before doing this operation.")); + this, tr("Forbidden"), + tr("Please check some keys before doing this operation.")); return; } - auto dialog = new ExportKeyPackageDialog(std::move(keys_checked), this); + auto* dialog = new ExportKeyPackageDialog(std::move(keys_checked), this); dialog->exec(); - emit SignalStatusBarChanged(QString(_("key(s) exported"))); + emit SignalStatusBarChanged(tr("key(s) exported")); } void KeyMgmt::SlotExportKeyToClipboard() { auto keys_checked = key_list_->GetChecked(); if (keys_checked->empty()) { QMessageBox::critical( - this, _("Forbidden"), - _("Please check some keys before doing this operation.")); + this, tr("Forbidden"), + tr("Please check some keys before doing this operation.")); return; } - ByteArrayPtr key_export_data = nullptr; - if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked, - key_export_data)) { - return; + if (keys_checked->size() == 1) { + auto key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front()); + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance().ExportKey(key, false, true, false); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + QApplication::clipboard()->setText(gf_buffer.ConvertToQByteArray()); + } else { + auto keys = GpgKeyGetter::GetInstance().GetKeys(keys_checked); + CommonUtils::WaitForOpera( + this, tr("Exporting"), [=](const OperaWaitingHd& op_hd) { + GpgKeyImportExporter::GetInstance().ExportKeys( + *keys, false, true, false, false, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + if (data_obj == nullptr || !data_obj->Check<GFBuffer>()) { + GF_CORE_LOG_ERROR("data object checking failed"); + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto gf_buffer = ExtractParams<GFBuffer>(data_obj, 0); + QApplication::clipboard()->setText( + gf_buffer.ConvertToQByteArray()); + }); + }); } - QApplication::clipboard()->setText(QString::fromStdString(*key_export_data)); } void KeyMgmt::SlotGenerateKeyDialog() { - auto* keyGenDialog = new KeyGenDialog(this); - keyGenDialog->show(); + (new KeyGenDialog(this))->exec(); + this->raise(); } void KeyMgmt::SlotGenerateSubKey() { auto keys_selected = key_list_->GetSelected(); if (keys_selected->empty()) { QMessageBox::information( - this, _("Invalid Operation"), - _("Please select one KeyPair before doing this operation.")); + this, tr("Invalid Operation"), + tr("Please select one KeyPair before doing this operation.")); return; } const auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } if (!key.IsPrivateKey()) { - QMessageBox::critical(this, _("Invalid Operation"), - _("If a key pair does not have a private key then " - "it will not be able to generate sub-keys.")); + QMessageBox::critical(this, tr("Invalid Operation"), + tr("If a key pair does not have a private key then " + "it will not be able to generate sub-keys.")); return; } - auto dialog = new SubkeyGenerateDialog(key.GetId(), this); - dialog->show(); + (new SubkeyGenerateDialog(key.GetId(), this))->exec(); + this->raise(); } void KeyMgmt::SlotExportAsOpenSSHFormat() { - ByteArrayPtr key_export_data = nullptr; auto keys_checked = key_list_->GetChecked(); - if (keys_checked->empty()) { QMessageBox::critical( - this, _("Forbidden"), - _("Please select a key before performing this operation. If you select " - "multiple keys, only the first key will be exported.")); - return; - } - - auto key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front()); - if (!GpgKeyImportExporter::GetInstance().ExportKeyOpenSSH(key, - key_export_data)) { - QMessageBox::critical(this, _("Error"), _("An error occur in exporting.")); - return; - } - - if (key_export_data->empty()) { - QMessageBox::critical( - this, _("Error"), - _("This key may not be able to export as OpenSSH format. Please check " - "the key-size of the subkey(s) used to sign.")); + this, tr("Forbidden"), + tr("Please check a key before performing this operation.")); return; } - key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front()); - if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + if (keys_checked->size() > 1) { + QMessageBox::critical(this, tr("Forbidden"), + tr("This operation accepts just a single key.")); return; } - QString fileString = QString::fromStdString( - key.GetName() + " " + key.GetEmail() + "(" + key.GetId() + ").pub"); - QString file_name = QFileDialog::getSaveFileName( - this, _("Export OpenSSH Key To File"), fileString, - QString(_("OpenSSH Public Key Files")) + " (*.pub);;All Files (*)"); - - if (!file_name.isEmpty()) { - write_buffer_to_file(file_name.toStdString(), *key_export_data); - emit SignalStatusBarChanged(QString(_("key(s) exported"))); - } + auto keys = GpgKeyGetter::GetInstance().GetKeys(keys_checked); + CommonUtils::WaitForOpera( + this, tr("Exporting"), [this, keys](const OperaWaitingHd& op_hd) { + GpgKeyImportExporter::GetInstance().ExportKeys( + *keys, false, true, false, true, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + if (data_obj == nullptr || !data_obj->Check<GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto gf_buffer = ExtractParams<GFBuffer>(data_obj, 0); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + if (gf_buffer.Empty()) { + QMessageBox::critical( + this, tr("Error"), + tr("This key may not be able to export as OpenSSH format. " + "Please check the key-size of the subkey(s) used to " + "sign.")); + return; + } + + QString const file_name = QFileDialog::getSaveFileName( + this, tr("Export OpenSSH Key To File"), "authorized_keys", + tr("OpenSSH Public Key Files") + "All Files (*)"); + + if (!file_name.isEmpty()) { + WriteFileGFBuffer(file_name, gf_buffer); + emit SignalStatusBarChanged(tr("key(s) exported")); + } + }); + }); } void KeyMgmt::SlotImportKeyPackage() { - SPDLOG_INFO("Importing key package..."); + GF_UI_LOG_INFO("Importing key package..."); auto key_package_file_name = QFileDialog::getOpenFileName( - this, _("Import Key Package"), {}, - QString(_("Key Package")) + " (*.gfepack);;All Files (*)"); + this, tr("Import Key Package"), {}, + tr("Key Package") + " (*.gfepack);;All Files (*)"); auto key_file_name = QFileDialog::getOpenFileName( - this, _("Import Key Package Passphrase File"), {}, - QString(_("Key Package Passphrase File")) + " (*.key);;All Files (*)"); + this, tr("Import Key Package Passphrase File"), {}, + tr("Key Package Passphrase File") + " (*.key);;All Files (*)"); if (key_package_file_name.isEmpty() || key_file_name.isEmpty()) return; - GpgImportInformation info; + GF_UI_LOG_INFO("importing key package: {}", key_package_file_name); - SPDLOG_INFO("importing key package: {}", key_package_file_name.toStdString()); + const auto [success, info] = KeyPackageOperator::ImportKeyPackage( + key_package_file_name, key_file_name); - if (KeyPackageOperator::ImportKeyPackage(key_package_file_name.toStdString(), - key_file_name.toStdString(), info)) { - emit SignalStatusBarChanged(QString(_("key(s) imported"))); + if (success) { + emit SignalStatusBarChanged(tr("key(s) imported")); emit SignalKeyStatusUpdated(); - auto dialog = new KeyImportDetailDialog(info, false, this); + auto* dialog = new KeyImportDetailDialog(info, this); dialog->exec(); } else { - QMessageBox::critical(this, _("Error"), - _("An error occur in importing key package.")); + QMessageBox::critical(this, tr("Error"), + tr("An error occur in importing key package.")); } } diff --git a/src/ui/main_window/KeyMgmt.h b/src/ui/main_window/KeyMgmt.h index 2073113a..696ce733 100644 --- a/src/ui/main_window/KeyMgmt.h +++ b/src/ui/main_window/KeyMgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEYMGMT_H__ -#define __KEYMGMT_H__ +#pragma once #include "ui/GpgFrontendUI.h" #include "ui/dialog/import_export/KeyImportDetailDialog.h" @@ -150,11 +149,13 @@ class KeyMgmt : public GeneralMainWindow { */ void delete_keys_with_warning(GpgFrontend::KeyIdArgsListPtr uidList); - KeyList* key_list_; ///< - QMenu* file_menu_{}; ///< - QMenu* key_menu_{}; ///< - QMenu* generate_key_menu_{}; ///< - QMenu* import_key_menu_{}; ///< + KeyList* key_list_; ///< + QMenu* file_menu_{}; ///< + QMenu* key_menu_{}; ///< + QMenu* generate_key_menu_{}; ///< + QMenu* import_key_menu_{}; ///< + QMenu* export_key_menu_{}; /// < + QAction* open_key_file_act_{}; ///< QAction* export_key_to_file_act_{}; ///< QAction* export_key_as_open_ssh_format_{}; ///< @@ -170,9 +171,8 @@ class KeyMgmt : public GeneralMainWindow { QAction* import_keys_from_key_package_act_{}; ///< QAction* close_act_{}; ///< QAction* show_key_details_act_{}; ///< - KeyServerImportDialog* import_dialog_{}; ///< + QAction* set_owner_trust_of_key_act_{}; + KeyServerImportDialog* import_dialog_{}; ///< }; } // namespace GpgFrontend::UI - -#endif // __KEYMGMT_H__ diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index b07ad309..f0a2be29 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,24 +28,27 @@ #include "MainWindow.h" -#include "core/GpgConstants.h" +#include "core/GpgModel.h" #include "core/function/CacheManager.h" +#include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAdvancedOperator.h" -#include "main_window/GeneralMainWindow.h" -#include "nlohmann/json_fwd.hpp" -#include "spdlog/spdlog.h" -#include "ui/SignalStation.h" -#include "ui/UserInterfaceUtils.h" +#include "core/module/ModuleManager.h" +#include "ui/UISignalStation.h" +#include "ui/main_window/GeneralMainWindow.h" #include "ui/struct/SettingsObject.h" -#include "ui/thread/VersionCheckTask.h" -#include "widgets/KeyList.h" +#include "ui/struct/settings/KeyServerSO.h" +#include "ui/widgets/KeyList.h" namespace GpgFrontend::UI { MainWindow::MainWindow() : GeneralMainWindow("main_window") { this->setMinimumSize(1200, 700); this->setWindowTitle(qApp->applicationName()); + + connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalNeedUserInputPassphrase, this, + &MainWindow::SlotRaisePinentry); } void MainWindow::Init() noexcept { @@ -84,19 +87,19 @@ void MainWindow::Init() noexcept { this->menuBar()->show(); connect(this, &MainWindow::SignalRestartApplication, - SignalStation::GetInstance(), - &SignalStation::SignalRestartApplication); + UISignalStation::GetInstance(), + &UISignalStation::SignalRestartApplication); - connect(this, &MainWindow::SignalUIRefresh, SignalStation::GetInstance(), - &SignalStation::SignalUIRefresh); + connect(this, &MainWindow::SignalUIRefresh, UISignalStation::GetInstance(), + &UISignalStation::SignalUIRefresh); connect(this, &MainWindow::SignalKeyDatabaseRefresh, - SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); connect(edit_->tab_widget_, &QTabWidget::currentChanged, this, &MainWindow::slot_disable_tab_actions); - connect(SignalStation::GetInstance(), - &SignalStation::SignalRefreshStatusBar, this, + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalRefreshStatusBar, this, [=](const QString &message, int timeout) { statusBar()->showMessage(message, timeout); }); @@ -120,163 +123,101 @@ void MainWindow::Init() noexcept { edit_->CurTextPage()->setFocus(); - auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("wizard") || - settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup) - settings.add("wizard", libconfig::Setting::TypeGroup); - - auto &wizard = settings["wizard"]; - - // Show wizard, if the don't show wizard message box wasn't checked - // and keylist doesn't contain a private key - - if (!wizard.exists("show_wizard")) - wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = true; - - bool show_wizard = true; - wizard.lookupValue("show_wizard", show_wizard); - - SPDLOG_DEBUG("wizard show_wizard: {}", show_wizard); - - if (show_wizard) { - slot_start_wizard(); - } - - emit SignalLoaded(); - - // if not prohibit update checking - if (!prohibit_update_checking_) { - auto *version_task = new VersionCheckTask(); - - connect(version_task, &VersionCheckTask::SignalUpgradeVersion, this, - &MainWindow::slot_version_upgrade); - - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network) - ->PostTask(version_task); - } - // before application exit connect(qApp, &QCoreApplication::aboutToQuit, this, []() { - SPDLOG_DEBUG("about to quit process started"); - - if (GlobalSettingStation::GetInstance().LookupSettings( - "general.clear_gpg_password_cache", false)) { - if (GpgFrontend::GpgAdvancedOperator::GetInstance() - .ClearGpgPasswordCache()) { - SPDLOG_DEBUG("clear gpg password cache done"); - } else { - SPDLOG_ERROR("clear gpg password cache error"); - } + GF_UI_LOG_DEBUG("about to quit process started"); + + if (GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/clear_gpg_password_cache", false) + .toBool()) { + GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache( + [](int, DataObjectPtr) { + + }); } }); + Module::ListenRTPublishEvent( + this, "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.loading_done", + [=](Module::Namespace, Module::Key, int, std::any) { + GF_UI_LOG_DEBUG( + "versionchecking version.loading_done changed, calling slot " + "version upgrade"); + this->slot_version_upgrade_nofity(); + }); + + // loading process is done + emit SignalLoaded(); + Module::TriggerEvent("APPLICATION_LOADED"); + // recover unsaved page from cache if it exists recover_editor_unsaved_pages_from_cache(); + // check if need to open wizard window + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + bool show_wizard = settings.value("wizard/show_wizard", true).toBool(); + if (show_wizard) slot_start_wizard(); + } catch (...) { - SPDLOG_ERROR(_("Critical error occur while loading GpgFrontend.")); - QMessageBox::critical(nullptr, _("Loading Failed"), - _("Critical error occur while loading GpgFrontend.")); + GF_UI_LOG_ERROR(tr("Critical error occur while loading GpgFrontend.")); + QMessageBox::critical( + nullptr, tr("Loading Failed"), + tr("Critical error occur while loading GpgFrontend.")); QCoreApplication::quit(); exit(0); } } void MainWindow::restore_settings() { - try { - SPDLOG_DEBUG("restore settings key_server"); - - SettingsObject key_server_json("key_server"); - if (!key_server_json.contains("server_list") || - key_server_json["server_list"].empty()) { - key_server_json["server_list"] = {"https://keyserver.ubuntu.com", - "https://keys.openpgp.org"}; - } - if (!key_server_json.contains("default_server")) { - key_server_json["default_server"] = 0; - } - - auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("general") || - settings.lookup("general").getType() != libconfig::Setting::TypeGroup) - settings.add("general", libconfig::Setting::TypeGroup); - - auto &general = settings["general"]; - - if (!general.exists("save_key_checked")) { - general.add("save_key_checked", libconfig::Setting::TypeBoolean) = true; - } + GF_UI_LOG_DEBUG("restore settings for main windows"); - if (!general.exists("non_ascii_when_export")) { - general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) = - true; - } + KeyServerSO key_server(SettingsObject("key_server")); + if (key_server.server_list.empty()) key_server.ResetDefaultServerList(); + if (key_server.default_server < 0) key_server.default_server = 0; - bool save_key_checked = true; - general.lookupValue("save_key_checked", save_key_checked); - - // set appearance - import_button_->setToolButtonStyle(icon_style_); - - try { - SPDLOG_DEBUG("restore settings default_key_checked"); - - // Checked Keys - SettingsObject default_key_checked("default_key_checked"); - if (save_key_checked) { - auto key_ids_ptr = std::make_unique<KeyIdArgsList>(); - for (auto &it : default_key_checked) { - std::string key_id = it; - SPDLOG_DEBUG("get checked key id: {}", key_id); - key_ids_ptr->push_back(key_id); - } - m_key_list_->SetChecked(std::move(key_ids_ptr)); - } - } catch (...) { - SPDLOG_ERROR("restore default_key_checked failed"); - } + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + if (!settings.contains("basic/non_ascii_when_export")) { + settings.setValue("basic/non_ascii_when_export", true); + } - prohibit_update_checking_ = false; - try { - prohibit_update_checking_ = - settings.lookup("network.prohibit_update_checking"); - } catch (...) { - SPDLOG_ERROR("setting operation error: prohibit_update_checking"); - } + // set appearance + import_button_->setToolButtonStyle(icon_style_); - } catch (...) { - SPDLOG_ERROR("cannot resolve settings"); - } + prohibit_update_checking_ = + settings.value("network/prohibit_update_check").toBool(); - GlobalSettingStation::GetInstance().SyncSettings(); - SPDLOG_DEBUG("settings restored"); + GF_UI_LOG_DEBUG("settings restored"); } void MainWindow::recover_editor_unsaved_pages_from_cache() { - auto unsaved_page_array = - CacheManager::GetInstance().LoadCache("editor_unsaved_pages"); + auto json_data = + CacheManager::GetInstance().LoadDurableCache("editor_unsaved_pages"); - if (!unsaved_page_array.is_array() || unsaved_page_array.empty()) { + if (json_data.isEmpty() || !json_data.isArray()) { return; } - SPDLOG_DEBUG("plan ot recover unsaved page from cache, page array: {}", - unsaved_page_array.dump()); + GF_UI_LOG_DEBUG("plan ot recover unsaved page from cache, page array: {}", + json_data.toJson()); bool first = true; - for (auto &unsaved_page_json : unsaved_page_array) { + QJsonArray unsaved_page_array = json_data.array(); + for (const auto &value_ref : unsaved_page_array) { + if (!value_ref.isObject()) continue; + auto unsaved_page_json = value_ref.toObject(); + if (!unsaved_page_json.contains("title") || !unsaved_page_json.contains("content")) { continue; } - std::string title = unsaved_page_json["title"]; - std::string content = unsaved_page_json["content"]; - SPDLOG_DEBUG( + QString title = unsaved_page_json["title"].toString(); + QString content = unsaved_page_json["content"].toString(); + + GF_UI_LOG_DEBUG( "recovering unsaved page from cache, page title: {}, content size", title, content.size()); @@ -289,27 +230,6 @@ void MainWindow::recover_editor_unsaved_pages_from_cache() { } } -void MainWindow::save_settings() { - bool save_key_checked = GlobalSettingStation::GetInstance().LookupSettings( - "general.save_key_checked", false); - - // keyid-list of private checked keys - if (save_key_checked) { - auto key_ids_need_to_store = m_key_list_->GetChecked(); - - SettingsObject default_key_checked("default_key_checked"); - default_key_checked.clear(); - - for (const auto &key_id : *key_ids_need_to_store) - default_key_checked.push_back(key_id); - } else { - auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); - settings["general"].remove("save_key_checked"); - } - - GlobalSettingStation::GetInstance().SyncSettings(); -} - void MainWindow::close_attachment_dock() { if (!attachment_dock_created_) { return; @@ -325,7 +245,6 @@ void MainWindow::closeEvent(QCloseEvent *event) { * modified documents in any tab */ if (edit_->MaybeSaveAnyTab()) { - save_settings(); event->accept(); } else { event->ignore(); @@ -333,8 +252,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (event->isAccepted()) { // clear cache of unsaved page - CacheManager::GetInstance().SaveCache("editor_unsaved_pages", - nlohmann::json::array(), true); + CacheManager::GetInstance().SaveDurableCache( + "editor_unsaved_pages", QJsonDocument(QJsonArray()), true); // clear password from memory // GpgContext::GetInstance().clearPasswordCache(); diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index 42f9daf3..66b61d68 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,31 +20,22 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __GPGWIN_H__ -#define __GPGWIN_H__ - -#include "KeyMgmt.h" -#include "core/GpgConstants.h" -#include "core/function/result_analyse/GpgDecryptResultAnalyse.h" -#include "core/function/result_analyse/GpgEncryptResultAnalyse.h" -#include "core/function/result_analyse/GpgSignResultAnalyse.h" -#include "ui/GpgFrontendUI.h" -#include "ui/dialog/WaitingDialog.h" -#include "ui/dialog/Wizard.h" -#include "ui/dialog/help/AboutDialog.h" -#include "ui/dialog/import_export/KeyUploadDialog.h" -#include "ui/dialog/settings/SettingsDialog.h" +#pragma once + #include "ui/main_window/GeneralMainWindow.h" -#include "ui/widgets/FindWidget.h" #include "ui/widgets/InfoBoardWidget.h" #include "ui/widgets/TextEdit.h" +namespace GpgFrontend { +class GpgPassphraseContext; +} + namespace GpgFrontend::UI { /** * @brief @@ -127,82 +118,130 @@ class MainWindow : public GeneralMainWindow { /** * @details Open a new tab for path */ - void SlotOpenFile(QString& path); + void SlotOpenFile(const QString& path); /** - * @details Open dialog for encrypting file. + * @details encrypt the text of currently active textedit-page + * with the currently checked keys */ - void SlotFileEncrypt(); + void SlotEncrypt(); /** - * @details Open dialog for decrypting file. + * @details encrypt and sign the text of currently active textedit-page + * with the currently checked keys */ - void SlotFileDecrypt(); + void SlotEncryptSign(); /** - * @details Open dialog for signing file. + * @details Show a passphrase dialog and decrypt the text of currently active + * tab. */ - void SlotFileSign(); + void SlotDecrypt(); /** - * @details Open dialog for verifying file. + * @details Sign the text of currently active tab with the checked private + * keys */ - void SlotFileVerify(); + void SlotSign(); /** - * @details Open dialog for signing file. + * @details Verify the text of currently active tab and show verify + * information. If document is signed with a key, which is not in keylist, + * show import missing key from keyserver in Menu of verifynotification. */ - void SlotFileEncryptSign(); + void SlotVerify(); /** - * @details Open dialog for verifying file. + * @details decrypt and verify the text of currently active textedit-page + * with the currently checked keys */ - void SlotFileDecryptVerify(); + void SlotDecryptVerify(); /** - * @details get value of member restartNeeded to needed. - * @param needed true, if application has to be restarted + * @details Open dialog for encrypting file. */ - void SlotSetRestartNeeded(int); + void SlotFileEncrypt(const QString&); - private slots: + /** + * @brief + * + */ + void SlotDirectoryEncrypt(const QString&); /** - * @details encrypt the text of currently active textedit-page - * with the currently checked keys + * @brief + * + * @param path */ - void slot_encrypt(); + void SlotFileDecrypt(const QString& path); /** - * @details encrypt and sign the text of currently active textedit-page - * with the currently checked keys + * @brief + * + * @param path */ - void slot_encrypt_sign(); + void SlotArchiveDecrypt(const QString& path); /** - * @details Show a passphrase dialog and decrypt the text of currently active - * tab. + * @brief + * + * @param path */ - void slot_decrypt(); + void SlotFileSign(const QString& path); /** - * @details Sign the text of currently active tab with the checked private - * keys + * @brief + * + * @param path */ - void slot_sign(); + void SlotFileVerify(const QString& path); /** - * @details Verify the text of currently active tab and show verify - * information. If document is signed with a key, which is not in keylist, - * show import missing key from keyserver in Menu of verifynotification. + * @brief + * + * @param path */ - void slot_verify(); + void SlotFileEncryptSign(const QString& path); /** - * @details decrypt and verify the text of currently active textedit-page - * with the currently checked keys + * @brief + * + * @param path + */ + void SlotDirectoryEncryptSign(const QString& path); + + /** + * @brief + * + * @param path + */ + void SlotFileDecryptVerify(const QString& path); + + /** + * @brief + * + * @param path + */ + void SlotArchiveDecryptVerify(const QString& path); + + /** + * @details get value of member restartNeeded to needed. + * @param needed true, if application has to be restarted + */ + void SlotSetRestartNeeded(int); + + /** + * @details Open a new tab for path + */ + void SlotRaisePinentry(QSharedPointer<GpgPassphraseContext>); + + private slots: + + /** + * @brief + * */ - void slot_decrypt_verify(); + void slot_refresh_current_file_view(); /** * @details Show the details of the first of the first of selected keys @@ -315,7 +354,7 @@ class MainWindow : public GeneralMainWindow { /** * @details called when need to upgrade. */ - void slot_version_upgrade(const SoftwareVersion& version); + void slot_version_upgrade_nofity(); /** * @details @@ -380,11 +419,6 @@ class MainWindow : public GeneralMainWindow { void recover_editor_unsaved_pages_from_cache(); /** - * @details Save settings to ini-file. - */ - void save_settings(); - - /** * @brief return true, if restart is needed */ [[nodiscard]] int get_restart_needed() const; @@ -490,5 +524,3 @@ class MainWindow : public GeneralMainWindow { }; } // namespace GpgFrontend::UI - -#endif // __GPGWIN_H__ diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index 6fe8062b..76fd4a9d 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,526 +20,618 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "MainWindow.h" -#include "core/function/ArchiveFileOperator.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgFileOpera.h" #include "core/function/gpg/GpgKeyGetter.h" -#include "core/thread/Task.h" -#include "dialog/SignersPicker.h" +#include "core/function/result_analyse/GpgDecryptResultAnalyse.h" +#include "core/function/result_analyse/GpgEncryptResultAnalyse.h" +#include "core/function/result_analyse/GpgSignResultAnalyse.h" +#include "core/function/result_analyse/GpgVerifyResultAnalyse.h" +#include "core/utils/GpgUtils.h" +#include "core/utils/IOUtils.h" #include "ui/UserInterfaceUtils.h" +#include "ui/dialog/SignersPicker.h" namespace GpgFrontend::UI { -bool path_pre_check(QWidget* parent, const QString& path) { - QFileInfo file_info(path); - QFileInfo path_info(file_info.absolutePath()); - if (!path_info.exists()) { - QMessageBox::critical(parent, _("Error"), - QString(_("The path %1 does not exist.")).arg(path)); - return false; - } - if (!file_info.isReadable()) { - QMessageBox::critical(parent, _("Error"), - _("No permission to read this file.")); - return false; - } - if (!path_info.isWritable()) { - QMessageBox::critical(parent, _("Error"), - _("No permission to create file.")); - return false; - } - return true; -} - -/** - * @brief convert directory into tarball - * - * @param parent parent widget - * @param path the directory to be converted - * @return - */ -bool process_tarball_into_directory(QWidget* parent, - std::filesystem::path& path) { - SPDLOG_DEBUG("converting directory into tarball: {}", path.u8string()); - auto selected_dir_path = std::filesystem::path(path); - - if (selected_dir_path.extension() != ".tar") { - QMessageBox::critical(parent, _("Error"), _("The file is not a tarball.")); - return false; - } - - try { - auto base_path = selected_dir_path.parent_path(); - - auto target_path = selected_dir_path; - target_path.replace_extension(".tar"); - - SPDLOG_DEBUG("base path: {} target archive path: {]", base_path.u8string(), - target_path.u8string()); - - bool if_error = false; - process_operation(parent, _("Extracting Tarball"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - GpgFrontend::ArchiveFileOperator::ExtractArchive( - target_path, base_path); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (if_error || !exists(target_path)) { - throw std::runtime_error("Decompress Failed"); - } - path = target_path.u8string().c_str(); - } catch (...) { - SPDLOG_ERROR("decompress error"); - return false; +void MainWindow::SlotFileEncrypt(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot read from file: %1").arg(QFileInfo(path).fileName())); + return; } - return true; -} -/** - * @brief convert tarball into directory - * - * @param parent parent widget - * @param path the tarball to be converted - */ -bool process_directory_into_tarball(QWidget* parent, QString& path) { -#ifdef WINDOWS - std::filesystem::path selected_dir_path = path.toStdU16String(); -#else - std::filesystem::path selected_dir_path = path.toStdString(); -#endif - - try { - auto base_path = selected_dir_path.parent_path(); - auto target_path = selected_dir_path; - selected_dir_path.replace_extension(""); - - SPDLOG_DEBUG("base path: {} target archive path: {} selected_dir_path: {}", - base_path.u8string(), target_path.u8string(), - selected_dir_path.u8string()); - - bool if_error = false; - process_operation(parent, _("Making Tarball"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - GpgFrontend::ArchiveFileOperator::CreateArchive( - base_path, target_path, 0, {selected_dir_path}); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (if_error || !exists(target_path)) { - throw std::runtime_error("Compress Failed"); - } - path = target_path.u8string().c_str(); - } catch (...) { - SPDLOG_ERROR("compress error"); - return false; - } - return true; -} + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + auto out_path = + SetExtensionOfOutputFile(path, kENCRYPT, !non_ascii_when_export); -void MainWindow::SlotFileEncrypt() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + if (QFile::exists(out_path)) { + auto out_file_name = tr("The target file %1 already exists, " + "do you need to overwrite it?") + .arg(out_path); + auto ret = QMessageBox::warning(this, tr("Warning"), out_file_name, + QMessageBox::Ok | QMessageBox::Cancel); - if (!path_pre_check(this, path)) { - SPDLOG_ERROR("path pre check failed"); + if (ret == QMessageBox::Cancel) return; + } + + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); return; } // check selected keys auto key_ids = m_key_list_->GetChecked(); - GpgEncrResult result = nullptr; - GpgError error; - bool if_error = false; + if (key_ids->empty()) { + // Symmetric Encrypt + auto ret = QMessageBox::information( + this, tr("Symmetric Encryption"), + tr("No Key Selected. Do you want to encrypt with a " + "symmetric cipher using a passphrase?"), + QMessageBox::Ok | QMessageBox::Cancel); + if (ret == QMessageBox::Cancel) return; + + CommonUtils::WaitForOpera( + this, tr("Symmetrically Encrypting"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptFileSymmetric( + path, !non_ascii_when_export, out_path, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || + data_obj == nullptr || + !data_obj->Check<GpgEncryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); + }); + + return; + } - bool non_ascii_when_export = - GlobalSettingStation::GetInstance().LookupSettings( - "general.non_ascii_when_export", true); + auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - // get file info - QFileInfo file_info(path); + // check key abilities + for (const auto& key : *p_keys) { + bool const key_can_encrypt = key.IsHasActualEncryptionCapability(); - if (file_info.isDir()) { - path = path + (file_info.isDir() ? ".tar" : ""); + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for encryption.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); + return; + } } - auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; - auto _extension = ".asc"; - if (non_ascii_when_export || file_info.isDir()) { - _channel = GPGFRONTEND_NON_ASCII_CHANNEL; - _extension = ".gpg"; + CommonUtils::WaitForOpera( + this, tr("Encrypting"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptFile( + {p_keys->begin(), p_keys->end()}, path, !non_ascii_when_export, + out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgEncryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); + }); +} + +void MainWindow::SlotDirectoryEncrypt(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot read from file: %1").arg(QFileInfo(path).fileName())); + return; } - auto out_path = path + _extension; + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + auto out_path = SetExtensionOfOutputFileForArchive(path, kENCRYPT, + !non_ascii_when_export); if (QFile::exists(out_path)) { -#ifdef WINDOWS - std::filesystem::path _out_path = out_path.toStdU16String(); -#else - std::filesystem::path _out_path = out_path.toStdString(); -#endif - auto out_file_name = boost::format(_("The target file %1% already exists, " - "do you need to overwrite it?")) % - _out_path.filename(); - auto ret = - QMessageBox::warning(this, _("Warning"), out_file_name.str().c_str(), - QMessageBox::Ok | QMessageBox::Cancel); + auto out_file_name = tr("The target file %1 already exists, " + "do you need to overwrite it?") + .arg(out_path); + auto ret = QMessageBox::warning(this, tr("Warning"), out_file_name, + QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } - if (file_info.isDir()) { - // stop if the process making tarball failed - if (!process_directory_into_tarball(this, path)) { - QMessageBox::critical(this, _("Error"), - _("Unable to convert the folder into tarball.")); - return; - } + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); + return; } + // check selected keys + auto key_ids = m_key_list_->GetChecked(); + // symmetric encrypt if (key_ids->empty()) { - // Symmetric Encrypt auto ret = QMessageBox::information( - this, _("Symmetric Encryption"), - _("No Key Selected. Do you want to encrypt with a " - "symmetric cipher using a passphrase?"), + this, tr("Symmetric Encryption"), + tr("No Key Selected. Do you want to encrypt with a " + "symmetric cipher using a passphrase?"), QMessageBox::Ok | QMessageBox::Cancel); - if (ret == QMessageBox::Cancel) return; - process_operation( - this, _("Symmetrically Encrypting"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFrontend::GpgFileOpera::EncryptFileSymmetric( - path.toStdString(), out_path.toStdString(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; + CommonUtils::WaitForOpera( + this, tr("Archiving & Symmetrically Encrypting"), + [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptDerectorySymmetric( + path, !non_ascii_when_export, out_path, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (data_obj == nullptr || + !data_obj->Check<GpgEncryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); }); - } else { - auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - - // check key abilities - for (const auto& key : *p_keys) { - bool key_can_encrypt = key.IsHasActualEncryptionCapability(); - - if (!key_can_encrypt) { - QMessageBox::critical( - nullptr, _("Invalid KeyPair"), - QString(_("The selected keypair cannot be used for encryption.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.GetUIDs()->front().GetUID())); - return; - } - } - process_operation(this, _("Encrypting"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::EncryptFile( - std::move(p_keys), path.toStdString(), - out_path.toStdString(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - } - - // remove xxx.tar and only left xxx.tar.gpg - if (file_info.isDir()) { - auto selected_dir_path = std::filesystem::path(path.toStdString()); - auto target_path = selected_dir_path.replace_extension(".tar"); - if (exists(target_path)) { - std::filesystem::remove(target_path); + return; + } + + auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + // check key abilities + for (const auto& key : *p_keys) { + bool const key_can_encrypt = key.IsHasActualEncryptionCapability(); + + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for encryption.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); + return; } } - if (!if_error) { - auto resultAnalyse = GpgEncryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - fileTreeView->update(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); + CommonUtils::WaitForOpera( + this, tr("Archiving & Encrypting"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptDirectory( + {p_keys->begin(), p_keys->end()}, path, !non_ascii_when_export, + out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgEncryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); + }); +} + +void MainWindow::SlotFileDecrypt(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot read from file: %1").arg(QFileInfo(path).fileName())); return; } -} -void MainWindow::SlotFileDecrypt() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + auto out_path = SetExtensionOfOutputFile(path, kDECRYPT, true); + if (QFileInfo(out_path).exists()) { + auto ret = QMessageBox::warning( + this, tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); - if (!path_pre_check(this, path)) return; + if (ret == QMessageBox::Cancel) return; + } + + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); + return; + } -#ifdef WINDOWS - std::filesystem::path out_path = path.toStdU16String(); -#else - std::filesystem::path out_path = path.toStdString(); -#endif + CommonUtils::WaitForOpera( + this, tr("Decrypting"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().DecryptFile( + path, out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); - if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") { - out_path = out_path.parent_path() / out_path.stem(); - } else { - out_path += ".out"; + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgDecryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto result_analyse = GpgDecryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); + }); +} + +void MainWindow::SlotArchiveDecrypt(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot read from file: %1").arg(path)); + return; } - if (exists(out_path)) { + auto out_path = SetExtensionOfOutputFileForArchive(path, kDECRYPT, true); + if (QFileInfo(out_path).exists()) { auto ret = QMessageBox::warning( - this, _("Warning"), - _("The target file already exists, do you need to overwrite it?"), + this, tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } - GpgDecrResult result = nullptr; - gpgme_error_t error; - bool if_error = false; - process_operation(this, _("Decrypting"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::DecryptFile( - path.toStdString(), out_path.u8string(), result); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (!if_error) { - auto resultAnalyse = GpgDecryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - - fileTreeView->update(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); return; } - // extract the tarball - if (out_path.extension() == ".tar" && exists(out_path)) { - bool ret = QMessageBox::information( - this, _("Decrypting"), - _("Do you want to extract and delete the decrypted tarball?"), - QMessageBox::Ok | QMessageBox::Cancel); - if (ret) { - if (process_tarball_into_directory(this, out_path)) { - QMessageBox::information(this, _("Decrypting"), - _("Extracting tarball succeeded.")); - // remove tarball - std::filesystem::remove(out_path); - } else { - QMessageBox::critical(this, _("Decrypting"), - _("Extracting tarball failed.")); - } - } - } -} + CommonUtils::WaitForOpera( + this, tr("Decrypting & Extrating"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().DecryptArchive( + path, out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); -void MainWindow::SlotFileSign() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgDecryptResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } - if (!path_pre_check(this, path)) return; + auto result = ExtractParams<GpgDecryptResult>(data_obj, 0); + auto result_analyse = GpgDecryptResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); + }); +} + +void MainWindow::SlotFileSign(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot read from file: %1").arg(QFileInfo(path).fileName())); + return; + } auto key_ids = m_key_list_->GetChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); if (keys->empty()) { QMessageBox::critical( - this, _("No Key Checked"), - _("Please check the key in the key toolbox on the right.")); + this, tr("No Key Checked"), + tr("Please check the key in the key toolbox on the right.")); return; } for (const auto& key : *keys) { if (!key.IsHasActualSigningCapability()) { QMessageBox::information( - this, _("Invalid Operation"), - QString(_("The selected key contains a key that does not actually " - "have a sign usage.")) + - "<br/><br/>" + _("for example the Following Key:") + " <br/>" + - QString::fromStdString(key.GetUIDs()->front().GetUID())); + this, tr("Invalid Operation"), + tr("The selected key contains a key that does not actually " + "have a sign usage.") + + "<br/><br/>" + tr("for example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); return; } } - bool non_ascii_when_export = - GlobalSettingStation::GetInstance().LookupSettings( - "general.non_ascii_when_export", true); - - auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; - auto _extension = ".asc"; - if (non_ascii_when_export) { - _channel = GPGFRONTEND_NON_ASCII_CHANNEL; - _extension = ".sig"; - } - -#ifdef WINDOWS - std::filesystem::path in_path = path.toStdU16String(); -#else - std::filesystem::path in_path = path.toStdString(); -#endif + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + auto sig_file_path = + SetExtensionOfOutputFile(path, kSIGN, !non_ascii_when_export); - auto sig_file_path = in_path; - sig_file_path += _extension; - if (exists(sig_file_path)) { - auto ret = QMessageBox::warning( - this, _("Warning"), - QString(_("The signature file \"%1\" exists, " - "do you need to overwrite it?")) - .arg(sig_file_path.filename().u8string().c_str()), - QMessageBox::Ok | QMessageBox::Cancel); + if (QFileInfo(sig_file_path).exists()) { + auto ret = QMessageBox::warning(this, tr("Warning"), + tr("The signature file \"%1\" exists, " + "do you need to overwrite it?") + .arg(sig_file_path), + QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } - GpgSignResult result = nullptr; - gpgme_error_t error; - bool if_error = false; - - process_operation( - this, _("Signing"), [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::SignFile(std::move(keys), in_path.u8string(), - sig_file_path.u8string(), result, - _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; + CommonUtils::WaitForOpera( + this, tr("Signing"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().SignFile( + {keys->begin(), keys->end()}, path, !non_ascii_when_export, + sig_file_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgSignResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgSignResult>(data_obj, 0); + auto result_analyse = GpgSignResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + this->slot_refresh_current_file_view(); + }); }); +} - if (!if_error) { - auto resultAnalyse = GpgSignResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); +void MainWindow::SlotFileVerify(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot read from file: %1").arg(QFileInfo(path).fileName())); + return; + } - fileTreeView->update(); + auto file_info = QFileInfo(path); + QString sign_file_path = path; + QString data_file_path; + bool const prossible_singleton_target = + file_info.suffix() == "gpg" || file_info.suffix() == "pgp"; + if (prossible_singleton_target) { + swap(data_file_path, sign_file_path); } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; + data_file_path = file_info.path() + "/" + file_info.baseName(); } - fileTreeView->update(); -} + auto data_file_info = QFileInfo(data_file_path); + if (!prossible_singleton_target && !data_file_info.exists()) { + bool ok; + QString const text = QInputDialog::getText( + this, tr("File to be Verified"), + tr("Please provide An ABSOLUTE Path \n" + "If Data And Signature is COMBINED within a single file, " + "KEEP THIS EMPTY: "), + QLineEdit::Normal, data_file_path, &ok); -void MainWindow::SlotFileVerify() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + if (!ok) return; -#ifdef WINDOWS - std::filesystem::path in_path = path.toStdU16String(); -#else - std::filesystem::path in_path = path.toStdString(); -#endif + data_file_path = text.isEmpty() ? path : text; + } - std::filesystem::path sign_file_path = in_path, data_file_path; + if (!data_file_info.isFile() || + (!sign_file_path.isEmpty() && !QFileInfo(sign_file_path).isFile())) { + QMessageBox::critical( + this, tr("Error"), + tr("Please select the appropriate origin file or signature file. " + "Ensure that both are in this directory.")); + return; + } - bool non_ascii_when_export = - GlobalSettingStation::GetInstance().LookupSettings( - "general.non_ascii_when_export", true); + GF_UI_LOG_DEBUG("verification data file path: {}", data_file_path); + GF_UI_LOG_DEBUG("verification signature file path: {}", sign_file_path); + + CommonUtils::WaitForOpera( + this, tr("Verifying"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().VerifyFile( + data_file_path, sign_file_path, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgVerifyResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgVerifyResult>(data_obj, 0); + auto result_analyse = GpgVerifyResultAnalyse(err, result); + result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, result_analyse); + if (result_analyse.GetStatus() == -2) { + import_unknown_key_from_keyserver(this, result_analyse); + } + if (result_analyse.GetStatus() >= 0) { + show_verify_details(this, info_board_, err, result); + } + + this->slot_refresh_current_file_view(); + }); + }); +} - auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; - if (non_ascii_when_export) { - _channel = GPGFRONTEND_NON_ASCII_CHANNEL; +void MainWindow::SlotFileEncryptSign(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot read from file: %1").arg(path)); + return; } - if (in_path.extension() == ".gpg") { - swap(data_file_path, sign_file_path); - } else if (in_path.extension() == ".sig" || in_path.extension() == ".asc") { - data_file_path = sign_file_path.parent_path() / sign_file_path.stem(); + // check selected keys + auto key_ids = m_key_list_->GetChecked(); + auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + if (p_keys->empty()) { + QMessageBox::critical( + this, tr("No Key Checked"), + tr("Please check the key in the key toolbox on the right.")); + return; } - SPDLOG_DEBUG("sign_file_path: {} {}", sign_file_path.u8string(), - sign_file_path.extension().u8string()); + // check key abilities + for (const auto& key : *p_keys) { + bool const key_can_encrypt = key.IsHasActualEncryptionCapability(); - if (in_path.extension() != ".gpg") { - bool ok; - QString text = QInputDialog::getText( - this, _("Origin file to verify"), _("Filepath"), QLineEdit::Normal, - data_file_path.u8string().c_str(), &ok); - if (ok && !text.isEmpty()) { - data_file_path = text.toStdString(); - } else { + if (!key_can_encrypt) { + QMessageBox::critical( + nullptr, tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for encryption.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); return; } } - if (!is_regular_file(data_file_path) || - (!sign_file_path.empty() && !is_regular_file(sign_file_path))) { - QMessageBox::critical( - this, _("Error"), - _("Please select the appropriate origin file or signature file. " - "Ensure that both are in this directory.")); + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + auto out_path = + SetExtensionOfOutputFile(path, kENCRYPT_SIGN, !non_ascii_when_export); + + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); return; } - SPDLOG_DEBUG("data path: {}", data_file_path.u8string()); - SPDLOG_DEBUG("sign path: {}", sign_file_path.u8string()); - - GpgVerifyResult result = nullptr; - gpgme_error_t error; - bool if_error = false; - process_operation( - this, _("Verifying"), [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::VerifyFile(data_file_path.u8string(), - sign_file_path.u8string(), result, - _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); + if (QFile::exists(out_path)) { + auto ret = QMessageBox::warning( + this, tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), + QMessageBox::Ok | QMessageBox::Cancel); - if (!if_error) { - auto result_analyse = GpgVerifyResultAnalyse(error, result); - result_analyse.Analyse(); - process_result_analyse(edit_, info_board_, result_analyse); + if (ret == QMessageBox::Cancel) return; + } - if (result_analyse.GetStatus() == -2) - import_unknown_key_from_keyserver(this, result_analyse); + auto* signers_picker = new SignersPicker(this); + QEventLoop loop; + connect(signers_picker, &SignersPicker::finished, &loop, &QEventLoop::quit); + loop.exec(); - if (result_analyse.GetStatus() >= 0) - show_verify_details(this, info_board_, error, result); + // return when canceled + if (!signers_picker->GetStatus()) return; - fileTreeView->update(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } -} + auto signer_key_ids = signers_picker->GetCheckedSigners(); + auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); -void MainWindow::SlotFileEncryptSign() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + CommonUtils::WaitForOpera( + this, tr("Encrypting and Signing"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptSignFile( + {p_keys->begin(), p_keys->end()}, + {p_signer_keys->begin(), p_signer_keys->end()}, path, + !non_ascii_when_export, out_path, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgEncryptResult, GpgSignResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto encrypt_result = + ExtractParams<GpgEncryptResult>(data_obj, 0); + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 1); + + auto encrypt_result_analyse = + GpgEncryptResultAnalyse(err, encrypt_result); + encrypt_result_analyse.Analyse(); + + auto sign_result_analyse = GpgSignResultAnalyse(err, sign_result); + sign_result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, encrypt_result_analyse, + sign_result_analyse); + + this->slot_refresh_current_file_view(); + }); + }); +} - if (!path_pre_check(this, path)) return; +void MainWindow::SlotDirectoryEncryptSign(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot read from file: %1").arg(path)); + return; + } // check selected keys auto key_ids = m_key_list_->GetChecked(); @@ -547,205 +639,228 @@ void MainWindow::SlotFileEncryptSign() { if (p_keys->empty()) { QMessageBox::critical( - this, _("No Key Checked"), - _("Please check the key in the key toolbox on the right.")); + this, tr("No Key Checked"), + tr("Please check the key in the key toolbox on the right.")); return; } // check key abilities for (const auto& key : *p_keys) { - bool key_can_encrypt = key.IsHasActualEncryptionCapability(); + bool const key_can_encrypt = key.IsHasActualEncryptionCapability(); if (!key_can_encrypt) { QMessageBox::critical( - nullptr, _("Invalid KeyPair"), - QString(_("The selected keypair cannot be used for encryption.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.GetUIDs()->front().GetUID())); + nullptr, tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for encryption.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); return; } } - bool non_ascii_when_export = - GlobalSettingStation::GetInstance().LookupSettings( - "general.non_ascii_when_export", true); - - // get file info - QFileInfo file_info(path); - - if (file_info.isDir()) { - path = path + (file_info.isDir() ? ".tar" : ""); - } + bool const non_ascii_when_export = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/non_ascii_when_export", true) + .toBool(); + auto out_path = SetExtensionOfOutputFileForArchive(path, kENCRYPT_SIGN, + !non_ascii_when_export); - auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; - auto _extension = ".asc"; - if (non_ascii_when_export || file_info.isDir()) { - _channel = GPGFRONTEND_NON_ASCII_CHANNEL; - _extension = ".gpg"; + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); + return; } - auto out_path = path + _extension; - if (QFile::exists(out_path)) { auto ret = QMessageBox::warning( - this, _("Warning"), - _("The target file already exists, do you need to overwrite it?"), + this, tr("Warning"), + tr("The target file already exists, do you need to overwrite it?"), QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } - auto signersPicker = new SignersPicker(this); + auto* signers_picker = new SignersPicker(this); QEventLoop loop; - connect(signersPicker, &SignersPicker::finished, &loop, &QEventLoop::quit); + connect(signers_picker, &SignersPicker::finished, &loop, &QEventLoop::quit); loop.exec(); // return when canceled - if (!signersPicker->GetStatus()) return; + if (!signers_picker->GetStatus()) return; - auto signer_key_ids = signersPicker->GetCheckedSigners(); + auto signer_key_ids = signers_picker->GetCheckedSigners(); auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - // convert directory into tarball - if (file_info.isDir()) { - // stop if the process making tarball failed - if (!process_directory_into_tarball(this, path)) { - QMessageBox::critical(this, _("Error"), - _("Unable to convert the folder into tarball.")); - return; - } - } - - GpgEncrResult encr_result = nullptr; - GpgSignResult sign_result = nullptr; - - gpgme_error_t error; - bool if_error = false; - - process_operation(this, _("Encrypting and Signing"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::EncryptSignFile( - std::move(p_keys), std::move(p_signer_keys), - path.toStdString(), out_path.toStdString(), - encr_result, sign_result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); + CommonUtils::WaitForOpera( + this, tr("Archiving & Encrypting & Signing"), + [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().EncryptSignDirectory( + {p_keys->begin(), p_keys->end()}, + {p_signer_keys->begin(), p_signer_keys->end()}, path, + !non_ascii_when_export, out_path, + [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgEncryptResult, GpgSignResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto encrypt_result = + ExtractParams<GpgEncryptResult>(data_obj, 0); + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 1); + + auto encrypt_result_analyse = + GpgEncryptResultAnalyse(err, encrypt_result); + encrypt_result_analyse.Analyse(); + + auto sign_result_analyse = GpgSignResultAnalyse(err, sign_result); + sign_result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, encrypt_result_analyse, + sign_result_analyse); + + this->slot_refresh_current_file_view(); + }); + }); +} - if (!if_error) { - auto encrypt_result = - GpgEncryptResultAnalyse(error, std::move(encr_result)); - auto sign_res = GpgSignResultAnalyse(error, std::move(sign_result)); - encrypt_result.Analyse(); - sign_res.Analyse(); - process_result_analyse(edit_, info_board_, encrypt_result, sign_res); +void MainWindow::SlotFileDecryptVerify(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot read from file: %1").arg(path)); + return; + } - fileTreeView->update(); + auto out_path = SetExtensionOfOutputFile(path, kDECRYPT_VERIFY, true); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); return; } - // remove xxx.tar and only left xxx.tar.gpg - if (file_info.isDir()) { - auto selected_dir_path = std::filesystem::path(path.toStdString()); - auto target_path = selected_dir_path.replace_extension(".tar"); - if (exists(target_path)) { - std::filesystem::remove(target_path); - } + if (QFile::exists(out_path)) { + auto ret = QMessageBox::warning(this, tr("Warning"), + tr("The output file %1 already exists, do " + "you need to overwrite it?") + .arg(out_path), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; } -} -void MainWindow::SlotFileDecryptVerify() { - auto fileTreeView = edit_->SlotCurPageFileTreeView(); - auto path = fileTreeView->GetSelected(); + CommonUtils::WaitForOpera( + this, tr("Decrypting and Verifying"), [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().DecryptVerifyFile( + path, out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgDecryptResult, GpgVerifyResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto verify_result = ExtractParams<GpgVerifyResult>(data_obj, 1); + + auto decrypt_result_analyse = + GpgDecryptResultAnalyse(err, decrypt_result); + decrypt_result_analyse.Analyse(); + + auto verify_result_analyse = + GpgVerifyResultAnalyse(err, verify_result); + verify_result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, decrypt_result_analyse, + verify_result_analyse); + if (verify_result_analyse.GetStatus() == -2) { + import_unknown_key_from_keyserver(this, verify_result_analyse); + } + if (verify_result_analyse.GetStatus() >= 0) { + show_verify_details(this, info_board_, err, verify_result); + } + + this->slot_refresh_current_file_view(); + }); + }); +} - if (!path_pre_check(this, path)) return; +void MainWindow::SlotArchiveDecryptVerify(const QString& path) { + auto check_result = TargetFilePreCheck(path, true); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot read from file: %1").arg(path)); + return; + } -#ifdef WINDOWS - std::filesystem::path in_path = path.toStdU16String(); -#else - std::filesystem::path in_path = path.toStdString(); -#endif + auto out_path = + SetExtensionOfOutputFileForArchive(path, kDECRYPT_VERIFY, true); - std::filesystem::path out_path = in_path; - if (in_path.extension() == ".asc" || in_path.extension() == ".gpg") { - out_path = in_path.parent_path() / out_path.stem(); - } else { - out_path += ".out"; + check_result = TargetFilePreCheck(out_path, false); + if (!std::get<0>(check_result)) { + QMessageBox::critical(this, tr("Error"), + tr("Cannot write to file: %1").arg(out_path)); + return; } - SPDLOG_DEBUG("out path: {}", out_path.u8string()); - if (QFile::exists(out_path.u8string().c_str())) { - auto ret = - QMessageBox::warning(this, _("Warning"), - QString(_("The output file %1 already exists, do " - "you need to overwrite it?")) - .arg(out_path.filename().u8string().c_str()), - QMessageBox::Ok | QMessageBox::Cancel); + if (QFile::exists(out_path)) { + auto ret = QMessageBox::warning(this, tr("Warning"), + tr("The output file %1 already exists, do " + "you need to overwrite it?") + .arg(out_path), + QMessageBox::Ok | QMessageBox::Cancel); if (ret == QMessageBox::Cancel) return; } - GpgDecrResult d_result = nullptr; - GpgVerifyResult v_result = nullptr; - gpgme_error_t error; - bool if_error = false; - process_operation(this, _("Decrypting and Verifying"), - [&](Thread::Task::DataObjectPtr) -> int { - try { - error = GpgFileOpera::DecryptVerifyFile( - path.toStdString(), out_path.u8string(), d_result, - v_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - return 0; - }); - - if (!if_error) { - auto decrypt_res = GpgDecryptResultAnalyse(error, std::move(d_result)); - auto verify_res = GpgVerifyResultAnalyse(error, v_result); - decrypt_res.Analyse(); - verify_res.Analyse(); - process_result_analyse(edit_, info_board_, decrypt_res, verify_res); - - if (verify_res.GetStatus() == -2) - import_unknown_key_from_keyserver(this, verify_res); - - if (verify_res.GetStatus() >= 0) - show_verify_details(this, info_board_, error, v_result); - - fileTreeView->update(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - - // extract the tarball - if (out_path.extension() == ".tar" && exists(out_path)) { - bool ret = QMessageBox::information( - this, _("Decrypting"), - _("Do you want to extract and delete the decrypted tarball?"), - QMessageBox::Ok | QMessageBox::Cancel); - if (ret) { - if (process_tarball_into_directory(this, out_path)) { - QMessageBox::information(this, _("Decrypting"), - _("Extracting tarball succeeded.")); - // remove tarball - std::filesystem::remove(out_path); - } else { - QMessageBox::critical(this, _("Decrypting"), - _("Extracting tarball failed.")); - } - } - } + CommonUtils::WaitForOpera( + this, tr("Decrypting & Verifying & Extracting"), + [=](const OperaWaitingHd& op_hd) { + GpgFileOpera::GetInstance().DecryptVerifyArchive( + path, out_path, [=](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgDecryptResult, GpgVerifyResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto verify_result = ExtractParams<GpgVerifyResult>(data_obj, 1); + + auto decrypt_result_analyse = + GpgDecryptResultAnalyse(err, decrypt_result); + decrypt_result_analyse.Analyse(); + + auto verify_result_analyse = + GpgVerifyResultAnalyse(err, verify_result); + verify_result_analyse.Analyse(); + + process_result_analyse(edit_, info_board_, decrypt_result_analyse, + verify_result_analyse); + if (verify_result_analyse.GetStatus() == -2) { + import_unknown_key_from_keyserver(this, verify_result_analyse); + } + if (verify_result_analyse.GetStatus() >= 0) { + show_verify_details(this, info_board_, err, verify_result); + } + + this->slot_refresh_current_file_view(); + }); + }); } } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowGpgOperaFunction.cpp b/src/ui/main_window/MainWindowGpgOperaFunction.cpp new file mode 100644 index 00000000..ea9540bb --- /dev/null +++ b/src/ui/main_window/MainWindowGpgOperaFunction.cpp @@ -0,0 +1,396 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "MainWindow.h" +#include "core/function/gpg/GpgBasicOperator.h" +#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/result_analyse/GpgDecryptResultAnalyse.h" +#include "core/function/result_analyse/GpgEncryptResultAnalyse.h" +#include "core/function/result_analyse/GpgSignResultAnalyse.h" +#include "core/function/result_analyse/GpgVerifyResultAnalyse.h" +#include "core/model/DataObject.h" +#include "core/model/GpgEncryptResult.h" +#include "core/utils/GpgUtils.h" +#include "ui/UserInterfaceUtils.h" +#include "ui/dialog/SignersPicker.h" + +namespace GpgFrontend::UI { + +void MainWindow::SlotEncrypt() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + auto key_ids = m_key_list_->GetChecked(); + + if (key_ids->empty()) { + // Symmetric Encrypt + auto ret = QMessageBox::information( + this, tr("Symmetric Encryption"), + tr("No Key Checked. Do you want to encrypt with a " + "symmetric cipher using a passphrase?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + CommonUtils::WaitForOpera( + this, tr("Symmetrically Encrypting"), + [this, buffer](const OperaWaitingHd& op_hd) { + GpgFrontend::GpgBasicOperator::GetInstance().EncryptSymmetric( + buffer, true, + [this, op_hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || + data_obj == nullptr || + !data_obj->Check<GpgEncryptResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto buffer = ExtractParams<GFBuffer>(data_obj, 1); + + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + process_result_analyse(edit_, info_board_, result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText(buffer.ConvertToQByteArray()); + } + info_board_->ResetOptionActionsMenu(); + }); + }); + + return; + } + + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.IsHasActualEncryptionCapability()) { + QMessageBox::information( + this, tr("Invalid Operation"), + tr("The selected key contains a key that does not actually have a " + "encrypt usage.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); + return; + } + } + + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + CommonUtils::WaitForOpera( + this, tr("Encrypting"), + [this, keys, buffer](const OperaWaitingHd& op_hd) { + GpgFrontend::GpgBasicOperator::GetInstance().Encrypt( + {keys->begin(), keys->end()}, buffer, true, + [this, op_hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + op_hd(); + + if (data_obj == nullptr || + !data_obj->Check<GpgEncryptResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + + auto result = ExtractParams<GpgEncryptResult>(data_obj, 0); + auto buffer = ExtractParams<GFBuffer>(data_obj, 1); + + auto result_analyse = GpgEncryptResultAnalyse(err, result); + result_analyse.Analyse(); + process_result_analyse(edit_, info_board_, result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText(buffer.ConvertToQByteArray()); + } + info_board_->ResetOptionActionsMenu(); + }); + }); +} + +void MainWindow::SlotSign() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + auto key_ids = m_key_list_->GetPrivateChecked(); + if (key_ids->empty()) { + QMessageBox::critical( + this, tr("No Key Checked"), + tr("Please check the key in the key toolbox on the right.")); + return; + } + + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + for (const auto& key : *keys) { + if (!key.IsHasActualSigningCapability()) { + QMessageBox::information( + this, tr("Invalid Operation"), + tr("The selected key contains a key that does not actually have a " + "signature usage.") + + "<br/><br/>" + tr("For example the Following Key:") + "<br/>" + + key.GetUIDs()->front().GetUID()); + return; + } + } + + // set input buffer + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + CommonUtils::WaitForOpera( + this, tr("Signing"), [this, keys, buffer](const OperaWaitingHd& hd) { + GpgFrontend::GpgBasicOperator::GetInstance().Sign( + {keys->begin(), keys->end()}, buffer, GPGME_SIG_MODE_CLEAR, true, + [this, hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgSignResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 0); + auto sign_out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + auto result_analyse = GpgSignResultAnalyse(err, sign_result); + result_analyse.Analyse(); + process_result_analyse(edit_, info_board_, result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText( + sign_out_buffer.ConvertToQByteArray()); + } + }); + }); +} + +void MainWindow::SlotDecrypt() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + // data to transfer into task + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + + CommonUtils::WaitForOpera( + this, tr("Decrypting"), [this, buffer](const OperaWaitingHd& hd) { + GpgFrontend::GpgBasicOperator::GetInstance().Decrypt( + buffer, [this, hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgDecryptResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto out_buffer = ExtractParams<GFBuffer>(data_obj, 1); + auto result_analyse = + GpgDecryptResultAnalyse(err, decrypt_result); + result_analyse.Analyse(); + process_result_analyse(edit_, info_board_, result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText( + out_buffer.ConvertToQByteArray()); + } + }); + }); +} + +void MainWindow::SlotVerify() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + // set input buffer + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + + CommonUtils::WaitForOpera( + this, tr("Verifying"), [this, buffer](const OperaWaitingHd& hd) { + GpgFrontend::GpgBasicOperator::GetInstance().Verify( + buffer, GFBuffer(), + [this, hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj->Check<GpgVerifyResult>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto verify_result = ExtractParams<GpgVerifyResult>(data_obj, 0); + + // analyse result + auto result_analyse = GpgVerifyResultAnalyse(err, verify_result); + result_analyse.Analyse(); + process_result_analyse(edit_, info_board_, result_analyse); + }); + }); +} + +void MainWindow::SlotEncryptSign() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + auto key_ids = m_key_list_->GetChecked(); + + if (key_ids->empty()) { + QMessageBox::critical( + this, tr("No Key Checked"), + tr("Please check some key in the key toolbox on the right.")); + return; + } + + auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); + + for (const auto& key : *keys) { + bool key_can_encrypt = key.IsHasActualEncryptionCapability(); + + if (!key_can_encrypt) { + QMessageBox::critical( + this, tr("Invalid KeyPair"), + tr("The selected keypair cannot be used for encryption.") + + "<br/><br/>" + tr("For example the Following Key:") + " <br/>" + + key.GetUIDs()->front().GetUID()); + return; + } + } + + auto* signers_picker = new SignersPicker(this); + QEventLoop loop; + connect(signers_picker, &SignersPicker::finished, &loop, &QEventLoop::quit); + loop.exec(); + + // return when canceled + if (!signers_picker->GetStatus()) return; + + auto signer_key_ids = signers_picker->GetCheckedSigners(); + auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); + + for (const auto& key : *keys) { + GF_UI_LOG_DEBUG("keys {}", key.GetEmail()); + } + + for (const auto& signer : *signer_keys) { + GF_UI_LOG_DEBUG("signers {}", signer.GetEmail()); + } + + // data to transfer into task + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + + CommonUtils::WaitForOpera( + this, tr("Encrypting and Signing"), + [this, keys, signer_keys, buffer](const OperaWaitingHd& hd) { + GpgFrontend::GpgBasicOperator::GetInstance().EncryptSign( + {keys->begin(), keys->end()}, + {signer_keys->begin(), signer_keys->end()}, buffer, true, + [this, hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj + ->Check<GpgEncryptResult, GpgSignResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto encrypt_result = + ExtractParams<GpgEncryptResult>(data_obj, 0); + auto sign_result = ExtractParams<GpgSignResult>(data_obj, 1); + auto out_buffer = ExtractParams<GFBuffer>(data_obj, 2); + + // analyse result + auto encrypt_result_analyse = + GpgEncryptResultAnalyse(err, encrypt_result); + encrypt_result_analyse.Analyse(); + + auto sign_result_analyse = GpgSignResultAnalyse(err, sign_result); + sign_result_analyse.Analyse(); + + // show analyse result + process_result_analyse(edit_, info_board_, encrypt_result_analyse, + sign_result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText( + out_buffer.ConvertToQByteArray()); + } + }); + }); +} + +void MainWindow::SlotDecryptVerify() { + if (edit_->SlotCurPageTextEdit() == nullptr) return; + + // data to transfer into task + auto buffer = GFBuffer(edit_->CurTextPage()->GetTextPage()->toPlainText()); + + CommonUtils::WaitForOpera( + this, tr("Decrypting and Verifying"), + [this, buffer](const OperaWaitingHd& hd) { + GpgFrontend::GpgBasicOperator::GetInstance().DecryptVerify( + buffer, [this, hd](GpgError err, const DataObjectPtr& data_obj) { + // stop waiting + hd(); + + if (CheckGpgError(err) == GPG_ERR_USER_1 || data_obj == nullptr || + !data_obj + ->Check<GpgDecryptResult, GpgVerifyResult, GFBuffer>()) { + QMessageBox::critical(this, tr("Error"), + tr("Unknown error occurred")); + return; + } + auto decrypt_result = + ExtractParams<GpgDecryptResult>(data_obj, 0); + auto verify_result = ExtractParams<GpgVerifyResult>(data_obj, 1); + auto out_buffer = ExtractParams<GFBuffer>(data_obj, 2); + + // analyse result + auto decrypt_result_analyse = + GpgDecryptResultAnalyse(err, decrypt_result); + decrypt_result_analyse.Analyse(); + + auto verify_result_analyse = + GpgVerifyResultAnalyse(err, verify_result); + verify_result_analyse.Analyse(); + + // show analyse result + process_result_analyse(edit_, info_board_, decrypt_result_analyse, + verify_result_analyse); + + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) { + edit_->SlotFillTextEditWithText( + out_buffer.ConvertToQByteArray()); + } + }); + }); +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index 1adf2d4e..fe9aa0df 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,577 +20,28 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#include <boost/date_time/posix_time/posix_time.hpp> -#include <boost/date_time/posix_time/posix_time_io.hpp> -#include <memory> -#include <string> -#include <utility> - #include "MainWindow.h" -#include "core/GpgConstants.h" -#include "core/GpgContext.h" #include "core/GpgModel.h" -#include "core/function/gpg/GpgBasicOperator.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" -#include "core/function/gpg/GpgKeyManager.h" -#include "dialog/SignersPicker.h" -#include "spdlog/spdlog.h" +#include "core/module/ModuleManager.h" +#include "core/typedef/GpgTypedef.h" +#include "core/utils/CommonUtils.h" +#include "core/utils/GpgUtils.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/help/AboutDialog.h" +#include "ui/dialog/import_export/KeyUploadDialog.h" +#include "ui/dialog/keypair_details/KeyDetailsDialog.h" +#include "ui/function/SetOwnerTrustLevel.h" +#include "ui/widgets/FindWidget.h" namespace GpgFrontend::UI { -/** - * Encrypt Entry(Text & File) - */ -void MainWindow::slot_encrypt() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileEncrypt(); - return; - } - - auto key_ids = m_key_list_->GetChecked(); - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - - // the callback function - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object->GetObjectSize() != 3) - throw std::runtime_error("Invalid data object size"); - auto error = data_object->PopObject<GpgError>(); - auto result = data_object->PopObject<GpgEncrResult>(); - auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); - - auto resultAnalyse = GpgEncryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); - info_board_->ResetOptionActionsMenu(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - Thread::Task::TaskRunnable encrypt_runner = nullptr; - - std::string encrypt_type = ""; - - if (key_ids->empty()) { - // Symmetric Encrypt - auto ret = QMessageBox::information( - this, _("Symmetric Encryption"), - _("No Key Checked. Do you want to encrypt with a " - "symmetric cipher using a passphrase?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) return; - - encrypt_type = _("Symmetrically Encrypting"); - encrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { - if (data_object == nullptr || data_object->GetObjectSize() != 1) - throw std::runtime_error("Invalid data object size"); - auto buffer = data_object->PopObject<std::string>(); - try { - GpgEncrResult result = nullptr; - auto tmp = std::make_unique<ByteArray>(); - GpgError error = - GpgFrontend::GpgBasicOperator::GetInstance().EncryptSymmetric( - buffer, tmp, result); - data_object->AppendObject(std::move(tmp)); - data_object->AppendObject(std::move(result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - - } else { - auto& key_getter = GpgFrontend::GpgKeyGetter::GetInstance(); - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto& key : *keys) { - if (!key.IsHasActualEncryptionCapability()) { - QMessageBox::information( - this, _("Invalid Operation"), - QString(_( - "The selected key contains a key that does not actually have a " - "encrypt usage.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.GetUIDs()->front().GetUID())); - return; - } - } - - // push the keys into data object - data_object->AppendObject(std::move(keys)); - - // Asymmetric Encrypt - encrypt_type = _("Encrypting"); - encrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 2) - throw std::runtime_error("Invalid data object size"); - - auto keys = data_object->PopObject<KeyListPtr>(); - auto buffer = data_object->PopObject<std::string>(); - try { - GpgEncrResult result = nullptr; - auto tmp = std::make_unique<ByteArray>(); - GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Encrypt( - std::move(keys), buffer, tmp, result); - - data_object->AppendObject(std::move(tmp)); - data_object->AppendObject(std::move(result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - } - // Do the task - process_operation(this, _("Encrypting"), std::move(encrypt_runner), - std::move(result_callback), data_object); -} - -void MainWindow::slot_sign() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileSign(); - return; - } - - auto key_ids = m_key_list_->GetPrivateChecked(); - - if (key_ids->empty()) { - QMessageBox::critical( - this, _("No Key Checked"), - _("Please check the key in the key toolbox on the right.")); - return; - } - - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - for (const auto& key : *keys) { - if (!key.IsHasActualSigningCapability()) { - QMessageBox::information( - this, _("Invalid Operation"), - QString( - _("The selected key contains a key that does not actually have a " - "signature usage.")) + - "<br/><br/>" + _("For example the Following Key:") + "<br/>" + - key.GetUIDs()->front().GetUID().c_str()); - return; - } - } - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - - // push the keys into data object - data_object->AppendObject(std::move(keys)); - - auto sign_ruunner = [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 2) - throw std::runtime_error("Invalid data object size"); - - auto keys = data_object->PopObject<KeyListPtr>(); - auto buffer = data_object->PopObject<std::string>(); - try { - GpgSignResult result = nullptr; - auto tmp = std::make_unique<ByteArray>(); - GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Sign( - std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, result); - data_object->AppendObject(std::move(tmp)); - data_object->AppendObject(std::move(result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object == nullptr || data_object->GetObjectSize() != 3) - throw std::runtime_error("Invalid data object size"); - auto error = data_object->PopObject<GpgError>(); - auto result = data_object->PopObject<GpgSignResult>(); - auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); - auto resultAnalyse = GpgSignResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - process_operation(this, _("Signing"), std::move(sign_ruunner), - std::move(result_callback), data_object); -} - -void MainWindow::slot_decrypt() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileDecrypt(); - return; - } - - QByteArray text = edit_->CurTextPage()->GetTextPage()->toPlainText().toUtf8(); - - if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { - QMessageBox::critical( - this, _("Notice"), - _("Short Crypto Text only supports Decrypt & Verify.")); - return; - } - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - - auto decrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 1) - throw std::runtime_error("Invalid data object size"); - - auto buffer = data_object->PopObject<std::string>(); - try { - GpgDecrResult result = nullptr; - auto decrypted = std::make_unique<ByteArray>(); - GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Decrypt( - buffer, decrypted, result); - data_object->AppendObject(std::move(decrypted)); - data_object->AppendObject(std::move(result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object == nullptr || data_object->GetObjectSize() != 3) - throw std::runtime_error("Invalid data object size"); - auto error = data_object->PopObject<GpgError>(); - auto result = data_object->PopObject<GpgDecrResult>(); - auto decrypted = data_object->PopObject<std::unique_ptr<ByteArray>>(); - auto resultAnalyse = GpgDecryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*decrypted)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - process_operation(this, _("Decrypting"), std::move(decrypt_runner), - std::move(result_callback), data_object); -} - -void MainWindow::slot_verify() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) this->SlotFileVerify(); - return; - } - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - - auto verify_runner = [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 1) - throw std::runtime_error("Invalid data object size"); - - auto buffer = data_object->PopObject<std::string>(); - - SPDLOG_DEBUG("verify buffer size: {}", buffer.size()); - - try { - GpgVerifyResult verify_result = nullptr; - auto sig_buffer = std::unique_ptr<ByteArray>(nullptr); - GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Verify( - buffer, sig_buffer, verify_result); - - data_object->AppendObject(std::move(verify_result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object == nullptr || data_object->GetObjectSize() != 2) - throw std::runtime_error("Invalid data object size"); - auto error = data_object->PopObject<GpgError>(); - auto verify_result = data_object->PopObject<GpgVerifyResult>(); - - auto result_analyse = GpgVerifyResultAnalyse(error, verify_result); - result_analyse.Analyse(); - process_result_analyse(edit_, info_board_, result_analyse); - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) { - if (result_analyse.GetStatus() == -2) - import_unknown_key_from_keyserver(this, result_analyse); - - if (result_analyse.GetStatus() >= 0) - show_verify_details(this, info_board_, error, verify_result); - } - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - process_operation(this, _("Verifying"), verify_runner, result_callback, - data_object); -} - -void MainWindow::slot_encrypt_sign() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) - this->SlotFileEncryptSign(); - return; - } - - auto key_ids = m_key_list_->GetChecked(); - - if (key_ids->empty()) { - QMessageBox::critical( - this, _("No Key Checked"), - _("Please check some key in the key toolbox on the right.")); - return; - } - - auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - - for (const auto& key : *keys) { - bool key_can_encrypt = key.IsHasActualEncryptionCapability(); - - if (!key_can_encrypt) { - QMessageBox::critical( - this, _("Invalid KeyPair"), - QString(_("The selected keypair cannot be used for encryption.")) + - "<br/><br/>" + _("For example the Following Key:") + " <br/>" + - QString::fromStdString(key.GetUIDs()->front().GetUID())); - return; - } - } - - auto signersPicker = new SignersPicker(this); - QEventLoop loop; - connect(signersPicker, &SignersPicker::finished, &loop, &QEventLoop::quit); - loop.exec(); - - // return when canceled - if (!signersPicker->GetStatus()) return; - - auto signer_key_ids = signersPicker->GetCheckedSigners(); - auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); - - for (const auto& key : *keys) { - SPDLOG_DEBUG("keys {}", key.GetEmail()); - } - - for (const auto& signer : *signer_keys) { - SPDLOG_DEBUG("signers {}", signer.GetEmail()); - } - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - // push the keys into data object - data_object->AppendObject(std::move(keys)); - data_object->AppendObject(std::move(signer_keys)); - - auto encrypt_sign_runner = - [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 3) - throw std::runtime_error("Invalid data object size"); - - auto signer_keys = data_object->PopObject<KeyListPtr>(); - auto keys = data_object->PopObject<KeyListPtr>(); - auto buffer = data_object->PopObject<std::string>(); - try { - GpgEncrResult encr_result = nullptr; - GpgSignResult sign_result = nullptr; - auto tmp = std::make_unique<ByteArray>(); - GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().EncryptSign( - std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, - sign_result); - - data_object->AppendObject(std::move(tmp)); - data_object->AppendObject(std::move(sign_result)); - data_object->AppendObject(std::move(encr_result)); - data_object->AppendObject(std::move(error)); - - } catch (const std::runtime_error& e) { - return -1; - } - return 0; - }; - - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object == nullptr || data_object->GetObjectSize() != 4) - throw std::runtime_error("Invalid data object size"); - auto error = data_object->PopObject<GpgError>(); - auto encrypt_result = data_object->PopObject<GpgEncrResult>(); - auto sign_result = data_object->PopObject<GpgSignResult>(); - auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); - - auto encrypt_result_analyse = - GpgEncryptResultAnalyse(error, std::move(encrypt_result)); - auto sign_result_analyse = - GpgSignResultAnalyse(error, std::move(sign_result)); - encrypt_result_analyse.Analyse(); - sign_result_analyse.Analyse(); - process_result_analyse(edit_, info_board_, encrypt_result_analyse, - sign_result_analyse); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); - - info_board_->ResetOptionActionsMenu(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - process_operation(this, _("Encrypting and Signing"), encrypt_sign_runner, - result_callback, data_object); -} - -void MainWindow::slot_decrypt_verify() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - if (edit_->SlotCurPageFileTreeView() != nullptr) - this->SlotFileDecryptVerify(); - return; - } - - // data to transfer into task - auto data_object = std::make_shared<Thread::Task::DataObject>(); - - // set input buffer - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - data_object->AppendObject(std::move(buffer)); - - auto decrypt_verify_runner = - [](Thread::Task::DataObjectPtr data_object) -> int { - // check the size of the data object - if (data_object == nullptr || data_object->GetObjectSize() != 1) - throw std::runtime_error("Invalid data object size"); - - auto buffer = data_object->PopObject<std::string>(); - try { - GpgDecrResult decrypt_result = nullptr; - GpgVerifyResult verify_result = nullptr; - auto decrypted_buffer = std::make_unique<ByteArray>(); - GpgError error = GpgBasicOperator::GetInstance().DecryptVerify( - buffer, decrypted_buffer, decrypt_result, verify_result); - - data_object->AppendObject(std::move(decrypted_buffer)); - data_object->AppendObject(std::move(verify_result)); - data_object->AppendObject(std::move(decrypt_result)); - data_object->AppendObject(std::move(error)); - } catch (const std::runtime_error& e) { - SPDLOG_ERROR(e.what()); - return -1; - } - return 0; - }; - - auto result_callback = [this](int rtn, - Thread::Task::DataObjectPtr data_object) { - if (!rtn) { - if (data_object == nullptr || data_object->GetObjectSize() != 4) - throw std::runtime_error("Invalid data object size"); - - auto error = data_object->PopObject<GpgError>(); - auto decrypt_result = data_object->PopObject<GpgDecrResult>(); - auto verify_result = data_object->PopObject<GpgVerifyResult>(); - auto decrypted = data_object->PopObject<std::unique_ptr<ByteArray>>(); - - auto decrypt_result_analyse = - GpgDecryptResultAnalyse(error, std::move(decrypt_result)); - auto verify_result_analyse = GpgVerifyResultAnalyse(error, verify_result); - decrypt_result_analyse.Analyse(); - verify_result_analyse.Analyse(); - process_result_analyse(edit_, info_board_, decrypt_result_analyse, - verify_result_analyse); - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*decrypted)); - - if (verify_result_analyse.GetStatus() == -2) - import_unknown_key_from_keyserver(this, verify_result_analyse); - - if (verify_result_analyse.GetStatus() >= 0) - show_verify_details(this, info_board_, error, verify_result); - - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } - }; - - process_operation(this, _("Decrypting and Verifying"), decrypt_verify_runner, - result_callback, data_object); -} void MainWindow::slot_find() { if (edit_->TabCount() == 0 || edit_->CurTextPage() == nullptr) { @@ -608,76 +59,68 @@ void MainWindow::slot_find() { * Append the selected (not checked!) Key(s) To Textedit */ void MainWindow::slot_append_selected_keys() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - return; - } - - auto exported = std::make_unique<ByteArray>(); auto key_ids = m_key_list_->GetSelected(); if (key_ids->empty()) { - SPDLOG_ERROR("no key is selected"); + GF_UI_LOG_ERROR("no key is selected to export"); return; } - if (!GpgKeyImportExporter::GetInstance().ExportKeys(key_ids, exported)) { - QMessageBox::critical(this, _("Error"), _("Key Export Operation Failed.")); + auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); + if (!key.IsGood()) { + GF_UI_LOG_ERROR("selected key for exporting is invalid, key id: {}", + key_ids->front()); return; } - edit_->CurTextPage()->GetTextPage()->appendPlainText( - QString::fromStdString(*exported)); -} -void MainWindow::slot_append_keys_create_datetime() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance().ExportKey(key, false, true, false); + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); return; } + edit_->SlotAppendText2CurTextPage(gf_buffer.ConvertToQByteArray()); +} + +void MainWindow::slot_append_keys_create_datetime() { auto key_ids = m_key_list_->GetSelected(); if (key_ids->empty()) { - SPDLOG_ERROR("no key is selected"); + GF_UI_LOG_ERROR("no key is selected"); return; } auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } - auto create_datetime_format_str = - boost::posix_time::to_iso_extended_string(key.GetCreateTime()) + - " (UTC) " + "\n"; - - edit_->CurTextPage()->GetTextPage()->appendPlainText( - QString::fromStdString(create_datetime_format_str)); + auto create_datetime_format_str_local = + QLocale::system().toString(key.GetCreateTime()) + tr(" (Local Time) ") + + "\n"; + edit_->SlotAppendText2CurTextPage(create_datetime_format_str_local); } void MainWindow::slot_append_keys_expire_datetime() { - if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) { - return; - } - auto key_ids = m_key_list_->GetSelected(); if (key_ids->empty()) { - SPDLOG_ERROR("no key is selected"); + GF_UI_LOG_ERROR("no key is selected"); return; } auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } auto create_datetime_format_str = - boost::posix_time::to_iso_extended_string(key.GetCreateTime()) + - " (UTC) " + "\n"; + key.GetCreateTime().toString() + " (UTC) " + "\n"; - edit_->CurTextPage()->GetTextPage()->appendPlainText( - QString::fromStdString(create_datetime_format_str)); + edit_->SlotAppendText2CurTextPage(create_datetime_format_str); } void MainWindow::slot_append_keys_fingerprint() { @@ -686,15 +129,14 @@ void MainWindow::slot_append_keys_fingerprint() { auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } auto fingerprint_format_str = - beautify_fingerprint(key.GetFingerprint()) + "\n"; + BeautifyFingerprint(key.GetFingerprint()) + "\n"; - edit_->CurTextPage()->GetTextPage()->appendPlainText( - QString::fromStdString(fingerprint_format_str)); + edit_->SlotAppendText2CurTextPage(fingerprint_format_str); } void MainWindow::slot_copy_mail_address_to_clipboard() { @@ -703,11 +145,11 @@ void MainWindow::slot_copy_mail_address_to_clipboard() { auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } QClipboard* cb = QApplication::clipboard(); - cb->setText(QString::fromStdString(key.GetEmail())); + cb->setText(key.GetEmail()); } void MainWindow::slot_copy_default_uid_to_clipboard() { @@ -716,11 +158,11 @@ void MainWindow::slot_copy_default_uid_to_clipboard() { auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } QClipboard* cb = QApplication::clipboard(); - cb->setText(QString::fromStdString(key.GetUIDs()->front().GetUID())); + cb->setText(key.GetUIDs()->front().GetUID()); } void MainWindow::slot_copy_key_id_to_clipboard() { @@ -729,11 +171,11 @@ void MainWindow::slot_copy_key_id_to_clipboard() { auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); if (!key.IsGood()) { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); return; } QClipboard* cb = QApplication::clipboard(); - cb->setText(QString::fromStdString(key.GetId())); + cb->setText(key.GetId()); } void MainWindow::slot_show_key_details() { @@ -744,7 +186,7 @@ void MainWindow::slot_show_key_details() { if (key.IsGood()) { new KeyDetailsDialog(key, this); } else { - QMessageBox::critical(this, _("Error"), _("Key Not Found.")); + QMessageBox::critical(this, tr("Error"), tr("Key Not Found.")); } } @@ -781,50 +223,9 @@ void MainWindow::slot_set_owner_trust_level_of_key() { auto key_ids = m_key_list_->GetSelected(); if (key_ids->empty()) return; - auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front()); - - QStringList items; - - items << _("Unknown") << _("Undefined") << _("Never") << _("Marginal") - << _("Full") << _("Ultimate"); - bool ok; - QString item = QInputDialog::getItem(this, _("Modify Owner Trust Level"), - _("Trust for the Key Pair:"), items, - key.GetOwnerTrustLevel(), false, &ok); - - if (ok && !item.isEmpty()) { - SPDLOG_DEBUG("selected policy: {}", item.toStdString()); - int trust_level = 0; // Unknown Level - if (item == _("Ultimate")) { - trust_level = 5; - } else if (item == _("Full")) { - trust_level = 4; - } else if (item == _("Marginal")) { - trust_level = 3; - } else if (item == _("Never")) { - trust_level = 2; - } else if (item == _("Undefined")) { - trust_level = 1; - } - - if (trust_level == 0) { - QMessageBox::warning( - this, _("Warning"), - QString(_("Owner Trust Level cannot set to Unknown level, automately " - "changing it into Undefined level."))); - trust_level = 1; - } - - bool status = - GpgKeyManager::GetInstance().SetOwnerTrustLevel(key, trust_level); - if (!status) { - QMessageBox::critical(this, _("Failed"), - QString(_("Modify Owner Trust Level failed."))); - } else { - // update key database and refresh ui - emit SignalKeyDatabaseRefresh(); - } - } + auto* function = new SetOwnerTrustLevel(this); + function->Exec(key_ids->front()); + function->deleteLater(); } void MainWindow::upload_key_to_server() { @@ -834,50 +235,97 @@ void MainWindow::upload_key_to_server() { dialog->SlotUpload(); } -void MainWindow::SlotOpenFile(QString& path) { edit_->SlotOpenFile(path); } +void MainWindow::SlotOpenFile(const QString& path) { + QFileInfo const info(path); + if (!info.isFile() || !info.isReadable()) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot open this file. Please make sure that this " + "is a regular file and it's readable.")); + return; + } -void MainWindow::slot_version_upgrade(const SoftwareVersion& version) { - if (!version.InfoValid()) { - SPDLOG_ERROR("invalid version info"); + if (info.size() > static_cast<qint64>(1024 * 1024)) { + QMessageBox::critical( + this, tr("Error"), + tr("Cannot open this file. The file is TOO LARGE (>1MB) for " + "GpgFrontend Text Editor.")); return; } - SPDLOG_DEBUG( - "version info, need upgrade: {}, with drawn: {}, current version " - "released: {}", - version.NeedUpgrade(), version.VersionWithDrawn(), - version.CurrentVersionReleased()); + edit_->SlotOpenFile(path); +} + +void MainWindow::slot_version_upgrade_nofity() { + GF_UI_LOG_DEBUG( + "slot version upgrade notify called, checking version info from rt..."); + auto is_loading_done = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.loading_done", false); + + GF_UI_LOG_DEBUG("checking version info from rt, is loading done state: {}", + is_loading_done); + if (!is_loading_done) { + GF_UI_LOG_ERROR("invalid version info from rt, loading hasn't done yet"); + return; + } + + auto is_need_upgrade = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.need_upgrade", false); + + auto is_current_a_withdrawn_version = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.current_a_withdrawn_version", false); + + auto is_current_version_released = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.current_version_released", false); - if (version.NeedUpgrade()) { + auto latest_version = Module::RetrieveRTValueTypedOrDefault<>( + "com.bktus.gpgfrontend.module.integrated.version-checking", + "version.latest_version", QString{}); + + GF_UI_LOG_DEBUG( + "got version info from rt, need upgrade: {}, with drawn: {}, " + "current version released: {}", + is_need_upgrade, is_current_a_withdrawn_version, + is_current_version_released); + + if (is_need_upgrade) { statusBar()->showMessage( - QString(_("GpgFrontend Upgradeable (New Version: %1).")) - .arg(version.latest_version.c_str()), + tr("GpgFrontend Upgradeable (New Version: %1).").arg(latest_version), 30000); - auto update_button = new QPushButton("Update GpgFrontend", this); + auto* update_button = new QPushButton("Update GpgFrontend", this); connect(update_button, &QPushButton::clicked, [=]() { auto* about_dialog = new AboutDialog(2, this); about_dialog->show(); }); statusBar()->addPermanentWidget(update_button, 0); - } else if (version.VersionWithDrawn()) { + } else if (is_current_a_withdrawn_version) { QMessageBox::warning( - this, _("Withdrawn Version"), - QString( - _("This version(%1) may have been withdrawn by the developer due " - "to serious problems. Please stop using this version " - "immediately and use the latest stable version.")) - .arg(version.current_version.c_str()) + + this, tr("Withdrawn Version"), + + tr("This version(%1) may have been withdrawn by the developer due " + "to serious problems. Please stop using this version " + "immediately and use the latest stable version.") + .arg(latest_version) + "<br/>" + - QString(_("You can download the latest stable version(%1) on " - "Github Releases " - "Page.<br/>")) - .arg(version.latest_version.c_str())); - } else if (!version.CurrentVersionReleased()) { + tr("You can download the latest stable version(%1) on " + "Github Releases Page.<br/>") + .arg(latest_version)); + } else if (!is_current_version_released) { statusBar()->showMessage( - QString(_("This maybe a BETA Version (Latest Stable Version: %1).")) - .arg(version.latest_version.c_str()), + tr("This maybe a BETA Version (Latest Stable Version: %1).") + .arg(latest_version), 30000); } } +void MainWindow::slot_refresh_current_file_view() { + if (edit_->CurFilePage() != nullptr) { + edit_->CurFilePage()->update(); + } +} + } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 0b7f4c64..1b39b606 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,9 +28,13 @@ #include "MainWindow.h" #include "core/GpgConstants.h" -#include "core/function/GlobalSettingStation.h" +#include "core/model/GpgPassphraseContext.h" #include "ui/UserInterfaceUtils.h" +#include "ui/dialog/Wizard.h" +#include "ui/function/RaisePinentry.h" +#include "ui/main_window/KeyMgmt.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/AppearanceSO.h" namespace GpgFrontend::UI { @@ -47,11 +51,12 @@ void MainWindow::slot_start_wizard() { void MainWindow::slot_import_key_from_edit() { if (edit_->TabCount() == 0 || edit_->SlotCurPageTextEdit() == nullptr) return; CommonUtils::GetInstance()->SlotImportKeys( - this, edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString()); + this, edit_->CurTextPage()->GetTextPage()->toPlainText()); } void MainWindow::slot_open_key_management() { auto* dialog = new KeyMgmt(this); + dialog->setWindowModality(Qt::ApplicationModal); dialog->show(); dialog->raise(); } @@ -61,10 +66,7 @@ void MainWindow::slot_open_file_tab() { edit_->SlotNewFileTab(); } void MainWindow::slot_disable_tab_actions(int number) { bool disable; - if (number == -1) - disable = true; - else - disable = false; + disable = number == -1; if (edit_->CurFilePage() != nullptr) { disable = true; @@ -93,7 +95,6 @@ void MainWindow::slot_disable_tab_actions(int number) { zoom_in_act_->setDisabled(disable); clean_double_line_breaks_act_->setDisabled(disable); quote_act_->setDisabled(disable); - append_selected_keys_act_->setDisabled(disable); import_key_from_edit_act_->setDisabled(disable); cut_pgp_header_act_->setDisabled(disable); @@ -101,32 +102,26 @@ void MainWindow::slot_disable_tab_actions(int number) { } void MainWindow::slot_open_settings_dialog() { - auto dialog = new SettingsDialog(this); + auto* dialog = new SettingsDialog(this); connect(dialog, &SettingsDialog::finished, this, [&]() -> void { - SettingsObject general_settings_state("general_settings_state"); - - int width = general_settings_state.Check("icon_size").Check("width", 24), - height = general_settings_state.Check("icon_size").Check("height", 24); - SPDLOG_DEBUG("icon_size: {} {}", width, height); - - general_settings_state.Check("info_font_size", 10); + AppearanceSO appearance(SettingsObject("general_settings_state")); + GF_UI_LOG_DEBUG("tool bar icon_size: {}, {}", + appearance.tool_bar_icon_width, + appearance.tool_bar_icon_height); - // icon_style - int s_icon_style = - general_settings_state.Check("icon_style", Qt::ToolButtonTextUnderIcon); - auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style); - this->setToolButtonStyle(icon_style); - import_button_->setToolButtonStyle(icon_style); + this->setToolButtonStyle(appearance.tool_bar_button_style); + import_button_->setToolButtonStyle(appearance.tool_bar_button_style); // icons ize - this->setIconSize(QSize(width, height)); - import_button_->setIconSize(QSize(width, height)); + this->setIconSize( + QSize(appearance.tool_bar_icon_width, appearance.tool_bar_icon_height)); + import_button_->setIconSize( + QSize(appearance.tool_bar_icon_width, appearance.tool_bar_icon_height)); // restart mainwindow if necessary - if (get_restart_needed()) { + if (get_restart_needed() != 0) { if (edit_->MaybeSaveAnyTab()) { - save_settings(); emit SignalRestartApplication(get_restart_needed()); } } @@ -151,8 +146,8 @@ void MainWindow::slot_add_pgp_header() { QString content = edit_->CurTextPage()->GetTextPage()->toPlainText().trimmed(); - content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN); - content.append("\n").append(GpgConstants::PGP_CRYPT_END); + content.prepend("\n\n").prepend(PGP_CRYPT_BEGIN); + content.append("\n").append(PGP_CRYPT_END); edit_->SlotFillTextEditWithText(content); } @@ -163,8 +158,8 @@ void MainWindow::slot_cut_pgp_header() { } QString content = edit_->CurTextPage()->GetTextPage()->toPlainText(); - int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN); - int end = content.indexOf(GpgConstants::PGP_CRYPT_END); + int start = content.indexOf(PGP_CRYPT_BEGIN); + int end = content.indexOf(PGP_CRYPT_END); if (start < 0 || end < 0) { return; @@ -175,14 +170,14 @@ void MainWindow::slot_cut_pgp_header() { content.remove(start, headEnd - start); // remove tail - end = content.indexOf(GpgConstants::PGP_CRYPT_END); - content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size()); + end = content.indexOf(PGP_CRYPT_END); + content.remove(end, QString(PGP_CRYPT_END).size()); edit_->SlotFillTextEditWithText(content.trimmed()); } void MainWindow::SlotSetRestartNeeded(int mode) { - SPDLOG_DEBUG("restart mode: {}", mode); + GF_UI_LOG_DEBUG("restart mode: {}", mode); this->restart_needed_ = mode; } @@ -190,7 +185,7 @@ int MainWindow::get_restart_needed() const { return this->restart_needed_; } void MainWindow::SetCryptoMenuStatus( MainWindow::CryptoMenu::OperationType type) { - SPDLOG_DEBUG("type: {}", type); + GF_UI_LOG_DEBUG("type: {}", type); // refresh status to disable all verify_act_->setDisabled(true); @@ -221,4 +216,10 @@ void MainWindow::SetCryptoMenuStatus( } } +void MainWindow::SlotRaisePinentry( + QSharedPointer<GpgPassphraseContext> context) { + auto* function = new RaisePinentry(this, context); + function->Exec(); +} + } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index d1a3cb68..662c673f 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,151 +20,149 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ +#include <any> + #include "MainWindow.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgAdvancedOperator.h" -#include "dialog/gnupg/GnuPGControllerDialog.h" +#include "core/module/ModuleManager.h" +#include "core/utils/IOUtils.h" #include "ui/UserInterfaceUtils.h" +#include "ui/dialog/gnupg/GnuPGControllerDialog.h" +#include "ui/dialog/help/AboutDialog.h" namespace GpgFrontend::UI { void MainWindow::create_actions() { /* Main Menu */ - new_tab_act_ = new QAction(_("New"), this); - new_tab_act_->setIcon(QIcon(":misc_doc.png")); - QList<QKeySequence> newTabActShortcutList; -#ifdef GPGFRONTEND_GUI_QT6 - newTabActShortcutList.append(QKeySequence(Qt::CTRL | Qt::Key_N)); - newTabActShortcutList.append(QKeySequence(Qt::CTRL | Qt::Key_T)); -#else -#endif - new_tab_act_->setShortcuts(newTabActShortcutList); - new_tab_act_->setToolTip(_("Open a new file")); + new_tab_act_ = new QAction(tr("New"), this); + new_tab_act_->setIcon(QIcon(":/icons/misc_doc.png")); + QList<QKeySequence> new_tab_act_shortcut_list; + new_tab_act_shortcut_list.append(QKeySequence(Qt::CTRL | Qt::Key_N)); + new_tab_act_shortcut_list.append(QKeySequence(Qt::CTRL | Qt::Key_T)); + new_tab_act_->setShortcuts(new_tab_act_shortcut_list); + new_tab_act_->setToolTip(tr("Open a new file")); connect(new_tab_act_, &QAction::triggered, edit_, &TextEdit::SlotNewTab); - open_act_ = new QAction(_("Open..."), this); - open_act_->setIcon(QIcon(":fileopen.png")); + open_act_ = new QAction(tr("Open..."), this); + open_act_->setIcon(QIcon(":/icons/fileopen.png")); open_act_->setShortcut(QKeySequence::Open); - open_act_->setToolTip(_("Open an existing file")); + open_act_->setToolTip(tr("Open an existing file")); connect(open_act_, &QAction::triggered, edit_, &TextEdit::SlotOpen); - browser_act_ = new QAction(_("File Browser"), this); - browser_act_->setIcon(QIcon(":file-browser.png")); -#ifdef GPGFRONTEND_GUI_QT6 + browser_act_ = new QAction(tr("File Browser"), this); + browser_act_->setIcon(QIcon(":/icons/file-browser.png")); browser_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B)); -#else - browser_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); -#endif - browser_act_->setToolTip(_("Open a file browser")); + browser_act_->setToolTip(tr("Open a file browser")); connect(browser_act_, &QAction::triggered, this, &MainWindow::slot_open_file_tab); - save_act_ = new QAction(_("Save File"), this); - save_act_->setIcon(QIcon(":filesave.png")); + save_act_ = new QAction(tr("Save File"), this); + save_act_->setIcon(QIcon(":/icons/filesave.png")); save_act_->setShortcut(QKeySequence::Save); - save_act_->setToolTip(_("Save the current File")); + save_act_->setToolTip(tr("Save the current File")); connect(save_act_, &QAction::triggered, edit_, &TextEdit::SlotSave); - save_as_act_ = new QAction(QString(_("Save As")) + "...", this); - save_as_act_->setIcon(QIcon(":filesaveas.png")); + save_as_act_ = new QAction(tr("Save As") + "...", this); + save_as_act_->setIcon(QIcon(":/icons/filesaveas.png")); save_as_act_->setShortcut(QKeySequence::SaveAs); - save_as_act_->setToolTip(_("Save the current File as...")); + save_as_act_->setToolTip(tr("Save the current File as...")); connect(save_as_act_, &QAction::triggered, edit_, &TextEdit::SlotSaveAs); - print_act_ = new QAction(_("Print"), this); - print_act_->setIcon(QIcon(":fileprint.png")); + print_act_ = new QAction(tr("Print"), this); + print_act_->setIcon(QIcon(":/icons/fileprint.png")); print_act_->setShortcut(QKeySequence::Print); - print_act_->setToolTip(_("Print Document")); + print_act_->setToolTip(tr("Print Document")); connect(print_act_, &QAction::triggered, edit_, &TextEdit::SlotPrint); - close_tab_act_ = new QAction(_("Close"), this); + close_tab_act_ = new QAction(tr("Close"), this); close_tab_act_->setShortcut(QKeySequence::Close); - close_tab_act_->setToolTip(_("Close file")); + close_tab_act_->setToolTip(tr("Close file")); connect(close_tab_act_, &QAction::triggered, edit_, &TextEdit::SlotCloseTab); - quit_act_ = new QAction(_("Quit"), this); + quit_act_ = new QAction(tr("Quit"), this); quit_act_->setShortcut(QKeySequence::Quit); - quit_act_->setIcon(QIcon(":exit.png")); - quit_act_->setToolTip(_("Quit Program")); + quit_act_->setIcon(QIcon(":/icons/exit.png")); + quit_act_->setToolTip(tr("Quit Program")); connect(quit_act_, &QAction::triggered, this, &MainWindow::close); /* Edit Menu */ - undo_act_ = new QAction(_("Undo"), this); + undo_act_ = new QAction(tr("Undo"), this); undo_act_->setShortcut(QKeySequence::Undo); - undo_act_->setToolTip(_("Undo Last Edit Action")); + undo_act_->setToolTip(tr("Undo Last Edit Action")); connect(undo_act_, &QAction::triggered, edit_, &TextEdit::SlotUndo); - redo_act_ = new QAction(_("Redo"), this); + redo_act_ = new QAction(tr("Redo"), this); redo_act_->setShortcut(QKeySequence::Redo); - redo_act_->setToolTip(_("Redo Last Edit Action")); + redo_act_->setToolTip(tr("Redo Last Edit Action")); connect(redo_act_, &QAction::triggered, edit_, &TextEdit::SlotRedo); - zoom_in_act_ = new QAction(_("Zoom In"), this); + zoom_in_act_ = new QAction(tr("Zoom In"), this); zoom_in_act_->setShortcut(QKeySequence::ZoomIn); connect(zoom_in_act_, &QAction::triggered, edit_, &TextEdit::SlotZoomIn); - zoom_out_act_ = new QAction(_("Zoom Out"), this); + zoom_out_act_ = new QAction(tr("Zoom Out"), this); zoom_out_act_->setShortcut(QKeySequence::ZoomOut); connect(zoom_out_act_, &QAction::triggered, edit_, &TextEdit::SlotZoomOut); - paste_act_ = new QAction(_("Paste"), this); - paste_act_->setIcon(QIcon(":button_paste.png")); + paste_act_ = new QAction(tr("Paste"), this); + paste_act_->setIcon(QIcon(":/icons/button_paste.png")); paste_act_->setShortcut(QKeySequence::Paste); - paste_act_->setToolTip(_("Paste Text From Clipboard")); + paste_act_->setToolTip(tr("Paste Text From Clipboard")); connect(paste_act_, &QAction::triggered, edit_, &TextEdit::SlotPaste); - cut_act_ = new QAction(_("Cut"), this); - cut_act_->setIcon(QIcon(":button_cut.png")); + cut_act_ = new QAction(tr("Cut"), this); + cut_act_->setIcon(QIcon(":/icons/button_cut.png")); cut_act_->setShortcut(QKeySequence::Cut); cut_act_->setToolTip( - _("Cut the current selection's contents to the " - "clipboard")); + tr("Cut the current selection's contents to the " + "clipboard")); connect(cut_act_, &QAction::triggered, edit_, &TextEdit::SlotCut); - copy_act_ = new QAction(_("Copy"), this); - copy_act_->setIcon(QIcon(":button_copy.png")); + copy_act_ = new QAction(tr("Copy"), this); + copy_act_->setIcon(QIcon(":/icons/button_copy.png")); copy_act_->setShortcut(QKeySequence::Copy); copy_act_->setToolTip( - _("Copy the current selection's contents to the " - "clipboard")); + tr("Copy the current selection's contents to the " + "clipboard")); connect(copy_act_, &QAction::triggered, edit_, &TextEdit::SlotCopy); - quote_act_ = new QAction(_("Quote"), this); - quote_act_->setIcon(QIcon(":quote.png")); - quote_act_->setToolTip(_("Quote whole text")); + quote_act_ = new QAction(tr("Quote"), this); + quote_act_->setIcon(QIcon(":/icons/quote.png")); + quote_act_->setToolTip(tr("Quote whole text")); connect(quote_act_, &QAction::triggered, edit_, &TextEdit::SlotQuote); - select_all_act_ = new QAction(_("Select All"), this); - select_all_act_->setIcon(QIcon(":edit.png")); + select_all_act_ = new QAction(tr("Select All"), this); + select_all_act_->setIcon(QIcon(":/icons/edit.png")); select_all_act_->setShortcut(QKeySequence::SelectAll); - select_all_act_->setToolTip(_("Select the whole text")); + select_all_act_->setToolTip(tr("Select the whole text")); connect(select_all_act_, &QAction::triggered, edit_, &TextEdit::SlotSelectAll); - find_act_ = new QAction(_("Find"), this); + find_act_ = new QAction(tr("Find"), this); find_act_->setShortcut(QKeySequence::Find); - find_act_->setToolTip(_("Find a word")); + find_act_->setToolTip(tr("Find a word")); connect(find_act_, &QAction::triggered, this, &MainWindow::slot_find); - clean_double_line_breaks_act_ = new QAction(_("Remove spacing"), this); + clean_double_line_breaks_act_ = new QAction(tr("Remove spacing"), this); clean_double_line_breaks_act_->setIcon( - QIcon(":format-line-spacing-triple.png")); + QIcon(":/icons/format-line-spacing-triple.png")); // cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll); clean_double_line_breaks_act_->setToolTip( - _("Remove double linebreaks, e.g. in pasted text from Web Mailer")); + tr("Remove double linebreaks, e.g. in pasted text from Web Mailer")); connect(clean_double_line_breaks_act_, &QAction::triggered, this, &MainWindow::slot_clean_double_line_breaks); - open_settings_act_ = new QAction(_("Settings"), this); - open_settings_act_->setToolTip(_("Open settings dialog")); + open_settings_act_ = new QAction(tr("Settings"), this); + open_settings_act_->setToolTip(tr("Open settings dialog")); open_settings_act_->setMenuRole(QAction::PreferencesRole); open_settings_act_->setShortcut(QKeySequence::Preferences); connect(open_settings_act_, &QAction::triggered, this, @@ -172,269 +170,345 @@ void MainWindow::create_actions() { /* Crypt Menu */ - encrypt_act_ = new QAction(_("Encrypt"), this); - encrypt_act_->setIcon(QIcon(":encrypted.png")); -#ifdef GPGFRONTEND_GUI_QT6 + encrypt_act_ = new QAction(tr("Encrypt"), this); + encrypt_act_->setIcon(QIcon(":/icons/encrypted.png")); encrypt_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_E)); -#else -#endif - encrypt_act_->setToolTip(_("Encrypt Message")); - connect(encrypt_act_, &QAction::triggered, this, &MainWindow::slot_encrypt); - - encrypt_sign_act_ = new QAction(_("Encrypt Sign"), this); - encrypt_sign_act_->setIcon(QIcon(":encrypted_signed.png")); -#ifdef GPGFRONTEND_GUI_QT6 + + encrypt_act_->setToolTip(tr("Encrypt Message")); + connect(encrypt_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + this->SlotFileEncrypt(path); + } else if (file_info.isDir()) { + this->SlotDirectoryEncrypt(path); + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotEncrypt(); + } + }); + + encrypt_sign_act_ = new QAction(tr("Encrypt Sign"), this); + encrypt_sign_act_->setIcon(QIcon(":/icons/encrypted_signed.png")); encrypt_sign_act_->setShortcut( QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_E)); -#else - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); -#endif - encrypt_sign_act_->setToolTip(_("Encrypt and Sign Message")); - connect(encrypt_sign_act_, &QAction::triggered, this, - &MainWindow::slot_encrypt_sign); - - decrypt_act_ = new QAction(_("Decrypt"), this); - decrypt_act_->setIcon(QIcon(":decrypted.png")); -#ifdef GPGFRONTEND_GUI_QT6 + + encrypt_sign_act_->setToolTip(tr("Encrypt and Sign Message")); + connect(encrypt_sign_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + this->SlotFileEncryptSign(path); + } else if (file_info.isDir()) { + this->SlotDirectoryEncryptSign(path); + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotEncryptSign(); + } + }); + + decrypt_act_ = new QAction(tr("Decrypt"), this); + decrypt_act_->setIcon(QIcon(":/icons/decrypted.png")); decrypt_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D)); -#else - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); -#endif - decrypt_act_->setToolTip(_("Decrypt Message")); - connect(decrypt_act_, &QAction::triggered, this, &MainWindow::slot_decrypt); - - decrypt_verify_act_ = new QAction(_("Decrypt Verify"), this); - decrypt_verify_act_->setIcon(QIcon(":decrypted_verified.png")); -#ifdef GPGFRONTEND_GUI_QT6 + decrypt_act_->setToolTip(tr("Decrypt Message")); + connect(decrypt_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + const QString extension = file_info.completeSuffix(); + + if (extension == "tar.gpg" || extension == "tar.asc") { + this->SlotArchiveDecrypt(path); + } else { + this->SlotFileDecrypt(path); + } + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotDecrypt(); + } + }); + + decrypt_verify_act_ = new QAction(tr("Decrypt Verify"), this); + decrypt_verify_act_->setIcon(QIcon(":/icons/decrypted_verified.png")); decrypt_verify_act_->setShortcut( QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D)); -#else - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); -#endif - decrypt_verify_act_->setToolTip(_("Decrypt and Verify Message")); - connect(decrypt_verify_act_, &QAction::triggered, this, - &MainWindow::slot_decrypt_verify); - - sign_act_ = new QAction(_("Sign"), this); - sign_act_->setIcon(QIcon(":signature.png")); -#ifdef GPGFRONTEND_GUI_QT6 + decrypt_verify_act_->setToolTip(tr("Decrypt and Verify Message")); + connect(decrypt_verify_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) { + const QString extension = file_info.completeSuffix(); + + if (extension == ".tar.gpg" || extension == ".tar.asc") { + this->SlotArchiveDecryptVerify(path); + } else { + this->SlotFileDecryptVerify(path); + } + } + } + if (edit_->SlotCurPageTextEdit() != nullptr) { + this->SlotDecryptVerify(); + } + }); + + sign_act_ = new QAction(tr("Sign"), this); + sign_act_->setIcon(QIcon(":/icons/signature.png")); sign_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I)); -#else - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); -#endif - sign_act_->setToolTip(_("Sign Message")); - connect(sign_act_, &QAction::triggered, this, &MainWindow::slot_sign); - - verify_act_ = new QAction(_("Verify"), this); - verify_act_->setIcon(QIcon(":verify.png")); -#ifdef GPGFRONTEND_GUI_QT6 + sign_act_->setToolTip(tr("Sign Message")); + connect(sign_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) this->SlotFileSign(path); + } + if (edit_->SlotCurPageTextEdit() != nullptr) this->SlotSign(); + }); + + verify_act_ = new QAction(tr("Verify"), this); + verify_act_->setIcon(QIcon(":/icons/verify.png")); verify_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_V)); -#else - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); -#endif - verify_act_->setToolTip(_("Verify Message")); - connect(verify_act_, &QAction::triggered, this, &MainWindow::slot_verify); + verify_act_->setToolTip(tr("Verify Message")); + connect(verify_act_, &QAction::triggered, this, [this]() { + if (edit_->SlotCurPageFileTreeView() != nullptr) { + const auto* file_tree_view = edit_->SlotCurPageFileTreeView(); + const auto path = file_tree_view->GetSelected(); + + const auto file_info = QFileInfo(path); + if (file_info.isFile()) this->SlotFileVerify(path); + } + if (edit_->SlotCurPageTextEdit() != nullptr) this->SlotVerify(); + }); /* Key Menu */ - import_key_from_file_act_ = new QAction(_("File"), this); - import_key_from_file_act_->setIcon(QIcon(":import_key_from_file.png")); - import_key_from_file_act_->setToolTip(_("Import New Key From File")); + import_key_from_file_act_ = new QAction(tr("File"), this); + import_key_from_file_act_->setIcon(QIcon(":/icons/import_key_from_file.png")); + import_key_from_file_act_->setToolTip(tr("Import New Key From File")); connect(import_key_from_file_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromFile(this); }); - import_key_from_clipboard_act_ = new QAction(_("Clipboard"), this); + import_key_from_clipboard_act_ = new QAction(tr("Clipboard"), this); import_key_from_clipboard_act_->setIcon( - QIcon(":import_key_from_clipboard.png")); + QIcon(":/icons/import_key_from_clipboard.png")); import_key_from_clipboard_act_->setToolTip( - _("Import New Key From Clipboard")); + tr("Import New Key From Clipboard")); connect(import_key_from_clipboard_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromClipboard(this); }); bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); + GlobalSettingStation::GetInstance() + .GetSettings() + .value("network/forbid_all_gnupg_connection", false) + .toBool(); - import_key_from_key_server_act_ = new QAction(_("Keyserver"), this); + import_key_from_key_server_act_ = new QAction(tr("Keyserver"), this); import_key_from_key_server_act_->setIcon( - QIcon(":import_key_from_server.png")); + QIcon(":/icons/import_key_from_server.png")); import_key_from_key_server_act_->setToolTip( - _("Import New Key From Keyserver")); + tr("Import New Key From Keyserver")); import_key_from_key_server_act_->setDisabled(forbid_all_gnupg_connection); connect(import_key_from_key_server_act_, &QAction::triggered, this, [&]() { CommonUtils::GetInstance()->SlotImportKeyFromKeyServer(this); }); - import_key_from_edit_act_ = new QAction(_("Editor"), this); - import_key_from_edit_act_->setIcon(QIcon(":txt.png")); - import_key_from_edit_act_->setToolTip(_("Import New Key From Editor")); + import_key_from_edit_act_ = new QAction(tr("Editor"), this); + import_key_from_edit_act_->setIcon(QIcon(":/icons/txt.png")); + import_key_from_edit_act_->setToolTip(tr("Import New Key From Editor")); connect(import_key_from_edit_act_, &QAction::triggered, this, &MainWindow::slot_import_key_from_edit); - open_key_management_act_ = new QAction(_("Manage Keys"), this); - open_key_management_act_->setIcon(QIcon(":keymgmt.png")); - open_key_management_act_->setToolTip(_("Open Key Management")); + open_key_management_act_ = new QAction(tr("Manage Keys"), this); + open_key_management_act_->setIcon(QIcon(":/icons/keymgmt.png")); + open_key_management_act_->setToolTip(tr("Open Key Management")); connect(open_key_management_act_, &QAction::triggered, this, &MainWindow::slot_open_key_management); - clean_gpg_password_cache_act_ = new QAction(_("Clear Password Cache"), this); - clean_gpg_password_cache_act_->setIcon(QIcon(":configure.png")); - clean_gpg_password_cache_act_->setToolTip(_("Clear Password Cache of GnuPG")); + clean_gpg_password_cache_act_ = new QAction(tr("Clear Password Cache"), this); + clean_gpg_password_cache_act_->setIcon(QIcon(":/icons/configure.png")); + clean_gpg_password_cache_act_->setToolTip( + tr("Clear Password Cache of GnuPG")); connect(clean_gpg_password_cache_act_, &QAction::triggered, this, [=]() { - if (GpgFrontend::GpgAdvancedOperator::GetInstance() - .ClearGpgPasswordCache()) { - QMessageBox::information(this, _("Successful Operation"), - _("Clear password cache successfully")); - } else { - QMessageBox::critical(this, _("Failed Operation"), - _("Failed to clear password cache of GnuPG")); - } + GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache([=](int err, + DataObjectPtr) { + if (err >= 0) { + QMessageBox::information(this, tr("Successful Operation"), + tr("Clear password cache successfully")); + } else { + QMessageBox::critical(this, tr("Failed Operation"), + tr("Failed to clear password cache of GnuPG")); + } + }); }); - reload_components_act_ = new QAction(_("Reload All Components"), this); - reload_components_act_->setIcon(QIcon(":configure.png")); - reload_components_act_->setToolTip(_("Reload All GnuPG's Components")); + reload_components_act_ = new QAction(tr("Reload All Components"), this); + reload_components_act_->setIcon(QIcon(":/icons/configure.png")); + reload_components_act_->setToolTip(tr("Reload All GnuPG's Components")); connect(reload_components_act_, &QAction::triggered, this, [=]() { - if (GpgFrontend::GpgAdvancedOperator::GetInstance().ReloadGpgComponents()) { - QMessageBox::information( - this, _("Successful Operation"), - _("Reload all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, _("Failed Operation"), - _("Failed to reload all or one of the GnuPG's component(s)")); - } + GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents( + [=](int err, DataObjectPtr) { + if (err >= 0) { + QMessageBox::information( + this, tr("Successful Operation"), + tr("Reload all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, tr("Failed Operation"), + tr("Failed to reload all or one of the GnuPG's component(s)")); + } + }); }); - restart_components_act_ = new QAction(_("Restart All Components"), this); - restart_components_act_->setIcon(QIcon(":configure.png")); - restart_components_act_->setToolTip(_("Restart All GnuPG's Components")); + restart_components_act_ = new QAction(tr("Restart All Components"), this); + restart_components_act_->setIcon(QIcon(":/icons/configure.png")); + restart_components_act_->setToolTip(tr("Restart All GnuPG's Components")); connect(restart_components_act_, &QAction::triggered, this, [=]() { - if (GpgFrontend::GpgAdvancedOperator::GetInstance() - .RestartGpgComponents()) { - QMessageBox::information( - this, _("Successful Operation"), - _("Restart all the GnuPG's components successfully")); - } else { - QMessageBox::critical( - this, _("Failed Operation"), - _("Failed to restart all or one of the GnuPG's component(s)")); - } + GpgFrontend::GpgAdvancedOperator::RestartGpgComponents(); + Module::ListenRTPublishEvent( + this, "core", "gpg_advanced_operator.restart_gpg_components", + [=](Module::Namespace, Module::Key, int, std::any value) { + bool success_state = std::any_cast<bool>(value); + if (success_state) { + QMessageBox::information( + this, tr("Successful Operation"), + tr("Restart all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, tr("Failed Operation"), + tr("Failed to restart all or one of the GnuPG's component(s)")); + } + }); }); - gnupg_controller_open_act_ = new QAction(_("Open GnuPG Controller"), this); - gnupg_controller_open_act_->setIcon(QIcon(":configure.png")); - gnupg_controller_open_act_->setToolTip(_("Open GnuPG Controller Dialog")); + gnupg_controller_open_act_ = new QAction(tr("Open GnuPG Controller"), this); + gnupg_controller_open_act_->setIcon(QIcon(":/icons/configure.png")); + gnupg_controller_open_act_->setToolTip(tr("Open GnuPG Controller Dialog")); connect(gnupg_controller_open_act_, &QAction::triggered, this, [this]() { (new GnuPGControllerDialog(this))->exec(); }); /* * About Menu */ - about_act_ = new QAction(_("About"), this); - about_act_->setIcon(QIcon(":help.png")); - about_act_->setToolTip(_("Show the application's About box")); + about_act_ = new QAction(tr("About"), this); + about_act_->setIcon(QIcon(":/icons/help.png")); + about_act_->setToolTip(tr("Show the application's About box")); about_act_->setMenuRole(QAction::AboutRole); connect(about_act_, &QAction::triggered, this, [=]() { new AboutDialog(0, this); }); - gnupg_act_ = new QAction(_("GnuPG"), this); - gnupg_act_->setIcon(QIcon(":help.png")); - gnupg_act_->setToolTip(_("Information about Gnupg")); + gnupg_act_ = new QAction(tr("GnuPG"), this); + gnupg_act_->setIcon(QIcon(":/icons/help.png")); + gnupg_act_->setToolTip(tr("Information about Gnupg")); connect(gnupg_act_, &QAction::triggered, this, [=]() { new AboutDialog(1, this); }); - translate_act_ = new QAction(_("Translate"), this); - translate_act_->setIcon(QIcon(":help.png")); - translate_act_->setToolTip(_("Information about translation")); + translate_act_ = new QAction(tr("Translate"), this); + translate_act_->setIcon(QIcon(":/icons/help.png")); + translate_act_->setToolTip(tr("Information about translation")); connect(translate_act_, &QAction::triggered, this, [=]() { new AboutDialog(2, this); }); /* * Check Update Menu */ - check_update_act_ = new QAction(_("Check for Updates"), this); - check_update_act_->setIcon(QIcon(":help.png")); - check_update_act_->setToolTip(_("Check for updates")); + check_update_act_ = new QAction(tr("Check for Updates"), this); + check_update_act_->setIcon(QIcon(":/icons/help.png")); + check_update_act_->setToolTip(tr("Check for updates")); connect(check_update_act_, &QAction::triggered, this, [=]() { new AboutDialog(3, this); }); - start_wizard_act_ = new QAction(_("Open Wizard"), this); - start_wizard_act_->setToolTip(_("Open the wizard")); + start_wizard_act_ = new QAction(tr("Open Wizard"), this); + start_wizard_act_->setToolTip(tr("Open the wizard")); connect(start_wizard_act_, &QAction::triggered, this, &MainWindow::slot_start_wizard); append_selected_keys_act_ = - new QAction(_("Append Public Key to Editor"), this); + new QAction(tr("Append Public Key to Editor"), this); append_selected_keys_act_->setToolTip( - _("Append selected Keypair's Public Key to Editor")); + tr("Append selected Keypair's Public Key to Editor")); connect(append_selected_keys_act_, &QAction::triggered, this, &MainWindow::slot_append_selected_keys); append_key_create_date_to_editor_act_ = - new QAction(_("Append Create DateTime to Editor"), this); + new QAction(tr("Append Create DateTime to Editor"), this); append_key_create_date_to_editor_act_->setToolTip( - _("Append selected Key's creation date and time to Editor")); + tr("Append selected Key's creation date and time to Editor")); connect(append_key_create_date_to_editor_act_, &QAction::triggered, this, &MainWindow::slot_append_keys_create_datetime); append_key_expire_date_to_editor_act_ = - new QAction(_("Append Expire DateTime to Editor"), this); + new QAction(tr("Append Expire DateTime to Editor"), this); append_key_expire_date_to_editor_act_->setToolTip( - _("Append selected Key's expiration date and time to Editor")); + tr("Append selected Key's expiration date and time to Editor")); connect(append_key_expire_date_to_editor_act_, &QAction::triggered, this, &MainWindow::slot_append_keys_expire_datetime); append_key_fingerprint_to_editor_act_ = - new QAction(_("Append Fingerprint to Editor"), this); + new QAction(tr("Append Fingerprint to Editor"), this); append_key_expire_date_to_editor_act_->setToolTip( - _("Append selected Key's Fingerprint to Editor")); + tr("Append selected Key's Fingerprint to Editor")); connect(append_key_fingerprint_to_editor_act_, &QAction::triggered, this, &MainWindow::slot_append_keys_fingerprint); - copy_mail_address_to_clipboard_act_ = new QAction(_("Copy Email"), this); + copy_mail_address_to_clipboard_act_ = new QAction(tr("Copy Email"), this); copy_mail_address_to_clipboard_act_->setToolTip( - _("Copy selected Keypair's to clipboard")); + tr("Copy selected Keypair's to clipboard")); connect(copy_mail_address_to_clipboard_act_, &QAction::triggered, this, &MainWindow::slot_copy_mail_address_to_clipboard); copy_key_default_uid_to_clipboard_act_ = - new QAction(_("Copy Default UID"), this); + new QAction(tr("Copy Default UID"), this); copy_key_default_uid_to_clipboard_act_->setToolTip( - _("Copy selected Keypair's default UID to clipboard")); + tr("Copy selected Keypair's default UID to clipboard")); connect(copy_key_default_uid_to_clipboard_act_, &QAction::triggered, this, &MainWindow::slot_copy_default_uid_to_clipboard); - copy_key_id_to_clipboard_act_ = new QAction(_("Copy Key ID"), this); + copy_key_id_to_clipboard_act_ = new QAction(tr("Copy Key ID"), this); copy_key_id_to_clipboard_act_->setToolTip( - _("Copy selected Keypair's ID to clipboard")); + tr("Copy selected Keypair's ID to clipboard")); connect(copy_key_id_to_clipboard_act_, &QAction::triggered, this, &MainWindow::slot_copy_key_id_to_clipboard); - show_key_details_act_ = new QAction(_("Show Key Details"), this); - show_key_details_act_->setToolTip(_("Show Details for this Key")); + show_key_details_act_ = new QAction(tr("Show Key Details"), this); + show_key_details_act_->setToolTip(tr("Show Details for this Key")); connect(show_key_details_act_, &QAction::triggered, this, &MainWindow::slot_show_key_details); - add_key_2_favourtie_act_ = new QAction(_("Add To Favourite"), this); - add_key_2_favourtie_act_->setToolTip(_("Add this key to Favourite Table")); + add_key_2_favourtie_act_ = new QAction(tr("Add To Favourite"), this); + add_key_2_favourtie_act_->setToolTip(tr("Add this key to Favourite Table")); add_key_2_favourtie_act_->setData(QVariant("add_key_2_favourite_action")); connect(add_key_2_favourtie_act_, &QAction::triggered, this, &MainWindow::slot_add_key_2_favourite); remove_key_from_favourtie_act_ = - new QAction(_("Remove From Favourite"), this); + new QAction(tr("Remove From Favourite"), this); remove_key_from_favourtie_act_->setToolTip( - _("Remove this key from Favourite Table")); + tr("Remove this key from Favourite Table")); remove_key_from_favourtie_act_->setData( QVariant("remove_key_from_favourtie_action")); connect(remove_key_from_favourtie_act_, &QAction::triggered, this, &MainWindow::slot_remove_key_from_favourite); - set_owner_trust_of_key_act_ = new QAction(_("Set Owner Trust Level"), this); - set_owner_trust_of_key_act_->setToolTip(_("Set Owner Trust Level")); + set_owner_trust_of_key_act_ = new QAction(tr("Set Owner Trust Level"), this); + set_owner_trust_of_key_act_->setToolTip(tr("Set Owner Trust Level")); set_owner_trust_of_key_act_->setData(QVariant("set_owner_trust_level")); connect(set_owner_trust_of_key_act_, &QAction::triggered, this, &MainWindow::slot_set_owner_trust_level_of_key); @@ -453,17 +527,17 @@ void MainWindow::create_actions() { &TextEdit::SlotSwitchTabDown); this->addAction(switch_tab_down_act_); - cut_pgp_header_act_ = new QAction(_("Remove PGP Header"), this); + cut_pgp_header_act_ = new QAction(tr("Remove PGP Header"), this); connect(cut_pgp_header_act_, &QAction::triggered, this, &MainWindow::slot_cut_pgp_header); - add_pgp_header_act_ = new QAction(_("Add PGP Header"), this); + add_pgp_header_act_ = new QAction(tr("Add PGP Header"), this); connect(add_pgp_header_act_, &QAction::triggered, this, &MainWindow::slot_add_pgp_header); } void MainWindow::create_menus() { - file_menu_ = menuBar()->addMenu(_("File")); + file_menu_ = menuBar()->addMenu(tr("File")); file_menu_->addAction(new_tab_act_); file_menu_->addAction(browser_act_); file_menu_->addAction(open_act_); @@ -476,7 +550,7 @@ void MainWindow::create_menus() { file_menu_->addAction(close_tab_act_); file_menu_->addAction(quit_act_); - edit_menu_ = menuBar()->addMenu(_("Edit")); + edit_menu_ = menuBar()->addMenu(tr("Edit")); edit_menu_->addAction(undo_act_); edit_menu_->addAction(redo_act_); edit_menu_->addSeparator(); @@ -494,7 +568,7 @@ void MainWindow::create_menus() { edit_menu_->addSeparator(); edit_menu_->addAction(open_settings_act_); - crypt_menu_ = menuBar()->addMenu(_("Crypt")); + crypt_menu_ = menuBar()->addMenu(tr("Crypt")); crypt_menu_->addAction(encrypt_act_); crypt_menu_->addAction(encrypt_sign_act_); crypt_menu_->addAction(decrypt_act_); @@ -504,16 +578,16 @@ void MainWindow::create_menus() { crypt_menu_->addAction(verify_act_); crypt_menu_->addSeparator(); - key_menu_ = menuBar()->addMenu(_("Keys")); - import_key_menu_ = key_menu_->addMenu(_("Import Key")); - import_key_menu_->setIcon(QIcon(":key_import.png")); + key_menu_ = menuBar()->addMenu(tr("Keys")); + import_key_menu_ = key_menu_->addMenu(tr("Import Key")); + import_key_menu_->setIcon(QIcon(":/icons/key_import.png")); import_key_menu_->addAction(import_key_from_file_act_); import_key_menu_->addAction(import_key_from_edit_act_); import_key_menu_->addAction(import_key_from_clipboard_act_); import_key_menu_->addAction(import_key_from_key_server_act_); key_menu_->addAction(open_key_management_act_); - gpg_menu_ = menuBar()->addMenu(_("GnuPG")); + gpg_menu_ = menuBar()->addMenu(tr("GnuPG")); gpg_menu_->addAction(clean_gpg_password_cache_act_); gpg_menu_->addSeparator(); gpg_menu_->addAction(reload_components_act_); @@ -521,13 +595,13 @@ void MainWindow::create_menus() { gpg_menu_->addSeparator(); gpg_menu_->addAction(gnupg_controller_open_act_); - steganography_menu_ = menuBar()->addMenu(_("Steganography")); + steganography_menu_ = menuBar()->addMenu(tr("Steganography")); steganography_menu_->addAction(cut_pgp_header_act_); steganography_menu_->addAction(add_pgp_header_act_); - view_menu_ = menuBar()->addMenu(_("View")); + view_menu_ = menuBar()->addMenu(tr("View")); - help_menu_ = menuBar()->addMenu(_("Help")); + help_menu_ = menuBar()->addMenu(tr("Help")); help_menu_->addAction(start_wizard_act_); help_menu_->addSeparator(); help_menu_->addAction(check_update_act_); @@ -537,15 +611,14 @@ void MainWindow::create_menus() { } void MainWindow::create_tool_bars() { - file_tool_bar_ = addToolBar(_("File")); + file_tool_bar_ = addToolBar(tr("File")); file_tool_bar_->setObjectName("fileToolBar"); file_tool_bar_->addAction(new_tab_act_); file_tool_bar_->addAction(open_act_); - file_tool_bar_->addAction(save_act_); file_tool_bar_->addAction(browser_act_); view_menu_->addAction(file_tool_bar_->toggleViewAction()); - crypt_tool_bar_ = addToolBar(_("Operations")); + crypt_tool_bar_ = addToolBar(tr("Operations")); crypt_tool_bar_->setObjectName("cryptToolBar"); crypt_tool_bar_->addAction(encrypt_act_); crypt_tool_bar_->addAction(encrypt_sign_act_); @@ -555,12 +628,12 @@ void MainWindow::create_tool_bars() { crypt_tool_bar_->addAction(verify_act_); view_menu_->addAction(crypt_tool_bar_->toggleViewAction()); - key_tool_bar_ = addToolBar(_("Key")); + key_tool_bar_ = addToolBar(tr("Key")); key_tool_bar_->setObjectName("keyToolBar"); key_tool_bar_->addAction(open_key_management_act_); view_menu_->addAction(key_tool_bar_->toggleViewAction()); - edit_tool_bar_ = addToolBar(_("Edit")); + edit_tool_bar_ = addToolBar(tr("Edit")); edit_tool_bar_->setObjectName("editToolBar"); edit_tool_bar_->addAction(copy_act_); edit_tool_bar_->addAction(paste_act_); @@ -568,7 +641,7 @@ void MainWindow::create_tool_bars() { edit_tool_bar_->hide(); view_menu_->addAction(edit_tool_bar_->toggleViewAction()); - special_edit_tool_bar_ = addToolBar(_("Special Edit")); + special_edit_tool_bar_ = addToolBar(tr("Special Edit")); special_edit_tool_bar_->setObjectName("specialEditToolBar"); special_edit_tool_bar_->addAction(quote_act_); special_edit_tool_bar_->addAction(clean_double_line_breaks_act_); @@ -579,32 +652,32 @@ void MainWindow::create_tool_bars() { import_button_ = new QToolButton(); import_button_->setMenu(import_key_menu_); import_button_->setPopupMode(QToolButton::InstantPopup); - import_button_->setIcon(QIcon(":key_import.png")); - import_button_->setToolTip(_("Import key from...")); - import_button_->setText(_("Import key")); + import_button_->setIcon(QIcon(":/icons/key_import.png")); + import_button_->setToolTip(tr("Import key from...")); + import_button_->setText(tr("Import key")); key_tool_bar_->addWidget(import_button_); } void MainWindow::create_status_bar() { - auto* statusBarBox = new QWidget(); - auto* statusBarBoxLayout = new QHBoxLayout(); + auto* status_bar_box = new QWidget(); + auto* status_bar_box_layout = new QHBoxLayout(); // QPixmap* pixmap; // icon which should be shown if there are files in attachments-folder - // pixmap = new QPixmap(":statusbar_icon.png"); + // pixmap = new QPixmap(":/icons/statusbar_icon.png"); // statusBarIcon = new QLabel(); // statusBar()->addWidget(statusBarIcon); // // statusBarIcon->setPixmap(*pixmap); // statusBar()->insertPermanentWidget(0, statusBarIcon, 0); - statusBar()->showMessage(_("Ready"), 2000); - statusBarBox->setLayout(statusBarBoxLayout); + statusBar()->showMessage(tr("Ready"), 2000); + status_bar_box->setLayout(status_bar_box_layout); } void MainWindow::create_dock_windows() { /* KeyList-Dock window */ - key_list_dock_ = new QDockWidget(_("Key ToolBox"), this); + key_list_dock_ = new QDockWidget(tr("Key ToolBox"), this); key_list_dock_->setObjectName("EncryptDock"); key_list_dock_->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); @@ -612,7 +685,7 @@ void MainWindow::create_dock_windows() { addDockWidget(Qt::RightDockWidgetArea, key_list_dock_); m_key_list_->AddListGroupTab( - _("Default"), "default", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Default"), "default", KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -620,7 +693,7 @@ void MainWindow::create_dock_windows() { }); m_key_list_->AddListGroupTab( - _("Favourite"), "favourite", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Favourite"), "favourite", KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -628,7 +701,8 @@ void MainWindow::create_dock_windows() { }); m_key_list_->AddListGroupTab( - _("Only Public Key"), "only_public_key", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Only Public Key"), "only_public_key", + KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -637,7 +711,8 @@ void MainWindow::create_dock_windows() { }); m_key_list_->AddListGroupTab( - _("Has Private Key"), "has_private_key", KeyListRow::SECRET_OR_PUBLIC_KEY, + tr("Has Private Key"), "has_private_key", + KeyListRow::SECRET_OR_PUBLIC_KEY, KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage | KeyListColumn::Validity, [](const GpgKey& key, const KeyTable&) -> bool { @@ -650,7 +725,7 @@ void MainWindow::create_dock_windows() { key_list_dock_->setWidget(m_key_list_); view_menu_->addAction(key_list_dock_->toggleViewAction()); - info_board_dock_ = new QDockWidget(_("Information Board"), this); + info_board_dock_ = new QDockWidget(tr("Information Board"), this); info_board_dock_->setObjectName("Information Board"); info_board_dock_->setAllowedAreas(Qt::BottomDockWidgetArea); addDockWidget(Qt::BottomDockWidgetArea, info_board_dock_); diff --git a/src/ui/struct/CacheObject.cpp b/src/ui/struct/CacheObject.cpp new file mode 100644 index 00000000..bd3b9818 --- /dev/null +++ b/src/ui/struct/CacheObject.cpp @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "CacheObject.h" + +#include "core/function/CacheManager.h" + +namespace GpgFrontend::UI { + +CacheObject::CacheObject(QString cache_name) + : cache_name_(std::move(cache_name)) { + this->QJsonDocument::operator=( + CacheManager::GetInstance().LoadDurableCache(cache_name_)); +} + +CacheObject::~CacheObject() { + CacheManager::GetInstance().SaveDurableCache(cache_name_, *this); +} + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/struct/CacheObject.h b/src/ui/struct/CacheObject.h new file mode 100644 index 00000000..ae8aa056 --- /dev/null +++ b/src/ui/struct/CacheObject.h @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::UI { + +class CacheObject : public QJsonDocument { + public: + /** + * @brief Construct a new Cache Object object + * + * @param cache_name + */ + explicit CacheObject(QString cache_name); + + /** + * @brief Destroy the Cache Object object + * + */ + ~CacheObject(); + + private: + QString cache_name_; ///< +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/struct/SettingsObject.cpp b/src/ui/struct/SettingsObject.cpp index d5230089..cc5e85bf 100644 --- a/src/ui/struct/SettingsObject.cpp +++ b/src/ui/struct/SettingsObject.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,77 +28,42 @@ #include "SettingsObject.h" -nlohmann::json& GpgFrontend::UI::SettingsObject::Check( - const std::string& key, const nlohmann::json& default_value) { - // check if the self null - if (this->nlohmann::json::is_null()) { - SPDLOG_DEBUG("settings object is null, creating new one"); - this->nlohmann::json::operator=(nlohmann::json::object()); - } - - try { - if (!this->nlohmann::json::contains(key) || - this->nlohmann::json::at(key).is_null() || - this->nlohmann::json::at(key).type_name() != - default_value.type_name()) { - SPDLOG_DEBUG("added missing key: {}", key); - if (default_value.is_null()) { - SPDLOG_WARN("default value is null, using empty object"); - this->nlohmann::json::operator[](key) = nlohmann::json::object(); - } else { - this->nlohmann::json::operator[](key) = default_value; - } - } - return this->nlohmann::json::at(key); - } catch (nlohmann::json::exception& e) { - SPDLOG_ERROR(e.what()); - throw e; - } -} - -GpgFrontend::UI::SettingsObject GpgFrontend::UI::SettingsObject::Check( - const std::string& key) { - // check if the self null - if (this->nlohmann::json::is_null()) { - SPDLOG_DEBUG("settings object is null, creating new one"); - this->nlohmann::json::operator=(nlohmann::json::object()); - } +#include "core/function/DataObjectOperator.h" - if (!nlohmann::json::contains(key) || - this->nlohmann::json::at(key).is_null() || - this->nlohmann::json::at(key).type() != nlohmann::json::value_t::object) { - SPDLOG_DEBUG("added missing key: {}", key); - this->nlohmann::json::operator[](key) = nlohmann::json::object(); - } - return SettingsObject{nlohmann::json::operator[](key), false}; -} +namespace GpgFrontend::UI { -GpgFrontend::UI::SettingsObject::SettingsObject(std::string settings_name) +SettingsObject::SettingsObject(QString settings_name) : settings_name_(std::move(settings_name)) { try { - SPDLOG_DEBUG("loading settings from: {}", this->settings_name_); - auto _json_optional = - GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( - settings_name_); + GF_UI_LOG_DEBUG("loading settings from: {}", this->settings_name_); + auto json_optional = + DataObjectOperator::GetInstance().GetDataObject(settings_name_); - if (_json_optional.has_value()) { - SPDLOG_DEBUG("settings object: {} loaded.", settings_name_); - nlohmann::json::operator=(_json_optional.value()); + if (json_optional.has_value() && json_optional->isObject()) { + GF_UI_LOG_DEBUG("settings object: {} loaded.", settings_name_); + QJsonObject::operator=(json_optional.value().object()); } else { - SPDLOG_DEBUG("settings object: {} not found.", settings_name_); - nlohmann::json::operator=({}); + GF_UI_LOG_DEBUG("settings object: {} not found.", settings_name_); + QJsonObject::operator=({}); } } catch (std::exception& e) { - SPDLOG_ERROR(e.what()); + GF_UI_LOG_ERROR("load setting object error: {}", e.what()); } } -GpgFrontend::UI::SettingsObject::SettingsObject(nlohmann::json _sub_json, bool) - : nlohmann::json(std::move(_sub_json)), settings_name_({}) {} +SettingsObject::SettingsObject(QJsonObject sub_json) + : QJsonObject(std::move(sub_json)) {} -GpgFrontend::UI::SettingsObject::~SettingsObject() { - if (!settings_name_.empty()) - GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(settings_name_, - *this); -}
\ No newline at end of file +SettingsObject::~SettingsObject() { + if (!settings_name_.isEmpty()) { + DataObjectOperator::GetInstance().SaveDataObj(settings_name_, + QJsonDocument(*this)); + } +} + +void SettingsObject::Store(const QJsonObject& json) { + auto* parent = (static_cast<QJsonObject*>(this)); + *parent = json; +} +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/struct/SettingsObject.h b/src/ui/struct/SettingsObject.h index d1e85be5..a9e5819f 100644 --- a/src/ui/struct/SettingsObject.h +++ b/src/ui/struct/SettingsObject.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,41 +20,36 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_SETTINGSOBJECT_H -#define GPGFRONTEND_SETTINGSOBJECT_H - -#include <utility> - -#include "core/function/DataObjectOperator.h" +#pragma once namespace GpgFrontend::UI { /** * @brief The SettingsObject class - * This class is used to store settings for the application securely. + * This class is used to store data for the application securely. * */ -class SettingsObject : public nlohmann::json { +class SettingsObject : public QJsonObject { public: /** * @brief Construct a new Settings Object object * * @param settings_name The name of the settings object */ - explicit SettingsObject(std::string settings_name); + explicit SettingsObject(QString settings_name); /** * @brief Construct a new Settings Object object * * @param _sub_json */ - explicit SettingsObject(nlohmann::json _sub_json, bool); + explicit SettingsObject(QJsonObject sub_json); /** * @brief Destroy the Settings Object object @@ -65,24 +60,10 @@ class SettingsObject : public nlohmann::json { /** * @brief * - * @param key - * @param default_value - * @return nlohmann::json& - */ - nlohmann::json& Check(const std::string& key, - const nlohmann::json& default_value); - - /** - * @brief - * - * @param key - * @return SettingsObject */ - SettingsObject Check(const std::string& key); + void Store(const QJsonObject&); private: - std::string settings_name_; ///< + QString settings_name_; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_SETTINGSOBJECT_H diff --git a/src/ui/struct/SoftwareVersion.cpp b/src/ui/struct/SoftwareVersion.cpp deleted file mode 100644 index 6a60cb02..00000000 --- a/src/ui/struct/SoftwareVersion.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "SoftwareVersion.h" - -int GpgFrontend::UI::SoftwareVersion::version_compare(const std::string& a, - const std::string& b) { - auto temp_a = a, temp_b = b; - - if (!temp_a.empty() && temp_a.front() == 'v') { - temp_a = temp_a.erase(0, 1); - SPDLOG_DEBUG("real version a: {}", temp_a); - } - - if (!temp_b.empty() && temp_b.front() == 'v') { - temp_b.erase(0, 1); - SPDLOG_DEBUG("real version b: {}", temp_b); - } - - // First, split the string. - std::vector<std::string> va, vb; - boost::split(va, temp_a, boost::is_any_of(".")); - boost::split(vb, temp_b, boost::is_any_of(".")); - - // Compare the numbers step by step, but only as deep as the version - // with the least elements allows. - const int depth = - std::min(static_cast<int>(va.size()), static_cast<int>(vb.size())); - int ia = 0, ib = 0; - for (int i = 0; i < depth; ++i) { - try { - ia = boost::lexical_cast<int>(va[i]); - ib = boost::lexical_cast<int>(vb[i]); - } catch (boost::bad_lexical_cast& ignored) { - break; - } - if (ia != ib) break; - } - - // Return the required number. - if (ia > ib) - return 1; - else if (ia < ib) - return -1; - else { - // In case of equal versions, assumes that the version - // with the most elements is the highest version. - if (va.size() > vb.size()) - return 1; - else if (va.size() < vb.size()) - return -1; - } - - // Everything is equal, return 0. - return 0; -} - -bool GpgFrontend::UI::SoftwareVersion::NeedUpgrade() const { - SPDLOG_DEBUG("compair version current {} latest {}, result {}", - current_version, latest_version, - version_compare(current_version, latest_version)); - - SPDLOG_DEBUG("load done: {}, pre-release: {}, draft: {}", load_info_done, - latest_prerelease, latest_draft); - return load_info_done && !latest_prerelease && !latest_draft && - version_compare(current_version, latest_version) < 0; -} - -bool GpgFrontend::UI::SoftwareVersion::VersionWithDrawn() const { - return load_info_done && !current_version_found && current_prerelease && - !current_draft; -} - -bool GpgFrontend::UI::SoftwareVersion::CurrentVersionReleased() const { - return load_info_done && current_version_found; -}
\ No newline at end of file diff --git a/src/ui/struct/settings/AppearanceSO.h b/src/ui/struct/settings/AppearanceSO.h new file mode 100644 index 00000000..25262f22 --- /dev/null +++ b/src/ui/struct/settings/AppearanceSO.h @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::UI { + +struct AppearanceSO { + int text_editor_font_size = 12; + int info_board_font_size = 12; + int tool_bar_icon_width = 24; + int tool_bar_icon_height = 24; + Qt::ToolButtonStyle tool_bar_button_style = Qt::ToolButtonTextUnderIcon; + + bool save_window_state; + + explicit AppearanceSO(const QJsonObject& j) { + if (const auto v = j["text_editor_font_size"]; v.isDouble()) { + text_editor_font_size = v.toInt(); + } + if (const auto v = j["info_board_font_size"]; v.isDouble()) { + info_board_font_size = v.toInt(); + } + if (const auto v = j["tool_bar_icon_width"]; v.isDouble()) { + tool_bar_icon_width = v.toInt(); + } + if (const auto v = j["tool_bar_icon_height"]; v.isDouble()) { + tool_bar_icon_height = v.toInt(); + } + if (const auto v = j["tool_bar_button_style"]; v.isDouble()) { + tool_bar_button_style = static_cast<Qt::ToolButtonStyle>(v.toInt()); + } + + if (const auto v = j["save_window_state"]; v.isBool()) { + save_window_state = v.toBool(); + } + } + + [[nodiscard]] auto ToJson() const -> QJsonObject { + QJsonObject j; + j["text_editor_font_size"] = text_editor_font_size; + j["info_board_font_size"] = info_board_font_size; + j["tool_bar_icon_width"] = tool_bar_icon_width; + j["tool_bar_icon_height"] = tool_bar_icon_height; + j["tool_bar_button_style"] = tool_bar_button_style; + + j["save_window_state"] = save_window_state; + return j; + } +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/struct/settings/KeyServerSO.h b/src/ui/struct/settings/KeyServerSO.h new file mode 100644 index 00000000..3c9320d2 --- /dev/null +++ b/src/ui/struct/settings/KeyServerSO.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::UI { + +struct KeyServerSO { + int default_server = 0; + QStringList server_list; + + KeyServerSO() = default; + + explicit KeyServerSO(const QJsonObject& j) { + if (const auto v = j["default_server"]; v.isDouble()) { + default_server = v.toInt(); + } + + if (const auto v = j["server_list"]; v.isArray()) { + const QJsonArray j_array = v.toArray(); + server_list.reserve(j_array.size()); + for (const auto& server : j_array) { + server_list.append(server.toString()); + } + } + + if (server_list.empty()) ResetDefaultServerList(); + } + + auto ToJson() -> QJsonObject { + QJsonObject j; + j["default_server"] = default_server; + auto j_array = QJsonArray(); + + for (const auto& s : server_list) { + j_array.push_back(s); + } + j["server_list"] = j_array; + return j; + } + + auto GetTargetServer() -> QString { + if (server_list.empty()) this->ResetDefaultServerList(); + if (default_server >= server_list.size()) default_server = 0; + return server_list[default_server]; + } + + void ResetDefaultServerList() { + server_list << "https://keyserver.ubuntu.com" + << "https://keys.openpgp.org"; + } +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/struct/settings/WindowStateSO.h b/src/ui/struct/settings/WindowStateSO.h new file mode 100644 index 00000000..3fa56f3c --- /dev/null +++ b/src/ui/struct/settings/WindowStateSO.h @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::UI { + +struct WindowStateSO { + bool window_save = false; + QString window_state_data; + int x = 100; + int y = 100; + int width = 400; + int height = 200; + + WindowStateSO() = default; + + explicit WindowStateSO(const QJsonObject &j) { + if (const auto v = j["window_save"]; v.isBool()) window_save = v.toBool(); + if (const auto v = j["window_state_data"]; v.isString()) { + window_state_data = v.toString(); + } + if (const auto v = j["x"]; v.isDouble()) x = v.toInt(); + if (const auto v = j["y"]; v.isDouble()) y = v.toInt(); + if (const auto v = j["width"]; v.isDouble()) width = v.toInt(); + if (const auto v = j["height"]; v.isDouble()) height = v.toInt(); + } + + [[nodiscard]] auto Json() const -> QJsonObject { + QJsonObject j; + j["window_save"] = window_save; + j["window_state_data"] = window_state_data; + j["x"] = x; + j["y"] = y; + j["width"] = width; + j["height"] = height; + return j; + } +}; +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/thread/KeyServerImportTask.cpp b/src/ui/thread/KeyServerImportTask.cpp index fc6a868c..63cabbcd 100644 --- a/src/ui/thread/KeyServerImportTask.cpp +++ b/src/ui/thread/KeyServerImportTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,47 +19,76 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "ui/thread/KeyServerImportTask.h" -#include <vector> +#include "core/function/gpg/GpgKeyImportExporter.h" +#include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/KeyServerSO.h" GpgFrontend::UI::KeyServerImportTask::KeyServerImportTask( - std::string keyserver_url, std::vector<std::string> keyids) + QString keyserver_url, std::vector<QString> keyids) : Task("key_server_import_task"), keyserver_url_(std::move(keyserver_url)), keyids_(std::move(keyids)), - manager_(new QNetworkAccessManager(this)) {} + manager_(new QNetworkAccessManager(this)) { + HoldOnLifeCycle(true); -void GpgFrontend::UI::KeyServerImportTask::run() { - SetFinishAfterRun(false); + if (keyserver_url_.isEmpty()) { + KeyServerSO key_server(SettingsObject("general_settings_state")); + keyserver_url_ = key_server.GetTargetServer(); + GF_UI_LOG_DEBUG("key server import task sets key server url: {}", + keyserver_url_); + } +} - QUrl keyserver_url = QUrl(keyserver_url_.c_str()); +auto GpgFrontend::UI::KeyServerImportTask::Run() -> int { + QUrl const keyserver_url = QUrl(keyserver_url_); for (const auto& key_id : keyids_) { - QUrl req_url(keyserver_url.scheme() + "://" + keyserver_url.host() + - "/pks/lookup?op=get&search=0x" + key_id.c_str() + - "&options=mr"); + QUrl const req_url(keyserver_url.scheme() + "://" + keyserver_url.host() + + "/pks/lookup?op=get&search=0x" + key_id + "&options=mr"); reply_ = manager_->get(QNetworkRequest(req_url)); - connect(reply_, &QNetworkReply::finished, this, &KeyServerImportTask::dealing_reply_from_server); } + return 0; } void GpgFrontend::UI::KeyServerImportTask::dealing_reply_from_server() { - QByteArray buffer; - QNetworkReply::NetworkError network_reply = reply_->error(); - if (network_reply == QNetworkReply::NoError) { - buffer = reply_->readAll(); + auto const network_reply = reply_->error(); + auto buffer = reply_->readAll(); + + if (network_reply != QNetworkReply::NoError) { + GF_UI_LOG_ERROR("key import error, message from key server reply: ", + buffer); + QString err_msg; + switch (network_reply) { + case QNetworkReply::ContentNotFoundError: + err_msg = tr("Key not found in the Keyserver."); + break; + case QNetworkReply::TimeoutError: + err_msg = tr("Network connection timeout."); + break; + case QNetworkReply::HostNotFoundError: + err_msg = tr("Cannot resolve the address of target key server."); + break; + default: + err_msg = tr("General connection error occurred."); + } + emit SignalKeyServerImportResult(false, err_msg, buffer, nullptr); } - emit SignalKeyServerImportResult(network_reply, buffer); - if (result_count_++ == keyids_.size() - 1) { - emit SignalTaskRunnableEnd(0); + auto info = GpgKeyImportExporter::GetInstance().ImportKey(GFBuffer(buffer)); + emit SignalKeyServerImportResult(true, tr("Success"), buffer, info); + + if (static_cast<size_t>(result_count_++) == keyids_.size() - 1) { + emit SignalTaskShouldEnd(0); } }
\ No newline at end of file diff --git a/src/ui/thread/KeyServerImportTask.h b/src/ui/thread/KeyServerImportTask.h index 7d3b66c6..8797916c 100644 --- a/src/ui/thread/KeyServerImportTask.h +++ b/src/ui/thread/KeyServerImportTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,17 +19,26 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYSERVERIMPORTTASK_H -#define GPGFRONTEND_KEYSERVERIMPORTTASK_H +#pragma once + +#include <qnetworkaccessmanager.h> +#include <qnetworkreply.h> + +#include "core/thread/Task.h" -#include "GpgFrontendUI.h" +namespace GpgFrontend { +class GpgImportInformation; +} namespace GpgFrontend::UI { + class KeyServerImportTask : public Thread::Task { Q_OBJECT public: @@ -39,25 +48,23 @@ class KeyServerImportTask : public Thread::Task { * @param keyserver_url * @param search_string */ - KeyServerImportTask(std::string keyserver_url, - std::vector<std::string> keyid); - - signals: + KeyServerImportTask(QString keyserver_url, std::vector<QString> keyid); /** * @brief * - * @param result */ - void SignalKeyServerImportResult(QNetworkReply::NetworkError reply, - QByteArray buffer); + auto Run() -> int override; + + signals: - protected: /** * @brief * + * @param result */ - void run() override; + void SignalKeyServerImportResult(bool, QString, QByteArray, + std::shared_ptr<GpgImportInformation>); private slots: @@ -68,13 +75,11 @@ class KeyServerImportTask : public Thread::Task { void dealing_reply_from_server(); private: - std::string keyserver_url_; ///< - std::vector<std::string> keyids_; ///< + QString keyserver_url_; ///< + std::vector<QString> keyids_; ///< int result_count_ = 0; QNetworkAccessManager *manager_; ///< QNetworkReply *reply_; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYSERVERIMPORTTASK_H
\ No newline at end of file diff --git a/src/ui/thread/KeyServerSearchTask.cpp b/src/ui/thread/KeyServerSearchTask.cpp index 863a4ca3..2f05b774 100644 --- a/src/ui/thread/KeyServerSearchTask.cpp +++ b/src/ui/thread/KeyServerSearchTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,34 +19,34 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "ui/thread/KeyServerSearchTask.h" -#include <utility> - -GpgFrontend::UI::KeyServerSearchTask::KeyServerSearchTask( - std::string keyserver_url, std::string search_string) +GpgFrontend::UI::KeyServerSearchTask::KeyServerSearchTask(QString keyserver_url, + QString search_string) : Task("key_server_search_task"), keyserver_url_(std::move(keyserver_url)), search_string_(std::move(search_string)), - manager_(new QNetworkAccessManager(this)) {} - -void GpgFrontend::UI::KeyServerSearchTask::run() { - SetFinishAfterRun(false); + manager_(new QNetworkAccessManager(this)) { + HoldOnLifeCycle(true); +} - QUrl url_from_remote = - QString::fromStdString(keyserver_url_) + - "/pks/lookup?search=" + QString::fromStdString(search_string_) + - "&op=index&options=mr"; +auto GpgFrontend::UI::KeyServerSearchTask::Run() -> int { + QUrl url_from_remote = keyserver_url_ + + "/pks/lookup?search=" + search_string_ + + "&op=index&options=mr"; reply_ = manager_->get(QNetworkRequest(url_from_remote)); - connect(reply_, &QNetworkReply::finished, this, &KeyServerSearchTask::dealing_reply_from_server); + + return 0; } void GpgFrontend::UI::KeyServerSearchTask::dealing_reply_from_server() { @@ -56,5 +56,5 @@ void GpgFrontend::UI::KeyServerSearchTask::dealing_reply_from_server() { buffer = reply_->readAll(); } emit SignalKeyServerSearchResult(network_reply, buffer); - emit SignalTaskRunnableEnd(0); + emit SignalTaskShouldEnd(0); } diff --git a/src/ui/thread/KeyServerSearchTask.h b/src/ui/thread/KeyServerSearchTask.h index 3333e949..cdce944d 100644 --- a/src/ui/thread/KeyServerSearchTask.h +++ b/src/ui/thread/KeyServerSearchTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,18 +19,22 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_KEYSERVERSEARCHTASK_H -#define GPGFRONTEND_KEYSERVERSEARCHTASK_H +#pragma once + +#include <qnetworkaccessmanager.h> +#include <qnetworkreply.h> #include "GpgFrontendUI.h" +#include "core/thread/ThreadingModel.h" namespace GpgFrontend::UI { - class KeyServerSearchTask : public Thread::Task { Q_OBJECT public: @@ -40,37 +44,34 @@ class KeyServerSearchTask : public Thread::Task { * @param keyserver_url * @param search_string */ - KeyServerSearchTask(std::string keyserver_url, std::string search_string); - - signals: + KeyServerSearchTask(QString keyserver_url, QString search_string); /** * @brief * - * @param result */ - void SignalKeyServerSearchResult(QNetworkReply::NetworkError reply, - QByteArray buffer); + auto Run() -> int override; + + signals: - protected: /** * @brief * + * @param result */ - void run() override; + void SignalKeyServerSearchResult(QNetworkReply::NetworkError reply, + QByteArray buffer); private slots: void dealing_reply_from_server(); private: - std::string keyserver_url_; ///< - std::string search_string_; ///< + QString keyserver_url_; ///< + QString search_string_; ///< QNetworkAccessManager *manager_; ///< QNetworkReply *reply_; ///< }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_KEYSERVERSEARCHTASK_H
\ No newline at end of file diff --git a/src/ui/thread/ListedKeyServerTestTask.cpp b/src/ui/thread/ListedKeyServerTestTask.cpp index 914cd3d6..4ab7ba5f 100644 --- a/src/ui/thread/ListedKeyServerTestTask.cpp +++ b/src/ui/thread/ListedKeyServerTestTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,46 +19,48 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "ListedKeyServerTestTask.h" +#include <QtNetwork> #include <vector> GpgFrontend::UI::ListedKeyServerTestTask::ListedKeyServerTestTask( - const QStringList& urls, int timeout, QWidget* parent) + QStringList urls, int timeout, QWidget* /*parent*/) : Task("listed_key_server_test_task"), - urls_(urls), - timeout_(timeout), + urls_(std::move(urls)), + result_(urls_.size(), kTEST_RESULT_TYPE_ERROR), network_manager_(new QNetworkAccessManager(this)), - result_(urls_.size(), kTestResultType_Error) { + timeout_(timeout) { + HoldOnLifeCycle(true); qRegisterMetaType<std::vector<KeyServerTestResultType>>( "std::vector<KeyServerTestResultType>"); } -void GpgFrontend::UI::ListedKeyServerTestTask::run() { - SetFinishAfterRun(false); - +auto GpgFrontend::UI::ListedKeyServerTestTask::Run() -> int { size_t index = 0; for (const auto& url : urls_) { auto key_url = QUrl{url}; - SPDLOG_DEBUG("key server request: {}", key_url.host().toStdString()); + GF_UI_LOG_DEBUG("key server request: {}", key_url.host().toStdString()); auto* network_reply = network_manager_->get(QNetworkRequest{key_url}); auto* timer = new QTimer(this); connect(network_reply, &QNetworkReply::finished, this, [this, index, network_reply]() { - SPDLOG_DEBUG("key server domain reply: {}", - urls_[index].toStdString()); + GF_UI_LOG_DEBUG("key server domain reply: {}", + urls_[index].toStdString()); this->slot_process_network_reply(index, network_reply); }); connect(timer, &QTimer::timeout, this, [this, index, network_reply]() { - SPDLOG_DEBUG("timeout for key server: {}", urls_[index].toStdString()); + GF_UI_LOG_DEBUG("timeout for key server: {}", urls_[index].toStdString()); if (network_reply->isRunning()) { network_reply->abort(); this->slot_process_network_reply(index, network_reply); @@ -66,24 +68,26 @@ void GpgFrontend::UI::ListedKeyServerTestTask::run() { }); timer->start(timeout_); - index++; } + + return 0; } void GpgFrontend::UI::ListedKeyServerTestTask::slot_process_network_reply( int index, QNetworkReply* reply) { if (!reply->isRunning() && reply->error() == QNetworkReply::NoError) { - result_[index] = kTestResultType_Success; + result_[index] = kTEST_RESULT_TYPE_SUCCESS; } else { - if (!reply->isFinished()) - result_[index] = kTestResultType_Timeout; - else - result_[index] = kTestResultType_Error; + if (!reply->isFinished()) { + result_[index] = kTEST_RESULT_TYPE_TIMEOUT; + } else { + result_[index] = kTEST_RESULT_TYPE_ERROR; + } } if (++result_count_ == urls_.size()) { emit SignalKeyServerListTestResult(result_); - emit SignalTaskRunnableEnd(0); + emit SignalTaskShouldEnd(0); } } diff --git a/src/ui/thread/ListedKeyServerTestTask.h b/src/ui/thread/ListedKeyServerTestTask.h index aa1bac5e..fdd036d4 100644 --- a/src/ui/thread/ListedKeyServerTestTask.h +++ b/src/ui/thread/ListedKeyServerTestTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,21 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_LISTEDKEYSERVERTESTTHREAD_H -#define GPGFRONTEND_LISTEDKEYSERVERTESTTHREAD_H +#pragma once #include "GpgFrontendUI.h" +#include "core/thread/ThreadingModel.h" + +class QNetworkAccessManager; +class QNetworkReply; + namespace GpgFrontend::UI { /** @@ -38,29 +44,28 @@ class ListedKeyServerTestTask : public Thread::Task { Q_OBJECT public: enum KeyServerTestResultType { - kTestResultType_Success, - kTestResultType_Timeout, - kTestResultType_Error, + kTEST_RESULT_TYPE_SUCCESS, + kTEST_RESULT_TYPE_TIMEOUT, + kTEST_RESULT_TYPE_ERROR, }; - explicit ListedKeyServerTestTask(const QStringList& urls, int timeout, + explicit ListedKeyServerTestTask(QStringList urls, int timeout, QWidget* parent = nullptr); - signals: /** * @brief * - * @param result */ - void SignalKeyServerListTestResult( - std::vector<KeyServerTestResultType> result); + auto Run() -> int override; - protected: + signals: /** * @brief * + * @param result */ - void run() override; + void SignalKeyServerListTestResult( + std::vector<KeyServerTestResultType> result); private: QStringList urls_; ///< @@ -81,5 +86,3 @@ class ListedKeyServerTestTask : public Thread::Task { } // namespace GpgFrontend::UI class TestListedKeyServerThread {}; - -#endif // GPGFRONTEND_LISTEDKEYSERVERTESTTHREAD_H diff --git a/src/ui/thread/ProxyConnectionTestTask.cpp b/src/ui/thread/ProxyConnectionTestTask.cpp index c7d623d7..6b0993fe 100644 --- a/src/ui/thread/ProxyConnectionTestTask.cpp +++ b/src/ui/thread/ProxyConnectionTestTask.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,35 +19,39 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "ProxyConnectionTestTask.h" +#include <QtNetwork> + GpgFrontend::UI::ProxyConnectionTestTask::ProxyConnectionTestTask(QString url, int timeout) : Task("proxy_connection_test_task"), url_(std::move(url)), timeout_(timeout), - network_manager_(new QNetworkAccessManager(this)) {} - -void GpgFrontend::UI::ProxyConnectionTestTask::run() { - SetFinishAfterRun(false); + network_manager_(new QNetworkAccessManager(this)) { + HoldOnLifeCycle(true); +} +auto GpgFrontend::UI::ProxyConnectionTestTask::Run() -> int { auto* network_reply = network_manager_->get(QNetworkRequest{url_}); auto* timer = new QTimer(this); connect(network_reply, &QNetworkReply::finished, this, [this, network_reply]() { - SPDLOG_DEBUG("key server domain reply: {} received", - url_.toStdString()); + GF_UI_LOG_DEBUG("key server domain reply: {} received", + url_.toStdString()); this->slot_process_network_reply(network_reply); }); connect(timer, &QTimer::timeout, this, [this, network_reply]() { - SPDLOG_DEBUG("timeout for key server: {}", url_.toStdString()); + GF_UI_LOG_DEBUG("timeout for key server: {}", url_.toStdString()); if (network_reply->isRunning()) { network_reply->abort(); this->slot_process_network_reply(network_reply); @@ -55,13 +59,14 @@ void GpgFrontend::UI::ProxyConnectionTestTask::run() { }); timer->start(timeout_); + return 0; } void GpgFrontend::UI::ProxyConnectionTestTask::slot_process_network_reply( QNetworkReply* reply) { auto buffer = reply->readAll(); - SPDLOG_DEBUG("key server domain reply: {}, buffer size: {}", - url_.toStdString(), buffer.size()); + GF_UI_LOG_DEBUG("key server domain reply: {}, buffer size: {}", + url_.toStdString(), buffer.size()); if (reply->error() == QNetworkReply::NoError && !buffer.isEmpty()) { result_ = "Reachable"; @@ -70,5 +75,5 @@ void GpgFrontend::UI::ProxyConnectionTestTask::slot_process_network_reply( } emit SignalProxyConnectionTestResult(result_); - emit SignalTaskRunnableEnd(0); + emit SignalTaskShouldEnd(0); } diff --git a/src/ui/thread/ProxyConnectionTestTask.h b/src/ui/thread/ProxyConnectionTestTask.h index 38e78ae4..c15f45bc 100644 --- a/src/ui/thread/ProxyConnectionTestTask.h +++ b/src/ui/thread/ProxyConnectionTestTask.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,19 +19,20 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H -#define GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H - -class ProxyConnectionTestThread {}; - -#include <utility> +#pragma once #include "GpgFrontendUI.h" +#include "core/thread/ThreadingModel.h" + +class QNetworkAccessManager; +class QNetworkReply; namespace GpgFrontend::UI { @@ -51,6 +52,12 @@ class ProxyConnectionTestTask : public Thread::Task { */ explicit ProxyConnectionTestTask(QString url, int timeout); + /** + * @brief + * + */ + auto Run() -> int override; + signals: /** * @brief @@ -59,14 +66,13 @@ class ProxyConnectionTestTask : public Thread::Task { */ void SignalProxyConnectionTestResult(const QString& result); - protected: + private slots: + /** * @brief * + * @param reply */ - void run() override; - - private slots: void slot_process_network_reply(QNetworkReply* reply); private: @@ -77,5 +83,3 @@ class ProxyConnectionTestTask : public Thread::Task { }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H diff --git a/src/ui/thread/VersionCheckTask.cpp b/src/ui/thread/VersionCheckTask.cpp deleted file mode 100644 index e9490e1c..00000000 --- a/src/ui/thread/VersionCheckTask.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Copyright (C) 2021 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend 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 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "VersionCheckTask.h" - -#include <QMetaType> -#include <memory> - -#include "GpgFrontendBuildInfo.h" - -namespace GpgFrontend::UI { - -VersionCheckTask::VersionCheckTask() - : Task("version_check_task"), - network_manager_(new QNetworkAccessManager(this)), - current_version_(std::string("v") + std::to_string(VERSION_MAJOR) + "." + - std::to_string(VERSION_MINOR) + "." + - std::to_string(VERSION_PATCH)) { - qRegisterMetaType<SoftwareVersion>("SoftwareVersion"); - version_.current_version = current_version_; -} - -void VersionCheckTask::Run() { - SetFinishAfterRun(false); - - try { - using namespace nlohmann; - SPDLOG_DEBUG("current version: {}", current_version_); - std::string latest_version_url = - "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; - - QNetworkRequest latest_request; - latest_request.setUrl(QUrl(latest_version_url.c_str())); - latest_reply_ = network_manager_->get(latest_request); - connect(latest_reply_, &QNetworkReply::finished, this, - &VersionCheckTask::slot_parse_latest_version_info); - - // loading done - version_.load_info_done = true; - - } catch (...) { - SPDLOG_ERROR("unknown error occurred"); - emit SignalTaskRunnableEnd(-1); - } -} - -void VersionCheckTask::slot_parse_latest_version_info() { - version_.current_version = current_version_; - - try { - if (latest_reply_ == nullptr || - latest_reply_->error() != QNetworkReply::NoError) { - SPDLOG_ERROR("latest version request error"); - version_.latest_version = current_version_; - } else { - latest_reply_bytes_ = latest_reply_->readAll(); - - auto latest_reply_json = - nlohmann::json::parse(latest_reply_bytes_.toStdString()); - - std::string latest_version = latest_reply_json["tag_name"]; - - SPDLOG_INFO("latest version from Github: {}", latest_version); - - QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); - auto version_match = re.match(latest_version.c_str()); - if (version_match.hasMatch()) { - latest_version = version_match.captured(0).toStdString(); - SPDLOG_DEBUG("latest version matched: {}", latest_version); - } else { - latest_version = current_version_; - SPDLOG_WARN("latest version unknown"); - } - - bool prerelease = latest_reply_json["prerelease"], - draft = latest_reply_json["draft"]; - std::string publish_date = latest_reply_json["published_at"]; - std::string release_note = latest_reply_json["body"]; - version_.latest_version = latest_version; - version_.latest_prerelease = prerelease; - version_.latest_draft = draft; - version_.publish_date = publish_date; - version_.release_note = release_note; - } - } catch (...) { - SPDLOG_ERROR("unknown error occurred"); - version_.load_info_done = false; - } - - if (latest_reply_ != nullptr) { - latest_reply_->deleteLater(); - } - - try { - std::string current_version_url = - "https://api.github.com/repos/saturneric/gpgfrontend/releases/tags/" + - current_version_; - - QNetworkRequest current_request; - current_request.setUrl(QUrl(current_version_url.c_str())); - current_reply_ = network_manager_->get(current_request); - - connect(current_reply_, &QNetworkReply::finished, this, - &VersionCheckTask::slot_parse_current_version_info); - } catch (...) { - SPDLOG_ERROR("current version request create error"); - emit SignalTaskRunnableEnd(-1); - } -} - -void VersionCheckTask::slot_parse_current_version_info() { - try { - if (current_reply_ == nullptr || - current_reply_->error() != QNetworkReply::NoError) { - if (current_reply_ != nullptr) { - SPDLOG_ERROR("current version request network error: {}", - current_reply_->errorString().toStdString()); - } else { - SPDLOG_ERROR( - "current version request network error, null reply object"); - } - - version_.current_version_found = false; - version_.load_info_done = false; - } else { - version_.current_version_found = true; - current_reply_bytes_ = current_reply_->readAll(); - SPDLOG_DEBUG("current version: {}", current_reply_bytes_.size()); - auto current_reply_json = - nlohmann::json::parse(current_reply_bytes_.toStdString()); - bool current_prerelease = current_reply_json["prerelease"], - current_draft = current_reply_json["draft"]; - version_.latest_prerelease = current_prerelease; - version_.latest_draft = current_draft; - version_.load_info_done = true; - } - } catch (...) { - SPDLOG_ERROR("unknown error occurred"); - version_.load_info_done = false; - } - - SPDLOG_DEBUG("current version parse done: {}", - version_.current_version_found); - - if (current_reply_ != nullptr) { - current_reply_->deleteLater(); - } - - emit SignalUpgradeVersion(version_); - emit SignalTaskRunnableEnd(0); -} - -} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index b5243da0..27f4205f 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,40 +28,29 @@ #include "ui/widgets/FilePage.h" -#include <string> - -#include "core/function/ArchiveFileOperator.h" -#include "core/function/gpg/GpgFileOpera.h" -#include "ui/SignalStation.h" +#include "core/GpgModel.h" +#include "ui/UISignalStation.h" #include "ui/main_window/MainWindow.h" #include "ui_FilePage.h" namespace GpgFrontend::UI { -FilePage::FilePage(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_FilePage>()) { +FilePage::FilePage(QWidget* parent, const QString& target_path) + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_FilePage>()), + file_tree_view_(new FileTreeView(this, target_path)) { ui_->setupUi(this); + ui_->trewViewLayout->addWidget(file_tree_view_); - first_parent_ = parent; - - dir_model_ = new QFileSystemModel(); - dir_model_->setRootPath(QDir::currentPath()); - dir_model_->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - - ui_->fileTreeView->setModel(dir_model_); - ui_->fileTreeView->setColumnWidth(0, 320); - ui_->fileTreeView->sortByColumn(0, Qt::AscendingOrder); - m_path_ = std::filesystem::path(dir_model_->rootPath().toStdString()); - - create_popup_menu(); - - connect(ui_->upPathButton, &QPushButton::clicked, this, - &FilePage::slot_up_level); + connect(ui_->upPathButton, &QPushButton::clicked, file_tree_view_, + &FileTreeView::SlotUpLevel); connect(ui_->refreshButton, &QPushButton::clicked, this, &FilePage::SlotGoPath); - ui_->optionsButton->setMenu(option_popup_menu_); + connect(this->ui_->newDirButton, &QPushButton::clicked, file_tree_view_, + &FileTreeView::SlotMkdir); - ui_->pathEdit->setText(dir_model_->rootPath()); + ui_->pathEdit->setText( + QString::fromStdString(file_tree_view_->GetCurrentPath().u8string())); path_edit_completer_ = new QCompleter(this); path_complete_model_ = new QStringListModel(); @@ -71,12 +60,19 @@ FilePage::FilePage(QWidget* parent) QCompleter::UnfilteredPopupCompletion); ui_->pathEdit->setCompleter(path_edit_completer_); - connect(ui_->fileTreeView, &QTreeView::clicked, this, - &FilePage::slot_file_tree_view_item_clicked); - connect(ui_->fileTreeView, &QTreeView::doubleClicked, this, - &FilePage::slot_file_tree_view_item_double_clicked); - connect(ui_->fileTreeView, &QTreeView::customContextMenuRequested, this, - &FilePage::onCustomContextMenu); + option_popup_menu_ = new QMenu(this); + auto* show_hidden_act = new QAction(tr("Show Hidden File"), this); + show_hidden_act->setCheckable(true); + connect(show_hidden_act, &QAction::triggered, file_tree_view_, + &FileTreeView::SlotShowHiddenFile); + option_popup_menu_->addAction(show_hidden_act); + + auto* show_system_act = new QAction(tr("Show System File"), this); + show_system_act->setCheckable(true); + connect(show_system_act, &QAction::triggered, file_tree_view_, + &FileTreeView::SlotShowSystemFile); + option_popup_menu_->addAction(show_system_act); + ui_->optionsButton->setMenu(option_popup_menu_); connect(ui_->pathEdit, &QLineEdit::textChanged, [=]() { auto path = ui_->pathEdit->text(); @@ -94,387 +90,84 @@ FilePage::FilePage(QWidget* parent) } }); - connect(this, &FilePage::SignalRefreshInfoBoard, SignalStation::GetInstance(), - &SignalStation::SignalRefreshInfoBoard); -} - -void FilePage::slot_file_tree_view_item_clicked(const QModelIndex& index) { -#ifdef WINDOWS - selected_path_ = std::filesystem::path( - dir_model_->fileInfo(index).absoluteFilePath().toStdU16String()); -#else - selected_path_ = std::filesystem::path( - dir_model_->fileInfo(index).absoluteFilePath().toStdString()); -#endif - - m_path_ = selected_path_; - SPDLOG_DEBUG("selected path: {}", selected_path_.u8string()); - - selected_path_ = std::filesystem::path(selected_path_); - MainWindow::CryptoMenu::OperationType operation_type = - MainWindow::CryptoMenu::None; - - if (index.isValid()) { - QFileInfo info(QString::fromStdString(selected_path_.u8string())); - - if ((info.isDir() || info.isFile()) && - (info.suffix() != "gpg" && info.suffix() != "pgp" && - info.suffix() != "sig" && info.suffix() != "asc")) { - operation_type |= MainWindow::CryptoMenu::Encrypt; - } - - if ((info.isDir() || info.isFile()) && - (info.suffix() != "gpg" && info.suffix() != "pgp" && - info.suffix() != "sig" && info.suffix() != "asc")) { - operation_type |= MainWindow::CryptoMenu::EncryptAndSign; - } - - if (info.isFile() && (info.suffix() == "gpg" || info.suffix() == "pgp" || - info.suffix() == "asc")) { - operation_type |= MainWindow::CryptoMenu::Decrypt; - operation_type |= MainWindow::CryptoMenu::DecryptAndVerify; - } - - if (info.isFile() && (info.suffix() != "gpg" && info.suffix() != "pgp" && - info.suffix() != "sig" && info.suffix() != "asc")) { - operation_type |= MainWindow::CryptoMenu::Sign; - } - - if (info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg" || - info.suffix() == "pgp" || info.suffix() == "asc")) { - operation_type |= MainWindow::CryptoMenu::Verify; - } - } - - auto main_window = qobject_cast<MainWindow*>(first_parent_); - if (main_window != nullptr) main_window->SetCryptoMenuStatus(operation_type); -} - -void FilePage::slot_up_level() { - QModelIndex currentRoot = ui_->fileTreeView->rootIndex(); -#ifdef WINDOWS - auto str_path = - dir_model_->fileInfo(currentRoot).absoluteFilePath().toStdU16String(); -#else - auto str_path = dir_model_->fileInfo(currentRoot) - .absoluteFilePath() - .toUtf8() - .toStdString(); -#endif - std::filesystem::path path_obj(str_path); - - m_path_ = path_obj; - SPDLOG_DEBUG("get path: {}", m_path_.u8string()); - if (m_path_.has_parent_path() && !m_path_.parent_path().empty()) { - m_path_ = m_path_.parent_path(); - SPDLOG_DEBUG("parent path: {}", m_path_.u8string()); - ui_->pathEdit->setText(m_path_.u8string().c_str()); - this->SlotGoPath(); - } -} - -void FilePage::slot_file_tree_view_item_double_clicked( - const QModelIndex& index) { - QFileInfo file_info(dir_model_->fileInfo(index).absoluteFilePath()); - if (file_info.isFile()) { - slot_open_item(); - } else { - ui_->pathEdit->setText(file_info.filePath()); - SlotGoPath(); + connect(this, &FilePage::SignalRefreshInfoBoard, + UISignalStation::GetInstance(), + &UISignalStation::SignalRefreshInfoBoard); + connect(file_tree_view_, &FileTreeView::SignalPathChanged, this, + [this](const QString& path) { this->ui_->pathEdit->setText(path); }); + connect(file_tree_view_, &FileTreeView::SignalPathChanged, this, + &FilePage::SignalPathChanged); + + auto* main_window = qobject_cast<MainWindow*>(this->parent()); + if (main_window != nullptr) { + connect(file_tree_view_, &FileTreeView::SignalOpenFile, main_window, + &MainWindow::SlotOpenFile); + + connect(file_tree_view_, &FileTreeView::SignalSelectedChanged, this, + [main_window](const QString& selected_path) { + MainWindow::CryptoMenu::OperationType operation_type = + MainWindow::CryptoMenu::None; + + // abort... + if (selected_path.isEmpty()) return; + + QFileInfo const info(selected_path); + + if ((info.isDir() || info.isFile()) && + (info.suffix() != "gpg" && info.suffix() != "pgp" && + info.suffix() != "sig" && info.suffix() != "asc")) { + operation_type |= MainWindow::CryptoMenu::Encrypt; + } + + if ((info.isDir() || info.isFile()) && + (info.suffix() != "gpg" && info.suffix() != "pgp" && + info.suffix() != "sig" && info.suffix() != "asc")) { + operation_type |= MainWindow::CryptoMenu::EncryptAndSign; + } + + if (info.isFile() && + (info.suffix() == "gpg" || info.suffix() == "pgp" || + info.suffix() == "asc")) { + operation_type |= MainWindow::CryptoMenu::Decrypt; + operation_type |= MainWindow::CryptoMenu::DecryptAndVerify; + } + + if (info.isFile() && + (info.suffix() != "gpg" && info.suffix() != "pgp" && + info.suffix() != "sig" && info.suffix() != "asc")) { + operation_type |= MainWindow::CryptoMenu::Sign; + } + + if (info.isFile() && + (info.suffix() == "sig" || info.suffix() == "gpg" || + info.suffix() == "pgp" || info.suffix() == "asc")) { + operation_type |= MainWindow::CryptoMenu::Verify; + } + + main_window->SetCryptoMenuStatus(operation_type); + }); } } -QString FilePage::GetSelected() const { - return QString::fromStdString(selected_path_.u8string()); +auto FilePage::GetSelected() const -> QString { + return QString::fromStdString(file_tree_view_->GetSelectedPath().string()); } void FilePage::SlotGoPath() { #ifdef WINDOWS - std::filesystem::path path_edit_obj(ui_->pathEdit->text().toStdU16String()); + std::filesystem::path target_path(ui_->pathEdit->text().toStdU16String()); #else - std::filesystem::path path_edit_obj(ui_->pathEdit->text().toStdString()); + std::filesystem::path target_path(ui_->pathEdit->text().toStdString()); #endif - - m_path_ = m_path_ != path_edit_obj ? path_edit_obj : m_path_; - auto fileInfo = QFileInfo(m_path_.string().c_str()); - if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) { -#ifdef WINDOWS - m_path_ = std::filesystem::path(fileInfo.filePath().toStdU16String()); -#else - m_path_ = std::filesystem::path(fileInfo.filePath().toStdString()); -#endif - - SPDLOG_DEBUG("set path: {}", m_path_.u8string()); - ui_->fileTreeView->setRootIndex(dir_model_->index(fileInfo.filePath())); - dir_model_->setRootPath(fileInfo.filePath()); - for (int i = 1; i < dir_model_->columnCount(); ++i) { - ui_->fileTreeView->resizeColumnToContents(i); - } - ui_->pathEdit->setText(QString::fromStdString(m_path_.u8string())); - } else { - QMessageBox::critical( - this, _("Error"), - _("The path is not exists, unprivileged or unreachable.")); - } - emit SignalPathChanged(QString::fromStdString(m_path_.u8string())); -} - -void FilePage::create_popup_menu() { - popup_menu_ = new QMenu(); - - ui_->actionOpenFile->setText(_("Open")); - connect(ui_->actionOpenFile, &QAction::triggered, this, - &FilePage::slot_open_item); - ui_->actionRenameFile->setText(_("Rename")); - connect(ui_->actionRenameFile, &QAction::triggered, this, - &FilePage::slot_rename_item); - ui_->actionDeleteFile->setText(_("Delete")); - connect(ui_->actionDeleteFile, &QAction::triggered, this, - &FilePage::slot_delete_item); - - ui_->actionCalculateHash->setText(_("Calculate Hash")); - connect(ui_->actionCalculateHash, &QAction::triggered, this, - &FilePage::slot_calculate_hash); - - ui_->actionMakeDirectory->setText(_("Directory")); - connect(ui_->actionMakeDirectory, &QAction::triggered, this, - &FilePage::slot_mkdir); - - ui_->actionCreateEmptyFile->setText(_("File")); - connect(ui_->actionCreateEmptyFile, &QAction::triggered, this, - &FilePage::slot_create_empty_file); - - ui_->actionCompressFiles->setText(_("Compress...")); - ui_->actionCompressFiles->setVisible(false); - connect(ui_->actionCompressFiles, &QAction::triggered, this, - &FilePage::slot_compress_files); - - ui_->actionOpenWithSystemDefaultApplication->setText( - _("Open with Default System Application")); - connect(ui_->actionOpenWithSystemDefaultApplication, &QAction::triggered, - this, &FilePage::slot_open_item_by_system_application); - - auto new_item_action_menu = new QMenu(this); - new_item_action_menu->setTitle(_("New")); - new_item_action_menu->addAction(ui_->actionCreateEmptyFile); - new_item_action_menu->addAction(ui_->actionMakeDirectory); - - popup_menu_->addAction(ui_->actionOpenFile); - popup_menu_->addAction(ui_->actionOpenWithSystemDefaultApplication); - - popup_menu_->addSeparator(); - popup_menu_->addMenu(new_item_action_menu); - popup_menu_->addSeparator(); - - popup_menu_->addAction(ui_->actionRenameFile); - popup_menu_->addAction(ui_->actionDeleteFile); - popup_menu_->addAction(ui_->actionCompressFiles); - popup_menu_->addAction(ui_->actionCalculateHash); - - option_popup_menu_ = new QMenu(); - - auto showHiddenAct = new QAction(_("Show Hidden File"), this); - showHiddenAct->setCheckable(true); - connect(showHiddenAct, &QAction::triggered, this, [&](bool checked) { - SPDLOG_DEBUG("set hidden: {}", checked); - if (checked) - dir_model_->setFilter(dir_model_->filter() | QDir::Hidden); - else - dir_model_->setFilter(dir_model_->filter() & ~QDir::Hidden); - dir_model_->setRootPath(m_path_.u8string().c_str()); - }); - option_popup_menu_->addAction(showHiddenAct); - - auto showSystemAct = new QAction(_("Show System File"), this); - showSystemAct->setCheckable(true); - connect(showSystemAct, &QAction::triggered, this, [&](bool checked) { - SPDLOG_DEBUG("set hidden: {}", checked); - if (checked) - dir_model_->setFilter(dir_model_->filter() | QDir::System); - else - dir_model_->setFilter(dir_model_->filter() & ~QDir::System); - dir_model_->setRootPath(m_path_.u8string().c_str()); - }); - option_popup_menu_->addAction(showSystemAct); -} - -void FilePage::onCustomContextMenu(const QPoint& point) { - QModelIndex index = ui_->fileTreeView->indexAt(point); - SPDLOG_DEBUG("right click: {}", selected_path_.u8string()); - -#ifdef WINDOWS - auto index_dir_str = - dir_model_->fileInfo(index).absoluteFilePath().toStdU16String(); -#else - auto index_dir_str = - dir_model_->fileInfo(index).absoluteFilePath().toStdString(); -#endif - - selected_path_ = std::filesystem::path(index_dir_str); - - // update crypt menu - slot_file_tree_view_item_clicked(index); - - if (index.isValid()) { - ui_->actionOpenFile->setEnabled(true); - ui_->actionRenameFile->setEnabled(true); - ui_->actionDeleteFile->setEnabled(true); - - QFileInfo info(QString::fromStdString(selected_path_.u8string())); - ui_->actionCalculateHash->setEnabled(info.isFile() && info.isReadable()); - } else { - ui_->actionOpenFile->setEnabled(false); - ui_->actionRenameFile->setEnabled(false); - ui_->actionDeleteFile->setEnabled(false); - - ui_->actionCalculateHash->setEnabled(false); - } - popup_menu_->exec(ui_->fileTreeView->viewport()->mapToGlobal(point)); -} - -void FilePage::slot_open_item() { - QFileInfo info(QString::fromStdString(selected_path_.u8string())); - if (info.isDir()) { - if (info.isReadable() && info.isExecutable()) { - const auto file_path = info.filePath().toUtf8().toStdString(); - SPDLOG_DEBUG("set path: {}", file_path); - ui_->pathEdit->setText(info.filePath().toUtf8()); - SlotGoPath(); - } else { - QMessageBox::critical(this, _("Error"), - _("The directory is unprivileged or unreachable.")); - } - } else { - if (info.isReadable()) { - // handle normal text or binary file - auto main_window = qobject_cast<MainWindow*>(first_parent_); - auto qt_open_path = QString::fromStdString(selected_path_.u8string()); - SPDLOG_DEBUG("open item: {}", qt_open_path.toStdString()); - if (main_window != nullptr) main_window->SlotOpenFile(qt_open_path); - } else { - QMessageBox::critical(this, _("Error"), - _("The file is unprivileged or unreachable.")); - } - } -} - -void FilePage::slot_open_item_by_system_application() { - QFileInfo info(QString::fromStdString(selected_path_.u8string())); - auto q_selected_path = QString::fromStdString(selected_path_.u8string()); - if (info.isDir()) { - const auto file_path = info.filePath().toUtf8().toStdString(); - QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path)); - - } else { - QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path)); - } -} - -void FilePage::slot_rename_item() { - auto new_name_path = selected_path_, old_name_path = selected_path_; - auto old_name = old_name_path.filename(); - new_name_path = new_name_path.remove_filename(); - - bool ok; - auto text = QInputDialog::getText( - this, _("Rename"), _("New Filename"), QLineEdit::Normal, - QString::fromStdString(old_name.u8string()), &ok); - if (ok && !text.isEmpty()) { - try { -#ifdef WINDOWS - new_name_path /= text.toStdU16String(); -#else - new_name_path /= text.toStdString(); -#endif - SPDLOG_DEBUG("new name path: {}", new_name_path.u8string()); - std::filesystem::rename(old_name_path, new_name_path); - // refresh - this->SlotGoPath(); - } catch (...) { - SPDLOG_ERROR("rename error: {}", new_name_path.u8string()); - QMessageBox::critical(this, _("Error"), - _("Unable to rename the file or folder.")); - } - } -} - -void FilePage::slot_delete_item() { - QModelIndex index = ui_->fileTreeView->currentIndex(); - QVariant data = ui_->fileTreeView->model()->data(index); - - auto ret = QMessageBox::warning(this, _("Warning"), - _("Are you sure you want to delete it?"), - QMessageBox::Ok | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) return; - - SPDLOG_DEBUG("delete item: {}", data.toString().toStdString()); - - if (!dir_model_->remove(index)) { - QMessageBox::critical(this, _("Error"), - _("Unable to delete the file or folder.")); - } -} - -void FilePage::slot_calculate_hash() { - auto info_str = FileOperator::CalculateHash(selected_path_); - emit SignalRefreshInfoBoard(info_str.c_str(), InfoBoardStatus::INFO_ERROR_OK); -} - -void FilePage::slot_mkdir() { - auto index = ui_->fileTreeView->rootIndex(); - - QString new_dir_name; - bool ok; - new_dir_name = - QInputDialog::getText(this, _("Make New Directory"), _("Directory Name"), - QLineEdit::Normal, new_dir_name, &ok); - if (ok && !new_dir_name.isEmpty()) { - dir_model_->mkdir(index, new_dir_name); - } -} - -void FilePage::slot_create_empty_file() { -#ifdef WINDOWS - auto root_path_str = dir_model_->rootPath().toStdU16String(); -#else - auto root_path_str = dir_model_->rootPath().toStdString(); -#endif - std::filesystem::path root_path(root_path_str); - - QString new_file_name; - bool ok; - new_file_name = QInputDialog::getText(this, _("Create Empty File"), - _("Filename (you can given extension)"), - QLineEdit::Normal, new_file_name, &ok); - if (ok && !new_file_name.isEmpty()) { -#ifdef WINDOWS - auto file_path = root_path / new_file_name.toStdU16String(); -#else - auto file_path = root_path / new_file_name.toStdString(); -#endif - QFile new_file(file_path.u8string().c_str()); - if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) { - QMessageBox::critical(this, _("Error"), _("Unable to create the file.")); - } - new_file.close(); - } + file_tree_view_->SlotGoPath(target_path); } void FilePage::keyPressEvent(QKeyEvent* event) { - SPDLOG_DEBUG("key press: {}", event->key()); + GF_UI_LOG_DEBUG("file page notices key press by user: {}", event->key()); if (ui_->pathEdit->hasFocus() && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { SlotGoPath(); - } else if (ui_->fileTreeView->currentIndex().isValid()) { - if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) - slot_open_item(); - else if (event->key() == Qt::Key_Delete || - event->key() == Qt::Key_Backspace) - slot_delete_item(); } } -void FilePage::slot_compress_files() {} - } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h index 74548b13..da5370a2 100644 --- a/src/ui/widgets/FilePage.h +++ b/src/ui/widgets/FilePage.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,16 +20,16 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_FILEPAGE_H -#define GPGFRONTEND_FILEPAGE_H +#pragma once #include "ui/GpgFrontendUI.h" +#include "ui/widgets/FileTreeView.h" #include "ui/widgets/InfoBoardWidget.h" class Ui_FilePage; @@ -48,14 +48,14 @@ class FilePage : public QWidget { * * @param parent */ - explicit FilePage(QWidget* parent = nullptr); + explicit FilePage(QWidget* parent, const QString&); /** * @brief Get the Selected object * * @return QString */ - [[nodiscard]] QString GetSelected() const; + [[nodiscard]] auto GetSelected() const -> QString; public slots: /** @@ -82,76 +82,6 @@ class FilePage : public QWidget { void SignalRefreshInfoBoard(const QString& text, InfoBoardStatus verify_label_status); - private slots: - - /** - * @brief - * - * @param index - */ - void slot_file_tree_view_item_clicked(const QModelIndex& index); - - /** - * @brief - * - * @param index - */ - void slot_file_tree_view_item_double_clicked(const QModelIndex& index); - - /** - * @brief - * - */ - void slot_up_level(); - - /** - * @brief - * - */ - void slot_open_item(); - - /** - * @brief - * - */ - void slot_open_item_by_system_application(); - - /** - * @brief - * - */ - void slot_rename_item(); - - /** - * @brief - * - */ - void slot_delete_item(); - - /** - * @brief - * - */ - void slot_calculate_hash(); - - /** - * @brief - * - */ - void slot_mkdir(); - - /** - * @brief - * - */ - void slot_create_empty_file(); - - /** - * @brief compress directory into gpg-zip - * - */ - void slot_compress_files(); - protected: /** * @brief @@ -160,34 +90,15 @@ class FilePage : public QWidget { */ void keyPressEvent(QKeyEvent* event) override; - /** - * @brief - * - * @param point - */ - void onCustomContextMenu(const QPoint& point); - private: - /** - * @brief Create a popup menu object - * - */ - void create_popup_menu(); - std::shared_ptr<Ui_FilePage> ui_; ///< - QFileSystemModel* dir_model_; ///< QCompleter* path_edit_completer_; ///< QStringListModel* path_complete_model_; ///< - std::filesystem::path m_path_; ///< - std::filesystem::path selected_path_; ///< - QMenu* popup_menu_{}; ///< QMenu* option_popup_menu_{}; ///< - QWidget* first_parent_{}; ///< + FileTreeView* file_tree_view_; }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_FILEPAGE_H diff --git a/src/ui/widgets/FileTreeView.cpp b/src/ui/widgets/FileTreeView.cpp new file mode 100644 index 00000000..f3556dc9 --- /dev/null +++ b/src/ui/widgets/FileTreeView.cpp @@ -0,0 +1,403 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "FileTreeView.h" + +#include "core/utils/IOUtils.h" +#include "ui/UISignalStation.h" + +namespace GpgFrontend::UI { + +FileTreeView::FileTreeView(QWidget* parent, const QString& target_path) + : QTreeView(parent) { + dir_model_ = new QFileSystemModel(); + dir_model_->setRootPath(target_path.isEmpty() ? QDir::currentPath() + : target_path); + dir_model_->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + + this->setModel(dir_model_); + this->setColumnWidth(0, 320); + this->sortByColumn(0, Qt::AscendingOrder); + current_path_ = std::filesystem::path(dir_model_->rootPath().toStdString()); + + slot_create_popup_menu(); + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &QWidget::customContextMenuRequested, this, + &FileTreeView::slot_show_custom_context_menu); + connect(this, &QTreeView::doubleClicked, this, + &FileTreeView::slot_file_tree_view_item_double_clicked); +} + +void FileTreeView::selectionChanged(const QItemSelection& selected, + const QItemSelection& deselected) { + QTreeView::selectionChanged(selected, deselected); + + if (!selected.indexes().empty()) { + selected_path_ = dir_model_->fileInfo(selected.indexes().first()) + .filesystemAbsoluteFilePath(); + GF_UI_LOG_DEBUG("file tree view selected target path: {}", + selected_path_.u8string()); + emit SignalSelectedChanged(QString::fromStdString(selected_path_)); + } else { + selected_path_ = std::filesystem::path{}; + } +} + +void FileTreeView::SlotGoPath(const std::filesystem::path& target_path) { + auto file_info = QFileInfo(target_path); + if (file_info.isDir() && file_info.isReadable() && file_info.isExecutable()) { + current_path_ = file_info.filesystemAbsoluteFilePath(); + GF_UI_LOG_DEBUG("file tree view set target path: {}", + current_path_.u8string()); + this->setRootIndex(dir_model_->index(file_info.filePath())); + dir_model_->setRootPath(file_info.filePath()); + for (int i = 1; i < dir_model_->columnCount(); ++i) { + this->resizeColumnToContents(i); + } + } else { + QMessageBox::critical( + this, tr("Error"), + tr("The path is not exists, unprivileged or unreachable.")); + } + emit SignalPathChanged(QString::fromStdString(current_path_.u8string())); +} + +void FileTreeView::slot_file_tree_view_item_double_clicked( + const QModelIndex& index) { + QFileInfo const file_info(dir_model_->fileInfo(index).absoluteFilePath()); + if (file_info.isFile()) { + if (file_info.isReadable()) { + emit SignalOpenFile(file_info.absoluteFilePath()); + } else { + QMessageBox::critical(this, tr("Error"), + tr("The file is unprivileged or unreachable.")); + } + } else { + SlotGoPath(file_info.filesystemAbsoluteFilePath()); + } +} + +void FileTreeView::SlotUpLevel() { + QModelIndex const current_root = this->rootIndex(); + + auto target_path = + dir_model_->fileInfo(current_root).filesystemAbsoluteFilePath(); + if (target_path.has_parent_path() && !target_path.parent_path().empty()) { + target_path = target_path.parent_path(); + GF_UI_LOG_DEBUG("file tree view go parent path: {}", + target_path.u8string()); + this->SlotGoPath(target_path); + } + current_path_ = target_path; +} + +auto FileTreeView::GetCurrentPath() -> std::filesystem::path { + return current_path_; +} + +void FileTreeView::SlotShowSystemFile(bool on) { + auto filters = on ? dir_model_->filter() | QDir::System + : dir_model_->filter() & ~QDir::System; + dir_model_->setFilter(filters); + dir_model_->setRootPath(QString::fromStdString(current_path_.u8string())); +} + +void FileTreeView::SlotShowHiddenFile(bool on) { + auto filters = on ? dir_model_->filter() | QDir::Hidden + : dir_model_->filter() & ~QDir::Hidden; + dir_model_->setFilter(filters); + dir_model_->setRootPath(QString::fromStdString(current_path_.u8string())); +} + +auto FileTreeView::GetPathByClickPoint(const QPoint& point) + -> std::filesystem::path { + auto const index = this->indexAt(point); + + if (!index.isValid()) { + return {}; + } + + auto index_path = dir_model_->fileInfo(index).filesystemAbsoluteFilePath(); + GF_UI_LOG_DEBUG("file tree view right click on: {}", index_path.string()); + return index_path; +} + +auto FileTreeView::GetSelectedPath() -> std::filesystem::path { + return selected_path_; +} + +auto FileTreeView::SlotDeleteSelectedItem() -> void { + QModelIndex const index = this->currentIndex(); + QVariant const data = this->model()->data(index); + + auto ret = QMessageBox::warning(this, tr("Warning"), + tr("Are you sure you want to delete it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + + GF_UI_LOG_DEBUG("delete item: {}", data.toString().toStdString()); + + if (!dir_model_->remove(index)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to delete the file or folder.")); + } +} + +void FileTreeView::SlotMkdir() { + auto index = this->rootIndex(); + + QString new_dir_name; + bool ok; + new_dir_name = QInputDialog::getText(this, tr("Make New Directory"), + tr("Directory Name"), QLineEdit::Normal, + new_dir_name, &ok); + if (ok && !new_dir_name.isEmpty()) { + dir_model_->mkdir(index, new_dir_name); + } +} + +void FileTreeView::SlotMkdirBelowAtSelectedItem() { + auto index = this->currentIndex(); + + QString new_dir_name; + bool ok; + new_dir_name = QInputDialog::getText(this, tr("Make New Directory"), + tr("Directory Name"), QLineEdit::Normal, + new_dir_name, &ok); + if (ok && !new_dir_name.isEmpty()) { + dir_model_->mkdir(index, new_dir_name); + } +} + +void FileTreeView::SlotTouch() { +#ifdef WINDOWS + auto root_path_str = dir_model_->rootPath().toStdU16String(); +#else + auto root_path_str = dir_model_->rootPath().toStdString(); +#endif + std::filesystem::path root_path(root_path_str); + + QString new_file_name; + bool ok; + new_file_name = QInputDialog::getText( + this, tr("Create Empty File"), tr("Filename (you can given extension)"), + QLineEdit::Normal, new_file_name, &ok); + if (ok && !new_file_name.isEmpty()) { +#ifdef WINDOWS + auto file_path = root_path / new_file_name.toStdU16String(); +#else + auto file_path = root_path / new_file_name.toStdString(); +#endif + QFile new_file(file_path.u8string().c_str()); + if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to create the file.")); + } + new_file.close(); + } +} + +void FileTreeView::SlotTouchBelowAtSelectedItem() { + std::filesystem::path root_path(selected_path_); + + QString new_file_name; + bool ok; + new_file_name = QInputDialog::getText( + this, tr("Create Empty File"), tr("Filename (you can given extension)"), + QLineEdit::Normal, new_file_name, &ok); + if (ok && !new_file_name.isEmpty()) { +#ifdef WINDOWS + auto file_path = root_path / new_file_name.toStdU16String(); +#else + auto file_path = root_path / new_file_name.toStdString(); +#endif + QFile new_file(file_path.u8string().c_str()); + if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to create the file.")); + } + new_file.close(); + } +} + +void FileTreeView::keyPressEvent(QKeyEvent* event) { + QTreeView::keyPressEvent(event); + + if (this->currentIndex().isValid()) { + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + slot_file_tree_view_item_double_clicked(this->currentIndex()); + } else if (event->key() == Qt::Key_Delete || + event->key() == Qt::Key_Backspace) { + SlotDeleteSelectedItem(); + } + } +} + +void FileTreeView::SlotOpenSelectedItemBySystemApplication() { + QFileInfo const info(QString::fromStdString(selected_path_.u8string())); + auto q_selected_path = QString::fromStdString(selected_path_.u8string()); + if (info.isDir()) { + const auto file_path = info.filePath().toUtf8().toStdString(); + QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path)); + + } else { + QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path)); + } +} + +void FileTreeView::SlotRenameSelectedItem() { + bool ok; + auto text = QInputDialog::getText( + this, tr("Rename"), tr("New Filename"), QLineEdit::Normal, + QString::fromStdString(selected_path_.filename().u8string()), &ok); + if (ok && !text.isEmpty()) { + try { +#ifdef WINDOWS + auto new_name_path = selected_path_.parent_path() / text.toStdU16String(); +#else + auto new_name_path = selected_path_.parent_path() / text.toStdString(); +#endif + GF_UI_LOG_DEBUG("new name path: {}", new_name_path.u8string()); + std::filesystem::rename(selected_path_, new_name_path); + + // refresh + SlotGoPath(current_path_); + } catch (...) { + GF_UI_LOG_ERROR("file tree view rename error: {}", + selected_path_.u8string()); + QMessageBox::critical(this, tr("Error"), + tr("Unable to rename the file or folder.")); + } + } +} + +auto FileTreeView::GetMousePointGlobal(const QPoint& point) -> QPoint { + return this->viewport()->mapToGlobal(point); +} + +void FileTreeView::slot_create_popup_menu() { + popup_menu_ = new QMenu(); + + action_open_file_ = new QAction(this); + action_open_file_->setText(tr("Open")); + connect(action_open_file_, &QAction::triggered, this, [this](bool) { + emit SignalOpenFile(QString::fromStdString(GetSelectedPath())); + }); + + action_rename_file_ = new QAction(this); + action_rename_file_->setText(tr("Rename")); + connect(action_rename_file_, &QAction::triggered, this, + &FileTreeView::SlotRenameSelectedItem); + + action_delete_file_ = new QAction(this); + action_delete_file_->setText(tr("Delete")); + connect(action_delete_file_, &QAction::triggered, this, + &FileTreeView::SlotDeleteSelectedItem); + + action_calculate_hash_ = new QAction(this); + action_calculate_hash_->setText(tr("Calculate Hash")); + connect(action_calculate_hash_, &QAction::triggered, this, + &FileTreeView::slot_calculate_hash); + + action_make_directory_ = new QAction(this); + action_make_directory_->setText(tr("Directory")); + connect(action_make_directory_, &QAction::triggered, this, + &FileTreeView::SlotMkdirBelowAtSelectedItem); + + action_create_empty_file_ = new QAction(this); + action_create_empty_file_->setText(tr("File")); + connect(action_create_empty_file_, &QAction::triggered, this, + &FileTreeView::SlotTouchBelowAtSelectedItem); + + action_compress_files_ = new QAction(this); + action_compress_files_->setText(tr("Compress...")); + action_compress_files_->setVisible(false); + connect(action_compress_files_, &QAction::triggered, this, + &FileTreeView::slot_compress_files); + + auto* action_open_with_system_default_application = new QAction(this); + action_open_with_system_default_application->setText( + tr("Open with Default System Application")); + connect(action_open_with_system_default_application, &QAction::triggered, + this, &FileTreeView::SlotOpenSelectedItemBySystemApplication); + + auto* new_item_action_menu = new QMenu(this); + new_item_action_menu->setTitle(tr("New")); + new_item_action_menu->addAction(action_create_empty_file_); + new_item_action_menu->addAction(action_make_directory_); + + popup_menu_->addAction(action_open_file_); + popup_menu_->addAction(action_open_with_system_default_application); + + popup_menu_->addSeparator(); + popup_menu_->addMenu(new_item_action_menu); + popup_menu_->addSeparator(); + + popup_menu_->addAction(action_rename_file_); + popup_menu_->addAction(action_delete_file_); + popup_menu_->addAction(action_compress_files_); + popup_menu_->addAction(action_calculate_hash_); +} + +void FileTreeView::slot_show_custom_context_menu(const QPoint& point) { + auto target_path = this->GetPathByClickPoint(point); + + if (!target_path.empty()) { + action_open_file_->setEnabled(true); + action_rename_file_->setEnabled(true); + action_delete_file_->setEnabled(true); + + QFileInfo const info(QString::fromStdString(this->GetSelectedPath())); + action_calculate_hash_->setEnabled(info.isFile() && info.isReadable()); + + } else { + action_open_file_->setEnabled(false); + action_rename_file_->setEnabled(false); + action_delete_file_->setEnabled(false); + + action_calculate_hash_->setEnabled(false); + } + popup_menu_->exec(this->GetMousePointGlobal(point)); +} + +void FileTreeView::slot_calculate_hash() { + emit UISignalStation::GetInstance()->SignalRefreshInfoBoard( + CalculateHash(this->GetSelectedPath().c_str()), + InfoBoardStatus::INFO_ERROR_OK); +} + +void FileTreeView::slot_compress_files() {} + +void FileTreeView::paintEvent(QPaintEvent* event) { + QTreeView::paintEvent(event); + for (int i = 1; i < dir_model_->columnCount(); ++i) { + this->resizeColumnToContents(i); + } +} +} // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FileTreeView.h b/src/ui/widgets/FileTreeView.h new file mode 100644 index 00000000..5d013ae4 --- /dev/null +++ b/src/ui/widgets/FileTreeView.h @@ -0,0 +1,229 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend 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 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend 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 GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +namespace GpgFrontend::UI { + +class FileTreeView : public QTreeView { + Q_OBJECT + public: + explicit FileTreeView(QWidget* parent, const QString& target_path); + + /** + * @brief Get the Current Path object + * + * @return std::filesystem::path + */ + auto GetCurrentPath() -> std::filesystem::path; + + /** + * @brief Get the Selected Path object + * + * @return std::filesystem::path + */ + auto GetSelectedPath() -> std::filesystem::path; + + /** + * @brief Get the Path By Click Point object + * + * @param point + * @return std::filesystem::path + */ + auto GetPathByClickPoint(const QPoint& point) -> std::filesystem::path; + + /** + * @brief Get the Mouse Point Global object + * + * @param point + * @return QPoint + */ + auto GetMousePointGlobal(const QPoint& point) -> QPoint; + + protected: + /** + * @brief + * + * @param selected + * @param deselected + */ + void selectionChanged(const QItemSelection& selected, + const QItemSelection& deselected) override; + + /** + * @brief + * + * @param event + */ + void keyPressEvent(QKeyEvent* event) override; + + /** + * @brief + * + */ + void paintEvent(QPaintEvent* event) override; + + signals: + + /** + * @brief + * + * @param path + */ + void SignalPathChanged(const QString&); + + /** + * @brief + * + */ + void SignalSelectedChanged(const QString&); + + /** + * @brief + * + */ + void SignalOpenFile(const QString&); + + public slots: + + /** + * @brief + * + */ + void SlotGoPath(const std::filesystem::path&); + + /** + * @brief + * + */ + void SlotUpLevel(); + + /** + * @brief + * + */ + void SlotShowSystemFile(bool); + + /** + * @brief + * + * @param on + */ + void SlotShowHiddenFile(bool); + + /** + * @brief + * + */ + auto SlotDeleteSelectedItem() -> void; + + /** + * @brief + * + */ + void SlotMkdir(); + + /** + * @brief + * + */ + void SlotMkdirBelowAtSelectedItem(); + + /** + * @brief + * + */ + void SlotTouch(); + + /** + * @brief + * + */ + void SlotTouchBelowAtSelectedItem(); + + /** + * @brief + * + */ + void SlotRenameSelectedItem(); + + /** + * @brief + * + */ + void SlotOpenSelectedItemBySystemApplication(); + + private slots: + + /** + * @brief + * + * @param index + */ + void slot_file_tree_view_item_double_clicked(const QModelIndex& index); + + /** + * @brief + * + */ + void slot_calculate_hash(); + + /** + * @brief compress directory into gpg-zip + * + */ + void slot_compress_files(); + + /** + * @brief + * + * @param point + */ + void slot_show_custom_context_menu(const QPoint& point); + + /** + * @brief Create a popup menu object + * + */ + void slot_create_popup_menu(); + + private: + QFileSystemModel* dir_model_; ///< + std::filesystem::path current_path_; ///< + std::filesystem::path selected_path_; ///< + + QMenu* popup_menu_; + QAction* action_open_file_; + QAction* action_rename_file_; + QAction* action_delete_file_; + QAction* action_calculate_hash_; + QAction* action_create_empty_file_; + QAction* action_make_directory_; + QAction* action_compress_files_; +}; +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/widgets/FindWidget.cpp b/src/ui/widgets/FindWidget.cpp index 598d8004..7cc569e4 100644 --- a/src/ui/widgets/FindWidget.cpp +++ b/src/ui/widgets/FindWidget.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -33,28 +33,31 @@ namespace GpgFrontend::UI { FindWidget::FindWidget(QWidget* parent, PlainTextEditorPage* edit) : QWidget(parent), m_text_page_(edit) { find_edit_ = new QLineEdit(this); - auto* closeButton = new QPushButton( + auto* close_button = new QPushButton( this->style()->standardIcon(QStyle::SP_TitleBarCloseButton), QString(), this); - auto* nextButton = new QPushButton(QIcon(":button_next.png"), QString()); - auto* previousButton = new QPushButton(QIcon(":button_previous.png"), ""); - - auto* notificationWidgetLayout = new QHBoxLayout(this); - notificationWidgetLayout->setContentsMargins(10, 0, 0, 0); - notificationWidgetLayout->addWidget(new QLabel(QString(_("Find")) + ": ")); - notificationWidgetLayout->addWidget(find_edit_, 2); - notificationWidgetLayout->addWidget(nextButton); - notificationWidgetLayout->addWidget(previousButton); - notificationWidgetLayout->addWidget(closeButton); - - this->setLayout(notificationWidgetLayout); + auto* next_button = + new QPushButton(QIcon(":/icons/button_next.png"), QString()); + auto* previous_button = + new QPushButton(QIcon(":/icons/button_previous.png"), ""); + + auto* notification_widget_layout = new QHBoxLayout(this); + notification_widget_layout->setContentsMargins(10, 0, 0, 0); + notification_widget_layout->addWidget(new QLabel(tr("Find") + ": ")); + notification_widget_layout->addWidget(find_edit_, 2); + notification_widget_layout->addWidget(next_button); + notification_widget_layout->addWidget(previous_button); + notification_widget_layout->addWidget(close_button); + + this->setLayout(notification_widget_layout); connect(find_edit_, &QLineEdit::textEdited, this, &FindWidget::slot_find); connect(find_edit_, &QLineEdit::returnPressed, this, &FindWidget::slot_find_next); - connect(nextButton, &QPushButton::clicked, this, &FindWidget::slot_find_next); - connect(previousButton, &QPushButton::clicked, this, + connect(next_button, &QPushButton::clicked, this, + &FindWidget::slot_find_next); + connect(previous_button, &QPushButton::clicked, this, &FindWidget::slot_find_previous); - connect(closeButton, &QPushButton::clicked, this, &FindWidget::slot_close); + connect(close_button, &QPushButton::clicked, this, &FindWidget::slot_close); // The timer is necessary for setting the focus QTimer::singleShot(0, find_edit_, SLOT(setFocus())); @@ -63,17 +66,17 @@ FindWidget::FindWidget(QWidget* parent, PlainTextEditorPage* edit) void FindWidget::set_background() { // auto cursor = m_text_page_->GetTextPage()->textCursor(); // if match is found set background of QLineEdit to white, otherwise to red - QPalette bgPalette(find_edit_->palette()); + QPalette bg_palette(find_edit_->palette()); if (!find_edit_->text().isEmpty() && m_text_page_->GetTextPage() ->document() ->find(find_edit_->text()) .position() < 0) { - bgPalette.setColor(QPalette::Base, "#ececba"); + bg_palette.setColor(QPalette::Base, "#ececba"); } else { - bgPalette.setColor(QPalette::Base, Qt::white); + bg_palette.setColor(QPalette::Base, Qt::white); } - find_edit_->setPalette(bgPalette); + find_edit_->setPalette(bg_palette); } void FindWidget::slot_find_next() { diff --git a/src/ui/widgets/FindWidget.h b/src/ui/widgets/FindWidget.h index dfe50f9c..a32a877c 100644 --- a/src/ui/widgets/FindWidget.h +++ b/src/ui/widgets/FindWidget.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef FINDWIDGET_H -#define FINDWIDGET_H +#pragma once #include "ui/GpgFrontendUI.h" #include "ui/widgets/PlainTextEditorPage.h" @@ -95,5 +94,3 @@ class FindWidget : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // FINDWIDGET_H diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp index b116df30..dc82d279 100644 --- a/src/ui/widgets/HelpPage.cpp +++ b/src/ui/widgets/HelpPage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,8 +28,6 @@ #include "ui/widgets/HelpPage.h" -#include <utility> - namespace GpgFrontend::UI { HelpPage::HelpPage(const QString& path, QWidget* parent) : QWidget(parent) { diff --git a/src/ui/widgets/HelpPage.h b/src/ui/widgets/HelpPage.h index 0b0db5ea..3ab2cbf6 100644 --- a/src/ui/widgets/HelpPage.h +++ b/src/ui/widgets/HelpPage.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef HELPPAGE_H -#define HELPPAGE_H +#pragma once #include "ui/GpgFrontendUI.h" @@ -70,5 +69,3 @@ class HelpPage : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // HELPPAGE_H diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp index 98b07089..fdec1e50 100644 --- a/src/ui/widgets/InfoBoardWidget.cpp +++ b/src/ui/widgets/InfoBoardWidget.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,31 +28,34 @@ #include "ui/widgets/InfoBoardWidget.h" -#include "core/function/GlobalSettingStation.h" -#include "ui/SignalStation.h" +#include "core/GpgModel.h" +#include "ui/UISignalStation.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/AppearanceSO.h" #include "ui_InfoBoard.h" namespace GpgFrontend::UI { InfoBoardWidget::InfoBoardWidget(QWidget* parent) - : QWidget(parent), ui_(std::make_shared<Ui_InfoBoard>()) { + : QWidget(parent), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_InfoBoard>()) { ui_->setupUi(this); ui_->actionButtonLayout->addStretch(); - ui_->copyButton->setText(_("Copy")); - ui_->saveButton->setText(_("Save File")); - ui_->clearButton->setText(_("Clear")); + ui_->copyToolButton->setToolTip(tr("Copy")); + ui_->saveToolButton->setToolTip(tr("Save File")); + ui_->clearToolButton->setToolTip(tr("Clear")); - connect(ui_->copyButton, &QPushButton::clicked, this, + connect(ui_->copyToolButton, &QToolButton::clicked, this, &InfoBoardWidget::slot_copy); - connect(ui_->saveButton, &QPushButton::clicked, this, + connect(ui_->saveToolButton, &QToolButton::clicked, this, &InfoBoardWidget::slot_save); - connect(ui_->clearButton, &QPushButton::clicked, this, + connect(ui_->clearToolButton, &QToolButton::clicked, this, &InfoBoardWidget::SlotReset); - connect(SignalStation::GetInstance(), &SignalStation::SignalRefreshInfoBoard, - this, &InfoBoardWidget::SlotRefresh); + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalRefreshInfoBoard, this, + &InfoBoardWidget::SlotRefresh); } void InfoBoardWidget::SetInfoBoard(const QString& text, @@ -79,12 +82,10 @@ void InfoBoardWidget::SetInfoBoard(const QString& text, status.setColor(QPalette::Text, color); ui_->infoBoard->setPalette(status); - SettingsObject general_settings_state("general_settings_state"); + AppearanceSO appearance(SettingsObject("general_settings_state")); // info board font size - auto info_font_size = - general_settings_state.Check("text_editor").Check("font_size", 10); - ui_->infoBoard->setFont(QFont("Times", info_font_size)); + ui_->infoBoard->setFont(QFont("Times", appearance.info_board_font_size)); } void InfoBoardWidget::SlotRefresh(const QString& text, InfoBoardStatus status) { @@ -94,9 +95,10 @@ void InfoBoardWidget::SlotRefresh(const QString& text, InfoBoardStatus status) { } void InfoBoardWidget::AssociateTextEdit(QTextEdit* edit) { - if (m_text_page_ != nullptr) + if (m_text_page_ != nullptr) { disconnect(m_text_page_, &QTextEdit::textChanged, this, &InfoBoardWidget::SlotReset); + } this->m_text_page_ = edit; connect(edit, &QTextEdit::textChanged, this, &InfoBoardWidget::SlotReset); } @@ -113,15 +115,15 @@ void InfoBoardWidget::AssociateTabWidget(QTabWidget* tab) { void InfoBoardWidget::AddOptionalAction(const QString& name, const std::function<void()>& action) { - SPDLOG_DEBUG("add option: {}", name.toStdString()); - auto actionButton = new QPushButton(name); - auto layout = new QHBoxLayout(); + GF_UI_LOG_DEBUG("add option: {}", name.toStdString()); + auto* action_button = new QPushButton(name); + auto* layout = new QHBoxLayout(); layout->setContentsMargins(5, 0, 5, 0); ui_->infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); // set margin from surroundings - layout->addWidget(actionButton); + layout->addWidget(action_button); ui_->actionButtonLayout->addLayout(layout); - connect(actionButton, &QPushButton::clicked, this, [=]() { action(); }); + connect(action_button, &QPushButton::clicked, this, [=]() { action(); }); } /** @@ -146,10 +148,11 @@ void InfoBoardWidget::delete_widgets_in_layout(QLayout* layout, QLayoutItem* item; while ((item = layout->layout()->takeAt(start_index)) != nullptr) { layout->removeItem(item); - if (item->layout() != nullptr) + if (item->layout() != nullptr) { delete_widgets_in_layout(item->layout()); - else if (item->widget() != nullptr) + } else if (item->widget() != nullptr) { delete item->widget(); + } delete item; } } @@ -161,8 +164,8 @@ void InfoBoardWidget::slot_copy() { void InfoBoardWidget::slot_save() { auto file_path = QFileDialog::getSaveFileName( - this, _("Save Information Board's Content"), {}, tr("Text (*.txt)")); - SPDLOG_DEBUG("file path: {}", file_path.toStdString()); + this, tr("Save Information Board's Content"), {}, tr("Text (*.txt)")); + GF_UI_LOG_DEBUG("file path: {}", file_path.toStdString()); if (file_path.isEmpty()) return; QFile file(file_path); @@ -170,8 +173,8 @@ void InfoBoardWidget::slot_save() { file.write(ui_->infoBoard->toPlainText().toUtf8()); } else { QMessageBox::critical( - this, _("Error"), - _("The file path is not exists, unprivileged or unreachable.")); + this, tr("Error"), + tr("The file path is not exists, unprivileged or unreachable.")); } file.close(); } diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h index 47740456..183a386c 100644 --- a/src/ui/widgets/InfoBoardWidget.h +++ b/src/ui/widgets/InfoBoardWidget.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __VERIFYNOTIFICATION_H__ -#define __VERIFYNOTIFICATION_H__ +#pragma once #include "PlainTextEditorPage.h" #include "core/function/result_analyse/GpgVerifyResultAnalyse.h" @@ -144,5 +143,3 @@ class InfoBoardWidget : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // __VERIFYNOTIFICATION_H__
\ No newline at end of file diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index ce3c1c3d..a3eb85ea 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,24 +28,21 @@ #include "ui/widgets/KeyList.h" -#include <boost/format.hpp> +#include <cstddef> #include <mutex> -#include <utility> #include "core/GpgCoreInit.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" -#include "spdlog/spdlog.h" -#include "ui/SignalStation.h" +#include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui_KeyList.h" -#include "widgets/TextEdit.h" namespace GpgFrontend::UI { KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability, QWidget* parent) : QWidget(parent), - ui_(std::make_shared<Ui_KeyList>()), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_KeyList>()), menu_ability_(menu_ability) { init(); } @@ -53,7 +50,7 @@ KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability, QWidget* parent) void KeyList::init() { ui_->setupUi(this); - ui_->menuWidget->setHidden(!menu_ability_); + ui_->menuWidget->setHidden(menu_ability_ == 0U); ui_->refreshKeyListButton->setHidden(~menu_ability_ & KeyMenuAbility::REFRESH); ui_->syncButton->setHidden(~menu_ability_ & KeyMenuAbility::SYNC_PUBLIC_KEY); @@ -64,20 +61,22 @@ void KeyList::init() { popup_menu_ = new QMenu(this); bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); + GlobalSettingStation::GetInstance() + .GetSettings() + .value("network/forbid_all_gnupg_connection", false) + .toBool(); // forbidden networks connections if (forbid_all_gnupg_connection) ui_->syncButton->setDisabled(true); // register key database refresh signal - connect(this, &KeyList::SignalRefreshDatabase, SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefresh); - connect(SignalStation::GetInstance(), - &SignalStation::SignalKeyDatabaseRefreshDone, this, + connect(this, &KeyList::SignalRefreshDatabase, UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefresh); + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, &KeyList::SlotRefresh); - connect(SignalStation::GetInstance(), &SignalStation::SignalUIRefresh, this, - &KeyList::SlotRefreshUI); + connect(UISignalStation::GetInstance(), &UISignalStation::SignalUIRefresh, + this, &KeyList::SlotRefreshUI); // register key database sync signal for refresh button connect(ui_->refreshKeyListButton, &QPushButton::clicked, this, @@ -91,33 +90,34 @@ void KeyList::init() { &KeyList::slot_sync_with_key_server); connect(ui_->searchBarEdit, &QLineEdit::textChanged, this, &KeyList::filter_by_keyword); - connect(this, &KeyList::SignalRefreshStatusBar, SignalStation::GetInstance(), - &SignalStation::SignalRefreshStatusBar); + connect(this, &KeyList::SignalRefreshStatusBar, + UISignalStation::GetInstance(), + &UISignalStation::SignalRefreshStatusBar); setAcceptDrops(true); - ui_->refreshKeyListButton->setText(_("Refresh")); + ui_->refreshKeyListButton->setText(tr("Refresh")); ui_->refreshKeyListButton->setToolTip( - _("Refresh the key list to synchronize changes.")); - ui_->syncButton->setText(_("Sync Public Key")); + tr("Refresh the key list to synchronize changes.")); + ui_->syncButton->setText(tr("Sync Public Key")); ui_->syncButton->setToolTip( - _("Sync public key with your default keyserver.")); - ui_->uncheckButton->setText(_("Uncheck ALL")); + tr("Sync public key with your default keyserver.")); + ui_->uncheckButton->setText(tr("Uncheck ALL")); ui_->uncheckButton->setToolTip( - _("Cancel all checked items in the current tab at once.")); - ui_->checkALLButton->setText(_("Check ALL")); + tr("Cancel all checked items in the current tab at once.")); + ui_->checkALLButton->setText(tr("Check ALL")); ui_->checkALLButton->setToolTip( - _("Check all items in the current tab at once")); - ui_->searchBarEdit->setPlaceholderText(_("Search for keys...")); + tr("Check all items in the current tab at once")); + ui_->searchBarEdit->setPlaceholderText(tr("Search for keys...")); } void KeyList::AddListGroupTab(const QString& name, const QString& id, KeyListRow::KeyType selectType, KeyListColumn::InfoType infoType, const KeyTable::KeyTableFilter filter) { - SPDLOG_DEBUG("add tab: {}", name.toStdString()); + GF_UI_LOG_DEBUG("add tab: {}", name.toStdString()); - auto key_list = new QTableWidget(this); + auto* key_list = new QTableWidget(this); if (m_key_list_ == nullptr) { m_key_list_ = key_list; } @@ -144,28 +144,28 @@ void KeyList::AddListGroupTab(const QString& name, const QString& id, key_list->setAlternatingRowColors(true); // Hidden Column For Purpose - if (!(infoType & KeyListColumn::TYPE)) { + if ((infoType & KeyListColumn::TYPE) == 0U) { key_list->setColumnHidden(1, true); } - if (!(infoType & KeyListColumn::NAME)) { + if ((infoType & KeyListColumn::NAME) == 0U) { key_list->setColumnHidden(2, true); } - if (!(infoType & KeyListColumn::EmailAddress)) { + if ((infoType & KeyListColumn::EmailAddress) == 0U) { key_list->setColumnHidden(3, true); } - if (!(infoType & KeyListColumn::Usage)) { + if ((infoType & KeyListColumn::Usage) == 0U) { key_list->setColumnHidden(4, true); } - if (!(infoType & KeyListColumn::Validity)) { + if ((infoType & KeyListColumn::Validity) == 0U) { key_list->setColumnHidden(5, true); } - if (!(infoType & KeyListColumn::FingerPrint)) { + if ((infoType & KeyListColumn::FingerPrint) == 0U) { key_list->setColumnHidden(6, true); } QStringList labels; - labels << _("Select") << _("Type") << _("Name") << _("Email Address") - << _("Usage") << _("Trust") << _("Finger Print"); + labels << tr("Select") << tr("Type") << tr("Name") << tr("Email Address") + << tr("Usage") << tr("Trust") << tr("Finger Print"); key_list->setHorizontalHeaderLabels(labels); key_list->horizontalHeader()->setStretchLastSection(false); @@ -175,18 +175,18 @@ void KeyList::AddListGroupTab(const QString& name, const QString& id, } void KeyList::SlotRefresh() { - SPDLOG_DEBUG("refresh, address: {}", static_cast<void*>(this)); + GF_UI_LOG_DEBUG("refresh, address: {}", static_cast<void*>(this)); ui_->refreshKeyListButton->setDisabled(true); ui_->syncButton->setDisabled(true); - emit SignalRefreshStatusBar(_("Refreshing Key List..."), 3000); + emit SignalRefreshStatusBar(tr("Refreshing Key List..."), 3000); this->buffered_keys_list_ = GpgKeyGetter::GetInstance().FetchKey(); this->slot_refresh_ui(); } void KeyList::SlotRefreshUI() { - SPDLOG_DEBUG("refresh, address: {}", static_cast<void*>(this)); + GF_UI_LOG_DEBUG("refresh, address: {}", static_cast<void*>(this)); this->slot_refresh_ui(); } @@ -201,7 +201,7 @@ KeyIdArgsListPtr KeyList::GetChecked(const KeyTable& key_table) { } KeyIdArgsListPtr KeyList::GetChecked() { - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); const auto& buffered_keys = m_key_tables_[ui_->keyGroupTab->currentIndex()].buffered_keys_; @@ -215,13 +215,13 @@ KeyIdArgsListPtr KeyList::GetChecked() { } KeyIdArgsListPtr KeyList::GetAllPrivateKeys() { - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); const auto& buffered_keys = m_key_tables_[ui_->keyGroupTab->currentIndex()].buffered_keys_; auto ret = std::make_unique<KeyIdArgsList>(); for (int i = 0; i < key_list->rowCount(); i++) { - if (key_list->item(i, 1) && buffered_keys[i].IsPrivateKey()) { + if ((key_list->item(i, 1) != nullptr) && buffered_keys[i].IsPrivateKey()) { ret->push_back(buffered_keys[i].GetId()); } } @@ -232,14 +232,14 @@ KeyIdArgsListPtr KeyList::GetPrivateChecked() { auto ret = std::make_unique<KeyIdArgsList>(); if (ui_->keyGroupTab->size().isEmpty()) return ret; - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); const auto& buffered_keys = m_key_tables_[ui_->keyGroupTab->currentIndex()].buffered_keys_; for (int i = 0; i < key_list->rowCount(); i++) { if ((key_list->item(i, 0)->checkState() == Qt::Checked) && - (key_list->item(i, 1))) { + ((key_list->item(i, 1)) != nullptr)) { ret->push_back(buffered_keys[i].GetId()); } } @@ -259,7 +259,7 @@ void KeyList::SetChecked(const KeyIdArgsListPtr& keyIds, } void KeyList::SetChecked(KeyIdArgsListPtr key_ids) { - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); if (key_list == nullptr) return; if (!m_key_tables_.empty()) { @@ -276,13 +276,13 @@ KeyIdArgsListPtr KeyList::GetSelected() { auto ret = std::make_unique<KeyIdArgsList>(); if (ui_->keyGroupTab->size().isEmpty()) return ret; - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); const auto& buffered_keys = m_key_tables_[ui_->keyGroupTab->currentIndex()].buffered_keys_; for (int i = 0; i < key_list->rowCount(); i++) { - if (key_list->item(i, 0)->isSelected() == 1) { + if (key_list->item(i, 0)->isSelected()) { ret->push_back(buffered_keys[i].GetId()); } } @@ -294,7 +294,7 @@ KeyIdArgsListPtr KeyList::GetSelected() { m_key_list_ = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); for (int i = 0; i < m_key_list_->rowCount(); i++) { - if (m_key_list_->item(i, 1)) { + if (m_key_list_->item(i, 1) != nullptr) { return true; } } @@ -314,8 +314,8 @@ void KeyList::contextMenuEvent(QContextMenuEvent* event) { QString current_tab_widget_obj_name = ui_->keyGroupTab->widget(ui_->keyGroupTab->currentIndex())->objectName(); - SPDLOG_DEBUG("current tab widget object name: {}", - current_tab_widget_obj_name.toStdString()); + GF_UI_LOG_DEBUG("current tab widget object name: {}", + current_tab_widget_obj_name.toStdString()); if (current_tab_widget_obj_name == "favourite") { QList<QAction*> actions = popup_menu_->actions(); for (QAction* action : actions) { @@ -348,31 +348,30 @@ void KeyList::AddMenuAction(QAction* act) { popup_menu_->addAction(act); } void KeyList::dropEvent(QDropEvent* event) { auto* dialog = new QDialog(); - dialog->setWindowTitle(_("Import Keys")); + dialog->setWindowTitle(tr("Import Keys")); QLabel* label; - label = - new QLabel(QString(_("You've dropped something on the table.")) + "\n " + - _("GpgFrontend " - "will now try to import key(s).") + - "\n"); + label = new QLabel(tr("You've dropped something on the table.") + "\n " + + tr("GpgFrontend will now try to import key(s).") + "\n"); // "always import keys"-CheckBox - auto* checkBox = new QCheckBox(_("Always import without bothering.")); + auto* check_box = new QCheckBox(tr("Always import without bothering.")); - bool confirm_import_keys = GlobalSettingStation::GetInstance().LookupSettings( - "general.confirm_import_keys", true); - if (confirm_import_keys) checkBox->setCheckState(Qt::Checked); + bool confirm_import_keys = GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/confirm_import_keys", true) + .toBool(); + if (confirm_import_keys) check_box->setCheckState(Qt::Checked); // Buttons for ok and cancel - auto* buttonBox = + auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + connect(button_box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); auto* vbox = new QVBoxLayout(); vbox->addWidget(label); - vbox->addWidget(checkBox); - vbox->addWidget(buttonBox); + vbox->addWidget(check_box); + vbox->addWidget(button_box); dialog->setLayout(vbox); @@ -380,19 +379,8 @@ void KeyList::dropEvent(QDropEvent* event) { dialog->exec(); if (dialog->result() == QDialog::Rejected) return; - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - - if (!settings.exists("general") || - settings.lookup("general").getType() != libconfig::Setting::TypeGroup) - settings.add("general", libconfig::Setting::TypeGroup); - auto& general = settings["general"]; - if (!general.exists("confirm_import_keys")) - general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) = - checkBox->isChecked(); - else { - general["confirm_import_keys"] = checkBox->isChecked(); - } - GlobalSettingStation::GetInstance().SyncSettings(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + settings.setValue("basic/confirm_import_keys", check_box->isChecked()); } if (event->mimeData()->hasUrls()) { @@ -400,15 +388,15 @@ void KeyList::dropEvent(QDropEvent* event) { QFile file; file.setFileName(tmp.toLocalFile()); if (!file.open(QIODevice::ReadOnly)) { - SPDLOG_ERROR("couldn't open file: {}", tmp.toString().toStdString()); + GF_UI_LOG_ERROR("couldn't open file: {}", tmp.toString().toStdString()); } - QByteArray inBuffer = file.readAll(); - this->import_keys(inBuffer); + QByteArray in_buffer = file.readAll(); + this->import_keys(in_buffer); file.close(); } } else { - QByteArray inBuffer(event->mimeData()->text().toUtf8()); - this->import_keys(inBuffer); + QByteArray in_buffer(event->mimeData()->text().toUtf8()); + this->import_keys(in_buffer); } } @@ -416,20 +404,10 @@ void KeyList::dragEnterEvent(QDragEnterEvent* event) { event->acceptProposedAction(); } -/** set background color for Keys and put them to top - * - */ -[[maybe_unused]] void KeyList::MarkKeys(QStringList* keyIds) { - foreach (QString id, *keyIds) { - spdlog::debug("marked: ", id.toStdString()); - } -} - -void KeyList::import_keys(const QByteArray& inBuffer) { - auto std_buffer = std::make_unique<ByteArray>(inBuffer.toStdString()); - GpgImportInformation result = - GpgKeyImportExporter::GetInstance().ImportKey(std::move(std_buffer)); - new KeyImportDetailDialog(result, false, this); +void KeyList::import_keys(const QByteArray& in_buffer) { + auto result = + GpgKeyImportExporter::GetInstance().ImportKey(GFBuffer(in_buffer)); + (new KeyImportDetailDialog(result, this))->exec(); } void KeyList::slot_double_clicked(const QModelIndex& index) { @@ -448,13 +426,13 @@ void KeyList::SetDoubleClickedAction( this->m_action_ = std::move(action); } -std::string KeyList::GetSelectedKey() { +QString KeyList::GetSelectedKey() { if (ui_->keyGroupTab->size().isEmpty()) return {}; const auto& buffered_keys = m_key_tables_[ui_->keyGroupTab->currentIndex()].buffered_keys_; for (int i = 0; i < m_key_list_->rowCount(); i++) { - if (m_key_list_->item(i, 0)->isSelected() == 1) { + if (m_key_list_->item(i, 0)->isSelected()) { return buffered_keys[i].GetId(); } } @@ -462,7 +440,7 @@ std::string KeyList::GetSelectedKey() { } void KeyList::slot_refresh_ui() { - SPDLOG_DEBUG("refresh: {}", static_cast<void*>(buffered_keys_list_.get())); + GF_UI_LOG_DEBUG("refresh: {}", static_cast<void*>(buffered_keys_list_.get())); if (buffered_keys_list_ != nullptr) { std::lock_guard<std::mutex> guard(buffered_key_list_mutex_); @@ -471,7 +449,7 @@ void KeyList::slot_refresh_ui() { GpgKeyGetter::GetInstance().GetKeysCopy(buffered_keys_list_)); } } - emit SignalRefreshStatusBar(_("Key List Refreshed."), 1000); + emit SignalRefreshStatusBar(tr("Key List Refreshed."), 1000); ui_->refreshKeyListButton->setDisabled(false); ui_->syncButton->setDisabled(false); } @@ -481,8 +459,9 @@ void KeyList::slot_sync_with_key_server() { { std::lock_guard<std::mutex> guard(buffered_key_list_mutex_); for (const auto& key : *buffered_keys_list_) { - if (!(key.IsPrivateKey() && key.IsHasMasterKey())) + if (!(key.IsPrivateKey() && key.IsHasMasterKey())) { key_ids.push_back(key.GetId()); + } } } @@ -491,23 +470,25 @@ void KeyList::slot_sync_with_key_server() { ui_->refreshKeyListButton->setDisabled(true); ui_->syncButton->setDisabled(true); - emit SignalRefreshStatusBar(_("Syncing Key List..."), 3000); + emit SignalRefreshStatusBar(tr("Syncing Key List..."), 3000); CommonUtils::SlotImportKeyFromKeyServer( - key_ids, [=](const std::string& key_id, const std::string& status, + key_ids, [=](const QString& key_id, const QString& status, size_t current_index, size_t all_index) { - SPDLOG_DEBUG("import key: {} {} {} {}", key_id, status, current_index, - all_index); + GF_UI_LOG_DEBUG("import key: {} {} {} {}", key_id, status, + current_index, all_index); auto key = GpgKeyGetter::GetInstance().GetKey(key_id); - boost::format status_str = boost::format(_("Sync [%1%/%2%] %3% %4%")) % - current_index % all_index % - key.GetUIDs()->front().GetUID() % status; - emit SignalRefreshStatusBar(status_str.str().c_str(), 1500); + auto status_str = tr("Sync [%1/%2] %3 %4") + .arg(current_index) + .arg(all_index) + .arg(key.GetUIDs()->front().GetUID()) + .arg(status); + emit SignalRefreshStatusBar(status_str, 1500); if (current_index == all_index) { ui_->syncButton->setDisabled(false); ui_->refreshKeyListButton->setDisabled(false); - emit SignalRefreshStatusBar(_("Key List Sync Done."), 3000); + emit SignalRefreshStatusBar(tr("Key List Sync Done."), 3000); emit this->SignalRefreshDatabase(); } }); @@ -517,10 +498,10 @@ void KeyList::filter_by_keyword() { auto keyword = ui_->searchBarEdit->text(); keyword = keyword.trimmed(); - SPDLOG_DEBUG("get new keyword of search bar: {}", keyword.toStdString()); + GF_UI_LOG_DEBUG("get new keyword of search bar: {}", keyword); for (auto& table : m_key_tables_) { // refresh arguments - table.SetFilterKeyword(keyword.toLower().toStdString()); + table.SetFilterKeyword(keyword.toLower()); table.SetMenuAbility(menu_ability_); } // refresh ui @@ -528,7 +509,7 @@ void KeyList::filter_by_keyword() { } void KeyList::uncheck_all() { - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); if (key_list == nullptr) return; if (!m_key_tables_.empty()) { @@ -542,7 +523,7 @@ void KeyList::uncheck_all() { } void KeyList::check_all() { - auto key_list = + auto* key_list = qobject_cast<QTableWidget*>(ui_->keyGroupTab->currentWidget()); if (key_list == nullptr) return; if (!m_key_tables_.empty()) { @@ -556,10 +537,11 @@ void KeyList::check_all() { } KeyIdArgsListPtr& KeyTable::GetChecked() { - if (checked_key_ids_ == nullptr) + if (checked_key_ids_ == nullptr) { checked_key_ids_ = std::make_unique<KeyIdArgsList>(); + } auto& ret = checked_key_ids_; - for (int i = 0; i < buffered_keys_.size(); i++) { + for (size_t i = 0; i < buffered_keys_.size(); i++) { auto key_id = buffered_keys_[i].GetId(); if (key_list_->item(i, 0)->checkState() == Qt::Checked && std::find(ret->begin(), ret->end(), key_id) == ret->end()) { @@ -582,32 +564,24 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { // Optimization for copy KeyLinkListPtr keys = nullptr; - if (m_keys == nullptr) + if (m_keys == nullptr) { keys = GpgKeyGetter::GetInstance().FetchKey(); - else + } else { keys = std::move(m_keys); + } auto it = keys->begin(); int row_count = 0; while (it != keys->end()) { // filter by search bar's keyword - if (ability_ & KeyMenuAbility::SEARCH_BAR && !keyword_.empty()) { - auto name = it->GetName(); - std::transform(name.begin(), name.end(), name.begin(), - [](unsigned char c) { return std::tolower(c); }); - - auto email = it->GetEmail(); - std::transform(email.begin(), email.end(), email.begin(), - [](unsigned char c) { return std::tolower(c); }); - - auto comment = it->GetComment(); - std::transform(comment.begin(), comment.end(), comment.begin(), - [](unsigned char c) { return std::tolower(c); }); - - if (name.find(keyword_) == std::string::npos && - email.find(keyword_) == std::string::npos && - comment.find(keyword_) == std::string::npos) { + if (ability_ & KeyMenuAbility::SEARCH_BAR && !keyword_.isEmpty()) { + auto name = it->GetName().toLower(); + auto email = it->GetEmail().toLower(); + auto comment = it->GetComment().toLower(); + + if (!name.contains(keyword_) && !email.contains(keyword_) && + !comment.contains(keyword_)) { it = keys->erase(it); continue; } @@ -662,9 +636,9 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { auto* tmp1 = new QTableWidgetItem(type_str); key_list_->setItem(row_index, 1, tmp1); - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(it->GetName())); + auto* tmp2 = new QTableWidgetItem(it->GetName()); key_list_->setItem(row_index, 2, tmp2); - auto* tmp3 = new QTableWidgetItem(QString::fromStdString(it->GetEmail())); + auto* tmp3 = new QTableWidgetItem(it->GetEmail()); key_list_->setItem(row_index, 3, tmp3); QString usage; @@ -679,13 +653,11 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { temp_usage->setTextAlignment(Qt::AlignCenter); key_list_->setItem(row_index, 4, temp_usage); - auto* temp_validity = - new QTableWidgetItem(QString::fromStdString(it->GetOwnerTrust())); + auto* temp_validity = new QTableWidgetItem(it->GetOwnerTrust()); temp_validity->setTextAlignment(Qt::AlignCenter); key_list_->setItem(row_index, 5, temp_validity); - auto* temp_fpr = - new QTableWidgetItem(QString::fromStdString(it->GetFingerprint())); + auto* temp_fpr = new QTableWidgetItem(it->GetFingerprint()); temp_fpr->setTextAlignment(Qt::AlignCenter); key_list_->setItem(row_index, 6, temp_fpr); @@ -735,7 +707,7 @@ void KeyTable::SetMenuAbility(KeyMenuAbility::AbilityType ability) { this->ability_ = ability; } -void KeyTable::SetFilterKeyword(std::string keyword) { - this->keyword_ = keyword; +void KeyTable::SetFilterKeyword(QString keyword) { + this->keyword_ = std::move(keyword); } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index eb346740..f709aa9e 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,20 +20,15 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __KEYLIST_H__ -#define __KEYLIST_H__ +#pragma once -#include <string> -#include <utility> - -#include "core/GpgContext.h" -#include "ui/dialog/import_export/KeyImportDetailDialog.h" +#include "core/GpgModel.h" class Ui_KeyList; @@ -96,7 +91,7 @@ struct KeyTable { KeyTableFilter filter_; ///< KeyIdArgsListPtr checked_key_ids_; ///< KeyMenuAbility::AbilityType ability_; ///< - std::string keyword_; ///< + QString keyword_; ///< /** * @brief Construct a new Key Table object @@ -160,7 +155,7 @@ struct KeyTable { * @brief * */ - void SetFilterKeyword(std::string keyword); + void SetFilterKeyword(QString keyword); }; /** @@ -279,16 +274,9 @@ class KeyList : public QWidget { /** * @brief Get the Selected Key object * - * @return std::string - */ - std::string GetSelectedKey(); - - /** - * @brief - * - * @param keyIds + * @return QString */ - [[maybe_unused]] static void MarkKeys(QStringList* keyIds); + QString GetSelectedKey(); /** * @brief @@ -414,5 +402,3 @@ class KeyList : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // __KEYLIST_H__ diff --git a/src/ui/widgets/PlainTextEditorPage.cpp b/src/ui/widgets/PlainTextEditorPage.cpp index c9a65a4c..7d951006 100644 --- a/src/ui/widgets/PlainTextEditorPage.cpp +++ b/src/ui/widgets/PlainTextEditorPage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,56 +19,49 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "PlainTextEditorPage.h" -#include <boost/format.hpp> -#include <string> -#include <utility> - -#include "core/function/CharsetOperator.h" #include "core/thread/FileReadTask.h" -#include "core/thread/Task.h" #include "core/thread/TaskRunnerGetter.h" #include "ui/struct/SettingsObject.h" +#include "ui/struct/settings/AppearanceSO.h" #include "ui_PlainTextEditor.h" namespace GpgFrontend::UI { PlainTextEditorPage::PlainTextEditorPage(QString file_path, QWidget *parent) : QWidget(parent), - ui_(std::make_shared<Ui_PlainTextEditor>()), + ui_(GpgFrontend::SecureCreateSharedObject<Ui_PlainTextEditor>()), full_file_path_(std::move(file_path)) { ui_->setupUi(this); ui_->textPage->setFocus(); ui_->loadingLabel->setHidden(true); - // Front in same width - SettingsObject general_settings_state("general_settings_state"); - // font size - auto editor_font_size = - general_settings_state.Check("text_editor").Check("font_size", 10); - ui_->textPage->setFont(QFont("Courier", editor_font_size)); + AppearanceSO appearance(SettingsObject("general_settings_state")); + ui_->textPage->setFont(QFont("Courier", appearance.text_editor_font_size)); this->setAttribute(Qt::WA_DeleteOnClose); - this->ui_->characterLabel->setText(_("0 character")); - this->ui_->lfLabel->setText(_("lf")); - this->ui_->encodingLabel->setText(_("utf-8")); + this->ui_->characterLabel->setText(tr("0 character")); + this->ui_->lfLabel->setHidden(true); + this->ui_->encodingLabel->setText("Unicode"); connect(ui_->textPage, &QPlainTextEdit::textChanged, this, [=]() { // if file is loading if (!read_done_) return; auto text = ui_->textPage->document()->toPlainText(); - auto str = boost::format(_("%1% character(s)")) % text.size(); - this->ui_->characterLabel->setText(str.str().c_str()); + auto str = tr("%1 character(s)").arg(text.size()); + this->ui_->characterLabel->setText(str); }); if (full_file_path_.isEmpty()) { @@ -76,7 +69,7 @@ PlainTextEditorPage::PlainTextEditorPage(QString file_path, QWidget *parent) ui_->loadingLabel->setHidden(true); } else { read_done_ = false; - ui_->loadingLabel->setText(_("Loading...")); + ui_->loadingLabel->setText(tr("Loading...")); ui_->loadingLabel->setHidden(false); } } @@ -87,24 +80,11 @@ const QString &PlainTextEditorPage::GetFilePath() const { QPlainTextEdit *PlainTextEditorPage::GetTextPage() { return ui_->textPage; } -bool PlainTextEditorPage::WillCharsetChange() const { - // detect if the line-ending will change - if (is_crlf_) return true; - - // detect if the charset of the file will change - if (charset_name_ != "UTF-8" && charset_name_ != "ISO-8859-1") - return true; - else - return false; -} - void PlainTextEditorPage::NotifyFileSaved() { this->is_crlf_ = false; - this->charset_confidence_ = 100; - this->charset_name_ = "UTF-8"; - this->ui_->lfLabel->setText(_("lf")); - this->ui_->encodingLabel->setText(_("UTF-8")); + this->ui_->lfLabel->setText(tr("lf")); + this->ui_->encodingLabel->setText(tr("UTF-8")); } void PlainTextEditorPage::SetFilePath(const QString &filePath) { @@ -130,10 +110,9 @@ void PlainTextEditorPage::slot_format_gpg_header() { QString content = ui_->textPage->toPlainText(); // Get positions of the gpg-headers, if they exist - int start = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN); - int startSig = - content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN); - int endSig = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_END); + int start = content.indexOf(GpgFrontend::PGP_SIGNED_BEGIN); + int startSig = content.indexOf(GpgFrontend::PGP_SIGNATURE_BEGIN); + int endSig = content.indexOf(GpgFrontend::PGP_SIGNATURE_END); if (start < 0 || startSig < 0 || endSig < 0 || sign_marked_) { return; @@ -168,12 +147,12 @@ void PlainTextEditorPage::ReadFile() { ui_->loadingLabel->setHidden(false); ui_->textPage->document()->blockSignals(true); - auto text_page = this->GetTextPage(); + auto *text_page = this->GetTextPage(); text_page->setReadOnly(true); - const auto target_path = this->full_file_path_.toStdString(); + const auto target_path = this->full_file_path_; - auto *task_runner = + auto task_runner = GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner(); auto *read_task = new FileReadTask(target_path); @@ -182,13 +161,12 @@ void PlainTextEditorPage::ReadFile() { connect(this, &PlainTextEditorPage::SignalUIBytesDisplayed, read_task, &FileReadTask::SignalFileBytesReadNext, Qt::QueuedConnection); - connect(read_task, &FileReadTask::SignalTaskRunnableEnd, this, - []() { SPDLOG_DEBUG("read thread closed"); }); + connect(read_task, &FileReadTask::SignalTaskShouldEnd, this, + []() { GF_UI_LOG_DEBUG("read thread closed"); }); connect(this, &PlainTextEditorPage::close, read_task, - [=]() { read_task->SignalTaskRunnableEnd(0); }); + [=]() { read_task->SignalTaskShouldEnd(0); }); connect(read_task, &FileReadTask::SignalFileBytesReadEnd, this, [=]() { // set the UI - if (!binary_mode_) text_page->setReadOnly(false); this->read_done_ = true; this->ui_->textPage->setEnabled(true); text_page->document()->setModified(false); @@ -200,104 +178,27 @@ void PlainTextEditorPage::ReadFile() { task_runner->PostTask(read_task); } -std::string binary_to_string(const std::string &source) { - static char syms[] = "0123456789ABCDEF"; - std::stringstream ss; - for (unsigned char c : source) - ss << syms[((c >> 4) & 0xf)] << syms[c & 0xf] << " "; - return ss.str(); +auto BinaryToString(const QByteArray &source) -> QString { + static const char kSyms[] = "0123456789ABCDEF"; + QString buffer; + QTextStream ss(&buffer); + for (auto c : source) ss << kSyms[((c >> 4) & 0xf)] << kSyms[c & 0xf] << " "; + return buffer; } void PlainTextEditorPage::slot_insert_text(QByteArray bytes_data) { - std::string data = bytes_data.toStdString(); - SPDLOG_DEBUG("data size: {}", data.size()); - read_bytes_ += data.size(); - // If binary format is detected, the entire file is converted to binary - // format for display. - bool if_last_binary_mode = binary_mode_; - if (!binary_mode_ && !read_done_) { - detect_encoding(data); - } + GF_UI_LOG_TRACE("inserting data read to editor, data size: {}", + bytes_data.size()); + read_bytes_ += bytes_data.size(); - if (binary_mode_) { - // change formery displayed text to binary format - if (if_last_binary_mode != binary_mode_) { - auto text_buffer = - ui_->textPage->document()->toRawText().toLocal8Bit().toStdString(); - ui_->textPage->clear(); - this->GetTextPage()->insertPlainText( - binary_to_string(text_buffer).c_str()); - this->ui_->lfLabel->setText("None"); - } + // insert the text to the text page + this->GetTextPage()->insertPlainText(bytes_data); - // insert new data - this->GetTextPage()->insertPlainText(binary_to_string(data).c_str()); + auto text = this->GetTextPage()->toPlainText(); + auto str = tr("%1 character(s)").arg(text.size()); + this->ui_->characterLabel->setText(str); - // update the size of the file - auto str = boost::format(_("%1% byte(s)")) % read_bytes_; - this->ui_->characterLabel->setText(str.str().c_str()); - } else { - // detect crlf/lf line ending - detect_cr_lf(data); - - // when reding from a text file - // try convert the any of thetext to utf8 - std::string utf8_data; - if (!read_done_ && charset_confidence_ > 25) { - CharsetOperator::Convert2Utf8(data, utf8_data, charset_name_); - } else { - // when editing a text file, do nothing. - utf8_data = data; - } - - // insert the text to the text page - this->GetTextPage()->insertPlainText(utf8_data.c_str()); - - auto text = this->GetTextPage()->toPlainText(); - auto str = boost::format(_("%1% character(s)")) % text.size(); - this->ui_->characterLabel->setText(str.str().c_str()); - } QTimer::singleShot(25, this, &PlainTextEditorPage::SignalUIBytesDisplayed); } -void PlainTextEditorPage::detect_encoding(const std::string &data) { - // skip the binary data to avoid the false detection of the encoding - if (binary_mode_) return; - - // detect the encoding - auto charset = CharsetOperator::Detect(data); - this->charset_name_ = std::get<0>(charset).c_str(); - this->language_name_ = std::get<1>(charset).c_str(); - this->charset_confidence_ = std::get<2>(charset); - - // probably there is no need to detect the encoding again - if (this->charset_confidence_ < 10) { - binary_mode_ = true; - } - - if (binary_mode_) { - // hide the line ending label, when the file is binary - this->ui_->lfLabel->setHidden(true); - this->ui_->encodingLabel->setText(_("binary")); - } else { - ui_->encodingLabel->setText(this->charset_name_.c_str()); - } -} - -void PlainTextEditorPage::detect_cr_lf(const std::string &data) { - if (binary_mode_) { - return; - } - - // if contain crlf, set the label to crlf - if (is_crlf_) return; - - if (data.find("\r\n") != std::string::npos) { - this->ui_->lfLabel->setText("crlf"); - is_crlf_ = true; - } else { - this->ui_->lfLabel->setText("lf"); - } -} - } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/PlainTextEditorPage.h b/src/ui/widgets/PlainTextEditorPage.h index ffa31762..4981b24c 100644 --- a/src/ui/widgets/PlainTextEditorPage.h +++ b/src/ui/widgets/PlainTextEditorPage.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,19 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __EDITORPAGE_H__ -#define __EDITORPAGE_H__ - -#include <string> - -#include "core/GpgConstants.h" -#include "ui/GpgFrontendUI.h" +#pragma once class Ui_PlainTextEditor; @@ -101,12 +95,6 @@ class PlainTextEditorPage : public QWidget { [[nodiscard]] bool ReadDone() const { return this->read_done_; } /** - * @brief detect if the charset of the file will change - * - */ - bool WillCharsetChange() const; - - /** * @brief notify the user that the file has been saved. * */ @@ -124,27 +112,9 @@ class PlainTextEditorPage : public QWidget { std::shared_ptr<Ui_PlainTextEditor> ui_; ///< QString full_file_path_; ///< The path to the file handled in the tab bool sign_marked_{}; ///< true, if the signed header is marked, false if not - bool read_done_ = false; ///< - bool binary_mode_ = false; ///< - size_t read_bytes_ = 0; ///< - std::string charset_name_; ///< - std::string language_name_; ///< - int32_t charset_confidence_{}; ///< - bool is_crlf_ = false; ///< - - /** - * @brief - * - * @param data - */ - void detect_encoding(const std::string& data); - - /** - * @brief - * - * @param data - */ - void detect_cr_lf(const std::string& data); + bool read_done_ = false; ///< + size_t read_bytes_ = 0; ///< + bool is_crlf_ = false; ///< private slots: @@ -162,5 +132,3 @@ class PlainTextEditorPage : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // __EDITORPAGE_H__ diff --git a/src/ui/widgets/TOFUInfoPage.cpp b/src/ui/widgets/TOFUInfoPage.cpp index 709a66e1..39cf8921 100644 --- a/src/ui/widgets/TOFUInfoPage.cpp +++ b/src/ui/widgets/TOFUInfoPage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,27 +19,28 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ #include "TOFUInfoPage.h" GpgFrontend::UI::TOFUInfoPage::TOFUInfoPage( - const GpgFrontend::GpgTOFUInfo &tofu_info, QWidget *parent) + const GpgFrontend::GpgTOFUInfo & /*tofu_info*/, QWidget *parent) : QWidget(parent) { auto grid_layout = new QGridLayout(); - grid_layout->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0); - grid_layout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0); - grid_layout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0); - grid_layout->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0); - grid_layout->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0); - grid_layout->addWidget(new QLabel(QString(_("Expires on")) + ": "), 5, 0); - grid_layout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 6, 0); - grid_layout->addWidget(new QLabel(QString(_("Secret Key Existence")) + ": "), - 7, 0); + grid_layout->addWidget(new QLabel(tr("Key ID") + ": "), 0, 0); + grid_layout->addWidget(new QLabel(tr("Algorithm") + ": "), 1, 0); + grid_layout->addWidget(new QLabel(tr("Key Size") + ": "), 2, 0); + grid_layout->addWidget(new QLabel(tr("Nominal Usage") + ": "), 3, 0); + grid_layout->addWidget(new QLabel(tr("Actual Usage") + ": "), 4, 0); + grid_layout->addWidget(new QLabel(tr("Expires on") + ": "), 5, 0); + grid_layout->addWidget(new QLabel(tr("Last Update") + ": "), 6, 0); + grid_layout->addWidget(new QLabel(tr("Secret Key Existence") + ": "), 7, 0); setLayout(grid_layout); } diff --git a/src/ui/widgets/TOFUInfoPage.h b/src/ui/widgets/TOFUInfoPage.h index 445b1567..4bd9b89a 100644 --- a/src/ui/widgets/TOFUInfoPage.h +++ b/src/ui/widgets/TOFUInfoPage.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -19,15 +19,16 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef GPGFRONTEND_TOFUINFOPAGE_H -#define GPGFRONTEND_TOFUINFOPAGE_H +#pragma once -#include "core/GpgModel.h" +#include "core/typedef/GpgTypedef.h" #include "ui/GpgFrontendUI.h" namespace GpgFrontend::UI { @@ -49,5 +50,3 @@ class TOFUInfoPage : public QWidget { QWidget *parent = nullptr); }; } // namespace GpgFrontend::UI - -#endif // GPGFRONTEND_TOFUINFOPAGE_H diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp index 7af4d5f8..59890465 100644 --- a/src/ui/widgets/TextEdit.cpp +++ b/src/ui/widgets/TextEdit.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,15 +28,14 @@ #include "ui/widgets/TextEdit.h" -#include <boost/format.hpp> -#include <string> +#include <QtPrintSupport> #include <tuple> #include <vector> +#include "core/GpgModel.h" #include "core/function/CacheManager.h" #include "core/function/GlobalSettingStation.h" -#include "nlohmann/json_fwd.hpp" -#include "spdlog/spdlog.h" +#include "ui/struct/CacheObject.h" namespace GpgFrontend::UI { @@ -60,11 +59,11 @@ TextEdit::TextEdit(QWidget* parent) : QWidget(parent) { } void TextEdit::SlotNewTab() { - QString header = _("untitled") + QString::number(++count_page_) + ".txt"; + QString header = tr("untitled") + QString::number(++count_page_) + ".txt"; auto* page = new PlainTextEditorPage(); auto index = tab_widget_->addTab(page, header); - tab_widget_->setTabIcon(index, QIcon(":file.png")); + tab_widget_->setTabIcon(index, QIcon(":/icons/file.png")); tab_widget_->setCurrentIndex(tab_widget_->count() - 1); page->GetTextPage()->setFocus(); connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged, @@ -73,21 +72,20 @@ void TextEdit::SlotNewTab() { this, &TextEdit::slot_save_status_to_cache_for_revovery); } -void TextEdit::SlotNewTabWithContent(std::string title, - const std::string& content) { - QString header = _("untitled") + QString::number(++count_page_) + ".txt"; - if (!title.empty()) { +void TextEdit::SlotNewTabWithContent(QString title, const QString& content) { + QString header = tr("untitled") + QString::number(++count_page_) + ".txt"; + if (!title.isEmpty()) { // modify title - if (!title.empty() && title[0] == '*') { - title.erase(0, 1); + if (!title.isEmpty() && title[0] == '*') { + title.remove(0, 1); } // set title - header = QString::fromStdString(title); + header = title; } auto* page = new PlainTextEditorPage(); auto index = tab_widget_->addTab(page, header); - tab_widget_->setTabIcon(index, QIcon(":file.png")); + tab_widget_->setTabIcon(index, QIcon(":/icons/file.png")); tab_widget_->setCurrentIndex(tab_widget_->count() - 1); page->GetTextPage()->setFocus(); connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged, @@ -96,8 +94,7 @@ void TextEdit::SlotNewTabWithContent(std::string title, this, &TextEdit::slot_save_status_to_cache_for_revovery); // set content with modified status - page->GetTextPage()->document()->setPlainText( - QString::fromStdString(content)); + page->GetTextPage()->document()->setPlainText(content); } void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const { @@ -106,10 +103,15 @@ void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const { tab_widget_->setCurrentIndex(tab_widget_->count() - 1); } -void TextEdit::SlotNewFileTab() const { - auto* page = new FilePage(qobject_cast<QWidget*>(parent())); +void TextEdit::SlotNewFileTab() { + auto const target_dir = QFileDialog::getExistingDirectory( + this, tr("Open Directory"), QDir::home().path(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (target_dir.isEmpty()) return; + + auto* page = new FilePage(qobject_cast<QWidget*>(parent()), target_dir); auto index = tab_widget_->addTab(page, QString()); - tab_widget_->setTabIcon(index, QIcon(":file-browser.png")); + tab_widget_->setTabIcon(index, QIcon(":/icons/file-browser.png")); tab_widget_->setCurrentIndex(tab_widget_->count() - 1); connect(page, &FilePage::SignalPathChanged, this, &TextEdit::slot_file_page_path_changed); @@ -118,7 +120,8 @@ void TextEdit::SlotNewFileTab() const { void TextEdit::SlotOpenFile(const QString& path) { QFile file(path); - SPDLOG_DEBUG("path: {}", path.toStdString()); + GF_UI_LOG_DEBUG("main window editor is opening file at path: {}", + path.toStdString()); auto result = file.open(QIODevice::ReadOnly | QIODevice::Text); if (result) { auto* page = new PlainTextEditorPage(path); @@ -131,17 +134,15 @@ void TextEdit::SlotOpenFile(const QString& path) { QApplication::setOverrideCursor(Qt::WaitCursor); auto index = tab_widget_->addTab(page, stripped_name(path)); - tab_widget_->setTabIcon(index, QIcon(":file.png")); + tab_widget_->setTabIcon(index, QIcon(":/icons/file.png")); tab_widget_->setCurrentIndex(tab_widget_->count() - 1); QApplication::restoreOverrideCursor(); page->GetTextPage()->setFocus(); page->ReadFile(); } else { - QMessageBox::warning(this, _("Warning"), - (boost::format(_("Cannot read file %1%:\n%2%.")) % - path.toStdString() % file.errorString().toStdString()) - .str() - .c_str()); + QMessageBox::warning( + this, tr("Warning"), + tr("Cannot read file %1:\n%2.").arg(path).arg(file.errorString())); } file.close(); @@ -149,7 +150,7 @@ void TextEdit::SlotOpenFile(const QString& path) { void TextEdit::SlotOpen() { QStringList file_names = - QFileDialog::getOpenFileNames(this, _("Open file"), QDir::currentPath()); + QFileDialog::getOpenFileNames(this, tr("Open file"), QDir::currentPath()); for (const auto& file_name : file_names) { if (!file_name.isEmpty()) { SlotOpenFile(file_name); @@ -162,14 +163,14 @@ void TextEdit::SlotSave() { return; } - QString fileName = SlotCurPageTextEdit()->GetFilePath(); + QString file_name = SlotCurPageTextEdit()->GetFilePath(); - if (fileName.isEmpty()) { + if (file_name.isEmpty()) { // QString docname = tabWidget->tabText(tabWidget->currentIndex()); // docname.remove(0,2); SlotSaveAs(); } else { - save_file(fileName); + save_file(file_name); } } @@ -181,54 +182,31 @@ bool TextEdit::save_file(const QString& fileName) { PlainTextEditorPage* page = SlotCurPageTextEdit(); if (page == nullptr) return false; - if (page->WillCharsetChange()) { - auto result = QMessageBox::warning( - this, _("Save"), - QString("<p>") + - _("After saving, the encoding of the current file will be " - "converted to UTF-8 and the line endings will be changed to " - "LF. ") + - "</p>" + "<p>" + - _("If this is not the result you expect, please use \"save " - "as\".") + - "</p>", - QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel); - - if (result == QMessageBox::Cancel) { - return false; - } - } - QFile file(fileName); - if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream outputStream(&file); + QTextStream output_stream(&file); QApplication::setOverrideCursor(Qt::WaitCursor); - outputStream << page->GetTextPage()->toPlainText(); + output_stream << page->GetTextPage()->toPlainText(); QApplication::restoreOverrideCursor(); QTextDocument* document = page->GetTextPage()->document(); document->setModified(false); - int curIndex = tab_widget_->currentIndex(); - tab_widget_->setTabText(curIndex, stripped_name(fileName)); + int cur_index = tab_widget_->currentIndex(); + tab_widget_->setTabText(cur_index, stripped_name(fileName)); page->SetFilePath(fileName); page->NotifyFileSaved(); file.close(); return true; - } else { - QMessageBox::warning( - this, _("Warning"), - (boost::format(_("Cannot read file %1%:\n%2%.")) % - fileName.toStdString() % file.errorString().toStdString()) - .str() - .c_str()); - return false; } + QMessageBox::warning( + this, tr("Warning"), + tr("Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString())); + return false; } -bool TextEdit::SlotSaveAs() { +auto TextEdit::SlotSaveAs() -> bool { if (tab_widget_->count() == 0 || SlotCurPageTextEdit() == nullptr) { return true; } @@ -241,8 +219,7 @@ bool TextEdit::SlotSaveAs() { path = tab_widget_->tabText(tab_widget_->currentIndex()).remove(0, 2); } - QString fileName = QFileDialog::getSaveFileName(this, _("Save file"), path); - return save_file(fileName); + return save_file(QFileDialog::getSaveFileName(this, tr("Save file"), path)); } void TextEdit::SlotCloseTab() { @@ -303,13 +280,13 @@ bool TextEdit::maybe_save_current_tab(bool askToSave) { const QString& file_path = page->GetFilePath(); if (askToSave) { result = QMessageBox::warning( - this, _("Unsaved document"), - QString(_("The document \"%1\" has been modified. Do you want to " - "save your changes?")) + this, tr("Unsaved document"), + tr("The document \"%1\" has been modified. Do you want to " + "save your changes?") .arg(doc_name) + - "<br/><b>" + _("Note:") + "</b>" + - _("If you don't save these files, all changes are " - "lost.") + + "<br/><b>" + tr("Note:") + "</b>" + + tr("If you don't save these files, all changes are " + "lost.") + "<br/>", QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); } @@ -318,20 +295,16 @@ bool TextEdit::maybe_save_current_tab(bool askToSave) { // QString docname = tabWidget->tabText(tabWidget->currentIndex()); // docname.remove(0,2); return SlotSaveAs(); - } else { - return save_file(file_path); } - } else if (result == QMessageBox::Discard) { - return true; - } else { - return false; + return save_file(file_path); } + return result == QMessageBox::Discard; } page->deleteLater(); return true; } -bool TextEdit::MaybeSaveAnyTab() { +auto TextEdit::MaybeSaveAnyTab() -> bool { // get a list of all unsaved documents and their tabids QHash<int, QString> unsaved_docs = this->UnsavedDocuments(); @@ -346,8 +319,8 @@ bool TextEdit::MaybeSaveAnyTab() { * and show normal unsaved doc dialog */ if (unsaved_docs.size() == 1) { - int modifiedTab = unsaved_docs.keys().at(0); - tab_widget_->setCurrentIndex(modifiedTab); + int modified_tab = unsaved_docs.keys().at(0); + tab_widget_->setCurrentIndex(modified_tab); return maybe_save_current_tab(true); } @@ -355,32 +328,29 @@ bool TextEdit::MaybeSaveAnyTab() { * more than one unsaved documents */ if (unsaved_docs.size() > 1) { - QHashIterator<int, QString> i(unsaved_docs); + QHashIterator<int, QString> const i(unsaved_docs); QuitDialog* dialog; - dialog = new QuitDialog(this, unsaved_docs); - int result = dialog->exec(); + dialog = new QuitDialog( + this->parentWidget() != nullptr ? this->parentWidget() : this, + unsaved_docs); + int const result = dialog->exec(); // if result is QDialog::Rejected, discard or cancel was clicked if (result == QDialog::Rejected) { // return true, if discard is clicked, so app can be closed - if (dialog->IsDiscarded()) { - return true; - } else { - return false; - } - } else { - bool all_saved = true; - QList<int> tabIdsToSave = dialog->GetTabIdsToSave(); - - for (const auto& tabId : tabIdsToSave) { - tab_widget_->setCurrentIndex(tabId); - if (!maybe_save_current_tab(false)) { - all_saved = false; - } + return dialog->IsDiscarded(); + } + + bool all_saved = true; + QList<int> const tab_ids_to_save = dialog->GetTabIdsToSave(); + for (const auto& tab_id : tab_ids_to_save) { + tab_widget_->setCurrentIndex(tab_id); + if (!maybe_save_current_tab(false)) { + all_saved = false; } - return all_saved; } + return all_saved; } // code should never reach this statement return false; @@ -390,26 +360,30 @@ PlainTextEditorPage* TextEdit::CurTextPage() const { return qobject_cast<PlainTextEditorPage*>(tab_widget_->currentWidget()); } +void TextEdit::SlotAppendText2CurTextPage(const QString& text) { + if (CurTextPage() == nullptr) SlotNewTab(); + CurTextPage()->GetTextPage()->appendPlainText(text); +} + FilePage* TextEdit::CurFilePage() const { - auto* curFilePage = qobject_cast<FilePage*>(tab_widget_->currentWidget()); - if (curFilePage != nullptr) { - return curFilePage; - } else { - return nullptr; + auto* cur_file_page = qobject_cast<FilePage*>(tab_widget_->currentWidget()); + if (cur_file_page != nullptr) { + return cur_file_page; } + return nullptr; } int TextEdit::TabCount() const { return tab_widget_->count(); } PlainTextEditorPage* TextEdit::SlotCurPageTextEdit() const { - auto* curPage = + auto* cur_page = qobject_cast<PlainTextEditorPage*>(tab_widget_->currentWidget()); - return curPage; + return cur_page; } FilePage* TextEdit::SlotCurPageFileTreeView() const { - auto* curPage = qobject_cast<FilePage*>(tab_widget_->currentWidget()); - return curPage; + auto* cur_page = qobject_cast<FilePage*>(tab_widget_->currentWidget()); + return cur_page; } void TextEdit::SlotQuote() const { @@ -446,11 +420,8 @@ void TextEdit::LoadFile(const QString& fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning( - this, _("Warning"), - (boost::format(_("Cannot read file %1%:\n%2%.")) % - fileName.toStdString() % file.errorString().toStdString()) - .str() - .c_str()); + this, tr("Warning"), + tr("Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString())); return; } QTextStream in(&file); @@ -460,7 +431,7 @@ void TextEdit::LoadFile(const QString& fileName) { SlotCurPageTextEdit()->SetFilePath(fileName); tab_widget_->setTabText(tab_widget_->currentIndex(), stripped_name(fileName)); file.close(); - // statusBar()->showMessage(_("File loaded"), 2000); + // statusBar()->showMessage(tr("File loaded"), 2000); } QString TextEdit::stripped_name(const QString& full_file_name) { @@ -483,9 +454,13 @@ void TextEdit::SlotPrint() { if (dlg->exec() != QDialog::Accepted) { return; } - document->print(&printer); + if (document != nullptr) { + document->print(&printer); + } else { + QMessageBox::warning(this, tr("Warning"), tr("No document to print")); + } - // statusBar()->showMessage(_("Ready"), 2000); + // statusBar()->showMessage(tr("Ready"), 2000); #endif } @@ -528,22 +503,22 @@ void TextEdit::SlotSwitchTabDown() const { * return a hash of tabindexes and title of unsaved tabs */ QHash<int, QString> TextEdit::UnsavedDocuments() const { - QHash<int, QString> unsavedDocs; // this list could be used to implement - // gedit like "unsaved changed"-dialog + QHash<int, QString> unsaved_docs; // this list could be used to implement + // gedit like "unsaved changed"-dialog for (int i = 0; i < tab_widget_->count(); i++) { auto* ep = qobject_cast<PlainTextEditorPage*>(tab_widget_->widget(i)); if (ep != nullptr && ep->ReadDone() && ep->GetTextPage()->document()->isModified()) { QString doc_name = tab_widget_->tabText(i); - SPDLOG_DEBUG("unsaved: {}", doc_name.toStdString()); + GF_UI_LOG_DEBUG("unsaved: {}", doc_name.toStdString()); // remove * before name of modified doc doc_name.remove(0, 2); - unsavedDocs.insert(i, doc_name); + unsaved_docs.insert(i, doc_name); } } - return unsavedDocs; + return unsaved_docs; } void TextEdit::SlotCut() const { @@ -617,42 +592,38 @@ void TextEdit::SlotSelectAll() const { void TextEdit::slot_file_page_path_changed(const QString& path) const { int index = tab_widget_->currentIndex(); - QString mPath; - QFileInfo fileInfo(path); - QString tPath = fileInfo.absoluteFilePath(); + QString m_path; + QFileInfo file_info(path); + QString t_path = file_info.absoluteFilePath(); if (path.size() > 18) { - mPath = tPath.mid(tPath.size() - 18, 18).prepend("..."); + m_path = t_path.mid(t_path.size() - 18, 18).prepend("..."); } else { - mPath = tPath; + m_path = t_path; } - tab_widget_->setTabText(index, mPath); + tab_widget_->setTabText(index, m_path); } void TextEdit::slot_save_status_to_cache_for_revovery() { if (this->text_page_data_modified_count_++ % 8 != 0) return; - auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); - bool restore_text_editor_page = false; - try { - restore_text_editor_page = - settings.lookup("general.restore_text_editor_page"); - } catch (...) { - SPDLOG_ERROR("setting operation error: restore_text_editor_page"); - } + auto settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetSettings(); + bool restore_text_editor_page = + settings.value("basic/restore_text_editor_page", false).toBool(); if (!restore_text_editor_page) { - SPDLOG_DEBUG("restore_text_editor_page is false, ignoring..."); + GF_UI_LOG_DEBUG("restore_text_editor_page is false, ignoring..."); return; } int tab_count = tab_widget_->count(); - SPDLOG_DEBUG( + GF_UI_LOG_DEBUG( "restore_text_editor_page is true, pan to save pages, current tabs " "count: " "{}", tab_count); - std::vector<std::tuple<int, std::string, std::string>> unsaved_pages; + std::vector<std::tuple<int, QString, QString>> unsaved_pages; for (int i = 0; i < tab_count; i++) { auto* target_page = @@ -664,31 +635,31 @@ void TextEdit::slot_save_status_to_cache_for_revovery() { } auto* document = target_page->GetTextPage()->document(); - auto tab_title = tab_widget_->tabText(i).toStdString(); + auto tab_title = tab_widget_->tabText(i); if (!target_page->ReadDone() || !target_page->isEnabled() || !document->isModified()) { continue; } - auto raw_text = document->toRawText().toStdString(); - SPDLOG_DEBUG("unsaved page index: {}, tab title: {} tab content: {}", i, - tab_title, raw_text.size()); - unsaved_pages.push_back({i, tab_title, raw_text}); + auto raw_text = document->toRawText(); + GF_UI_LOG_DEBUG("unsaved page index: {}, tab title: {}", i, tab_title); + unsaved_pages.emplace_back(i, tab_title, raw_text); } - nlohmann::json unsaved_page_array = nlohmann::json::array(); + CacheObject cache("editor_unsaved_pages"); + QJsonArray unsaved_page_array; for (const auto& page : unsaved_pages) { - nlohmann::json page_json; - page_json["index"] = std::get<0>(page); - page_json["title"] = std::get<1>(page); - page_json["content"] = std::get<2>(page); + const auto [index, title, content] = page; + + QJsonObject page_json; + page_json["index"] = index; + page_json["title"] = title; + page_json["content"] = content; unsaved_page_array.push_back(page_json); } - SPDLOG_DEBUG("unsaved page json array: {}", unsaved_page_array.dump()); - CacheManager::GetInstance().SaveCache("editor_unsaved_pages", - unsaved_page_array); + cache.setArray(unsaved_page_array); } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h index f69bda4c..cba1c6e4 100644 --- a/src/ui/widgets/TextEdit.h +++ b/src/ui/widgets/TextEdit.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __TEXTEDIT_H__ -#define __TEXTEDIT_H__ +#pragma once #include "ui/dialog/QuitDialog.h" #include "ui/widgets/FilePage.h" @@ -154,7 +153,7 @@ class TextEdit : public QWidget { * @details * */ - void SlotNewTabWithContent(std::string title, const std::string& content); + void SlotNewTabWithContent(QString title, const QString& content); /** * @details Adds a new tab with opening file by path @@ -172,7 +171,7 @@ class TextEdit : public QWidget { /** * New File Tab to do file operation */ - void SlotNewFileTab() const; + void SlotNewFileTab(); /** * @details put a * in front of current tabs title, if current textedit is @@ -283,6 +282,13 @@ class TextEdit : public QWidget { */ void SlotSelectAll() const; + /** + * @brief + * + * @param text + */ + void SlotAppendText2CurTextPage(const QString& text); + protected: /** * @brief Saves the content of currentTab to the file filename @@ -293,5 +299,3 @@ class TextEdit : public QWidget { }; } // namespace GpgFrontend::UI - -#endif // __TEXTEDIT_H__ diff --git a/src/ui/widgets/VerifyKeyDetailBox.cpp b/src/ui/widgets/VerifyKeyDetailBox.cpp index 192b09f3..c2dd74d3 100644 --- a/src/ui/widgets/VerifyKeyDetailBox.cpp +++ b/src/ui/widgets/VerifyKeyDetailBox.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,7 +20,7 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,8 +28,10 @@ #include "ui/widgets/VerifyKeyDetailBox.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/utils/CommonUtils.h" namespace GpgFrontend::UI { @@ -43,21 +45,23 @@ VerifyKeyDetailBox::VerifyKeyDetailBox(const GpgSignature& signature, this->setTitle("A Error Signature"); bool forbid_all_gnupg_connection = - GlobalSettingStation::GetInstance().LookupSettings( - "network.forbid_all_gnupg_connection", false); + GlobalSettingStation::GetInstance() + .GetSettings() + .value("network/forbid_all_gnupg_connection", false) + .toBool(); - auto* import_button = new QPushButton(_("Import from keyserver")); + auto* import_button = new QPushButton(tr("Import from keyserver")); import_button->setDisabled(forbid_all_gnupg_connection); connect(import_button, &QPushButton::clicked, this, &VerifyKeyDetailBox::slot_import_form_key_server); - this->setTitle(QString(_("Key not present with id 0x")) + fpr_.c_str()); + this->setTitle(tr("Key not present with id 0x") + fpr_); - auto grid = new QGridLayout(); + auto* grid = new QGridLayout(); - grid->addWidget(new QLabel(QString(_("Status")) + _(":")), 0, 0); - // grid->addWidget(new QLabel(_("Fingerprint:")), 1, 0); - grid->addWidget(new QLabel(_("Key not present in key list")), 0, 1); + grid->addWidget(new QLabel(tr("Status") + tr(":")), 0, 0); + // grid->addWidget(new QLabel(tr("Fingerprint:")), 1, 0); + grid->addWidget(new QLabel(tr("Key not present in key list")), 0, 1); // grid->addWidget(new QLabel(signature->fpr), 1, 1); grid->addWidget(import_button, 2, 0, 2, 1); @@ -65,96 +69,91 @@ VerifyKeyDetailBox::VerifyKeyDetailBox(const GpgSignature& signature, break; } case GPG_ERR_NO_ERROR: { - this->setTitle(QString(_("A Signature")) + ":"); - auto gird = create_key_info_grid(signature); + this->setTitle(tr("A Signature") + ":"); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; } case GPG_ERR_CERT_REVOKED: { this->setTitle("An Error Signature"); - vbox->addWidget( - new QLabel(QString(_("Status")) + ":" + _("Cert Revoked"))); - auto gird = create_key_info_grid(signature); + vbox->addWidget(new QLabel(tr("Status") + ":" + tr("Cert Revoked"))); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; } case GPG_ERR_SIG_EXPIRED: { this->setTitle("An Error Signature"); - vbox->addWidget( - new QLabel(QString(_("Status")) + ":" + _("Signature Expired"))); - auto gird = create_key_info_grid(signature); + vbox->addWidget(new QLabel(tr("Status") + ":" + tr("Signature Expired"))); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; } case GPG_ERR_KEY_EXPIRED: { this->setTitle("An Error Signature"); - vbox->addWidget( - new QLabel(QString(_("Status")) + ":" + _("Key Expired"))); - vbox->addWidget( - new QLabel(QString(_("Status")) + ":" + _("Key Expired"))); - auto gird = create_key_info_grid(signature); + vbox->addWidget(new QLabel(tr("Status") + ":" + tr("Key Expired"))); + vbox->addWidget(new QLabel(tr("Status") + ":" + tr("Key Expired"))); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; } case GPG_ERR_GENERAL: { this->setTitle("An Error Signature"); - vbox->addWidget( - new QLabel(QString(_("Status")) + ":" + _("General Error"))); - auto gird = create_key_info_grid(signature); + vbox->addWidget(new QLabel(tr("Status") + ":" + tr("General Error"))); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; } default: { this->setTitle("An Error Signature"); - this->setTitle(QString(_("Status")) + ":" + _("Unknown Error ")); - auto gird = create_key_info_grid(signature); + this->setTitle(tr("Status") + ":" + tr("Unknown Error ")); + auto* gird = create_key_info_grid(signature); if (gird != nullptr) { vbox->addLayout(gird); } else { - vbox->addWidget(new QLabel(_("Key Information is NOT Available"))); - if (!signature.GetFingerprint().empty()) { - vbox->addWidget(new QLabel(QString(_("Fingerprint")) + ": " + - signature.GetFingerprint().c_str())); + vbox->addWidget(new QLabel(tr("Key Information is NOT Available"))); + if (!signature.GetFingerprint().isEmpty()) { + vbox->addWidget(new QLabel(tr("Fingerprint") + ": " + + signature.GetFingerprint())); } } break; @@ -164,59 +163,60 @@ VerifyKeyDetailBox::VerifyKeyDetailBox(const GpgSignature& signature, } void VerifyKeyDetailBox::slot_import_form_key_server() { - auto* importDialog = new KeyServerImportDialog(false, this); + auto* import_dialog = new KeyServerImportDialog(this); auto key_ids = std::make_unique<KeyIdArgsList>(); key_ids->push_back(fpr_); - importDialog->SlotImport(key_ids); + import_dialog->SlotImport(key_ids); } -QGridLayout* VerifyKeyDetailBox::create_key_info_grid( - const GpgSignature& signature) { - auto grid = new QGridLayout(); - GpgKey key = GpgKeyGetter::GetInstance().GetKey(fpr_); +auto VerifyKeyDetailBox::create_key_info_grid(const GpgSignature& signature) + -> QGridLayout* { + auto* grid = new QGridLayout(); + auto key = GpgKeyGetter::GetInstance().GetKey(fpr_); if (!key.IsGood()) return nullptr; - grid->addWidget(new QLabel(QString(_("Signer Name")) + ":"), 0, 0); - grid->addWidget(new QLabel(QString(_("Signer Email")) + ":"), 1, 0); - grid->addWidget(new QLabel(QString(_("Key's Fingerprint")) + ":"), 2, 0); - grid->addWidget(new QLabel(QString(_("Valid")) + ":"), 3, 0); - grid->addWidget(new QLabel(QString(_("Flags")) + ":"), 4, 0); - - grid->addWidget(new QLabel(QString::fromStdString(key.GetName())), 0, 1); - grid->addWidget(new QLabel(QString::fromStdString(key.GetEmail())), 1, 1); - grid->addWidget(new QLabel(beautify_fingerprint(fpr_).c_str()), 2, 1); - - if (signature.GetSummary() & GPGME_SIGSUM_VALID) { - grid->addWidget(new QLabel(_("Fully Valid")), 3, 1); + grid->addWidget(new QLabel(tr("Signer Name") + ":"), 0, 0); + grid->addWidget(new QLabel(tr("Signer Email") + ":"), 1, 0); + grid->addWidget(new QLabel(tr("Key's Fingerprint") + ":"), 2, 0); + grid->addWidget(new QLabel(tr("Valid") + ":"), 3, 0); + grid->addWidget(new QLabel(tr("Flags") + ":"), 4, 0); + + grid->addWidget(new QLabel(key.GetName()), 0, 1); + grid->addWidget(new QLabel(key.GetEmail()), 1, 1); + grid->addWidget(new QLabel(BeautifyFingerprint(fpr_)), 2, 1); + + if ((signature.GetSummary() & GPGME_SIGSUM_VALID) != 0U) { + grid->addWidget(new QLabel(tr("Fully Valid")), 3, 1); } else { - grid->addWidget(new QLabel(_("NOT Fully Valid")), 3, 1); + grid->addWidget(new QLabel(tr("NOT Fully Valid")), 3, 1); } - std::stringstream text_stream; + QString buffer; + QTextStream text_stream(&buffer); - if (signature.GetSummary() & GPGME_SIGSUM_GREEN) { - text_stream << _("Good") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_GREEN) != 0U) { + text_stream << tr("Good") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_RED) { - text_stream << _("Bad") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_RED) != 0U) { + text_stream << tr("Bad") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_SIG_EXPIRED) { - text_stream << _("Expired") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_SIG_EXPIRED) != 0U) { + text_stream << tr("Expired") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_KEY_MISSING) { - text_stream << _("Missing Key") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_KEY_MISSING) != 0U) { + text_stream << tr("Missing Key") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_KEY_REVOKED) { - text_stream << _("Revoked Key") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_KEY_REVOKED) != 0U) { + text_stream << tr("Revoked Key") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_KEY_EXPIRED) { - text_stream << _("Expired Key") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_KEY_EXPIRED) != 0U) { + text_stream << tr("Expired Key") << " "; } - if (signature.GetSummary() & GPGME_SIGSUM_CRL_MISSING) { - text_stream << _("Missing CRL") << " "; + if ((signature.GetSummary() & GPGME_SIGSUM_CRL_MISSING) != 0U) { + text_stream << tr("Missing CRL") << " "; } - grid->addWidget(new QLabel(text_stream.str().c_str()), 4, 1); + grid->addWidget(new QLabel(text_stream.readAll()), 4, 1); return grid; } diff --git a/src/ui/widgets/VerifyKeyDetailBox.h b/src/ui/widgets/VerifyKeyDetailBox.h index 6ed9fd52..4885fdda 100644 --- a/src/ui/widgets/VerifyKeyDetailBox.h +++ b/src/ui/widgets/VerifyKeyDetailBox.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Saturneric + * Copyright (C) 2021 Saturneric <[email protected]> * * This file is part of GpgFrontend. * @@ -20,14 +20,13 @@ * the gpg4usb project, which is under GPL-3.0-or-later. * * All the source code of GpgFrontend was modified and released by - * Saturneric<[email protected]> starting on May 12, 2021. + * Saturneric <[email protected]> starting on May 12, 2021. * * SPDX-License-Identifier: GPL-3.0-or-later * */ -#ifndef __VERIFYKEYDETAILBOX_H__ -#define __VERIFYKEYDETAILBOX_H__ +#pragma once #include "ui/dialog/import_export/KeyServerImportDialog.h" #include "ui/widgets/KeyList.h" @@ -65,9 +64,7 @@ class VerifyKeyDetailBox : public QGroupBox { */ QGridLayout* create_key_info_grid(const GpgSignature& signature); - std::string fpr_; ///< fingerprint of the key + QString fpr_; ///< fingerprint of the key }; } // namespace GpgFrontend::UI - -#endif // __VERIFYKEYDETAILBOX_H__ |