diff --git a/CMakeLists.txt b/CMakeLists.txt index 456203a..6a016c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,10 @@ IF(POLICY CMP0054) CMAKE_POLICY(SET CMP0054 NEW) ENDIF() +IF(POLICY CMP0063) + CMAKE_POLICY(SET CMP0063 NEW) +ENDIF() + # "tools.only" can be defined to disable the normal build and enable # cmdline "tools" only. For example: "make format" or "make package_source" IF(tools.only) @@ -25,7 +29,7 @@ ELSE() ENDIF() -PROJECT(AusweisApp2 VERSION 1.10.3 LANGUAGES ${LANGUAGES}) +PROJECT(AusweisApp2 VERSION 1.12.2 LANGUAGES ${LANGUAGES}) # Set TWEAK if not defined in PROJECT_VERSION above to # have a valid tweak version without propagating it diff --git a/Doxyfile.in b/Doxyfile.in index be40873..7c4633f 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -36,7 +36,7 @@ CALL_GRAPH = YES CALLER_GRAPH = YES GRAPHICAL_HIERARCHY = NO DIRECTORY_GRAPH = NO -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg INTERACTIVE_SVG = NO DOT_GRAPH_MAX_NODES = 50 diff --git a/LICENSE.txt b/LICENSE.txt index b306c7e..3bb7c6e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -44,7 +44,7 @@ Auf diese Nutzungsbedingungen ist ausschließlich deutsches Recht unter Ausschlu Anhang Eingearbeitete Open Source-Komponenten -Qt, OpenSSL, http_parser, Qhttpserver und Fervor. +Qt, OpenSSL und http_parser. @@ -466,7 +466,7 @@ Die verwendeten OpenSource-Bibliotheken unterliegen den folgenden Nutzungsbeding Qt Lizenz: LGPL v3 - Version: 5.7.0 + Version: 5.8.0 Adresse: https://www.qt.io/ http_parser @@ -474,16 +474,6 @@ http_parser Version: 2.7.1 Adresse: https://github.com/nodejs/http-parser/ -qhttpserver - Lizenz: MIT - Version: 0.1.0 - Adresse: https://github.com/nikhilm/qhttpserver/ - -fervor - Lizenz: MIT - Version: 9980f27 - Adresse: https://github.com/pypt/fervor/ - Die Lizenztexte lauten in ihrer originalen Fassung wie folgt: @@ -694,41 +684,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - - - - -Copyright (c) 2012 Linas Valiukas and others. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - - - - -Copyright (C) 2011-2014 Nikhil Marathe - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/README.rst b/README.rst index bd7f017..20b52dd 100644 --- a/README.rst +++ b/README.rst @@ -112,7 +112,7 @@ Parameter notwendig um das APK zu signieren. -DAPK_SIGN_KEYSTORE_PSW=123456 Wie schon bei der Toolchain wird standardmäßig die Architektur "armeabi-v7a" verwendet. -Dies kann mittels CMake Parameter "-DANDROID_ABI=x86" verändert werden. +Dies kann mittels CMake Parameter "-DCMAKE_ANDROID_ARCH_ABI=x86" verändert werden. diff --git a/cmake/AndroidNdkGdb.cmake b/cmake/AndroidNdkGdb.cmake deleted file mode 100644 index b9102c7..0000000 --- a/cmake/AndroidNdkGdb.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2014, Pavel Rojtberg -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -# ------------------------------------------------------------------------------ - -macro(android_ndk_gdb_enable) - if(ANDROID) - # create custom target that depends on the real target so it gets executed afterwards - add_custom_target(NDK_GDB ALL) - - set(NDK_GDB_SOLIB_PATH ${PROJECT_BINARY_DIR}/dist/obj/local/${ANDROID_NDK_ABI_NAME}/) - file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH}) - - # 1. generate essential Android Makefiles - file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/dist/jni) - if(NOT EXISTS ${PROJECT_BINARY_DIR}/dist/jni/Android.mk) - file(WRITE ${PROJECT_BINARY_DIR}/dist/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") - endif() - if(NOT EXISTS ${PROJECT_BINARY_DIR}/dist/jni/Application.mk) - file(WRITE ${PROJECT_BINARY_DIR}/dist/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") - endif() - - # 2. generate gdb.setup - get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES) - string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}") - - file(WRITE ${PROJECT_BINARY_DIR}/dist/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n") - file(APPEND ${PROJECT_BINARY_DIR}/dist/libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "directory ${PROJECT_INCLUDES}\n") - endif() -endmacro() - -macro(android_ndk_gdb_debuggable TARGET_NAME) - if(ANDROID) - # create custom target that depends on the real target so it gets executed afterwards - add_dependencies(NDK_GDB ${TARGET_NAME}) - add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${NDK_GDB_SOLIB_PATH}) - endif() -endmacro() diff --git a/cmake/Appcast.cmake b/cmake/Appcast.cmake index 4494153..59b75ea 100644 --- a/cmake/Appcast.cmake +++ b/cmake/Appcast.cmake @@ -6,33 +6,38 @@ IF(MAC OR LINUX OR WIN32) ENDIF() MACRO(ADD_APPCAST_FILE _files _system) + SET(HASHFILE_ENDING "sha256") + STRING(TIMESTAMP APPCAST_DATE "%Y-%m-%dT%H:%M:%S") + FOREACH(filePath ${_files}) FILE_SIZE(fileSize ${filePath}) + GET_FILENAME_COMPONENT(file ${filePath} NAME) + IF(NOT DEFINED fileSize) MESSAGE(FATAL_ERROR "Cannot get file size of: ${file}") ENDIF() - GET_FILENAME_COMPONENT(file ${filePath} NAME) MESSAGE(STATUS "Processing: ${file}") IF(NOT "${_system}" STREQUAL "SOURCES") - FILE(READ ${PACKAGING_DIR}/updater/Appcast.item.xml.in item) + FILE(READ ${PACKAGING_DIR}/updater/Appcast.item.json.in item) STRING(REPLACE "AusweisApp2-" "" APPCAST_FILE_VERSION ${file}) STRING(REPLACE ".dmg" "" APPCAST_FILE_VERSION ${APPCAST_FILE_VERSION}) STRING(REPLACE ".msi" "" APPCAST_FILE_VERSION ${APPCAST_FILE_VERSION}) - STRING(TIMESTAMP currentDate "%Y-%m-%dT%H:%M:%S") - STRING(REPLACE "APPCAST_DATE" ${currentDate} item ${item}) - STRING(REPLACE "APPCAST_DOWNLOAD_URL" "${APPCAST_URL}/${file}" item ${item}) + STRING(REPLACE "APPCAST_DATE" "${APPCAST_DATE}" item ${item}) + STRING(REPLACE "APPCAST_PLATFORM" ${_system} item ${item}) STRING(REPLACE "APPCAST_VERSION" "${APPCAST_FILE_VERSION}" item ${item}) - STRING(REPLACE "APPCAST_OS" ${_system} item ${item}) - STRING(REPLACE "APPCAST_PACKAGE_SIZE" "${fileSize}" item ${item}) - STRING(REPLACE "APPCAST_URL" "${APPCAST_URL}" item ${item}) - SET(APPCAST_ITEMS "${APPCAST_ITEMS}\n${item}") + STRING(REPLACE "APPCAST_URL" "${APPCAST_URL}/${file}" item ${item}) + STRING(REPLACE "APPCAST_SIZE" "${fileSize}" item ${item}) + STRING(REPLACE "APPCAST_CHECKSUM" "${APPCAST_URL}/${file}.${HASHFILE_ENDING}" item ${item}) + STRING(REPLACE "APPCAST_NOTES" "${APPCAST_URL}/ReleaseNotes.html#${APPCAST_FILE_VERSION}" item ${item}) + + SET(APPCAST_ITEMS "${APPCAST_ITEMS}${item},") ENDIF() FILE(SHA256 ${filePath} fileHash) - FILE(WRITE ${filePath}.sha256 "${fileHash} ${file}\n") + FILE(WRITE ${filePath}.${HASHFILE_ENDING} "${fileHash} ${file}\n") ENDFOREACH() ENDMACRO() @@ -54,7 +59,8 @@ IF(MAC OR LINUX OR WIN32) ENDIF() IF(APPCAST_ITEMS) - CONFIGURE_FILE(${PACKAGING_DIR}/updater/Appcast.xml.in ${PROJECT_BINARY_DIR}/Appcast.xml @ONLY) + STRING(REGEX REPLACE ",$" "" APPCAST_ITEMS "${APPCAST_ITEMS}") + CONFIGURE_FILE(${PACKAGING_DIR}/updater/Appcast.json.in ${PROJECT_BINARY_DIR}/Appcast.json @ONLY) ENDIF() ENDIF() diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 7aac825..0694de2 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -5,6 +5,7 @@ ADD_DEFINITIONS(-DQT_NO_CAST_TO_ASCII) ADD_DEFINITIONS(-DQT_RESTRICTED_CAST_FROM_ASCII) ADD_DEFINITIONS(-DQT_NO_FOREACH) ADD_DEFINITIONS(-DQT_NO_KEYWORDS) +ADD_DEFINITIONS(-DQT_NO_EXCEPTIONS) IF(QT_VENDOR STREQUAL "Governikus") ADD_DEFINITIONS(-DGOVERNIKUS_QT) @@ -30,11 +31,13 @@ IF(MSVC) ELSE() ADD_DEFINITIONS(-DQT_STRICT_ITERATORS) + STRING(REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wcast-qual -Wshadow -Wvla") + ADD_FLAG(-fno-exceptions) ADD_FLAG(-fstack-protector-strong -fstack-protector) ADD_FLAG(-fuse-ld=gold VAR CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS LINK -fuse-ld=gold) - ADD_FLAG(-Wfloat-conversion) + ADD_FLAG(-Wconversion) ADD_FLAG(-Wloop-analysis) ADD_FLAG(-Wlogical-op) ADD_FLAG(-Wmisleading-indentation) @@ -43,6 +46,17 @@ ELSE() ADD_FLAG(-Wcovered-switch-default) ADD_FLAG(-Wno-gnu-zero-variadic-macro-arguments) # Qt (qDebug) is not compatible + IF(ANDROID) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-limit=64") + SET(CMAKE_CXX_VISIBILITY_PRESET hidden) + ENDIF() + + IF("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + ADD_FLAG(-flto VAR CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS LINK -flto) + ENDIF() + + IF(WARNINGS_ARE_ERRORS AND NOT CMAKE_GENERATOR STREQUAL Xcode) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") ENDIF() @@ -58,10 +72,12 @@ ELSE() SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0") - IF(SANITIZER STREQUAL "address") - ADD_FLAG("-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls" LINK -fsanitize=address) - ELSEIF(SANITIZER STREQUAL "undefined") - ADD_FLAG("-fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls" LINK -fsanitize=undefined) + IF(SANITIZER) + IF(CMAKE_COMPILER_IS_GNUCXX) + ADD_FLAG("-fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls" LINK -fsanitize=address -fsanitize=undefined) + ELSE() + ADD_FLAG("-fsanitize=address -fsanitize=undefined -fsanitize=unsigned-integer-overflow -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-optimize-sibling-calls" LINK -fsanitize=address -fsanitize=undefined) + ENDIF() ENDIF() ENDIF() diff --git a/cmake/DVCS.cmake b/cmake/DVCS.cmake index 12c906f..9a970cf 100644 --- a/cmake/DVCS.cmake +++ b/cmake/DVCS.cmake @@ -110,3 +110,17 @@ IF(DVCS_FOUND) CHECK_DVCS() ENDIF() ENDIF() + +FUNCTION(CHECK_VERSION _out) + IF(PROJECT_VERSION_MINOR) + MATH(EXPR _odd "${PROJECT_VERSION_MINOR} % 2") + IF(_odd OR dvcs_revision) + SET(${_out} TRUE PARENT_SCOPE) + RETURN() + ENDIF() + ENDIF() + + SET(${_out} FALSE PARENT_SCOPE) +ENDFUNCTION() + +CHECK_VERSION(IS_DEVELOPER_VERSION) diff --git a/cmake/Helper.cmake b/cmake/Helper.cmake index e8c1b14..44d3945 100644 --- a/cmake/Helper.cmake +++ b/cmake/Helper.cmake @@ -87,10 +87,6 @@ FUNCTION(GET_FILE_EXTENSIONS _result) cmake_parse_arguments(_PARAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) SET(FILE_EXTENSIONS *.cpp) - OPTION(WITH_HEADER "Add header to target; only useful for some IDEs" OFF) - IF(WITH_HEADER) - LIST(APPEND FILE_EXTENSIONS *.h) - ENDIF() IF(IOS) LIST(APPEND FILE_EXTENSIONS *.m *.mm) ENDIF() @@ -257,7 +253,7 @@ IF(UNIX AND NOT ANDROID AND NOT APPLE AND NOT CYGWIN AND NOT BSD) SET(LINUX true) ENDIF() -IF(LINUX OR WIN32 OR MAC OR CYGWIN OR BSD) +IF((WIN32 AND NOT WINDOWS_STORE) OR LINUX OR MAC OR CYGWIN OR BSD) SET(DESKTOP true) ENDIF() diff --git a/cmake/Install.cmake b/cmake/Install.cmake index b5705a1..0ee00b0 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -32,12 +32,18 @@ IF(WIN32) FETCH_TARGET_LOCATION(libSvg "Qt5::Svg") FETCH_TARGET_LOCATION(pluginSvg "Qt5::QSvgPlugin") FETCH_TARGET_LOCATION(pluginGif "Qt5::QGifPlugin") - FETCH_TARGET_LOCATION(platformWin "Qt5::QWindowsIntegrationPlugin") + FETCH_TARGET_LOCATION(pluginJpeg "Qt5::QJpegPlugin") + IF(WINDOWS_STORE) + FETCH_TARGET_LOCATION(platformWin "Qt5::QWinRTIntegrationPlugin") + ELSE() + FETCH_TARGET_LOCATION(platformWin "Qt5::QWindowsIntegrationPlugin") + ENDIF() INSTALL(TARGETS AusweisApp DESTINATION . COMPONENT Application) INSTALL(FILES ${libSvg} DESTINATION . COMPONENT Runtime) INSTALL(FILES ${pluginSvg} DESTINATION imageformats COMPONENT Runtime) INSTALL(FILES ${pluginGif} DESTINATION imageformats COMPONENT Runtime) + INSTALL(FILES ${pluginJpeg} DESTINATION imageformats COMPONENT Runtime) INSTALL(FILES ${platformWin} DESTINATION platforms COMPONENT Runtime) INSTALL(CODE @@ -52,6 +58,7 @@ IF(WIN32) ELSEIF(APPLE AND NOT IOS) SET(MACOS_BUNDLE_PLUGINS_DIR ../PlugIns) SET(MACOS_BUNDLE_FRAMEWORKS_DIR ../Frameworks) + SET(MACOS_BUNDLE_RESOURCES_DIR ../Resources) # We need to include the following (i.e. all) image format plug-ins, # since those seem to be loaded upon program start-up. Not including @@ -73,6 +80,19 @@ ELSEIF(APPLE AND NOT IOS) ENDFOREACH() ENDFOREACH() + FOREACH(entry QtQuick QtQuick.2 QtQml QtGraphicalEffects Qt) + SET(_dir "${QT_HOST_PREFIX}/qml") + FILE(GLOB_RECURSE DYLIB "${_dir}/${entry}/*.dylib") + FOREACH(_lib ${DYLIB}) + FILE(RELATIVE_PATH _lib_dest "${_dir}" "${_lib}") + IF(NOT _lib_dest MATCHES "XmlListModel|Particles.2|LocalStorage") # blacklist not needed stuff + GET_FILENAME_COMPONENT(_lib_dest_dir ${_lib_dest} DIRECTORY) + INSTALL(FILES ${_lib} DESTINATION ${MACOS_BUNDLE_RESOURCES_DIR}/qml_stationary/${_lib_dest_dir} COMPONENT Runtime) + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Resources/qml_stationary/${_lib_dest}") + ENDIF() + ENDFOREACH() + ENDFOREACH() + INSTALL(TARGETS AusweisApp DESTINATION . COMPONENT Application) INSTALL(FILES ${platformMac} DESTINATION ${MACOS_BUNDLE_PLUGINS_DIR}/platforms COMPONENT Runtime) @@ -80,8 +100,9 @@ ELSEIF(APPLE AND NOT IOS) " ${SEARCH_ADDITIONAL_DIRS} file(GLOB_RECURSE QTPLUGINS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MACOS_BUNDLE_PLUGINS_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") + file(GLOB_RECURSE QtQuickPLUGINS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MACOS_BUNDLE_RESOURCES_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") INCLUDE(BundleUtilities) - FIXUP_BUNDLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}\" \"\${QTPLUGINS}\" \"${TOOLCHAIN_LIB_PATH};\${ADDITIONAL_DIRS}\") + FIXUP_BUNDLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}\" \"\${QTPLUGINS};\${QtQuickPLUGINS}\" \"${TOOLCHAIN_LIB_PATH};\${ADDITIONAL_DIRS}\") " COMPONENT Runtime) LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtCore.framework") @@ -91,11 +112,11 @@ ELSEIF(APPLE AND NOT IOS) LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtSvg.framework") LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtWidgets.framework") LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtPrintSupport.framework") - - IF(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") - LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQml.framework") - LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQuick.framework") - ENDIF() + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQml.framework") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQuick.framework") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQuickControls2.framework") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQuickTemplates2.framework") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtQuickWidgets.framework") FOREACH (OPENSSL_LIBRARY ${OPENSSL_LIBRARIES}) GET_FILENAME_COMPONENT(OPENSSL_LIBRARY_REAL ${OPENSSL_LIBRARY} REALPATH) @@ -112,27 +133,50 @@ ELSEIF(IOS) ELSEIF(ANDROID) - SET(ANDROID_DEST libs/${ANDROID_ABI}) + SET(ANDROID_PACKAGE_SRC_DIR ${PROJECT_BINARY_DIR}/package-src-dir) + SET(ANDROID_DEST libs/${CMAKE_ANDROID_ARCH_ABI}) SET(PERMISSIONS PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) INSTALL(TARGETS AusweisApp DESTINATION ${ANDROID_DEST} ${PERMISSIONS} COMPONENT Application) SET(RESOURCES_IMG_ANDROID_DIR ${RESOURCES_DIR}/images/android) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/ldpi/npa.png DESTINATION res/drawable-ldpi COMPONENT Runtime) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/mdpi/npa.png DESTINATION res/drawable-mdpi COMPONENT Runtime) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/hdpi/npa.png DESTINATION res/drawable-hdpi COMPONENT Runtime) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/xhdpi/npa.png DESTINATION res/drawable-xhdpi COMPONENT Runtime) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/xxhdpi/npa.png DESTINATION res/drawable-xxhdpi COMPONENT Runtime) - INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/xxxhdpi/npa.png DESTINATION res/drawable-xxxhdpi COMPONENT Runtime) - INSTALL(FILES ${PACKAGING_DIR}/android/nfc_tech_filter.xml DESTINATION res/xml COMPONENT Runtime) - INSTALL(FILES ${PACKAGING_DIR}/android/colors.xml DESTINATION res/values COMPONENT Runtime) + IF(IS_DEVELOPER_VERSION) + SET(ANDROID_LAUNCHER_ICON "npa_beta.png") + SET(ANDROID_PACKAGE_NAME "com.governikus.ausweisapp2.dev") + ELSE() + SET(ANDROID_LAUNCHER_ICON "npa.png") + SET(ANDROID_PACKAGE_NAME "com.governikus.ausweisapp2") + ENDIF() + + FOREACH(entry ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi) + INSTALL(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/drawable-${entry} COMPONENT Runtime RENAME npa.png) + ENDFOREACH() + + INSTALL(FILES ${PACKAGING_DIR}/android/nfc_tech_filter.xml DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/xml COMPONENT Runtime) + INSTALL(FILES ${PACKAGING_DIR}/android/styles.xml DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/values COMPONENT Runtime) FILE(GLOB_RECURSE JAVA_FILES "${SRC_DIR}/*.java") - INSTALL(FILES ${JAVA_FILES} DESTINATION src COMPONENT Runtime) - INSTALL(FILES ${PACKAGING_DIR}/android/IAusweisApp2Sdk.aidl DESTINATION src/com/governikus/ausweisapp2/ COMPONENT Runtime) - INSTALL(FILES ${PACKAGING_DIR}/android/IAusweisApp2SdkCallback.aidl DESTINATION src/com/governikus/ausweisapp2/ COMPONENT Runtime) + INSTALL(FILES ${JAVA_FILES} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/src COMPONENT Runtime) + INSTALL(FILES ${PACKAGING_DIR}/android/IAusweisApp2Sdk.aidl DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/src/com/governikus/ausweisapp2/ COMPONENT Runtime) + INSTALL(FILES ${PACKAGING_DIR}/android/IAusweisApp2SdkCallback.aidl DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/src/com/governikus/ausweisapp2/ COMPONENT Runtime) - SET(TRANSLATION_DESTINATION assets/translations) - SET(DEFAULT_FILE_DESTINATION assets) + IF(VERSION_DVCS) + SET(ANDROID_VERSION_NAME ${VERSION_DVCS}) + ELSE() + SET(ANDROID_VERSION_NAME ${PROJECT_VERSION}) + ENDIF() + CONFIGURE_FILE(${PACKAGING_DIR}/android/AndroidManifest.xml.in ${ANDROID_PACKAGE_SRC_DIR}/AndroidManifest.xml @ONLY) + + GET_FILENAME_COMPONENT(ANDROID_TOOLCHAIN_MACHINE_NAME "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}" NAME) + STRING(REGEX REPLACE "-$" "" ANDROID_TOOLCHAIN_MACHINE_NAME "${ANDROID_TOOLCHAIN_MACHINE_NAME}") + STRING(REGEX MATCH "/toolchains/(.*)/prebuilt/" _unused "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}") + STRING(REGEX REPLACE "-${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}$" "" ANDROID_TOOLCHAIN_PREFIX "${CMAKE_MATCH_1}") + + SET(ANDROID_DEPLOYMENT_SETTINGS ${PROJECT_BINARY_DIR}/libAusweisApp2.so-deployment-settings.json CACHE INTERNAL "apk deployment" FORCE) + SET(ANDROID_APP_BINARY "${CMAKE_INSTALL_PREFIX}/${ANDROID_DEST}/libAusweisApp2.so") + CONFIGURE_FILE(${PACKAGING_DIR}/android/libAusweisApp2.so-deployment-settings.json.in ${ANDROID_DEPLOYMENT_SETTINGS} @ONLY) + + SET(TRANSLATION_DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/assets/translations) + SET(DEFAULT_FILE_DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/assets) ELSEIF(UNIX) IF(BUILD_SHARED_LIBS) @@ -201,8 +245,13 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.json DESTINATION ${DEFAULT_FILE # qtlogging.ini INSTALL(FILES ${RESOURCES_DIR}/qtlogging.ini DESTINATION ${DEFAULT_FILE_DESTINATION} COMPONENT Runtime) -# qml directory -IF(IOS OR ANDROID) +# qml directories +IF(DESKTOP) + INSTALL(DIRECTORY ${RESOURCES_DIR}/qml_stationary DESTINATION ${DEFAULT_FILE_DESTINATION} COMPONENT Runtime) + FOREACH(entry QtQuick QtQuick.2 QtQml QtGraphicalEffects Qt) + INSTALL(DIRECTORY ${QT_HOST_PREFIX}/qml/${entry} DESTINATION ${DEFAULT_FILE_DESTINATION}/qml_stationary COMPONENT Runtime PATTERN "*.dylib" EXCLUDE) + ENDFOREACH() +ELSE() INSTALL(DIRECTORY ${RESOURCES_DIR}/qml DESTINATION ${DEFAULT_FILE_DESTINATION} COMPONENT Runtime) ENDIF() diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index 7a73a93..8c2e307 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -4,26 +4,27 @@ IF(MINGW)# AND CMAKE_VERSION VERSION_LESS 3.3.0) # see https://public.kitware.co SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib") ENDIF() -SET(MIN_QT_VERSION 5.7) +SET(MIN_QT_VERSION 5.8) FIND_PACKAGE(Qt5Core ${MIN_QT_VERSION} REQUIRED) FIND_PACKAGE(Qt5Network ${MIN_QT_VERSION} REQUIRED) FIND_PACKAGE(Qt5Xml ${MIN_QT_VERSION} REQUIRED) FIND_PACKAGE(Qt5Svg ${MIN_QT_VERSION} REQUIRED) -FIND_PACKAGE(Qt5PrintSupport ${MIN_QT_VERSION} REQUIRED) FIND_PACKAGE(Qt5LinguistTools ${MIN_QT_VERSION} REQUIRED) +FIND_PACKAGE(Qt5Qml ${MIN_QT_VERSION} REQUIRED) +FIND_PACKAGE(Qt5Quick ${MIN_QT_VERSION} REQUIRED) +FIND_PACKAGE(Qt5QuickControls2 ${MIN_QT_VERSION} REQUIRED) +FIND_PACKAGE(Qt5WebSockets ${MIN_QT_VERSION} REQUIRED) IF(DESKTOP) FIND_PACKAGE(Qt5Widgets ${MIN_QT_VERSION} REQUIRED) -ENDIF() + FIND_PACKAGE(Qt5QuickWidgets ${MIN_QT_VERSION} REQUIRED) + FIND_PACKAGE(Qt5PrintSupport ${MIN_QT_VERSION} REQUIRED) -IF(ANDROID OR IOS OR "${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") - FIND_PACKAGE(Qt5Qml ${MIN_QT_VERSION} REQUIRED) - FIND_PACKAGE(Qt5Quick ${MIN_QT_VERSION} REQUIRED) - FIND_PACKAGE(Qt5QuickControls2 ${MIN_QT_VERSION} REQUIRED) - FIND_PACKAGE(Qt5WebSockets ${MIN_QT_VERSION} REQUIRED) + IF(WIN32) + FIND_PACKAGE(Qt5WinExtras ${MIN_QT_VERSION} REQUIRED) + ENDIF() ENDIF() - IF(LINUX OR ANDROID OR IOS) FIND_PACKAGE(Qt5Bluetooth ${MIN_QT_VERSION} REQUIRED) ENDIF() @@ -115,4 +116,5 @@ ENDIF() IF("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") FIND_PACKAGE(Qt5Test ${MIN_QT_VERSION} REQUIRED) + FIND_PACKAGE(Qt5QuickTest ${MIN_QT_VERSION} REQUIRED) ENDIF() diff --git a/cmake/Messages.cmake b/cmake/Messages.cmake index cf503f8..302c577 100644 --- a/cmake/Messages.cmake +++ b/cmake/Messages.cmake @@ -6,22 +6,17 @@ MESSAGE(STATUS "CMAKE_LIBRARY_PATH: ${CMAKE_LIBRARY_PATH}") MESSAGE(STATUS "CMAKE_SYSTEM_PREFIX_PATH: ${CMAKE_SYSTEM_PREFIX_PATH}") MESSAGE(STATUS "CMAKE_SYSTEM_INCLUDE_PATH: ${CMAKE_SYSTEM_INCLUDE_PATH}") MESSAGE(STATUS "CMAKE_VERSION: ${CMAKE_VERSION}") +MESSAGE(STATUS "CMAKE_SYSROOT: ${CMAKE_SYSROOT}") IF(ANDROID) + MESSAGE(STATUS "CMAKE_ANDROID_NDK: ${CMAKE_ANDROID_NDK}") + MESSAGE(STATUS "CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG: ${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}") + MESSAGE(STATUS "CMAKE_ANDROID_ARCH_ABI: ${CMAKE_ANDROID_ARCH_ABI}") + MESSAGE(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}") + MESSAGE(STATUS "CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION: ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}") + MESSAGE(STATUS "ANDROID_SDK: ${ANDROID_SDK}") - - MESSAGE(STATUS "ANDROID_NDK: ${ANDROID_NDK}") - MESSAGE(STATUS "ANDROID_NDK_RELEASE: ${ANDROID_NDK_RELEASE}") - MESSAGE(STATUS "ANDROID_NDK_HOST_SYSTEM_NAME: ${ANDROID_NDK_HOST_SYSTEM_NAME}") - - MESSAGE(STATUS "ANDROID_ABI: ${ANDROID_ABI}") - MESSAGE(STATUS "ANDROID_NATIVE_API_LEVEL: ${ANDROID_NATIVE_API_LEVEL}") - MESSAGE(STATUS "ANDROID_SYSROOT: ${ANDROID_SYSROOT}") - - MESSAGE(STATUS "ANDROID_COMPILER_VERSION: ${ANDROID_COMPILER_VERSION}") - MESSAGE(STATUS "ANDROID_TOOLCHAIN_MACHINE_NAME: ${ANDROID_TOOLCHAIN_MACHINE_NAME}") - MESSAGE(STATUS "ANDROID_TOOLCHAIN_NAME: ${ANDROID_TOOLCHAIN_NAME}") - MESSAGE(STATUS "ANDROID_TOOLCHAIN_ROOT: ${ANDROID_TOOLCHAIN_ROOT}") + MESSAGE(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}") ELSEIF(IOS) MESSAGE(STATUS "CMAKE_IOS_SDK_ROOT: ${CMAKE_IOS_SDK_ROOT}") diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index f188619..203c8e6 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -4,7 +4,7 @@ SET(FILENAME ${PROJECT_NAME}-${PROJECT_VERSION}) IF(ANDROID) - SET(FILENAME ${FILENAME}-${ANDROID_ABI}) + SET(FILENAME ${FILENAME}-${CMAKE_ANDROID_ARCH_ABI}) ENDIF() IF(DEFINED dvcs_distance) @@ -160,55 +160,48 @@ ELSEIF(ANDROID) ENDIF() MESSAGE(STATUS "Using androiddeployqt: ${androiddeployqt}") - SET(ANDROID_APK_DIR ${CMAKE_INSTALL_PREFIX}) - SET(DEPLOYMENT_SETTINGS ${PROJECT_BINARY_DIR}/libAusweisApp2.so-deployment-settings.json) - SET(PACKAGE_SRC_DIR ${PROJECT_BINARY_DIR}/package-src-dir) - - IF("${ANDROID_ABI}" STREQUAL "x86") - SET(ANDROID_TOOLCHAIN_PREFIX x86) - SET(ANDROID_TOOL_PREFIX i686-linux-android) - ELSEIF("${ANDROID_ABI}" STREQUAL "armeabi-v7a") - SET(ANDROID_TOOLCHAIN_PREFIX arm-linux-androideabi) - SET(ANDROID_TOOL_PREFIX arm-linux-androideabi) - ELSEIF("${ANDROID_ABI}" STREQUAL "arm64-v8a") - SET(ANDROID_TOOLCHAIN_PREFIX aarch64-linux-android) - SET(ANDROID_TOOL_PREFIX aarch64-linux-android) - ELSE() - MESSAGE(FATAL_ERROR "Unsupported ANDROID_ABI: ${ANDROID_ABI}") - ENDIF() - - CONFIGURE_FILE(${PACKAGING_DIR}/android/AndroidManifest.xml.in ${PACKAGE_SRC_DIR}/AndroidManifest.xml @ONLY) - CONFIGURE_FILE(${PACKAGING_DIR}/android/libAusweisApp2.so-deployment-settings.json.in ${DEPLOYMENT_SETTINGS} @ONLY) + OPTION(ANDROID_USE_GRADLE "Use gradle for androiddeployqt" OFF) IF(${CMAKE_BUILD_TYPE} STREQUAL "RELEASE") IF(APK_SIGN_KEYSTORE AND APK_SIGN_KEYSTORE_ALIAS AND APK_SIGN_KEYSTORE_PSW) MESSAGE(STATUS "Release build will be signed using: ${APK_SIGN_KEYSTORE} | Alias: ${APK_SIGN_KEYSTORE_ALIAS}") SET(DEPLOY_CMD_SIGN --sign ${APK_SIGN_KEYSTORE} ${APK_SIGN_KEYSTORE_ALIAS} --storepass ${APK_SIGN_KEYSTORE_PSW} --digestalg SHA-256 --sigalg SHA256WithRSA) - SET(APK_FILE QtApp-release-signed.apk) + IF(ANDROID_USE_GRADLE) + SET(APK_FILE dist-release-signed.apk) + ELSE() + SET(APK_FILE QtApp-release-signed.apk) + ENDIF() ELSE() MESSAGE(FATAL_ERROR "Cannot sign release build! Set APK_SIGN_KEYSTORE, APK_SIGN_KEYSTORE_ALIAS and APK_SIGN_KEYSTORE_PSW!") ENDIF() ELSE() - SET(APK_FILE QtApp-debug.apk) + IF(ANDROID_USE_GRADLE) + SET(APK_FILE dist-debug.apk) + ELSE() + SET(APK_FILE QtApp-debug.apk) + ENDIF() ENDIF() - SET(DEPLOY_CMD ${androiddeployqt} --verbose --input ${DEPLOYMENT_SETTINGS} --output ${ANDROID_APK_DIR} ${DEPLOY_CMD_SIGN}) - SET(DESTINATION_APK_FILE ${CMAKE_INSTALL_PREFIX}/bin/${CPACK_PACKAGE_FILE_NAME}.apk) + SET(DEPLOY_CMD ${androiddeployqt} --verbose --input ${ANDROID_DEPLOYMENT_SETTINGS} --output ${CMAKE_INSTALL_PREFIX} ${DEPLOY_CMD_SIGN}) + IF(ANDROID_USE_GRADLE) + SET(DEPLOY_CMD ${DEPLOY_CMD} --gradle) + SET(SOURCE_APK_FILE ${CMAKE_INSTALL_PREFIX}/build/outputs/apk/${APK_FILE}) + ELSE() + SET(SOURCE_APK_FILE ${CMAKE_INSTALL_PREFIX}/bin/${APK_FILE}) + ENDIF() + + SET(DESTINATION_APK_FILE ${CMAKE_INSTALL_PREFIX}/${CPACK_PACKAGE_FILE_NAME}.apk) # Add DEPENDS install someday # http://public.kitware.com/Bug/view.php?id=8438 ADD_CUSTOM_TARGET(apk COMMAND ${DEPLOY_CMD} - COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_INSTALL_PREFIX}/bin/${APK_FILE} ${DESTINATION_APK_FILE}) + COMMAND ${CMAKE_COMMAND} -E copy ${SOURCE_APK_FILE} ${DESTINATION_APK_FILE}) - FIND_PROGRAM(jarsigner jarsigner CMAKE_FIND_ROOT_PATH_BOTH) - IF(jarsigner) - IF(APK_SIGN_KEYSTORE) - SET(jarsigner_keystore -keystore ${APK_SIGN_KEYSTORE}) - ENDIF() - ADD_CUSTOM_TARGET(verify.signature - COMMAND ${jarsigner} -verify -verbose -certs ${jarsigner_keystore} ${DESTINATION_APK_FILE}) + FIND_PROGRAM(apksigner apksigner HINTS ${ANDROID_SDK}/build-tools/${ANDROID_BUILD_TOOLS_REVISION} CMAKE_FIND_ROOT_PATH_BOTH) + IF(apksigner) + ADD_CUSTOM_TARGET(verify.signature COMMAND ${apksigner} verify --verbose --print-certs -Werr ${DESTINATION_APK_FILE}) ENDIF() ELSEIF(UNIX) diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index a93d0ca..f527052 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -144,17 +144,21 @@ IF(UNCRUSTIFY) IF("${UNCRUSTIFY_VERSION}" STRLESS "${UNCRUSTIFY_NEEDED_VERSION}") MESSAGE(WARNING "Uncrustify seems to be too old. Use at least ${UNCRUSTIFY_NEEDED_VERSION}... you are using: ${UNCRUSTIFY_VERSION}") ELSE() - ADD_CUSTOM_TARGET(format COMMAND ${UNCRUSTIFY_CMD} SOURCES ${UNCRUSTIFY_CFG}) + ADD_CUSTOM_TARGET(format COMMAND ${UNCRUSTIFY_CMD} SOURCES ${UNCRUSTIFY_CFG} ${FILES}) ENDIF() ENDIF() FIND_PROGRAM(QMLLINT_BIN qmllint CMAKE_FIND_ROOT_PATH_BOTH) IF(QMLLINT_BIN) + FILE(GLOB_RECURSE TEST_FILES_QML ${TEST_DIR}/qml/*.qml) + FILE(GLOB_RECURSE TEST_FILES_QML_STATIONARY ${TEST_DIR}/qml_stationary/*.qml) FILE(GLOB_RECURSE FILES_QML ${RESOURCES_DIR}/qml/*.qml) + FILE(GLOB_RECURSE FILES_QML_STATIONARY ${RESOURCES_DIR}/qml_stationary/*.qml) FILE(GLOB_RECURSE FILES_JS ${RESOURCES_DIR}/qml/*.js) - SET(QMLLINT_CMD ${QMLLINT_BIN} ${FILES_QML} ${FILES_JS}) + FILE(GLOB_RECURSE FILES_JS_STATIONARY ${RESOURCES_DIR}/qml_stationary/*.js) + SET(QMLLINT_CMD ${QMLLINT_BIN} ${FILES_QML} ${FILES_QML_STATIONARY} ${FILES_JS}) - ADD_CUSTOM_TARGET(qmllint COMMAND ${QMLLINT_CMD} SOURCES ${FILES_QML} ${FILES_JS}) + ADD_CUSTOM_TARGET(qmllint COMMAND ${QMLLINT_CMD} SOURCES ${TEST_FILES_QML} ${TEST_FILES_QML_STATIONARY} ${FILES_QML} ${FILES_QML_STATIONARY} ${FILES_JS} ${FILES_JS_STATIONARY}) ENDIF() # doc8 (https://pypi.python.org/pypi/doc8) @@ -169,4 +173,63 @@ FUNCTION(CREATE_DOC8_TARGET _dir _name) ENDIF() ENDFUNCTION() +FIND_PROGRAM(CONVERT convert CMAKE_FIND_ROOT_PATH_BOTH) +IF(CONVERT) + SET(CONVERT_CMD convert -background transparent) + ADD_CUSTOM_TARGET(npaicons + COMMAND ${CONVERT_CMD} npa.svg -define icon:auto-resize=256,96,64,48,40,32,24,20,16 npa.ico + COMMAND ${CONVERT_CMD} npa.svg -resize 16x16 autentapp2.iconset/icon_16x16.png + COMMAND ${CONVERT_CMD} npa.svg -resize 32x32 autentapp2.iconset/icon_16x16@2x.png + COMMAND ${CONVERT_CMD} npa.svg -resize 32x32 autentapp2.iconset/icon_32x32.png + COMMAND ${CONVERT_CMD} npa.svg -resize 64x64 autentapp2.iconset/icon_32x32@2x.png + COMMAND ${CONVERT_CMD} npa.svg -resize 128x128 autentapp2.iconset/icon_128x128.png + COMMAND ${CONVERT_CMD} npa.svg -resize 256x256 autentapp2.iconset/icon_128x128@2x.png + COMMAND ${CONVERT_CMD} npa.svg -resize 256x256 autentapp2.iconset/icon_256x256.png + COMMAND ${CONVERT_CMD} npa.svg -resize 512x512 autentapp2.iconset/icon_256x256@2x.png + COMMAND ${CONVERT_CMD} npa.svg -resize 512x512 autentapp2.iconset/icon_512x512.png + COMMAND ${CONVERT_CMD} npa.svg -resize 1024x1024 autentapp2.iconset/icon_512x512@2x.png + COMMAND ${CONVERT_CMD} npa.svg -resize 36x36 android/ldpi/npa.png + COMMAND ${CONVERT_CMD} npa.svg -resize 48x48 android/mdpi/npa.png + COMMAND ${CONVERT_CMD} npa.svg -resize 72x72 android/hdpi/npa.png + COMMAND ${CONVERT_CMD} npa.svg -resize 96x96 android/xhdpi/npa.png + COMMAND ${CONVERT_CMD} npa.svg -resize 144x144 android/xxhdpi/npa.png + COMMAND ${CONVERT_CMD} npa.svg -resize 192x192 android/xxxhdpi/npa.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 36x36 android/ldpi/npa_beta.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 48x48 android/mdpi/npa_beta.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 72x72 android/hdpi/npa_beta.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 96x96 android/xhdpi/npa_beta.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 144x144 android/xxhdpi/npa_beta.png + COMMAND ${CONVERT_CMD} npa_beta.svg -resize 192x192 android/xxxhdpi/npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) +ENDIF() + +FIND_PROGRAM(PNGQUANT pngquant CMAKE_FIND_ROOT_PATH_BOTH) +IF(PNGQUANT) +SET(PNGQUANT_CMD pngquant -f -o) + ADD_CUSTOM_TARGET(pngquant + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_16x16.png -- autentapp2.iconset/icon_16x16.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_16x16@2x.png -- autentapp2.iconset/icon_16x16@2x.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_32x32.png -- autentapp2.iconset/icon_32x32.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_32x32@2x.png -- autentapp2.iconset/icon_32x32@2x.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_128x128.png -- autentapp2.iconset/icon_128x128.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_128x128@2x.png -- autentapp2.iconset/icon_128x128@2x.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_256x256.png -- autentapp2.iconset/icon_256x256.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_256x256@2x.png -- autentapp2.iconset/icon_256x256@2x.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_512x512.png -- autentapp2.iconset/icon_512x512.png + COMMAND ${PNGQUANT_CMD} autentapp2.iconset/icon_512x512@2x.png -- autentapp2.iconset/icon_512x512@2x.png + COMMAND ${PNGQUANT_CMD} android/ldpi/npa.png -- android/ldpi/npa.png + COMMAND ${PNGQUANT_CMD} android/mdpi/npa.png -- android/mdpi/npa.png + COMMAND ${PNGQUANT_CMD} android/hdpi/npa.png -- android/hdpi/npa.png + COMMAND ${PNGQUANT_CMD} android/xhdpi/npa.png -- android/xhdpi/npa.png + COMMAND ${PNGQUANT_CMD} android/xxhdpi/npa.png -- android/xxhdpi/npa.png + COMMAND ${PNGQUANT_CMD} android/xxxhdpi/npa.png -- android/xxxhdpi/npa.png + COMMAND ${PNGQUANT_CMD} android/ldpi/npa_beta.png -- android/ldpi/npa_beta.png + COMMAND ${PNGQUANT_CMD} android/mdpi/npa_beta.png -- android/mdpi/npa_beta.png + COMMAND ${PNGQUANT_CMD} android/hdpi/npa_beta.png -- android/hdpi/npa_beta.png + COMMAND ${PNGQUANT_CMD} android/xhdpi/npa_beta.png -- android/xhdpi/npa_beta.png + COMMAND ${PNGQUANT_CMD} android/xxhdpi/npa_beta.png -- android/xxhdpi/npa_beta.png + COMMAND ${PNGQUANT_CMD} android/xxxhdpi/npa_beta.png -- android/xxxhdpi/npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) +ENDIF() + INCLUDE(Sphinx) diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index cb30dc9..ce73809 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -1,1690 +1,17 @@ -# Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2014, Andrey Kamaev -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. +CMAKE_MINIMUM_REQUIRED(VERSION 3.7.1) -# ------------------------------------------------------------------------------ -# Android CMake toolchain file, for use with the Android NDK r5-r10d -# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended). -# See home page: https://github.com/taka-no-me/android-cmake -# -# Usage Linux: -# $ export ANDROID_NDK=/absolute/path/to/the/android-ndk -# $ mkdir build && cd build -# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. -# $ make -j8 -# -# Usage Windows: -# You need native port of make to build your project. -# Android NDK r7 (and newer) already has make.exe on board. -# For older NDK you have to install it separately. -# For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm -# -# $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk -# $ mkdir build && cd build -# $ cmake.exe -G"MinGW Makefiles" -# -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake -# -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. -# $ cmake.exe --build . -# -# -# Options (can be set as cmake parameters: -D=): -# ANDROID_NDK=/opt/android-ndk - path to the NDK root. -# Can be set as environment variable. Can be set only at first cmake run. -# -# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary -# Interface (ABI). This option nearly matches to the APP_ABI variable -# used by ndk-build tool from Android NDK. -# -# Possible targets are: -# "armeabi" - ARMv5TE based CPU with software floating point operations -# "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions -# this ABI target is used by default -# "armeabi-v7a with NEON" - same as armeabi-v7a, but -# sets NEON as floating-point unit -# "armeabi-v7a with VFPV3" - same as armeabi-v7a, but -# sets VFPV3 as floating-point unit (has 32 registers instead of 16) -# "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP -# "x86" - IA-32 instruction set -# "mips" - MIPS32 instruction set -# -# 64-bit ABIs for NDK r10 and newer: -# "arm64-v8a" - ARMv8 AArch64 instruction set -# "x86_64" - Intel64 instruction set (r1) -# "mips64" - MIPS64 instruction set (r6) -# -# ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. -# Option is read-only when standalone toolchain is used. -# Note: building for "android-L" requires explicit configuration. -# -# ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler -# toolchain to be used. The list of possible values depends on the NDK -# version. For NDK r10c the possible values are: -# -# * aarch64-linux-android-4.9 -# * aarch64-linux-android-clang3.4 -# * aarch64-linux-android-clang3.5 -# * arm-linux-androideabi-4.6 -# * arm-linux-androideabi-4.8 -# * arm-linux-androideabi-4.9 (default) -# * arm-linux-androideabi-clang3.4 -# * arm-linux-androideabi-clang3.5 -# * mips64el-linux-android-4.9 -# * mips64el-linux-android-clang3.4 -# * mips64el-linux-android-clang3.5 -# * mipsel-linux-android-4.6 -# * mipsel-linux-android-4.8 -# * mipsel-linux-android-4.9 -# * mipsel-linux-android-clang3.4 -# * mipsel-linux-android-clang3.5 -# * x86-4.6 -# * x86-4.8 -# * x86-4.9 -# * x86-clang3.4 -# * x86-clang3.5 -# * x86_64-4.9 -# * x86_64-clang3.4 -# * x86_64-clang3.5 -# -# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions -# instead of Thumb. Is not available for "armeabi-v6 with VFP" -# (is forced to be ON) ABI. -# -# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker -# errors even if they are not used. -# -# ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared -# libraries. Automatically turned for NDK r5x and r6x due to GLESv2 -# problems. -# -# ANDROID_STL=gnustl_static - specify the runtime to use. -# -# Possible values are: -# none -> Do not configure the runtime. -# system -> Use the default minimal system C++ runtime library. -# Implies -fno-rtti -fno-exceptions. -# Is not available for standalone toolchain. -# system_re -> Use the default minimal system C++ runtime library. -# Implies -frtti -fexceptions. -# Is not available for standalone toolchain. -# gabi++_static -> Use the GAbi++ runtime as a static library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7 and newer. -# Is not available for standalone toolchain. -# gabi++_shared -> Use the GAbi++ runtime as a shared library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7 and newer. -# Is not available for standalone toolchain. -# stlport_static -> Use the STLport runtime as a static library. -# Implies -fno-rtti -fno-exceptions for NDK before r7. -# Implies -frtti -fno-exceptions for NDK r7 and newer. -# Is not available for standalone toolchain. -# stlport_shared -> Use the STLport runtime as a shared library. -# Implies -fno-rtti -fno-exceptions for NDK before r7. -# Implies -frtti -fno-exceptions for NDK r7 and newer. -# Is not available for standalone toolchain. -# gnustl_static -> Use the GNU STL as a static library. -# Implies -frtti -fexceptions. -# gnustl_shared -> Use the GNU STL as a shared library. -# Implies -frtti -fno-exceptions. -# Available for NDK r7b and newer. -# Silently degrades to gnustl_static if not available. -# -# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on -# chosen runtime. If disabled, then the user is responsible for settings -# these options. -# -# What?: -# android-cmake toolchain searches for NDK/toolchain in the following order: -# ANDROID_NDK - cmake parameter -# ANDROID_NDK - environment variable -# ANDROID_STANDALONE_TOOLCHAIN - cmake parameter -# ANDROID_STANDALONE_TOOLCHAIN - environment variable -# ANDROID_NDK - default locations -# ANDROID_STANDALONE_TOOLCHAIN - default locations -# -# Make sure to do the following in your scripts: -# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) -# SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) -# The flags will be prepopulated with critical flags, so don't loose them. -# Also be aware that toolchain also sets configuration-specific compiler -# flags and linker flags. -# -# ANDROID and BUILD_ANDROID will be set to true, you may test any of these -# variables to make necessary Android-specific configuration changes. -# -# Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 -# will be set true, mutually exclusive. NEON option will be set true -# if VFP is set to NEON. -# -# ------------------------------------------------------------------------------ +SET(ANDROID_SDK $ENV{ANDROID_HOME}) +SET(ANDROID_BUILD_TOOLS_REVISION $ENV{ANDROID_BUILD_TOOLS_REVISION}) -cmake_minimum_required( VERSION 2.6.3 ) +SET(CMAKE_SYSTEM_NAME Android) +SET(CMAKE_ANDROID_STL_TYPE gnustl_shared) -if( DEFINED CMAKE_CROSSCOMPILING ) - # subsequent toolchain loading is not really needed - return() -endif() +IF(NOT CMAKE_ANDROID_ARCH_ABI) + SET(CMAKE_ANDROID_ARCH_ABI armeabi-v7a) +ENDIF() -if( CMAKE_TOOLCHAIN_FILE ) - # touch toolchain variable to suppress "unused variable" warning -endif() - -# inherit settings in recursive loads -get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) -if( _CMAKE_IN_TRY_COMPILE ) - include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) -endif() - -# this one is important -if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) - set( CMAKE_SYSTEM_NAME Android ) -else() - set( CMAKE_SYSTEM_NAME Linux ) -endif() - -# this one not so much -set( CMAKE_SYSTEM_VERSION 1 ) - -# rpath makes low sense for Android -set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) -set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) - -# NDK search paths -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10e -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) -if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS ) - if( CMAKE_HOST_WIN32 ) - file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) - set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" ) - else() - file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) - set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" ) - endif() -endif() -if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) - set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) -endif() - -# known ABIs -set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) -set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) -set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) -set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) -set( ANDROID_SUPPORTED_ABIS_mips "mips" ) -set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) - -# API level defaults -set( ANDROID_DEFAULT_NDK_API_LEVEL 18 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 18 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 18 ) -set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) - - -macro( __LIST_FILTER listvar regex ) - if( ${listvar} ) - foreach( __val ${${listvar}} ) - if( __val MATCHES "${regex}" ) - list( REMOVE_ITEM ${listvar} "${__val}" ) - endif() - endforeach() - endif() -endmacro() - -macro( __INIT_VARIABLE var_name ) - set( __test_path 0 ) - foreach( __var ${ARGN} ) - if( __var STREQUAL "PATH" ) - set( __test_path 1 ) - break() - endif() - endforeach() - - if( __test_path AND NOT EXISTS "${${var_name}}" ) - unset( ${var_name} CACHE ) - endif() - - if( " ${${var_name}}" STREQUAL " " ) - set( __values 0 ) - foreach( __var ${ARGN} ) - if( __var STREQUAL "VALUES" ) - set( __values 1 ) - elseif( NOT __var STREQUAL "PATH" ) - if( __var MATCHES "^ENV_.*$" ) - string( REPLACE "ENV_" "" __var "${__var}" ) - set( __value "$ENV{${__var}}" ) - elseif( DEFINED ${__var} ) - set( __value "${${__var}}" ) - elseif( __values ) - set( __value "${__var}" ) - else() - set( __value "" ) - endif() - - if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") ) - set( ${var_name} "${__value}" ) - break() - endif() - endif() - endforeach() - unset( __value ) - unset( __values ) - endif() - - if( __test_path ) - file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) - endif() - unset( __test_path ) -endmacro() - -macro( __DETECT_NATIVE_API_LEVEL _var _path ) - set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) - file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) - if( NOT __apiFileContent ) - message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) - endif() - string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) - unset( __apiFileContent ) - unset( __ndkApiLevelRegex ) -endmacro() - -macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) - if( EXISTS "${_root}" ) - file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) - __LIST_FILTER( __gccExePath "^[.].*" ) - list( LENGTH __gccExePath __gccExePathsCount ) - if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) - message( WARNING "Could not determine machine name for compiler from ${_root}" ) - set( ${_var} "" ) - else() - get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) - string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) - endif() - unset( __gccExePath ) - unset( __gccExePathsCount ) - unset( __gccExeName ) - else() - set( ${_var} "" ) - endif() -endmacro() - - -# fight against cygwin -set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") -mark_as_advanced( ANDROID_FORBID_SYGWIN ) -if( ANDROID_FORBID_SYGWIN ) - if( CYGWIN ) - message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) - endif() - - if( CMAKE_HOST_WIN32 ) - # remove cygwin from PATH - set( __new_path "$ENV{PATH}") - __LIST_FILTER( __new_path "cygwin" ) - set(ENV{PATH} "${__new_path}") - unset(__new_path) - endif() -endif() - - -# detect current host platform -if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) - set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) - mark_as_advanced( ANDROID_NDK_HOST_X64 ) -endif() - -set( TOOL_OS_SUFFIX "" ) -if( CMAKE_HOST_APPLE ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) -elseif( CMAKE_HOST_WIN32 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) - set( TOOL_OS_SUFFIX ".exe" ) -elseif( CMAKE_HOST_UNIX ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) -else() - message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) -endif() - -if( NOT ANDROID_NDK_HOST_X64 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) -endif() - -__INIT_VARIABLE( ANDROID_SDK PATH ENV_ANDROID_HOME ) -if( ANDROID_SDK ) - set( ANDROID_SDK "${ANDROID_SDK}" CACHE INTERNAL "Path of the Android SDK" FORCE ) -endif() - -# see if we have path to Android NDK -if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN ) - __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) -endif() -if( NOT ANDROID_NDK ) - # see if we have path to Android standalone toolchain - __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN ) - - if( NOT ANDROID_STANDALONE_TOOLCHAIN ) - #try to find Android NDK in one of the the default locations - set( __ndkSearchPaths ) - foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) - foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) - list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" ) - endforeach() - endforeach() - __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) - unset( __ndkSearchPaths ) - - if( ANDROID_NDK ) - message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) - message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) - else() - #try to find Android standalone toolchain in one of the the default locations - __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) - - if( ANDROID_STANDALONE_TOOLCHAIN ) - message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) - message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) - endif( ANDROID_STANDALONE_TOOLCHAIN ) - endif( ANDROID_NDK ) - endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) -endif( NOT ANDROID_NDK ) - -# remember found paths -if( ANDROID_NDK ) - get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) - set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) - set( BUILD_WITH_ANDROID_NDK True ) - if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) - file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) - string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) - else() - set( ANDROID_NDK_RELEASE "r1x" ) - set( ANDROID_NDK_RELEASE_FULL "unreleased" ) - endif() - string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) - string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) - math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) -elseif( ANDROID_STANDALONE_TOOLCHAIN ) - get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) - # try to detect change - if( CMAKE_AR ) - string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) - if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) - message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) - endif() - unset( __androidStandaloneToolchainPreviousPath ) - unset( __length ) - endif() - set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) - set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) -else() - list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) - message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. - You should either set an environment variable: - export ANDROID_NDK=~/my-android-ndk - or - export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain - or put the toolchain or NDK in the default path: - sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk - sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) -endif() - -# android NDK layout -if( BUILD_WITH_ANDROID_NDK ) - if( NOT DEFINED ANDROID_NDK_LAYOUT ) - # try to automatically detect the layout - if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") - set( ANDROID_NDK_LAYOUT "RELEASE" ) - elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) - set( ANDROID_NDK_LAYOUT "LINARO" ) - elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) - set( ANDROID_NDK_LAYOUT "ANDROID" ) - endif() - endif() - set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) - mark_as_advanced( ANDROID_NDK_LAYOUT ) - if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) - elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) - set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) - else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" - set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) - endif() - get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) - - # try to detect change of NDK - if( CMAKE_AR ) - string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) - if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) - message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. - " ) - endif() - unset( __androidNdkPreviousPath ) - unset( __length ) - endif() -endif() - - -# get all the details about standalone toolchain -if( BUILD_WITH_STANDALONE_TOOLCHAIN ) - __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) - set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - set( __availableToolchains "standalone" ) - __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) - if( NOT __availableToolchainMachines ) - message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) - endif() - if( __availableToolchainMachines MATCHES x86_64 ) - set( __availableToolchainArchs "x86_64" ) - elseif( __availableToolchainMachines MATCHES i686 ) - set( __availableToolchainArchs "x86" ) - elseif( __availableToolchainMachines MATCHES aarch64 ) - set( __availableToolchainArchs "arm64" ) - elseif( __availableToolchainMachines MATCHES arm ) - set( __availableToolchainArchs "arm" ) - elseif( __availableToolchainMachines MATCHES mips64el ) - set( __availableToolchainArchs "mips64" ) - elseif( __availableToolchainMachines MATCHES mipsel ) - set( __availableToolchainArchs "mips" ) - endif() - execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion - OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) - if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) - list( APPEND __availableToolchains "standalone-clang" ) - list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) - list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) - list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) - endif() -endif() - -macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) - foreach( __toolchain ${${__availableToolchainsLst}} ) - if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) - SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) - FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) - if( __toolchainVersionStr ) - string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) - string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) - else() - string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) - endif() - unset( __toolchainVersionStr ) - unset( __toolchainVersionRegex ) - else() - set( __gcc_toolchain "${__toolchain}" ) - endif() - __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) - if( __machine ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) - if( __machine MATCHES x86_64 ) - set( __arch "x86_64" ) - elseif( __machine MATCHES i686 ) - set( __arch "x86" ) - elseif( __machine MATCHES aarch64 ) - set( __arch "arm64" ) - elseif( __machine MATCHES arm ) - set( __arch "arm" ) - elseif( __machine MATCHES mips64el ) - set( __arch "mips64" ) - elseif( __machine MATCHES mipsel ) - set( __arch "mips" ) - else() - set( __arch "" ) - endif() - #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") - if (__arch) - list( APPEND __availableToolchainMachines "${__machine}" ) - list( APPEND __availableToolchainArchs "${__arch}" ) - list( APPEND __availableToolchainCompilerVersions "${__version}" ) - list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) - endif() - endif() - unset( __gcc_toolchain ) - endforeach() -endmacro() - -# get all the details about NDK -if( BUILD_WITH_ANDROID_NDK ) - file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) - string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) - set( __availableToolchains "" ) - set( __availableToolchainMachines "" ) - set( __availableToolchainArchs "" ) - set( __availableToolchainCompilerVersions "" ) - if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) - # do not go through all toolchains if we know the name - set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) - if( __availableToolchains ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) - endif() - endif() - endif() - if( NOT __availableToolchains ) - file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) - if( __availableToolchainsLst ) - list(SORT __availableToolchainsLst) # we need clang to go after gcc - endif() - __LIST_FILTER( __availableToolchainsLst "^[.]" ) - __LIST_FILTER( __availableToolchainsLst "llvm" ) - __LIST_FILTER( __availableToolchainsLst "renderscript" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) - if( __availableToolchains ) - set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) - endif() - endif() - endif() - if( NOT __availableToolchains ) - message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) - endif() -endif() - -# build list of available ABIs -set( ANDROID_SUPPORTED_ABIS "" ) -set( __uniqToolchainArchNames ${__availableToolchainArchs} ) -list( REMOVE_DUPLICATES __uniqToolchainArchNames ) -list( SORT __uniqToolchainArchNames ) -foreach( __arch ${__uniqToolchainArchNames} ) - list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) -endforeach() -unset( __uniqToolchainArchNames ) -if( NOT ANDROID_SUPPORTED_ABIS ) - message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) -endif() - -# choose target ABI -__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} ) -# verify that target ABI is supported -list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) -if( __androidAbiIdx EQUAL -1 ) - string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) - message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. - Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" - " ) -endif() -unset( __androidAbiIdx ) - -# set target ABI options -if( ANDROID_ABI STREQUAL "x86" ) - set( X86 true ) - set( ANDROID_NDK_ABI_NAME "x86" ) - set( ANDROID_ARCH_NAME "x86" ) - set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "i686" ) -elseif( ANDROID_ABI STREQUAL "x86_64" ) - set( X86 true ) - set( X86_64 true ) - set( ANDROID_NDK_ABI_NAME "x86_64" ) - set( ANDROID_ARCH_NAME "x86_64" ) - set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) - set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) -elseif( ANDROID_ABI STREQUAL "mips64" ) - set( MIPS64 true ) - set( ANDROID_NDK_ABI_NAME "mips64" ) - set( ANDROID_ARCH_NAME "mips64" ) - set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "mips64" ) -elseif( ANDROID_ABI STREQUAL "mips" ) - set( MIPS true ) - set( ANDROID_NDK_ABI_NAME "mips" ) - set( ANDROID_ARCH_NAME "mips" ) - set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "mips" ) -elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) - set( ARM64_V8A true ) - set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) - set( ANDROID_ARCH_NAME "arm64" ) - set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) - set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) - set( VFPV3 true ) - set( NEON true ) -elseif( ANDROID_ABI STREQUAL "armeabi" ) - set( ARMEABI true ) - set( ANDROID_NDK_ABI_NAME "armeabi" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) -elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) - set( ARMEABI_V6 true ) - set( ANDROID_NDK_ABI_NAME "armeabi" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv6" ) - # need always fallback to older platform - set( ARMEABI true ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a") - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) - set( VFPV3 true ) -elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) - set( ARMEABI_V7A true ) - set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) - set( ANDROID_ARCH_NAME "arm" ) - set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) - set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) - set( VFPV3 true ) - set( NEON true ) -else() - message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) -endif() - -if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) - # really dirty hack - # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... - file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) -endif() - -if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) - __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF ) - set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) - mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) -else() - unset( ANDROID_FORCE_ARM_BUILD CACHE ) -endif() - -# choose toolchain -if( ANDROID_TOOLCHAIN_NAME ) - list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) - if( __toolchainIdx EQUAL -1 ) - list( SORT __availableToolchains ) - string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) - set( toolchains_list " * ${toolchains_list}") - message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. -To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) - endif() - list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) - if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) - message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) - endif() -else() - set( __toolchainIdx -1 ) - set( __applicableToolchains "" ) - set( __toolchainMaxVersion "0.0.0" ) - list( LENGTH __availableToolchains __availableToolchainsCount ) - math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) - foreach( __idx RANGE ${__availableToolchainsCount} ) - list( GET __availableToolchainArchs ${__idx} __toolchainArch ) - if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) - list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) - string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") - if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) - set( __toolchainMaxVersion "${__toolchainVersion}" ) - set( __toolchainIdx ${__idx} ) - endif() - endif() - endforeach() - unset( __availableToolchainsCount ) - unset( __toolchainMaxVersion ) - unset( __toolchainVersion ) -endif() -unset( __toolchainArch ) -if( __toolchainIdx EQUAL -1 ) - message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) -endif() -list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) -list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) -list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) - -unset( __toolchainIdx ) -unset( __availableToolchains ) -unset( __availableToolchainMachines ) -unset( __availableToolchainArchs ) -unset( __availableToolchainCompilerVersions ) - -# choose native API level -__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) -string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) -string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) -# adjust API level -set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) -foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) - set( __real_api_level ${__level} ) - endif() -endforeach() -if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) - message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") - set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) -endif() -unset(__real_api_level) -# validate -list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) -if( __levelIdx EQUAL -1 ) - message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) -else() - if( BUILD_WITH_ANDROID_NDK ) - __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) - if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) - message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) - endif() - unset( __realApiLevel ) - endif() - set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) - set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} ) - if( CMAKE_VERSION VERSION_GREATER "2.8" ) - list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) - set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) - endif() -endif() -unset( __levelIdx ) - - -# remember target ABI -set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) -if( CMAKE_VERSION VERSION_GREATER "2.8" ) - list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) - set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) -endif() - - -# runtime choice (STL, rtti, exceptions) -if( NOT ANDROID_STL ) - set( ANDROID_STL gnustl_static ) -endif() -set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) -set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) -mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) - -if( BUILD_WITH_ANDROID_NDK ) - if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") - message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". -The possible values are: - none -> Do not configure the runtime. - system -> Use the default minimal system C++ runtime library. - system_re -> Same as system but with rtti and exceptions. - gabi++_static -> Use the GAbi++ runtime as a static library. - gabi++_shared -> Use the GAbi++ runtime as a shared library. - stlport_static -> Use the STLport runtime as a static library. - stlport_shared -> Use the STLport runtime as a shared library. - gnustl_static -> (default) Use the GNU STL as a static library. - gnustl_shared -> Use the GNU STL as a shared library. -" ) - endif() -elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) - if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") - message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". -The possible values are: - none -> Do not configure the runtime. - gnustl_static -> (default) Use the GNU STL as a static library. - gnustl_shared -> Use the GNU STL as a shared library. -" ) - endif() -endif() - -unset( ANDROID_RTTI ) -unset( ANDROID_EXCEPTIONS ) -unset( ANDROID_STL_INCLUDE_DIRS ) -unset( __libstl ) -unset( __libsupcxx ) - -if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) - message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). -You are strongly recommended to switch to another NDK release. -" ) -endif() - -if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) - message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: -See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 - diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h - index 5e28c64..65892a1 100644 - --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h - +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h - @@ -51,7 +51,11 @@ typedef long int ssize_t; - #endif - #ifndef _PTRDIFF_T - #define _PTRDIFF_T - -typedef long ptrdiff_t; - +# ifdef __ANDROID__ - + typedef int ptrdiff_t; - +# else - + typedef long ptrdiff_t; - +# endif - #endif -" ) -endif() - - -# setup paths and STL for standalone toolchain -if( BUILD_WITH_STANDALONE_TOOLCHAIN ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) - set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) - - if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) - if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) - # old location ( pre r8c ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) - endif() - if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) - else() - list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) - endif() - # always search static GNU STL to get the location of libsupc++.a - if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) - elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) - elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) - endif() - if( __libstl ) - set( __libsupcxx "${__libstl}/libsupc++.a" ) - set( __libstl "${__libstl}/libstdc++.a" ) - endif() - if( NOT EXISTS "${__libsupcxx}" ) - message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. - Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. - You need to either upgrade to newer NDK or manually copy - $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a - to - ${__libsupcxx} - " ) - endif() - if( ANDROID_STL STREQUAL "gnustl_shared" ) - if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) - elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) - endif() - endif() - endif() -endif() - -# clang -if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) - set( ANDROID_COMPILER_IS_CLANG 1 ) - execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) - string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") -elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) - string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") - string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) - message( FATAL_ERROR "Could not find the Clang compiler driver" ) - endif() - set( ANDROID_COMPILER_IS_CLANG 1 ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) -else() - set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - unset( ANDROID_COMPILER_IS_CLANG CACHE ) -endif() - -string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) -if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) - set( _clang_name "clang" ) -endif() - - -# setup paths and STL for NDK -if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) - set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) - - if( ANDROID_STL STREQUAL "none" ) - # do nothing - elseif( ANDROID_STL STREQUAL "system" ) - set( ANDROID_RTTI OFF ) - set( ANDROID_EXCEPTIONS OFF ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) - elseif( ANDROID_STL STREQUAL "system_re" ) - set( ANDROID_RTTI ON ) - set( ANDROID_EXCEPTIONS ON ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) - elseif( ANDROID_STL MATCHES "gabi" ) - if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") - endif() - set( ANDROID_RTTI ON ) - set( ANDROID_EXCEPTIONS OFF ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) - elseif( ANDROID_STL MATCHES "stlport" ) - if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d - set( ANDROID_EXCEPTIONS ON ) - else() - set( ANDROID_EXCEPTIONS OFF ) - endif() - if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - set( ANDROID_RTTI OFF ) - else() - set( ANDROID_RTTI ON ) - endif() - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) - elseif( ANDROID_STL MATCHES "gnustl" ) - set( ANDROID_EXCEPTIONS ON ) - set( ANDROID_RTTI ON ) - if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) - if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) - # gnustl binary for 4.7 compiler is buggy :( - # TODO: look for right fix - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) - else() - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) - endif() - else() - set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) - endif() - set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" ) - if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) - set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) - else() - set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) - endif() - else() - message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) - endif() - # find libsupc++.a - rtti & exceptions - if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer - if( NOT EXISTS "${__libsupcxx}" ) - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 - endif() - if( NOT EXISTS "${__libsupcxx}" ) # before r7 - if( ARMEABI_V7A ) - if( ANDROID_FORCE_ARM_BUILD ) - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) - else() - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) - endif() - elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) - else() - set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) - endif() - endif() - if( NOT EXISTS "${__libsupcxx}") - message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") - endif() - endif() -endif() - - -# case of shared STL linkage -if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) - string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) - # TODO: check if .so file exists before the renaming -endif() - - -# ccache support -__INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) -if( _ndk_ccache ) - if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) - unset( NDK_CCACHE CACHE ) - endif() - find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") -else() - unset( NDK_CCACHE CACHE ) -endif() -unset( _ndk_ccache ) - - -# setup the cross-compiler -if( NOT CMAKE_C_COMPILER ) - if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) - set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) - set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - else() - set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - endif() - else() - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") - set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") - else() - set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) - set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) - endif() - endif() - set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) - set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) - if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" ) - # Use gcc-ar if we have it for better LTO support. - set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) - else() - set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) - endif() - set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) - set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) - set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) - set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) - set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) -endif() - -set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) -if( CMAKE_VERSION VERSION_LESS 2.8.5 ) - set( CMAKE_ASM_COMPILER_ARG1 "-c" ) -endif() -if( APPLE ) - find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) - if( NOT CMAKE_INSTALL_NAME_TOOL ) - message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) - endif() - mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) -endif() - -if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_C_COMPILER_ID Clang ) -endif() -set( CMAKE_C_PLATFORM_ID Linux ) -if( X86_64 OR MIPS64 OR ARM64_V8A ) - set( CMAKE_C_SIZEOF_DATA_PTR 8 ) -else() - set( CMAKE_C_SIZEOF_DATA_PTR 4 ) -endif() -set( CMAKE_C_HAS_ISYSROOT 1 ) -set( CMAKE_C_COMPILER_ABI ELF ) - -if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_CXX_COMPILER_ID Clang) -endif() -set( CMAKE_CXX_PLATFORM_ID Linux ) -set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) -set( CMAKE_CXX_HAS_ISYSROOT 1 ) -set( CMAKE_CXX_COMPILER_ABI ELF ) -set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) -# force ASM compiler (required for CMake < 2.8.5) -set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) -set( CMAKE_ASM_COMPILER_ID GNU ) -set( CMAKE_ASM_COMPILER_WORKS TRUE ) -set( CMAKE_ASM_COMPILER_FORCED TRUE ) -set( CMAKE_COMPILER_IS_GNUASM 1) -set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) - -foreach( lang C CXX ASM ) - if( ANDROID_COMPILER_IS_CLANG ) - set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} ) - else() - set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} ) - endif() -endforeach() - -# flags and definitions -remove_definitions( -DANDROID ) -add_definitions( -DANDROID ) - -if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) - if( CMAKE_HOST_WIN32 ) - # try to convert path to 8.3 form - file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) - execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" - OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE __result ERROR_QUIET ) - if( __result EQUAL 0 ) - file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) - set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) - else() - set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) - endif() - else() - set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) - endif() - if( NOT _CMAKE_IN_TRY_COMPILE ) - # quotes can break try_compile and compiler identification - message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") - endif() -else() - set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) -endif() - -# NDK flags -if (ARM64_V8A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) - endif() -elseif( ARMEABI OR ARMEABI_V7A) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) - set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) - endif() - else() - # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI - set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) - endif() - endif() -elseif( X86 OR X86_64 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) - endif() - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) -elseif( MIPS OR MIPS64 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" ) - set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) - set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) - if( NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) - set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) - endif() -elseif() - set( ANDROID_CXX_FLAGS_RELEASE "" ) - set( ANDROID_CXX_FLAGS_DEBUG "" ) -endif() - -#set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries - -if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) -endif() - -if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ -endif() - -# ABI-specific flags -if( ARMEABI_V7A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) - if( NEON ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) - elseif( VFPV3 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) - else() - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) - endif() -elseif( ARMEABI_V6 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 -elseif( ARMEABI ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) -endif() - -if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) -else() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) -endif() - -# STL -if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) - if( EXISTS "${__libstl}" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) - endif() - if( EXISTS "${__libsupcxx}" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) - # C objects: - set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_C_LINK_EXECUTABLE " -o " ) - set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) - set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) - set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) - endif() - if( ANDROID_STL MATCHES "gnustl" ) - if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) - set( ANDROID_LIBM_PATH -lm ) - endif() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) - endif() -endif() - -# variables controlling optional build flags -if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 - # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. - # So this flag option is required for all projects using OpenGL from native. - __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) -else() - __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) -endif() -__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON ) -__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) -__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) -__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) -__INIT_VARIABLE( ANDROID_RELRO VALUES ON ) - -set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) -set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) -set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" ) -set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) -set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) -set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) -mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) - -# linker flags -set( ANDROID_LINKER_FLAGS "" ) - -if( ARMEABI_V7A ) - # this is *required* to use the following linker flags that routes around - # a CPU bug in some Cortex-A8 implementations: - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) -endif() - -if( ANDROID_NO_UNDEFINED ) - if( MIPS ) - # there is some sysroot-related problem in mips linker... - if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) - endif() - else() - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) - endif() -endif() - -if( ANDROID_SO_UNDEFINED ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) -endif() - -if( ANDROID_FUNCTION_LEVEL_LINKING ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) -endif() - -if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) - if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) - elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) - elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) - message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 - On Linux and OS X host platform you can workaround this problem using gold linker (default). - Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. -" ) - endif() -endif() # version 4.6 - -if( ANDROID_NOEXECSTACK ) - if( ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) - else() - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) - endif() - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) -endif() - -if( ANDROID_RELRO ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) -endif() - -if( ANDROID_COMPILER_IS_CLANG ) - set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) - if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) - endif() -endif() - -# cache flags -set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) -set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) -set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) -set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) -set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) -set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) -set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) -set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) -set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) - -# put flags to cache (for debug purpose only) -set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) -set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) -set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) -set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) - -# finish flags -set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) -set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) -set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) -set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) -set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) -set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) -set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) -set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) -set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) - -if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) - set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) - set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) - set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) -endif() - -# pie/pic -if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) ) - set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) - set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") -else() - set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) - set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) -endif() - -# configure rtti -if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) - if( ANDROID_RTTI ) - set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) - else() - set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) - endif() -endif() - -# configure exceptios -if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) - if( ANDROID_EXCEPTIONS ) - set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) - else() - set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) - set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) - endif() -endif() - -# global includes and link directories -include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) -get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning -link_directories( "${__android_install_path}" ) - -# detect if need link crtbegin_so.o explicitly -if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) - set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) - string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) - string( REPLACE "" "-shared" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) - string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) - string( REPLACE "" "" __cmd "${__cmd}" ) - separate_arguments( __cmd ) - foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) - if( ${__var} ) - set( __tmp "${${__var}}" ) - separate_arguments( __tmp ) - string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") - endif() - endforeach() - string( REPLACE "'" "" __cmd "${__cmd}" ) - string( REPLACE "\"" "" __cmd "${__cmd}" ) - execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) - if( __cmd_result EQUAL 0 ) - set( ANDROID_EXPLICIT_CRT_LINK ON ) - else() - set( ANDROID_EXPLICIT_CRT_LINK OFF ) - endif() -endif() - -if( ANDROID_EXPLICIT_CRT_LINK ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) -endif() - -if( DEFINED LIBRARY_OUTPUT_PATH_ROOT - OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml" - OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") ) - set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" ) - if( NOT _CMAKE_IN_TRY_COMPILE ) - if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) - set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) - else() - set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) - endif() - set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" ) - endif() -endif() - -# copy shaed stl library to build directory -if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH ) - get_filename_component( __libstlname "${__libstl}" NAME ) - execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) - if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") - message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) - endif() - unset( __fileCopyProcess ) - unset( __libstlname ) -endif() - - -# set these global flags for cmake client scripts to change behavior -set( ANDROID True ) -set( BUILD_ANDROID True ) - -# where is the target environment -set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" "${CMAKE_PREFIX_PATH}") - -# only search for libraries and includes in the ndk toolchain -set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) - - -# macro to find packages on the host OS -macro( find_host_package ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) - if( CMAKE_HOST_WIN32 ) - SET( WIN32 1 ) - SET( UNIX ) - elseif( CMAKE_HOST_APPLE ) - SET( APPLE 1 ) - SET( UNIX ) - endif() - find_package( ${ARGN} ) - SET( WIN32 ) - SET( APPLE ) - SET( UNIX 1 ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) -endmacro() - - -# macro to find programs on the host OS -macro( find_host_program ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) - if( CMAKE_HOST_WIN32 ) - SET( WIN32 1 ) - SET( UNIX ) - elseif( CMAKE_HOST_APPLE ) - SET( APPLE 1 ) - SET( UNIX ) - endif() - find_program( ${ARGN} ) - SET( WIN32 ) - SET( APPLE ) - SET( UNIX 1 ) - set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) - set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) -endmacro() - - -# export toolchain settings for the try_compile() command -if( NOT _CMAKE_IN_TRY_COMPILE ) - set( __toolchain_config "") - foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN - ANDROID_NDK_HOST_X64 - ANDROID_NDK - ANDROID_NDK_LAYOUT - ANDROID_STANDALONE_TOOLCHAIN - ANDROID_TOOLCHAIN_NAME - ANDROID_ABI - ANDROID_NATIVE_API_LEVEL - ANDROID_STL - ANDROID_STL_FORCE_FEATURES - ANDROID_FORCE_ARM_BUILD - ANDROID_NO_UNDEFINED - ANDROID_SO_UNDEFINED - ANDROID_FUNCTION_LEVEL_LINKING - ANDROID_GOLD_LINKER - ANDROID_NOEXECSTACK - ANDROID_RELRO - ANDROID_LIBM_PATH - ANDROID_EXPLICIT_CRT_LINK - ANDROID_APP_PIE - ) - if( DEFINED ${__var} ) - if( ${__var} MATCHES " ") - set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) - else() - set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) - endif() - endif() - endforeach() - file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) - unset( __toolchain_config ) -endif() - - -# force cmake to produce / instead of \ in build commands for Ninja generator -if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) - # it is a bad hack after all - # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW - set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW - set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion - # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it - unset( MINGW ) -endif() - - -# Variables controlling behavior or set by cmake toolchain: -# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" -# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) -# ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none -# ANDROID_FORBID_SYGWIN : ON/OFF -# ANDROID_NO_UNDEFINED : ON/OFF -# ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) -# ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF -# ANDROID_GOLD_LINKER : ON/OFF -# ANDROID_NOEXECSTACK : ON/OFF -# ANDROID_RELRO : ON/OFF -# ANDROID_FORCE_ARM_BUILD : ON/OFF -# ANDROID_STL_FORCE_FEATURES : ON/OFF -# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` -# Can be set only at the first run: -# ANDROID_NDK : path to your NDK install -# NDK_CCACHE : path to your ccache executable -# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain -# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) -# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) -# LIBRARY_OUTPUT_PATH_ROOT : -# ANDROID_STANDALONE_TOOLCHAIN -# -# Primary read-only variables: -# ANDROID : always TRUE -# ARMEABI : TRUE for arm v6 and older devices -# ARMEABI_V6 : TRUE for arm v6 -# ARMEABI_V7A : TRUE for arm v7a -# ARM64_V8A : TRUE for arm64-v8a -# NEON : TRUE if NEON unit is enabled -# VFPV3 : TRUE if VFP version 3 is enabled -# X86 : TRUE if configured for x86 -# X86_64 : TRUE if configured for x86_64 -# MIPS : TRUE if configured for mips -# MIPS64 : TRUE if configured for mips64 -# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used -# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used -# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform -# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI -# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK -# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) -# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI -# ANDROID_SYSROOT : path to the compiler sysroot -# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform -# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used -# -# Secondary (less stable) read-only variables: -# ANDROID_COMPILER_VERSION : GCC version used (not Clang version) -# ANDROID_CLANG_VERSION : version of clang compiler if clang is used -# ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform -# ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI -# ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" -# ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) -# ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools -# ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK -# ANDROID_STL_INCLUDE_DIRS : stl include paths -# ANDROID_RTTI : if rtti is enabled by the runtime -# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime -# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used -# -# Defaults: -# ANDROID_DEFAULT_NDK_API_LEVEL -# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} -# ANDROID_NDK_SEARCH_PATHS -# ANDROID_SUPPORTED_ABIS_${ARCH} -# ANDROID_SUPPORTED_NDK_VERSIONS +IF(CMAKE_ANDROID_ARCH_ABI MATCHES "arm64-v8a") + SET(CMAKE_SYSTEM_VERSION 21) +ELSE() + SET(CMAKE_SYSTEM_VERSION 18) +ENDIF() diff --git a/docs/releasenotes/1.12.0.rst b/docs/releasenotes/1.12.0.rst new file mode 100644 index 0000000..c9d1a87 --- /dev/null +++ b/docs/releasenotes/1.12.0.rst @@ -0,0 +1,22 @@ +AusweisApp2 1.12.0 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 27. März 2017 + + + +Anwender +"""""""" + - Veröffentlichung betrifft nur die Plattform "Android". + + - Unterstützung von Android 4.3 und höher. + + - Zertifiziert vom Bundesamt für Sicherheit in der Informationstechnik (BSI). + + + +Entwickler +"""""""""" + - Aktualisierung von OpenSSL auf die Version 1.0.2k. + + - Aktualisierung von Qt auf die Version 5.8.0. diff --git a/docs/releasenotes/1.12.1.rst b/docs/releasenotes/1.12.1.rst new file mode 100644 index 0000000..03ac720 --- /dev/null +++ b/docs/releasenotes/1.12.1.rst @@ -0,0 +1,23 @@ +AusweisApp2 1.12.1 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 09. Juni 2017 + + + +Anmerkung +""""""""" + - Version wurde auf Grund der EUPL v1.2 ausgesetzt. + + + +Anwender +"""""""" + - Veröffentlichung der AusweisApp2 unter geänderten + Nutzungsbedingungen (EUPL v1.1). + + + +Entwickler +"""""""""" + - Bereitstellung des Sourcecode der AusweisApp2 auf GitHub. diff --git a/docs/releasenotes/1.12.2.rst b/docs/releasenotes/1.12.2.rst new file mode 100644 index 0000000..8f6366a --- /dev/null +++ b/docs/releasenotes/1.12.2.rst @@ -0,0 +1,15 @@ +AusweisApp2 1.12.2 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 30. Juni 2017 + + +Anwender +"""""""" + - Veröffentlichung der AusweisApp2 unter geänderten + Nutzungsbedingungen (EUPL v1.2). + + +Entwickler +"""""""""" + - Bereitstellung des Sourcecode der AusweisApp2 auf GitHub. diff --git a/docs/releasenotes/appcast.rst b/docs/releasenotes/appcast.rst index 21870f4..a1c0a4f 100644 --- a/docs/releasenotes/appcast.rst +++ b/docs/releasenotes/appcast.rst @@ -4,9 +4,8 @@ Release Notes .. toctree:: :maxdepth: 1 - 1.10.3 - 1.10.2 - 1.10.1 - 1.10.0 + 1.12.2 + 1.12.1 + 1.12.0 announce issues diff --git a/docs/releasenotes/issues.rst b/docs/releasenotes/issues.rst index 34899cf..9cda8b6 100644 --- a/docs/releasenotes/issues.rst +++ b/docs/releasenotes/issues.rst @@ -9,9 +9,6 @@ Die nachfolgende Liste bezieht sich auf die aktuelle Version der AusweisApp2. - Bei Erhöhung der Schriftgröße über 175% kommt es zu Darstellungsfehlern. - - Unter OS X 10.9 wird teilweise das Auflegen eines Ausweisdokumentes erst - nach einem Neustart der AusweisApp2 erkannt. - - Wenn unter OS X ein Kartenleser mit aufliegendem Ausweisdokument angeschlossen wird und eine Selbstauskunft angestartet wurde, kann unter Umständen die AusweisApp2 einfrieren. diff --git a/docs/releasenotes/support.rst b/docs/releasenotes/support.rst index f2523ae..6b443a9 100644 --- a/docs/releasenotes/support.rst +++ b/docs/releasenotes/support.rst @@ -8,8 +8,6 @@ der AusweisApp2 unterstützt. Betriebssysteme """"""""""""""" - - OS X 10.9 - - OS X 10.10 - OS X 10.11 diff --git a/docs/releasenotes/versions.rst b/docs/releasenotes/versions.rst index 8bf5ccd..d554d8e 100644 --- a/docs/releasenotes/versions.rst +++ b/docs/releasenotes/versions.rst @@ -1,6 +1,16 @@ Versionen ========= +Versionszweig 1.12 +------------------ +.. toctree:: + :maxdepth: 1 + + 1.12.2 + 1.12.1 + 1.12.0 + + Versionszweig 1.10 ------------------ .. toctree:: diff --git a/docs/sdk/android.rst b/docs/sdk/android.rst index 0f5084c..ee3fb2b 100644 --- a/docs/sdk/android.rst +++ b/docs/sdk/android.rst @@ -4,7 +4,7 @@ This chapter deals with the Android specific properties of the AusweisApp2 SDK. The AusweisApp2 core is encapsulated into an **Android service** which is running in the background without a user interface. This service is interfaced via an Android specific interprocess communication (IPC) mechanism. The basics -of this very mechanism - the **Android Interface Definition Language** (AIDL) - +of this mechanism - the **Android Interface Definition Language** (AIDL) - are introduced in the following section. The following section deals with the cryptographic verification of the SDKs authenticity. This step is necessary to ensure that the SDK has not been modified in a malicious way. Subsequent @@ -12,6 +12,32 @@ sections deal with the SDK interface itself and explain which steps are necessary in order to talk to the AusweisApp2 SDK. +Security +-------- +The following listing provides information about the solution to provide a +secure connection to AusweisApp2. + + - Data between two apps connected via AIDL as a bound service cannot be + grabbed by an attacker. Android will send the data to the corresponding + app directly. There is no broadcast like an implicit intent. + + - An attacker cannot bind to an already bound service as AusweisApp2 will + accept only one connection at the same time. + + - An attacker cannot resume a connection after the previous app disconnects + because AusweisApp2 will reset the internal state if an app connects + with another session ID. + + - An attacker cannot grab the session ID of the previous app because + AusweisApp2 uses multiple sources of secure random number generator and + provides an optional API for the app to provide additional random number + entropy. + + - An attacker cannot fake AusweisApp2 for other apps because the connection + via AIDL is bound with package name "com.governikus.ausweisapp2". Google + ensures that there is no other app in Google Play Store with that package + name. Also the client app can check the fingerprint of signature certificate + used for that package name. @@ -623,15 +649,17 @@ are shown in code listing below. void enable() { - mAdapter.enableForegroundDispatch(mActivity, - mPendingIntent, - mFilters, - mTechLists); + if (mAdapter != null) + mAdapter.enableForegroundDispatch(mActivity, + mPendingIntent, + mFilters, + mTechLists); } void disable() { - mAdapter.disableForegroundDispatch(mActivity); + if (mAdapter != null) + mAdapter.disableForegroundDispatch(mActivity); } } diff --git a/docs/sdk/commands.rst b/docs/sdk/commands.rst index 0e6d4f6..c1a3761 100644 --- a/docs/sdk/commands.rst +++ b/docs/sdk/commands.rst @@ -281,15 +281,18 @@ For detailed information see message :ref:`enter_pin`. If the PIN was correct, the workflow will continue. +If the last attempt to enter the PIN failed, AusweisApp2 +will send the message :ref:`enter_puk`. -- **pin**: The personal identification number of the card. + +- **value**: The personal identification number of the card. This must be 6 digits. .. code-block:: json { "cmd": "SET_PIN", - "pin": "123456" + "value": "123456" } .. note:: @@ -313,14 +316,14 @@ The AusweisApp2 will send an :ref:`enter_can` message on error. Otherwise the workflow will continue with :ref:`enter_pin`. -- **can**: The card access number of the card. +- **value**: The card access number of the card. This must be 6 digits. .. code-block:: json { "cmd": "SET_CAN", - "can": "123456" + "value": "123456" } .. note:: diff --git a/docs/sdk/messages.rst b/docs/sdk/messages.rst index 45f1e0f..64be8fc 100644 --- a/docs/sdk/messages.rst +++ b/docs/sdk/messages.rst @@ -280,11 +280,11 @@ and the CAN was incorrect the AusweisApp2 will send :ref:`enter_can` again but without an error parameter. -- **error**: Optional error message if your command :ref:`set_can` - was invalid. + - **error**: Optional error message if your command :ref:`set_can` + was invalid. -- **reader**: Information about the used card and card reader. - Please see message :ref:`READER` for details. + - **reader**: Information about the used card and card reader. + Please see message :ref:`reader` for details. .. code-block:: json @@ -297,7 +297,6 @@ again but without an error parameter. "attached": true, "card": { - "inserted": true, "deactivated": false, "retryCounter": 1 } @@ -338,7 +337,7 @@ AusweisApp2 will send an :ref:`enter_pin` again with a retryCounter of **1**. was invalid. - **reader**: Information about the used card and card reader. - Please see message :ref:`READER` for details. + Please see message :ref:`reader` for details. .. code-block:: json @@ -351,7 +350,6 @@ AusweisApp2 will send an :ref:`enter_pin` again with a retryCounter of **1**. "attached": true, "card": { - "inserted": true, "deactivated": false, "retryCounter": 3 } @@ -361,6 +359,41 @@ AusweisApp2 will send an :ref:`enter_pin` again with a retryCounter of **1**. +.. _enter_puk: + +ENTER_PUK +^^^^^^^^^ +Indicates that a PUK is required to continue the workflow. + +If AusweisApp2 sends this message, you will have to +show a message to the user that the card is blocked +and needs to be unblocked by AusweisApp2. + +You need to send a :ref:`cancel` to abort the workflow. + + + - **reader**: Information about the used card and card reader. + Please see message :ref:`reader` for details. + +.. code-block:: json + + { + "msg": "ENTER_PUK", + "reader": + { + "name": "NFC", + "attached": true, + "card": + { + "deactivated": false, + "retryCounter": 0 + } + } + } + + + + .. _info: INFO @@ -422,8 +455,9 @@ If your application receives this message it should show a hint to the user. After the user inserted a card the workflow will automatically -continue. If the user already inserted a card this message -won't be send at all. +continue, unless the eID functionality is disabled. +In this case, the workflow will be paused until another card is inserted. +If the user already inserted a card this message will not be sent at all. This message will also be send if there is no connected card reader. @@ -492,14 +526,16 @@ card reader or removed from a card reader. Your application can explicitly check for card reader with :ref:`get_reader`. +If a workflow is in progress and a card with disabled eID functionality was +inserted, this message will still be sent, but the workflow will be paused +until a card with enabled eID functionality is inserted. + - **name**: Identifier of card reader. - **attached**: Indicates if a card reader is connected or disconnected. - - **card**: Provides information about inserted card. - - - **inserted**: True if card inserted, otherwise false. + - **card**: Provides information about inserted card, otherwise null. - **deactivated**: True if eID functionality is deactivated, otherwise false. @@ -514,7 +550,6 @@ Your application can explicitly check for card reader with :ref:`get_reader`. "attached": true, "card": { - "inserted": true, "deactivated": false, "retryCounter": 3 } @@ -531,7 +566,7 @@ Provides information about all connected card readers. - **reader**: A list of all connected card readers. Please - see message :ref:`READER` for details. + see message :ref:`reader` for details. .. code-block:: json @@ -542,10 +577,7 @@ Provides information about all connected card readers. { "name": "Example reader 1 [SmartCard] (1234567) 01 00", "attached": true, - "card": - { - "inserted": false - } + "card": null }, { @@ -553,7 +585,6 @@ Provides information about all connected card readers. "attached": true, "card": { - "inserted": true, "deactivated": false, "retryCounter": 3 } diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 5f1fe6d..c5d961b 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -51,7 +51,7 @@ ENDIF() IF(CMAKE_BUILD_TYPE) STRING(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) ELSE() - SET(CMAKE_BUILD_TYPE "RELEASE" CACHE STRING "build type configuration" FORCE) + SET(CMAKE_BUILD_TYPE "DEBUG" CACHE STRING "build type configuration" FORCE) ENDIF() IF(NOT ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "RELEASE") @@ -97,11 +97,11 @@ INCLUDE(Messages) ################################## Versionen -SET(QT 5.7.0) -SET(OPENSSL 1.0.2j) +SET(QT 5.8.0) +SET(QT_HASH 0f4c54386d3dbac0606a936a7145cebb7b94b0ca2d29bc001ea49642984824b6) -SET(QT_HASH a6a2632de7e44bbb790bc3b563f143702c610464a7f537d02036749041fd1800) -SET(OPENSSL_HASH e7aff292be21c259c6af26469c7a9b3ba26e9abaaffd325e3dccc9785256c431) +SET(OPENSSL 1.0.2k) +SET(OPENSSL_HASH 6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0) ################################## Files SET(QT_FILE qt-everywhere-opensource-src-${QT}.tar.xz) @@ -131,29 +131,12 @@ ENDIF() ######################################################################### IF(ANDROID) - SET(HOST --host=${ANDROID_TOOLCHAIN_MACHINE_NAME}) - FIND_PROGRAM(SED_CMD sed CMAKE_FIND_ROOT_PATH_BOTH) IF(SED_CMD) MESSAGE(STATUS "Using 'sed' command... ${SED_CMD}") ELSE() MESSAGE(FATAL_ERROR "Cannot find 'sed' command") ENDIF() - - SET(ANDROID_STANDALONE "${PROJECT_BINARY_DIR}/standalone") - IF(ANDROID_NDK AND NOT EXISTS ${ANDROID_STANDALONE}) - MESSAGE(STATUS "Creating standalone toolchain...") - - EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${ANDROID_NDK}/build/tools/make_standalone_toolchain.py - --arch ${ANDROID_ARCH_NAME} --api ${ANDROID_NATIVE_API_LEVEL} --install-dir ${ANDROID_STANDALONE} - RESULT_VARIABLE CREATE_STANDALONE_TOOLCHAIN) - - if(${CREATE_STANDALONE_TOOLCHAIN} EQUAL 0) - MESSAGE(STATUS "You need to call 'export PATH=${ANDROID_STANDALONE}/bin:\$PATH'") - ELSE() - MESSAGE(FATAL_ERROR "Cannot create standalone toolchain") - ENDIF() - ENDIF() ENDIF() IF(IOS) @@ -169,11 +152,7 @@ SET(ENABLED_TARGETS) ################################## OpenSSL ######################################################################### LIST(APPEND ENABLED_TARGETS openssl) -SET(OPENSSL_CONFIGURE_FLAGS no-ssl2 no-ssl3 no-ssl3-method no-dtls no-srp no-idea no-mdc2 no-rc5 no-hw -DOPENSSL_NO_HEARTBEATS shared) - -IF(NOT WIN32) - SET(OPENSSL_CONFIGURE_FLAGS no-engine ${OPENSSL_CONFIGURE_FLAGS}) -ENDIF() +SET(OPENSSL_CONFIGURE_FLAGS no-ssl2 no-ssl3 no-ssl3-method no-dtls no-srp no-idea no-mdc2 no-rc5 no-hw no-engine no-dso -DOPENSSL_NO_HEARTBEATS shared) IF(IOS) SET(OPENSSL_PATCH_COMMAND ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl_iOS.patch && ) @@ -190,18 +169,19 @@ ELSEIF(MSVC) SET(OPENSSL_ADDITIONAL_MAKE -f ms/ntdll.mak) SET(OPENSSL_INSTALL_TARGET install) ELSEIF(ANDROID) - IF("${ANDROID_TOOLCHAIN_MACHINE_NAME}" STREQUAL "arm-linux-androideabi") + IF(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") SET(OPENSSL_ARCH android-armv7) SET(OPENSSL_COMPILER_FLAGS "-mfloat-abi=softfp") - ELSEIF("${ANDROID_TOOLCHAIN_MACHINE_NAME}" STREQUAL "i686-linux-android") + ELSEIF(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") SET(OPENSSL_ARCH android-x86) - ELSEIF("${ANDROID_TOOLCHAIN_MACHINE_NAME}" STREQUAL "aarch64-linux-android") + ELSEIF(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") SET(OPENSSL_ARCH android) ELSE() - MESSAGE(FATAL_ERROR "ANDROID_TOOLCHAIN_MACHINE_NAME not supported by openssl") + MESSAGE(FATAL_ERROR "CMAKE_ANDROID_ARCH_ABI not supported by openssl") ENDIF() - SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} --cross-compile-prefix=${ANDROID_TOOLCHAIN_MACHINE_NAME}- ${OPENSSL_ARCH}) + SET(OPENSSL_ENV export ANDROID_DEV=${CMAKE_SYSROOT}/usr &&) + SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} --cross-compile-prefix=${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX} ${OPENSSL_ARCH}) SET(OPENSSL_PATCH_COMMAND ${PATCH_CMD} -p0 ${PATCH_OPTIONS} ${PATCHES_DIR}/soname/openssl_makefile.shared.patch && ${SH_CMD} ${PATCHES_DIR}/soname/openssl_sed.sh && ) ELSEIF(BSD) @@ -229,6 +209,7 @@ IF(IOS) PATCH_COMMAND ${OPENSSL_PATCH_COMMAND} + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl-fix-no-engine-build.patch && ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl_rsa_psk.patch CONFIGURE_COMMAND ${PERL_EXECUTABLE} Configure --prefix=${PROJECT_BINARY_DIR}/openssl64-prefix/tmp ${OPENSSL_CONFIGURE_FLAGS} "-arch ${IOS_ARCH64}" "${COMPILER_FLAGS}" @@ -245,6 +226,7 @@ IF(IOS) PATCH_COMMAND ${OPENSSL_PATCH_COMMAND} + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl-fix-no-engine-build.patch && ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl_rsa_psk.patch CONFIGURE_COMMAND ${PERL_EXECUTABLE} Configure --prefix=${PROJECT_BINARY_DIR}/openssl-prefix/tmp ${OPENSSL_CONFIGURE_FLAGS} "-arch ${IOS_ARCH}" "${COMPILER_FLAGS}" @@ -262,16 +244,17 @@ ExternalProject_Add(openssl PATCH_COMMAND ${OPENSSL_PATCH_COMMAND} + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl-fix-no-engine-build.patch && ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl_rsa_psk.patch - CONFIGURE_COMMAND ${PERL_EXECUTABLE} Configure --prefix=${DESTINATION_DIR} ${OPENSSL_CONFIGURE_FLAGS} "${COMPILER_FLAGS}" "${OPENSSL_COMPILER_FLAGS}" - BUILD_COMMAND ${MAKE} ${OPENSSL_ADDITIONAL_MAKE} + CONFIGURE_COMMAND ${OPENSSL_ENV} ${PERL_EXECUTABLE} Configure --prefix=${DESTINATION_DIR} ${OPENSSL_CONFIGURE_FLAGS} "${COMPILER_FLAGS}" "${OPENSSL_COMPILER_FLAGS}" + BUILD_COMMAND ${OPENSSL_ENV} ${MAKE} ${OPENSSL_ADDITIONAL_MAKE} BUILD_IN_SOURCE 1 INSTALL_COMMAND ${MAKE} ${OPENSSL_ADDITIONAL_MAKE} ${OPENSSL_INSTALL_TARGET} ) ExternalProject_Add_Step(openssl prebuild - COMMAND ${OPENSSL_PREBUILD} + COMMAND ${OPENSSL_ENV} ${OPENSSL_PREBUILD} DEPENDEES configure DEPENDERS build WORKING_DIRECTORY ) @@ -282,15 +265,9 @@ IF(UNIX) ENDIF() IF(ANDROID) - IF(ANDROID_COMPILER_IS_CLANG) - SET(COMPILER clang) - ELSE() - SET(COMPILER gcc) - ENDIF() - ADD_CUSTOM_COMMAND(TARGET openssl POST_BUILD - COMMAND ${ANDROID_TOOLCHAIN_MACHINE_NAME}-${COMPILER} -o ${DESTINATION_DIR}/lib/libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX} -shared -Wl,-soname=libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX} -Wl,--whole-archive ${DESTINATION_DIR}/lib/libcrypto${CMAKE_STATIC_LIBRARY_SUFFIX} -Wl,--no-whole-archive - COMMAND ${ANDROID_TOOLCHAIN_MACHINE_NAME}-${COMPILER} -o ${DESTINATION_DIR}/lib/libgovssl${CMAKE_SHARED_LIBRARY_SUFFIX} -shared -Wl,-soname=libgovssl${CMAKE_SHARED_LIBRARY_SUFFIX} -Wl,--whole-archive ${DESTINATION_DIR}/lib/libssl${CMAKE_STATIC_LIBRARY_SUFFIX} -Wl,--no-whole-archive ${DESTINATION_DIR}/lib/libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX}) + COMMAND ${CMAKE_C_COMPILER} --sysroot ${CMAKE_SYSROOT} -o ${DESTINATION_DIR}/lib/libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX} -shared -Wl,-soname=libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX} -Wl,--whole-archive ${DESTINATION_DIR}/lib/libcrypto${CMAKE_STATIC_LIBRARY_SUFFIX} -Wl,--no-whole-archive + COMMAND ${CMAKE_C_COMPILER} --sysroot ${CMAKE_SYSROOT} -o ${DESTINATION_DIR}/lib/libgovssl${CMAKE_SHARED_LIBRARY_SUFFIX} -shared -Wl,-soname=libgovssl${CMAKE_SHARED_LIBRARY_SUFFIX} -Wl,--whole-archive ${DESTINATION_DIR}/lib/libssl${CMAKE_STATIC_LIBRARY_SUFFIX} -Wl,--no-whole-archive ${DESTINATION_DIR}/lib/libgovcrypto${CMAKE_SHARED_LIBRARY_SUFFIX}) ELSEIF(MAC) SET(OPENSSL_FILE_VERSION 1.0.0) ADD_CUSTOM_COMMAND(TARGET openssl POST_BUILD @@ -299,7 +276,7 @@ ELSEIF(MAC) COMMAND install_name_tool -change ${DESTINATION_DIR}/lib/libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} libcrypto.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libssl.${OPENSSL_FILE_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}) ENDIF() -################################## QT +################################## Qt ######################################################################### LIST(APPEND ENABLED_TARGETS qt) @@ -310,13 +287,13 @@ ELSE() SET(QT_CONFIGURE_FLAGS -release -no-qml-debug) ENDIF() -SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} -opensource -confirm-license -shared -qt-zlib -no-mtdev -qt-libpng -qt-libjpeg -qt-freetype -no-harfbuzz -qt-pcre -system-proxies -no-compile-examples -nomake examples -nomake tests -no-sql-sqlite -openssl-linked -I ${DESTINATION_DIR}/include -L ${DESTINATION_DIR}/lib) -SET(QT_CONFIGURE_FLAGS_OTHER --prefix=${DESTINATION_DIR} -no-journald -no-dbus -no-directfb -no-linuxfb) -SET(QT_CONFIGURE_FLAGS_SKIP_MODULES -skip qtwebchannel -skip qtwebengine -skip qtscript -skip qtactiveqt -skip qtlocation -skip qtserialbus -skip qtserialport -skip qtgamepad -skip qtvirtualkeyboard -skip qtcanvas3d -skip qtcharts -skip qtdatavis3d -skip qt3d -skip qtpurchasing) +SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} -prefix ${DESTINATION_DIR} -opensource -confirm-license -qt-zlib -no-mtdev -qt-libpng -qt-libjpeg -no-harfbuzz -qt-pcre -system-proxies -no-compile-examples -nomake examples -nomake tests -no-sql-sqlite -openssl-linked -I ${DESTINATION_DIR}/include -L ${DESTINATION_DIR}/lib) +SET(QT_CONFIGURE_FLAGS_OTHER -no-journald -no-dbus -no-directfb -no-linuxfb) +SET(QT_CONFIGURE_FLAGS_SKIP_MODULES -skip qtscxml -skip qtxmlpatterns -skip qtwebchannel -skip qtwebengine -skip qtscript -skip qtactiveqt -skip qtlocation -skip qtserialbus -skip qtserialport -skip qtgamepad -skip qtvirtualkeyboard -skip qtcanvas3d -skip qtcharts -skip qtdatavis3d -skip qt3d -skip qtpurchasing) SET(QT_CONFIGURE ./configure) IF(IOS) - SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_OTHER} -framework -sdk iphoneos -xplatform macx-ios-clang) + SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_OTHER} -sdk iphoneos -xplatform macx-ios-clang) ELSEIF(APPLE) FIND_PROGRAM(XCODE_SELECT xcode-select) IF(NOT XCODE_SELECT) @@ -338,18 +315,22 @@ ELSEIF(WIN32) SET(QT_OPENSSL OPENSSL_LIBS=-lcrypto\ -lssl) ENDIF() - SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_OPENSSL} -prefix ${DESTINATION_DIR} -opengl desktop -no-icu -no-sql-odbc -platform ${QT_PLATFORM}) + SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_OPENSSL} -opengl desktop -no-icu -no-sql-odbc -platform ${QT_PLATFORM}) SET(QT_CONFIGURE configure.bat) ELSEIF(ANDROID) SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_OTHER} - -android-sdk ${ANDROID_SDK} -android-ndk ${ANDROID_NDK} -android-ndk-platform android-${ANDROID_NATIVE_API_LEVEL} -android-ndk-host ${ANDROID_NDK_HOST_SYSTEM_NAME} - -android-arch ${ANDROID_ABI} -android-toolchain-version ${ANDROID_COMPILER_VERSION} + -android-sdk ${ANDROID_SDK} -android-ndk ${CMAKE_ANDROID_NDK} -android-ndk-platform android-${CMAKE_SYSTEM_VERSION} -android-ndk-host ${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG} + -android-arch ${CMAKE_ANDROID_ARCH_ABI} -android-toolchain-version ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION} -xplatform android-g++) SET(QT_ENV export OPENSSL_LIBS=-lgovcrypto\ -lgovssl &&) ELSE() SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_OTHER} -no-libproxy) ENDIF() +IF(IOS OR ANDROID) + SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} -no-widgets) +ENDIF() + ExternalProject_Add(qt DEPENDS openssl URL ${QT_URL}/${QT_FILE} @@ -357,12 +338,18 @@ ExternalProject_Add(qt DOWNLOAD_DIR ${PACKAGES_DIR} PATCH_COMMAND ${QT_PATCH_COMMAND} - ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-disable-qtplugininfo.patch && - ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Re-apply-the-cast-part-of-commit-392c7b99348e2a96ef1.patch && - ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Enable-use-of-the-same-NetworkAccessAuthenticationManager.patch && - ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Make-sure-SSL-configuration-is-correct-in-QNetworkRe.patch && - ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Make-QCryptographicHash-a-Q_GADGET.patch && ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Make-server-side-signature-algorithms-configurable.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Use-apksigner-by-default-if-available-to-sign-the-AP.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Android-Add-support-for-sendCommand-to-QNearFieldTarget.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Android-QNearfieldTarget-Introduce-maxCommandLength.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-QNearfieldTarget-Introduce-set-keepConnection-and-disconnect.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Use-defaultSize-according-to-svg-standard-in-svg-plugin.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Do-not-request-an-unnessessary-dangerous-right.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Introduce-QNetworkAccessManager-clearConnectionCache.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Make-variant-selection-possible-if-base-is-missing.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Allow-using-nfc-when-running-as-a-service.patch && ${CMAKE_COMMAND} -E touch qtbase/.gitignore CONFIGURE_COMMAND ${QT_ENV} ${QT_CONFIGURE} ${QT_CONFIGURE_FLAGS} ${QT_CONFIGURE_FLAGS_SKIP_MODULES} BUILD_COMMAND ${MAKE} ${MAKE_JOBS} @@ -404,7 +391,7 @@ IF(IOS) # Globbing is not supported by cmake command mode! This will work if executed with unix shell only. SET(CLEANUP_FILES ${CMAKE_COMMAND} -E remove ${DESTINATION_DIR}/lib/*.dylib) ELSEIF(ANDROID) - SET(SYSTEM_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_CXX_COMPILER_ID}_${ANDROID_ABI}) + SET(SYSTEM_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_CXX_COMPILER_ID}_${CMAKE_ANDROID_ARCH_ABI}) ELSE() SET(SYSTEM_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_CXX_COMPILER_ID}) ENDIF() diff --git a/libs/README.rst b/libs/README.rst index 877caa0..1b406bf 100644 --- a/libs/README.rst +++ b/libs/README.rst @@ -36,7 +36,7 @@ Notwendige Bibliotheken: Notwendige Tools: -- CMake >= 3.1.0 +- CMake >= 3.1.0 (>= 3.7.0 für Android) - http://www.cmake.org @@ -95,7 +95,7 @@ Beispiel: Innerhalb von /Users/governikus/AusweisApp2 befindet sich der Quellcod $ cd /Users/governikus $ mkdir build $ cd build - $ cmake -DPACKAGES_DIR=/Users/governikus/packages ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=/Users/governikus/packages ../AusweisApp2/libs $ make @@ -164,7 +164,7 @@ Dabei wird Qt über Windows-CLI und OpenSSL unter MSYS gebaut. #. cd c:\msys\1.0\home\user\qt -#. cmake -DPACKAGES_DIR=C:/packages C:/AusweisApp2/libs -G "MinGW Makefiles" +#. cmake -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=C:/packages C:/AusweisApp2/libs -G "MinGW Makefiles" #. MSYS Shell starten @@ -198,7 +198,7 @@ Beispiel: Innerhalb von /Users/governikus/AusweisApp2 befindet sich der Quellcod $ cd /Users/governikus $ mkdir build $ cd build - $ cmake -DPACKAGES_DIR=/Users/governikus/packages -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/iOS.toolchain.cmake ../AusweisApp2/libs + $ cmake -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=/Users/governikus/packages -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/iOS.toolchain.cmake ../AusweisApp2/libs $ make @@ -211,20 +211,20 @@ Komponenten vorhanden sein: - https://developer.android.com/tools/sdk/ndk/index.html - - Getestet: r12b (x86_64) + - Getestet: r13b (x86_64) - Android SDK mit gesetztem ANDROID_HOME - https://developer.android.com/sdk/index.html#Other - - Getestet: 25.1.7 + - Getestet: 25.2.2 - Unter bestimmten Umständen kann es vorkommen, dass die Build-Tools-Version nicht erkannt wird. Dies kann mittels der Umgebungsvariable ANDROID_BUILD_TOOLS_REVISION behoben werden. Die genaue Version ist im Android Manager vom Android SDK (./tools/android) hinterlegt. - Um Qt erfolgreich zu bauen, sind verschiedene API Level von Android notwendig. - Diese sollten mindestens Level 10, 11, 16 und 18 sein. Nähere Informationen dazu + Diese sollten mindestens Level 18 und 21 sein. Nähere Informationen dazu sind im Wiki von Qt enthalten: http://wiki.qt.io/Android Die Plattformen können mittels Android Manager nachinstalliert werden. @@ -240,14 +240,9 @@ Beispiel: Innerhalb von /home/governikus/AusweisApp2 befindet sich der Quellcode $ cd /home/governikus $ mkdir build $ cd build - $ cmake -DPACKAGES_DIR=/home/governikus/packages -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/android.toolchain.cmake ../AusweisApp2/libs - $ export PATH=/home/governikus/build/standalone/bin:$PATH + $ cmake -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=/home/governikus/packages -DCMAKE_TOOLCHAIN_FILE=../AusweisApp2/cmake/android.toolchain.cmake ../AusweisApp2/libs $ make Standardmäßig wird die Architektur "armeabi-v7a" gewählt. Um zum Beispiel die Toolchain für x86-Architektur -zu bauen , ist beim Aufruf von CMake der Parameter "-DANDROID_ABI=x86" mitzugeben. - -Der "export" der PATH-Variable wird auch beim Konfigurieren angezeigt. Siehe dazu "You need to call ..."! -Sofern die PATH-Variable nicht um den standalone-Ordner erweitert wird, wird es beim Build zu dem Fehler kommen, -dass der Cross-Compiler für die jeweilige Architektur nicht gefunden werden konnte. +zu bauen , ist beim Aufruf von CMake der Parameter "-DCMAKE_ANDROID_ARCH_ABI=x86" mitzugeben. diff --git a/patches/openssl-fix-no-engine-build.patch b/patches/openssl-fix-no-engine-build.patch new file mode 100644 index 0000000..0d574f8 --- /dev/null +++ b/patches/openssl-fix-no-engine-build.patch @@ -0,0 +1,75 @@ +From 08b250d56592b8e385cfc37c2d938b839653c264 Mon Sep 17 00:00:00 2001 +From: "Dr. Stephen Henson" +Date: Sat, 16 Jan 2016 16:11:34 +0000 +Subject: [PATCH] fix no-engine build + +Reviewed-by: Rich Salz +Reviewed-by: Richard Levitte +--- + crypto/ts/ts.h | 2 ++ + util/libeay.num | 4 ++-- + util/mk1mf.pl | 3 +-- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/crypto/ts/ts.h b/crypto/ts/ts.h +index 2daa1b2fb..fc8c14b2d 100644 +--- a/crypto/ts/ts.h ++++ b/crypto/ts/ts.h +@@ -737,9 +737,11 @@ EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass); + const char *TS_CONF_get_tsa_section(CONF *conf, const char *section); + int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb, + TS_RESP_CTX *ctx); ++#ifndef OPENSSL_NO_ENGINE + int TS_CONF_set_crypto_device(CONF *conf, const char *section, + const char *device); + int TS_CONF_set_default_engine(const char *name); ++#endif + int TS_CONF_set_signer_cert(CONF *conf, const char *section, + const char *cert, TS_RESP_CTX *ctx); + int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs, +diff --git a/util/libeay.num b/util/libeay.num +index 2094ab364..23ade08e2 100755 +--- a/util/libeay.num ++++ b/util/libeay.num +@@ -3874,7 +3874,7 @@ b2i_PVK_bio 4250 EXIST::FUNCTION:RC4 + ASN1_UTCTIME_adj 4251 EXIST::FUNCTION: + TS_TST_INFO_new 4252 EXIST::FUNCTION: + EVP_MD_do_all_sorted 4253 EXIST::FUNCTION: +-TS_CONF_set_default_engine 4254 EXIST::FUNCTION: ++TS_CONF_set_default_engine 4254 EXIST::FUNCTION:ENGINE + TS_ACCURACY_set_seconds 4255 EXIST::FUNCTION: + TS_TST_INFO_get_time 4256 EXIST::FUNCTION: + PKCS8_pkey_get0 4257 EXIST::FUNCTION: +@@ -4099,7 +4099,7 @@ EVP_PKEY_meth_find 4469 EXIST::FUNCTION: + EVP_PKEY_id 4470 EXIST::FUNCTION: + TS_TST_INFO_set_serial 4471 EXIST::FUNCTION: + a2i_GENERAL_NAME 4472 EXIST::FUNCTION: +-TS_CONF_set_crypto_device 4473 EXIST::FUNCTION: ++TS_CONF_set_crypto_device 4473 EXIST::FUNCTION:ENGINE + EVP_PKEY_verify_init 4474 EXIST::FUNCTION: + TS_CONF_set_policies 4475 EXIST::FUNCTION: + ASN1_PCTX_new 4476 EXIST::FUNCTION: +diff --git a/util/mk1mf.pl b/util/mk1mf.pl +index 7a3ae11f7..6ada6fa62 100755 +--- a/util/mk1mf.pl ++++ b/util/mk1mf.pl +@@ -428,7 +428,6 @@ EOF + { + $extra_install .= <<"EOF" + \$(MKDIR) \"\$(INSTALLTOP)${o}lib${o}engines\" +- \$(CP) \"\$(E_SHLIB)\" \"\$(INSTALLTOP)${o}lib${o}engines\" + EOF + } + } +@@ -597,7 +596,7 @@ init: \$(TMP_D) \$(LIB_D) \$(INC_D) \$(INCO_D) \$(BIN_D) \$(TEST_D) headers + + headers: \$(HEADER) \$(EXHEADER) + +-lib: \$(LIBS_DEP) \$(E_SHLIB) ++lib: \$(LIBS_DEP) + + exe: \$(T_EXE) \$(BIN_D)$o\$(E_EXE)$exep + +-- +2.11.0 + diff --git a/patches/openssl_rsa_psk.patch b/patches/openssl_rsa_psk.patch index 5e54697..05c2f66 100644 --- a/patches/openssl_rsa_psk.patch +++ b/patches/openssl_rsa_psk.patch @@ -1,4 +1,4 @@ -From 47367d2aed4a3acade0a29b45c01b0c2b3cc2854 Mon Sep 17 00:00:00 2001 +From 496ac24b811593df82490643d574a037aa47d80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Thu, 23 Apr 2015 20:59:30 +0200 Subject: [PATCH] Introduce TLS-RSA-PSK support @@ -23,7 +23,7 @@ PR: 2464 9 files changed, 587 insertions(+), 35 deletions(-) diff --git x/doc/apps/ciphers.pod y/doc/apps/ciphers.pod -index 9224557..234350f 100644 +index 922455725..234350faa 100644 --- x/doc/apps/ciphers.pod +++ y/doc/apps/ciphers.pod @@ -583,10 +583,22 @@ Note: these ciphers can also be used in SSL v3. @@ -50,7 +50,7 @@ index 9224557..234350f 100644 =head2 Deprecated SSL v2.0 cipher suites. diff --git x/ssl/s3_clnt.c y/ssl/s3_clnt.c -index 2185347..1bd6138 100644 +index 32f2f1aee..cd05f4d52 100644 --- x/ssl/s3_clnt.c +++ y/ssl/s3_clnt.c @@ -337,7 +337,7 @@ int ssl3_connect(SSL *s) @@ -102,7 +102,7 @@ index 2185347..1bd6138 100644 /* Temporary RSA keys only allowed in export ciphersuites */ if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { al = SSL_AD_UNEXPECTED_MESSAGE; -@@ -2012,8 +2021,16 @@ int ssl3_get_key_exchange(SSL *s) +@@ -2034,8 +2043,16 @@ int ssl3_get_key_exchange(SSL *s) } } } else { @@ -121,7 +121,7 @@ index 2185347..1bd6138 100644 /* Might be wrong key type, check it */ if (ssl3_check_cert_and_algorithm(s)) /* Otherwise this shouldn't happen */ -@@ -3102,7 +3119,11 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3124,7 +3141,11 @@ int ssl3_send_client_key_exchange(SSL *s) } #endif #ifndef OPENSSL_NO_PSK @@ -134,7 +134,7 @@ index 2185347..1bd6138 100644 /* * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a * \0-terminated identity. The last byte is for us for simulating -@@ -3110,8 +3131,8 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3132,8 +3153,8 @@ int ssl3_send_client_key_exchange(SSL *s) */ char identity[PSK_MAX_IDENTITY_LEN + 2]; size_t identity_len; @@ -144,7 +144,7 @@ index 2185347..1bd6138 100644 unsigned int pre_ms_len = 0, psk_len = 0; int psk_err = 1; -@@ -3143,14 +3164,34 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3165,14 +3186,34 @@ int ssl3_send_client_key_exchange(SSL *s) ERR_R_INTERNAL_ERROR); goto psk_err; } @@ -187,7 +187,7 @@ index 2185347..1bd6138 100644 if (s->session->psk_identity_hint != NULL) OPENSSL_free(s->session->psk_identity_hint); -@@ -3180,8 +3221,41 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3202,8 +3243,41 @@ int ssl3_send_client_key_exchange(SSL *s) pre_ms_len); s2n(identity_len, p); memcpy(p, identity, identity_len); @@ -229,7 +229,7 @@ index 2185347..1bd6138 100644 psk_err: OPENSSL_cleanse(identity, sizeof(identity)); OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); -@@ -3552,7 +3626,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) +@@ -3574,7 +3648,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) } #endif #ifndef OPENSSL_NO_RSA @@ -242,7 +242,7 @@ index 2185347..1bd6138 100644 if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) { SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, -@@ -3619,7 +3697,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) +@@ -3641,7 +3719,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { #ifndef OPENSSL_NO_RSA @@ -256,7 +256,7 @@ index 2185347..1bd6138 100644 SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_EXPORT_TMP_RSA_KEY); diff --git x/ssl/s3_lib.c y/ssl/s3_lib.c -index 0385e03..ce69ec4 100644 +index 0385e039c..ce69ec470 100644 --- x/ssl/s3_lib.c +++ y/ssl/s3_lib.c @@ -1765,6 +1765,74 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[] = { @@ -487,7 +487,7 @@ index 0385e03..ce69ec4 100644 #endif /* OPENSSL_NO_PSK */ diff --git x/ssl/s3_srvr.c y/ssl/s3_srvr.c -index 01ccd5d..154d22e 100644 +index ea56f9ca8..2b1797cc8 100644 --- x/ssl/s3_srvr.c +++ y/ssl/s3_srvr.c @@ -458,19 +458,23 @@ int ssl3_accept(SSL *s) @@ -538,7 +538,7 @@ index 01ccd5d..154d22e 100644 /* no cert request */ skip = 1; s->s3->tmp.cert_request = 0; -@@ -1827,7 +1834,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1830,7 +1837,11 @@ int ssl3_send_server_key_exchange(SSL *s) } else #endif /* !OPENSSL_NO_ECDH */ #ifndef OPENSSL_NO_PSK @@ -551,7 +551,7 @@ index 01ccd5d..154d22e 100644 /* * reserve size for record length and PSK identity hint */ -@@ -1866,7 +1877,14 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1879,7 +1890,14 @@ int ssl3_send_server_key_exchange(SSL *s) } if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) @@ -567,7 +567,7 @@ index 01ccd5d..154d22e 100644 if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md)) == NULL) { al = SSL_AD_DECODE_ERROR; -@@ -1926,7 +1944,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1953,7 +1971,11 @@ int ssl3_send_server_key_exchange(SSL *s) #endif #ifndef OPENSSL_NO_PSK @@ -580,7 +580,7 @@ index 01ccd5d..154d22e 100644 /* copy PSK identity hint */ s2n(strlen(s->ctx->psk_identity_hint), p); strncpy((char *)p, s->ctx->psk_identity_hint, -@@ -1942,7 +1964,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1969,7 +1991,11 @@ int ssl3_send_server_key_exchange(SSL *s) * points to the space at the end. */ #ifndef OPENSSL_NO_RSA @@ -593,7 +593,7 @@ index 01ccd5d..154d22e 100644 q = md_buf; j = 0; for (num = 2; num > 0; num--) { -@@ -2816,6 +2842,181 @@ int ssl3_get_client_key_exchange(SSL *s) +@@ -2843,6 +2869,181 @@ int ssl3_get_client_key_exchange(SSL *s) goto f_err; } else #endif @@ -776,7 +776,7 @@ index 01ccd5d..154d22e 100644 if (alg_k & SSL_kSRP) { int param_len; diff --git x/ssl/ssl.h y/ssl/ssl.h -index 90aeb0c..78cf221 100644 +index 90aeb0ce4..78cf2212e 100644 --- x/ssl/ssl.h +++ y/ssl/ssl.h @@ -254,6 +254,7 @@ extern "C" { @@ -796,7 +796,7 @@ index 90aeb0c..78cf221 100644 # define SSL_TXT_DES "DES" diff --git x/ssl/ssl_ciph.c y/ssl/ssl_ciph.c -index 2ad8f43..33f6da1 100644 +index 2ad8f4392..33f6da1be 100644 --- x/ssl/ssl_ciph.c +++ y/ssl/ssl_ciph.c @@ -263,6 +263,7 @@ static const SSL_CIPHER cipher_aliases[] = { @@ -844,10 +844,10 @@ index 2ad8f43..33f6da1 100644 kx = "SRP"; break; diff --git x/ssl/ssl_lib.c y/ssl/ssl_lib.c -index 42b980a..f20505b 100644 +index f8054dae6..b835f1fa5 100644 --- x/ssl/ssl_lib.c +++ y/ssl/ssl_lib.c -@@ -2436,8 +2436,14 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) +@@ -2434,8 +2434,14 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) #ifndef OPENSSL_NO_PSK mask_k |= SSL_kPSK; @@ -863,7 +863,7 @@ index 42b980a..f20505b 100644 #endif diff --git x/ssl/ssl_locl.h y/ssl/ssl_locl.h -index 6df725f..29af2a4 100644 +index d50edd18c..3c59fff1b 100644 --- x/ssl/ssl_locl.h +++ y/ssl/ssl_locl.h @@ -314,6 +314,8 @@ @@ -876,7 +876,7 @@ index 6df725f..29af2a4 100644 /* Bits for algorithm_auth (server authentication) */ /* RSA auth */ diff --git x/ssl/tls1.h y/ssl/tls1.h -index 7e237d0..173be49 100644 +index 7e237d063..173be499f 100644 --- x/ssl/tls1.h +++ y/ssl/tls1.h @@ -410,6 +410,24 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) @@ -930,5 +930,5 @@ index 7e237d0..173be49 100644 # define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA" # define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA" -- -2.10.0 +2.11.0 diff --git a/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch b/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch new file mode 100644 index 0000000..4538465 --- /dev/null +++ b/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch @@ -0,0 +1,80 @@ +From a65c1ef2833757f49024f13900645abf62d6eb22 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Tue, 10 Jan 2017 08:52:35 +0100 +Subject: Add debug stream operator for QNetworkProxyQuery + +Change-Id: Iae215827350e47a8ce31e5828d3ad1ed54564e84 +--- + src/network/kernel/qnetworkproxy.cpp | 19 +++++++++++++++---- + src/network/kernel/qnetworkproxy.h | 4 ++++ + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git x/qtbase/src/network/kernel/qnetworkproxy.cpp y/qtbase/src/network/kernel/qnetworkproxy.cpp +index 94719e9c2d..6bd6fa2658 100644 +--- x/qtbase/src/network/kernel/qnetworkproxy.cpp ++++ y/qtbase/src/network/kernel/qnetworkproxy.cpp +@@ -1634,10 +1634,6 @@ QList QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuer + } + + #ifndef QT_NO_DEBUG_STREAM +-/*! +- \since 5.0 +- Outputs a QNetworkProxy details to a debug stream +-*/ + QDebug operator<<(QDebug debug, const QNetworkProxy &proxy) + { + QDebugStateSaver saver(debug); +@@ -1686,6 +1682,21 @@ QDebug operator<<(QDebug debug, const QNetworkProxy &proxy) + debug << '[' << scaps.join(QLatin1Char(' ')) << ']'; + return debug; + } ++ ++QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxyQuery) ++{ ++ QDebugStateSaver saver(debug); ++ debug.resetFormat().nospace() ++ << "ProxyQuery(" ++ << "type: " << proxyQuery.queryType() ++ << ", protocol: " << proxyQuery.protocolTag() ++ << ", peerPort: " << proxyQuery.peerPort() ++ << ", peerHostName: " << proxyQuery.peerHostName() ++ << ", localPort: " << proxyQuery.localPort() ++ << ", url: " << proxyQuery.url() ++ << ')'; ++ return debug; ++} + #endif + + QT_END_NAMESPACE +diff --git x/qtbase/src/network/kernel/qnetworkproxy.h y/qtbase/src/network/kernel/qnetworkproxy.h +index 8fcb7e33cf..8699c313e9 100644 +--- x/qtbase/src/network/kernel/qnetworkproxy.h ++++ y/qtbase/src/network/kernel/qnetworkproxy.h +@@ -56,6 +56,8 @@ class QNetworkConfiguration; + class QNetworkProxyQueryPrivate; + class Q_NETWORK_EXPORT QNetworkProxyQuery + { ++ Q_GADGET ++ + public: + enum QueryType { + TcpSocket, +@@ -65,6 +67,7 @@ public: + UrlRequest, + SctpServer + }; ++ Q_ENUM(QueryType) + + QNetworkProxyQuery(); + explicit QNetworkProxyQuery(const QUrl &requestUrl, QueryType queryType = UrlRequest); +@@ -222,6 +225,7 @@ public: + + #ifndef QT_NO_DEBUG_STREAM + Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxy &proxy); ++Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxyQuery); + #endif + + QT_END_NAMESPACE +-- +2.11.0 + diff --git a/patches/qt-Allow-using-nfc-when-running-as-a-service.patch b/patches/qt-Allow-using-nfc-when-running-as-a-service.patch new file mode 100644 index 0000000..309c334 --- /dev/null +++ b/patches/qt-Allow-using-nfc-when-running-as-a-service.patch @@ -0,0 +1,98 @@ +From b42f7623ee75b651f6e756a73d0f8f385f337220 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Thu, 26 Jan 2017 15:02:37 +0100 +Subject: Allow using nfc when running as a service + +With this change it will be possible to use a tag +injected from outside when running as a service. + + Intent newIntent = new Intent(); + newIntent.putExtra(NfcAdapter.EXTRA_TAG, tag); + QtNative.onNewIntent(newIntent); + +Task-number: QTBUG-57646 +Change-Id: I628d4357f023a0926e7d61914b39278342ac7161 +--- + .../src/org/qtproject/qt5/android/nfc/QtNfc.java | 24 ++++++++++++++-------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git x/qtconnectivity/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java y/qtconnectivity/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java +index 47dcf1bf..25c560f8 100644 +--- x/qtconnectivity/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java ++++ y/qtconnectivity/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java +@@ -62,22 +62,25 @@ public class QtNfc + static public NfcAdapter m_adapter = null; + static public PendingIntent m_pendingIntent = null; + static public IntentFilter[] m_filters; +- static public Activity m_activity; ++ static public Context m_context = null; ++ static public Activity m_activity = null; + + static public void setContext(Context context) + { +- if (!(context instanceof Activity)) { +- Log.w(TAG, "NFC only works with Android activities and not in Android services. " + +- "NFC has been disabled."); ++ m_context = context; ++ if (context instanceof Activity) m_activity = (Activity) context; ++ m_adapter = NfcAdapter.getDefaultAdapter(context); ++ ++ if (m_activity == null) { ++ Log.w(TAG, "New NFC tags will only be recognized with Android activities and not with Android services."); + return; + } + +- m_activity = (Activity)context; +- m_adapter = NfcAdapter.getDefaultAdapter(m_activity); + if (m_adapter == null) { + //Log.e(TAG, "No NFC available"); + return; + } ++ + m_pendingIntent = PendingIntent.getActivity( + m_activity, + 0, +@@ -103,7 +106,8 @@ public class QtNfc + + static public boolean start() + { +- if (m_adapter == null) return false; ++ if (m_adapter == null || m_activity == null) return false; ++ + m_activity.runOnUiThread(new Runnable() { + public void run() { + //Log.d(TAG, "Enabling NFC"); +@@ -136,7 +140,8 @@ public class QtNfc + + static public boolean stop() + { +- if (m_adapter == null) return false; ++ if (m_adapter == null || m_activity == null) return false; ++ + m_activity.runOnUiThread(new Runnable() { + public void run() { + //Log.d(TAG, "Disabling NFC"); +@@ -153,11 +158,11 @@ public class QtNfc + + static public boolean isAvailable() + { +- m_adapter = NfcAdapter.getDefaultAdapter(m_activity); + if (m_adapter == null) { + //Log.e(TAG, "No NFC available (Adapter is null)"); + return false; + } ++ + return m_adapter.isEnabled(); + } + +@@ -165,6 +170,7 @@ public class QtNfc + { + Log.d(TAG, "getStartIntent"); + if (m_activity == null) return null; ++ + Intent intent = m_activity.getIntent(); + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) || + NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) || +-- +2.11.0 + diff --git a/patches/qt-Android-Add-support-for-sendCommand-to-QNearFieldTarget.patch b/patches/qt-Android-Add-support-for-sendCommand-to-QNearFieldTarget.patch new file mode 100644 index 0000000..a049d99 --- /dev/null +++ b/patches/qt-Android-Add-support-for-sendCommand-to-QNearFieldTarget.patch @@ -0,0 +1,180 @@ +From 6483796d9c117a7dee7c2ffcef090600b04bd21c Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Tue, 13 Dec 2016 15:34:32 +0100 +Subject: Android: Add support for sendCommand to QNearFieldTarget + +For the communication with a German ID card its required to execute +commands. This change enables support for sendCommand. + +Change-Id: I95773c047953b244cd5c3e22bfc7abf7f7eb656e +--- + src/nfc/qnearfieldtarget.cpp | 3 +- + src/nfc/qnearfieldtarget.h | 3 +- + src/nfc/qnearfieldtarget_android.cpp | 81 +++++++++++++++++++++++------------- + 3 files changed, 56 insertions(+), 31 deletions(-) + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.cpp y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +index 509160c1..a65b4be2 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +@@ -111,7 +111,7 @@ QT_BEGIN_NAMESPACE + /*! + \enum QNearFieldTarget::Error + +- This enum describes the error codes that that a near field target reports. ++ This enum describes the error codes that a near field target reports. + + \value NoError No error has occurred. + \value UnknownError An unidentified error occurred. +@@ -123,6 +123,7 @@ QT_BEGIN_NAMESPACE + \value InvalidParametersError Invalid parameters were passed to a tag type specific function. + \value NdefReadError Failed to read NDEF messages from the target. + \value NdefWriteError Failed to write NDEF messages to the target. ++ \value CommandError Failed to send a command to the target. + */ + + // Copied from qbytearray.cpp +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.h y/qtconnectivity/src/nfc/qnearfieldtarget.h +index dc081f5e..dfb474f6 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.h +@@ -91,7 +91,8 @@ public: + ChecksumMismatchError, + InvalidParametersError, + NdefReadError, +- NdefWriteError ++ NdefWriteError, ++ CommandError + }; + Q_ENUM(Error) + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +index e0c1616d..478f4d8c 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +@@ -43,6 +43,7 @@ + + #define NDEFTECHNOLOGY "android.nfc.tech.Ndef" + #define NDEFFORMATABLETECHNOLOGY "android.nfc.tech.NdefFormatable" ++#define ISODEPTECHNOLOGY "android.nfc.tech.IsoDep" + #define NFCATECHNOLOGY "android.nfc.tech.NfcA" + #define NFCBTECHNOLOGY "android.nfc.tech.NfcB" + #define NFCFTECHNOLOGY "android.nfc.tech.NfcF" +@@ -84,7 +85,19 @@ QNearFieldTarget::Type NearFieldTarget::type() const + + QNearFieldTarget::AccessMethods NearFieldTarget::accessMethods() const + { +- AccessMethods result = NdefAccess; ++ AccessMethods result = UnknownAccess; ++ ++ if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY)) ++ || m_techList.contains(QStringLiteral(NDEFFORMATABLETECHNOLOGY))) ++ result |= NdefAccess; ++ ++ if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY)) ++ || m_techList.contains(QStringLiteral(NFCATECHNOLOGY)) ++ || m_techList.contains(QStringLiteral(NFCBTECHNOLOGY)) ++ || m_techList.contains(QStringLiteral(NFCFTECHNOLOGY)) ++ || m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) ++ result |= TagTypeSpecificAccess; ++ + return result; + } + +@@ -157,24 +170,23 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + return requestId; + } + +- + QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &command) + { +- Q_UNUSED(command); +- Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId()); +- return QNearFieldTarget::RequestId(); +- +- //Not supported for now +- /*if (command.size() == 0) { ++ if (command.size() == 0) { + Q_EMIT QNearFieldTarget::error(QNearFieldTarget::InvalidParametersError, QNearFieldTarget::RequestId()); + return QNearFieldTarget::RequestId(); + } + +- AndroidNfc::AttachedJNIEnv aenv; +- JNIEnv *env = aenv.jniEnv; ++ // Making sure that target has commands ++ if (!(accessMethods() & TagTypeSpecificAccess)) ++ return QNearFieldTarget::RequestId(); ++ ++ QAndroidJniEnvironment env; + +- jobject tagTech; +- if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { ++ QAndroidJniObject tagTech; ++ if (m_techList.contains(ISODEPTECHNOLOGY)) { ++ tagTech = getTagTechnology(ISODEPTECHNOLOGY); ++ } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { + tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); + } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { + tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY)); +@@ -187,30 +199,41 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + return QNearFieldTarget::RequestId(); + } + +- QByteArray ba(ba); +- +- jclass techClass = env->GetObjectClass(tagTech); +- jmethodID tranceiveMID = env->GetMethodID(techClass, "tranceive", "([B)[B"); +- Q_ASSERT_X(tranceiveMID != 0, "sendCommand", "could not find tranceive method"); ++ // Connecting ++ QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate()); ++ tagTech.callMethod("connect"); ++ if (catchJavaExceptions()) { ++ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, ++ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError), ++ Q_ARG(const QNearFieldTarget::RequestId&, requestId)); ++ return requestId; ++ } + ++ // Making QByteArray ++ QByteArray ba(command); + jbyteArray jba = env->NewByteArray(ba.size()); + env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast(ba.data())); + +- jbyteArray rsp = reinterpret_cast(env->CallObjectMethod(tagTech, tranceiveMID, jba)); +- +- jsize len = env->GetArrayLength(rsp); +- QByteArray rspQBA; +- rspQBA.resize(len); +- +- env->GetByteArrayRegion(rsp, 0, len, reinterpret_cast(rspQBA.data())); +- +- qDebug() << "Send command returned QBA size: " << rspQBA.size(); +- +- ++ // Writing ++ QAndroidJniObject myNewVal = tagTech.callObjectMethod("transceive", "([B)[B", jba); ++ if (catchJavaExceptions()) { ++ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, ++ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::CommandError), ++ Q_ARG(const QNearFieldTarget::RequestId&, requestId)); ++ return requestId; ++ } ++ QByteArray result = jbyteArrayToQByteArray(myNewVal.object()); + env->DeleteLocalRef(jba); + ++ handleResponse(requestId, result); + +- return QNearFieldTarget::RequestId();*/ ++ // Closing connection, sending signal and exit ++ tagTech.callMethod("close"); ++ catchJavaExceptions(); // IOException at this point does not matter anymore. ++ QMetaObject::invokeMethod(this, "requestCompleted", Qt::QueuedConnection, ++ Q_ARG(const QNearFieldTarget::RequestId&, requestId)); ++ ++ return requestId; + } + + QNearFieldTarget::RequestId NearFieldTarget::sendCommands(const QList &commands) +-- +2.11.0 + diff --git a/patches/qt-Android-QNearfieldTarget-Introduce-maxCommandLength.patch b/patches/qt-Android-QNearfieldTarget-Introduce-maxCommandLength.patch new file mode 100644 index 0000000..ec910c9 --- /dev/null +++ b/patches/qt-Android-QNearfieldTarget-Introduce-maxCommandLength.patch @@ -0,0 +1,374 @@ +From f4f7f906ed1c9763c8e79f0882d25caaa00eb264 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Tue, 29 Nov 2016 16:34:37 +0100 +Subject: Android: QNearfieldTarget: Introduce maxCommandLength() + +For the communication with a German ID card its required to execute +commands with a length up to 500 byte. With this change it is +possible to check if the required length is supported. + +[ChangeLog][QNearfieldTarget] Introduce maxCommandLength() to +make it possible to check the maximum supported length for commands. + +Change-Id: I7e655f419765d8ad728f6d6005a85a01d5aa03e9 +--- + src/nfc/nfc.pro | 7 +++-- + src/nfc/qnearfieldtarget.cpp | 15 +++++++++- + src/nfc/qnearfieldtarget.h | 1 + + src/nfc/qnearfieldtarget_android.cpp | 31 ++++++++++++++++++-- + src/nfc/qnearfieldtarget_android_p.cpp | 53 ++++++++++++++++++++++++++++++++++ + src/nfc/qnearfieldtarget_android_p.h | 1 + + src/nfc/qnearfieldtarget_neard_p.cpp | 52 +++++++++++++++++++++++++++++++++ + src/nfc/qnearfieldtarget_p.cpp | 52 +++++++++++++++++++++++++++++++++ + src/nfc/qnearfieldtarget_p.h | 8 +++++ + 9 files changed, 214 insertions(+), 6 deletions(-) + create mode 100644 src/nfc/qnearfieldtarget_android_p.cpp + create mode 100644 src/nfc/qnearfieldtarget_neard_p.cpp + create mode 100644 src/nfc/qnearfieldtarget_p.cpp + +diff --git x/qtconnectivity/src/nfc/nfc.pro y/qtconnectivity/src/nfc/nfc.pro +index 0819cc4f..ce193efa 100644 +--- x/qtconnectivity/src/nfc/nfc.pro ++++ y/qtconnectivity/src/nfc/nfc.pro +@@ -74,7 +74,8 @@ linux:!android:qtHaveModule(dbus) { + qllcpserver_p.cpp \ + qnearfieldsharemanagerimpl_p.cpp \ + qnearfieldsharetargetimpl_p.cpp \ +- qnearfieldmanager_neard.cpp ++ qnearfieldmanager_neard.cpp \ ++ qnearfieldtarget_neard_p.cpp + + include(neard/neard.pri) + +@@ -107,6 +108,7 @@ linux:!android:qtHaveModule(dbus) { + android/androidjninfc.cpp \ + qnearfieldmanager_android.cpp \ + qnearfieldtarget_android.cpp \ ++ qnearfieldtarget_android_p.cpp \ + qnearfieldsharemanagerimpl_p.cpp \ + qnearfieldsharetargetimpl_p.cpp \ + android/androidmainnewintentlistener.cpp +@@ -127,7 +129,8 @@ isEmpty(NFC_BACKEND_AVAILABLE) { + qllcpserver_p.cpp \ + qnearfieldmanagerimpl_p.cpp \ + qnearfieldsharemanagerimpl_p.cpp \ +- qnearfieldsharetargetimpl_p.cpp ++ qnearfieldsharetargetimpl_p.cpp \ ++ qnearfieldtarget_p.cpp + } + + HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.cpp y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +index a65b4be2..274ef175 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +@@ -277,7 +277,7 @@ QNearFieldTarget::RequestId &QNearFieldTarget::RequestId::operator=(const Reques + Constructs a new near field target with \a parent. + */ + QNearFieldTarget::QNearFieldTarget(QObject *parent) +-: QObject(parent), d_ptr(new QNearFieldTargetPrivate) ++: QObject(parent), d_ptr(new QNearFieldTargetPrivate(this)) + { + qRegisterMetaType(); + qRegisterMetaType(); +@@ -365,6 +365,19 @@ QNearFieldTarget::RequestId QNearFieldTarget::writeNdefMessages(const QListmaxCommandLength(); ++} ++ ++/*! + Sends \a command to the near field target. Returns a request id which can be used to track the + completion status of the request. An invalid request id will be returned if the target does not + support sending tag type specific commands. +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.h y/qtconnectivity/src/nfc/qnearfieldtarget.h +index dfb474f6..620ea813 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.h +@@ -134,6 +134,7 @@ public: + virtual RequestId writeNdefMessages(const QList &messages); + + // TagTypeSpecificAccess ++ int maxCommandLength() const; + virtual RequestId sendCommand(const QByteArray &command); + virtual RequestId sendCommands(const QList &commands); + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +index 478f4d8c..f41b0b2e 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +@@ -170,9 +170,34 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + return requestId; + } + ++int NearFieldTarget::maxCommandLength() const ++{ ++ QAndroidJniObject tagTech; ++ if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY)); ++ } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); ++ } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY)); ++ } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(NFCFTECHNOLOGY)); ++ } else if (m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(NFCVTECHNOLOGY)); ++ } else { ++ return 0; ++ } ++ ++ int returnVal = tagTech.callMethod("getMaxTransceiveLength"); ++ if (catchJavaExceptions()) { ++ return 0; ++ } ++ ++ return returnVal; ++} ++ + QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &command) + { +- if (command.size() == 0) { ++ if (command.size() == 0 || command.size() > maxCommandLength()) { + Q_EMIT QNearFieldTarget::error(QNearFieldTarget::InvalidParametersError, QNearFieldTarget::RequestId()); + return QNearFieldTarget::RequestId(); + } +@@ -184,8 +209,8 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + QAndroidJniEnvironment env; + + QAndroidJniObject tagTech; +- if (m_techList.contains(ISODEPTECHNOLOGY)) { +- tagTech = getTagTechnology(ISODEPTECHNOLOGY); ++ if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) { ++ tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY)); + } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { + tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); + } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp +new file mode 100644 +index 00000000..da2d8f2d +--- /dev/null ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp +@@ -0,0 +1,53 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2017 Governikus GmbH & Co. KG ++** Contact: https://www.qt.io/licensing/ ++** ++** This file is part of the QtNfc module of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and The Qt Company. For licensing terms ++** and conditions see https://www.qt.io/terms-conditions. For further ++** information use the contact form at https://www.qt.io/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 3 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL3 included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 3 requirements ++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 2.0 or (at your option) the GNU General ++** Public license version 3 or any later version approved by the KDE Free ++** Qt Foundation. The licenses are as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ++** included in the packaging of this file. Please review the following ++** information to ensure the GNU General Public License requirements will ++** be met: https://www.gnu.org/licenses/gpl-2.0.html and ++** https://www.gnu.org/licenses/gpl-3.0.html. ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#include ++ ++#include "qnearfieldtarget_p.h" ++#include "qnearfieldtarget_android_p.h" ++ ++QT_BEGIN_NAMESPACE ++ ++int QNearFieldTargetPrivate::maxCommandLength() const ++{ ++ NearFieldTarget * const q = reinterpret_cast(q_ptr); ++ return q->maxCommandLength(); ++} ++ ++QT_END_NAMESPACE +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h +index 94bb394d..f2e2ee7f 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h +@@ -77,6 +77,7 @@ public: + virtual AccessMethods accessMethods() const; + virtual bool hasNdefMessage(); + virtual RequestId readNdefMessages(); ++ int maxCommandLength() const; + virtual RequestId sendCommand(const QByteArray &command); + virtual RequestId sendCommands(const QList &commands); + virtual RequestId writeNdefMessages(const QList &messages); +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp +new file mode 100644 +index 00000000..3d1bfa6c +--- /dev/null ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp +@@ -0,0 +1,52 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2017 Governikus GmbH & Co. K ++** Contact: https://www.qt.io/licensing/ ++** ++** This file is part of the QtNfc module of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and The Qt Company. For licensing terms ++** and conditions see https://www.qt.io/terms-conditions. For further ++** information use the contact form at https://www.qt.io/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 3 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL3 included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 3 requirements ++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 2.0 or (at your option) the GNU General ++** Public license version 3 or any later version approved by the KDE Free ++** Qt Foundation. The licenses are as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ++** included in the packaging of this file. Please review the following ++** information to ensure the GNU General Public License requirements will ++** be met: https://www.gnu.org/licenses/gpl-2.0.html and ++** https://www.gnu.org/licenses/gpl-3.0.html. ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#include ++ ++#include "qnearfieldtarget.h" ++#include "qnearfieldtarget_p.h" ++ ++QT_BEGIN_NAMESPACE ++ ++int QNearFieldTargetPrivate::maxCommandLength() const ++{ ++ return 0; ++} ++ ++QT_END_NAMESPACE +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp +new file mode 100644 +index 00000000..3d1bfa6c +--- /dev/null ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp +@@ -0,0 +1,52 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2017 Governikus GmbH & Co. K ++** Contact: https://www.qt.io/licensing/ ++** ++** This file is part of the QtNfc module of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and The Qt Company. For licensing terms ++** and conditions see https://www.qt.io/terms-conditions. For further ++** information use the contact form at https://www.qt.io/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 3 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL3 included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 3 requirements ++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 2.0 or (at your option) the GNU General ++** Public license version 3 or any later version approved by the KDE Free ++** Qt Foundation. The licenses are as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ++** included in the packaging of this file. Please review the following ++** information to ensure the GNU General Public License requirements will ++** be met: https://www.gnu.org/licenses/gpl-2.0.html and ++** https://www.gnu.org/licenses/gpl-3.0.html. ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#include ++ ++#include "qnearfieldtarget.h" ++#include "qnearfieldtarget_p.h" ++ ++QT_BEGIN_NAMESPACE ++ ++int QNearFieldTargetPrivate::maxCommandLength() const ++{ ++ return 0; ++} ++ ++QT_END_NAMESPACE +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_p.h y/qtconnectivity/src/nfc/qnearfieldtarget_p.h +index 7a787ace..9b2ed480 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_p.h +@@ -57,6 +57,7 @@ + + #include + #include ++#include + + QT_BEGIN_NAMESPACE + +@@ -66,8 +67,15 @@ class QNearFieldTarget::RequestIdPrivate : public QSharedData + + class QNearFieldTargetPrivate + { ++ QNearFieldTarget *q_ptr; ++ Q_DECLARE_PUBLIC(QNearFieldTarget) ++ + public: ++ QNearFieldTargetPrivate(QNearFieldTarget *q) : q_ptr(q) {} ++ + QMap m_decodedResponses; ++ ++ int maxCommandLength() const; + }; + + QT_END_NAMESPACE +-- +2.11.0 + diff --git a/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch b/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch new file mode 100644 index 0000000..d0c7a92 --- /dev/null +++ b/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch @@ -0,0 +1,44 @@ +From 1e9d5b22fbd18cfcf56f5c6ced19c0d9ba55a4f1 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Wed, 11 Jan 2017 17:29:40 +0100 +Subject: [PATCH] Do not request an unnessessary dangerous right + +Bluetooth LE discovery needs ACCESS_COARSE_LOCATION permission +since android 6.0. In the manifest file it is possible use it by +"" +in general. But the bluetooth LE discovery requests it for every +android version. This change enables the request for android > 6.0 +only (API-Level >=23). + +Task-number: QTBUG-58085 +Change-Id: I78ad2fe83eb16eaf45813137335f85c7b3930992 +--- + src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git x/qtconnectivity/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp y/qtconnectivity/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +index 2d6e64be..e76ddff7 100644 +--- x/qtconnectivity/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp ++++ y/qtconnectivity/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +@@ -45,6 +45,7 @@ + #include + #include "android/devicediscoverybroadcastreceiver_p.h" + #include ++#include + + QT_BEGIN_NAMESPACE + +@@ -147,7 +148,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent + + // check Android v23+ permissions + // -> BTLE search requires android.permission.ACCESS_COARSE_LOCATION +- if (requestedMethods && QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { ++ if (requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod ++ && QtAndroid::androidSdkVersion() >= 23) ++ { + QString permission(QLatin1String("android.permission.ACCESS_COARSE_LOCATION")); + + // do we have required permission already, if so nothing to do +-- +2.11.0 + diff --git a/patches/qt-Introduce-QNetworkAccessManager-clearConnectionCache.patch b/patches/qt-Introduce-QNetworkAccessManager-clearConnectionCache.patch new file mode 100644 index 0000000..da571dd --- /dev/null +++ b/patches/qt-Introduce-QNetworkAccessManager-clearConnectionCache.patch @@ -0,0 +1,140 @@ +From 523c61571e234865e411d823366dc87d62fe50ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20L=C3=B6sch?= +Date: Wed, 10 Aug 2016 16:51:34 +0200 +Subject: Introduce QNetworkAccessManager::clearConnectionCache() + +Sometimes it is desirable to use a new connection but keep already +entered user credentials for usability reasons. This is now possible by +clearing the connection cache (but keeping the authentication cache). + +Change-Id: I2f5f64836ce19f81c8525701783a3da823dd468e +--- + src/network/access/qnetworkaccessmanager.cpp | 25 +++++++++++++++++++--- + src/network/access/qnetworkaccessmanager.h | 2 ++ + src/network/access/qnetworkaccessmanager_p.h | 3 ++- + .../access/qnetworkreply/tst_qnetworkreply.cpp | 3 ++- + .../tst_network_remote_stresstest.cpp | 3 ++- + .../network_stresstest/tst_network_stresstest.cpp | 3 ++- + 6 files changed, 32 insertions(+), 7 deletions(-) + +diff --git x/qtbase/src/network/access/qnetworkaccessmanager.cpp y/qtbase/src/network/access/qnetworkaccessmanager.cpp +index 6d5b2400f1..b763547a15 100644 +--- x/qtbase/src/network/access/qnetworkaccessmanager.cpp ++++ y/qtbase/src/network/access/qnetworkaccessmanager.cpp +@@ -1352,10 +1352,26 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const + + This function is useful for doing auto tests. + ++ \sa clearConnectionCache() + */ + void QNetworkAccessManager::clearAccessCache() + { +- QNetworkAccessManagerPrivate::clearCache(this); ++ QNetworkAccessManagerPrivate::clearAuthenticationCache(this); ++ QNetworkAccessManagerPrivate::clearConnectionCache(this); ++} ++ ++/*! ++ \since 5.9 ++ ++ Flushes the internal cache of network connections. ++ In contrast to clearAccessCache() the authentication data ++ is preserved. ++ ++ \sa clearAccessCache() ++*/ ++void QNetworkAccessManager::clearConnectionCache() ++{ ++ QNetworkAccessManagerPrivate::clearConnectionCache(this); + } + + void QNetworkAccessManagerPrivate::_q_replyFinished() +@@ -1552,11 +1568,14 @@ QList QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx + } + #endif + +-void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) ++void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager) + { +- manager->d_func()->objectCache.clear(); + manager->d_func()->authenticationManager->clearCache(); ++} + ++void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager) ++{ ++ manager->d_func()->objectCache.clear(); + manager->d_func()->destroyThread(); + } + +diff --git x/qtbase/src/network/access/qnetworkaccessmanager.h y/qtbase/src/network/access/qnetworkaccessmanager.h +index 4b8c4ddf0e..649013cced 100644 +--- x/qtbase/src/network/access/qnetworkaccessmanager.h ++++ y/qtbase/src/network/access/qnetworkaccessmanager.h +@@ -106,6 +106,8 @@ public: + + void clearAccessCache(); + ++ void clearConnectionCache(); ++ + #ifndef QT_NO_NETWORKPROXY + QNetworkProxy proxy() const; + void setProxy(const QNetworkProxy &proxy); +diff --git x/qtbase/src/network/access/qnetworkaccessmanager_p.h y/qtbase/src/network/access/qnetworkaccessmanager_p.h +index bb4641ab8b..b4b5e6a789 100644 +--- x/qtbase/src/network/access/qnetworkaccessmanager_p.h ++++ y/qtbase/src/network/access/qnetworkaccessmanager_p.h +@@ -202,7 +202,8 @@ public: + QNetworkAccessCache objectCache; + static inline QNetworkAccessCache *getObjectCache(QNetworkAccessBackend *backend) + { return &backend->manager->objectCache; } +- Q_AUTOTEST_EXPORT static void clearCache(QNetworkAccessManager *manager); ++ Q_AUTOTEST_EXPORT static void clearAuthenticationCache(QNetworkAccessManager *manager); ++ Q_AUTOTEST_EXPORT static void clearConnectionCache(QNetworkAccessManager *manager); + #ifndef QT_NO_BEARERMANAGEMENT + Q_AUTOTEST_EXPORT static const QWeakPointer getNetworkSession(const QNetworkAccessManager *manager); + #endif +diff --git x/qtbase/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp y/qtbase/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +index 649278d48b..c555cd8fa0 100644 +--- x/qtbase/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp ++++ y/qtbase/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +@@ -6797,7 +6797,8 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() + // QTBUG-23136 workaround (needed even with danted v1.1.19): + if (proxy.port() == 1081) { + #ifdef QT_BUILD_INTERNAL +- QNetworkAccessManagerPrivate::clearCache(&manager); ++ QNetworkAccessManagerPrivate::clearAuthenticationCache(&manager); ++ QNetworkAccessManagerPrivate::clearConnectionCache(&manager); + #else + return; + #endif +diff --git x/qtbase/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp y/qtbase/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp +index 05ede9da99..99e3d148df 100644 +--- x/qtbase/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp ++++ y/qtbase/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp +@@ -147,7 +147,8 @@ void tst_NetworkRemoteStressTest::init() + void tst_NetworkRemoteStressTest::clearManager() + { + #ifdef QT_BUILD_INTERNAL +- QNetworkAccessManagerPrivate::clearCache(&manager); ++ QNetworkAccessManagerPrivate::clearAuthenticationCache(&manager); ++ QNetworkAccessManagerPrivate::clearConnectionCache(&manager); + manager.setProxy(QNetworkProxy()); + manager.setCache(0); + #endif +diff --git x/qtbase/tests/manual/network_stresstest/tst_network_stresstest.cpp y/qtbase/tests/manual/network_stresstest/tst_network_stresstest.cpp +index e3c76ea11b..d46703c671 100644 +--- x/qtbase/tests/manual/network_stresstest/tst_network_stresstest.cpp ++++ y/qtbase/tests/manual/network_stresstest/tst_network_stresstest.cpp +@@ -138,7 +138,8 @@ void tst_NetworkStressTest::init() + void tst_NetworkStressTest::clearManager() + { + #ifdef QT_BUILD_INTERNAL +- QNetworkAccessManagerPrivate::clearCache(&manager); ++ QNetworkAccessManagerPrivate::clearAuthenticationCache(&manager); ++ QNetworkAccessManagerPrivate::clearConnectionCache(&manager); + manager.setProxy(QNetworkProxy()); + manager.setCache(0); + #endif +-- +2.11.0 + diff --git a/patches/qt-Enable-use-of-the-same-NetworkAccessAuthenticationManager.patch b/patches/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch similarity index 87% rename from patches/qt-Enable-use-of-the-same-NetworkAccessAuthenticationManager.patch rename to patches/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch index b1e1922..8c6a98f 100644 --- a/patches/qt-Enable-use-of-the-same-NetworkAccessAuthenticationManager.patch +++ b/patches/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch @@ -1,7 +1,7 @@ -From 017de42929811e384a9741d46e4553e74605b79c Mon Sep 17 00:00:00 2001 +From e1ba5a3265be01d7d353bf82e4d8af331edbb434 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Tue, 13 Sep 2016 14:24:25 +0200 -Subject: [PATCH] Introduce QNetworkAccessManager::useAuthenticationManagerFrom +Subject: Introduce QNetworkAccessManager::useAuthenticationManagerFrom Sometimes it is desirable to use a new connection but keep already entered user credentials for usability reasons. This is now possible by @@ -16,10 +16,10 @@ Change-Id: If61f0d03fc8b2f159bad869d0a2b650170e1e174 2 files changed, 17 insertions(+) diff --git x/qtbase/src/network/access/qnetworkaccessmanager.cpp y/qtbase/src/network/access/qnetworkaccessmanager.cpp -index 927e103..c6dfca4 100644 +index b763547a15..83cb33ce72 100644 --- x/qtbase/src/network/access/qnetworkaccessmanager.cpp +++ y/qtbase/src/network/access/qnetworkaccessmanager.cpp -@@ -1083,6 +1083,21 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) +@@ -1079,6 +1079,21 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) } /*! @@ -42,10 +42,10 @@ index 927e103..c6dfca4 100644 Sends a custom request to the server identified by the URL of \a request. diff --git x/qtbase/src/network/access/qnetworkaccessmanager.h y/qtbase/src/network/access/qnetworkaccessmanager.h -index 4ce4757..66e3ffb 100644 +index 649013cced..24f3c7147c 100644 --- x/qtbase/src/network/access/qnetworkaccessmanager.h +++ y/qtbase/src/network/access/qnetworkaccessmanager.h -@@ -143,6 +143,8 @@ public: +@@ -149,6 +149,8 @@ public: #endif void connectToHost(const QString &hostName, quint16 port = 80); @@ -55,5 +55,5 @@ index 4ce4757..66e3ffb 100644 #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); -- -2.9.3 +2.11.0 diff --git a/patches/qt-Make-QCryptographicHash-a-Q_GADGET.patch b/patches/qt-Make-QCryptographicHash-a-Q_GADGET.patch deleted file mode 100644 index b828a84..0000000 --- a/patches/qt-Make-QCryptographicHash-a-Q_GADGET.patch +++ /dev/null @@ -1,44 +0,0 @@ -From a899b4f42ba33cf1e40f6177da00c5bc901264aa Mon Sep 17 00:00:00 2001 -From: "Richard J. Moore" -Date: Thu, 30 Jul 2015 21:42:45 +0100 -Subject: [PATCH] Make QCryptographicHash a Q_GADGET. - -This makes the hash algorithm play nicely with qDebug. - -Change-Id: I6db651cd5c73e8be65442dd68d6b865dcb975f4c -Reviewed-by: Olivier Goffart (Woboq GmbH) ---- - src/corelib/tools/qcryptographichash.h | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git x/qtbase/src/corelib/tools/qcryptographichash.h y/qtbase/src/corelib/tools/qcryptographichash.h -index a19c734..0f17baa 100644 ---- x/qtbase/src/corelib/tools/qcryptographichash.h -+++ y/qtbase/src/corelib/tools/qcryptographichash.h -@@ -42,6 +42,7 @@ - #define QCRYPTOGRAPHICHASH_H - - #include -+#include - - QT_BEGIN_NAMESPACE - -@@ -51,6 +52,7 @@ class QIODevice; - - class Q_CORE_EXPORT QCryptographicHash - { -+ Q_GADGET - public: - enum Algorithm { - #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -@@ -69,6 +71,7 @@ public: - Sha3_512 - #endif - }; -+ Q_ENUM(Algorithm) - - explicit QCryptographicHash(Algorithm method); - ~QCryptographicHash(); --- -2.10.0 - diff --git a/patches/qt-Make-server-side-signature-algorithms-configurable.patch b/patches/qt-Make-server-side-signature-algorithms-configurable.patch index ea819e7..96675d4 100644 --- a/patches/qt-Make-server-side-signature-algorithms-configurable.patch +++ b/patches/qt-Make-server-side-signature-algorithms-configurable.patch @@ -11,19 +11,20 @@ server side. Change-Id: Ia178efd4778b91863fcc919bf50219115b300d77 --- src/network/ssl/qsslconfiguration.cpp | 42 +++++++++++++ - src/network/ssl/qsslconfiguration.h | 6 ++ + src/network/ssl/qsslconfiguration.h | 8 ++- src/network/ssl/qsslconfiguration_p.h | 5 ++ src/network/ssl/qsslcontext_openssl.cpp | 45 ++++++++++++++ + src/network/ssl/qsslcontext_openssl_p.h | 1 + src/network/ssl/qsslsocket.cpp | 2 + src/network/ssl/qsslsocket_openssl_symbols_p.h | 5 ++ - .../auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 71 ++++++++++++++++++++++ - 7 files changed, 176 insertions(+) + .../auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 70 ++++++++++++++++++++++ + 8 files changed, 177 insertions(+), 1 deletion(-) diff --git x/qtbase/src/network/ssl/qsslconfiguration.cpp y/qtbase/src/network/ssl/qsslconfiguration.cpp -index c8040de..6bfca86 100644 +index 75a880f..37f99fe 100644 --- x/qtbase/src/network/ssl/qsslconfiguration.cpp +++ y/qtbase/src/network/ssl/qsslconfiguration.cpp -@@ -217,6 +217,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const +@@ -221,6 +221,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->peerVerifyMode == other.d->peerVerifyMode && d->peerVerifyDepth == other.d->peerVerifyDepth && d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading && @@ -31,7 +32,7 @@ index c8040de..6bfca86 100644 d->sslOptions == other.d->sslOptions && d->sslSession == other.d->sslSession && d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint && -@@ -258,6 +259,7 @@ bool QSslConfiguration::isNull() const +@@ -263,6 +264,7 @@ bool QSslConfiguration::isNull() const d->privateKey.isNull() && d->peerCertificate.isNull() && d->peerCertificateChain.count() == 0 && @@ -39,7 +40,7 @@ index c8040de..6bfca86 100644 d->sslOptions == QSslConfigurationPrivate::defaultSslOptions && d->sslSession.isNull() && d->sslSessionTicketLifeTimeHint == -1 && -@@ -811,6 +813,46 @@ QVector QSslConfiguration::supportedEllipticCurves() +@@ -870,6 +872,46 @@ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParame } /*! @@ -87,23 +88,27 @@ index c8040de..6bfca86 100644 This function returns the protocol negotiated with the server diff --git x/qtbase/src/network/ssl/qsslconfiguration.h y/qtbase/src/network/ssl/qsslconfiguration.h -index f0754d7..cfa1e81 100644 +index 1c57beb..4d3e512 100644 --- x/qtbase/src/network/ssl/qsslconfiguration.h +++ y/qtbase/src/network/ssl/qsslconfiguration.h -@@ -56,7 +56,10 @@ +@@ -56,10 +56,13 @@ #ifndef QSSLCONFIGURATION_H #define QSSLCONFIGURATION_H +-#include +#include +#include #include +#include #include #include ++#include -@@ -141,6 +144,9 @@ public: - void setEllipticCurves(const QVector &curves); - static QVector supportedEllipticCurves(); + #ifndef QT_NO_SSL + +@@ -149,6 +152,9 @@ public: + QSslDiffieHellmanParameters diffieHellmanParameters() const; + void setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams); + QVector > signatureAndHashAlgorithms() const; + void setSignatureAndHashAlgorithms(const QVector > &algorithms); @@ -112,22 +117,22 @@ index f0754d7..cfa1e81 100644 static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git x/qtbase/src/network/ssl/qsslconfiguration_p.h y/qtbase/src/network/ssl/qsslconfiguration_p.h -index 364bba9..9553088 100644 +index 6adf2c9..7be2539 100644 --- x/qtbase/src/network/ssl/qsslconfiguration_p.h +++ y/qtbase/src/network/ssl/qsslconfiguration_p.h -@@ -73,6 +73,9 @@ - #include "qsslcipher.h" +@@ -75,6 +75,9 @@ #include "qsslkey.h" #include "qsslellipticcurve.h" + #include "qssldiffiehellmanparameters.h" +#include +#include +#include QT_BEGIN_NAMESPACE -@@ -117,6 +120,8 @@ public: +@@ -123,6 +126,8 @@ public: - QVector ellipticCurves; + QSslDiffieHellmanParameters dhParams; + QVector > signatureAndHashAlgorithms; + @@ -135,18 +140,18 @@ index 364bba9..9553088 100644 int sslSessionTicketLifeTimeHint; diff --git x/qtbase/src/network/ssl/qsslcontext_openssl.cpp y/qtbase/src/network/ssl/qsslcontext_openssl.cpp -index f132d02..83f2435 100644 +index c92d8fc..29df53a 100644 --- x/qtbase/src/network/ssl/qsslcontext_openssl.cpp +++ y/qtbase/src/network/ssl/qsslcontext_openssl.cpp -@@ -41,6 +41,7 @@ - +@@ -42,6 +42,7 @@ #include + #include +#include #include #include "private/qssl_p.h" -@@ -92,6 +93,11 @@ QSslContext::~QSslContext() +@@ -78,6 +79,11 @@ QSslContext::~QSslContext() q_SSL_SESSION_free(session); } @@ -158,7 +163,7 @@ index f132d02..83f2435 100644 static inline QString msgErrorSettingEllipticCurves(const QString &why) { return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why); -@@ -367,6 +373,45 @@ init_context: +@@ -371,6 +377,45 @@ init_context: sslContext->errorCode = QSslError::UnspecifiedError; } } @@ -204,11 +209,23 @@ index f132d02..83f2435 100644 } QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading) +diff --git x/qtbase/src/network/ssl/qsslcontext_openssl_p.h y/qtbase/src/network/ssl/qsslcontext_openssl_p.h +index 06a31af..c8c8e194 100644 +--- x/qtbase/src/network/ssl/qsslcontext_openssl_p.h ++++ y/qtbase/src/network/ssl/qsslcontext_openssl_p.h +@@ -54,6 +54,7 @@ + // + + #include ++#include + #include + #include + #include diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp -index a5ee9bf..c92645f 100644 +index 29e1f32..8257112 100644 --- x/qtbase/src/network/ssl/qsslsocket.cpp +++ y/qtbase/src/network/ssl/qsslsocket.cpp -@@ -927,6 +927,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) +@@ -922,6 +922,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyDepth = configuration.peerVerifyDepth(); d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); @@ -216,7 +233,7 @@ index a5ee9bf..c92645f 100644 d->configuration.sslOptions = configuration.d->sslOptions; d->configuration.sslSession = configuration.sessionTicket(); d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint(); -@@ -2235,6 +2236,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri +@@ -2230,6 +2231,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->peerVerifyDepth = global->peerVerifyDepth; ptr->sslOptions = global->sslOptions; ptr->ellipticCurves = global->ellipticCurves; @@ -225,10 +242,10 @@ index a5ee9bf..c92645f 100644 /*! diff --git x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h -index 36e041b..7bdd719 100644 +index b35a895..d4cd493 100644 --- x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h -@@ -493,6 +493,11 @@ int q_EC_curve_nist2nid(const char *name); +@@ -517,6 +517,11 @@ int q_EC_curve_nist2nid(const char *name); #define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key) #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L @@ -241,22 +258,22 @@ index 36e041b..7bdd719 100644 int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca); PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12); diff --git x/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp y/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp -index f8c5b8b..a94e385 100644 +index 4eb26d1..79a55cc 100644 --- x/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ y/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp -@@ -229,6 +229,8 @@ private slots: - void simplePskConnect(); - void ephemeralServerKey_data(); +@@ -236,6 +236,8 @@ private slots: void ephemeralServerKey(); + void allowedProtocolNegotiation(); + void pskServer(); + void signatureAlgorithm_data(); + void signatureAlgorithm(); #endif - static void exitLoop() -@@ -3375,6 +3377,75 @@ void tst_QSslSocket::ephemeralServerKey() - QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey); + void setEmptyDefaultConfiguration(); // this test should be last +@@ -3744,6 +3746,74 @@ void tst_QSslSocket::pskServer() + QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); + QCOMPARE(disconnectedSpy.count(), 1); } - +using SigAlgPair = QPair; +Q_DECLARE_METATYPE(QCryptographicHash::Algorithm); +Q_DECLARE_METATYPE(QSsl::KeyAlgorithm); @@ -325,10 +342,9 @@ index f8c5b8b..a94e385 100644 + QCOMPARE(client.state(), state); +} + -+ + #endif // QT_NO_OPENSSL - #endif // QT_NO_SSL -- -2.10.0 +2.10.2 diff --git a/patches/qt-Make-sure-SSL-configuration-is-correct-in-QNetworkRe.patch b/patches/qt-Make-sure-SSL-configuration-is-correct-in-QNetworkRe.patch deleted file mode 100644 index df970e3..0000000 --- a/patches/qt-Make-sure-SSL-configuration-is-correct-in-QNetworkRe.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 29618d33243783725bb601ff8d9bd263309f4f32 Mon Sep 17 00:00:00 2001 -From: Vladimir Prus -Date: Fri, 20 Nov 2015 11:20:02 +0300 -Subject: [PATCH] Make sure SSL configuration is correct in - QNetworkReply::encrypted. - -In some cases, when QNetworkReply::encrypted is emitted, -QNetworkReply::sslConfiguration is not yet initialized, in particular -certificate chain is empty, which breaks the documented usage of -'encrypted' to perform additional checks on certificate chain. - -It looks to be caused by the fact that QHttpNetworkReply is originally -associated with 0th QHttpNetworkConnectionChannel, and this association -is not updated if HTTP pipelining is not used. Therefore, a reply on -channel >0 might arrive before reply on channel 0, and then using ssl -configuration from channel 0, which not made it through handshake, is -not usable. - -Task-number: QTBUG-49554 -Change-Id: Ie5d4b5a0c503d5bdc44761ce8581f6ffe4e3bac2 ---- - src/network/access/qhttpnetworkconnection.cpp | 15 +++++++++++---- - src/network/access/qhttpnetworkconnection_p.h | 1 + - src/network/access/qhttpnetworkconnectionchannel.cpp | 3 +-- - 3 files changed, 13 insertions(+), 6 deletions(-) - -diff --git x/qtbase/src/network/access/qhttpnetworkconnection.cpp y/qtbase/src/network/access/qhttpnetworkconnection.cpp -index 79f418f..7f07403 100644 ---- x/qtbase/src/network/access/qhttpnetworkconnection.cpp -+++ y/qtbase/src/network/access/qhttpnetworkconnection.cpp -@@ -674,8 +674,7 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket) - HttpMessagePair messagePair = highPriorityQueue.takeLast(); - if (!messagePair.second->d_func()->requestIsPrepared) - prepareRequest(messagePair); -- channels[i].request = messagePair.first; -- channels[i].reply = messagePair.second; -+ updateChannel(i, messagePair); - return true; - } - -@@ -684,13 +683,21 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket) - HttpMessagePair messagePair = lowPriorityQueue.takeLast(); - if (!messagePair.second->d_func()->requestIsPrepared) - prepareRequest(messagePair); -- channels[i].request = messagePair.first; -- channels[i].reply = messagePair.second; -+ updateChannel(i, messagePair); - return true; - } - return false; - } - -+void QHttpNetworkConnectionPrivate::updateChannel(int i, const HttpMessagePair &messagePair) -+{ -+ channels[i].request = messagePair.first; -+ channels[i].reply = messagePair.second; -+ // Now that reply is assigned a channel, correct reply to channel association -+ // previously set in queueRequest. -+ channels[i].reply->d_func()->connectionChannel = &channels[i]; -+} -+ - QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest() const - { - if (!highPriorityQueue.isEmpty()) -diff --git x/qtbase/src/network/access/qhttpnetworkconnection_p.h y/qtbase/src/network/access/qhttpnetworkconnection_p.h -index e05bc1d..df71425 100644 ---- x/qtbase/src/network/access/qhttpnetworkconnection_p.h -+++ y/qtbase/src/network/access/qhttpnetworkconnection_p.h -@@ -213,6 +213,7 @@ public: - void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke - bool dequeueRequest(QAbstractSocket *socket); - void prepareRequest(HttpMessagePair &request); -+ void updateChannel(int i, const HttpMessagePair &messagePair); - QHttpNetworkRequest predictNextRequest() const; - - void fillPipeline(QAbstractSocket *socket); -diff --git x/qtbase/src/network/access/qhttpnetworkconnectionchannel.cpp y/qtbase/src/network/access/qhttpnetworkconnectionchannel.cpp -index 56716cb..8e0e88d 100644 ---- x/qtbase/src/network/access/qhttpnetworkconnectionchannel.cpp -+++ y/qtbase/src/network/access/qhttpnetworkconnectionchannel.cpp -@@ -1076,6 +1076,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted() - connection->d_func()->dequeueRequest(socket); - if (reply) { - reply->setSpdyWasUsed(false); -+ Q_ASSERT(reply->d_func()->connectionChannel == this); - emit reply->encrypted(); - } - if (reply) -@@ -1115,8 +1116,6 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList &errors) - connection->d_func()->pauseConnection(); - if (pendingEncrypt && !reply) - connection->d_func()->dequeueRequest(socket); -- if (reply) // a reply was actually dequeued. -- reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest(); - if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) { - if (reply) - emit reply->sslErrors(errors); --- -2.10.0 - diff --git a/patches/qt-Make-variant-selection-possible-if-base-is-missing.patch b/patches/qt-Make-variant-selection-possible-if-base-is-missing.patch new file mode 100644 index 0000000..93aec2a --- /dev/null +++ b/patches/qt-Make-variant-selection-possible-if-base-is-missing.patch @@ -0,0 +1,69 @@ +From a3a86b6b4acb210392d0aa0aad555f7afb455e0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20L=C3=B6sch?= +Date: Tue, 1 Nov 2016 11:16:32 +0100 +Subject: Make variant selection possible if base is missing + +[ChangeLog][QtCore][QFileSelector] Removed the requirement for an unused +default base file in case you want to load only a variant. + +When the base file (e.g. /image.jpg) was missing, no selectors were +considered and it was not possible to load variants of this file (e.g. +/+android/image.jpg, /+android/+tablet/image.jpg) without specifying the +directory as well. + +As a work around, one previously had to place a default file in +the base location, which is undesirable in some cases because: +1. The extra file consumes unnecessary space. +2. It is impossible to encapsulate platform-specific implementation + details by hiding files in a subdirectory. + +Task-number: QTBUG-51230 +Change-Id: I4c7f9ec952bff6e5b7738d8cabe3c762c208a38e +--- + src/corelib/io/qfileselector.cpp | 9 +++------ + tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp | 2 +- + 2 files changed, 4 insertions(+), 7 deletions(-) + +diff --git x/qtbase/src/corelib/io/qfileselector.cpp y/qtbase/src/corelib/io/qfileselector.cpp +index 920281cef7..b48b3e1162 100644 +--- x/qtbase/src/corelib/io/qfileselector.cpp ++++ y/qtbase/src/corelib/io/qfileselector.cpp +@@ -133,9 +133,9 @@ QFileSelectorPrivate::QFileSelectorPrivate() + With those files available, you would select a different file on the android platform, + but only if the locale was en_GB. + +- QFileSelector will not attempt to select if the base file does not exist. For error handling in +- the case no valid selectors are present, it is recommended to have a default or error-handling +- file in the base file location even if you expect selectors to be present for all deployments. ++ For error handling in the case no valid selectors are present, it is recommended to have a default or ++ error-handling file in the base file location even if you expect selectors to be present for all ++ deployments. + + In a future version, some may be marked as deploy-time static and be moved during the + deployment step as an optimization. As selectors come with a performance cost, it is +@@ -298,9 +298,6 @@ QString QFileSelectorPrivate::select(const QString &filePath) const + { + Q_Q(const QFileSelector); + QFileInfo fi(filePath); +- // If file doesn't exist, don't select +- if (!fi.exists()) +- return filePath; + + QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'), + fi.fileName(), q->allSelectors()); +diff --git x/qtbase/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp y/qtbase/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp +index e5ede1ad06..8c2886f337 100644 +--- x/qtbase/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp ++++ y/qtbase/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp +@@ -138,7 +138,7 @@ void tst_QFileSelector::basicTest_data() + << QString(":/extras/test2"); + + QTest::newRow("custom1-withselector-nobasefile") << QString(":/extras/test3") << (QStringList() << custom1) +- << QString(":/extras/test3"); ++ << QString(":/extras/+custom1/test3"); + + QString custom2("custom2"); + QString custom3("custom3"); +-- +2.11.0 + diff --git a/patches/qt-QNearfieldTarget-Introduce-set-keepConnection-and-disconnect.patch b/patches/qt-QNearfieldTarget-Introduce-set-keepConnection-and-disconnect.patch new file mode 100644 index 0000000..b66b7cb --- /dev/null +++ b/patches/qt-QNearfieldTarget-Introduce-set-keepConnection-and-disconnect.patch @@ -0,0 +1,681 @@ +From 0d81394307262f386e9e7d05b37f373c6e64066d Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Thu, 5 Jan 2017 13:43:57 +0100 +Subject: QNearfieldTarget: Introduce (set)keepConnection() and disconnect() + +For the communication with a German ID card its required to execute +several commands in a row, whereby a state is generated. Every command +works on the state created by the command before. Depending on the +Android version the state gets lost when the connection is closed. + +With this change it is possible to keep the connection as long as needed +and close it manually. Because of backward compatibility the connection +is created and closed automatically by default. With the use of +setKeepConnection(true) the communication with the target is also a +lot of faster. + +[ChangeLog][QNearfieldTarget] Introduce (set)keepConnection() and +disconnect() to keep the state of a target and speed up communication. + +Change-Id: I5778c9bdaf04cfeae78b3222bef4475f4cd7c436 +--- + src/nfc/qnearfieldtarget.cpp | 46 ++++++ + src/nfc/qnearfieldtarget.h | 4 + + src/nfc/qnearfieldtarget_android.cpp | 252 ++++++++++++++++++++------------- + src/nfc/qnearfieldtarget_android_p.cpp | 20 ++- + src/nfc/qnearfieldtarget_android_p.h | 8 ++ + src/nfc/qnearfieldtarget_neard_p.cpp | 15 ++ + src/nfc/qnearfieldtarget_p.cpp | 16 +++ + src/nfc/qnearfieldtarget_p.h | 5 + + 8 files changed, 265 insertions(+), 101 deletions(-) + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.cpp y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +index 274ef175..4477d74b 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.cpp +@@ -319,6 +319,52 @@ QUrl QNearFieldTarget::url() const + */ + + /*! ++ \since 5.9 ++ ++ Returns true if this feature is enabled. ++ ++ \sa setKeepConnection(), disconnect() ++*/ ++bool QNearFieldTarget::keepConnection() const ++{ ++ return d_ptr->keepConnection(); ++} ++ ++/*! ++ \since 5.9 ++ ++ Causes QNearFieldTarget to keep the connection after processing a command ++ or reading/writing NDEF messages. A call of this function is only needed once. ++ ++ Returns true if enabling this feature was successful. A possible ++ reason for a failure is the lack of support on the used platform. ++ ++ Enabling this feature requires to use the disconnect() function too, to close the ++ connection manually and enable communication with the target from a different instance. ++ Disabling this feature will also close an open connection. ++ ++ \sa keepConnection(), disconnect() ++*/ ++bool QNearFieldTarget::setKeepConnection(bool isPersistent) ++{ ++ return d_ptr->setKeepConnection(isPersistent); ++} ++ ++/*! ++ \since 5.9 ++ ++ Closes the connection to the target. ++ ++ Returns true only if an existing connection was successfully closed. ++ ++ \sa keepConnection(), setKeepConnection() ++*/ ++bool QNearFieldTarget::disconnect() ++{ ++ return d_ptr->disconnect(); ++} ++ ++/*! + Returns true if the target is processing commands; otherwise returns false. + */ + bool QNearFieldTarget::isProcessingCommand() const +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget.h y/qtconnectivity/src/nfc/qnearfieldtarget.h +index 620ea813..19d87e96 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget.h +@@ -126,6 +126,10 @@ public: + virtual Type type() const = 0; + virtual AccessMethods accessMethods() const = 0; + ++ bool keepConnection() const; ++ bool setKeepConnection(bool isPersistent); ++ bool disconnect(); ++ + bool isProcessingCommand() const; + + // NdefAccess +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +index f41b0b2e..04718fc5 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android.cpp +@@ -41,26 +41,27 @@ + #include "android/androidjninfc_p.h" + #include "qdebug.h" + +-#define NDEFTECHNOLOGY "android.nfc.tech.Ndef" +-#define NDEFFORMATABLETECHNOLOGY "android.nfc.tech.NdefFormatable" +-#define ISODEPTECHNOLOGY "android.nfc.tech.IsoDep" +-#define NFCATECHNOLOGY "android.nfc.tech.NfcA" +-#define NFCBTECHNOLOGY "android.nfc.tech.NfcB" +-#define NFCFTECHNOLOGY "android.nfc.tech.NfcF" +-#define NFCVTECHNOLOGY "android.nfc.tech.NfcV" +-#define MIFARECLASSICTECHNOLOGY "android.nfc.tech.MifareClassic" +-#define MIFARECULTRALIGHTTECHNOLOGY "android.nfc.tech.MifareUltralight" +- +-#define MIFARETAG "com.nxp.ndef.mifareclassic" +-#define NFCTAGTYPE1 "org.nfcforum.ndef.type1" +-#define NFCTAGTYPE2 "org.nfcforum.ndef.type2" +-#define NFCTAGTYPE3 "org.nfcforum.ndef.type3" +-#define NFCTAGTYPE4 "org.nfcforum.ndef.type4" ++#define NDEFTECHNOLOGY QStringLiteral("android.nfc.tech.Ndef") ++#define NDEFFORMATABLETECHNOLOGY QStringLiteral("android.nfc.tech.NdefFormatable") ++#define ISODEPTECHNOLOGY QStringLiteral("android.nfc.tech.IsoDep") ++#define NFCATECHNOLOGY QStringLiteral("android.nfc.tech.NfcA") ++#define NFCBTECHNOLOGY QStringLiteral("android.nfc.tech.NfcB") ++#define NFCFTECHNOLOGY QStringLiteral("android.nfc.tech.NfcF") ++#define NFCVTECHNOLOGY QStringLiteral("android.nfc.tech.NfcV") ++#define MIFARECLASSICTECHNOLOGY QStringLiteral("android.nfc.tech.MifareClassic") ++#define MIFARECULTRALIGHTTECHNOLOGY QStringLiteral("android.nfc.tech.MifareUltralight") ++ ++#define MIFARETAG QStringLiteral("com.nxp.ndef.mifareclassic") ++#define NFCTAGTYPE1 QStringLiteral("org.nfcforum.ndef.type1") ++#define NFCTAGTYPE2 QStringLiteral("org.nfcforum.ndef.type2") ++#define NFCTAGTYPE3 QStringLiteral("org.nfcforum.ndef.type3") ++#define NFCTAGTYPE4 QStringLiteral("org.nfcforum.ndef.type4") + + NearFieldTarget::NearFieldTarget(QAndroidJniObject intent, const QByteArray uid, QObject *parent) : + QNearFieldTarget(parent), + m_intent(intent), +- m_uid(uid) ++ m_uid(uid), ++ m_keepConnection(false) + { + updateTechList(); + updateType(); +@@ -87,23 +88,54 @@ QNearFieldTarget::AccessMethods NearFieldTarget::accessMethods() const + { + AccessMethods result = UnknownAccess; + +- if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY)) +- || m_techList.contains(QStringLiteral(NDEFFORMATABLETECHNOLOGY))) ++ if (m_techList.contains(NDEFTECHNOLOGY) ++ || m_techList.contains(NDEFFORMATABLETECHNOLOGY)) + result |= NdefAccess; + +- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY)) +- || m_techList.contains(QStringLiteral(NFCATECHNOLOGY)) +- || m_techList.contains(QStringLiteral(NFCBTECHNOLOGY)) +- || m_techList.contains(QStringLiteral(NFCFTECHNOLOGY)) +- || m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) ++ if (m_techList.contains(ISODEPTECHNOLOGY) ++ || m_techList.contains(NFCATECHNOLOGY) ++ || m_techList.contains(NFCBTECHNOLOGY) ++ || m_techList.contains(NFCFTECHNOLOGY) ++ || m_techList.contains(NFCVTECHNOLOGY)) + result |= TagTypeSpecificAccess; + + return result; + } + ++bool NearFieldTarget::keepConnection() const ++{ ++ return m_keepConnection; ++} ++ ++bool NearFieldTarget::setKeepConnection(bool isPersistent) ++{ ++ m_keepConnection = isPersistent; ++ ++ if (!m_keepConnection) ++ disconnect(); ++ ++ return true; ++} ++ ++bool NearFieldTarget::disconnect() ++{ ++ if (!m_tagTech.isValid()) ++ return false; ++ ++ bool connected = m_tagTech.callMethod("isConnected"); ++ if (catchJavaExceptions()) ++ return false; ++ ++ if (!connected) ++ return false; ++ ++ m_tagTech.callMethod("close"); ++ return !catchJavaExceptions(); ++} ++ + bool NearFieldTarget::hasNdefMessage() + { +- return m_techList.contains(QStringLiteral(NDEFTECHNOLOGY)); ++ return m_techList.contains(NDEFTECHNOLOGY); + } + + QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() +@@ -122,8 +154,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + } + + // Getting Ndef technology object +- QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY)); +- if (!ndef.isValid()) { ++ if (!setTagTechnology({NDEFTECHNOLOGY})) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnsupportedError), + Q_ARG(const QNearFieldTarget::RequestId&, requestId)); +@@ -131,8 +162,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + } + + // Connect +- ndef.callMethod("connect"); +- if (catchJavaExceptions()) { ++ if (!connect()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError), + Q_ARG(const QNearFieldTarget::RequestId&, requestId)); +@@ -140,7 +170,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + } + + // Get NdefMessage object +- QAndroidJniObject ndefMessage = ndef.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;"); ++ QAndroidJniObject ndefMessage = m_tagTech.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;"); + if (catchJavaExceptions()) + ndefMessage = QAndroidJniObject(); + if (!ndefMessage.isValid()) { +@@ -154,9 +184,10 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + QAndroidJniObject ndefMessageBA = ndefMessage.callObjectMethod("toByteArray", "()[B"); + QByteArray ndefMessageQBA = jbyteArrayToQByteArray(ndefMessageBA.object()); + +- // Closing connection +- ndef.callMethod("close"); +- catchJavaExceptions(); // IOException at this point does not matter anymore. ++ if (!m_keepConnection) { ++ // Closing connection ++ disconnect(); // IOException at this point does not matter anymore. ++ } + + // Sending QNdefMessage, requestCompleted and exit. + QNdefMessage qNdefMessage = QNdefMessage::fromByteArray(ndefMessageQBA); +@@ -173,24 +204,22 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages() + int NearFieldTarget::maxCommandLength() const + { + QAndroidJniObject tagTech; +- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCFTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCVTECHNOLOGY)); +- } else { ++ if (m_techList.contains(ISODEPTECHNOLOGY)) ++ tagTech = getTagTechnology(ISODEPTECHNOLOGY); ++ else if (m_techList.contains(NFCATECHNOLOGY)) ++ tagTech = getTagTechnology(NFCATECHNOLOGY); ++ else if (m_techList.contains(NFCBTECHNOLOGY)) ++ tagTech = getTagTechnology(NFCBTECHNOLOGY); ++ else if (m_techList.contains(NFCFTECHNOLOGY)) ++ tagTech = getTagTechnology(NFCFTECHNOLOGY); ++ else if (m_techList.contains(NFCVTECHNOLOGY)) ++ tagTech = getTagTechnology(NFCVTECHNOLOGY); ++ else + return 0; +- } + + int returnVal = tagTech.callMethod("getMaxTransceiveLength"); +- if (catchJavaExceptions()) { ++ if (catchJavaExceptions()) + return 0; +- } + + return returnVal; + } +@@ -208,26 +237,14 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + + QAndroidJniEnvironment env; + +- QAndroidJniObject tagTech; +- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCFTECHNOLOGY)); +- } else if (m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) { +- tagTech = getTagTechnology(QStringLiteral(NFCVTECHNOLOGY)); +- } else { ++ if (!setTagTechnology({ISODEPTECHNOLOGY, NFCATECHNOLOGY, NFCBTECHNOLOGY, NFCFTECHNOLOGY, NFCVTECHNOLOGY})) { + Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId()); + return QNearFieldTarget::RequestId(); + } + + // Connecting + QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate()); +- tagTech.callMethod("connect"); +- if (catchJavaExceptions()) { ++ if (!connect()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError), + Q_ARG(const QNearFieldTarget::RequestId&, requestId)); +@@ -240,7 +257,7 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast(ba.data())); + + // Writing +- QAndroidJniObject myNewVal = tagTech.callObjectMethod("transceive", "([B)[B", jba); ++ QAndroidJniObject myNewVal = m_tagTech.callObjectMethod("transceive", "([B)[B", jba); + if (catchJavaExceptions()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::CommandError), +@@ -252,9 +269,10 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + + handleResponse(requestId, result); + +- // Closing connection, sending signal and exit +- tagTech.callMethod("close"); +- catchJavaExceptions(); // IOException at this point does not matter anymore. ++ if (!m_keepConnection) { ++ // Closing connection ++ disconnect(); // IOException at this point does not matter anymore. ++ } + QMetaObject::invokeMethod(this, "requestCompleted", Qt::QueuedConnection, + Q_ARG(const QNearFieldTarget::RequestId&, requestId)); + +@@ -264,9 +282,8 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma + QNearFieldTarget::RequestId NearFieldTarget::sendCommands(const QList &commands) + { + QNearFieldTarget::RequestId requestId; +- for (int i=0; i < commands.size(); i++){ ++ for (int i=0; i < commands.size(); i++) + requestId = sendCommand(commands.at(i)); +- } + return requestId; + } + +@@ -282,22 +299,18 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList("connect"); +- if (catchJavaExceptions()) { ++ if (!connect()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError), + Q_ARG(const QNearFieldTarget::RequestId&, requestId)); +@@ -326,9 +339,8 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList("close"); +- catchJavaExceptions(); // IOException at this point does not matter anymore. ++ if (!m_keepConnection) ++ disconnect(); // IOException at this point does not matter anymore. + QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection); + return requestId; + } +@@ -350,19 +362,26 @@ void NearFieldTarget::setIntent(QAndroidJniObject intent) + + void NearFieldTarget::checkIsTargetLost() + { +- if (!m_intent.isValid() || m_techList.isEmpty()) { ++ if (!m_intent.isValid() || !setTagTechnology(m_techList)) { + handleTargetLost(); + return; + } +- // Using first available technology to check connection +- QString techStr = m_techList.first(); +- QAndroidJniObject tagTech = getTagTechnology(techStr); +- tagTech.callMethod("connect"); ++ ++ bool connected = m_tagTech.callMethod("isConnected"); ++ if (catchJavaExceptions()) { ++ handleTargetLost(); ++ return; ++ } ++ ++ if (connected) ++ return; ++ ++ m_tagTech.callMethod("connect"); + if (catchJavaExceptions(false)) { + handleTargetLost(); + return; + } +- tagTech.callMethod("close"); ++ m_tagTech.callMethod("close"); + if (catchJavaExceptions(false)) + handleTargetLost(); + } +@@ -406,28 +425,28 @@ QNearFieldTarget::Type NearFieldTarget::getTagType() const + { + QAndroidJniEnvironment env; + +- if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))) { +- QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY)); ++ if (m_techList.contains(NDEFTECHNOLOGY)) { ++ QAndroidJniObject ndef = getTagTechnology(NDEFTECHNOLOGY); + QString qtype = ndef.callObjectMethod("getType", "()Ljava/lang/String;").toString(); + +- if (qtype.compare(QStringLiteral(MIFARETAG)) == 0) ++ if (qtype.compare(MIFARETAG) == 0) + return MifareTag; +- if (qtype.compare(QStringLiteral(NFCTAGTYPE1)) == 0) ++ if (qtype.compare(NFCTAGTYPE1) == 0) + return NfcTagType1; +- if (qtype.compare(QStringLiteral(NFCTAGTYPE2)) == 0) ++ if (qtype.compare(NFCTAGTYPE2) == 0) + return NfcTagType2; +- if (qtype.compare(QStringLiteral(NFCTAGTYPE3)) == 0) ++ if (qtype.compare(NFCTAGTYPE3) == 0) + return NfcTagType3; +- if (qtype.compare(QStringLiteral(NFCTAGTYPE4)) == 0) ++ if (qtype.compare(NFCTAGTYPE4) == 0) + return NfcTagType4; + return ProprietaryTag; +- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) { +- if (m_techList.contains(QStringLiteral(MIFARECLASSICTECHNOLOGY))) ++ } else if (m_techList.contains(NFCATECHNOLOGY)) { ++ if (m_techList.contains(MIFARECLASSICTECHNOLOGY)) + return MifareTag; + + // Checking ATQA/SENS_RES + // xxx0 0000 xxxx xxxx: Identifies tag Type 1 platform +- QAndroidJniObject nfca = getTagTechnology(QStringLiteral(NFCATECHNOLOGY)); ++ QAndroidJniObject nfca = getTagTechnology(NFCATECHNOLOGY); + QAndroidJniObject atqaBA = nfca.callObjectMethod("getAtqa", "()[B"); + QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA.object()); + if (atqaQBA.isEmpty()) +@@ -444,9 +463,9 @@ QNearFieldTarget::Type NearFieldTarget::getTagType() const + else if ((sakS & 0x0064) == 0x0020) + return NfcTagType4; + return ProprietaryTag; +- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) { ++ } else if (m_techList.contains(NFCBTECHNOLOGY)) { + return NfcTagType4; +- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) { ++ } else if (m_techList.contains(NFCFTECHNOLOGY)) { + return NfcTagType3; + } + +@@ -457,7 +476,7 @@ void NearFieldTarget::setupTargetCheckTimer() + { + m_targetCheckTimer = new QTimer(this); + m_targetCheckTimer->setInterval(1000); +- connect(m_targetCheckTimer, SIGNAL(timeout()), this, SLOT(checkIsTargetLost())); ++ QObject::connect(m_targetCheckTimer, &QTimer::timeout, this, &NearFieldTarget::checkIsTargetLost); + m_targetCheckTimer->start(); + } + +@@ -475,9 +494,42 @@ QAndroidJniObject NearFieldTarget::getTagTechnology(const QString &tech) const + // Getting requested technology + QAndroidJniObject tag = AndroidNfc::getTag(m_intent); + const QString sig = QString::fromUtf8("(Landroid/nfc/Tag;)L%1;"); +- QAndroidJniObject tagtech = QAndroidJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get", ++ QAndroidJniObject tagTech = QAndroidJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get", + sig.arg(techClass).toUtf8().constData(), tag.object()); +- return tagtech; ++ ++ return tagTech; ++} ++ ++bool NearFieldTarget::setTagTechnology(const QStringList &techList) ++{ ++ for (const QString &tech : techList) { ++ if (m_techList.contains(tech)) { ++ if (m_tech == tech) { ++ return true; ++ } ++ m_tech = tech; ++ m_tagTech = getTagTechnology(tech); ++ return m_tagTech.isValid(); ++ } ++ } ++ ++ return false; ++} ++ ++bool NearFieldTarget::connect() ++{ ++ if (!m_tagTech.isValid()) ++ return false; ++ ++ bool connected = m_tagTech.callMethod("isConnected"); ++ if (catchJavaExceptions()) ++ return false; ++ ++ if (connected) ++ return true; ++ ++ m_tagTech.callMethod("connect"); ++ return !catchJavaExceptions(); + } + + QByteArray NearFieldTarget::jbyteArrayToQByteArray(const jbyteArray &byteArray) const +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp +index da2d8f2d..de553ea9 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.cpp +@@ -44,9 +44,27 @@ + + QT_BEGIN_NAMESPACE + ++bool QNearFieldTargetPrivate::keepConnection() const ++{ ++ NEARFIELDTARGET_Q(); ++ return q->keepConnection(); ++} ++ ++bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent) ++{ ++ NEARFIELDTARGET_Q(); ++ return q->setKeepConnection(isPersistent); ++} ++ ++bool QNearFieldTargetPrivate::disconnect() ++{ ++ NEARFIELDTARGET_Q(); ++ return q->disconnect(); ++} ++ + int QNearFieldTargetPrivate::maxCommandLength() const + { +- NearFieldTarget * const q = reinterpret_cast(q_ptr); ++ NEARFIELDTARGET_Q(); + return q->maxCommandLength(); + } + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h +index f2e2ee7f..0063e9a5 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_android_p.h +@@ -75,6 +75,9 @@ public: + virtual QByteArray uid() const; + virtual Type type() const; + virtual AccessMethods accessMethods() const; ++ bool keepConnection() const; ++ bool setKeepConnection(bool isPersistent); ++ bool disconnect(); + virtual bool hasNdefMessage(); + virtual RequestId readNdefMessages(); + int maxCommandLength() const; +@@ -99,6 +102,8 @@ protected: + void setupTargetCheckTimer(); + void handleTargetLost(); + QAndroidJniObject getTagTechnology(const QString &tech) const; ++ bool setTagTechnology(const QStringList &techList); ++ bool connect(); + QByteArray jbyteArrayToQByteArray(const jbyteArray &byteArray) const; + bool catchJavaExceptions(bool verbose = true) const; + +@@ -108,6 +113,9 @@ protected: + QStringList m_techList; + Type m_type; + QTimer *m_targetCheckTimer; ++ QString m_tech; ++ QAndroidJniObject m_tagTech; ++ bool m_keepConnection; + }; + + QT_END_NAMESPACE +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp +index 3d1bfa6c..411b80d5 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_neard_p.cpp +@@ -44,6 +44,21 @@ + + QT_BEGIN_NAMESPACE + ++bool QNearFieldTargetPrivate::keepConnection() const ++{ ++ return false; ++} ++ ++bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent) ++{ ++ return false; ++} ++ ++bool QNearFieldTargetPrivate::disconnect() ++{ ++ return false; ++} ++ + int QNearFieldTargetPrivate::maxCommandLength() const + { + return 0; +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp y/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp +index 3d1bfa6c..4ed17a15 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_p.cpp +@@ -44,6 +44,22 @@ + + QT_BEGIN_NAMESPACE + ++bool QNearFieldTargetPrivate::keepConnection() const ++{ ++ return false; ++} ++ ++bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent) ++{ ++ Q_UNUSED(isPersistent); ++ return false; ++} ++ ++bool QNearFieldTargetPrivate::disconnect() ++{ ++ return false; ++} ++ + int QNearFieldTargetPrivate::maxCommandLength() const + { + return 0; +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_p.h y/qtconnectivity/src/nfc/qnearfieldtarget_p.h +index 9b2ed480..9cef2f55 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_p.h +@@ -59,6 +59,8 @@ + #include + #include + ++#define NEARFIELDTARGET_Q() NearFieldTarget * const q = reinterpret_cast(q_ptr) ++ + QT_BEGIN_NAMESPACE + + class QNearFieldTarget::RequestIdPrivate : public QSharedData +@@ -75,6 +77,9 @@ public: + + QMap m_decodedResponses; + ++ bool keepConnection() const; ++ bool setKeepConnection(bool isPersistent); ++ bool disconnect(); + int maxCommandLength() const; + }; + +-- +2.11.0 + diff --git a/patches/qt-Re-apply-the-cast-part-of-commit-392c7b99348e2a96ef1.patch b/patches/qt-Re-apply-the-cast-part-of-commit-392c7b99348e2a96ef1.patch deleted file mode 100644 index ba662d1..0000000 --- a/patches/qt-Re-apply-the-cast-part-of-commit-392c7b99348e2a96ef1.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0d2e326699d2646e38d60036659a7ff3e0b7b8d0 Mon Sep 17 00:00:00 2001 -From: Simon Hausmann -Date: Fri, 13 May 2016 14:24:59 +0200 -Subject: [PATCH] Re-apply the cast part of commit - 392c7b99348e2a96ef11adb5712095fbd13fb780 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We reverted this in 6f59c91c51edd7207635c3fa2f0b2b1179e7aa6e to avoid further -breakage in a patch release. Now let's do the right thing in the next minor -release and replace the qobject_cast on the instance with the IID check that -won't require instantiating the plugin in the qml loader thread. - -[ChangeLog][QtQml][Important Behavior Changes] When the engine looks for QML -modules / extension plugins in statically linked applications, the plugins are -not instantiated in the qml loader thread anymore. For this to work however -it is necessary for plugins to use Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) -in their class declaration instead of hardcoding the interface id as a string -literal. - -Task-number: QTBUG-52012 -Change-Id: I45fe8b9fec23b3d0408b7ee79ce297c7d47ce36d -Reviewed-by: Sebastian Lösch -Reviewed-by: J-P Nurmi ---- - src/qml/qml/qqmlimport.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git x/qtdeclarative/src/qml/qml/qqmlimport.cpp y/qtdeclarative/src/qml/qml/qqmlimport.cpp -index b51c78b..32faf76 100644 ---- x/qtdeclarative/src/qml/qml/qqmlimport.cpp -+++ y/qtdeclarative/src/qml/qml/qqmlimport.cpp -@@ -913,7 +913,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector &res - // To avoid traversing all static plugins for all imports, we cut down - // the list the first time called to only contain QML plugins: - foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) { -- if (qobject_cast(plugin.instance())) -+ if (plugin.metaData().value(QStringLiteral("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid)) - plugins.append(plugin); - } - } --- -2.8.3 - diff --git a/patches/qt-Use-apksigner-by-default-if-available-to-sign-the-AP.patch b/patches/qt-Use-apksigner-by-default-if-available-to-sign-the-AP.patch new file mode 100644 index 0000000..8d5468e --- /dev/null +++ b/patches/qt-Use-apksigner-by-default-if-available-to-sign-the-AP.patch @@ -0,0 +1,176 @@ +From 797de4af8231945e1b3688b14719900d9fd0f09e Mon Sep 17 00:00:00 2001 +From: BogDan Vatra +Date: Tue, 1 Nov 2016 17:53:29 +0200 +Subject: [PATCH] Use apksigner by default if available to sign the APKs + +apksigner is smart enough to know which techique to use to sign the apk +based on apk's manifest file. + +People that really want to use jarsigner they need to pass --jarsigner +argument + +Task-number: QTBUG-56702 +Change-Id: I3acd26576c5b0b312d5f2424b1c0a52e48fb920e +--- + src/androiddeployqt/main.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 109 insertions(+), 1 deletion(-) + +diff --git x/qttools/src/androiddeployqt/main.cpp y/qttools/src/androiddeployqt/main.cpp +index c1fd130..fc1cb94 100644 +--- x/qttools/src/androiddeployqt/main.cpp ++++ y/qttools/src/androiddeployqt/main.cpp +@@ -102,6 +102,7 @@ struct Options + , internalSf(false) + , sectionsOnly(false) + , protectedAuthenticationPath(false) ++ , jarSigner(false) + , gdbServer(Auto) + , installApk(false) + , uninstallApk(false) +@@ -181,6 +182,7 @@ struct Options + bool internalSf; + bool sectionsOnly; + bool protectedAuthenticationPath; ++ bool jarSigner; + + // Gdbserver + TriState gdbServer; +@@ -446,6 +448,8 @@ Options parseOptions() + options.sectionsOnly = true; + } else if (argument.compare(QLatin1String("--protected"), Qt::CaseInsensitive) == 0) { + options.protectedAuthenticationPath = true; ++ } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) { ++ options.jarSigner = true; + } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) { + options.generateAssetsFileList = false; + } +@@ -519,6 +523,8 @@ void printHelp() + " --internalsf: Include the .SF file inside the signature block.\n" + " --sectionsonly: Don't compute hash of entire manifest.\n" + " --protected: Keystore has protected authentication path.\n" ++ " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n" ++ " used if available.\n" + " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n" + " is bundled for debug pacakges.\n" + " --no-gdbserver: Prevents the gdbserver from being added to the package\n" +@@ -2554,7 +2560,7 @@ bool copyGnuStl(Options *options) + return true; + } + +-bool signPackage(const Options &options) ++bool jarSignerSignPackage(const Options &options) + { + if (options.verbose) + fprintf(stdout, "Signing Android package.\n"); +@@ -2680,6 +2686,108 @@ bool signPackage(const Options &options) + return QFile::remove(apkPath(options, UnsignedAPK)); + } + ++bool signPackage(const Options &options) ++{ ++ QString apksignerTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/apksigner"); ++#if defined(Q_OS_WIN32) ++ apksignerTool += QLatin1String(".bat"); ++#endif ++ ++ if (options.jarSigner || !QFile::exists(apksignerTool)) ++ return jarSignerSignPackage(options); ++ ++ // APKs signed with apksigner must not be changed after they're signed, therefore we need to zipalign it before we sign it. ++ ++ QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign"); ++#if defined(Q_OS_WIN32) ++ zipAlignTool += QLatin1String(".exe"); ++#endif ++ ++ if (!QFile::exists(zipAlignTool)) { ++ zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign"); ++#if defined(Q_OS_WIN32) ++ zipAlignTool += QLatin1String(".exe"); ++#endif ++ if (!QFile::exists(zipAlignTool)) { ++ fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool)); ++ return false; ++ } ++ } ++ ++ zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4") ++ .arg(shellQuote(zipAlignTool)) ++ .arg(options.verbose ? QString::fromLatin1(" -v") : QString()) ++ .arg(apkPath(options, UnsignedAPK)) ++ .arg(apkPath(options, SignedAPK)); ++ ++ FILE *zipAlignCommand = openProcess(zipAlignTool); ++ if (zipAlignCommand == 0) { ++ fprintf(stderr, "Couldn't run zipalign.\n"); ++ return false; ++ } ++ ++ char buffer[512]; ++ while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) ++ fprintf(stdout, "%s", buffer); ++ ++ int errorCode = pclose(zipAlignCommand); ++ if (errorCode != 0) { ++ fprintf(stderr, "zipalign command failed.\n"); ++ if (!options.verbose) ++ fprintf(stderr, " -- Run with --verbose for more information.\n"); ++ return false; ++ } ++ ++ QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2") ++ .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore)); ++ ++ if (!options.keyStorePassword.isEmpty()) ++ apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword)); ++ ++ if (!options.keyStoreAlias.isEmpty()) ++ apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias)); ++ ++ if (!options.keyPass.isEmpty()) ++ apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass)); ++ ++ if (options.verbose) ++ apkSignerCommandLine += QLatin1String(" --verbose"); ++ ++ apkSignerCommandLine += QString::fromLatin1(" %1") ++ .arg(apkPath(options, SignedAPK)); ++ ++ auto apkSignerRunner = [&] { ++ FILE *apkSignerCommand = openProcess(apkSignerCommandLine); ++ if (apkSignerCommand == 0) { ++ fprintf(stderr, "Couldn't run apksigner.\n"); ++ return false; ++ } ++ ++ char buffer[512]; ++ while (fgets(buffer, sizeof(buffer), apkSignerCommand) != 0) ++ fprintf(stdout, "%s", buffer); ++ ++ errorCode = pclose(apkSignerCommand); ++ if (errorCode != 0) { ++ fprintf(stderr, "apksigner command failed.\n"); ++ if (!options.verbose) ++ fprintf(stderr, " -- Run with --verbose for more information.\n"); ++ return false; ++ } ++ return true; ++ }; ++ ++ // Sign the package ++ if (!apkSignerRunner()) ++ return false; ++ ++ apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2") ++ .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK)); ++ ++ // Verify the package and remove the unsigned apk ++ return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK)); ++} ++ + bool copyGdbServer(const Options &options) + { + if (options.verbose) +-- +2.10.2 + diff --git a/patches/qt-Use-defaultSize-according-to-svg-standard-in-svg-plugin.patch b/patches/qt-Use-defaultSize-according-to-svg-standard-in-svg-plugin.patch new file mode 100644 index 0000000..5fb28cc --- /dev/null +++ b/patches/qt-Use-defaultSize-according-to-svg-standard-in-svg-plugin.patch @@ -0,0 +1,379 @@ +From eba0d9bdf34f60f2c36f8cef6c412cbed210fa2f Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Fri, 2 Dec 2016 08:05:46 +0100 +Subject: Use defaultSize according to svg standard in svg plugin + +The viewBox attribute defines the svg internal coordinate system. If no +width/height is set, the viewBox size is the right choice for defaultSize. +Otherwise the standard prescribes that the specified height/width must be +used. + +The old behavior ignored the width and height attributes, and this caused a +lot of problems in qml. If the viewBox was very small the result was a low +resolution image. If the viewBox was very large, loading took ages and the +result used much more memory than needed. Both situations could be avoided +by setting sourceSize. But when using the same image several times, the +sourceSize must be set every time to the same value, otherwise the image +cache would not work. It is cheaper to have the same high-quality source +image in the cache, and scale it down when required. + +With the new behavior it is possible to control the default image size +directly in the svg file at one place while it is still possible to set +different sourceSizes if needed. + +Task-number: QTBUG-44863 +Change-Id: I9c2fc7c122a29ebcf288b7cbd12427e081d404d5 +--- + src/plugins/imageformats/svg/qsvgiohandler.cpp | 2 +- + tests/auto/auto.pro | 1 + + tests/auto/qsvgplugin/.gitignore | 1 + + tests/auto/qsvgplugin/qsvgplugin.pro | 8 ++ + tests/auto/qsvgplugin/resources.qrc | 16 ++++ + tests/auto/qsvgplugin/square.svg | 5 ++ + tests/auto/qsvgplugin/square_size.svg | 5 ++ + tests/auto/qsvgplugin/square_size_viewbox.svg | 5 ++ + tests/auto/qsvgplugin/square_viewbox.svg | 5 ++ + tests/auto/qsvgplugin/tall.svg | 5 ++ + tests/auto/qsvgplugin/tall_size.svg | 5 ++ + tests/auto/qsvgplugin/tall_size_viewbox.svg | 5 ++ + tests/auto/qsvgplugin/tall_viewbox.svg | 5 ++ + tests/auto/qsvgplugin/tst_qsvgplugin.cpp | 108 +++++++++++++++++++++++++ + tests/auto/qsvgplugin/wide.svg | 5 ++ + tests/auto/qsvgplugin/wide_size.svg | 5 ++ + tests/auto/qsvgplugin/wide_size_viewbox.svg | 5 ++ + tests/auto/qsvgplugin/wide_viewbox.svg | 5 ++ + 18 files changed, 195 insertions(+), 1 deletion(-) + create mode 100644 tests/auto/qsvgplugin/.gitignore + create mode 100644 tests/auto/qsvgplugin/qsvgplugin.pro + create mode 100644 tests/auto/qsvgplugin/resources.qrc + create mode 100644 tests/auto/qsvgplugin/square.svg + create mode 100644 tests/auto/qsvgplugin/square_size.svg + create mode 100644 tests/auto/qsvgplugin/square_size_viewbox.svg + create mode 100644 tests/auto/qsvgplugin/square_viewbox.svg + create mode 100644 tests/auto/qsvgplugin/tall.svg + create mode 100644 tests/auto/qsvgplugin/tall_size.svg + create mode 100644 tests/auto/qsvgplugin/tall_size_viewbox.svg + create mode 100644 tests/auto/qsvgplugin/tall_viewbox.svg + create mode 100644 tests/auto/qsvgplugin/tst_qsvgplugin.cpp + create mode 100644 tests/auto/qsvgplugin/wide.svg + create mode 100644 tests/auto/qsvgplugin/wide_size.svg + create mode 100644 tests/auto/qsvgplugin/wide_size_viewbox.svg + create mode 100644 tests/auto/qsvgplugin/wide_viewbox.svg + +diff --git x/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp y/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp +index 88d37bc..0c26cb5 100644 +--- x/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp ++++ y/qtsvg/src/plugins/imageformats/svg/qsvgiohandler.cpp +@@ -98,7 +98,7 @@ bool QSvgIOHandlerPrivate::load(QIODevice *device) + } + + if (res) { +- defaultSize = QSize(r.viewBox().width(), r.viewBox().height()); ++ defaultSize = r.defaultSize(); + loaded = true; + } + +diff --git x/qtsvg/tests/auto/auto.pro y/qtsvg/tests/auto/auto.pro +index 43ff500..e2d84ec 100644 +--- x/qtsvg/tests/auto/auto.pro ++++ y/qtsvg/tests/auto/auto.pro +@@ -4,6 +4,7 @@ qtHaveModule(widgets) { + qsvgdevice \ + qsvggenerator \ + qsvgrenderer \ ++ qsvgplugin \ + qicon_svg \ + cmake \ + installed_cmake +diff --git x/qtsvg/tests/auto/qsvgplugin/.gitignore y/qtsvg/tests/auto/qsvgplugin/.gitignore +new file mode 100644 +index 0000000..c41c448 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/.gitignore +@@ -0,0 +1 @@ ++tst_qsvgplugin +diff --git x/qtsvg/tests/auto/qsvgplugin/qsvgplugin.pro y/qtsvg/tests/auto/qsvgplugin/qsvgplugin.pro +new file mode 100644 +index 0000000..3fec52e +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/qsvgplugin.pro +@@ -0,0 +1,8 @@ ++TARGET = tst_qsvgplugin ++CONFIG += testcase ++QT += svg testlib widgets gui-private ++ ++SOURCES += tst_qsvgplugin.cpp ++RESOURCES += resources.qrc ++ ++DEFINES += SRCDIR=\\\"$$PWD/\\\" +diff --git x/qtsvg/tests/auto/qsvgplugin/resources.qrc y/qtsvg/tests/auto/qsvgplugin/resources.qrc +new file mode 100644 +index 0000000..fcb311a +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/resources.qrc +@@ -0,0 +1,16 @@ ++ ++ ++ square.svg ++ square_size.svg ++ square_size_viewbox.svg ++ square_viewbox.svg ++ tall.svg ++ tall_size.svg ++ tall_size_viewbox.svg ++ tall_viewbox.svg ++ wide.svg ++ wide_size.svg ++ wide_size_viewbox.svg ++ wide_viewbox.svg ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/square.svg y/qtsvg/tests/auto/qsvgplugin/square.svg +new file mode 100644 +index 0000000..f35fb87 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/square.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/square_size.svg y/qtsvg/tests/auto/qsvgplugin/square_size.svg +new file mode 100644 +index 0000000..f4aeb67 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/square_size.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/square_size_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/square_size_viewbox.svg +new file mode 100644 +index 0000000..cf39bd7 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/square_size_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/square_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/square_viewbox.svg +new file mode 100644 +index 0000000..5811505 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/square_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/tall.svg y/qtsvg/tests/auto/qsvgplugin/tall.svg +new file mode 100644 +index 0000000..b243b62 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/tall.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/tall_size.svg y/qtsvg/tests/auto/qsvgplugin/tall_size.svg +new file mode 100644 +index 0000000..6121451 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/tall_size.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/tall_size_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/tall_size_viewbox.svg +new file mode 100644 +index 0000000..9d82492 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/tall_size_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/tall_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/tall_viewbox.svg +new file mode 100644 +index 0000000..8ed61a9 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/tall_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/tst_qsvgplugin.cpp y/qtsvg/tests/auto/qsvgplugin/tst_qsvgplugin.cpp +new file mode 100644 +index 0000000..4ec1737 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/tst_qsvgplugin.cpp +@@ -0,0 +1,108 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2016 The Qt Company Ltd. ++** Contact: https://www.qt.io/licensing/ ++** ++** This file is part of the test suite of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and The Qt Company. For licensing terms ++** and conditions see https://www.qt.io/terms-conditions. For further ++** information use the contact form at https://www.qt.io/contact-us. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 3 as published by the Free Software ++** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ++** included in the packaging of this file. Please review the following ++** information to ensure the GNU General Public License requirements will ++** be met: https://www.gnu.org/licenses/gpl-3.0.html. ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++ ++#include ++ ++#include "../../../src/plugins/imageformats/svg/qsvgiohandler.cpp" ++#include ++#include ++#include ++ ++#ifndef SRCDIR ++#define SRCDIR ++#endif ++ ++ ++class tst_QSvgPlugin : public QObject ++{ ++Q_OBJECT ++ ++public: ++ tst_QSvgPlugin(); ++ virtual ~tst_QSvgPlugin(); ++ ++private slots: ++ void checkSize_data(); ++ void checkSize(); ++}; ++ ++ ++ ++tst_QSvgPlugin::tst_QSvgPlugin() ++{ ++} ++ ++tst_QSvgPlugin::~tst_QSvgPlugin() ++{ ++} ++ ++void tst_QSvgPlugin::checkSize_data() ++{ ++ QTest::addColumn("filename"); ++ QTest::addColumn("imageHeight"); ++ QTest::addColumn("imageWidth"); ++ ++ QTest::newRow("square") << SRCDIR "square.svg" << 50 << 50; ++ QTest::newRow("square_size") << SRCDIR "square_size.svg" << 200 << 200; ++ QTest::newRow("square_size_viewbox") << SRCDIR "square_size_viewbox.svg" << 200 << 200; ++ QTest::newRow("square_viewbox") << SRCDIR "square_viewbox.svg" << 100 << 100; ++ QTest::newRow("tall") << SRCDIR "tall.svg" << 50 << 25; ++ QTest::newRow("tall_size") << SRCDIR "tall_size.svg" << 200 << 100; ++ QTest::newRow("tall_size_viewbox") << SRCDIR "tall_size_viewbox.svg" << 200 << 100; ++ QTest::newRow("tall_viewbox") << SRCDIR "tall_viewbox.svg" << 100 << 50; ++ QTest::newRow("wide") << SRCDIR "wide.svg" << 25 << 50; ++ QTest::newRow("wide_size") << SRCDIR "wide_size.svg" << 100 << 200; ++ QTest::newRow("wide_size_viewbox") << SRCDIR "wide_size_viewbox.svg" << 100 << 200; ++ QTest::newRow("wide_viewbox") << SRCDIR "wide_viewbox.svg" << 50 << 100; ++} ++ ++void tst_QSvgPlugin::checkSize() ++{ ++ QFETCH(QString, filename); ++ QFETCH(int, imageHeight); ++ QFETCH(int, imageWidth); ++ ++ QFile file(filename); ++ file.open(QIODevice::ReadOnly); ++ ++ QSvgIOHandler plugin; ++ plugin.setDevice(&file); ++ ++ QImage image; ++ plugin.read(&image); ++ ++ file.close(); ++ ++ QCOMPARE(imageHeight, image.height()); ++ QCOMPARE(imageWidth, image.width()); ++} ++ ++ ++QTEST_MAIN(tst_QSvgPlugin) ++#include "tst_qsvgplugin.moc" +diff --git x/qtsvg/tests/auto/qsvgplugin/wide.svg y/qtsvg/tests/auto/qsvgplugin/wide.svg +new file mode 100644 +index 0000000..9166606 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/wide.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/wide_size.svg y/qtsvg/tests/auto/qsvgplugin/wide_size.svg +new file mode 100644 +index 0000000..e816154 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/wide_size.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/wide_size_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/wide_size_viewbox.svg +new file mode 100644 +index 0000000..3d9b044 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/wide_size_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +diff --git x/qtsvg/tests/auto/qsvgplugin/wide_viewbox.svg y/qtsvg/tests/auto/qsvgplugin/wide_viewbox.svg +new file mode 100644 +index 0000000..aface45 +--- /dev/null ++++ y/qtsvg/tests/auto/qsvgplugin/wide_viewbox.svg +@@ -0,0 +1,5 @@ ++ ++ ++ ++ ++ +-- +2.11.0 + diff --git a/patches/qt-disable-qtplugininfo.patch b/patches/qt-disable-qtplugininfo.patch deleted file mode 100644 index 37f6e3d..0000000 --- a/patches/qt-disable-qtplugininfo.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 792487510efc7a1fb34366804c431aee6e1219c5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= -Date: Tue, 22 Dec 2015 18:43:02 +0100 -Subject: [PATCH] Disable qtpluginfo as it breaks install step on Android - ---- - src/src.pro | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git x/qttools/src/src.pro y/qttools/src/src.pro -index 387d54f..3151495 100644 ---- x/qttools/src/src.pro -+++ y/qttools/src/src.pro -@@ -14,8 +14,7 @@ qtHaveModule(widgets) { - } - - SUBDIRS += linguist \ -- qdoc \ -- qtplugininfo -+ qdoc - if(!android|android_app):!ios: SUBDIRS += qtpaths - - mac { --- -2.6.4 - diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 63edbf6..e78a850 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -3,13 +3,15 @@ SET(QRC_FILES "ausweisapp.qrc") IF(IOS OR ANDROID OR ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") LIST(APPEND QRC_FILES "ausweisapp_mobile.qrc") ENDIF() -IF(LINUX OR WIN32 OR MAC) + +IF(DESKTOP) LIST(APPEND QRC_FILES "ausweisapp_desktop.qrc") ENDIF() SET(RCC ${CMAKE_BINARY_DIR}/src/${PROJECT_NAME}.rcc) SET(RCC ${RCC} PARENT_SCOPE) qt5_add_binary_resources(AusweisAppRcc "${QRC_FILES}" DESTINATION ${RCC}) +SET(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml ${CMAKE_CURRENT_SOURCE_DIR}/qml_stationary CACHE string "qml files" FORCE) IF(WIN32) SET(WINDOWS_RC "${CMAKE_CURRENT_SOURCE_DIR}/windows.rc" PARENT_SCOPE) diff --git a/resources/asan_blacklist b/resources/asan_blacklist new file mode 100644 index 0000000..60992d5 --- /dev/null +++ b/resources/asan_blacklist @@ -0,0 +1,7 @@ +# Recommended usage: +# LSAN_OPTIONS=suppressions=/home/dev/src/asan_blacklist ./AusweisApp2 + +leak:g_malloc* +leak:CRYPTO_malloc +leak:libxcb* +leak:Q* diff --git a/resources/ausweisapp.qrc b/resources/ausweisapp.qrc index 2ff23fa..b643c6a 100644 --- a/resources/ausweisapp.qrc +++ b/resources/ausweisapp.qrc @@ -1,15 +1,6 @@ - images/beta.svg - images/siteWithLogo.png - images/MenuSelected.png - images/MenuUnselected.png - images/MenuUnselectedDisabled.png - images/information.png - images/npa.ico - images/Logo_AutentApp2_2014.png - images/AppLogo_AutentApp2_2014.png - images/start_nPA_eAT.png + images/npa.svg images/bg_da.png images/bt_1.svg images/bt_1b.svg @@ -21,26 +12,14 @@ images/bt_4b.svg images/bspd1.svg images/canHint.png - images/busy_animation.gif images/icon_attention.svg images/icon_ok.png images/icon_cancelled.png images/Icon_Checked.svg - images/autentapp2.iconset/icon_16x16.png - images/autentapp2.iconset/icon_32x32.png - images/autentapp2.iconset/icon_512x512.png - images/reader/default_no_cardreader_01.png - images/reader/default_more_cardreader.png - images/reader/default_no_card_found.png - images/reader/img_cyberjack_wave.png - images/reader/img_cyberjack_wave_mit_ausweis.png - - stylesheets/common.qss - stylesheets/macos.qss - stylesheets/windows.qss - stylesheets/desktop.qss - images/magnifying-glass.png - images/text-edit-x.png + images/android/search_icon.svg + images/android/search_cancel.svg + images/iOS/search_icon.svg + images/iOS/search_cancel.svg images/back-chevron.png images/iOS/tabBar/Anbieter-off.png images/iOS/tabBar/Anbieter-on.png @@ -50,29 +29,56 @@ images/iOS/tabBar/Pin-on.png images/iOS/tabBar/Verlauf-off.png images/iOS/tabBar/Verlauf-on.png - images/iOS/gruener_Haken.svg images/icon_Bluetooth.svg images/icon_Pin.svg - images/All.png images/iOS/tabBar/More-off.svg images/iOS/tabBar/More-on.svg - images/iOS/rotes_X.svg - images/iOS/ProviderInformation.png - images/iOS/ProviderPurpose.png + images/rotes_X.svg + images/gruener_Haken.svg images/iOS/CheckedCheckbox.png images/iOS/Header-Ausweisapp@3x.png images/delete.png + images/delete.svg images/NFCPhoneCard.png images/submit.png - images/androidtelefon.png + images/submit.svg images/ausweis.png + images/provider/information.svg + images/provider/purpose.svg images/provider/adresse.png + images/provider/+tablet/adresse.png images/provider/mail.png + images/provider/+tablet/mail.png images/provider/telefon.png + images/provider/+tablet/telefon.png images/provider/url.png + images/provider/+tablet/url.png images/provider/gradient-citizen.png images/provider/gradient-insurance.png images/provider/gradient-finance.png images/provider/gradient-other.png + images/provider/categoryIcons/+android/General.svg + images/provider/categoryIcons/+android/CitizenServices.svg + images/provider/categoryIcons/+android/Financials.svg + images/provider/categoryIcons/+android/Insurances.svg + images/provider/categoryIcons/+android/OtherServices.svg + images/provider/categoryIcons/+android/General_bg.svg + images/provider/categoryIcons/+android/General_button.svg + images/provider/categoryIcons/+android/CitizenServices_bg.svg + images/provider/categoryIcons/+android/CitizenServices_button.svg + images/provider/categoryIcons/+android/Financials_bg.svg + images/provider/categoryIcons/+android/Financials_button.svg + images/provider/categoryIcons/+android/Insurances_bg.svg + images/provider/categoryIcons/+android/Insurances_button.svg + images/provider/categoryIcons/+android/OtherServices_bg.svg + images/provider/categoryIcons/+android/OtherServices_button.svg + images/provider/categoryIcons/+android/General_section.svg + images/provider/categoryIcons/+android/CitizenServices_section.svg + images/provider/categoryIcons/+android/Financials_section.svg + images/provider/categoryIcons/+android/Insurances_section.svg + images/provider/categoryIcons/+android/OtherServices_section.svg + images/icon_nfc.svg + images/phone_nfc.svg + images/phone_bluetooth.svg diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index 147d5c4..b70fd74 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -2,6 +2,22 @@ html_templates/alreadyactive.html html_templates/error.html + + stylesheets/common.qss + stylesheets/macos.qss + stylesheets/windows.qss + stylesheets/desktop.qss + + images/beta.svg + images/MenuSelected.png + images/MenuUnselected.png + images/MenuUnselectedDisabled.png + images/npa.ico + images/siteWithLogo.png + images/Logo_AutentApp2_2014.png + images/AppLogo_AutentApp2_2014.png + images/start_nPA_eAT.png + images/busy_animation.gif images/html_message_section.jpg images/randompin/btn_normal_0.png images/randompin/btn_normal_1.png @@ -17,7 +33,12 @@ images/randompin/btn_ok.png images/randompin/btn_cancel.png images/randompin/btn_clear.png - + + images/reader/default_no_cardreader_01.png + images/reader/default_more_cardreader.png + images/reader/default_no_card_found.png + images/reader/img_cyberjack_wave.png + images/reader/img_cyberjack_wave_mit_ausweis.png images/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png images/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png images/reader/img_Reiner_SCT_cyberjack_RFID_standard.png @@ -25,14 +46,14 @@ images/reader/img_Reiner_SCT_cyberjack_RFID_basis.png images/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png images/reader/img_Identive_SCL011.png - - images/reader/img_Identive_SCL011_mit_ausweis.png + + images/reader/img_Identive_SCL011_mit_ausweis.png images/reader/img_Identive_SDI011.png images/reader/img_Identive_SDI011_mit_ausweis.png images/reader/img_KOBIL_ID_Token.png images/reader/img_KOBIL_ID_Token_mit_ausweis.png images/reader/img_ACS_ACR1281U.png - images/reader/img_ACS_ACR1281U_mit_ausweis.png + images/reader/img_ACS_ACR1281U_mit_ausweis.png images/reader/img_HID_Global_OMNIKEY_5321_V2.png images/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index b8b3afa..40ad763 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -1,31 +1,30 @@ - images/mobile/appStartPageBackground.jpg + qtquickcontrols2.conf + images/zahnraeder.svg + images/check.svg images/iOS/arrowLeft.svg images/iOS/arrowRight.svg - images/iOS/check.svg images/iOS/list_item_arrow.svg images/iOS/radio_button_check_ios.svg images/iOS/toggle_on.png images/iOS/toggle_off.png images/iOS/toggle_disabled.png - - images/android/navigation/ausweisen.png - images/android/navigation/anbieter.png - images/android/navigation/verlauf.png - images/android/navigation/pin.png - images/android/navigation/versionsinformation.png - images/android/navigation/faq.png - images/android/navigation/support.png - images/android/navigation/bewerten.png - images/android/navigation/teilen.png - + images/android/navigation/ausweisen.svg + images/android/navigation/anbieter.svg + images/android/navigation/balloon.svg + images/android/navigation/verlauf.svg + images/android/navigation/pin.svg + images/android/navigation/versionsinformation.svg + images/android/navigation/faq.svg + images/android/navigation/support.svg + images/android/navigation/bewerten.svg + images/android/navigation/teilen.svg images/android/mdpi/haken.png images/android/hdpi/haken.png images/android/xhdpi/haken.png images/android/xxhdpi/haken.png images/android/xxxhdpi/haken.png - images/android/checkbox_0.svg images/android/checkbox_1.svg images/android/tabDivider.svg @@ -39,45 +38,24 @@ images/android/android_toggle_off_disabled.png images/android/android_arrow_back.svg images/android/android_arrow_back_white.svg - images/android/android_search_icon.svg - images/more/icon_mehr_favorit.svg - images/more/icon_mehr_fragen.svg - images/more/icon_mehr_upload.svg - images/more/icon_mehr_info.svg - images/provider/categoryIcons/+android/CitizenServices.png - images/provider/categoryIcons/+android/Financials.png - images/provider/categoryIcons/+android/Insurances.png - images/provider/categoryIcons/+android/OtherServices.png - images/provider/categoryIcons/+android/CitizenServices_bg.png - images/provider/categoryIcons/+android/Financials_bg.png - images/provider/categoryIcons/+android/Insurances_bg.png - images/provider/categoryIcons/+android/OtherServices_bg.png - images/provider/categoryIcons/+android/CitizenServices_button.png - images/provider/categoryIcons/+android/Financials_button.png - images/provider/categoryIcons/+android/Insurances_button.png - images/provider/categoryIcons/+android/OtherServices_button.png - images/provider/categoryIcons/+android/General_bg.png - images/provider/categoryIcons/CitizenServices.png - images/provider/categoryIcons/Financials.png - images/provider/categoryIcons/Insurances.png - images/provider/categoryIcons/OtherServices.png - images/provider/+tablet/adresse.png - images/provider/+tablet/mail.png - images/provider/+tablet/telefon.png - images/provider/+tablet/url.png - images/provider/categoryIcons/+android/CitizenServices_bg.png - images/provider/categoryIcons/+android/Financials_bg.png - images/provider/categoryIcons/+android/Insurances_bg.png - images/provider/categoryIcons/+android/OtherServices_bg.png - images/provider/categoryIcons/+android/CitizenServices_button.png - images/provider/categoryIcons/+android/Financials_button.png - images/provider/categoryIcons/+android/Insurances_button.png - images/provider/categoryIcons/+android/OtherServices_button.png - images/provider/categoryIcons/+android/General_bg.png - images/provider/categoryIcons/+android/CitizenServices_section.png - images/provider/categoryIcons/+android/Financials_section.png - images/provider/categoryIcons/+android/Insurances_section.png - images/provider/categoryIcons/+android/OtherServices_section.png - images/zahnraeder.svg + images/iOS/more/icon_mehr_favorit.svg + images/iOS/more/icon_mehr_fragen.svg + images/iOS/more/icon_mehr_upload.svg + images/iOS/more/icon_mehr_info.svg + images/provider/categoryIcons/General.svg + images/provider/categoryIcons/CitizenServices.svg + images/provider/categoryIcons/Financials.svg + images/provider/categoryIcons/Insurances.svg + images/provider/categoryIcons/OtherServices.svg + images/provider/categoryIcons/+android/General_bg.svg + images/provider/categoryIcons/+android/General_button.svg + images/provider/categoryIcons/+android/CitizenServices_bg.svg + images/provider/categoryIcons/+android/CitizenServices_button.svg + images/provider/categoryIcons/+android/Financials_bg.svg + images/provider/categoryIcons/+android/Financials_button.svg + images/provider/categoryIcons/+android/Insurances_bg.svg + images/provider/categoryIcons/+android/Insurances_button.svg + images/provider/categoryIcons/+android/OtherServices_bg.svg + images/provider/categoryIcons/+android/OtherServices_button.svg diff --git a/resources/config.json.in b/resources/config.json.in index beba169..9bef63e 100644 --- a/resources/config.json.in +++ b/resources/config.json.in @@ -5,14 +5,12 @@ "_comment_2": [ "certificate 1: DECVCAeID00103_DECVCAeID00104", "certificate 2: DECVCAeID00102_DECVCAeID00103", - "certificate 3: DECVCAeID00102", - "certificate 7: DECVCAeIDCT00001" + "certificate 3: DECVCAeID00102" ], "cvRootCertificates": [ - "7f218201b67f4e82016e5f290100420e44454356434165494430303130337f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7864104241d8627338b64f20077ffd558909a096c635ddb222852038eaae642e869a40173d588f817d95db2a6a0f077ea5ee63596a20f85bc3cb176d2f98d88d90219aa8701015f200e44454356434165494430303130347f4c12060904007f0007030102025305fc0f13ffff5f25060105000901045f24060108000901045f3740313a81ed8734e7a8c45f16b55fb603e63027b7f44c2de3a8e782552d35949db221ca33bd41a01da6a1288c7885714fc3a03fa45683b75d3884930ec6738af8a0", - "7f218201b67f4e82016e5f290100420e44454356434165494430303130327f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641048925419fc7f194922cfc6b8dd25ae6a19c1b59216e6cf06270e5d75cfd64205f55cf867bbfefeefd6e680e1fd197f18ab684484901362568efc9adb5c6018d728701015f200e44454356434165494430303130337f4c12060904007f0007030102025305fc0f13ffff5f25060102010200035f24060105010200035f37404d6f08a86a4f18409f6685387dd3c6a7ff5d68ea4f7714a861bbb3bb721d05d3014adf1763c9292f715d8e94ee9b3e1b73ab1382414ebf39dfb3b0fb6c09dbeb", - "7F218201B67F4E82016E5F290100420E44454356434165494430303130327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641043347ECF96FFB4BD9B8554EFBCCFC7D0B242F1071E29B4C9C622C79E339D840AF67BEB9B912692265D9C16C62573F4579FFD4DE2DE92BAB409DD5C5D48244A9F78701015F200E44454356434165494430303130327F4C12060904007F0007030102025305FE0F01FFFF5F25060100010001085F24060103010001085F37405067145C68CAE9520F5BB34817F1CA9C43593DB56406C6A3B006CBF3F314E7349ACF0CC6BFEBCBDEFD10B4DCF0F231DA56977D88F9F90182D199076A56506451", - "7f218201ba7f4e8201725f2901004210444543564341654944435430303030317f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641041f86a5f098c0d277ccece27e4fc35687ca67027563c4301956859b7c60ce65991a412c57d02871e22616ea63578ad2267c4cc82a4e3432901bf33693e436d4528701015f2010444543564341654944435430303030317f4c12060904007f0007030102025305fe1fffffff5f25060103000701065f24060106000701055f37407cbf6936f5557d8331321d34c6f59332115fdb704166dd360f7443b0cbb28a815dd111647e354009f7c2de142306954283a4d8fcd2311898729f095763d556cb" + "7F218201B67F4E82016E5F290100420E44454356434165494430303130337F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104241D8627338B64F20077FFD558909A096C635DDB222852038EAAE642E869A40173D588F817D95DB2A6A0F077EA5EE63596A20F85BC3CB176D2F98D88D90219AA8701015F200E44454356434165494430303130347F4C12060904007F0007030102025305FC0F13FFFF5F25060105000901045F24060108000901045F3740313A81ED8734E7A8C45F16B55FB603E63027B7F44C2DE3A8E782552D35949DB221CA33BD41A01DA6A1288C7885714FC3A03FA45683B75D3884930EC6738AF8A0", + "7F218201B67F4E82016E5F290100420E44454356434165494430303130327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641048925419FC7F194922CFC6B8DD25AE6A19C1B59216E6CF06270E5D75CFD64205F55CF867BBFEFEEFD6E680E1FD197F18AB684484901362568EFC9ADB5C6018D728701015F200E44454356434165494430303130337F4C12060904007F0007030102025305FC0F13FFFF5F25060102010200035F24060105010200035F37404D6F08A86A4F18409F6685387DD3C6A7FF5D68EA4F7714A861BBB3BB721D05D3014ADF1763C9292F715D8E94EE9B3E1B73AB1382414EBF39DFB3B0FB6C09DBEB", + "7F218201B67F4E82016E5F290100420E44454356434165494430303130327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641043347ECF96FFB4BD9B8554EFBCCFC7D0B242F1071E29B4C9C622C79E339D840AF67BEB9B912692265D9C16C62573F4579FFD4DE2DE92BAB409DD5C5D48244A9F78701015F200E44454356434165494430303130327F4C12060904007F0007030102025305FE0F01FFFF5F25060100010001085F24060103010001085F37405067145C68CAE9520F5BB34817F1CA9C43593DB56406C6A3B006CBF3F314E7349ACF0CC6BFEBCBDEFD10B4DCF0F231DA56977D88F9F90182D199076A56506451" ], "_comment_3": "array of Test-CVCs; hex encoded", @@ -20,13 +18,19 @@ "certificate 4: DETESTeID00001", "certificate 5: DETESTeID00002_DETESTeID00001", "certificate 6: DETESTeID00004_DETESTeID00002", - "certificate 8: DETESTeID00005_DETESTeID00004" + "certificate 7: DETESTeID00005_DETESTeID00004", + "certificate 8: DECVCAeIDCTL0401_DECVCAeIDCTL0402", + "certificate 9: DECVCAeIDCT00001_DECVCAeIDCTL0401", + "certificate 10: DECVCAeIDCT00001_DECVCAeIDCT00001" ], "cvRootCertificatesTest": [ "7F218201B67F4E82016E5F290100420E44455445535465494430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104184BB519FC2A8F52DC0DC73112FACFE914F2A49B678DD5799A2B1DFE95E1A66359014E22FA8D66438413CEBA6CF0E215576B673376BF617AF4DFE9761D2290148701015F200E44455445535465494430303030317F4C12060904007F0007030102025305FE0F01FFFF5F25060100000801035F24060103000801035F37409F25EBFAF4B91E4C60A1683754C5DC076A3179753EF97D9F8CB01FE1DCD3B8C83E7A26602AB1F344BE5706006D79A9FF6A9716404DC83B9F30E1213B393128A2", - "7f218201b67f4e82016e5f290100420e44455445535465494430303030317f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7864104096eb58bfd86252238ec2652185c43c3a56c320681a21e37a8e69ddc387c0c5f5513856efe2fdc656e604893212e29449b365e304605ac5413e75be31e641f128701015f200e44455445535465494430303030327f4c12060904007f0007030102025305fe0f01ffff5f25060100000902015f24060103000902015f3740141120a0fdfc011a52f3f72b387a3dc7aca88b4868d5ae9741780b6ff8a0b49e5f55169a2d298ef5cf95935dca0c3df3e9d42dc45f74f2066317154961e6c746", - "7f218201b67f4e82016e5f290100420e44455445535465494430303030327f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a786410474ff63ab838c73c303ac003dfee95cf8bf55f91e8febcb7395d942036e47cf1845ec786ec95bb453aac288ad023b6067913cf9b63f908f49304e5cfc8b3050dd8701015f200e44455445535465494430303030347f4c12060904007f0007030102025305fc0f13ffff5f25060102000501015f24060105000501015f37405c035a0611b6c58f0b5261fdd009decab7dc7a79482d5248cca119059b7d82b2157cf0c4a499bcf441efdd35e294a58c0af19a34a0762159533285acf170a505", - "7f218201b67f4e82016e5f290100420e44455445535465494430303030347f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641049bfeba8dc7faab6e3bdeb3ff794dbb800848fe4f6940a4cc7eecb5159c87da5395505892026d420a22596cd014ed1fd872dada597db0f8d64441041198f62d448701015f200e44455445535465494430303030357f4c12060904007f0007030102025305fc0f13ffff5f25060105000500045f24060108000500045f37402d2468416d66bcbe259b9b907a73395bc1ef94ed75f9c17615210246e9efb06e6753e9055ce76623b7699b9efb1a7d3a9dd83f6e6e09e55a33ea0a5f62a1c719" + "7F218201B67F4E82016E5F290100420E44455445535465494430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104096EB58BFD86252238EC2652185C43C3A56C320681A21E37A8E69DDC387C0C5F5513856EFE2FDC656E604893212E29449B365E304605AC5413E75BE31E641F128701015F200E44455445535465494430303030327F4C12060904007F0007030102025305FE0F01FFFF5F25060100000902015F24060103000902015F3740141120A0FDFC011A52F3F72B387A3DC7ACA88B4868D5AE9741780B6FF8A0B49E5F55169A2D298EF5CF95935DCA0C3DF3E9D42DC45F74F2066317154961E6C746", + "7F218201B67F4E82016E5F290100420E44455445535465494430303030327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410474FF63AB838C73C303AC003DFEE95CF8BF55F91E8FEBCB7395D942036E47CF1845EC786EC95BB453AAC288AD023B6067913CF9B63F908F49304E5CFC8B3050DD8701015F200E44455445535465494430303030347F4C12060904007F0007030102025305FC0F13FFFF5F25060102000501015F24060105000501015F37405C035A0611B6C58F0B5261FDD009DECAB7DC7A79482D5248CCA119059B7D82B2157CF0C4A499BCF441EFDD35E294A58C0AF19A34A0762159533285ACF170A505", + "7F218201B67F4E82016E5F290100420E44455445535465494430303030347F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641049BFEBA8DC7FAAB6E3BDEB3FF794DBB800848FE4F6940A4CC7EECB5159C87DA5395505892026D420A22596CD014ED1FD872DADA597DB0F8D64441041198F62D448701015F200E44455445535465494430303030357F4C12060904007F0007030102025305FC0F13FFFF5F25060105000500045F24060108000500045F37402D2468416D66BCBE259B9B907A73395BC1EF94ED75F9C17615210246E9EFB06E6753E9055CE76623B7699B9EFB1A7D3A9DD83F6E6E09E55A33EA0A5F62A1C719", + "7F218201BA7F4E8201725F290100421044454356434165494443544C303430317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641043EE15015916563E31459045924DE804C1D93A77652AA25D0B753730DBA3233886A9A9B28A06AF84CC5A40F78E9167CA40B8098724A3A0332283D0A52C5453FE08701015F201044454356434165494443544C303430327F4C12060904007F0007030102025305FE1FFFFFFF5F25060106000300015F24060109000300015F374068261CEB4DC915301371C9B273377F33CEB25AFA07E70EDB3498ACF0327DC13B9AF99A9D694A6D048F0DB6FF1774E882CA8F41C8A0B96FDDF6F6DDABFD55CB43", + "7F218201BA7F4E8201725F2901004210444543564341654944435430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641042C037C6CF8C0B62E36E220B7D411404AF248A2C83C569A49FAB02FC232D2395B3A5FF80DDB01D0DFAFCEF55E54ACCBA4C56E528F0746BEF1108E7D9B0122EBA78701015F201044454356434165494443544C303430317F4C12060904007F0007030102025305FE1FFFFFFF5F25060106000300015F24060109000300015F37404FB2F9F17D38656EEC2846CBB1711E07D739E6A584D487B3AFBA5C723C73A10236995E6A19499DE941DFE3CC044E2AACB6B5869C0E46C9585AEF892E2236F62E", + "7F218201BA7F4E8201725F2901004210444543564341654944435430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104206160B85B82B2BE249DCD7B15FD1AD46CA03F39FE675C07535806E57CE24349392BBB9F73B364672F12243F18083DCC49ACA613767F0873AEB60715FC605A288701015F2010444543564341654944435430303030317F4C12060904007F0007030102025305FE1FFFFFFF5F25060106000300015F24060109000300015F37402B62927D46BF675DB387FC4A425FF3B604B20DD5ED6FFCDAFA9DA1DD920DC996245B358167C66A721DF39C6897864E4D648746339A97D22D08659885F92BDE21" ], "_comment_5": "array of certificates for checking the authenticity of updates; DER format, hex encoded", @@ -36,73 +40,91 @@ "308202eb308201d3a003020102020437a18b8a300d06092a864886f70d01010b05003026310b3009060355040613024445311730150603550403130e6275696c64617574656e74617070301e170d3134303732343131323334325a170d3234303732313131323334325a3026310b3009060355040613024445311730150603550403130e6275696c64617574656e7461707030820122300d06092a864886f70d01010105000382010f003082010a0282010100ca573d1c79c72f15dd80020b39886bec2de9004556eabc833f61b86aac3b4658ed8ecf7f32cb3daeb34576b49ff13e9eaaafa5ce2cf7cb13df2f89be6a1659f79cca6b4276b90914594e74998f9b9fffa0c8efdf4409be91a195458e1a0dce707cb1573cab99d297c80e8026c2f299fd97b8bbf14b172094f17abe50483a2e1df0cf6629d024cf5b752a1bb0edbe172dcce7ed30cc3c193ba742bff2e0afa0f15c414f27bdb374f65ac71c0c7af3a4a5fe1707d22bed1b63019e659c42e763c601f45d60094be915a422a0c183da33e8b3909cf83c0d7dfd3d5ffd1a92cf00c07961b284ddbef1e9b9d5536e12630cefa8493c8244edd2f687b09d38e79f639d0203010001a321301f301d0603551d0e04160414b29d3e7f193789f68d2234738a2773e737c4ce1c300d06092a864886f70d01010b0500038201010030800530f9d3abb215e8c8da5ee62ee083bdd8fce00d673702d00fac194eabd4c0b9338166a6dd76711651e685d0b9a50cdf2dc4872edeb5f4369372fb0d70d8fe02892b962e5fafd73add31ec0fd6708aa6ad2c82beca260773dd3e62460d1e416ac8d931e221b1bcf8255abd44933d38660e5bad639c38fb7dbbcf1f9504e20b27d75810b5ab475ce061d725b54628b4cfd7bd53f29d93a8ecb16e96df9ff654da55ea8ed1700c8d3135b1bc97655595a56f75dfb101c27341309602dce89e9c4db08a7c19d7fb199394f0ec478c4f246dbab0a37c2cea22b5b2b4c9e589a640611348b77dddd0fc412c9980cb5d516b274b9649debdd22df123cd06495924%" ], - "_comment_6": "ciphers are ordered by preference", - "_comment_7": "prime256v1 := secp256r1", - "ecCiphers": [ - "brainpoolP512r1", - "brainpoolP384r1", - "brainpoolP256r1", - "secp384r1", - "prime256v1", - "secp224r1" - ], - "pskCiphers": [ - "RSA-PSK-AES256-GCM-SHA384", - "RSA-PSK-AES256-CBC-SHA384", - "RSA-PSK-AES128-GCM-SHA256", - "RSA-PSK-AES128-CBC-SHA256", - "RSA-PSK-AES256-CBC-SHA" - ], - "fsCiphers": [ - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "DHE-DSS-AES256-GCM-SHA384", - "DHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES256-SHA384", - "ECDHE-RSA-AES256-SHA384", - "DHE-DSS-AES256-SHA256", - "DHE-RSA-AES256-SHA256", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "DHE-DSS-AES128-GCM-SHA256", - "DHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-AES128-SHA256", - "ECDHE-RSA-AES128-SHA256", - "DHE-DSS-AES128-SHA256", - "DHE-RSA-AES128-SHA256" - ], - "fsCiphersWithBc": [ - "ECDHE-ECDSA-AES256-SHA", - "ECDHE-RSA-AES256-SHA", - "DHE-DSS-AES256-SHA", - "DHE-RSA-AES256-SHA", - "ECDHE-ECDSA-AES128-SHA", - "ECDHE-RSA-AES128-SHA", - "DHE-DSS-AES128-SHA", - "DHE-RSA-AES128-SHA" - ], - "sslProtocolVersion": "TlsV1_0OrLater", - "sslProtocolVersionPsk": "TlsV1_1OrLater", - "signatureAlgorithms" : [ - "Rsa+Sha512", - "Dsa+Sha512", - "Ec+Sha512", - "Rsa+Sha384", - "Dsa+Sha384", - "Ec+Sha384", - "Rsa+Sha256", - "Dsa+Sha256", - "Ec+Sha256", - "Rsa+Sha224", - "Dsa+Sha224", - "Ec+Sha224" - ], - "signatureAlgorithmsPsk" : [ - "Rsa+Sha512", - "Rsa+Sha384", - "Rsa+Sha256", - "Rsa+Sha224" - ], + "tlsSettings" : { + "protocolVersion": "TlsV1_0OrLater", + "_comment_1": "ciphers are ordered by preference", + "ciphers": [ + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "DHE-DSS-AES256-GCM-SHA384", + "DHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES256-SHA384", + "ECDHE-RSA-AES256-SHA384", + "DHE-DSS-AES256-SHA256", + "DHE-RSA-AES256-SHA256", + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "DHE-DSS-AES128-GCM-SHA256", + "DHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES128-SHA256", + "ECDHE-RSA-AES128-SHA256", + "DHE-DSS-AES128-SHA256", + "DHE-RSA-AES128-SHA256", + "ECDHE-ECDSA-AES256-SHA", + "ECDHE-RSA-AES256-SHA", + "DHE-DSS-AES256-SHA", + "DHE-RSA-AES256-SHA", + "ECDHE-ECDSA-AES128-SHA", + "ECDHE-RSA-AES128-SHA", + "DHE-DSS-AES128-SHA", + "DHE-RSA-AES128-SHA" + ], + "_comment_2": "prime256v1 := secp256r1", + "ellipticCurves": [ + "brainpoolP512r1", + "brainpoolP384r1", + "brainpoolP256r1", + "secp384r1", + "prime256v1", + "secp224r1" + ], + "signatureAlgorithms" : [ + "Rsa+Sha512", + "Dsa+Sha512", + "Ec+Sha512", + "Rsa+Sha384", + "Dsa+Sha384", + "Ec+Sha384", + "Rsa+Sha256", + "Dsa+Sha256", + "Ec+Sha256", + "Rsa+Sha224", + "Dsa+Sha224", + "Ec+Sha224" + ] + }, + + "tlsSettingsPsk" : { + "protocolVersion": "TlsV1_1OrLater", + "_comment_1": "ciphers are ordered by preference", + "ciphers": [ + "RSA-PSK-AES256-GCM-SHA384", + "RSA-PSK-AES256-CBC-SHA384", + "RSA-PSK-AES128-GCM-SHA256", + "RSA-PSK-AES128-CBC-SHA256", + "RSA-PSK-AES256-CBC-SHA" + ], + "_comment_2": "ellipticCurves not needed", + "signatureAlgorithms" : [ + "Rsa+Sha512", + "Rsa+Sha384", + "Rsa+Sha256", + "Rsa+Sha224" + ] + }, + + "minStaticKeySizes": { + "Rsa": 2000, + "Dsa": 2000, + "Ec": 224 + }, + + "minEphemeralKeySizes": { + "Rsa": 2000, + "Dsa": 1024, + "Ec": 224 + }, + "selfAuthentication": { "_comment_1": "TCTokenURL for self authentication (AusweisAuskunft)", @@ -122,7 +144,7 @@ }, "updates": { - "release": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_APPCAST@/Appcast.xml", - "beta": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_APPCAST_BETA@/Appcast.xml" + "release": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_APPCAST@/Appcast.json", + "beta": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_APPCAST_BETA@/Appcast.json" } } diff --git a/resources/default-providers.json b/resources/default-providers.json index 9f58ef8..a3815a5 100644 --- a/resources/default-providers.json +++ b/resources/default-providers.json @@ -1,565 +1,875 @@ { - "issueDate": "2016-11-07T12:30:00+1:00", + "issueDate": "2017-01-30T13:00:00+1:00", + "callcosts" : [ + { + "prefixes" : ["1371", "1375"], + "landline" : { + "per-call" : 14 + } + }, + { + "prefixes" : ["1372", "1373", "1374", "138"], + "landline" : { + "per-minute" : 14 + } + }, + { + "prefixes" : ["1376"], + "landline" : { + "per-call" : 25 + } + }, + { + "prefixes" : ["1377"], + "landline" : { + "per-call" : 100 + } + }, + { + "prefixes" : ["1378", "1379"], + "landline" : { + "per-call" : 50 + } + }, + { + "prefixes" : ["1801"], + "landline" : { + "per-minute" : 3.9 + }, + "mobile" : { + "per-minute" : 42 + } + }, + { + "prefixes": ["1802"], + "landline" : { + "per-call" : 6 + }, + "mobile" : { + "per-minute" : 42 + } + }, + { + "prefixes" : ["1803"], + "landline" : { + "per-minute" : 9 + }, + "mobile" : { + "per-minute" : 42 + } + }, + { + "prefixes" : ["1804"], + "landline" : { + "per-call" : 20 + }, + "mobile" : { + "per-minute" : 42 + } + }, + { + "prefixes" : ["1805"], + "landline" : { + "per-minute" : 14 + }, + "mobile" : { + "per-minute" : 42 + } + }, + { + "prefixes" : ["1806"], + "landline" : { + "per-call" : 20 + }, + "mobile" : { + "per-call" : 60 + } + }, + { + "prefixes" : ["1807"], + "free-seconds": 30, + "landline" : { + "per-minute" : 14 + }, + "mobile" : { + "per-minute" : 42 + } + } + ], "provider": [ { "shortName": {"" : ":::(bit)kasten"}, + "longDescription": {"": "Der :::(bit)kasten ist ein elektronischer Briefkasten, in dem Sie Ihre Post elektronisch von teilnehmenden Unternehmen und Behörden zum Beispiel Rechnungen, Vertragsunterlagen oder Bescheide sicher und rechtsverbindlich empfangen. Ihre Post erhalten Sie wie bisher anhand Ihrer Postanschrift, nur eben digital. Sie müssen keine persönliche Daten an Dritte herausgeben, Ihre Postadresse reicht für den elektronischen Versand an den :::(bit)kasten aus.
Eine Registrierung für den :::(bit)kasten ist nicht zwingend erforderlich. Ob Sie sich ein Konto anlegen möchten, entscheiden Sie selbst. Nach Login mit Ihrer Online-Ausweisfunktion können Sie Ihre Post abrufen und verwalten.
Da Ihre Post nicht mehr als Papierpost verschickt werden muss, sparen Sie Zeit und senken den Papierverbrauch."}, "address": "https://www.bitkasten.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.bitkasten.de/", + "phone": "+49 911 6000 2874", + "email": "nachricht@bitkasten.de", + "postalAddress": "Wallensteinstr. 63
90431 Nürnberg", "category": "other", - "tcTokenUrl": "https://www.bitkasten.de/portal/api/login/npa/createRequest?returnUrl=https%3A%2F%2Fwww.bitkasten.de%2Fportal%2Fapi%2Flogin%2Fnpa%2Flogin.html" + "tcTokenUrl": "https://www.bitkasten.de/portal/api/login/npa/createRequest?returnUrl=https%3A%2F%2Fwww.bitkasten.de%2Fportal%2Fapi%2Flogin%2Fnpa%2Flogin.html", + "subjectUrls": ["https://www.bitkasten.de"] }, { "shortName": {"" : "Allianz Kundenportal - Meine Allianz"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion im Personalausweis können Sie sich am Kundenportal ,Meine Allianz' nach der Registrierung einfach und sicher anmelden. Auf dem Portal können Sie Ihre Vertragsdaten einsehen und Ihre Versicherung verwalten. Außerdem ist es möglich eine Versicherungsbescheinigung anzufordern oder Ihre persönlichen Daten, z. B. Adresse und Bankverbindung, schnell zu ändern."}, "address": "https://meine.allianz.de", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://meine.allianz.de", + "phone": "+49 800 4520104", + "email": "allianz-versicherungs-ag@allianz.de-mail.de", + "postalAddress": "Königinstraße 28
80802 München", "category": "insurance", "tcTokenUrl": "https://npa.allianz.de/azsecurity-npa-service/NpaEIDService/nparef/XIbOcJDGV0nWcgSIEaN8KA-", - "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway." + "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway.", + "subjectUrls": ["https://npa.allianz.de"] }, { "shortName": {"" : "Allianz Maklerportal"}, "address": "https://makler.allianz.de", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://makler.allianz.de", + "phone": "+49 800/22 23 557 ", + "email": "zviss.makler@allianz.de", + "postalAddress": "Königinstraße 28
80802 München", "category": "insurance", "tcTokenUrl": "https://npa.allianz.de/azsecurity-npa-service/NpaEIDService/nparef/-wnfwSFGamtJotxe6_BKiLj", - "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway." + "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway.", + "subjectUrls": ["https://npa.allianz.de"] }, { "shortName": {"" : "Ausweis Auskunft des Bundes"}, "address": "https://www.buergerserviceportal.de/bund/ausweisapp/bspx_selbstauskunft", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.buergerserviceportal.de/", + "phone": "+49 180-1-33 33 33", + "email": "eID_buergerservice@bmi.bund.de", + "postalAddress": "Bundesministerium des Innern
Alt-Moabit 101 D
10559 Berlin", "category": "citizen", - "tcTokenUrl" : "https://www.buergerserviceportal.de:443/bund/ausweisapp/bspx_selbstauskunft/SamlAuthnRequestProvider" + "tcTokenUrl" : "https://www.buergerserviceportal.de:443/bund/ausweisapp/bspx_selbstauskunft/SamlAuthnRequestProvider", + "subjectUrls": ["https://www.buergerserviceportal.de"] }, { "shortName": {"" : "BAföG Online"}, "address": "https://www.bafoegonline.bva.bund.de/", - "phone": "", + "homepage": "http://www.bafoeg.bund.de/", + "longDescription": {"": "Mit Ihrer Online-Ausweisfunktion können Sie sich beim Bundesverwaltungsamt für das BAföG-Rückzahlungsverfahren anmelden und sowohl Ihre persönlichen Daten als auch die erforderlichen Nachweise sicher und schnell elektronisch übermitteln. Sie müssen die Nachweise nicht mehr per Post senden.
Die Online-Ausweisfunktion vereinfacht und beschleunigt das BAföG-Rückzahlungsverfahren."}, + "phone": "+49 22899358 - 4500", "email": "", - "postalAddress": "", + "postalAddress": "Bundesverwaltungsamt
BT-BAföG
50728 Köln", "category": "citizen", "tcTokenUrl" : "", - "clientUrl" : "https://www.bafoegonline.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeldenMitNpaPreFlow" + "clientUrl" : "https://www.bafoegonline.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeldenMitNpaPreFlow", + "subjectUrls": ["https://e-id.bva.bund.de"] }, { "shortName": {"" : "BAföG Online Bayern (AKDB)"}, + "longDescription": {"": "In Bayern können Sie Ihr BAföG für ein Studium bzw. eine Ausbildung in Bayern, Österreich, Liechtenstein oder der Schweiz nicht nur auf dem Postweg oder durch persönliche Abgabe beim Amt beantragen, sondern auch mit der Online-Ausweisfunktion bequem und schnell im Internet.
Ihr Antrag muss dann nicht mehr ausgedruckt, unterschrieben und versandt werden, sondern gilt mit der Übermittlung Ihrer Daten als wirksam gestellt. Beizufügende und nachzureichende Unterlagen sowie Bescheinigungen können Sie über die Upload-Funktion ebenfalls elektronisch übermitteln.
Nach Übermittlung der Daten wird Ihnen der Antrag als PDF-Dokument zum Download angeboten. Der Bescheid wird Ihnen per Post zugestellt."}, "address": "https://afoegfofa.osrz-akdb.de", - "phone": "", + "homepage": "https://afoegfofa.osrz-akdb.de", + "phone": "+49 89 / 5903 - 0", "email": "", - "postalAddress": "", - "category": "citizen" + "postalAddress": "Anstalt für Kommunale Datenverarbeitung in Bayern (AKDB)
Hansastraße 12-16
80686 München", + "category": "citizen", + "subjectUrls": ["https://www.buergerserviceportal.de"] }, { "shortName": {"" : "BAföG Online Bayern (Studentenwerk)"}, "address": "https://www.bafoeg-bayern.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "https://www.bafoeg-bayern.de", + "phone": "+49 800-223 63 41", + "email": "webmaster@bafoeg-bayern.de", + "postalAddress": "Studentenwerk Niederbayern/Oberpfalz, Anstalt des öffentlichen Rechts
Administration BAföG-Bayern
Albertus-Magnus-Straße 4
93053 Regensburg", + "category": "citizen", + "subjectUrls": [] }, { - "shortName": {"" : "BAföG Online Berlin (Studentenwerk)"}, + "shortName": {"" : "BAföG Online Berlin"}, + "longName": {"" : "BAföG Online Berlin"}, + "shortDescription": {"": "BAföG-Anträge und Formblätter online ausfüllen und unterschreiben."}, + "longDescription": {"": "Sie wollen einen Antrag auf Ausbildungsförderung nach dem BAföG stellen? Mit dem neuen Personalausweis / elektronischen Aufenthaltstitel können Sie Ihren Antrag elektronisch signieren und an das Amt übermitteln. Ebenso können Ihre Eltern und ggf. Ihr Ehepartner die nötigen Formulare signieren."}, "address": "https://www.berlin-bafoeg.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "https://www.berlin-bafoeg.de", + "phone": "+49 30 939 39 - 70", + "email": "info@studentenwerk-berlin.de", + "postalAddress": "Studentenwerk Berlin
Hardenbergstr. 34
10623 Berlin", + "image": "BafoegBerlin_image.jpg", + "icon": "BafoegBerlin_icon.jpg", + "category": "citizen", + "subjectUrls": [] }, { "shortName": {"" : "BAföG Online Brandenburg"}, + "longDescription": {"": "In Brandenburg können Sie Ihr BAföG nicht nur auf dem Postweg oder durch persönliche Abgabe beim Amt beantragen, sondern auch bequem und schnell im Internet.
Ihr Antrag muss dann nicht mehr ausgedruckt, unterschrieben und versandt werden, sondern gilt mit der Übermittlung Ihrer Daten als wirksam gestellt. Beizufügende und nachzureichende Unterlagen sowie Bescheinigungen können Sie über die Upload-Funktion ebenfalls elektronisch übermitteln.
Nach Übermittlung der Daten wird Ihnen der Antrag als PDF-Dokument zum Download angeboten. Der Bescheid wird Ihnen per Post zugestellt."}, "address": "https://www.bafoeg-brandenburg.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "https://www.bafoeg-brandenburg.de", + "phone": "+49 331 / 866 45 60", + "email": "mwfk@mwfk.brandenburg.de", + "postalAddress": "Ministerium für Wissenschaft, Forschung und Kultur
Presse- und Öffentlichkeitsarbeit ", + "category": "citizen", + "subjectUrls": ["https://www.bafoeg-brandenburg.de"] }, { "shortName": {"" : "BAföG Online Hamburg"}, + "longDescription": {"": "In Hamburg können Sie Ihr BAföG nicht nur auf dem Postweg oder durch persönliche Abgabe beim Amt beantragen, sondern auch bequem und schnell im Internet.
Ihr Antrag muss dann nicht mehr ausgedruckt, unterschrieben und versandt werden, sondern gilt mit der Übermittlung Ihrer Daten als wirksam gestellt. Beizufügende und nachzureichende Unterlagen sowie Bescheinigungen können Sie über die neue Upload-Funktion ebenfalls elektronisch übermitteln.
Nach Übermittlung der Daten wird Ihnen der Antrag als PDF-Dokument zum Download angeboten. Der Bescheid wird Ihnen per Post zugestellt."}, "address": "https://bafoeg-online.hamburg.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "https://bafoeg-online.hamburg.de", + "phone": "+49 800-223 63 41", + "email": "Marita.Porr@bwfg.hamburg.de", + "postalAddress": "Ressortleiter Online-Redaktion der Behörde für Wissenschaft, Forschung und Gleichstellung:
Kommunikation
Daniel Drexelius
Hamburger Straße 37
22083 Hamburg", + "category": "citizen", + "subjectUrls": ["https://bafoeg-online.hamburg.de"] }, { "shortName": {"" : "BAföG Online Hessen"}, + "longName": {"" : "BAföG/AFBG Online Hessen"}, + "shortDescription": {"": "BAföG und AFBG Online-Antragstellung Hessen"}, + "longDescription": {"": "Mit Hilfe dieses Angebotes können Antragstellende, Ehegatten / eingetragene Lebenspartner und Eltern die erforderlichen Antragsformblätter online ausfüllen, mit Hilfe der eID rechtswirksam unterschreiben und papierlos dem zuständigen Amt übermitteln."}, "address": "https://www.bafoeg-hessen.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "http://www.hmwk.hessen.de", + "phone": "+49 611 32 - 3551", + "email": "hebav@hmwk.hessen.de", + "postalAddress": "Hessisches Ministerium für Wissenschaft und Kunst
Rheinstraße 23-25
65185 Wiesbaden ", + "image": "BafoegHessen_image.jpg", + "icon": "BafoegHessen_icon.png", + "category": "citizen", + "subjectUrls": ["https://www.bafoeg-hessen.de"] }, { "shortName": {"" : "BAföG Online Mecklenburg-Vorpommern"}, "address": "http://www.bm.regierung-mv.de/bafoeg", + "homepage": "http://www.regierung-mv.de/", "phone": "", "email": "", - "postalAddress": "", - "category": "citizen" + "postalAddress": "Ministerium für Bildung, Wissenschaft und Kultur Mecklenburg-Vorpommern
Werderstraße 124
19055 Schwerin", + "category": "citizen", + "subjectUrls": ["https://fms.mv-regierung.de"] }, { "shortName": {"" : "BAföG Online Nordrhein-Westfalen"}, + "longDescription": {"": "In Nordrhein-Westfalen können Sie mit der Online-Ausweisfunktion Ihren Antrag auf BAföG für eine Ausbildung (Schulausbildung, Studium in Nordrhein-Westfalen sowie Studium in Belgien, den Niederlanden oder Luxemburg) oder Ihren Antrag auf Aufstiegsfortbildungsförderung (z. B. für die Meisterausbildung) in Nordrhein-Westfalen bequem und schnell im Internet stellen.
Ihr Antrag muss dann nicht mehr ausgedruckt, unterschrieben und versandt werden, sondern gilt mit der Übermittlung Ihrer Daten als wirksam gestellt. Beizufügende und nachzureichende Unterlagen sowie Bescheinigungen können Sie über die Upload-Funktion ebenfalls elektronisch übermitteln.
Nach Übermittlung der Daten wird Ihnen der Antrag als PDF-Dokument zum Download angeboten. Der Bescheid wird Ihnen per Post zugestellt."}, "address": "https://www.bafoeg-online.nrw.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "https://www.bafoeg-online.nrw.de", + "phone": "+49 385-588 7145", + "email": "m.boehm@bm.mv-regierung.de", + "postalAddress": "Ministerium für Bildung, Wissenschaft und Kultur Mecklenburg-Vorpommern
Abteilung 1
Referat 140
Werderstraße 124
19055 Schwerin", + "category": "citizen", + "subjectUrls": [] }, { "shortName": {"" : "BAföG Online Schleswig-Holstein"}, + "longDescription": {"": "In Schleswig-Holstein können Sie Ihr BAföG nicht nur auf dem Postweg oder durch persönliche Abgabe beim Amt beantragen, sondern auch bequem und schnell im Internet.
Ihr Antrag muss dann nicht mehr ausgedruckt, unterschrieben und versandt werden, sondern gilt mit der Übermittlung Ihrer Daten als wirksam gestellt. Beizufügende und nachzureichende Unterlagen sowie Bescheinigungen können Sie über die Upload-Funktion ebenfalls elektronisch übermitteln.
Nach Übermittlung der Daten wird Ihnen der Antrag als PDF-Dokument zum Download angeboten. Der Bescheid wird Ihnen per Post zugestellt."}, "address": "https://bafoeg.schleswig-holstein.de/BAfoeGOnline/ABAfoeG/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://bafoeg.schleswig-holstein.de/", + "phone": "+49 431 988-0", + "email": "bafoeg@sozmi.landsh.de", + "postalAddress": "Ministerium für Soziales, Gesundheit, Wissenschaft und Gleichstellung des Landes Schleswig-Holstein
Abteilung VIII 5
Düsternbrooker Weg 104
24105 Kiel", "category": "citizen" }, { "shortName": {"" : "BAföG Online Sachsen"}, - "address": "https://fs.egov.sachsen.de/formserv/findform?shortname=bafoeg&formtecid=11&areashortname=SMWK_bafoeg", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "address": "https://fs.egov.sachsen.de/formserv/findform?shortname=bafoeg&formtecid=11&areashortname=SMWK_bafoeg", + "homepage": "http://www.studieren.sachsen.de/", + "phone": "+49 351 564-1080", + "email": "info@sk.sachsen.de", + "postalAddress": "Sächsische Staatskanzlei
Redaktion Amt24 / Bürgerbüro
01095 Dresden", + "category": "citizen", + "subjectUrls": ["https://fs.egov.sachsen.de"] }, { "shortName": {"" : "Beantragung Schwerbehindertenausweis Bayern"}, + "longDescription": {"": "Einen Schwerbehindertenantrag können Sie bei der Landesbehörde Zentrum Bayern Familie und Soziales (ZBFS) mit der Online-Ausweisfunktion komplett papierlos stellen.
Der papierlose Antrag ist ein bedeutender Schritt auf dem Weg zur digitalen Verwaltung – online, schnell und unkompliziert.
Das Online-Verfahren hat weitere Vorteile. Gerade für sehbehinderte Menschen ist die papiergebundene Schriftform ein Hindernis. Digitale Angebote bieten ihnen die Chance, Behördenangelegenheiten ein Stück weit selbständiger erledigen zu können.
Zu 100 Prozent digital – ein bisschen weniger lästiger Papierkram. Digitalisierung ist somit ein Beitrag zur Inklusion."}, "address": "https://www.schwerbehindertenantrag.bayern.de", - "phone": "", - "email": "", - "postalAddress": "", - "category": "citizen" + "homepage": "http://www.zbfs.bayern.de/", + "phone": "+49 921 605-03", + "email": "poststelle@zbfs.bayern.de", + "postalAddress": "Zentrum Bayern Familie und Soziales
95440 Bayreuth", + "category": "citizen", + "subjectUrls": ["https://www.buergerserviceportal.de"] }, { "shortName": {"" : "Beantragung Schwerbehindertenausweis Saarland"}, + "longDescription": {"": "Als erstes Bundesland bietet Ihnen das Saarland mit Schweb.NET Online die Möglichkeit, Ihren Erst- und Verschlimmerungsantrag auf Feststellung einer Behinderung nach dem Schwerbehindertenrecht online beim Landesamt für Soziales zu stellen.
Weite Wege werden dadurch vermieden. Bearbeitungszeiten und Arbeitsabläufe werden verkürzt.
Der Antrag ist selbsterklärend und nutzerfreundlich. "}, "address": "https://gatewaylas.saarland.de/FV/Onlineantrag", - "phone": "", + "homepage": "http://www.saarland.de/index.htm", + "phone": "+49 681/9978-2181", "email": "", - "postalAddress": "", + "postalAddress": "Ministerium für Soziales, Gesundheit, Frauen und Familie
Franz-Josef-Röder-Straße 23
66119 Saarbrücken", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://tbklas.saarland.de"] }, { "shortName": {"" : "Bundesagentur für Arbeit"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion des Personalausweises können Sie sich bei der Bundesagentur für Arbeit einfach und zuverlässig über Ihr Kindergeld informieren. Die Anwendung bietet u.a. die Möglichkeit:
- sich über den Antragstatus und die Berechnungsgrundlage für den eigenen Kindergeldbezug zu informieren
- Ihre persönlichen Daten online zu ändern, z. B. Ihre Adresse
- für Kunden der Familienkasse Änderungen vollständig papierlos zu übermitteln."}, "address": "https://www.arbeitsagentur.de/npa", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.arbeitsagentur.de/", + "phone": "+49 911/179-0", + "email": "Zentrale@arbeitsagentur.de ", + "postalAddress": "Bundesagentur für Arbeit
Regensburger Straße 104
90478 Nürnberg", "category": "other", "tcTokenUrl" : "", - "clientUrl" : "https://formular.arbeitsagentur.de/eantrag/fallinfo-npa.page" + "clientUrl" : "https://formular.arbeitsagentur.de/eantrag/fallinfo-npa.page", + "subjectUrls": ["https://formular.arbeitsagentur.de"] }, { "shortName": {"" : "Bundestag ePetition"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion des Personalausweises können Sie sich einfach und sicher am Petitionsportal des Deutschen Bundestages
- registrieren,
- eine Petition einreichen sowie
- eine Petition mitzeichnen."}, "address": "https://epetitionen.bundestag.de/epet/anmelden.html", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.bundestag.de/", + "phone": "+49 30 227-35257", + "email": "post.pet@bundestag.de", + "postalAddress": "Sekretariat des Petitionsausschusses
Platz der Republik 1
11011 Berlin", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://epetitionen.bundestag.de"] }, { "shortName": {"" : "Bürgerantrag Bremen"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion können Sie im Bundesland Bremen Bürgeranträge elektronisch mitzeichnen oder Unterschriften für Ihren eigenen Bürgerantrag sammeln. Mit nur 5.000 Mitzeichnerinnen und Mitzeichnern – egal ob online oder auf Papier – können Sie Anträge direkt in den Bremische Bürgerschaft (Landtag) einbringen. Für die Stadtbürgerschaft Bremen genügen sogar 4.000 Unterschriften."}, "address": "https://www.buergerantrag.bremen.de", + "homepage": "http://www.bremische-buergerschaft.de/", "phone": "", - "email": "", + "email": "webmaster@buergerschaft.bremen.de", "postalAddress": "", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://servicekonto.bremen.de"] }, { "shortName": {"" : "Bürgerdienste der Stadt Münster"}, + "longDescription": {"": "Die Stadt Münster bietet auf ihrer Webseite eine Reihe von Online-Diensten an. Dort können Sie mit der Online-Ausweisfunktion unter anderem:
- eine Personenstandsurkunde bestellen,
- Ihr Wunschkennzeichen beantragen,
- geografische Karten bestellen,
- Elektroschrott zur Abholung anmelden,
- eine Erklärung zum Elterneinkommen für die Festsetzung des Elternbeitrags für die Kindertagesbetreuung abgeben,
- eine Sondernutzungserlaubnis für private Baumaßnahmen an öffentlichen Straßen beantragen,
- eine Großanlage mit zentraler Trinkwassererwärmung anzeigen,
- einen Fahrradfund melden,
- ein Reitkennzeichen beantragen,
- Mietspiegel-Broschüren bestellen."}, "address": "http://www.muenster.de/stadt/neuer-personalausweis.html", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.muenster.de/", + "phone": "+49 251/4 92-0", + "email": "stadtverwaltung@stadt-muenster.de", + "postalAddress": "Stadt Münster
48127 Münster", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": [] }, { "shortName": {"" : "Bürgerportal Baden-Württemberg"}, + "longDescription": {"": "Das Bürgerportal ,mein service-bw' bietet Bürgerinnen und Bürgern mit dem Personalausweis praktische Anwendungen für die Online-Ausweisfunktion. Das Portal bietet seinen Nutzern unter anderem:
- sicheres Registrieren und Anmelden, um Behördengänge im Internet zu erledigen
- verschlüsselte Ablage persönlicher Daten und Dateien in einem Datenspeicher im Internet, dem sogenannten Dokumentensafe
- orts- und zeitunabhängiger Zugang zu den Daten im Dokumentensafe sowie die Möglichkeit, diese elektronisch an Behörden weiterzuleiten (z. B. für eine Gewerbeanmeldung)."}, "address": "http://service-bw.de/zfinder-bw-web/welcome.do?showMsbwDetails=1", + "homepage": "https://www.service-bw.de/", "phone": "", - "email": "", - "postalAddress": "", + "email": "service-bw@im.bwl.de", + "postalAddress": "Ministerium für Inneres, Digitalisierung und Migration Baden-Württemberg
Willy-Brandt-Straße 41
70173 Stuttgart", "category": "citizen", - "tcTokenUrlInfo" : "Unable to locate URL" + "tcTokenUrlInfo" : "Unable to locate URL", + "subjectUrls": ["https://eid.service-bw.de"] }, { "shortName": {"" : "Bürgerportal Rheinland Pfalz"}, + "longDescription": {"": "Über 80% der Meldebehörden und über 90% der Standesämter in Rheinland-Pfalz bieten Ihnen über das Portal www.rlpdirekt.de Verwaltungsleistungen mit der Online-Ausweisfunktion an, für die Sie nicht mehr zur Behörde gehen müssen, z. B.:
- Kfz abmelden
- Führungszeugnis beantragen,
- Meldebescheinigung beantragen,
- Aufenthaltsbescheinigung beantragen,
- Übermittlungssperre einrichten,
- Auskunft aus dem Gewerbezentralregister beantragen,
- Beurkundung im Personenstandswesen beantragen.
Welche Dienste in Ihrer Kommune mit der Online-Ausweisfunktion genutzt werden können, erfahren Sie, wenn Sie auf dem Portal unter \"Stadt/Ort\" Ihren Wohnort eingeben."}, "address": "http://www.rlpdirekt.de/rheinland-pfalz", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.rlpdirekt.de/rheinland-pfalz/", + "phone": "+49 6131 / 6277-0", + "email": "support@kommwis.de", + "postalAddress": "KommWis GmbH
Gesellschaft für Kommunikation und Wissenstransfer mbH
Hindenburgplatz 3
55118 Mainz", "category": "citizen", - "tcTokenUrlInfo" : "PLZ required" + "tcTokenUrlInfo" : "PLZ required", + "subjectUrls": [] }, { "shortName": {"" : "Bürgerservice-Portal Kreis Herford"}, + "longName": {"" : "Bürgerservice-Portal Kreis Herford"}, + "shortDescription": {"": "Anträge an die Kreisverwaltung Herford online erfassen."}, + "longDescription": {"": "In unserem Bürgerservice-Portal können Sie Anträge an die Kreisverwaltung Herford online erfassen und direkt zur weiteren Bearbeitung an die zuständigen Stellen übermitteln."}, "address": "https://www.buergerserviceportal.nrw/krz/lkrherford", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.kreis-herford.de/", + "phone": "+49 5223/988 - 500", + "email": "portal@kreis-herford.de", + "postalAddress": "Kreis Herford
Amtshausstraße 3
32051 Herford", + "image": "KreisHerford_image.jpg", + "icon": "KreisHerford_icon.png", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] }, { "shortName": {"" : "Bürgerservice-Portal Kreis Minden-Lübbecke"}, + "longName": {"" : "Bürgerservice-Portal Kreis Minden-Lübbecke"}, + "shortDescription": {"": "Anträge an den Kreis Minden-Lübbecke online erfassen."}, + "longDescription": {"": "In unserem Portal können Sie Ihren Antrag an den Kreis Minden-Lübbecke direkt online erfassen und elektronisch übermitteln."}, "address": "https://www.buergerserviceportal.nrw/krz/mindenluebbecke", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.minden-luebbecke.de/", + "phone": "+49 571 807-0", + "email": "info@minden-luebbecke.de", + "postalAddress": "Kreis Minden-Lübbecke
Portastraße 13
32423 Minden", + "image": "KreisMindenLuebbeke_image.jpg", + "icon": "KreisMindenLuebbeke_icon.png", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] }, { "shortName": {"" : "Bürgerservice-Portal Stadt Lage"}, + "longName": {"" : "Bürgerservice-Portal Stadt Lage"}, + "shortDescription": {"": "Anträge online erfassen und an die Verwaltung weiterleiten."}, + "longDescription": {"": "Das Bürgerservice-Portal bietet die Möglichkeit, Anträge an die Verwaltung der Stadt Lage online zu erfassen und elektronisch zur weiteren Bearbeitung weiterzuleiten."}, "address": "https://www.buergerserviceportal.nrw/krz/lage", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.lage.de/", + "phone": "+49 5232/601300", + "email": "Buergerbuero@lage.de", + "postalAddress": "Bürgerbüro Lage
Bergstraße 21
32791 Lage", + "image": "StadtLage_image.jpg", + "icon": "StadtLage_icon.png", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] }, { "shortName": {"" : "Bürgerservice-Portal Stadt Norderstedt"}, + "longDescription": {"": "In Norderstedt können Sie mit der Online-Ausweisfunktion über das Bürgerservice-Portal folgende Bürgerdienste nutzen:
- Meldebestätigung
- Aufenthaltsbescheinigung
- Übermittlungssperren
- Umzug innerhalb der Stadt
- Voranzeige einer Anmeldung
- Briefwahlunterlagen
- Führungszeugnis
Darüber hinaus können Sie Ihr persönliches Bürgerkonto einrichten. Nach Einrichtung des Bürgerkontos werden die bei einer Nutzung des Bürgerservice-Portals notwendigen persönlichen Daten komfortabel aus Ihrem Bürgerkonto übernommen. Damit sparen Sie Zeit und erleichtern den Behörden die Bearbeitung Ihres Antrags."}, "address": "https://norderstedt.de/digital", - "phone": "", - "email": "", - "postalAddress": "", - "category": "other", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "homepage": "https://www.norderstedt.de/", + "phone": "+49 40 - 535 95-0 ", + "email": "info@norderstedt.de", + "postalAddress": "Stadt Norderstedt
Rathausallee 50
22846 Norderstedt", + "category": "citizen", + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://sh.buergerserviceportal.de"] }, { "shortName": {"" : "Bürgerservice-Portal Wiesbaden"}, + "longDescription": {"": "In Wiesbaden können Sie mit der Online-Ausweisfunktion über das Bürgerservice-Portal
- Briefwahlunterlagen,
- Meldebestätigungen,
- Aufenthaltsbescheinigungen,
- Übermittlungssperren,
- Führungszeugnisse und
- Auskünfte aus dem Gewerbezentralregister beantragen."}, "address": "https://www.buergerserviceportal.de/hessen/wiesbaden", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.wiesbaden.de/", + "phone": "+49 611 / 31 - 8300", + "email": "buergeramt@wiesbaden.de", + "postalAddress": "Postfach 3920
65029 Wiesbaden", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.de"] }, { "shortName": {"" : "Bürgerservice-Portale der bayerischen Kommunen"}, + "longDescription": {"": "Das BayernPortal ist das zentrale Verwaltungsportal für den Freistaat Bayern und die bayerischen Kommunen.
Es bietet Ihnen eine einheitliche Anlaufstelle sowie einen einheitlichen Zugang zu den staatlichen und kommunalen Verwaltungsdienstleistungen in Bayern. Sie erreichen darüber mehr als 150 Online-Dienstleistungen, mehr als 2.000 Fachdatenbanken, über 2.500 Formulare und Merkblätter sowie mehr als 20.000 Ansprechpartnerinnen und Ansprechpartner bei Behörden.
Über das BayernPortal können Sie sich zudem ein Servicekonto einrichten, das BayernID genannt wird und mit dem Sie die Verwaltungsdienstleistungen aller angeschlossenen Kommunen und des Freistaats Bayern einfach und sicher nutzen können. Die Einrichtung Ihrer BayernID und die Anmeldung an diesem persönlichen Servicekonto können Sie auch mit der Online-Ausweisfunktion vornehmen.
Ihre in Ihrem Servicekonto gespeicherten Daten werden automatisch in Ihre Anträge übernommen. Dadurch sparen Sie Zeit und erleichtern der Behörde die Bearbeitung Ihres Anliegens.
In Verbindung mit dem Bayerischen E-Government Gesetz bietet Ihnen die BayernID die Möglichkeit, die in vielen Fällen erforderliche Schriftform zu ersetzen und damit Ihre Anträge ohne handschriftliche Unterschrift, d. h. vollständig online abzuwickeln. Sie müssen nicht mehr zur Behörde gehen oder Unterlagen per Post senden."}, "address": "https://www.buergerserviceportal.de/bayern/classic/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.freistaat.bayern/", + "phone": "+49 (0)89 12 22 20", + "email": "direkt@bayern.de", + "postalAddress": "Postfach 22 00 03
80535 München", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.de"] }, { "shortName": {"" : "CosmosDirekt Kundenportal meinCosmosDirekt"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion des Personalausweises können Sie sich einfach und sicher am Kundenportal ,mein Cosmos-Direkt' registrieren und anmelden. Im Portal haben Sie die Möglichkeit Ihre Versicherungen zu verwalten. Sie können online einen Antrag für ein Tagesgeldkonto stellen oder auch schnell und einfach Ihre persönlichen Daten, z.B. Ihre Adresse, ändern."}, "address": "https://www.cosmosdirekt.de/services/mcd-info", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.cosmosdirekt.de/", + "phone": "+49 681-9 66 68 00", + "email": "info@cosmosdirekt.de", + "postalAddress": "CosmosDirekt
66101 Saarbrücken", + "image": "CosmosDirekt_image.jpg", + "icon": "CosmosDirekt_icon.png", "category": "insurance", - "tcTokenUrl" : "https://www.cosmosdirekt.de/nPa/IdentifizierenNPA?back_url=https://www.cosmosdirekt.de/meincosmosdirekt-registrierung/*ident=1" + "tcTokenUrl" : "https://www.cosmosdirekt.de/nPa/IdentifizierenNPA?back_url=https://www.cosmosdirekt.de/meincosmosdirekt-registrierung/*ident=1", + "subjectUrls": ["https://www.cosmosdirekt.de"] }, { "shortName": {"" : "d.velop – foxdox.de: Dokumente sicher ablegen"}, + "longDescription": {"": "Dokumente, Verträge, Reiseunterlagen, Bilder und vieles mehr können Sie einfach in Ihren persönlichen foxdox-Account hochladen.
Sie melden sich mit der Online-Ausweisfunktion an und können von überall und jederzeit auf Ihre Dokumentenablage zugreifen, z. B. um sie innerhalb der Familie, Ihren Kollegen oder auch Ihrem Steuerberater zur Verfügung zu stellen.
Quittungen und Belege können Sie einfach fotografieren oder scannen, hochladen und sicher in Ihrem foxdox-Account mit übersichtlichem Ordner-System speichern. Eine separate Ablage oder Kopien sind nicht mehr notwendig. Alle Daten liegen sicher und verschlüsselt in einem Rechenzentrum in Deutschland.
Ein Standard-Account ist kostenfrei erhältlich."}, "address": "https://mein.foxdox.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.d-velop.de/foxdox/foxdox-home", + "phone": "+49 (0) 2542 9307-0", + "email": "support@foxdox.de", + "postalAddress": "d.velop business services GmbH
Schildarpstraße 6-8
48712 Gescher", "category": "other", - "tcTokenUrl" : "https://mein.foxdox.de/npa_login?action=gettctoken&next=/documents" + "tcTokenUrl" : "https://mein.foxdox.de/npa_login?action=gettctoken&next=/documents", + "subjectUrls": ["https://mein.foxdox.de"] }, { "shortName": {"" : "Datev - Arbeitnehmer online / Lohn- und Gehaltsabrechnung"}, - "address": "https://www.datev.de/portal/ShowPage.do?pid=ano&nid=159749", - "phone": "", - "email": "", - "postalAddress": "", + "longDescription": {"": "Nach einmaliger Freischaltung durch den Arbeitgeber erhalten Sie Ihren persönlichen Aktivierungscode per Post. Mit dem Aktivierungscode registrieren Sie sich an dem Portal „DATEV Arbeitnehmer online“, dazu können Sie u.a. die Online-Ausweisfunktion nutzen. Danach können Sie jederzeit Ihre Brutto/Netto-Abrechnungen, Sozialversicherungsnachweise und Lohnsteuerbescheinigungen online abrufen. Sie haben dadurch jederzeit und überall einen schnellen Überblick über Ihre gesamten Lohn- und Gehaltsdokumente. "}, + "address": "https://www.datev.de/portal/ShowPage.do?pid=ano&nid=159749", + "homepage": "https://www.datev.de", + "phone": "+49 800 3283825", + "email": "info@datev.de", + "postalAddress": "DATEV eG
90329 Nürnberg", "category": "other", - "tcTokenUrlInfo" : "Address is faulty" + "tcTokenUrlInfo" : "Address is faulty", + "subjectUrls": ["https://secure6.datev.de"] }, { "shortName": {"" : "Deutsche Rentenversicherung"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...
- auf Informationen Ihres Rentenkontos im Kundenbereich ,eService' sicher zugreifen (z. B. Versicherungsverlauf und Beitragsrechnung),
- Ihre Rentenauskunft online abrufen,
- schnell und einfach Ihre persönlichen Daten ändern (z. B. Ihre Adresse und Bankverbindung)."}, "address": "https://www.eservice-drv.de/OnlineDiensteWeb/init.do?npa=true", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.deutsche-rentenversicherung.de/", + "phone": "+49 800 100 048070", + "email": "Online-Dienste@deutsche-rentenversicherung.de", + "postalAddress": "Ruhrstraße 2
10709 Berlin", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." - }, - { - "shortName": {"" : "DKB-Cash - Onlineantrag Konto und Kreditkarte"}, - "address": "http://www.dkb.de/privatkunden/dkb_cash", - "phone": "", - "email": "", - "postalAddress": "", - "category": "finance", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.eservice-drv.de"] }, { "shortName": {"" : "eAntrag der Investitionsbank Berlin (IBB)"}, - "address": "http://www.ibb.de/e_antrag.aspx", - "phone": "", - "email": "", - "postalAddress": "", + "longDescription": {"": "Im Kundenportal der Investitionsbank Berlin können Sie verschiedene Förder-Produkte durchgängig elektronisch beantragen:
- Berlin Kapital
- IBB Familienbaudarlehen
- IBB Wohnraum modernisieren
- KMU-Fonds über 25.000 Euro
- Liquiditätshilfen BERLIN
- Mikrokredit aus dem KMU-Fonds
- Pro FIT (Projektvorschlagsphase)
- Pro FIT (Frühphasenfinanzierung)
Für die rechtsverbindliche, fristwahrende Antragstellung der Produkte
- GRW
- Innovationsassistent
- PFI - Gemeinschaft
- PFI - KMU
- PFI - Netzwerk
- ProFIT (Projektantragsphase)
gilt aus verwaltungsrechtlichen Anforderungen das Schriftformerfordernis: Die elektronische Antragstellung ist zwingend nachträglich schriftlich zu bestätigen.
Mit der Online-Ausweisfunktion können Sie sich bequem und sicher elektronisch legitimieren und müssen dadurch Ihre Identität weder per Postident-Verfahren noch persönlich vor Ort nachweisen.
Nach Ihrer Legitimierung können Sie über eine persönliche Dokumentenablage die rechtsverbindliche Kommunikation mit Ihrem IBB-Ansprechpartner online – und unabhängig von Öffnungszeiten oder Postwegen – über das Kundenportal erledigen."}, + "address": "https://registrierung-eantrag.ibb.de", + "homepage": "http://www.ibb.de/", + "phone": "+49 30 / 2125 - 0", + "email": "info@ibb.de", + "postalAddress": "Investitionsbank Berlin (IBB)
Bundesallee 210
10719 Berlin", "category": "finance", - "tcTokenUrlInfo" : "Registration required." + "tcTokenUrlInfo" : "Registration required.", + "subjectUrls": [] }, { - "shortName": {"" : "easy Login - Der Zugang für Finanz- & Versicherungsvermittler"}, + "shortName": {"" : "easy Login - Der Zugang für Finanz- & Versicherungsvermittler"}, "address": "http://www.easy-login.de", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.easy-login.de", + "phone": "+49 921 75758-555", + "email": "info@easy-login.de", + "postalAddress": "easy Login GmbH
Bindlacher Str. 4
95448 Bayreuth", "category": "insurance", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://easy-login.vdg-portal.de"] }, { "shortName": {"" : "ElsterOnline-Portal"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion des Personalausweises können Sie Ihre Steuererklärung online ausfüllen und abgeben sowie verschiedene weitere Dienste nutzen, z. B. den elektronischen Einspruch oder die Auskunft über die Elektronischen Lohnsteuerabzugsmerkmale.
Für die Registrierung im ElsterOnline-Portal wird Ihre Identität anhand Ihres Personalausweises überprüft. Sie müssen nicht mehr auf den Aktivierungsbrief warten. Die Registrierung kann innerhalb weniger Minuten abgeschlossen werden. Dadurch wird die Registrierung erheblich beschleunigt und vereinfacht."}, "address": "https://www.elsteronline.de", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.elsteronline.de", + "phone": "+49 800 52 35 055", + "email": "hotline@elster.de", + "postalAddress": "Bayerisches Landesamt für Steuern - Dienststelle München
80284 München", "category": "citizen", - "tcTokenUrlInfo" : "Registration required." + "tcTokenUrlInfo" : "Registration required.", + "subjectUrls": [] }, { "shortName": {"" : "Einheitlicher Ansprechpartner Köln"}, "address": "http://www.einheitlicher-ansprechpartner-koeln.de/eaportal/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.stadt-koeln.de/", + "phone": "+49 221 / 221-0", + "email": "stadtverwaltung@stadt-koeln.de", + "postalAddress": "Stadt Köln
Die Oberbürgermeisterin
Henriette Reker
Historisches Rathaus
50667 Köln-Innenstadt", "category": "other", - "tcTokenUrl" : "https://ea.stadt-koeln.de/Gastzugang/EIDServiceProvider/Request.ashx?appID=6" + "tcTokenUrl" : "https://ea.stadt-koeln.de/Gastzugang/EIDServiceProvider/Request.ashx?appID=6", + "subjectUrls": [] }, { "shortName": {"" : "ERGO Direkt Lebensversicherung AG"}, "address": "https://ergodirekt.de/de/persoenlicherbereich.html#login", - "phone": "", - "email": "", - "postalAddress": "", - "category": "insurance" + "homepage": "https://ergodirekt.de", + "phone": "+49 800 / 444 1000", + "email": "beratung@ergodirekt.de", + "postalAddress": "Karl-Martell-Straße 60
90344 Nürnberg", + "category": "insurance", + "subjectUrls": ["https://ergodirekt.de"] }, { "shortName": {"" : "Feinstaubplakette beantragen"}, + "longDescription": {"": "In Berlin können Sie eine Feinstaubplakette für alle Kraftfahrzeuge mit der Online-Ausweisfunktion beantragen. Der Antrag ist unabhängig davon, ob Ihr Fahrzeug in Berlin, bei einer anderen deutschen Zulassungsbehörde, oder im Ausland zugelassen ist.
Ihre persönlichen Daten werden verschlüsselt übertragen. Sie müssen Ihre Angaben nicht per Hand eingeben und die Behörde erhält zuverlässig korrekte Informationen, die rasch weiterverarbeitet werden können.
Auf der Internet-Seite Umweltzonen und Feinstaubplaketten der Senatsverwaltung für Stadtentwicklung und Umwelt können Sie sich vorab informieren, welche Plakette Ihrem Fahrzeug zugeteilt werden kann."}, "address": "http://www.berlin.de/labo/fahrzeuge/kfz-zulassung/feinstaubplakette/shop.85047.php", - "phone": "", + "homepage": "https://www.berlin.de", + "phone": "+49 30 90269 – 0", "email": "", - "postalAddress": "", + "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", "category": "other", - "tcTokenUrlInfo" : "Car lizence number required" + "tcTokenUrlInfo" : "Car lizence number required", + "subjectUrls": [] }, { "shortName": {"" : "Führungszeugnis und Auskunft aus dem Gewerbezentralregister"}, + "longDescription": {"": "Sie benötigen ein Führungszeugnis oder eine Auskunft aus dem Gewerbezentralregister? Mit dem Personalausweis im Scheckkartenformat können Sie einen Behördengang sparen. Weitere Voraussetzungen sind die freigeschaltete Online-Ausweisfunktion und ein passendes Kartenlesegerät für Ihren Computer. Auf diese Weise kann eindeutig identifiziert werden, wer den Antrag stellt. Ausländische Mitbürger, die keinen deutschen Personalausweis besitzen, können in gleicher Weise die entsprechende Funktion ihres elektronischen Aufenthaltstitels nutzen.
Neben Führungszeugnissen können auch Auskünfte aus dem Gewerbezentralregister über das neue Online-Portal des BfJ beantragt werden. Solche Auskünfte benötigen Unternehmen, die sich in Ausschreibungsverfahren um öffentliche Aufträge bewerben, recht häufig. Auch hier kann das Online-Verfahren den Aufwand erheblich senken."}, "address": "https://www.fuehrungszeugnis.bund.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.bundesjustizamt.de", + "phone": "+49 228 99 410-40", + "email": "poststelle@bfj.bund.de", + "postalAddress": "Bundesamt für Justiz
53094 Bonn", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.fuehrungszeugnis.bund.de/ffw"] }, { "shortName": {"" : "Halterauskunft zu einem KFZ beantragen"}, + "longDescription": {"": "In Berlin können Sie für Fahrzeuge, die bei der Zulassungsbehörde Berlin registriert sind, mit der Online-Ausweisfunktion eine Halterauskunft beantragen.
Ihre persönlichen Daten werden verschlüsselt übertragen. Sie müssen Ihre Angaben nicht per Hand eingeben und die Behörde erhält zuverlässig korrekte Informationen, die rasch weiterverarbeitet werden können.
Bitte beachten Sie, dass eine Halterauskunft nur erteilt werden kann, wenn diese der Geltendmachung oder Abwehr von Rechtsansprüchen dient, die sich aus der Teilnahme am Straßenverkehr ergeben, oder wenn sie zur Erhebung einer Privatklage aufgrund im Straßenverkehr begangener Verstöße benötigt wird."}, "address": "https://www.berlin.de/labo/mobilitaet/kfz-zulassung/halterauskunft/shop.86598.php", - "phone": "", + "homepage": "https://www.berlin.de", + "phone": "+49 30 90269 – 0", "email": "", - "postalAddress": "", + "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", "category": "other", - "tcTokenUrlInfo" : "Car lizence number required." + "tcTokenUrlInfo" : "Car lizence number required.", + "subjectUrls": [] }, { "shortName": {"" : "Hamburg Service Online-Bürgerdienste"}, + "longDescription": {"": "Über das Portal ,HamburgService' finden Sie auf einen Blick alle Online-Dienste der Freien und Hansestadt Hamburg. Für die Dienste, die mit sensiblen Daten arbeiten (Dienste der Sicherheitsstufe 2), müssen Sie sich nach der Registrierung einmalig identifizieren. Sie können dazu die Online-Ausweisfunktion Ihres Personalausweises nutzen. Eine persönliche Identifizierung in einem Kundenzentrum der Stadt Hamburg ist dann nicht mehr nötig."}, "address": "https://gateway.hamburg.de/HamburgGateway/FVP/Application/Index.aspx", + "homepage": "http://www.hamburg.de/", "phone": "", - "email": "", - "postalAddress": "", + "email": "dataporthamburggateway-service@dataport.de", + "postalAddress": "Bürgermeister Olaf Scholz
Rathausmarkt 1
20095 Hamburg", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://gateway.hamburg.de"] }, { "shortName": {"" : "HUK 24 AG - Registrierung für Servicebereich \"Meine HUK24\""}, + "longDescription": {"": "Die Registrierung am Kundenportal ,Meine HUK24' können Sie mit der Online-Ausweisfunktion im Personalausweis schnell und einfach selbst erledigen. Ihre Versicherung lässt sich damit komplett online verwalten: egal, ob Sie einen Vertrag abändern eine neue Versicherung abschließen, oder Ihre persönlichen Daten aktualisieren möchten – mit dem Personalausweis können Sie alles problemlos von Zuhause aus erledigen."}, "address": "https://www.huk24.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.huk24.de/", + "phone": "+49 95 61/96-13 38", + "email": "info@huk24.de", + "postalAddress": "HUK24 AG
Willi-Hussong-Str. 2
96440 Coburg", "category": "insurance", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.huk24.de"] }, { "shortName": {"" : "ID-Safe des Landkreis Kitzingen"}, + "longDescription": {"": "Die Stadt Kitzingen bietet bei verschiedenen Bürgerdiensten die Nutzung der Online-Ausweisfunktion in Verbindung mit elektronischen Antragsformularen an:
- Gewerbeanmeldung
- Gewerbeummeldung
- Gewerbeabmeldung
- Fischereischein
- Verkehrsrechtliche Anordnung
- Sondernutzung
- Parkerleichterung
- Mängelmeldung"}, "address": "https://www.buergerservice.org/ID-Safe-Kitzingen", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.kitzingen.de/", + "phone": "+49 9321 / 928-0,", + "email": "info@kitzingen.de", + "postalAddress": "Landratsamt Kitzingen
Herr Thomas Langhojer
Kaiserstraße 4
97318 Kitzingen", "category": "citizen", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.buergerservice.org"] }, { "shortName": {"" : "ID-Safe des Landkreis Ostallgäu"}, + "longDescription": {"": "Der Landkreis Ostallgäu bietet Ihnen bei verschiedenen Bürgerdiensten die Nutzung der Online-Ausweisfunktion in Verbindung mit elektronischen Antragsformularen an:
- Bauantrag digital
- Sperrmüll-Abholung
- An-, Um- oder Abmeldung einer Abfalltonne
- Antrag auf Dauergenehmigung und Feriengenehmigung für ein Segelboot oder Motorboot auf dem Forggensee
Der Landkreis Ostallgäu bietet Ihnen außerdem einen ID-Safe an. Hier können Sie die Daten aus Ihrer Online-Ausweisfunktion hinterlegen und um weitere Kontaktdaten ergänzen. Anschließend können Sie die elektronischen Antragsformulare des Landkreises automatisch mit Ihren hinterlegten Daten befüllen. Dadurch vermeiden Sie Tippfehler und können die Bearbeitung Ihres Vorgangs beschleunigen.
Darüber hinaus können Sie im Landkreis Ostallgäu über das bayerische Bürgerservice-Portal folgende Bürgerdienste online beantragen:
- Fahrzeug-Anmeldung
- Fahrzeug-Abmeldung
- Feinstaubplakette
- Wunschkennzeichen"}, "address": "https://www.sixform.com/ID-safe", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.landkreis-ostallgaeu.de/", + "phone": "+49 83 42 · 9 11 - 0", + "email": "poststelle@lra-oal.bayern.de", + "postalAddress": "Landkreis Ostallgäu
Schwabenstraße 11
87616 Marktoberdorf", "category": "citizen", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.sixform.com"] }, { "shortName": {"" : "ID-Safe des Landkreis Würzburg"}, "address": "https://www.buergerservice.org/ID-Safe-Wuerzburg", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.landkreis-wuerzburg.de/startseite.phtml", + "phone": "+49 931 8003-0 ", + "email": "poststelle@lra-wue.bayern.de", + "postalAddress": "Landratsamt Würzburg
Zeppelinstraße 15
97074 Würzburg", "category": "citizen", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.buergerservice.org"] }, { "shortName": {"" : "Identitätsprüfungen nach dem Signaturgesetz und dem Geldwäschegesetz"}, + "longDescription": {"": "Die identity Trust Management AG bietet Unternehmen die Möglichkeit, ihre Kunden schnell und sicher mit der Online-Ausweisfunktion zu identifizieren.
Kunden der Kooperationspartner der identity Trust Management AG können die Identitätsprüfung nach dem Signaturgesetz und dem Geldwäschegesetz auch direkt über die Internetseite der identity Trust Management AG vornehmen."}, "address": "https://www.identity.tm", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.identity.tm", + "phone": "+49 211 68 77 3-0", + "email": "kontakt@identity.tm", + "postalAddress": "identity Trust Management AG
Lierenfelder Straße 51
40231 Düsseldorf", "category": "other", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": [] }, { "shortName": {"" : "Kraftfahrt-Bundesamt - Auskunft aus dem Verkehrszentralregister"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion können Sie beim Kraftfahrt-Bundesamt einfach und schnell eine Auskunft über Ihren Punktestand und die zu Ihrer Person gespeicherten Eintragungen im Fahreignungsregister (FAER) beantragen. Dazu müssen Sie Ihr Kartenlesegerät an Ihrem Computer anschließen und die AusweisApp2 installiert und gestartet haben. Die erforderlichen Daten werden dann von Ihrem Personalausweis ausgelesen. Die Auskunft erhalten Sie innerhalb weniger Tage per Post."}, "address": "https://www.kba-online.de/faeronline/faeranfrage.do", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.kba.de/", + "phone": "+49 461 316-0", + "email": "poststelle@kba.de-mail.de", + "postalAddress": "Kraftfahrt-Bundesamt
Fördestraße 16
24944 Flensburg", "category": "citizen", "tcTokenUrl" : "https://www.kba-online.de:443/faeronline/eidstart.do;jsessionid=vG0b7cExL-p+rDGAQx+aG152.as-idmz-prod1:P_faeronline?ref=vG0b7cExL-p+rDGAQx+aG152.as-idmz-prod1:P_faeronline", - "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway." + "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway.", + "subjectUrls": ["https://www.kba-online.de/faeronline"] }, { "shortName": {"" : "Login Meine VBL"}, + "longDescription": {"": "Bei der VBL können Sie sich mit dem Personalausweis am Kundenportal ,Meine VBL' registrieren und anmelden. Dadurch entfällt der Postversand eines Freischaltcodes - Sie sparen Zeit. Im Kundenkonto können Sie Ihre Vertragsdaten und Ihre persönlichen Daten einsehen und weitere Online-Dienste nutzen, z. B.
- Rentenantrag stellen,
- Beitragserstattung beantragen,
- Kontaktdaten ändern,
- persönliche Mitteilungen von der VBL erhalten."}, "address": "https://vbl.de/de/meine_vbl", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://vbl.de/", + "phone": "+49 721 93 98 93 1", + "email": "info@vbl.de", + "postalAddress": "VBL. Kundenservice
76240 Karlsruhe", "category": "other", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.vbl.de"] }, { "shortName": {"" : "LVM Versicherung - Kundenportal Meine LVM"}, + "longDescription": {"": "Mit der Online-Ausweisfunktion im Personalausweis können Sie sich nach der Registrierung durch Ihre LVM-Agentur sicher am Kundenportal ,Meine LVM' anmelden. Ihre Versicherung können Sie nun selbst verwalten und beispielsweise sämtliche Vertragsdaten online einsehen. Darüber hinaus ist es möglich über das Portal Versicherungsbescheinigungen anzufordern sowie schnell und einfach Ihre persönlichen Daten wie Adresse oder Bankverbindung zu ändern."}, "address": "http://www.lvm.de/personalausweis", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.lvm.de/", + "phone": "+49 251 702-0", + "email": "info@lvm.de", + "postalAddress": "LVM Versicherung
48126 Münster", "category": "insurance", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.lvm.de"] }, { "shortName": {"" : "Mentana-Claimsoft AG - Registrierung beim De-Mail Dienst"}, "address": "https://www.fp-demail.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.fp-demail.de/", + "phone": "+49 800-6368262", + "email": "de-mail.info@mentana.de", + "postalAddress": "Mentana-Claimsoft GmbH
Trebuser-Str. 47 Haus 1
D-15517 Fürstenwalde", "category": "other", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.fp-demail.de"] }, { "shortName": {"" : "OpenPGP-eID"}, + "longDescription": {"": "Durch die Verschlüsselung Ihrer Nachrichten mittels OpenPGP ist die Vertraulichkeit Ihrer Information gewährleistet. Aber kann ein Empfänger der Nachricht sicher sein, dass der Absender der ist, der er vorgibt zu sein? Die Antwortet lautet: Nein. Abhilfe schafft die Beglaubigung Ihres OpenPGP-Schlüssels durch eine Signatur. Sie benötigen hierfür einen Personalausweis bzw. elektronischen Aufenthaltstitel mit aktivierter Online-Ausweisfunktion. Diesen Dienst stellen wir im Auftrag des Bundesamtes für Sicherheit in der Informationstechnik (BSI) zur Verfügung."}, "address": "https://pgp.governikus-eid.de/pgp/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.governikus.de/", + "phone": "+49 421 204 95-0", + "email": "kontakt@governikus.com", + "postalAddress": "Governikus GmbH & Co. KG
Am Fallturm 9
28359 Bremen", "category": "other", - "tcTokenUrl" : "https://pgp.governikus-eid.de/pgp/EIDRequest" + "tcTokenUrl" : "https://pgp.governikus-eid.de/pgp/EIDRequest", + "subjectUrls": ["https://pgp.governikus-eid.de"] }, { "shortName": {"" : "Registrierung/Login auf www.tk.de"}, + "longDescription": {"": "Die Online-Ausweisfunktion des Personalausweises ermöglicht Ihnen die schnelle und sichere Registrierung am Kundenportal \"Meine TK\". Damit können Sie online verbindlich Anträge stellen und Ihre Unterlagen anfordern (z. B. eine neue Versichertenkarte). Außerdem lassen sich persönliche Daten wie Kontoverbindung oder Adresse selbstständig ändern und verwalten. Wenn Sie \"Meine TK\" mit der Online-Ausweisfunktion nutzen, sparen Sie Zeit und Aufwand."}, "address": "https://www.tk.de/tk/online-filiale/meine-tk/meine-tk/118032", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.tk.de/", + "phone": "+49 800 - 285 85 85", + "email": "service@tk.de", + "postalAddress": "Techniker Krankenkasse
Bramfelder Straße 140
22305 Hamburg", "category": "other", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.tk.de"] }, { "shortName": {"" : "Schufa – Auskunftsportal „Meine SCHUFA“"}, + "longDescription": {"": "Wenn Sie Ihre Bonität gegenüber Dritten z. B. für einen Mietvertrag, belegen müssen, benötigen Sie dazu in der Regel eine SCHUFA-Auskunft. Mit der Online-Ausweisfunktion können Sie sich einfach und sicher am Kundenportal „MeineSCHUFA“ registrieren. Ohne weitere Verzögerungen haben Sie nach Anmeldung am Portal die Möglichkeit Ihre Schufa-Auskunft direkt online abzurufen oder auf dem Postweg Ihren Geschäftspartnern zukommen zu lassen. Der Personalausweis erspart Ihnen hierbei unnötige Wartezeit und gewährleistet dennoch eine verlässliche Identifizierung."}, "address": "https://www.meineschufa.de/index.php?site=30_2_1_pa#tabNPA", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.meineschufa.de", + "phone": "+49 611 – 92780", + "email": "meineSCHUFA@SCHUFA.de", + "postalAddress": "SCHUFA Holding AG
Postfach 10 25 66
44725 Bochum", "category": "citizen", - "tcTokenUrl" : "https://www.meineschufa.de/eID-Service-Connector-V2/createSamlRequest/Reg" + "tcTokenUrl" : "https://www.meineschufa.de/eID-Service-Connector-V2/createSamlRequest/Reg", + "subjectUrls": ["https://www.meineschufa.de"] + }, + { + "shortName": {"" : "Selbstauskunft - „Meine Daten einsehen“"}, + "longDescription": {"": "Die AusweisApp2 verfügt über die Funktion \"Meine Daten einsehen\". Mit dieser Funktion können die auf dem Personalausweis bzw. dem elektronischen Aufenthaltstitel gespeicherten Daten ausgelesen und angezeigt werden.
Sobald Sie die AusweisApp2 gestartet und ein geeignetes Kartenlesegerät angeschlossen haben, können Sie diese Funktion unter dem Menüpunkt \"Ausweisen\" aufrufen. Über voreingestellte Checkboxen können Sie steuern, ob Sie alle gespeicherten Daten oder nur spezielle Daten auslesen möchten.
Nach Ihrer PIN-Eingabe und erfolgreicher Datenübertragung werden die von Ihnen festgelegten Daten in der AusweisApp2 dargestellt.
Bitte beachten Sie, dass Sie für diesen Vorgang eine Internetverbindung benötigen. Dies hat folgenden Hintergrund: Für jedes Auslesen der Daten aus dem Personalausweis oder dem elektronischen Aufenthaltstitel muss gesetzlich der Zweck des Auslesevorgangs angegeben werden. Dieser Zweck wird Ihnen auf einem speziellen Zertifikat angezeigt (Berechtigungszertifikat). Diese Zertifikate werden individuell durch die Vergabestelle für Berechtigungszertifikate beim Bundesverwaltungsamt genehmigt. Damit Sie also jederzeit genau wissen, wer zu welchem Zweck einen Auslesevorgang startet, wird eine Internetverbindung zu einem vertrauenswürdigen Authentisierungsserver aufgebaut. Die Berechtigungszertifikate dienen Ihrem Schutz!"}, + "address": "https://www.ausweisapp.bund.de/ausprobieren/ausweisauskunft/", + "homepage": "https://www.ausweisapp.bund.de/", + "phone": "+49 1805 - 348743", + "email": "support@ausweisapp.de", + "postalAddress": "Governikus GmbH & Co. KG
- im Auftrag des Bundesministeriums des Innern -
Am Fallturm 9
D-28359 Bremen", + "image": "Selbstauskunft.jpg", + "icon": "npa.svg", + "category": "citizen", + "tcTokenUrlInfo" : "https://www.autentapp.de/AusweisAuskunft/WebServiceRequesterServlet?mode=xml", + "subjectUrls": ["https://www.autentapp.de"] }, { "shortName": {"" : "Service-Portal \"Auto\" Kreis Lippe"}, + "longName": {"" : "Service-Portal \"Auto\" Kreis Lippe"}, + "shortDescription": {"": "Das Service-Portal bietet Online-Dienste rund um die KFZ-Zulassung."}, + "longDescription": {"": "Im Service-Portal \"Auto\" können Sie Ihr Auto online abmelden. Weitere Angebote wie die komplette online KFZ-Wiederzulassung und -Zulassung sind im Aufbau."}, "address": "https://www.buergerserviceportal.nrw/krz/lkrlippe", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.kreis-lippe.de/", + "phone": "+49 5231/62-0", + "email": "stva@kreis-lippe.de", + "postalAddress": "Kreis Lippe
Felix-Fechenbach-Straße 5
32756 Detmold", + "image": "KreisLippe_image.jpg", + "icon": "KreisLippe_icon.png", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] }, { "shortName": {"" : "sign-me (Bundesdruckerei)"}, "address": "https://live.esign-service.de/esign/start", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://live.esign-service.de/esign/start", + "phone": "+49 30 2598 0", + "email": "support@d-trust.net", + "postalAddress": "Bundesdruckerei GmbH
Kommandantenstr. 18
10969 Berlin", "category": "other", - "tcTokenUrlInfo" : "Website enforces Java plugin :)" + "tcTokenUrlInfo" : "Website enforces Java plugin :)", + "subjectUrls": [] }, { "shortName": {"" : "SkIDentity Service"}, "address": "https://skidentity.de/service", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.skidentity.de", + "phone": "+49 9571 89 64 79", + "email": "skidentity@ecsec.de", + "postalAddress": "Sudetenstraße 16
96247 Michelau", "category": "other", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": [] }, { "shortName": {"" : "Stadt Nürnberg: Online-Bürgerdienste Service"}, + "longDescription": {"": "Die Stadt Nürnberg bietet Ihnen mit ihrem Bürgerserviceportal ,Mein.Nürnberg' erstmals die Möglichkeit, Ihre Verwaltungsangelegenheiten komplett elektronisch abzuwickeln – von der Antragstellung bis zur Rückmeldung der Bescheide oder Schriftstücke in Ihren persönlichen Bereich auf dem Portal. Alle Online-Dienste der Stadt Nürnberg wurden zudem für die Nutzung mit mobilen Endgeräten optimiert.
Bei immer mehr Verfahren akzeptiert die Stadtverwaltung einen Unterschriftersatz durch die Online-Ausweisfunktion.
Jeder Online-Dienst der Stadt Nürnberg, der die Online-Ausweisfunktion nutzt, ist an dem Hinweis \"mit eID\" erkennbar. Derzeit sind dies z. B.:
- Aufenthaltstitel beantragen
- Gaststättenrechtliche Erlaubnis für den Ausschank von Alkohol beantragen
- Hunde – Negativzeugnis für Kampfhunde beantragen
- Kfz-Halterauskunft beantragen
- Melderegister – Widerspruch gegen Datenübermittlung
- Veranstaltung, Messe, Markt beantragen"}, "address": "http://www.nuernberg.de/internet/onlinedienste", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.nuernberg.de/", + "phone": "+49 9 11 / 2 31-8613", + "email": "poststelle@stadt.nuernberg.de", + "postalAddress": "Amt für Organisation, Informationsverarbeitung und Zentrale Dienste
E-Government-Büro
Rathausplatz 2
III. OG
90403 Nürnberg", "category": "citizen", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://meinkonto.nuernberg.de"] }, { "shortName": {"" : "Standesamt Online Mecklenburg-Vorpommern"}, + "longDescription": {"": "In Mecklenburg-Vorpommern können Sie in immer mehr Kommunen Urkunden mit der Online-Ausweisfunktion beantragen:
- Geburtsurkunden
- Eheurkunden
- Lebenspartnerschaftsurkunden
- Sterbeurkunden"}, "address": "https://portal.ego-mv.de/", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.ego-mv.de/", + "phone": "+49 3 85 77 33 47-0", + "email": "info@ego-mv.de", + "postalAddress": "Zweckverband Elektronische Verwaltung in Mecklenburg-Vorpommern (eGo-MV)
Eckdrift 103
19061 Schwerin", "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id." + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://tbk.ego-mv.de/BuergerKontoWeb"] }, { "shortName": {"" : "Telekom DeMail für Privat- und Geschäftskunden"}, "address": "https://www.telekom.de/de-mail", - "phone": "", + "homepage": "https://www.telekom.de/", + "phone": "+49 800 33 01000", "email": "", - "postalAddress": "", + "postalAddress": "Telekom Deutschland GmbH
Landgrabenweg 151
53227 Bonn", "category": "other", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.de-mail.t-online.de"] }, { "shortName": {"" : "T-Systems DeMail für Großkunden"}, "address": "https://www.t-systems.de/de-mail", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "https://www.t-systems.de/", + "phone": "+49 69 20060 - 0", + "email": "de-mail@t-systems.com", + "postalAddress": "T-Systems International GmbH
Hahnstraße 43d
60528 Frankfurt am Main", "category": "other", - "tcTokenUrlInfo" : "Registration required" + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.de-mail.t-systems.de"] }, { "shortName": {"" : "Urkundenservice Köln"}, + "longDescription": {"": "Bei der Stadt Köln können Sie mit der Online-Ausweisfunktion folgende Urkunden beantragen:
- Geburtsurkunden
- Eheurkunden
- Lebenspartnerschaftsurkunden
- Sterbeurkunden
Dabei werden die Adressatenangaben in den Online-Formularen automatisch befüllt."}, "address": "http://www.stadt-koeln.de/service/produkt/urkundenservice-des-standesamtes", - "phone": "", - "email": "", - "postalAddress": "", + "homepage": "http://www.stadt-koeln.de/", + "phone": "+49 221 / 221-26530", + "email": "standesamt@stadt-koeln.de", + "postalAddress": "Gülichplatz 1-3
50667 Köln", "category": "citizen", - "tcTokenUrl" : "https://ea.stadt-koeln.de/Gastzugang/EIDServiceProvider/Request.ashx?appID=7" + "tcTokenUrl" : "https://ea.stadt-koeln.de/Gastzugang/EIDServiceProvider/Request.ashx?appID=7", + "subjectUrls": ["https://ea.stadt-koeln.de"] + }, + { + "shortName": {"" : "Virtuelles Rathaus Stadt Dortmund"}, + "longDescription": {"": "Sie wollen städtische Dienstleistungen in Anspruch nehmen, sich zunächst nur informieren oder Sie suchen bereits ein bestimmtes Formular?
Wir haben für Sie ein umfassendes Informationsangebot über Produkte und Leistungen (Services) der Stadt Dortmund gegliedert nach Themen und der Behördenstruktur bereitgestellt."}, + "address": "https://www.domap.de/wps/portal/dortmund/login", + "homepage": "https://www.domap.de/", + "phone": "+49 231 / 50-25650", + "email": "domap-feedback@stadtdo.de", + "postalAddress": "Stadt Dortmund
Dortmunder Systemhaus
Deggingstraße 42
44122 Dortmund", + "category": "citizen", + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://rathaus.dortmund.de"] } ] } diff --git a/resources/images/All.png b/resources/images/All.png deleted file mode 100644 index b53ec70..0000000 Binary files a/resources/images/All.png and /dev/null differ diff --git a/resources/images/AusweisApp_2_Logo.svg b/resources/images/AusweisApp_2_Logo.svg index b584b8a..fb5a615 100644 --- a/resources/images/AusweisApp_2_Logo.svg +++ b/resources/images/AusweisApp_2_Logo.svg @@ -1,42 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - +I7//2Q==" transform="matrix(0.0666 0 0 -0.0666 4.8438 34.1055)"> + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Un7/AG+/fz/Nv//Z" transform="matrix(0.0666 0 0 -0.0666 18.7666 34.1055)"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/Icon_Checked.svg b/resources/images/Icon_Checked.svg index 2c82fcd..44b1045 100644 --- a/resources/images/Icon_Checked.svg +++ b/resources/images/Icon_Checked.svg @@ -1,10 +1,9 @@ - - - - - - - + + + + + + diff --git a/resources/images/android/android_arrow_back.svg b/resources/images/android/android_arrow_back.svg index 02edd34..67c0a0e 100644 --- a/resources/images/android/android_arrow_back.svg +++ b/resources/images/android/android_arrow_back.svg @@ -1,7 +1,6 @@ - - - - - - + + + + + diff --git a/resources/images/android/android_arrow_back_white.svg b/resources/images/android/android_arrow_back_white.svg index d27f07e..9b1cf74 100644 --- a/resources/images/android/android_arrow_back_white.svg +++ b/resources/images/android/android_arrow_back_white.svg @@ -1,7 +1,6 @@ - - - - - - + + + + + diff --git a/resources/images/android/android_nav_button_icon_history.svg b/resources/images/android/android_nav_button_icon_history.svg index c09ef0e..68c9f08 100644 --- a/resources/images/android/android_nav_button_icon_history.svg +++ b/resources/images/android/android_nav_button_icon_history.svg @@ -1,65 +1,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/android/android_nav_button_icon_identify.svg b/resources/images/android/android_nav_button_icon_identify.svg index 9d11a87..73a1890 100644 --- a/resources/images/android/android_nav_button_icon_identify.svg +++ b/resources/images/android/android_nav_button_icon_identify.svg @@ -1,64 +1,63 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/android/android_nav_button_icon_provider.svg b/resources/images/android/android_nav_button_icon_provider.svg index 8ecbc85..9d0ee0c 100644 --- a/resources/images/android/android_nav_button_icon_provider.svg +++ b/resources/images/android/android_nav_button_icon_provider.svg @@ -1,65 +1,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/android/android_nav_button_icon_settings.svg b/resources/images/android/android_nav_button_icon_settings.svg index 72ce66b..752d582 100644 --- a/resources/images/android/android_nav_button_icon_settings.svg +++ b/resources/images/android/android_nav_button_icon_settings.svg @@ -1,65 +1,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/android/android_search_icon.svg b/resources/images/android/android_search_icon.svg deleted file mode 100644 index fbb02bc..0000000 --- a/resources/images/android/android_search_icon.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/android/arrowLeft.svg b/resources/images/android/arrowLeft.svg index b422d07..028c9f2 100644 --- a/resources/images/android/arrowLeft.svg +++ b/resources/images/android/arrowLeft.svg @@ -1,11 +1,10 @@ - - - - - - - - - + + + + + + + + diff --git a/resources/images/android/arrowLeftWhite.svg b/resources/images/android/arrowLeftWhite.svg index db00bc1..eaa3030 100644 --- a/resources/images/android/arrowLeftWhite.svg +++ b/resources/images/android/arrowLeftWhite.svg @@ -1,12 +1,11 @@ - - - - - - - - - + + + + + + + + diff --git a/resources/images/android/arrowRight.svg b/resources/images/android/arrowRight.svg index 4cdfe9d..cfd991f 100644 --- a/resources/images/android/arrowRight.svg +++ b/resources/images/android/arrowRight.svg @@ -1,11 +1,10 @@ - - - - - - - - - + + + + + + + + diff --git a/resources/images/android/arrowRightWhite.svg b/resources/images/android/arrowRightWhite.svg index effd8c9..e5a3879 100644 --- a/resources/images/android/arrowRightWhite.svg +++ b/resources/images/android/arrowRightWhite.svg @@ -1,12 +1,11 @@ - - - - - - - - - + + + + + + + + diff --git a/resources/images/android/checkbox_0.svg b/resources/images/android/checkbox_0.svg index 879ea5d..b4edf1b 100644 --- a/resources/images/android/checkbox_0.svg +++ b/resources/images/android/checkbox_0.svg @@ -1,12 +1,11 @@ - - - - - - - - - - + + + + + + + + + diff --git a/resources/images/android/checkbox_1.svg b/resources/images/android/checkbox_1.svg index e145d1d..11586f5 100644 --- a/resources/images/android/checkbox_1.svg +++ b/resources/images/android/checkbox_1.svg @@ -1,11 +1,10 @@ - - - - - - - - - - + + + + + + + + + diff --git a/resources/images/android/hdpi/npa.png b/resources/images/android/hdpi/npa.png index c520325..c269b72 100644 Binary files a/resources/images/android/hdpi/npa.png and b/resources/images/android/hdpi/npa.png differ diff --git a/resources/images/android/hdpi/npa_beta.png b/resources/images/android/hdpi/npa_beta.png new file mode 100644 index 0000000..0011af6 Binary files /dev/null and b/resources/images/android/hdpi/npa_beta.png differ diff --git a/resources/images/android/ldpi/npa.png b/resources/images/android/ldpi/npa.png index fb3e83b..f9ed660 100644 Binary files a/resources/images/android/ldpi/npa.png and b/resources/images/android/ldpi/npa.png differ diff --git a/resources/images/android/ldpi/npa_beta.png b/resources/images/android/ldpi/npa_beta.png new file mode 100644 index 0000000..53f292c Binary files /dev/null and b/resources/images/android/ldpi/npa_beta.png differ diff --git a/resources/images/android/mdpi/npa.png b/resources/images/android/mdpi/npa.png index 4001dba..d92b9d1 100644 Binary files a/resources/images/android/mdpi/npa.png and b/resources/images/android/mdpi/npa.png differ diff --git a/resources/images/android/mdpi/npa_beta.png b/resources/images/android/mdpi/npa_beta.png new file mode 100644 index 0000000..e0e3d42 Binary files /dev/null and b/resources/images/android/mdpi/npa_beta.png differ diff --git a/resources/images/android/navigation/anbieter.png b/resources/images/android/navigation/anbieter.png deleted file mode 100644 index 5a85cd6..0000000 Binary files a/resources/images/android/navigation/anbieter.png and /dev/null differ diff --git a/resources/images/android/navigation/anbieter.svg b/resources/images/android/navigation/anbieter.svg new file mode 100644 index 0000000..02f8469 --- /dev/null +++ b/resources/images/android/navigation/anbieter.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/resources/images/android/navigation/ausweisen.png b/resources/images/android/navigation/ausweisen.png deleted file mode 100644 index 48f9419..0000000 Binary files a/resources/images/android/navigation/ausweisen.png and /dev/null differ diff --git a/resources/images/android/navigation/ausweisen.svg b/resources/images/android/navigation/ausweisen.svg new file mode 100644 index 0000000..5cd91c6 --- /dev/null +++ b/resources/images/android/navigation/ausweisen.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/resources/images/android/navigation/balloon.svg b/resources/images/android/navigation/balloon.svg new file mode 100644 index 0000000..9dbf87f --- /dev/null +++ b/resources/images/android/navigation/balloon.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/resources/images/android/navigation/bewerten.png b/resources/images/android/navigation/bewerten.png deleted file mode 100644 index 8b012b9..0000000 Binary files a/resources/images/android/navigation/bewerten.png and /dev/null differ diff --git a/resources/images/android/navigation/bewerten.svg b/resources/images/android/navigation/bewerten.svg new file mode 100644 index 0000000..30662a2 --- /dev/null +++ b/resources/images/android/navigation/bewerten.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/android/navigation/faq.png b/resources/images/android/navigation/faq.png deleted file mode 100644 index c98e202..0000000 Binary files a/resources/images/android/navigation/faq.png and /dev/null differ diff --git a/resources/images/android/navigation/faq.svg b/resources/images/android/navigation/faq.svg new file mode 100644 index 0000000..4c485bc --- /dev/null +++ b/resources/images/android/navigation/faq.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/resources/images/android/navigation/pin.png b/resources/images/android/navigation/pin.png deleted file mode 100644 index 7e6d221..0000000 Binary files a/resources/images/android/navigation/pin.png and /dev/null differ diff --git a/resources/images/android/navigation/pin.svg b/resources/images/android/navigation/pin.svg new file mode 100644 index 0000000..b71a3e5 --- /dev/null +++ b/resources/images/android/navigation/pin.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/resources/images/android/navigation/support.png b/resources/images/android/navigation/support.png deleted file mode 100644 index de991db..0000000 Binary files a/resources/images/android/navigation/support.png and /dev/null differ diff --git a/resources/images/android/navigation/support.svg b/resources/images/android/navigation/support.svg new file mode 100644 index 0000000..6eaa164 --- /dev/null +++ b/resources/images/android/navigation/support.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/navigation/teilen.png b/resources/images/android/navigation/teilen.png deleted file mode 100644 index 4dd2885..0000000 Binary files a/resources/images/android/navigation/teilen.png and /dev/null differ diff --git a/resources/images/android/navigation/teilen.svg b/resources/images/android/navigation/teilen.svg new file mode 100644 index 0000000..5528674 --- /dev/null +++ b/resources/images/android/navigation/teilen.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/android/navigation/verlauf.png b/resources/images/android/navigation/verlauf.png deleted file mode 100644 index 3a83a32..0000000 Binary files a/resources/images/android/navigation/verlauf.png and /dev/null differ diff --git a/resources/images/android/navigation/verlauf.svg b/resources/images/android/navigation/verlauf.svg new file mode 100644 index 0000000..61fe3f3 --- /dev/null +++ b/resources/images/android/navigation/verlauf.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/resources/images/android/navigation/versionsinformation.png b/resources/images/android/navigation/versionsinformation.png deleted file mode 100644 index 6077357..0000000 Binary files a/resources/images/android/navigation/versionsinformation.png and /dev/null differ diff --git a/resources/images/android/navigation/versionsinformation.svg b/resources/images/android/navigation/versionsinformation.svg new file mode 100644 index 0000000..513698c --- /dev/null +++ b/resources/images/android/navigation/versionsinformation.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/android/search_cancel.svg b/resources/images/android/search_cancel.svg new file mode 100644 index 0000000..84dc62a --- /dev/null +++ b/resources/images/android/search_cancel.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/android/search_icon.svg b/resources/images/android/search_icon.svg new file mode 100644 index 0000000..656a7d8 --- /dev/null +++ b/resources/images/android/search_icon.svg @@ -0,0 +1,6 @@ + + + + diff --git a/resources/images/android/tabDivider.svg b/resources/images/android/tabDivider.svg index 2b8c271..cf26d4a 100644 --- a/resources/images/android/tabDivider.svg +++ b/resources/images/android/tabDivider.svg @@ -1,7 +1,6 @@ - - - - - - + + + + + diff --git a/resources/images/android/xhdpi/npa.png b/resources/images/android/xhdpi/npa.png index 8e3f78c..54ebfaa 100644 Binary files a/resources/images/android/xhdpi/npa.png and b/resources/images/android/xhdpi/npa.png differ diff --git a/resources/images/android/xhdpi/npa_beta.png b/resources/images/android/xhdpi/npa_beta.png new file mode 100644 index 0000000..6bd309d Binary files /dev/null and b/resources/images/android/xhdpi/npa_beta.png differ diff --git a/resources/images/android/xxhdpi/npa.png b/resources/images/android/xxhdpi/npa.png index 0cf19ea..cac9cb0 100644 Binary files a/resources/images/android/xxhdpi/npa.png and b/resources/images/android/xxhdpi/npa.png differ diff --git a/resources/images/android/xxhdpi/npa_beta.png b/resources/images/android/xxhdpi/npa_beta.png new file mode 100644 index 0000000..2a93327 Binary files /dev/null and b/resources/images/android/xxhdpi/npa_beta.png differ diff --git a/resources/images/android/xxxhdpi/npa.png b/resources/images/android/xxxhdpi/npa.png index c10febd..9804a73 100644 Binary files a/resources/images/android/xxxhdpi/npa.png and b/resources/images/android/xxxhdpi/npa.png differ diff --git a/resources/images/android/xxxhdpi/npa_beta.png b/resources/images/android/xxxhdpi/npa_beta.png new file mode 100644 index 0000000..2ec73a1 Binary files /dev/null and b/resources/images/android/xxxhdpi/npa_beta.png differ diff --git a/resources/images/androidtelefon.png b/resources/images/androidtelefon.png deleted file mode 100644 index c9898c0..0000000 Binary files a/resources/images/androidtelefon.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_128x128.png b/resources/images/autentapp2.iconset/icon_128x128.png index a96aed0..7375e62 100644 Binary files a/resources/images/autentapp2.iconset/icon_128x128.png and b/resources/images/autentapp2.iconset/icon_128x128.png differ diff --git a/resources/images/autentapp2.iconset/icon_128x128@2x.png b/resources/images/autentapp2.iconset/icon_128x128@2x.png index 0d7ad73..344c865 100644 Binary files a/resources/images/autentapp2.iconset/icon_128x128@2x.png and b/resources/images/autentapp2.iconset/icon_128x128@2x.png differ diff --git a/resources/images/autentapp2.iconset/icon_16x16.png b/resources/images/autentapp2.iconset/icon_16x16.png index b3f0208..9155972 100644 Binary files a/resources/images/autentapp2.iconset/icon_16x16.png and b/resources/images/autentapp2.iconset/icon_16x16.png differ diff --git a/resources/images/autentapp2.iconset/icon_16x16@2x.png b/resources/images/autentapp2.iconset/icon_16x16@2x.png index 7047a7d..94217c5 100644 Binary files a/resources/images/autentapp2.iconset/icon_16x16@2x.png and b/resources/images/autentapp2.iconset/icon_16x16@2x.png differ diff --git a/resources/images/autentapp2.iconset/icon_256x256.png b/resources/images/autentapp2.iconset/icon_256x256.png index 0d7ad73..344c865 100644 Binary files a/resources/images/autentapp2.iconset/icon_256x256.png and b/resources/images/autentapp2.iconset/icon_256x256.png differ diff --git a/resources/images/autentapp2.iconset/icon_256x256@2x.png b/resources/images/autentapp2.iconset/icon_256x256@2x.png index ecd9369..ebbe464 100644 Binary files a/resources/images/autentapp2.iconset/icon_256x256@2x.png and b/resources/images/autentapp2.iconset/icon_256x256@2x.png differ diff --git a/resources/images/autentapp2.iconset/icon_32x32.png b/resources/images/autentapp2.iconset/icon_32x32.png index 7047a7d..94217c5 100644 Binary files a/resources/images/autentapp2.iconset/icon_32x32.png and b/resources/images/autentapp2.iconset/icon_32x32.png differ diff --git a/resources/images/autentapp2.iconset/icon_32x32@2x.png b/resources/images/autentapp2.iconset/icon_32x32@2x.png index 0c2f286..74707af 100644 Binary files a/resources/images/autentapp2.iconset/icon_32x32@2x.png and b/resources/images/autentapp2.iconset/icon_32x32@2x.png differ diff --git a/resources/images/autentapp2.iconset/icon_512x512.png b/resources/images/autentapp2.iconset/icon_512x512.png index ecd9369..ebbe464 100644 Binary files a/resources/images/autentapp2.iconset/icon_512x512.png and b/resources/images/autentapp2.iconset/icon_512x512.png differ diff --git a/resources/images/autentapp2.iconset/icon_512x512@2x.png b/resources/images/autentapp2.iconset/icon_512x512@2x.png index a6c35f6..aec5c6d 100644 Binary files a/resources/images/autentapp2.iconset/icon_512x512@2x.png and b/resources/images/autentapp2.iconset/icon_512x512@2x.png differ diff --git a/resources/images/beta.svg b/resources/images/beta.svg index fa506fd..ce23be0 100644 --- a/resources/images/beta.svg +++ b/resources/images/beta.svg @@ -1,1421 +1,1420 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bspd1.svg b/resources/images/bspd1.svg index 77e9dbf..a7c03ac 100644 --- a/resources/images/bspd1.svg +++ b/resources/images/bspd1.svg @@ -1,33 +1,32 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/resources/images/bt_1.svg b/resources/images/bt_1.svg index 1df03d7..4a71924 100644 --- a/resources/images/bt_1.svg +++ b/resources/images/bt_1.svg @@ -1,11 +1,10 @@ - - - - - - + + + + + diff --git a/resources/images/bt_1b.svg b/resources/images/bt_1b.svg index de05730..c77180e 100644 --- a/resources/images/bt_1b.svg +++ b/resources/images/bt_1b.svg @@ -1,11 +1,10 @@ - - - - - - + + + + + diff --git a/resources/images/bt_2.svg b/resources/images/bt_2.svg index 44ad1ac..ecfd652 100644 --- a/resources/images/bt_2.svg +++ b/resources/images/bt_2.svg @@ -1,22 +1,21 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/bt_2b.svg b/resources/images/bt_2b.svg index 8c3f7b6..79d2068 100644 --- a/resources/images/bt_2b.svg +++ b/resources/images/bt_2b.svg @@ -1,22 +1,21 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/bt_3.svg b/resources/images/bt_3.svg index f863b50..ba2eee3 100644 --- a/resources/images/bt_3.svg +++ b/resources/images/bt_3.svg @@ -1,15 +1,14 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/bt_3b.svg b/resources/images/bt_3b.svg index ad5c048..91e7301 100644 --- a/resources/images/bt_3b.svg +++ b/resources/images/bt_3b.svg @@ -1,15 +1,14 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/bt_4.svg b/resources/images/bt_4.svg index 6e780ce..3858f8e 100644 --- a/resources/images/bt_4.svg +++ b/resources/images/bt_4.svg @@ -1,24 +1,23 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/bt_4b.svg b/resources/images/bt_4b.svg index 759e5b5..738c3df 100644 --- a/resources/images/bt_4b.svg +++ b/resources/images/bt_4b.svg @@ -1,24 +1,23 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/check.svg b/resources/images/check.svg new file mode 100644 index 0000000..f44a545 --- /dev/null +++ b/resources/images/check.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/delete.svg b/resources/images/delete.svg new file mode 100644 index 0000000..7148f33 --- /dev/null +++ b/resources/images/delete.svg @@ -0,0 +1,5 @@ + + + + diff --git a/resources/images/gruener_Haken.svg b/resources/images/gruener_Haken.svg new file mode 100755 index 0000000..09d0a7c --- /dev/null +++ b/resources/images/gruener_Haken.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/resources/images/iOS/Icon-1024_white_background.png b/resources/images/iOS/Icon-1024_white_background.png deleted file mode 100644 index a1447ed..0000000 Binary files a/resources/images/iOS/Icon-1024_white_background.png and /dev/null differ diff --git a/resources/images/iOS/ProviderInformation.png b/resources/images/iOS/ProviderInformation.png deleted file mode 100644 index e0a6370..0000000 Binary files a/resources/images/iOS/ProviderInformation.png and /dev/null differ diff --git a/resources/images/iOS/ProviderPurpose.png b/resources/images/iOS/ProviderPurpose.png deleted file mode 100644 index 717f6d7..0000000 Binary files a/resources/images/iOS/ProviderPurpose.png and /dev/null differ diff --git a/resources/images/iOS/arrowLeft.svg b/resources/images/iOS/arrowLeft.svg index 96a0134..37ac0c1 100644 --- a/resources/images/iOS/arrowLeft.svg +++ b/resources/images/iOS/arrowLeft.svg @@ -1,9 +1,8 @@ - - - - - - - - + + + + + + + diff --git a/resources/images/iOS/arrowRight.svg b/resources/images/iOS/arrowRight.svg index 606be2c..8cd0e02 100644 --- a/resources/images/iOS/arrowRight.svg +++ b/resources/images/iOS/arrowRight.svg @@ -1,9 +1,8 @@ - - - - - - - - + + + + + + + diff --git a/resources/images/iOS/check.svg b/resources/images/iOS/check.svg deleted file mode 100644 index 7698307..0000000 --- a/resources/images/iOS/check.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/resources/images/iOS/gruener_Haken.svg b/resources/images/iOS/gruener_Haken.svg deleted file mode 100755 index 36913d2..0000000 --- a/resources/images/iOS/gruener_Haken.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - diff --git a/resources/images/iOS/list_item_arrow.svg b/resources/images/iOS/list_item_arrow.svg index 217066e..78403c8 100644 --- a/resources/images/iOS/list_item_arrow.svg +++ b/resources/images/iOS/list_item_arrow.svg @@ -1,7 +1,6 @@ - - - - - - + + + + + diff --git a/resources/images/iOS/more/icon_mehr_favorit.svg b/resources/images/iOS/more/icon_mehr_favorit.svg new file mode 100644 index 0000000..248aff0 --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_favorit.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/resources/images/iOS/more/icon_mehr_fragen.svg b/resources/images/iOS/more/icon_mehr_fragen.svg new file mode 100644 index 0000000..98e5312 --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_fragen.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/iOS/more/icon_mehr_info.svg b/resources/images/iOS/more/icon_mehr_info.svg new file mode 100644 index 0000000..4a4db94 --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_info.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/resources/images/iOS/more/icon_mehr_upload.svg b/resources/images/iOS/more/icon_mehr_upload.svg new file mode 100644 index 0000000..1447cfe --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_upload.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Contents.json b/resources/images/iOS/npa_icon_ios.appiconset/Contents.json deleted file mode 100644 index 1b34a14..0000000 --- a/resources/images/iOS/npa_icon_ios.appiconset/Contents.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x", - "filename" : "Icon-Small@2x.png" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x", - "filename" : "Icon-Small@3x.png" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x", - "filename" : "Icon-40@2x.png" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x", - "filename" : "Icon-40@3x.png" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x", - "filename" : "Icon-60@2x.png" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x", - "filename" : "Icon-60@3x.png" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x", - "filename" : "Icon-Small.png" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x", - "filename" : "Icon-Small@2x.png" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x", - "filename" : "Icon-40.png" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x", - "filename" : "Icon-40@2x.png" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x", - "filename" : "Icon-76.png" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x", - "filename" : "Icon-76@2x.png" - } - ], - "info" : { - "version" : 1, - "author" : "makeappicon" - } -} \ No newline at end of file diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-1024.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-1024.png deleted file mode 100644 index 168ce38..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-1024.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-40.png deleted file mode 100644 index d0365c6..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@2x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@2x.png deleted file mode 100644 index 9bc41bb..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@2x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@3x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@3x.png deleted file mode 100644 index b1cf3ee..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-40@3x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@2x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@2x.png deleted file mode 100644 index b1cf3ee..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@2x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@3x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@3x.png deleted file mode 100644 index f0532a5..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-60@3x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-76.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-76.png deleted file mode 100644 index 985991f..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-76.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-76@2x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-76@2x.png deleted file mode 100644 index 6e60d65..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-76@2x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small.png deleted file mode 100644 index 424795f..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@2x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@2x.png deleted file mode 100644 index 9a841e9..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@2x.png and /dev/null differ diff --git a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@3x.png b/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@3x.png deleted file mode 100644 index 9593d96..0000000 Binary files a/resources/images/iOS/npa_icon_ios.appiconset/Icon-Small@3x.png and /dev/null differ diff --git a/resources/images/iOS/radio_button_check_ios.svg b/resources/images/iOS/radio_button_check_ios.svg index b024d12..fac6a61 100644 --- a/resources/images/iOS/radio_button_check_ios.svg +++ b/resources/images/iOS/radio_button_check_ios.svg @@ -1,13 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + diff --git a/resources/images/iOS/rotes_X.svg b/resources/images/iOS/rotes_X.svg deleted file mode 100644 index 694cd4a..0000000 --- a/resources/images/iOS/rotes_X.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - diff --git a/resources/images/iOS/search_cancel.svg b/resources/images/iOS/search_cancel.svg new file mode 100644 index 0000000..bdfadc0 --- /dev/null +++ b/resources/images/iOS/search_cancel.svg @@ -0,0 +1,5 @@ + + + + diff --git a/resources/images/iOS/search_icon.svg b/resources/images/iOS/search_icon.svg new file mode 100644 index 0000000..20925a7 --- /dev/null +++ b/resources/images/iOS/search_icon.svg @@ -0,0 +1,6 @@ + + + + diff --git a/resources/images/iOS/tabBar/More-off.svg b/resources/images/iOS/tabBar/More-off.svg index a711bf7..c38a563 100644 --- a/resources/images/iOS/tabBar/More-off.svg +++ b/resources/images/iOS/tabBar/More-off.svg @@ -1,17 +1,16 @@ - - - - - - - - - - + + + + + + + + + diff --git a/resources/images/iOS/tabBar/More-on.svg b/resources/images/iOS/tabBar/More-on.svg index 093ee5c..1ed93a6 100644 --- a/resources/images/iOS/tabBar/More-on.svg +++ b/resources/images/iOS/tabBar/More-on.svg @@ -1,14 +1,13 @@ - - - - - - - - - - + + + + + + + + + diff --git a/resources/images/icon_Bluetooth.svg b/resources/images/icon_Bluetooth.svg index f1f3580..2590c48 100644 --- a/resources/images/icon_Bluetooth.svg +++ b/resources/images/icon_Bluetooth.svg @@ -1,70 +1,8 @@ - - - - - image/svg+xml - - - - - - - - - - + + + + diff --git a/resources/images/icon_Pin.svg b/resources/images/icon_Pin.svg index 3b3fd4f..7a8ed05 100644 --- a/resources/images/icon_Pin.svg +++ b/resources/images/icon_Pin.svg @@ -1,59 +1,6 @@ - - -image/svg+xml \ No newline at end of file + + + + + diff --git a/resources/images/icon_attention.svg b/resources/images/icon_attention.svg index 12bea34..ac9a9fa 100644 --- a/resources/images/icon_attention.svg +++ b/resources/images/icon_attention.svg @@ -1,35 +1,25 @@ - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/icon_nfc.svg b/resources/images/icon_nfc.svg new file mode 100644 index 0000000..fe01d4c --- /dev/null +++ b/resources/images/icon_nfc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/information.png b/resources/images/information.png deleted file mode 100644 index ff1830b..0000000 Binary files a/resources/images/information.png and /dev/null differ diff --git a/resources/images/magnifying-glass.png b/resources/images/magnifying-glass.png deleted file mode 100644 index eeef537..0000000 Binary files a/resources/images/magnifying-glass.png and /dev/null differ diff --git a/resources/images/mobile/appStartPageBackground.jpg b/resources/images/mobile/appStartPageBackground.jpg deleted file mode 100644 index e53af56..0000000 Binary files a/resources/images/mobile/appStartPageBackground.jpg and /dev/null differ diff --git a/resources/images/more/icon_mehr_favorit.svg b/resources/images/more/icon_mehr_favorit.svg deleted file mode 100644 index 94da7a1..0000000 --- a/resources/images/more/icon_mehr_favorit.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/more/icon_mehr_fragen.svg b/resources/images/more/icon_mehr_fragen.svg deleted file mode 100644 index e2eff29..0000000 --- a/resources/images/more/icon_mehr_fragen.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/more/icon_mehr_info.svg b/resources/images/more/icon_mehr_info.svg deleted file mode 100644 index 6a056b1..0000000 --- a/resources/images/more/icon_mehr_info.svg +++ /dev/null @@ -1,98 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/more/icon_mehr_upload.svg b/resources/images/more/icon_mehr_upload.svg deleted file mode 100644 index d4fc903..0000000 --- a/resources/images/more/icon_mehr_upload.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/resources/images/npa.ico b/resources/images/npa.ico index 0ef7f86..c539c44 100644 Binary files a/resources/images/npa.ico and b/resources/images/npa.ico differ diff --git a/resources/images/npa.svg b/resources/images/npa.svg new file mode 100644 index 0000000..902ddcf --- /dev/null +++ b/resources/images/npa.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/npa_beta.svg b/resources/images/npa_beta.svg new file mode 100644 index 0000000..d89208c --- /dev/null +++ b/resources/images/npa_beta.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/phone_bluetooth.svg b/resources/images/phone_bluetooth.svg new file mode 100644 index 0000000..4c59fec --- /dev/null +++ b/resources/images/phone_bluetooth.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/phone_nfc.svg b/resources/images/phone_nfc.svg new file mode 100644 index 0000000..54d8bee --- /dev/null +++ b/resources/images/phone_nfc.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices.png b/resources/images/provider/categoryIcons/+android/CitizenServices.png deleted file mode 100644 index 4729c99..0000000 Binary files a/resources/images/provider/categoryIcons/+android/CitizenServices.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices.svg b/resources/images/provider/categoryIcons/+android/CitizenServices.svg new file mode 100644 index 0000000..d7d0902 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/CitizenServices.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_bg.png b/resources/images/provider/categoryIcons/+android/CitizenServices_bg.png deleted file mode 100644 index 87070d5..0000000 Binary files a/resources/images/provider/categoryIcons/+android/CitizenServices_bg.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_bg.svg b/resources/images/provider/categoryIcons/+android/CitizenServices_bg.svg new file mode 100644 index 0000000..dba2a5b --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/CitizenServices_bg.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_button.png b/resources/images/provider/categoryIcons/+android/CitizenServices_button.png deleted file mode 100644 index a90d557..0000000 Binary files a/resources/images/provider/categoryIcons/+android/CitizenServices_button.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_button.svg b/resources/images/provider/categoryIcons/+android/CitizenServices_button.svg new file mode 100644 index 0000000..a8bdbe6 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/CitizenServices_button.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_section.png b/resources/images/provider/categoryIcons/+android/CitizenServices_section.png deleted file mode 100644 index 9704ec5..0000000 Binary files a/resources/images/provider/categoryIcons/+android/CitizenServices_section.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_section.svg b/resources/images/provider/categoryIcons/+android/CitizenServices_section.svg new file mode 100644 index 0000000..ac0abad --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/CitizenServices_section.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Financials.png b/resources/images/provider/categoryIcons/+android/Financials.png deleted file mode 100644 index 18f9df7..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Financials.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Financials.svg b/resources/images/provider/categoryIcons/+android/Financials.svg new file mode 100644 index 0000000..9affec0 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Financials.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Financials_bg.png b/resources/images/provider/categoryIcons/+android/Financials_bg.png deleted file mode 100644 index b73a27f..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Financials_bg.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Financials_bg.svg b/resources/images/provider/categoryIcons/+android/Financials_bg.svg new file mode 100644 index 0000000..66f2d69 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Financials_bg.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Financials_button.png b/resources/images/provider/categoryIcons/+android/Financials_button.png deleted file mode 100644 index 5a4bd4a..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Financials_button.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Financials_button.svg b/resources/images/provider/categoryIcons/+android/Financials_button.svg new file mode 100644 index 0000000..edfacb3 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Financials_button.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Financials_section.png b/resources/images/provider/categoryIcons/+android/Financials_section.png deleted file mode 100644 index cff3f3f..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Financials_section.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Financials_section.svg b/resources/images/provider/categoryIcons/+android/Financials_section.svg new file mode 100644 index 0000000..979985f --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Financials_section.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/General.svg b/resources/images/provider/categoryIcons/+android/General.svg new file mode 100644 index 0000000..5eff07d --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/General.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/General_bg.png b/resources/images/provider/categoryIcons/+android/General_bg.png deleted file mode 100644 index 436330d..0000000 Binary files a/resources/images/provider/categoryIcons/+android/General_bg.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/General_bg.svg b/resources/images/provider/categoryIcons/+android/General_bg.svg new file mode 100644 index 0000000..82022a8 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/General_bg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/General_button.svg b/resources/images/provider/categoryIcons/+android/General_button.svg new file mode 100644 index 0000000..7979f02 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/General_button.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/General_section.svg b/resources/images/provider/categoryIcons/+android/General_section.svg new file mode 100644 index 0000000..b78d990 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/General_section.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Insurances.png b/resources/images/provider/categoryIcons/+android/Insurances.png deleted file mode 100644 index 80dc02c..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Insurances.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Insurances.svg b/resources/images/provider/categoryIcons/+android/Insurances.svg new file mode 100644 index 0000000..5cb4276 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Insurances.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Insurances_bg.png b/resources/images/provider/categoryIcons/+android/Insurances_bg.png deleted file mode 100644 index 77d6c42..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Insurances_bg.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Insurances_bg.svg b/resources/images/provider/categoryIcons/+android/Insurances_bg.svg new file mode 100644 index 0000000..aaf40b0 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Insurances_bg.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Insurances_button.png b/resources/images/provider/categoryIcons/+android/Insurances_button.png deleted file mode 100644 index 97ed5eb..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Insurances_button.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Insurances_button.svg b/resources/images/provider/categoryIcons/+android/Insurances_button.svg new file mode 100644 index 0000000..c3f3c00 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Insurances_button.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/Insurances_section.png b/resources/images/provider/categoryIcons/+android/Insurances_section.png deleted file mode 100644 index 03e7fec..0000000 Binary files a/resources/images/provider/categoryIcons/+android/Insurances_section.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/Insurances_section.svg b/resources/images/provider/categoryIcons/+android/Insurances_section.svg new file mode 100644 index 0000000..cf4e961 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/Insurances_section.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/OtherServices.png b/resources/images/provider/categoryIcons/+android/OtherServices.png deleted file mode 100644 index 8b01eb8..0000000 Binary files a/resources/images/provider/categoryIcons/+android/OtherServices.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/OtherServices.svg b/resources/images/provider/categoryIcons/+android/OtherServices.svg new file mode 100644 index 0000000..e4bc6dd --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/OtherServices.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_bg.png b/resources/images/provider/categoryIcons/+android/OtherServices_bg.png deleted file mode 100644 index 598c305..0000000 Binary files a/resources/images/provider/categoryIcons/+android/OtherServices_bg.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_bg.svg b/resources/images/provider/categoryIcons/+android/OtherServices_bg.svg new file mode 100644 index 0000000..a8e32f3 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/OtherServices_bg.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_button.png b/resources/images/provider/categoryIcons/+android/OtherServices_button.png deleted file mode 100644 index 8d1f25c..0000000 Binary files a/resources/images/provider/categoryIcons/+android/OtherServices_button.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_button.svg b/resources/images/provider/categoryIcons/+android/OtherServices_button.svg new file mode 100644 index 0000000..e90c1c3 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/OtherServices_button.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_section.png b/resources/images/provider/categoryIcons/+android/OtherServices_section.png deleted file mode 100644 index ab03e8e..0000000 Binary files a/resources/images/provider/categoryIcons/+android/OtherServices_section.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_section.svg b/resources/images/provider/categoryIcons/+android/OtherServices_section.svg new file mode 100644 index 0000000..b6dda66 --- /dev/null +++ b/resources/images/provider/categoryIcons/+android/OtherServices_section.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/CitizenServices.png b/resources/images/provider/categoryIcons/CitizenServices.png deleted file mode 100644 index db5d4b3..0000000 Binary files a/resources/images/provider/categoryIcons/CitizenServices.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/CitizenServices.svg b/resources/images/provider/categoryIcons/CitizenServices.svg new file mode 100644 index 0000000..590db16 --- /dev/null +++ b/resources/images/provider/categoryIcons/CitizenServices.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/Financials.png b/resources/images/provider/categoryIcons/Financials.png deleted file mode 100644 index c305665..0000000 Binary files a/resources/images/provider/categoryIcons/Financials.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/Financials.svg b/resources/images/provider/categoryIcons/Financials.svg new file mode 100644 index 0000000..a884073 --- /dev/null +++ b/resources/images/provider/categoryIcons/Financials.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/General.svg b/resources/images/provider/categoryIcons/General.svg new file mode 100644 index 0000000..f163c36 --- /dev/null +++ b/resources/images/provider/categoryIcons/General.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/Insurances.png b/resources/images/provider/categoryIcons/Insurances.png deleted file mode 100644 index e3cbd08..0000000 Binary files a/resources/images/provider/categoryIcons/Insurances.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/Insurances.svg b/resources/images/provider/categoryIcons/Insurances.svg new file mode 100644 index 0000000..7a9a341 --- /dev/null +++ b/resources/images/provider/categoryIcons/Insurances.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/OtherServices.png b/resources/images/provider/categoryIcons/OtherServices.png deleted file mode 100644 index 512b6aa..0000000 Binary files a/resources/images/provider/categoryIcons/OtherServices.png and /dev/null differ diff --git a/resources/images/provider/categoryIcons/OtherServices.svg b/resources/images/provider/categoryIcons/OtherServices.svg new file mode 100644 index 0000000..c5a6b7e --- /dev/null +++ b/resources/images/provider/categoryIcons/OtherServices.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/provider/information.svg b/resources/images/provider/information.svg new file mode 100644 index 0000000..1931571 --- /dev/null +++ b/resources/images/provider/information.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/purpose.svg b/resources/images/provider/purpose.svg new file mode 100644 index 0000000..24dde6e --- /dev/null +++ b/resources/images/provider/purpose.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/reader/default_more_cardreader.svg b/resources/images/reader/default_more_cardreader.svg index 91089d5..06a6848 100644 --- a/resources/images/reader/default_more_cardreader.svg +++ b/resources/images/reader/default_more_cardreader.svg @@ -1,326 +1,325 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/reader/default_no_card_found.svg b/resources/images/reader/default_no_card_found.svg index 67938f0..7d2e85b 100644 --- a/resources/images/reader/default_no_card_found.svg +++ b/resources/images/reader/default_no_card_found.svg @@ -1,885 +1,884 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/reader/default_no_cardreader_01.svg b/resources/images/reader/default_no_cardreader_01.svg index db8c130..821201c 100644 --- a/resources/images/reader/default_no_cardreader_01.svg +++ b/resources/images/reader/default_no_cardreader_01.svg @@ -1,393 +1,392 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/rotes_X.svg b/resources/images/rotes_X.svg new file mode 100644 index 0000000..dfea783 --- /dev/null +++ b/resources/images/rotes_X.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/resources/images/submit.svg b/resources/images/submit.svg new file mode 100644 index 0000000..bcecdc6 --- /dev/null +++ b/resources/images/submit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/text-edit-x.png b/resources/images/text-edit-x.png deleted file mode 100644 index dee00f3..0000000 Binary files a/resources/images/text-edit-x.png and /dev/null differ diff --git a/resources/images/zahnraeder.svg b/resources/images/zahnraeder.svg index bd62d0a..6f4fe71 100644 --- a/resources/images/zahnraeder.svg +++ b/resources/images/zahnraeder.svg @@ -1,81 +1,80 @@ - - - - - - - - - + + + + + + + + diff --git a/resources/jenkins/dsl/Builds/Build_Android.groovy b/resources/jenkins/dsl/Builds/Build_Android.groovy index e45b279..1196747 100644 --- a/resources/jenkins/dsl/Builds/Build_Android.groovy +++ b/resources/jenkins/dsl/Builds/Build_Android.groovy @@ -10,7 +10,7 @@ def j = new Build name: 'Android_APK_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', - artifacts: 'build/dist/bin/AusweisApp2-*.apk' + artifacts: 'build/dist/**/AusweisApp2-*.apk' ).generate(this) @@ -21,10 +21,14 @@ j.with shell(strip("""\ cd build; cmake ../source + -DCMAKE_BUILD_TYPE=release -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake - -DNDK_CCACHE=/usr/bin/ccache - -DANDROID_ABI=${ARCH} + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + -DCMAKE_ANDROID_ARCH_ABI=${ARCH} + -DAPK_SIGN_KEYSTORE=\${APK_SIGN_KEYSTORE} + -DAPK_SIGN_KEYSTORE_ALIAS=\${APK_SIGN_KEYSTORE_ALIAS} + -DAPK_SIGN_KEYSTORE_PSW=\${APK_SIGN_KEYSTORE_PSW} """)) shell('cd build; make \${MAKE_FLAGS} install') diff --git a/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy b/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy new file mode 100644 index 0000000..eddb26d --- /dev/null +++ b/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy @@ -0,0 +1,46 @@ +import common.Build +import static common.Constants.strip + +def j = new Build + ( + name: 'FreeBSD', + libraries: 'FreeBSD', + label: 'FreeBSD', + xunit: true + ).generate(this) + + +j.with +{ + wrappers + { + environmentVariables + { + env("QT_PLUGIN_PATH", '$WORKSPACE/libs/build/dist/plugins') + } + } + + steps + { + shell(strip('''\ + cd build; + cmake ../source + -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + -DBUILD_SHARED_LIBS=on + -DSANITIZER=on + ''')) + + shell('''\ + export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH + cd build; make ${MAKE_FLAGS} + '''.stripIndent().trim()) + + shell('''\ + export QML2_IMPORT_PATH=$WORKSPACE/libs/build/dist/qml + export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH + export ASAN_OPTIONS=detect_leaks=0,new_delete_type_mismatch=0 + cd build; ctest ${MAKE_FLAGS} + '''.stripIndent().trim()) + } +} diff --git a/resources/jenkins/dsl/Builds/Build_Linux.groovy b/resources/jenkins/dsl/Builds/Build_Linux.groovy index 704cedd..c9f5dbb 100644 --- a/resources/jenkins/dsl/Builds/Build_Linux.groovy +++ b/resources/jenkins/dsl/Builds/Build_Linux.groovy @@ -29,7 +29,7 @@ j.with -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCOVERAGE=true -DBUILD_SHARED_LIBS=on - -DSANITIZER=address + -DSANITIZER=on ''')) shell('''\ @@ -38,8 +38,9 @@ j.with '''.stripIndent().trim()) shell('''\ + export QML2_IMPORT_PATH=$WORKSPACE/libs/build/dist/qml export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH - export ASAN_OPTIONS=detect_leaks=0 + export ASAN_OPTIONS=detect_leaks=0,new_delete_type_mismatch=0 cd build; ctest ${MAKE_FLAGS} '''.stripIndent().trim()) diff --git a/resources/jenkins/dsl/Builds/Build_MacOS.groovy b/resources/jenkins/dsl/Builds/Build_MacOS.groovy index 130c165..f7ed02b 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS.groovy @@ -34,6 +34,7 @@ j.with export DYLD_FRAMEWORK_PATH=${WORKSPACE}/libs/build/dist/lib export DYLD_LIBRARY_PATH=${WORKSPACE}/libs/build/dist/lib export QT_PLUGIN_PATH=${WORKSPACE}/libs/build/dist/plugins + export QML2_IMPORT_PATH=${WORKSPACE}/libs/build/dist/qml cd build; ctest ${MAKE_FLAGS} '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy b/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy index adb67fb..90d1603 100644 --- a/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy @@ -26,6 +26,7 @@ j.with batchFile('''\ set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins + set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Builds/Build_Win32_MSVC.groovy b/resources/jenkins/dsl/Builds/Build_Win32_MSVC.groovy index a340299..f6d9735 100644 --- a/resources/jenkins/dsl/Builds/Build_Win32_MSVC.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win32_MSVC.groovy @@ -28,6 +28,7 @@ j.with batchFile('''\ set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins + set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Libraries/Libs_Android.groovy b/resources/jenkins/dsl/Libraries/Libs_Android.groovy index 1cb94ba..9e635ce 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Android.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Android.groovy @@ -13,17 +13,9 @@ def j = new Library j.with { - wrappers - { - environmentVariables - { - env("PATH", "\${WORKSPACE}/build/standalone/bin:${PATH}") - } - } - steps { - shell("cd build; cmake ../source/libs -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR} -DANDROID_ABI=${ARCH}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR} -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Libraries/Libs_FreeBSD.groovy b/resources/jenkins/dsl/Libraries/Libs_FreeBSD.groovy new file mode 100644 index 0000000..1d4e079 --- /dev/null +++ b/resources/jenkins/dsl/Libraries/Libs_FreeBSD.groovy @@ -0,0 +1,18 @@ +import common.Library + +def j = new Library + ( + name: 'FreeBSD', + label: 'FreeBSD' + ).generate(this) + + +j.with +{ + steps + { + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") + + shell('cd build; make compress') + } +} diff --git a/resources/jenkins/dsl/Libraries/Libs_Linux.groovy b/resources/jenkins/dsl/Libraries/Libs_Linux.groovy index d816280..5ba860f 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Linux.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Linux.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell("cd build; cmake ../source/libs -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Libraries/Libs_MacOS.groovy b/resources/jenkins/dsl/Libraries/Libs_MacOS.groovy index c17e2d9..0689944 100644 --- a/resources/jenkins/dsl/Libraries/Libs_MacOS.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_MacOS.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell("cd build; cmake ../source/libs -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Libraries/Libs_Win32_GNU.groovy b/resources/jenkins/dsl/Libraries/Libs_Win32_GNU.groovy index 506a515..c8d546c 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win32_GNU.groovy @@ -11,7 +11,7 @@ j.with { steps { - batchFile("cd build & cmake ../source/libs -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") + batchFile("cd build & cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") shell('''\ #!c:\\msys\\1.0\\bin\\sh --login diff --git a/resources/jenkins/dsl/Libraries/Libs_Win32_GNU_dev.groovy b/resources/jenkins/dsl/Libraries/Libs_Win32_GNU_dev.groovy index 0ed219e..243404a 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win32_GNU_dev.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win32_GNU_dev.groovy @@ -11,7 +11,7 @@ j.with { steps { - batchFile("cd build & cmake ../source/libs -DCMAKE_BUILD_TYPE=debug -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") + batchFile("cd build & cmake ../source/libs -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") shell('''\ #!c:\\msys\\1.0\\bin\\sh --login diff --git a/resources/jenkins/dsl/Libraries/Libs_Win32_MSVC_dev.groovy b/resources/jenkins/dsl/Libraries/Libs_Win32_MSVC_dev.groovy index 6bca1e4..5bdf1c8 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Win32_MSVC_dev.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Win32_MSVC_dev.groovy @@ -14,7 +14,7 @@ j.with batchFile('''\ cd build call vcvarsall.bat - cmake ../source/libs -DCMAKE_BUILD_TYPE=debug -DPACKAGES_DIR=%PACKAGES_DIR% -G"NMake Makefiles" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME% + cmake ../source/libs -DPACKAGES_DIR=%PACKAGES_DIR% -G"NMake Makefiles" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME% '''.stripIndent().trim()) batchFile('''\ diff --git a/resources/jenkins/dsl/Libraries/Libs_iOS.groovy b/resources/jenkins/dsl/Libraries/Libs_iOS.groovy index 27bcec0..9b8154d 100644 --- a/resources/jenkins/dsl/Libraries/Libs_iOS.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_iOS.groovy @@ -13,7 +13,7 @@ j.with { shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain') - shell("cd build; cmake ../source/libs -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Releases/Release_Android.groovy b/resources/jenkins/dsl/Releases/Release_Android.groovy index 104e392..5cc85b4 100644 --- a/resources/jenkins/dsl/Releases/Release_Android.groovy +++ b/resources/jenkins/dsl/Releases/Release_Android.groovy @@ -10,7 +10,7 @@ def j = new Release name: 'Android_APK_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', - artifacts: 'build/dist/bin/AusweisApp2-*.apk' + artifacts: 'build/dist/**/AusweisApp2-*.apk' ).generate(this) @@ -28,7 +28,7 @@ j.with -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=release - -DANDROID_ABI=${ARCH} + -DCMAKE_ANDROID_ARCH_ABI=${ARCH} -DAPK_SIGN_KEYSTORE=\${APK_SIGN_KEYSTORE} -DAPK_SIGN_KEYSTORE_ALIAS=\${APK_SIGN_KEYSTORE_ALIAS} -DAPK_SIGN_KEYSTORE_PSW=\${APK_SIGN_KEYSTORE_PSW} diff --git a/resources/jenkins/dsl/Reviews/Review_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Android.groovy index 928b32a..67cecd4 100644 --- a/resources/jenkins/dsl/Reviews/Review_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Android.groovy @@ -10,7 +10,7 @@ def j = new Review name: 'Android_APK_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', - artifacts: 'build/dist/bin/AusweisApp2-*.apk' + artifacts: 'build/dist/**/AusweisApp2-*.apk' ).generate(this) @@ -26,8 +26,8 @@ j.with -DCMAKE_BUILD_TYPE=debug -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake - -DNDK_CCACHE=/usr/bin/ccache - -DANDROID_ABI=${ARCH} + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + -DCMAKE_ANDROID_ARCH_ABI=${ARCH} """)) shell('cd build; make \${MAKE_FLAGS} install') diff --git a/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy new file mode 100644 index 0000000..9fd6e51 --- /dev/null +++ b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy @@ -0,0 +1,50 @@ +import common.Review +import static common.Constants.strip + +def j = new Review + ( + name: 'FreeBSD', + libraries: 'FreeBSD', + label: 'FreeBSD', + artifacts: 'tmp/AusweisApp2.*.log', + allowEmptyArtifacts: true, + xunit: true, + ).generate(this) + + +j.with +{ + wrappers + { + environmentVariables + { + env("QT_PLUGIN_PATH", '$WORKSPACE/libs/build/dist/plugins') + } + } + + steps + { + shell('cd source; python resources/jenkins/import.py') + + shell(strip('''\ + cd build; + cmake ../source + -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + -DBUILD_SHARED_LIBS=on + -DSANITIZER=on + ''')) + + shell('''\ + export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH + cd build; make ${MAKE_FLAGS} + '''.stripIndent().trim()) + + shell('''\ + export QML2_IMPORT_PATH=${WORKSPACE}/libs/build/dist/qml + export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH + export ASAN_OPTIONS=detect_leaks=0,new_delete_type_mismatch=0 + cd build; ctest ${MAKE_FLAGS} + '''.stripIndent().trim()) + } +} diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy index b2f6906..e9fbfce 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy @@ -13,19 +13,11 @@ def j = new LibraryReview j.with { - wrappers - { - environmentVariables - { - env("PATH", "\${WORKSPACE}/build/standalone/bin:${PATH}") - } - } - steps { shell('cd source; python resources/jenkins/import.py') - shell("cd build; cmake ../source/libs -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR} -DANDROID_ABI=${ARCH}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR} -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy new file mode 100644 index 0000000..b0bc3b1 --- /dev/null +++ b/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy @@ -0,0 +1,20 @@ +import common.LibraryReview + +def j = new LibraryReview + ( + name: 'FreeBSD', + label: 'FreeBSD' + ).generate(this) + + +j.with +{ + steps + { + shell('cd source; python resources/jenkins/import.py') + + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") + + shell('cd build; make compress') + } +} diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy index 24cbaaa..f5cd9f9 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy @@ -13,7 +13,7 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell("cd build; cmake ../source/libs -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy index cf1d760..ae9f453 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy @@ -13,7 +13,7 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell("cd build; cmake ../source/libs -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win32_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win32_GNU.groovy index 69c621d..129f0c9 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win32_GNU.groovy @@ -13,7 +13,7 @@ j.with { batchFile('cd source & python resources/jenkins/import.py') - batchFile("cd build & cmake ../source/libs -DCMAKE_BUILD_TYPE=debug -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") + batchFile("cd build & cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DPACKAGES_DIR=%PACKAGES_DIR% -G\"MinGW Makefiles\" -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME%") shell('''\ #!c:\\msys\\1.0\\bin\\sh --login diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy index 4c0192e..c98806b 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy @@ -15,7 +15,7 @@ j.with shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain') - shell("cd build; cmake ../source/libs -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") + shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") shell('cd build; make compress') } diff --git a/resources/jenkins/dsl/Reviews/Review_Linux.groovy b/resources/jenkins/dsl/Reviews/Review_Linux.groovy index bc40cc9..fc00440 100644 --- a/resources/jenkins/dsl/Reviews/Review_Linux.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Linux.groovy @@ -40,7 +40,7 @@ j.with -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=${Compiler} -DBUILD_SHARED_LIBS=on - -DSANITIZER=address + -DSANITIZER=on ''')) shell('''\ @@ -49,8 +49,9 @@ j.with '''.stripIndent().trim()) shell('''\ + export QML2_IMPORT_PATH=${WORKSPACE}/libs/build/dist/qml export LD_LIBRARY_PATH=$WORKSPACE/libs/build/dist/lib:$LD_LIBRARY_PATH - export ASAN_OPTIONS=detect_leaks=0 + export ASAN_OPTIONS=detect_leaks=0,new_delete_type_mismatch=0 cd build; ctest ${MAKE_FLAGS} '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy index 62f8230..9173037 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy @@ -38,6 +38,7 @@ j.with export DYLD_FRAMEWORK_PATH=${WORKSPACE}/libs/build/dist/lib export DYLD_LIBRARY_PATH=${WORKSPACE}/libs/build/dist/lib export QT_PLUGIN_PATH=${WORKSPACE}/libs/build/dist/plugins + export QML2_IMPORT_PATH=${WORKSPACE}/libs/build/dist/qml cd build; ctest ${MAKE_FLAGS} '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy index 7e9e518..611a047 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy @@ -12,7 +12,7 @@ def getJobs() list << 'Android_APK_' + ARCH } - def unitTests = ['Linux', 'MacOS', 'Win32_GNU'] + def unitTests = ['Linux', 'MacOS', 'Win32_GNU', 'FreeBSD'] list += unitTests return list @@ -83,6 +83,8 @@ j.with phaseJob(getName('Win32_GNU')) phaseJob(getName('MacOS')) + + phaseJob(getName('FreeBSD')) } } diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy index f179cba..81f829e 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy @@ -6,7 +6,7 @@ import static common.Constants.createReviewMessage def getJobs() { - def list = ['Linux', 'MacOS', 'Win32_GNU', 'Win32_MSVC', 'iOS'] + def list = ['Linux', 'MacOS', 'Win32_GNU', 'Win32_MSVC', 'iOS', 'FreeBSD'] for(ARCH in Constants.AndroidArch) { list << 'Android_' + ARCH @@ -94,6 +94,12 @@ j.with abortAllJobs(false) killPhaseCondition('NEVER') } + + phaseJob(getName('FreeBSD')) + { + abortAllJobs(false) + killPhaseCondition('NEVER') + } } phase('Application') diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy index f92f3f7..6a97976 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy @@ -31,6 +31,7 @@ j.with set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% set PATH=%WORKSPACE%/install;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins + set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy index 835074d..4b89d96 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy @@ -32,6 +32,7 @@ j.with batchFile('''\ set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins + set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% '''.stripIndent().trim()) } diff --git a/resources/jenkins/dsl/common/Appcast.groovy b/resources/jenkins/dsl/common/Appcast.groovy index beec2d3..909c42d 100644 --- a/resources/jenkins/dsl/common/Appcast.groovy +++ b/resources/jenkins/dsl/common/Appcast.groovy @@ -9,7 +9,7 @@ class Appcast extends Build { String name = 'Appcast' String label= 'Common' - String artifacts = 'build/*.msi,build/*.dmg,build/*.tar.gz,build/*.sha256,build/Appcast.xml,build/ReleaseNotes.html,build/docs/**/*.pdf,build/docs/**/*.tar.xz,source/resources/default-*' + String artifacts = 'build/*.msi,build/*.dmg,build/*.tar.gz,build/*.sha256,build/Appcast.*,build/ReleaseNotes.html,build/docs/**/*.pdf,build/docs/**/*.tar.xz,source/resources/default-*' String trigger = null List oldBuilds = [-1, 5] boolean sendMail = false diff --git a/resources/jenkins/dsl/common/Constants.groovy b/resources/jenkins/dsl/common/Constants.groovy index 9c3bb6d..5cf8a1b 100644 --- a/resources/jenkins/dsl/common/Constants.groovy +++ b/resources/jenkins/dsl/common/Constants.groovy @@ -2,7 +2,7 @@ package common class Constants { - static final AndroidArch = ["armeabi-v7a", "x86"] + static final AndroidArch = ["armeabi-v7a", "x86", "arm64-v8a"] static String strip(String content) { diff --git a/resources/packaging/android/AndroidManifest.xml.in b/resources/packaging/android/AndroidManifest.xml.in index ba4ad1e..eddf62e 100644 --- a/resources/packaging/android/AndroidManifest.xml.in +++ b/resources/packaging/android/AndroidManifest.xml.in @@ -1,10 +1,11 @@ - + + android:launchMode="singleTask" + android:theme="@style/Theme.NoTitle"> @@ -13,7 +14,13 @@ - + + + + + + + @@ -143,16 +150,20 @@ - - + + + + + + + + + - - diff --git a/resources/packaging/android/colors.xml b/resources/packaging/android/colors.xml deleted file mode 100644 index 0a433ba..0000000 --- a/resources/packaging/android/colors.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - #49749C - #673751 - #44445F - #CEA62C - #053B3D - diff --git a/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in b/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in index 201d219..00866a1 100644 --- a/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in +++ b/resources/packaging/android/libAusweisApp2.so-deployment-settings.json.in @@ -2,12 +2,13 @@ "description": "This file is generated by cmake to be read by androiddeployqt and should not be modified by hand.", "qt": "@QT_HOST_PREFIX@", "sdk": "@ANDROID_SDK@", - "ndk": "@ANDROID_NDK@", + "ndk": "@CMAKE_ANDROID_NDK@", + "sdkBuildToolsRevision": "@ANDROID_BUILD_TOOLS_REVISION@", "toolchain-prefix": "@ANDROID_TOOLCHAIN_PREFIX@", - "tool-prefix": "@ANDROID_TOOL_PREFIX@", - "toolchain-version": "@ANDROID_COMPILER_VERSION@", - "ndk-host": "@ANDROID_NDK_HOST_SYSTEM_NAME@", - "target-architecture": "@ANDROID_ABI@", - "android-package-source-directory": "@PACKAGE_SRC_DIR@", - "application-binary": "@CMAKE_INSTALL_PREFIX@/libs/@ANDROID_ABI@/libAusweisApp2.so" + "tool-prefix": "@ANDROID_TOOLCHAIN_MACHINE_NAME@", + "toolchain-version": "@CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION@", + "ndk-host": "@CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG@", + "target-architecture": "@CMAKE_ANDROID_ARCH_ABI@", + "android-package-source-directory": "@ANDROID_PACKAGE_SRC_DIR@", + "application-binary": "@ANDROID_APP_BINARY@" } diff --git a/resources/packaging/android/styles.xml b/resources/packaging/android/styles.xml new file mode 100644 index 0000000..59ebb8e --- /dev/null +++ b/resources/packaging/android/styles.xml @@ -0,0 +1,8 @@ + + #dcebf6 + + diff --git a/resources/packaging/macos/start-ausweisapp2.sh b/resources/packaging/macos/start-ausweisapp2.sh index 99b0f7e..eb483ba 100755 --- a/resources/packaging/macos/start-ausweisapp2.sh +++ b/resources/packaging/macos/start-ausweisapp2.sh @@ -17,4 +17,4 @@ export QT_QPA_PLATFORM_PLUGIN_PATH=$AA2_PLUGINS # For debugging what libraries are loaded. #export DYLD_PRINT_LIBRARIES=1 -exec "$AA2_RESOURCES/@EXECUTABLE_NAME@" +exec "$AA2_RESOURCES/@EXECUTABLE_NAME@" $@ diff --git a/resources/packaging/updater/Appcast.item.json.in b/resources/packaging/updater/Appcast.item.json.in new file mode 100644 index 0000000..9c3408e --- /dev/null +++ b/resources/packaging/updater/Appcast.item.json.in @@ -0,0 +1,9 @@ + { + "date": "APPCAST_DATE", + "platform": "APPCAST_PLATFORM", + "version": "APPCAST_VERSION", + "url": "APPCAST_URL", + "size": APPCAST_SIZE, + "checksum": "APPCAST_CHECKSUM", + "notes": "APPCAST_NOTES" + } diff --git a/resources/packaging/updater/Appcast.item.xml.in b/resources/packaging/updater/Appcast.item.xml.in deleted file mode 100644 index 8bacb92..0000000 --- a/resources/packaging/updater/Appcast.item.xml.in +++ /dev/null @@ -1,14 +0,0 @@ - - AusweisApp2 APPCAST_VERSION / APPCAST_OS - APPCAST_DATE - APPCAST_URL/ReleaseNotes.html#APPCAST_VERSION - APPCAST_URL/ReleaseNotes.html#APPCAST_VERSION - APPCAST_URL/ReleaseNotes.html#APPCAST_VERSION - - - diff --git a/resources/packaging/updater/Appcast.json.in b/resources/packaging/updater/Appcast.json.in new file mode 100644 index 0000000..10d1bfd --- /dev/null +++ b/resources/packaging/updater/Appcast.json.in @@ -0,0 +1,6 @@ +{ + "items": + [ +@APPCAST_ITEMS@ + ] +} diff --git a/resources/packaging/updater/Appcast.xml.in b/resources/packaging/updater/Appcast.xml.in deleted file mode 100644 index 227f2b0..0000000 --- a/resources/packaging/updater/Appcast.xml.in +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Governikus AusweisApp2 Changelog - @APPCAST_URL@/Appcast.xml - Aktuelle Änderungen von AusweisApp2. - de - - -@APPCAST_ITEMS@ - - diff --git a/resources/qml/+android/ContentArea.qml b/resources/qml/+android/ContentArea.qml index 7df8842..7b369b5 100644 --- a/resources/qml/+android/ContentArea.qml +++ b/resources/qml/+android/ContentArea.qml @@ -37,8 +37,14 @@ Item { TabBarView { anchors.fill: parent - visible: baseItem.state === "versionInformation" - source: "more/VersionInformation.qml" + visible: baseItem.state === "feedback" + source: "more/Feedback.qml" + } + + TabBarView { + anchors.fill: parent + visible: baseItem.state === "information" + source: "more/Information.qml" } TabBarView { diff --git a/resources/qml/+android/Navigation.qml b/resources/qml/+android/Navigation.qml index ad378ba..bebb5e3 100644 --- a/resources/qml/+android/Navigation.qml +++ b/resources/qml/+android/Navigation.qml @@ -8,27 +8,16 @@ Item { state: "identify" width: !PlatformConstants.is_tablet || lockedAndHidden ? 0 : Constants.menubar_width - property bool lockedAndHidden: false - property bool isOpen: false + property bool lockedAndHidden: true + property bool isOpen: drawer.position > 0 property int currentIndex: 0 - signal opened() - signal closed() - onLockedAndHiddenChanged: { if (lockedAndHidden) { drawer.close() } } - onOpened: { - isOpen = true - } - - onClosed: { - isOpen = false - } - function open() { if (!lockedAndHidden) { drawer.open() @@ -78,18 +67,7 @@ Item { } } - // FIXME: - // when lockedAndHidden is true, dragging is still possible although the documentation stated: - // "Setting the value to 0 or less prevents opening the drawer by dragging" - dragMargin: lockedAndHidden ? 0 : Qt.styleHints.startDragDistance - - onOpened: { - parent.opened() - } - - onClosed: { - parent.closed() - } + dragMargin: lockedAndHidden ? 0 : Utils.dp(Qt.styleHints.startDragDistance) onPositionChanged: { if (PlatformConstants.is_tablet && position > 0) { diff --git a/resources/qml/+android/NavigationItem.qml b/resources/qml/+android/NavigationItem.qml index 3221d34..7d7112a 100644 --- a/resources/qml/+android/NavigationItem.qml +++ b/resources/qml/+android/NavigationItem.qml @@ -16,6 +16,7 @@ Item { Image { id: tabImage height: Utils.dp(35) + sourceSize.height: 96; fillMode: Image.PreserveAspectFit anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter @@ -27,7 +28,7 @@ Item { anchors.left: tabImageItem.right anchors.leftMargin: Utils.dp(10) anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Utils.sp(12) + font.pixelSize: Constants.small_font_size renderType: Text.NativeRendering color: "black" } diff --git a/resources/qml/+android/NavigationView.qml b/resources/qml/+android/NavigationView.qml index 31722cd..4b31c67 100644 --- a/resources/qml/+android/NavigationView.qml +++ b/resources/qml/+android/NavigationView.qml @@ -16,62 +16,39 @@ Rectangle { id: navModel ListElement { - image: "qrc:///images/android/navigation/ausweisen.png" + image: "qrc:///images/android/navigation/ausweisen.svg" desc: qsTr("Identify") condition: "identify" } ListElement { - image: "qrc:///images/android/navigation/anbieter.png" + image: "qrc:///images/android/navigation/anbieter.svg" desc: qsTr("Provider") condition: "provider" } ListElement { - image: "qrc:///images/android/navigation/verlauf.png" + image: "qrc:///images/android/navigation/verlauf.svg" desc: qsTr("History") condition: "history" } ListElement { - image: "qrc:///images/android/navigation/pin.png" - desc: qsTr("Pin") + image: "qrc:///images/android/navigation/pin.svg" + desc: qsTr("PIN Management") condition: "pin" } ListElement { - image: "qrc:///images/android/navigation/versionsinformation.png" - desc: qsTr("Versioninformation") - condition: "versionInformation" + image: "qrc:///images/android/navigation/balloon.svg" + desc: qsTr("Dialog & Feedback") + condition: "feedback" } ListElement { - image: "qrc:///images/android/navigation/faq.png" - desc: qsTr("FAQ") - condition: "external" - external: qsTr("https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/") - } - - ListElement { - image: "qrc:///images/android/navigation/support.png" - desc: qsTr("Support") - condition: "external" - external: qsTr("https://www.ausweisapp.bund.de/en/service/support/") - } - - ListElement { - image: "qrc:///images/android/navigation/bewerten.png" - desc: qsTr("Rate app") - condition: "external" - external: "market://details?id=com.governikus.ausweisapp2" - } - - ListElement { - image: "qrc:///images/android/navigation/teilen.png" - desc: qsTr("Share...") - condition: "share" - share: qsTr("I'm using AusweisApp2, download it here for Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2 or here for iOS: https://itunes.apple.com/de/app/wikipedia-mobile/id324715238?mt=8") - shareTitle: qsTr("Share with") + image: "qrc:///images/android/navigation/faq.svg" + desc: qsTr("Info & Help") + condition: "information" } ListElement { @@ -104,17 +81,8 @@ Rectangle { source: image text: desc onClicked: { - if (condition === "share") { - shareUtil.shareText(share, shareTitle) - } - else if (condition === "external") { - Qt.openUrlExternally(external) - } - else { - navigationController.currentIndex = index - navigationController.state = condition - } - + navigationController.currentIndex = index + navigationController.state = condition navigationController.close() } // Hide developer options if we are not using developer build (debug build) diff --git a/resources/qml/+android/ProviderContactTab.qml b/resources/qml/+android/ProviderContactTab.qml index 38db8ae..750c88f 100644 --- a/resources/qml/+android/ProviderContactTab.qml +++ b/resources/qml/+android/ProviderContactTab.qml @@ -6,54 +6,14 @@ import "global" Item { id: baseItem - - property string homepage - property string phone - property string email - property string postalAddress - - ListModel { - id: providerInfoModel - - property string homepage: baseItem.homepage - property string phone: baseItem.phone - property string email: baseItem.email - property string postalAddress: baseItem.postalAddress - - property string cssBegin: "" - property string cssEnd: "" - - onHomepageChanged: setProperty(0, "text", cssBegin + '' + homepage + "" + cssEnd) - onEmailChanged: setProperty(1, "text", cssBegin + '' + email + "" + cssEnd) - onPhoneChanged: setProperty(2, "text", cssBegin + '' + phone + "" + cssEnd) - onPostalAddressChanged: setProperty(3, "text", cssBegin + '' + postalAddress + "" + cssEnd) - - - ListElement { - imageSource: "qrc:///images/provider/url.png" - text: "" - } - - ListElement { - imageSource: "qrc:///images/provider/mail.png" - text: "" - } - - ListElement { - imageSource: "qrc:///images/provider/telefon.png" - text: "" - } - - ListElement { - imageSource: "qrc:///images/provider/adresse.png" - text: "" - } - } + property alias contactModel: infoList.model + readonly property int contentHeight: infoList.contentHeight ListView { - model: providerInfoModel + id: infoList anchors.fill: parent + interactive: false delegate: Item { id: delegateItem @@ -68,12 +28,12 @@ Item { anchors.left: parent.left anchors.leftMargin: Utils.dp(15) anchors.verticalCenter: parent.verticalCenter - source: model.imageSource + source: Qt.resolvedUrl(model.iconSource) } Text { id: textItem - text: model.text + text: !!model.text ? model.text : qsTr("Unknown") verticalAlignment: Text.AlignVCenter anchors.left: imageItem.right anchors.leftMargin: Utils.dp(20) @@ -83,14 +43,12 @@ Item { font.pixelSize: Utils.dp(16) wrapMode: Text.WordWrap textFormat: Text.RichText - onLinkActivated: Qt.openUrlExternally(link) } MouseArea { anchors.fill: delegateItem - onClicked: { - Qt.openUrlExternally(textItem.linkAt(textItem.x, textItem.y)) - } + enabled: !!model.link + onClicked: Qt.openUrlExternally(model.link) } Rectangle { diff --git a/resources/qml/+android/ProviderHeader.qml b/resources/qml/+android/ProviderHeader.qml index 73e15db..7bd67a9 100644 --- a/resources/qml/+android/ProviderHeader.qml +++ b/resources/qml/+android/ProviderHeader.qml @@ -5,70 +5,168 @@ import "global" Rectangle { id: baseItem - /* this is interpreted by the SectionPage component */ - readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : 0 + // Properties that are set by ProviderView or ProviderDetailView + property string selectedCategory: selectedProvider ? selectedProvider.category : "" + property var selectedProvider - property string address - property string providerIcon - property string providerImage - property color transparentColor : Constants.blue + // This is interpreted by the SectionPage component + readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : (customProviderImage ? Math.max(0, 0.5 - shadow.opacity) : 0) - color: "white" + // Internal vars + readonly property color shadowColor: Category.displayColor(selectedCategory) + readonly property bool customProviderImage: !!selectedProvider && !!selectedProvider.image + readonly property string backgroundImage: customProviderImage ? selectedProvider.image : Category.backgroundImageSource(selectedCategory) + readonly property string categoryIcon: selectedProvider || selectedCategory !== "all" ? "" : Category.imageSource(selectedCategory) + readonly property bool withButtons: selectedCategory === "" && !selectedProvider + + readonly property double iconHeightRatio: 0.3 + readonly property double iconVerticalMarginRatio: 0.2 + + property int maxContentY: withButtons ? parent.height * (iconHeightRatio + iconVerticalMarginRatio) : + height / 2 + + height: backgroundImage.height + providerInfo.height + + function definedContentY() { + // For some reason contentY is sometimes set to undefined. + return typeof(contentY) === "undefined" ? 0 : contentY + } + + function currentMargin() { + // Height of button icons. + var H = height * iconHeightRatio + + // Initial inferior margin for button icons. + var M = height * iconVerticalMarginRatio + + var y = definedContentY() + + return -2 * y * (M + H) / (3 * M + 2 * H) + M + } Image { - id: headerBackgroundImage - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + id: backgroundImage + source: baseItem.backgroundImage + height: width / 1.80 width: parent.width - height: parent.height * 0.7 - source: providerImage + anchors.left: parent.left + anchors.top: parent.top fillMode: Image.PreserveAspectCrop function transition() { - return Math.min(1, Math.max(0, contentY/(parent.height - 2 * Constants.titlebar_height - parent.height * 0.3))) + return Math.min(1, contentY / (height - Constants.titlebar_height)) + } + + Image { + id: categoryIcon + source: baseItem.categoryIcon + asynchronous: true + height: parent.height * 0.5 + width: height + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter: backgroundImage.horizontalCenter + anchors.bottom: backgroundImage.bottom + anchors.bottomMargin: Constants.component_spacing + + visible: baseItem.categoryIcon !== "" + + opacity: baseItem.definedContentY() <= maxContentY ? 1 : 0 + Behavior on opacity { + NumberAnimation {} + } + } + + Image { + source: selectedProvider ? selectedProvider.icon : "" + asynchronous: true + height: Utils.dp(70) + width: height + fillMode: Image.PreserveAspectFit + anchors.margins: Constants.component_spacing + anchors.left: parent.left + anchors.bottom: parent.bottom + visible: !!selectedProvider } Rectangle { id: shadow anchors.fill: parent - color: transparentColor - opacity: parent.transition() < 1 ? 0.5 : 1 - Behavior on opacity { - NumberAnimation {} + color: baseItem.shadowColor + opacity: parent.transition() + } + } + + Row { + id: iconsRow + + height: backgroundImage.height * iconHeightRatio + width: backgroundImage.width * 0.9 + + visible: withButtons + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: backgroundImage.bottom + anchors.bottomMargin: baseItem.currentMargin() + + Repeater { + model: ["citizen", "finance", "insurance", "other"] + + Rectangle { + height: parent.height + width: parent.width * 0.25 + color: "transparent" + + Image { + source: Category.buttonImageSource(modelData) + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + } + + MouseArea { + anchors.fill: parent + onClicked: providerModel.setCategorySelection(modelData) + } } } } Rectangle { - width: headerBackgroundImage.width - height: headerBackgroundImage.height - color: transparentColor - opacity: transparentColor === Constants.blue ? 0 : 0.7 - } + id: providerInfo + height: visible ? column.height + 2 * Constants.pane_padding : 0 + width: parent.width + anchors.left: parent.left + anchors.top: backgroundImage.bottom - Image { - anchors.left: baseItem.left - anchors.leftMargin: Utils.dp(30) - anchors.verticalCenter: headerBackgroundImage.bottom - height: Utils.dp(70) - width: height - source: providerIcon - fillMode: Image.Stretch - } + visible: !!selectedProvider - Button { - id: buttonText - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(12) - anchors.right: parent.right - anchors.rightMargin: Utils.dp(25) - buttonColor: transparentColor - text: qsTr("Online-Application") - onClicked: { - Qt.openUrlExternally(address) + Column { + id: column + anchors.margins: Constants.pane_padding + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + spacing: Constants.pane_spacing + + Text { + id: providerText + width: parent.width + text: selectedProvider ? selectedProvider.shortDescription : "" + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + visible: text.length > 0 + } + + Button { + id: providerButton + anchors.right: parent.right + buttonColor: shadowColor + text: qsTr("Online Application") + onClicked: { + Qt.openUrlExternally(selectedProvider ? selectedProvider.address : "") + } + } } } } diff --git a/resources/qml/+android/ProviderInfoSection.qml b/resources/qml/+android/ProviderInfoSection.qml new file mode 100644 index 0000000..d183ab1 --- /dev/null +++ b/resources/qml/+android/ProviderInfoSection.qml @@ -0,0 +1,43 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import "global" + + +Rectangle { + + property string imageSource; + property string title; + property string name; + + width: parent.width + height: Math.max(image.height, providerTitle.height) + + color: "white" + clip: true + + Image { + id: image + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + + height: Utils.dp(40) + width: Utils.dp(40) + + source: imageSource + fillMode: Image.PreserveAspectFit + } + + LabeledText { + id: providerTitle + anchors.verticalCenter: image.verticalCenter + anchors.left: image.right + anchors.leftMargin: Utils.dp(10) + anchors.right: parent.right + + label: title + text: name.length > 0 ? name : qsTr("Touch for more details") + } +} diff --git a/resources/qml/+android/ResultView.qml b/resources/qml/+android/ResultView.qml index 0a817e9..4d64f01 100644 --- a/resources/qml/+android/ResultView.qml +++ b/resources/qml/+android/ResultView.qml @@ -34,38 +34,38 @@ SectionPage { Image { id: resultImage + source: isError ? "qrc:///images/rotes_X.svg" : "qrc:///images/android/" + imageDir + "/haken.png" + height: Utils.dp(100) + width: height anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: Utils.dp(60) - fillMode: Image.PreserveAspectFit - - source: isError ? "qrc:///images/iOS/rotes_X.svg" : "qrc:///images/android/" + imageDir + "/haken.png" - width: Utils.dp(160) } Text { id: resultText - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - width: parent.width * 0.9 + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: resultImage.bottom + anchors.bottom: button.top font.pixelSize: Constants.header_font_size horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap color: Constants.blue + onLinkActivated: Qt.openUrlExternally(link) } Button { + id: button width: Utils.dp(90) - anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.bottomMargin: Utils.dp(30) text: qsTr("Ok") - onClicked: baseItem.clicked() } } diff --git a/resources/qml/+android/TitleBar.qml b/resources/qml/+android/TitleBar.qml index f37d08d..37db5e7 100644 --- a/resources/qml/+android/TitleBar.qml +++ b/resources/qml/+android/TitleBar.qml @@ -1,4 +1,4 @@ -import QtQuick 2.5 +import QtQuick 2.7 import QtQuick.Controls 1.4 import "global" @@ -10,39 +10,34 @@ Item id: titleBar height: Constants.titlebar_height - readonly property var standardMenuAction: TitleBarMenuAction { state: "" } - readonly property var standardTitle: TitleBarAction { text: qsTr("Identify"); font.bold: true } + readonly property TitleBarMenuAction standardMenuAction: TitleBarMenuAction { state: "" } + readonly property TitleBarAction standardTitle: TitleBarAction { text: qsTr("Identify"); font.bold: true } + + property TitleBarMenuAction menuAction: standardMenuAction + property TitleBarAction titleItem: standardTitle function reset() { - leftActionStack.clear() - headerActionStack.clear() rightActionStack.clear() - leftActionStack.push(standardMenuAction) - headerActionStack.push(standardTitle) - background.color = PlatformConstants.blue + setColor(PlatformConstants.blue) + menuAction = standardMenuAction + titleItem = standardTitle } function push(leftAction, headerAction, rightAction, color) { - // TODO Remove Stacks because they are not longer needed - leftActionStack.pop() - headerActionStack.pop() + // TODO Remove Stack because we no longer need it rightActionStack.pop() - background.color = color - leftActionStack.push(leftAction) - headerActionStack.push(headerAction) + setColor(color) + menuAction = leftAction + titleItem = headerAction rightActionStack.push(rightAction) } - - function pop(item) { - leftActionStack.pop(item) - headerActionStack.pop(item) - rightActionStack.pop(item) + function setColor(color) { + background.color = color } - Rectangle { id: background color: PlatformConstants.blue @@ -51,28 +46,7 @@ Item anchors.bottom: parent.bottom anchors.right: parent.right - onColorChanged: { - var colorString - var colorCompare = String(color) - switch(colorCompare) { - case Category.CATEGORY_COLOR_CITIZEN: - colorString = "CITIZEN" - break; - case Category.CATEGORY_COLOR_INSURANCE: - colorString = "INSURANCE" - break; - case Category.CATEGORY_COLOR_FINANCE: - colorString = "FINANCE" - break; - case Category.CATEGORY_COLOR_OTHER: - colorString = "OTHER" - break; - default: - colorString = "DEFAULT" - } - statusBarUtil.setStatusBarColor(colorString) - } - + onColorChanged: statusBarUtil.setStatusBarColor(String(color)) Behavior on color { ColorAnimation { duration: titleBar.duration } } } @@ -90,7 +64,7 @@ Item anchors.horizontalCenter: hamburgerFrame.horizontalCenter height: parent.height width: height - state: navBar.isOpen ? "back" : (leftActionStack.currentItem ? leftActionStack.currentItem.state : "") + state: navBar.isOpen ? "back" : menuAction.state MouseArea { anchors.fill: parent @@ -103,71 +77,63 @@ Item if (navBar.isOpen) { navBar.close() } else { - leftActionStack.currentItem.clicked() + menuAction.clicked() } break default: - leftActionStack.currentItem.clicked() + menuAction.clicked() } } } } - StackView { - id: leftActionStack - anchors.left: hamburgerFrame.right - anchors.leftMargin: Utils.dp(10) - height: parent.height - // We dont need this view on android at this time: width = 0 - width: 0 //currentItem ? currentItem.contentWidth : parent.height - delegate: StackViewDelegate { - pushTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "x"; from: 0; to: -headerActionStack.x } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "x"; from: headerActionStack.x; to: 0 } - } - popTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "x"; to: headerActionStack.x } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "x"; from: -headerActionStack.x; to: 0 } - } - } - } + Item { + id: titleText + property string text: titleItem.text + property bool bold: titleItem.font.bold + property int _width: parent.width - 2 * (Math.max(hamburgerFrame.width, rightActionStack.width) + Constants.titlebar_padding) - StackView { - property int _width: parent.width - 2 * Math.max(hamburgerFrame.width, rightActionStack.width) - Utils.dp(20) // 20 == margin - - id: headerActionStack anchors.centerIn: parent height: parent.height width: Math.max(_width, 0) - delegate: StackViewDelegate { - pushTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "x"; from: 0; to: headerActionStack.getRelX(leftActionStack) } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "x"; from: headerActionStack.getRelX(rightActionStack); to: 0 } - } - popTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "x"; to: headerActionStack.getRelX(rightActionStack) } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "x"; from: headerActionStack.getRelX(leftActionStack); to: 0 } + clip: true + + TitleBarText { + id: oldTitle + text: parent.text + Component.onCompleted: font.bold = parent.bold + opacity: 0 + + Behavior on text { + SequentialAnimation { + PropertyAnimation { target: oldTitle; property: "opacity"; from: 1; to: 0; duration: titleBar.duration } + PropertyAction { target: oldTitle; property: "font.bold"; value: titleText.bold } + PropertyAction { target: oldTitle; property: "text" } + } } } - function getRelX(otherItem) { - return headerActionStack.mapFromItem(otherItem,otherItem.x,0).x + + TitleBarText { + id: newTitle + text: parent.text + font.bold: parent.bold + + Behavior on text { + ParallelAnimation { + PropertyAnimation { target: newTitle; property: "opacity"; from: 0; to: 1; duration: titleBar.duration } + PropertyAnimation { target: newTitle; property: "x"; from: width; to: 0; duration: titleBar.duration } + } + } } + } StackView { id: rightActionStack + anchors.margins: Constants.titlebar_padding + anchors.top: parent.top anchors.right: parent.right - anchors.rightMargin: Utils.dp(10) - anchors.verticalCenter: parent.verticalCenter - height: parent.height + anchors.bottom: parent.bottom width: currentItem ? currentItem.contentWidth : 0 delegate: StackViewDelegate { pushTransition: StackViewTransition { diff --git a/resources/qml/+android/TitleBarAction.qml b/resources/qml/+android/TitleBarAction.qml new file mode 100644 index 0000000..d154e8f --- /dev/null +++ b/resources/qml/+android/TitleBarAction.qml @@ -0,0 +1,4 @@ +import QtQuick 2.7 + +Text { +} diff --git a/resources/qml/+android/TitleBarMenuAction.qml b/resources/qml/+android/TitleBarMenuAction.qml index c6b5787..6861272 100644 --- a/resources/qml/+android/TitleBarMenuAction.qml +++ b/resources/qml/+android/TitleBarMenuAction.qml @@ -1,20 +1,6 @@ -import QtQuick 2.5 - -import "global" +import QtQuick 2.7 Item { property string state - property alias text: textItem.text - property alias font: textItem.font - readonly property alias contentWidth: root.width signal clicked - - id: root - width: parent ? parent.width : undefined - height: parent ? parent.height : undefined - - Text { - id: textItem - visible: false - } } diff --git a/resources/qml/BluetoothProgressIndicator.qml b/resources/qml/BluetoothProgressIndicator.qml new file mode 100644 index 0000000..0db0733 --- /dev/null +++ b/resources/qml/BluetoothProgressIndicator.qml @@ -0,0 +1,64 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "global" + + +Item { + id: baseItem + + Image { + id: phone + source: "qrc:///images/phone_bluetooth.svg" + height: parent.height * 0.5 + width: height + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + visible: baseItem.state === "off" + } + Colorize { + id: grayLevel + source: phone + anchors.fill: phone + saturation: 0 + hue: 0 + lightness: 0.3 + cached: true + visible: baseItem.state === "off" + } + + Item { + id: currentAction + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: pCircle.top + anchors.margins: Constants.component_spacing + + BusyImageIndicator { + anchors.centerIn: parent + width: height + height: parent.height - Utils.dp(40) + image: "qrc:///images/icon_Bluetooth.svg" + running: visible + visible: baseItem.state === "one" + } + + CardReader { + anchors.centerIn: parent + height: parent.height + visible: baseItem.state === "two" || baseItem.state === "three" + cardAnimation: baseItem.state === "two" + pinFieldAnimation: baseItem.state === "three" + } + } + + ProgressCircle { + id: pCircle + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + state: baseItem.state + visible: baseItem.state === "one" || baseItem.state === "two" || baseItem.state === "three" + } +} diff --git a/resources/qml/BluetoothWorkflow.qml b/resources/qml/BluetoothWorkflow.qml index f7f76d0..807eefa 100644 --- a/resources/qml/BluetoothWorkflow.qml +++ b/resources/qml/BluetoothWorkflow.qml @@ -1,13 +1,26 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.1 import "global" -Item -{ +Item { id: baseItem + signal abortBluetooth - state: "initial" + readonly property bool showLocationPermissionInfo: applicationModel.locationPermissionRequired && !locationPermissionInfoConfirmed + property bool locationPermissionInfoConfirmed: false + + onStateChanged: { + if (state === "bt_connect") { + locationPermissionInfoConfirmed = false + } + } + + onShowLocationPermissionInfoChanged: { + if (applicationModel.bluetoothEnabled && !showLocationPermissionInfo) { + numberModel.continueWorkflow() + } + } function isInProcessingState() { return state === "bt_enternewpin" || state === "bt_updateretrycounter" || @@ -16,182 +29,69 @@ Item state === "bt_identify_enterpin" } - function processingText() { - if (state === "bt_enterpuk") { - return qsTr("Enter PUK...") - } - else if (state === "bt_changepin_entercan"|| state === "bt_identify_entercan") { - return qsTr("Enter CAN...") - } - else if (state === "bt_changepin_enterpin" || state === "bt_identify_enterpin") { - return qsTr("Enter PIN...") - } - else if (state === "bt_enternewpin") { - return qsTr("Enter new PIN...") - } - // This should never happen - else { - return "" - } - } - - Item { - id: currentAction + BluetoothProgressIndicator { + id: progressIndicator anchors.left: parent.left - anchors.right: parent.right anchors.top: parent.top - anchors.bottom: pCircle.top - anchors.margins: Utils.dp(40) - height: parent.height * 0.25 - - BusyImageIndicator { - anchors.centerIn: parent - width: height - height: parent.height - Utils.dp(40) - image: "qrc:///images/icon_Bluetooth.svg" - running: visible - visible: baseItem.state === "bt_connect" - } - - CardReader { - anchors.centerIn: parent - height: parent.height - visible: baseItem.state === "bt_card" || baseItem.isInProcessingState() - cardAnimation: baseItem.state === "bt_card" - pinFieldAnimation: baseItem.state === "bt_enternewpin" - } - } - - ProgressCircle { - id: pCircle - anchors.top: baseItem.verticalCenter - anchors.left: parent.left anchors.right: parent.right - state: { - if (baseItem.state === "bt_connect") { - return "one" - } - if (baseItem.state === "bt_card") { - return "two" - } - if (baseItem.isInProcessingState()) { - return "three" - } - return "initial" - } + height: parent.height / 2 + state: (!applicationModel.bluetoothAvailable || !applicationModel.bluetoothEnabled || parent.showLocationPermissionInfo) ? "off" : + (baseItem.state === "bt_connect") ? "one" : + (baseItem.state === "bt_card") ? "two" : + (baseItem.isInProcessingState()) ? "three" :"" } - Text { - id: titleText - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font.pixelSize: Constants.header_font_size - font.weight: Font.Bold - color: Constants.blue - anchors.top: pCircle.bottom - anchors.topMargin: Utils.dp(20) + TechnologyInfo { + id: techInfo anchors.left: parent.left + anchors.leftMargin: Utils.dp(5) anchors.right: parent.right + anchors.rightMargin: anchors.leftMargin + anchors.top: progressIndicator.bottom + anchors.bottom: switchToNfcAction.top + state: parent.state - states: [ - State { when: baseItem.state === "bt_connect"; - PropertyChanges { target: titleText; text: qsTr("Establish connection") } - }, - State { when: baseItem.state === "bt_card"; - PropertyChanges { target: titleText; text: qsTr("Determine card") } - }, - State { when: (baseItem.state === "bt_enternewpin" || - baseItem.state === "bt_enterpuk" || - baseItem.state === "bt_changepin_entercan" || - baseItem.state === "bt_changepin_enterpin"); - PropertyChanges { target: titleText; text: qsTr("Change PIN") } - }, - State { when: (baseItem.state === "bt_identify_entercan" || - baseItem.state === "bt_identify_enterpin"); - PropertyChanges { target: titleText; text: qsTr("Authenticate") } - } - ] - - transitions: [ - Transition { - SequentialAnimation { - NumberAnimation { target: rotation; property: "angle"; to: 90; duration: 500 } - PropertyAction { target: titleText; property: "text" } - NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 500 } - } - } - ] - - transform: Rotation { - id: rotation - origin.x: 0 - origin.y: titleText.height/2 - axis.x: 1; axis.y: 0; axis.z: 0 - angle: 0 - } - } - - - Rectangle { - id: subTitleTextBackground - color: Constants.red - anchors.centerIn: subTitleText - width: subTitleText.width + 2 * Utils.dp(5) - height: subTitleText.height + 2 * Utils.dp(5) - visible: false - } - Text { - id: subTitleText - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font.pixelSize: Constants.normal_font_size - color: Constants.grey - anchors.top: titleText.bottom - anchors.topMargin: Utils.dp(10) - anchors.horizontalCenter: baseItem.horizontalCenter - width: baseItem.width * 0.8 - wrapMode: Text.WordWrap - - states: [ - State { when: baseItem.state === "bt_connect" - PropertyChanges { target: subTitleText; text: qsTr("Establish connection...") } - PropertyChanges { target: subTitleText; color: Constants.grey } - }, - State { when: baseItem.state === "bt_card" - PropertyChanges { target: subTitleText; text: qsTr("Insert card...") } - PropertyChanges { target: subTitleText; color: Constants.grey } - }, - State { when: baseItem.isInProcessingState() && numberModel.inputError - PropertyChanges { target: subTitleText; text: numberModel.inputError } - PropertyChanges { target: subTitleText; color: "white" } - PropertyChanges { target: subTitleTextBackground; visible: true } - }, - State { when: baseItem.isInProcessingState() - PropertyChanges { target: subTitleText; text: baseItem.processingText() } - PropertyChanges { target: subTitleText; color: Constants.grey } - } - ] - - Behavior on text { - SequentialAnimation { - animations: animation + enableButtonVisible: applicationModel.bluetoothAvailable && (!applicationModel.bluetoothEnabled || parent.showLocationPermissionInfo) + enableButtonText: !applicationModel.bluetoothEnabled ? qsTr("Enable Bluetooth") : qsTr("Continue") + onEnableClicked: { + if (!applicationModel.bluetoothEnabled) { + applicationModel.bluetoothEnabled = true + } else { + parent.locationPermissionInfoConfirmed = true } } + enableText: !visible ? "" : + !applicationModel.bluetoothAvailable ? qsTr("Bluetooth is not supported by your device.
Please try NFC.") : + !applicationModel.bluetoothEnabled ? qsTr("Bluetooth is switched off.
Please enable Bluetooth.") : + parent.showLocationPermissionInfo ? qsTr("No paired and activated Bluetooth device was detected. The AusweisApp2 needs access to your location in order to discover available devices. You can grant this permission after clicking the continue button.") : "" - transitions: [ - Transition { - id: transition - animations: animation - } - ] + titleText: (baseItem.state === "bt_connect") ? qsTr("Establish connection") : + (baseItem.state === "bt_card") ? qsTr("Determine card") : + (baseItem.state === "bt_enternewpin" || baseItem.state === "bt_enterpuk" + || baseItem.state === "bt_changepin_entercan" || baseItem.state === "bt_changepin_enterpin") ? qsTr("Change PIN") : + (baseItem.state === "bt_identify_entercan" || baseItem.state === "bt_identify_enterpin") ? qsTr("Authenticate") : "" - SequentialAnimation { - id: animation - PropertyAnimation { target: subTitleText; property: "anchors.topMargin"; to: baseItem.height - subTitleText.y + subTitleText.height; duration: 500} - PropertyAction { target: subTitleText; property: "text" } - PropertyAction { target: subTitleText; property: "color" } - PropertyAction { target: subTitleTextBackground; property: "visible" } - PropertyAnimation { target: subTitleText; property: "anchors.topMargin"; to: Utils.dp(10); duration: 500 } + subTitleText: !visible ? "" : + !!numberModel.inputError ? numberModel.inputError : + numberModel.pinDeactivated ? qsTr("The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function.") : + (state === "bt_connect") ? qsTr("Connecting...") : + (state === "bt_card") ? qsTr("Please insert your ID card.") : + (state === "bt_changepin_enterpin") ? qsTr("Please enter your old PIN or your initial transport PIN first.") : + (state === "bt_identify_enterpin") ? qsTr("Please enter your personal PIN.") : + (state === "bt_changepin_entercan"|| state === "bt_identify_entercan") ? qsTr("You have entered the wrong PIN twice. For a third attempt, you have to enter your six-digit card access number first. You can find your card access number on the front of your ID card.") : + (state === "bt_enterpuk") ? qsTr("You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking.") : + (state === "bt_enternewpin") ? qsTr("Please enter a new arbitrary 6-digit PIN.") : "" + subTitleTextRedColor: numberModel.inputError || numberModel.pinDeactivated || state === "bt_changepin_entercan" || state === "bt_identify_entercan" || state === "bt_enterpuk" } + + TechnologySwitchButton { + id: switchToNfcAction + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + onClicked: { + parent.abortBluetooth() } + imageSource: "qrc:///images/icon_nfc.svg" + text: qsTr("Use NFC instead of
Bluetooth card reader") + enabled: parent.state === "bt_connect" || parent.state === "bt_card" } } diff --git a/resources/qml/EnterPinView.qml b/resources/qml/EnterPinView.qml new file mode 100644 index 0000000..e070720 --- /dev/null +++ b/resources/qml/EnterPinView.qml @@ -0,0 +1,124 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import "." +import "global" + +SectionPage +{ + id: baseItem + signal pinEntered() + + onVisibleChanged: { + pinField.text = "" + if (state !== "PIN_NEW_AGAIN") { + pinField.inputConfirmation = "" + } + } + + ColumnLayout + { + anchors.fill: parent + Item {/*spacer*/ Layout.fillHeight: true; width: parent.width } + + RowLayout { + spacing: Constants.component_spacing + width: parent.width + + Item {/*spacer*/ Layout.fillWidth: true; height: parent.height} + Image { + anchors.verticalCenter: parent.verticalCenter + width: Utils.dp(58) + height: width + Layout.maximumWidth: width + source: "qrc:///images/NFCPhoneCard.png" + fillMode: Image.PreserveAspectFit + } + + Text { + anchors.verticalCenter: parent.verticalCenter + Layout.fillWidth: true + Layout.maximumWidth: Math.ceil(implicitWidth) + + wrapMode: Text.WordWrap + font.pixelSize: text.length > 150 && !PlatformConstants.is_tablet? Utils.dp(15) : Constants.header_font_size + font.bold: true + color: { + if (!pinField.confirmedInput || !!numberModel.inputError || baseItem.state === "CAN" || baseItem.state === "PUK") { + Constants.red + } else { + Constants.blue + } + } + text: { + if (!pinField.confirmedInput) { + qsTr("The entered PIN does not match the new PIN. Please correct your input.") + } else if (!!numberModel.inputError) { + numberModel.inputError + } else { + baseItem.state === "CAN" ? qsTr("You have entered the wrong PIN twice. For a third attempt, you have to enter your six-digit card access number first. You can find your card access number on the front of your ID card.") : + baseItem.state === "PUK" ? qsTr("You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking.") : + baseItem.state === "PIN_NEW" ? qsTr("Please enter a new arbitrary 6-digit PIN.") : + baseItem.state === "PIN_NEW_AGAIN" ? qsTr("Please confirm your new PIN by re-entering your personal PIN.") : + baseItem.state === "PIN" ? qsTr("Please enter your personal PIN.") : + /*"PIN_OR_TRANSPORT_PIN"*/ qsTr("Please enter your old PIN or your initial transport PIN first.") + } + } + } + Item {/*spacer*/ Layout.fillWidth: true; height: parent.height} + } + + Item {/*spacer*/ Layout.fillHeight: true; width: parent.width } + + PinField { + id: pinField + anchors.horizontalCenter: parent.horizontalCenter + state: baseItem.state + Layout.preferredWidth: width + } + + Item {/*spacer*/ height: Constants.component_spacing; width: parent.width } + + PinPad { + anchors.horizontalCenter: parent.horizontalCenter + state: baseItem.state + Layout.preferredWidth: width + Layout.preferredHeight: height + + submitEnabled: pinField.validInput + deleteEnabled: pinField.text.length > 0 + onDigitPressed: pinField.append(digit) + onDeletePressed: pinField.removeLast() + onSubmitPressed: { + switch(baseItem.state) { + case "PIN": + /* fall through */ + case "PIN_OR_TRANSPORT_PIN": + numberModel.pin = pinField.text + baseItem.pinEntered() + break + case "PIN_NEW": + pinField.inputConfirmation = pinField.text + pinField.text = "" + baseItem.state = "PIN_NEW_AGAIN" + break + case "PIN_NEW_AGAIN": + numberModel.newPin = pinField.text + baseItem.pinEntered() + break + case "CAN": + numberModel.can = pinField.text + baseItem.pinEntered() + break + case "PUK": + numberModel.puk = pinField.text + baseItem.pinEntered() + break + } + } + } + + Item {/*spacer*/ Layout.fillHeight: true; width: parent.width } + } + +} diff --git a/resources/qml/NavigationItem.qml b/resources/qml/NavigationItem.qml index ac2927b..8d19586 100644 --- a/resources/qml/NavigationItem.qml +++ b/resources/qml/NavigationItem.qml @@ -22,7 +22,7 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.bottomMargin: font.pixelSize / 10 - font.pixelSize: Constants.tabbar_font_size + font.pixelSize: Constants.small_font_size renderType: Text.NativeRendering } diff --git a/resources/qml/NavigationView.qml b/resources/qml/NavigationView.qml index 644d31e..4ae63cd 100644 --- a/resources/qml/NavigationView.qml +++ b/resources/qml/NavigationView.qml @@ -36,7 +36,7 @@ Rectangle { ListElement { imageOn: "qrc:///images/iOS/tabBar/Pin-on.png" imageOff: "qrc:///images/iOS/tabBar/Pin-off.png" - desc: qsTr("Pin") + desc: qsTr("PIN Management") condition: "pin" } diff --git a/resources/qml/NfcConnectionIndication.qml b/resources/qml/NfcConnectionIndication.qml deleted file mode 100644 index 5f0f76c..0000000 --- a/resources/qml/NfcConnectionIndication.qml +++ /dev/null @@ -1,123 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item { - height: childrenRect.height - width: parent.width - - - SequentialAnimation { - id: shakingAnimation - loops: Animation.Infinite - readonly property int delta: Utils.dp(4) - readonly property int deltaDuration: 300 - - ParallelAnimation { - SequentialAnimation { - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x - shakingAnimation.delta; duration: shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x + shakingAnimation.delta; duration: 2*shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x; duration: shakingAnimation.deltaDuration } - } - SequentialAnimation { - PropertyAnimation { target: phoneNfcImage; property: "y"; to: phoneNfcImage.y - shakingAnimation.delta; duration: 2*shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "y"; to: phoneNfcImage.y; duration: 2*shakingAnimation.deltaDuration } - } - } - ParallelAnimation { - SequentialAnimation { - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x - shakingAnimation.delta; duration: shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x + shakingAnimation.delta; duration: 2*shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "x"; to: phoneNfcImage.x; duration: shakingAnimation.deltaDuration } - } - SequentialAnimation { - PropertyAnimation { target: phoneNfcImage; property: "y"; to: phoneNfcImage.y + shakingAnimation.delta; duration: 2*shakingAnimation.deltaDuration } - PropertyAnimation { target: phoneNfcImage; property: "y"; to: phoneNfcImage.y; duration: 2*shakingAnimation.deltaDuration } - } - } - } - - state: visible ? "on" : "off" - states: [ - State { - name: "off" - PropertyChanges { target: cardNfcImage; x: images.width; y: images.height / 2; rotation: -180 } - PropertyChanges { target: phoneNfcImage; x: 0 } - PropertyChanges { target: shakingAnimation; running: false } - }, - State { - name: "on" - PropertyChanges { target: cardNfcImage; x: (images.width + phoneNfcImage.width - cardNfcImage.width)/2; y: cardNfcImage.height / 4; rotation: 0 } - PropertyChanges { target: phoneNfcImage; x: (images.width - phoneNfcImage.width)/2 } - PropertyChanges { target: shakingAnimation; running: true } - } - ] - - transitions: - Transition { - from: "off"; to: "on"; reversible: false - SequentialAnimation - { - PauseAnimation { duration: 500 } - PropertyAnimation{ targets: cardNfcImage; properties: "x,y,rotation"; duration: 500; easing.type: Easing.OutQuad } - PropertyAnimation{ targets: phoneNfcImage; property: "x"; duration: 500; easing.type: Easing.OutQuart } - PropertyAction { target: shakingAnimation; property: "running" } - } - } - - Item { - id: images - width: parent.width - height: parent.height / 8 * 3 - anchors.top: parent.top - anchors.topMargin: parent.height / 8 * 1 - Image { - id: cardNfcImage - source: "qrc:///images/ausweis.png" - height: images.height / 3 * 2 // == parent.height / 8 * 2 - width: height - fillMode: Image.PreserveAspectFit - } - Image { - id: phoneNfcImage - source: "qrc:///images/androidtelefon.png" - height: cardNfcImage.height - width: height - fillMode: Image.PreserveAspectFit - - } - } - - Text { - id: headerText - anchors.top: images.bottom - anchors.topMargin: Utils.dp(30) - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Establish connection") - font.pixelSize: Constants.header_font_size - color: Constants.blue - } - Text { - function getInfoText() { - if (!applicationModel.nfcEnabled) { - return qsTr("NFC not supported") + "\n" + qsTr("or switched off"); - } - else if (applicationModel.extendedLengthApdusUnsupported) { - return qsTr("Your phone does not support the") + "\n" + qsTr("required extended length ADPUs."); - } - - return qsTr("Please place your smartphone") + "\n" + qsTr("on your id card"); - } - - id: infoText - anchors.top: headerText.bottom - anchors.topMargin: Utils.dp(30) - anchors.horizontalCenter: parent.horizontalCenter - width: text.width - text: getInfoText() - color: applicationModel.nfcEnabled && !applicationModel.extendedLengthApdusUnsupported ? "black" : Constants.red - font.pixelSize: Constants.normal_font_size - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } -} diff --git a/resources/qml/NfcProgressIndicator.qml b/resources/qml/NfcProgressIndicator.qml new file mode 100644 index 0000000..ba568e7 --- /dev/null +++ b/resources/qml/NfcProgressIndicator.qml @@ -0,0 +1,92 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "global" + + +Item { + id: baseItem + + SequentialAnimation { + id: shaking + loops: Animation.Infinite + readonly property int delta: Utils.dp(4) + readonly property int deltaDuration: 300 + + ParallelAnimation { + SequentialAnimation { + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: -shaking.delta; duration: shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: shaking.delta; duration: 2*shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: 0; duration: shaking.deltaDuration } + } + SequentialAnimation { + PropertyAnimation { target: phone.anchors; property: "verticalCenterOffset"; to: -shaking.delta; duration: 2*shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "verticalCenterOffset"; to: 0; duration: 2*shaking.deltaDuration } + } + } + ParallelAnimation { + SequentialAnimation { + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: -shaking.delta; duration: shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: shaking.delta; duration: 2*shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "horizontalCenterOffset"; to: 0; duration: shaking.deltaDuration } + } + SequentialAnimation { + PropertyAnimation { target: phone.anchors; property: "verticalCenterOffset"; to: shaking.delta; duration: 2*shaking.deltaDuration } + PropertyAnimation { target: phone.anchors; property: "verticalCenterOffset"; to: 0; duration: 2*shaking.deltaDuration } + } + } + } + + states: [ + State { + name: "off" + PropertyChanges { target: grayLevel; visible: true } + PropertyChanges { target: card; x: baseItem.width; y: baseItem.height / 2; rotation: -180 } + PropertyChanges { target: shaking; running: false } + }, + State { + name: "on" + PropertyChanges { target: grayLevel; visible: false } + PropertyChanges { target: card; x: (baseItem.width + phone.width - card.width)/2; y: baseItem.height / 4; rotation: 0 } + PropertyChanges { target: shaking; running: true } + } + ] + + transitions: + Transition { + from: "off"; to: "on"; reversible: false + SequentialAnimation + { + PauseAnimation { duration: 500 } + PropertyAnimation{ targets: card; properties: "x,y,rotation"; duration: 500; easing.type: Easing.OutQuad } + PropertyAnimation{ targets: phone; property: "x"; duration: 500; easing.type: Easing.OutQuart } + PropertyAction { target: shaking; property: "running" } + } + } + + Image { + id: card + source: "qrc:///images/ausweis.png" + height: phone.height + width: height + fillMode: Image.PreserveAspectFit + } + + Image { + id: phone + source: "qrc:///images/phone_nfc.svg" + height: parent.height * 0.5 + width: height + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + } + Colorize { + id: grayLevel + source: phone + anchors.fill: phone + saturation: 0 + hue: 0 + lightness: 0.3 + cached: true + } +} diff --git a/resources/qml/NfcWorkflow.qml b/resources/qml/NfcWorkflow.qml index 0bc7bb9..9177c8d 100644 --- a/resources/qml/NfcWorkflow.qml +++ b/resources/qml/NfcWorkflow.qml @@ -1,37 +1,57 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.1 + +import "global" + Item { id: baseItem signal abortNfc + clip: true - state: "initial" - states: [ - State { name: "nfc_connect" - PropertyChanges { target: switchToBluetoothAction; visible: true } - PropertyChanges { target: nfcConnectionIndication; visible: true } - }, - State { name: "nfc_card" - PropertyChanges { target: switchToBluetoothAction; visible: true } - PropertyChanges { target: nfcConnectionIndication; visible: true } - }, - State { name: "nfc_updateretrycounter" - PropertyChanges { target: switchToBluetoothAction; visible: false } - PropertyChanges { target: nfcConnectionIndication; visible: false } - } - ] - - NfcConnectionIndication { - id: nfcConnectionIndication - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.bottom: switchToBluetoothAction.top + NfcProgressIndicator { + id: progressIndicator + anchors.left: parent.left + anchors.right: parent.right + height: parent.height / 2 + state: visible && applicationModel.nfcAvailable && applicationModel.nfcEnabled ? "on" : "off" } - SwitchToBluetooth { + + TechnologyInfo { + anchors.left: parent.left + anchors.leftMargin: Utils.dp(5) + anchors.right: parent.right + anchors.rightMargin: anchors.leftMargin + anchors.top: progressIndicator.bottom + anchors.bottom: switchToBluetoothAction.top + clip: true + state: parent.state + + enableButtonVisible: applicationModel.nfcAvailable && !applicationModel.nfcEnabled + enableButtonText: qsTr("Enable NFC") + onEnableClicked: qmlExtension.showSettings("android.settings.NFC_SETTINGS") + enableText: !visible ? "" : + !applicationModel.nfcAvailable ? qsTr("NFC is not supported by your device.
Please try Bluetooth.") : + !applicationModel.nfcEnabled ? qsTr("NFC is switched off.
Please enable NFC.") : "" + + titleText: qsTr("Establish connection") + + subTitleText: !visible ? "" : + numberModel.extendedLengthApdusUnsupported ? qsTr("Your device does not meet the technical requirements (Extended Length not supported). You require an additional Bluetooth card reader to use the online identification function with this device.") : + numberModel.pinDeactivated ? qsTr("The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function.") : + qsTr("Please place your device
on your ID card.") + subTitleTextRedColor: numberModel.extendedLengthApdusUnsupported || numberModel.pinDeactivated + } + + + TechnologySwitchButton { id: switchToBluetoothAction anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom onClicked: parent.abortNfc() + imageSource: "qrc:///images/icon_Bluetooth.svg" + text: qsTr("Use Bluetooth card reader
instead of NFC") + enabled: parent.state === "nfc_connect" || parent.state === "nfc_card" } } diff --git a/resources/qml/NumPadButton.qml b/resources/qml/NumPadButton.qml deleted file mode 100644 index d82d481..0000000 --- a/resources/qml/NumPadButton.qml +++ /dev/null @@ -1,69 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Rectangle { - id: button - - property alias text: textItem.text; - property alias source: imageItem.source; - signal clicked - - width: Utils.dp(40) - height: width - - color: Constants.background_color - Behavior on color { ColorAnimation { duration: 120; easing.type: Easing.OutElastic} } - - Text { - id: textItem - - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - - font.pixelSize: Utils.sp(24) - wrapMode: Text.WordWrap - color: "black" - - Behavior on color { ColorAnimation { duration: 120; easing.type: Easing.OutElastic} } - states: [ - State { - name: "pressed" - when: mouse.pressed - PropertyChanges { - target: textItem - color: Qt.lighter("black") - } - PropertyChanges { - target: button - color: Qt.darker(Constants.blue_light) - } - } - ] - } - - Rectangle { - id: imageRect - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - - Image { - id: imageItem - - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - - width: button.width - height: button.width - - fillMode: Image.PreserveAspectFit - } - } - - MouseArea { - id: mouse - anchors.fill: parent - anchors.margins: -Utils.sp(24) - onClicked: parent.clicked(); - } -} diff --git a/resources/qml/PinField.qml b/resources/qml/PinField.qml new file mode 100644 index 0000000..50a9b10 --- /dev/null +++ b/resources/qml/PinField.qml @@ -0,0 +1,65 @@ +import QtQuick 2.7 + +import "global" + +Item { + id: baseItem + + property alias text: echoField.text + property string inputConfirmation + readonly property bool confirmedInput: inputConfirmation.length != text.length || inputConfirmation === text + readonly property bool validInput: echoField.acceptableInput && confirmedInput + + function append(number) { + echoField.insert(echoField.length, number) + } + function removeLast() { + echoField.remove(echoField.length-1, echoField.length) + } + + height: sample.implicitHeight * 1.5 + width: lines.width + clip: true + + TextInput { + id: echoField + verticalAlignment: TextInput.AlignVCenter + echoMode: TextInput.Password + font.pixelSize: Utils.sp(18) + font.letterSpacing: Utils.dp(10) + passwordMaskDelay: 500 + cursorVisible: false + activeFocusOnPress: false + focus: false + validator: RegExpValidator { + regExp: baseItem.state === "PUK" ? /[0-9]{10}/ : + baseItem.state === "PIN_OR_TRANSPORT_PIN" ? /[0-9]{5,6}/ : /[0-9]{6}/ } + maximumLength: baseItem.state === "PUK" ? 10 : 6 + clip: true + } + + TextInput { + id: sample + visible: false + echoMode: echoField.echoMode + font: echoField.font + text: "0" + } + + Row { + id: lines + anchors.bottom: baseItem.bottom + spacing: echoField.font.letterSpacing + anchors.left: echoField.left + + Repeater { + model: baseItem.state === "PUK" ? 10 : 6 + delegate: + Rectangle { + width: sample.contentWidth - sample.font.letterSpacing + height: 1 + color: "black" + } + } + } +} diff --git a/resources/qml/PinPad.qml b/resources/qml/PinPad.qml index dc5b857..736db5f 100644 --- a/resources/qml/PinPad.qml +++ b/resources/qml/PinPad.qml @@ -1,213 +1,46 @@ import QtQuick 2.5 +import QtQuick.Layouts 1.1 import "global" -Item { +GridLayout { id: baseItem - property string _checkablePin - signal pinEntered() - onVisibleChanged: { - if(visible) { - // Workflow: Change-PIN - // Wenn der Benutzer eine PIN eingegeben hat und den Workflow dann abbricht, - // ist nach erneutem Workflow-Start die vorher eingegebene PIN initial gesetzt - // - // Das ist unerklärlich, da wir in der ChangePinStateMachine den state auf INITIAL - // setzen, was zum löschen der alten PIN führt. Die alte PIN wird danach von Unbekannt - // wieder gesetzt. FIXME! - // - // Die folgende Zeile ist ein Workaround - echoField.text = "" - } + property bool deleteEnabled: true + property bool submitEnabled: true + + signal digitPressed(string digit) + signal deletePressed() + signal submitPressed() + + columns: 3 + columnSpacing: Utils.dp(10) + rowSpacing: columnSpacing + width: Utils.dp(250) + height: width + Layout.fillHeight: false + Layout.fillWidth: false + + PinPadButton { text: "1"; onClicked: baseItem.digitPressed("1"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "2"; onClicked: baseItem.digitPressed("2"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "3"; onClicked: baseItem.digitPressed("3"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "4"; onClicked: baseItem.digitPressed("4"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "5"; onClicked: baseItem.digitPressed("5"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "6"; onClicked: baseItem.digitPressed("6"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "7"; onClicked: baseItem.digitPressed("7"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "8"; onClicked: baseItem.digitPressed("8"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { text: "9"; onClicked: baseItem.digitPressed("9"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { + source: baseItem.deleteEnabled ? "qrc:///images/delete.svg" : "" + onClicked: baseItem.deletePressed() + enabled: baseItem.deleteEnabled + Layout.fillHeight: true; Layout.fillWidth: true } - - state: "INITIAL" - states: [ - State { name: "INITIAL" - PropertyChanges { target: baseItem; _checkablePin: "" } - PropertyChanges { target: echoField; text: "" } - }, - State { name: "PIN" }, - State { name: "PIN_OR_TRANSPORT_PIN" }, - State { name: "PIN_NEW" }, - State { name: "PIN_NEW_AGAIN" }, - State { name: "CAN" }, - State { name: "PUK" } - ] - - Item { - width: allImage.width + message.anchors.leftMargin + message.width - height: Math.max(allImage.height, message.height) - anchors.top: parent.top - anchors.topMargin: Utils.dp(20) - anchors.horizontalCenter: parent.horizontalCenter - - Image { - id: allImage - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - width: Utils.dp(58) - height: Utils.dp(58) - source: "qrc:///images/NFCPhoneCard.png" - fillMode: Image.PreserveAspectFit - } - - Text { - property bool isError: echoField.pinDoesNotMatch || numberModel.inputError.length > 0 - - id: message - anchors.leftMargin: parent.anchors.topMargin - anchors.left: allImage.right - anchors.verticalCenter: parent.verticalCenter - wrapMode: Text.WordWrap - width: { - var maxWidth = baseItem.width - allImage.width - 3 * anchors.leftMargin - Math.min(dummyTextMessage.width, maxWidth) - } - - font.pixelSize: isError ? Utils.sp(20) : Constants.header_font_size - font.bold: isError ? false : true - color: isError ? Constants.red : Constants.blue - text: { - if (isError) { - echoField.pinDoesNotMatch ? qsTr("The PIN does not match.") : numberModel.inputError - } else { - baseItem.state === "CAN" ? qsTr("Enter your CAN") : - baseItem.state === "PUK" ? qsTr("Enter your PUK") : - baseItem.state === "PIN_NEW" ? qsTr("Enter your new PIN") : - baseItem.state === "PIN_NEW_AGAIN" ? qsTr("Enter your new PIN again") : qsTr("Enter your PIN") - } - } - } - - // Hidden text to calculate length of the message without word wrap - Text { - id: dummyTextMessage - font.pixelSize: message.font.pixelSize - font.bold: message.font.bold - visible: false - text: message.text - } - } - - TextInput { - id: echoField - anchors.bottom: numPad.top - anchors.bottomMargin: Utils.dp(30) - anchors.left: lines.left - horizontalAlignment: TextInput.AlignHCenter - echoMode: TextInput.Password - font.pixelSize: baseItem.state === "PUK" ? Utils.sp(15) : Utils.sp(20) - font.letterSpacing: baseItem.state === "PUK" ? Utils.dp(15) : Utils.dp(20) - passwordMaskDelay: 500 - cursorVisible: false - activeFocusOnPress: false - focus: false; - validator: RegExpValidator { - regExp: baseItem.state === "PUK" ? /[0-9]{10}/ : - baseItem.state === "PIN_OR_TRANSPORT_PIN" ? /[0-9]{5,6}/ : /[0-9]{6}/ } - - readonly property bool pinDoesNotMatch: baseItem.state === "PIN_NEW_AGAIN" && echoField.length === _checkablePin.length && echoField.text.localeCompare(_checkablePin) !== 0 - } - - TextInput { - id: dummyTextInput - anchors.left: lines.left - horizontalAlignment: TextInput.AlignHCenter - echoMode: echoField.echoMode - font.pixelSize: echoField.font.pixelSize - font.letterSpacing: echoField.font.letterSpacing - visible: false - text: "0" - } - - Row { - id: lines - anchors.bottom: numPad.top - anchors.bottomMargin: Utils.dp(26) - spacing: echoField.font.letterSpacing - - anchors.horizontalCenter: parent.horizontalCenter - - Repeater { - model: baseItem.state === "PUK" ? 10 : 6 - delegate: - Rectangle { - width: dummyTextInput.contentWidth - dummyTextInput.font.letterSpacing - height: 1 - color: "black" - } - } - } - - Grid { - id: numPad - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(30) - - anchors.horizontalCenter: parent.horizontalCenter - - columns: 3 - columnSpacing: Utils.dp(50) - rowSpacing: Utils.dp(30) - - NumPadButton { text: "1"; onClicked: numPad.enterPin(1) } - NumPadButton { text: "2"; onClicked: numPad.enterPin(2) } - NumPadButton { text: "3"; onClicked: numPad.enterPin(3) } - NumPadButton { text: "4"; onClicked: numPad.enterPin(4) } - NumPadButton { text: "5"; onClicked: numPad.enterPin(5) } - NumPadButton { text: "6"; onClicked: numPad.enterPin(6) } - NumPadButton { text: "7"; onClicked: numPad.enterPin(7) } - NumPadButton { text: "8"; onClicked: numPad.enterPin(8) } - NumPadButton { text: "9"; onClicked: numPad.enterPin(9) } - NumPadButton { source: "qrc:///images/delete.png"; onClicked: numPad.resetPin() } - NumPadButton { text: "0"; onClicked: numPad.enterPin(0) } - NumPadButton { source: "qrc:///images/submit.png"; visible: echoField.acceptableInput && !echoField.pinDoesNotMatch; - onClicked: { - switch(baseItem.state) - { - case "PIN": - /* fall through */ - case "PIN_OR_TRANSPORT_PIN": - numberModel.pin = echoField.text - _checkablePin = "" - baseItem.pinEntered() - break - - case "PIN_NEW": - baseItem.state = "PIN_NEW_AGAIN" - _checkablePin = echoField.text - break - - case "PIN_NEW_AGAIN": - numberModel.newPin = _checkablePin - _checkablePin = "" - baseItem.pinEntered() - break - - case "CAN": - numberModel.can = echoField.text - _checkablePin = "" - baseItem.pinEntered() - break - - case "PUK": - numberModel.puk = echoField.text - _checkablePin = "" - baseItem.pinEntered() - break - } - numPad.resetPin() - } - } - - function enterPin(pNum) { - echoField.insert(echoField.length, pNum) - } - - function resetPin() { - echoField.text = "" - } + PinPadButton { text: "0"; onClicked: baseItem.digitPressed("0"); Layout.fillHeight: true; Layout.fillWidth: true } + PinPadButton { + source: baseItem.submitEnabled ? "qrc:///images/submit.svg" : "" + onClicked: baseItem.submitPressed() + enabled: baseItem.submitEnabled + Layout.fillHeight: true; Layout.fillWidth: true } } diff --git a/resources/qml/PinPadButton.qml b/resources/qml/PinPadButton.qml new file mode 100644 index 0000000..fdc3a6b --- /dev/null +++ b/resources/qml/PinPadButton.qml @@ -0,0 +1,42 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "global" + +MouseArea { + id: baseItem + property alias text: textItem.text + property alias source: imageItem.source + + Text { + id: textItem + anchors.centerIn: parent + font.pixelSize: Utils.sp(24) + wrapMode: Text.WordWrap + color: "black" + } + + Image { + id: imageItem + anchors.centerIn: parent + height:Utils.dp(36) + width: height + fillMode: Image.PreserveAspectFit + } + + Rectangle { + id: darkLayer + anchors.centerIn: parent + height: width + radius: width /2 + color: "#000000" + opacity: 0.1 + SequentialAnimation on width { + running: baseItem.pressed + alwaysRunToEnd: true + NumberAnimation { from: 0; to: Math.SQRT2 * baseItem.width } + PauseAnimation { duration: 100 } + PropertyAction { value: 0} + } + } +} diff --git a/resources/qml/ProgressView.qml b/resources/qml/ProgressView.qml index 849ec84..6e5b2a3 100644 --- a/resources/qml/ProgressView.qml +++ b/resources/qml/ProgressView.qml @@ -9,6 +9,7 @@ SectionPage id: baseItem property alias text: text.text property alias subText: subText.text + property alias subTextColor: subText.color BusyIndicator { id: busyIndicator @@ -38,7 +39,6 @@ SectionPage verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pixelSize: Constants.normal_font_size - color: Constants.grey anchors.top: text.bottom anchors.topMargin: Utils.dp(10) anchors.horizontalCenter: parent.horizontalCenter diff --git a/resources/qml/ProviderContactTab.qml b/resources/qml/ProviderContactTab.qml index e605c6b..dcacac0 100644 --- a/resources/qml/ProviderContactTab.qml +++ b/resources/qml/ProviderContactTab.qml @@ -6,44 +6,7 @@ import "global" Item { id: baseItem - - property string homepage - property string phone - property string email - property string postalAddress - - - ListModel { - id: providerInfoModel - - property string homepage: baseItem.homepage - property string phone: baseItem.phone - property string email: baseItem.email - property string postalAddress: baseItem.postalAddress - - onHomepageChanged: setProperty(0, "text", '' + homepage + "") - onPhoneChanged: setProperty(1, "text", '' + phone + "") - onEmailChanged: setProperty(2, "text", '' + email + "") - onPostalAddressChanged: setProperty(3, "text", postalAddress) - - ListElement { - label: qsTr("Homepage") - text: "" - } - ListElement { - label: qsTr("Phone") - text: "" - } - ListElement { - label: qsTr("E-Mail") - text: "" - } - ListElement { - label: qsTr("Contact") - text: "" - } - } - + property alias contactModel: repeater.model Pane { id: pane @@ -51,7 +14,6 @@ Item { Repeater { id: repeater - model: providerInfoModel Item { height: info.height + Utils.dp(20) diff --git a/resources/qml/ProviderHeader.qml b/resources/qml/ProviderHeader.qml index a07f3cc..7f18bec 100644 --- a/resources/qml/ProviderHeader.qml +++ b/resources/qml/ProviderHeader.qml @@ -5,45 +5,45 @@ import "global" Rectangle { id: baseItem - property string address - property string providerIcon - property string providerImage - property color transparentColor : Constants.blue + // Properties that are set by HistoryViewPage + property var selectedProvider - width: parent.width - height: Utils.dp(160) + // Internal vars + readonly property color shadowColor: Category.displayColor(selectedProvider.category) + readonly property string backgroundImage: !!selectedProvider.image ? selectedProvider.image : Category.backgroundImageSource(selectedProvider.category) + readonly property string providerIcon: !!selectedProvider.icon ? selectedProvider.icon : Category.buttonImageSource(selectedProvider.category) + readonly property string providerAddress: selectedProvider.address + readonly property string providerShortDescription: selectedProvider.shortDescription + height: headerBackgroundImage.height + buttonText.height + Constants.pane_spacing color: Constants.background_color Image { id: headerBackgroundImage - + source: backgroundImage + height: width / 1.80 + width: parent.width + fillMode: Image.PreserveAspectCrop anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - width: parent.width - height: parent.height * 0.7 - source: providerImage - fillMode: Image.PreserveAspectCrop - } - - - Rectangle { - width: headerBackgroundImage.width - height: headerBackgroundImage.height - color: transparentColor - opacity: transparentColor === Constants.blue ? 0 : 0.7 + Rectangle { + anchors.fill: parent + color: shadowColor + opacity: shadowColor === Constants.blue ? 0 : 0.7 + } } Image { + source: providerIcon + asynchronous: true + height: Utils.dp(70) + width: height + fillMode: Image.PreserveAspectFit anchors.left: baseItem.left anchors.leftMargin: Utils.dp(30) anchors.verticalCenter: headerBackgroundImage.bottom - height: Utils.dp(70) - width: height - source: providerIcon - fillMode: Image.Stretch } Button { @@ -51,10 +51,10 @@ Rectangle { width: baseItem.width / 2 anchors.bottom: baseItem.bottom anchors.right: parent.right - anchors.rightMargin: Utils.dp(20) - text: qsTr("Online-Application") + anchors.rightMargin: Constants.component_spacing + text: qsTr("Online Application") onClicked: { - Qt.openUrlExternally(address) + Qt.openUrlExternally(providerAddress) } } } diff --git a/resources/qml/identify/ProviderInfoSection.qml b/resources/qml/ProviderInfoSection.qml similarity index 83% rename from resources/qml/identify/ProviderInfoSection.qml rename to resources/qml/ProviderInfoSection.qml index 298a00d..1f34098 100644 --- a/resources/qml/identify/ProviderInfoSection.qml +++ b/resources/qml/ProviderInfoSection.qml @@ -3,15 +3,15 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.2 import QtQuick.Controls.Styles 1.4 -import "../" -import "../global" +import "global" +import "identify" Rectangle { - property string imageSource; - property string title; - property string name; - property bool showForwardAction: true; + property string imageSource + property string title + property string name + property bool showForwardAction: true width: parent.width height: Utils.dp(40) @@ -36,7 +36,7 @@ Rectangle { anchors.right: forwardAction.right label: title - text: name + text: name.length > 0 ? name : qsTr("Touch for more details") } Text { id: forwardAction diff --git a/resources/qml/ProviderModelItem.qml b/resources/qml/ProviderModelItem.qml new file mode 100644 index 0000000..25ad730 --- /dev/null +++ b/resources/qml/ProviderModelItem.qml @@ -0,0 +1,94 @@ +import QtQuick 2.7 + + +/* + * Convenience utility to access properties of a ProviderModel item + * This ensures having always a defined string, i.e. a non-null string object. + */ +Item { + id: baseItem + property var modelItem + + readonly property string category: !!modelItem && !!modelItem.providerCategory ? modelItem.providerCategory : "" + readonly property string shortName: !!modelItem && !!modelItem.providerShortName ? modelItem.providerShortName : "" + readonly property string longName: !!modelItem && !!modelItem.providerLongName ? modelItem.providerLongName : "" + readonly property string shortDescription: !!modelItem && !!modelItem.providerShortDescription ? modelItem.providerShortDescription : "" + readonly property string longDescription: !!modelItem && !!modelItem.providerLongDescription ? modelItem.providerLongDescription : "" + readonly property string address: !!modelItem && !!modelItem.providerAddress ? modelItem.providerAddress : "" + readonly property string addressDomain: !!modelItem && !!modelItem.providerAddressDomain ? modelItem.providerAddressDomain : "" + readonly property string homepage: !!modelItem && !!modelItem.providerHomepage ? modelItem.providerHomepage : "" + readonly property string homepageBase: !!modelItem && !!modelItem.providerHomepageBase ? modelItem.providerHomepageBase : "" + readonly property string phone: !!modelItem && !!modelItem.providerPhone ? modelItem.providerPhone : "" + readonly property string phoneCost: !!modelItem && !!modelItem.providerPhoneCost ? modelItem.providerPhoneCost : "" + readonly property string email: !!modelItem && !!modelItem.providerEmail ? modelItem.providerEmail : "" + readonly property string postalAddress: !!modelItem && !!modelItem.providerPostalAddress ? modelItem.providerPostalAddress : "" + readonly property string icon: !!modelItem && !!modelItem.providerIcon ? modelItem.providerIcon : "" + readonly property string image: !!modelItem && !!modelItem.providerImage ? modelItem.providerImage : "" + + readonly property ListModel contactModel: ListModel { + readonly property alias homepage: baseItem.homepage + readonly property alias email: baseItem.email + readonly property alias phone: baseItem.phone + readonly property alias phoneCost: baseItem.phoneCost + readonly property string phoneDisplayString: { + var s = "" + if (!!phone) { + s = '' + phone + "" + if (!!phoneCost) { + s += "
" + phoneCost + } + } + return s + } + readonly property alias postalAddress: baseItem.postalAddress + + function removeHtml(htmlString) { + return htmlString.replace(/<\/?[a-z][a-z0-9]*[^>]*>/ig, " "); + } + + onHomepageChanged: { + setProperty(0, "text", !!homepage ? '' + homepage + "" : "") + setProperty(0, "link", homepage) + } + onEmailChanged: { + setProperty(1, "text", !!email ? '' + email + "" : "") + setProperty(1, "link", !!email ? "mailto:" + email : "") + } + onPhoneDisplayStringChanged: { + setProperty(2, "text", phoneDisplayString) + setProperty(2, "link", !!phone? "tel:" + phone : "") + } + onPostalAddressChanged: { + setProperty(3, "text", !!postalAddress ? '' + postalAddress + "" : "") + setProperty(3, "link", !!postalAddress ? "geo:0,0?q=" + encodeURIComponent(postalAddress.replace(/\
/g,' ')) : "") + } + + ListElement { + iconSource: "qrc:///images/provider/url.png" + label: qsTr("Homepage") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/mail.png" + label: qsTr("E-Mail") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/telefon.png" + label: qsTr("Phone") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/adresse.png" + label: qsTr("Contact") + text: "" + link: "" + } + } +} diff --git a/resources/qml/ResultView.qml b/resources/qml/ResultView.qml index 13b2f54..d10c0bb 100644 --- a/resources/qml/ResultView.qml +++ b/resources/qml/ResultView.qml @@ -21,7 +21,7 @@ SectionPage { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.verticalCenter fillMode: Image.PreserveAspectFit - source: isError ? "qrc:///images/iOS/rotes_X.svg" : "qrc:///images/iOS/gruener_Haken.svg" + source: isError ? "qrc:///images/rotes_X.svg" : "qrc:///images/gruener_Haken.svg" width: Utils.dp(160) } Text { @@ -33,6 +33,7 @@ SectionPage { horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap color: Constants.blue + onLinkActivated: Qt.openUrlExternally(link) } Button { diff --git a/resources/qml/SectionPage.qml b/resources/qml/SectionPage.qml index 837750e..0ecb1c1 100644 --- a/resources/qml/SectionPage.qml +++ b/resources/qml/SectionPage.qml @@ -18,6 +18,8 @@ Item { property alias contentY: flickable.contentY property bool disableFlicking: false + onTitleBarColorChanged: titleBar.setColor(titleBarColor) + Flickable { property real startContentY: 0 id: flickable @@ -34,18 +36,6 @@ Item { } onContentYChanged: { if (disableFlicking || contentY < 0) { contentY = 0 /* prevent flicking over the top */} - - if (!headerLoader.item || typeof(headerLoader.item.stopFlickOn) === "undefined") { - return - } - if (startContentY > headerLoader.item.stopFlickOn && contentY < headerLoader.item.stopFlickOn) { - cancelFlick() - contentY = headerLoader.item.stopFlickOn - } - if (startContentY < headerLoader.item.stopFlickOn && contentY > headerLoader.item.stopFlickOn) { - cancelFlick() - contentY = headerLoader.item.stopFlickOn - } } Column { id: flickableContent diff --git a/resources/qml/SwitchToBluetooth.qml b/resources/qml/SwitchToBluetooth.qml deleted file mode 100644 index bbbf29c..0000000 --- a/resources/qml/SwitchToBluetooth.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item { - height: img.height + 2 * img.anchors.topMargin - width: img.width + text2.anchors.leftMargin + text2.width - - signal clicked - - Rectangle { - height: 1 - width: parent.width * 1.2 - anchors.horizontalCenter: parent.horizontalCenter - color: Constants.grey - } - Image { - id: img - anchors.top: parent.top - anchors.topMargin: Utils.dp(20) - height: Utils.dp(50) - fillMode: Image.PreserveAspectFit - smooth: true - source: "qrc:///images/icon_Bluetooth.svg" - } - Text { - id: dummyText - visible: false - text: qsTr("Bluetooth not supported") - font.pixelSize: Constants.normal_font_size - } - Text { - id: text1 - anchors.left: img.right - anchors.leftMargin: Utils.dp(10) - anchors.bottom: img.verticalCenter - text: applicationModel.bluetoothEnabled ? qsTr("or via") : qsTr("Bluetooth not supported") - font.pixelSize: Constants.normal_font_size - color: applicationModel.bluetoothEnabled ? "black" : Constants.red - } - Text { - id: text2 - anchors.top: img.verticalCenter - anchors.left: img.right - anchors.leftMargin: Utils.dp(10) - width: dummyText.width - text: applicationModel.bluetoothEnabled ? qsTr("Bluetooth reader") : qsTr("or switched off") - font.pixelSize: applicationModel.bluetoothEnabled ? Constants.header_font_size : Constants.normal_font_size - color: applicationModel.bluetoothEnabled ? Constants.blue : Constants.red - } - MouseArea { - id: mouseArea - anchors.fill: parent - enabled: applicationModel.bluetoothEnabled - onClicked: parent.clicked() - } -} diff --git a/resources/qml/TabBarView.qml b/resources/qml/TabBarView.qml index ff61db8..c612176 100644 --- a/resources/qml/TabBarView.qml +++ b/resources/qml/TabBarView.qml @@ -21,6 +21,8 @@ Item { id: loader asynchronous: true onLoaded: { + appWindow.hideSplashScreen() + baseItem.pushed = true push(item) @@ -30,7 +32,7 @@ Item { } baseItem.pendingItems = [] - authModel.continueWorkflow() + numberModel.continueWorkflow() } source: parent.visible ? parent.source : loader.source diff --git a/resources/qml/TechnologyInfo.qml b/resources/qml/TechnologyInfo.qml new file mode 100644 index 0000000..ac3a6c8 --- /dev/null +++ b/resources/qml/TechnologyInfo.qml @@ -0,0 +1,93 @@ +import QtQuick 2.5 + +import "global" + +Item { + id: baseItem + property alias enableText: enableInfo.text + property alias enableButtonText: enableButton.text + property alias enableButtonVisible: enableButton.visible + property alias titleText: title.text + property alias subTitleText: subTitle.text + property bool subTitleTextRedColor + + signal enableClicked() + + Text { + id: enableInfo + anchors.bottom: enableButton.top + anchors.bottomMargin: Constants.component_spacing + anchors.left: parent.left + anchors.right: parent.right + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Constants.normal_font_size + color: Constants.red + wrapMode: Text.WordWrap + visible: !!text + } + + Button { + id: enableButton + anchors.bottom: parent.bottom + anchors.bottomMargin: Constants.component_spacing + anchors.horizontalCenter: parent.horizontalCenter + onClicked: parent.enableClicked() + } + + Text { + id: title + anchors.bottom: parent.verticalCenter + anchors.bottomMargin: Constants.component_spacing + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: Constants.header_font_size + font.weight: Font.Bold + color: Constants.blue + visible: !enableInfo.visible && !enableButton.visible + + Behavior on text { + SequentialAnimation { + NumberAnimation { target: rotation; property: "angle"; to: 90; duration: 500 } + PropertyAction { target: title; property: "text" } + NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 500 } + } + } + + transform: Rotation { + id: rotation + origin.x: 0 + origin.y: title.height/2 + axis.x: 1; axis.y: 0; axis.z: 0 + angle: 0 + } + } + + Item { + anchors.left: parent.left + anchors.top: parent.verticalCenter + anchors.right: parent.right + anchors.bottom: parent.bottom + clip: true + + Text { + id: subTitle + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Constants.normal_font_size + color: "#000000" + wrapMode: Text.WordWrap + visible: !enableInfo.visible && !enableButton.visible + + Behavior on text { + SequentialAnimation { + PropertyAnimation { target: subTitle; property: "anchors.topMargin"; to: baseItem.height/2; duration: 500} + PropertyAction { target: subTitle; property: "text" } + PropertyAction { target: subTitle; property: "color"; value: baseItem.subTitleTextRedColor ? Constants.red : "#000000" } + PropertyAnimation { target: subTitle; property: "anchors.topMargin"; to: 0; duration: 500 } + } + } + } + } +} diff --git a/resources/qml/TechnologySwitchButton.qml b/resources/qml/TechnologySwitchButton.qml new file mode 100644 index 0000000..c7545e9 --- /dev/null +++ b/resources/qml/TechnologySwitchButton.qml @@ -0,0 +1,56 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "global" + +MouseArea { + property alias imageSource: img.source + property alias text: infoText.text + + height: img.height + 2 * img.anchors.topMargin + width: img.width + infoText.anchors.leftMargin + infoText.width + + Rectangle { + height: 1 + width: parent.width * 1.2 + anchors.horizontalCenter: parent.horizontalCenter + color: Constants.grey + } + Image { + id: img + sourceSize.height: 604 + anchors.top: parent.top + anchors.topMargin: Utils.dp(20) + height: Utils.dp(50) + fillMode: Image.PreserveAspectFit + smooth: true + } + Text { + id: infoText + anchors.left: img.right + anchors.leftMargin: Utils.dp(10) + anchors.verticalCenter: img.verticalCenter + font.pixelSize: Constants.normal_font_size + color: Constants.blue + } + Colorize { + id: grayLevel + source: img + anchors.fill: img + saturation: 0 + hue: 0 + lightness: 0.3 + cached: true + visible: !parent.enabled + } + Colorize { + id: grayLevel2 + source: infoText + anchors.fill: infoText + saturation: 0 + hue: 0 + lightness: 0.3 + cached: true + visible: !parent.enabled + } +} diff --git a/resources/qml/TitleBar.qml b/resources/qml/TitleBar.qml index fd61662..1f11b75 100644 --- a/resources/qml/TitleBar.qml +++ b/resources/qml/TitleBar.qml @@ -28,6 +28,10 @@ Item rightActionStack.pop(item) } + function setColor(color) { + colorStack.color = color + } + Rectangle { id: colorStack anchors.fill: parent diff --git a/resources/qml/TitleBarAction.qml b/resources/qml/TitleBarAction.qml index 4da8883..bba9593 100644 --- a/resources/qml/TitleBarAction.qml +++ b/resources/qml/TitleBarAction.qml @@ -26,18 +26,14 @@ Item id: invisibleText visible: false text: textItem.text + font.bold: textItem.font.bold font.pointSize: textItem.font.pointSize } - Text { + TitleBarText { id: textItem - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: plugin.platformStyle.indexOf("android") !== -1 ? undefined : parent.horizontalCenter - color: "white" - font.pixelSize: Constants.titlebar_font_size + anchors.horizontalCenter: parent.horizontalCenter width: Math.min(parent.width, invisibleText.contentWidth) - height: contentHeight - elide: invisibleText.contentWidth > width ? Text.ElideRight : Text.ElideNone text: root.text !== "" ? root.text : root.state === "cancel" ? qsTr("Cancel") : root.state === "edit" ? qsTr("Edit") : diff --git a/resources/qml/TitleBarText.qml b/resources/qml/TitleBarText.qml new file mode 100644 index 0000000..93dc386 --- /dev/null +++ b/resources/qml/TitleBarText.qml @@ -0,0 +1,13 @@ +import QtQuick 2.7 + +import "global" + +Text { + id: textItem + anchors.verticalCenter: parent.verticalCenter + width: parent.width + color: "white" + font.pixelSize: Constants.titlebar_font_size + maximumLineCount: 1 + elide: Text.ElideRight +} diff --git a/resources/qml/global/+android/CheckBox.qml b/resources/qml/global/+android/CheckBox.qml deleted file mode 100644 index 129f5a7..0000000 --- a/resources/qml/global/+android/CheckBox.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick 2.5 - -import "." - -Rectangle { - property bool checked - - height: Utils.dp(20) - width: height - - color: checked ? Constants.accent_color : "white" - border.color: checked ? Constants.accent_color : "black" - border.width: Utils.dp(2) - radius: Utils.dp(2) - - - Canvas { - id:canvas - anchors.fill: parent - anchors.margins: Utils.dp(3) - visible: checked - onPaint:{ - var ctx = canvas.getContext('2d'); - ctx.beginPath(); - ctx.moveTo(0, width/2); - ctx.lineWidth = Utils.dp(2); - ctx.lineTo(2*width/5, height-ctx.lineWidth); - ctx.lineTo(width, 0); - ctx.strokeStyle = "white" - ctx.stroke(); - } - } -} diff --git a/resources/qml/global/+android/GCheckBox.qml b/resources/qml/global/+android/GCheckBox.qml new file mode 100644 index 0000000..e6dc792 --- /dev/null +++ b/resources/qml/global/+android/GCheckBox.qml @@ -0,0 +1,50 @@ +import QtQuick 2.7 + +import "." + +Item { + property alias checked: box.checked + property alias text: description.text + + height: Utils.dp(20) + width: row.width + + Row { + id: row + height: parent.height + spacing: Utils.dp(6) + + Rectangle { + id: box + property bool checked + + height: parent.height + width: height + + color: enabled ? (checked ? Constants.accent_color : "white") : Constants.grey + border.color: checked ? Constants.accent_color : "black" + border.width: Utils.dp(2) + radius: Utils.dp(2) + + Image { + source: "qrc:///images/check.svg" + anchors.fill: parent + anchors.margins: Utils.dp(3) + fillMode: Image.PreserveAspectFit + visible: checked && enabled + } + } + + Text { + id: description + visible: text !== "" + anchors.verticalCenter: box.verticalCenter + font.pixelSize: Constants.normal_font_size + } + } + + MouseArea { + anchors.fill: row + onClicked: if (enabled) box.checked = !box.checked + } +} diff --git a/resources/qml/global/+android/LabeledText.qml b/resources/qml/global/+android/LabeledText.qml index cd680bd..d8c743b 100644 --- a/resources/qml/global/+android/LabeledText.qml +++ b/resources/qml/global/+android/LabeledText.qml @@ -5,6 +5,7 @@ import "." Item { property alias label: labelText.text property alias text: bodyText.text + property alias textFormat: bodyText.textFormat property int margin property int fontUppercase @@ -32,7 +33,7 @@ Item { anchors.leftMargin: margin anchors.right: parent.right anchors.rightMargin: margin - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.label_font_size color: Constants.blue wrapMode: Text.WordWrap } diff --git a/resources/qml/global/+android/Pane.qml b/resources/qml/global/+android/Pane.qml index 8421a26..1c7706b 100644 --- a/resources/qml/global/+android/Pane.qml +++ b/resources/qml/global/+android/Pane.qml @@ -8,22 +8,18 @@ Rectangle { id: root property alias title: titleText.text default property alias paneChildren: paneContent.children - readonly property real margin: Utils.dp(20) - readonly property real spacing: Utils.dp(20) anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: Utils.dp(10) - anchors.rightMargin: Utils.dp(10) height: childrenRect.height color: "white" - radius: 10 + radius: 16 Column { anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: root.margin - anchors.rightMargin: root.margin + anchors.leftMargin: Constants.pane_padding + anchors.rightMargin: Constants.pane_padding Text { id: titleText @@ -34,13 +30,13 @@ Rectangle { font.pixelSize: Constants.header_font_size color: Constants.blue } - Item { width: parent.width; height: root.margin } + Item { width: parent.width; height: Constants.pane_padding } Column { id: paneContent width: parent.width - spacing: root.spacing + spacing: Constants.pane_spacing } - Item { width: parent.width; height: root.margin } + Item { width: parent.width; height: Constants.pane_padding } } layer.enabled: true diff --git a/resources/qml/global/+android/PlatformConstants.qml b/resources/qml/global/+android/PlatformConstants.qml index 727828b..2a603e8 100644 --- a/resources/qml/global/+android/PlatformConstants.qml +++ b/resources/qml/global/+android/PlatformConstants.qml @@ -13,6 +13,7 @@ Item { readonly property color white_primary_text: "#ffffff" readonly property color dark_grey_secondary_text: "#444444" readonly property color grey_light: "#bbbbbb" + readonly property color grey_border: "lightslategrey" readonly property color all_image_background_color: "#dcebf6" readonly property color blue: blue_primary diff --git a/resources/qml/global/Category.js b/resources/qml/global/Category.js index f615ae1..6a55b97 100644 --- a/resources/qml/global/Category.js +++ b/resources/qml/global/Category.js @@ -1,52 +1,54 @@ +function getTableValue(table, key, defaultValue) { + return key in table ? table[key] : defaultValue +} + + +var CATEGORY_TO_DISPLAY_STRING = { + "": qsTr("Provider"), + "all": qsTr("All"), + "citizen": qsTr("Citizen services"), + "insurance": qsTr("Insurances"), + "finance": qsTr("Financials"), + "other": qsTr("Other services") +} + +function displayString(cat) { + return getTableValue(CATEGORY_TO_DISPLAY_STRING, cat, "") +} + + +var CATEGORY_COLOR_NONE = "#659bcd" var CATEGORY_COLOR_ALL = "#659bcd" var CATEGORY_COLOR_CITIZEN = "#aa4079" var CATEGORY_COLOR_INSURANCE = "#52539f" var CATEGORY_COLOR_FINANCE = "#ecc758" var CATEGORY_COLOR_OTHER = "#00868e" -function displayString(cat) { - if (cat === "all") { - return qsTr("Provider") - } - if (cat === "citizen") { - return qsTr("Citizen services") - } - if (cat === "insurance") { - return qsTr("Insurances") - } - if (cat === "finance") { - return qsTr("Financials") - } - return qsTr("Other services") +var CATEGORY_TO_COLOR = { + "": CATEGORY_COLOR_ALL, + "all": CATEGORY_COLOR_ALL, + "citizen": CATEGORY_COLOR_CITIZEN, + "insurance": CATEGORY_COLOR_INSURANCE, + "finance": CATEGORY_COLOR_FINANCE, + "other": CATEGORY_COLOR_OTHER } function displayColor(cat) { - if (cat === "all") { - return CATEGORY_COLOR_ALL - } - if (cat === "citizen") { - return CATEGORY_COLOR_CITIZEN - } - if (cat === "insurance") { - return CATEGORY_COLOR_INSURANCE - } - if (cat === "finance") { - return CATEGORY_COLOR_FINANCE - } - return CATEGORY_COLOR_OTHER + return getTableValue(CATEGORY_TO_COLOR, cat, CATEGORY_COLOR_NONE) } var CATEGORY_TO_IMAGE_NAME = { - "all": "General", "citizen": "CitizenServices", "insurance": "Insurances", - "finance": "Financials" + "finance": "Financials", + "other": "OtherServices", + "all": "General", + "": "General" } - function imageName(cat) { - return cat in CATEGORY_TO_IMAGE_NAME ? CATEGORY_TO_IMAGE_NAME[cat] : "OtherServices" + return getTableValue(CATEGORY_TO_IMAGE_NAME, cat, "General") } @@ -55,7 +57,6 @@ function getPlatform() { } - function gradientImageSource(cat) { if (cat !== "citizen" && cat !== "insurance" && cat !== "finance") { return "qrc:///images/provider/gradient-other.png" @@ -67,20 +68,20 @@ function gradientImageSource(cat) { function backgroundImageSource(cat) { - return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_bg.png" + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_bg.svg" } function buttonImageSource(cat) { - return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_button.png" + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_button.svg" } function imageSource(cat) { - return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + ".png" + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + ".svg" } function sectionImageSource(cat) { - return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_section.png" + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_section.svg" } diff --git a/resources/qml/global/Constants.qml b/resources/qml/global/Constants.qml index 422a65e..3f300cb 100644 --- a/resources/qml/global/Constants.qml +++ b/resources/qml/global/Constants.qml @@ -23,9 +23,11 @@ Item { readonly property int header_font_size: Utils.sp(22) readonly property int normal_font_size: Utils.sp(16) + readonly property int label_font_size: Utils.sp(14) readonly property int small_font_size: Utils.sp(12) readonly property int titlebar_height: Utils.dp(48) + readonly property int titlebar_padding: Utils.dp(12) readonly property int titlebar_font_size: PlatformConstants.titlebar_font_size readonly property int menubar_width: Utils.dp(60) @@ -41,5 +43,8 @@ Item { readonly property int button_height: PlatformConstants.button_height readonly property int tabbar_height: Utils.dp(48) - readonly property int tabbar_font_size: Utils.sp(10) + + readonly property int component_spacing: Utils.dp(20) + readonly property int pane_padding: Utils.dp(20) + readonly property int pane_spacing: Utils.dp(20) } diff --git a/resources/qml/global/CheckBox.qml b/resources/qml/global/GCheckBox.qml similarity index 100% rename from resources/qml/global/CheckBox.qml rename to resources/qml/global/GCheckBox.qml diff --git a/resources/qml/global/GTextField.qml b/resources/qml/global/GTextField.qml new file mode 100644 index 0000000..12ae727 --- /dev/null +++ b/resources/qml/global/GTextField.qml @@ -0,0 +1,35 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +import "." + +Item { + property alias text: field.text + property alias displayText: field.displayText + property alias echoMode: field.echoMode + signal accepted + + property bool valid: true + + height: Utils.dp(24) + width: Utils.dp(240) + + Rectangle { + radius: Utils.dp(6) + anchors.fill: parent + border.color: Constants.red + color: enabled ? "white" : Constants.grey + border.width: valid ? 0 : Utils.dp(2) + } + + TextField { + id: field + anchors.fill: parent + anchors.leftMargin: Utils.dp(6) + anchors.rightMargin: Utils.dp(6) + font.pixelSize: Constants.normal_font_size + onAccepted: parent.accepted() + } + + onActiveFocusChanged: if (focus) field.forceActiveFocus() +} diff --git a/resources/qml/global/LabeledText.qml b/resources/qml/global/LabeledText.qml index 14abdf6..aa045f5 100644 --- a/resources/qml/global/LabeledText.qml +++ b/resources/qml/global/LabeledText.qml @@ -5,6 +5,7 @@ import "." Item { property alias label: labelText.text property alias text: bodyText.text + property alias textFormat: bodyText.textFormat property int margin property int fontUppercase @@ -19,7 +20,7 @@ Item { anchors.leftMargin: margin anchors.right: parent.right anchors.rightMargin: margin - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.normal_font_size color: Constants.blue wrapMode: Text.WordWrap } diff --git a/resources/qml/history/+android/+tablet/HistoryView.qml b/resources/qml/history/+android/+tablet/HistoryView.qml index 1c6e7ed..f23067b 100644 --- a/resources/qml/history/+android/+tablet/HistoryView.qml +++ b/resources/qml/history/+android/+tablet/HistoryView.qml @@ -14,25 +14,24 @@ SectionPage { headerTitleBarAction: TitleBarAction { text: qsTr("History"); font.bold: true } - HistoryViewBackground { - visible: listView.count !== 0 - } - Text { anchors.centerIn: parent text: qsTr("Currently there are no history entries.") wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size visible: listView.count === 0 } ListView { id: listView anchors.fill: parent - anchors.topMargin: Utils.dp(5) - model: historyModel - spacing: Utils.dp(10) + onContentYChanged: { + if (contentY < 0) { + // prevent flicking over the top + contentY = 0 + } + } delegate: HistoryListViewDelegate { @@ -40,7 +39,8 @@ SectionPage { anchors.left: parent.left anchors.right: parent.right height: Utils.dp(120) - property var modelItem: model + property var historyModelItem: model + listModel: historyModel showDetail: false } } diff --git a/resources/qml/history/+android/CustomSwipeBar.qml b/resources/qml/history/+android/CustomSwipeBar.qml index 9c9a95f..107a5e0 100644 --- a/resources/qml/history/+android/CustomSwipeBar.qml +++ b/resources/qml/history/+android/CustomSwipeBar.qml @@ -16,6 +16,11 @@ QtControls.TabBar { QtControls.TabButton { id: firstButton padding: Utils.dp(10) + // TODO: Workaround, use contentItem when switching to Qt 5.7.1 + // See https://bugreports.qt.io/browse/QTBUG-50992 + text: qsTr("CONTACT") + +/* contentItem: Text { text: qsTr("Contact") font.pixelSize: Constants.normal_font_size @@ -26,11 +31,17 @@ QtControls.TabBar { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } +*/ } QtControls.TabButton { padding: Utils.dp(10) + // TODO: Workaround, use contentItem when switching to Qt 5.7.1 + // See https://bugreports.qt.io/browse/QTBUG-50992 + text: qsTr("HISTORY") + +/* contentItem: Text { text: qsTr("History") font.capitalization: Font.AllUppercase @@ -41,5 +52,6 @@ QtControls.TabBar { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } +*/ } } diff --git a/resources/qml/history/+android/HistoryDetails.qml b/resources/qml/history/+android/HistoryDetails.qml index a16cd20..feec155 100644 --- a/resources/qml/history/+android/HistoryDetails.qml +++ b/resources/qml/history/+android/HistoryDetails.qml @@ -1,15 +1,13 @@ -import QtQuick 2.5 - -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.0 import "../global" Item { id: baseItem - property string providerAddress: "" - - property int listItemIndex: -1 + property string providerAddress + property int listItemIndex property var listModel @@ -21,10 +19,8 @@ Item { width: parent.height * 0.3 Image { - anchors.centerIn: parent - height: parent.height - width: parent.width - source: "qrc:///images/android/navigation/versionsinformation.png" + anchors.fill: parent + source: "qrc:///images/android/navigation/versionsinformation.svg" fillMode: Image.PreserveAspectFit clip: true @@ -33,26 +29,64 @@ Item { MouseArea { anchors.fill: parent onClicked: { - popUp.popup() + popUp.open() } } - Menu { + Popup { id: popUp + x: - (width - baseItem.width) + padding: 0 + focus: true + modal: true + dim: false - MenuItem { - text: qsTr("Delete") - onTriggered: { - if (typeof(listModel) === "object") { - listModel.removeRows(listItemIndex, 1) + onClosed: navBar.close() + + contentItem: Column { + id: content + + Rectangle { + color: mouseArea.pressed ? "grey" : "lightgrey" + height: Math.max(menuText1.height, menuText2.height) + width: Math.max(menuText1.width, menuText2.width) + Text { + id: menuText1 + padding: Utils.dp(10) + text: qsTr("Delete") + font.pixelSize: Constants.normal_font_size + } + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: { + if (typeof(listModel) === "object") { + listModel.removeRows(listItemIndex, 1) + } + } } } - } - MenuItem { - text: qsTr("Go to online application") - onTriggered: { - Qt.openUrlExternally(providerAddress) + Rectangle { + color: mouseArea2.pressed ? "grey" : "lightgrey" + height: Math.max(menuText1.height, menuText2.height) + width: Math.max(menuText1.width, menuText2.width) + Text { + id: menuText2 + padding: Utils.dp(10) + text: qsTr("Go to online application") + font.pixelSize: Constants.normal_font_size + onLinkActivated: parent.triggered(link) + } + + MouseArea { + id: mouseArea2 + anchors.fill: parent + onClicked: { + Qt.openUrlExternally(providerAddress) + } + } + } } } diff --git a/resources/qml/history/+android/HistoryItemImage.qml b/resources/qml/history/+android/HistoryItemImage.qml index 4b46b47..5549ca2 100644 --- a/resources/qml/history/+android/HistoryItemImage.qml +++ b/resources/qml/history/+android/HistoryItemImage.qml @@ -3,35 +3,48 @@ import QtQuick 2.5 import "../global" Item { + id: baseItem + property string imageUrl: "" - id: baseItem + readonly property int imageMargin: Utils.dp(10) anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom height: parent.height - width: Utils.dp(60) + width: Utils.dp(80) + Rectangle { + id: background + anchors.centerIn: parent + height: parent.height - 2 * parent.imageMargin + width: parent.width - 2 * parent.imageMargin + color: historyModelItem ? Category.displayColor(historyModelItem.providerCategory) : Category.displayColor("unknown" ) + + visible: baseItem.imageUrl !== "" + } Image { - id: backgroundImage + id: categoryImage anchors.centerIn: parent - height: parent.height - width: parent.width - source: modelItem ? Category.sectionImageSource(modelItem.provider_category) : Category.sectionImageSource("unknown") + height: parent.height - 2 * parent.imageMargin + width: parent.width - 2 * parent.imageMargin + source: historyModelItem ? Category.sectionImageSource(historyModelItem.providerCategory) : Category.sectionImageSource("unknown") + asynchronous: true clip: true + + visible: baseItem.imageUrl === "" } Image { id: foregroundImage source: baseItem.imageUrl - anchors.verticalCenter: backgroundImage.verticalCenter - anchors.left: backgroundImage.left - anchors.right: backgroundImage.right - anchors.leftMargin: Utils.dp(5) - anchors.rightMargin: Utils.dp(5) + anchors.fill: background + anchors.margins: parent.imageMargin + asynchronous: true + visible: baseItem.imageUrl !== "" fillMode: Image.PreserveAspectFit } diff --git a/resources/qml/history/+android/HistoryListViewDelegate.qml b/resources/qml/history/+android/HistoryListViewDelegate.qml index d451865..3f86cd9 100644 --- a/resources/qml/history/+android/HistoryListViewDelegate.qml +++ b/resources/qml/history/+android/HistoryListViewDelegate.qml @@ -1,44 +1,24 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 +import QtQuick 2.7 import "../" import "../global" -Item { - id: baseItem - - property bool showDetail: false - property var listModel - - width: parent.width +Rectangle { + property alias showDetail: contentItem.showDetail + property alias listModel: contentItem.listModel + HistoryListViewDelegateContent { + id: contentItem + height: parent.height - borderLine.height + width: parent.width + anchors.top: parent.top + } Rectangle { - id: root - - anchors.left: parent.left - anchors.leftMargin: Utils.dp(10) - anchors.right: parent.right - anchors.rightMargin: Utils.dp(10) - - height: parent.height - - layer.enabled: true - layer.effect: DropShadow { - radius: 4 - samples: 8 - source: root - color: Constants.grey - verticalOffset: 2 - } - - HistoryListViewDelegateContent { - showDetail: baseItem.showDetail - listModel: baseItem.listModel - - width: parent.width - height: parent.height - } + id: borderLine + color: "black" + height: Utils.dp(1) + width: parent.width + anchors.top: contentItem.bottom + anchors.bottom: parent.bottom } } diff --git a/resources/qml/history/+android/HistoryView.qml b/resources/qml/history/+android/HistoryView.qml index d3c6c27..1729da0 100644 --- a/resources/qml/history/+android/HistoryView.qml +++ b/resources/qml/history/+android/HistoryView.qml @@ -13,25 +13,24 @@ SectionPage { headerTitleBarAction: TitleBarAction { text: qsTr("History"); font.bold: true } - HistoryViewBackground { - visible: listView.count !== 0 - } - Text { anchors.centerIn: parent text: qsTr("Currently there are no history entries.") wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size visible: listView.count === 0 } ListView { id: listView anchors.fill: parent - anchors.topMargin: Utils.dp(5) - model: historyModel - spacing: Utils.dp(10) + onContentYChanged: { + if (contentY < 0) { + // prevent flicking over the top + contentY = 0 + } + } delegate: HistoryListViewDelegate { @@ -39,7 +38,8 @@ SectionPage { anchors.left: parent.left anchors.right: parent.right height: Utils.dp(120) - property var modelItem: model + listModel: historyModel + property var historyModelItem: model showDetail: false } } diff --git a/resources/qml/history/+android/HistoryViewBackground.qml b/resources/qml/history/+android/HistoryViewBackground.qml deleted file mode 100644 index 644d186..0000000 --- a/resources/qml/history/+android/HistoryViewBackground.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Canvas { - id: canvas - anchors.fill: parent - property real start_x: parent.width / 2 - property real start_y: 0 - property real end_x: parent.width / 2 - property real end_y: height - property bool dashed: true - property real dash_length: Utils.dp(3) - property real dash_space: Utils.dp(5) - property real line_width: Utils.dp(1) - property real stipple_length: (dash_length + dash_space) > 0 ? (dash_length + dash_space) : 8 - property color draw_color: Constants.blue - - onPaint: { - // Get the drawing context - var ctx = canvas.getContext('2d') - // set line color - ctx.strokeStyle = draw_color; - ctx.lineWidth = line_width; - ctx.beginPath(); - - if (!dashed) - { - ctx.moveTo(start_x,start_y); - ctx.lineTo(end_x,end_y); - } - else - { - var dashLen = stipple_length; - var dX = end_x - start_x; - var dY = end_y - start_y; - var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen); - if (dashes == 0) - { - dashes = 1; - } - var dash_to_length = dash_length/dashLen - var space_to_length = 1 - dash_to_length - var dashX = dX / dashes; - var dashY = dY / dashes; - var x1 = start_x; - var y1 = start_y; - - ctx.moveTo(x1,y1); - - var q = 0; - while (q++ < dashes) { - x1 += dashX*dash_to_length; - y1 += dashY*dash_to_length; - ctx.lineTo(x1, y1); - x1 += dashX*space_to_length; - y1 += dashY*space_to_length; - ctx.moveTo(x1, y1); - - } - - } - - ctx.stroke(); - - } -} diff --git a/resources/qml/history/HistoryItemImage.qml b/resources/qml/history/HistoryItemImage.qml index 8445e45..37f1869 100644 --- a/resources/qml/history/HistoryItemImage.qml +++ b/resources/qml/history/HistoryItemImage.qml @@ -14,13 +14,13 @@ Item { width: Utils.dp(40) Image { - anchors.centerIn: parent - height: parent.height * 0.6 - width: height source: baseItem.imageUrl !== "" ? baseItem.imageUrl : - (modelItem ? Category.imageSource(modelItem.provider_category) : Category.imageSource("unknown")) - + (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown")) + asynchronous: true + height: parent.height * 0.6 + width: height fillMode: Image.PreserveAspectFit + anchors.centerIn: parent } } diff --git a/resources/qml/history/HistoryListView.qml b/resources/qml/history/HistoryListView.qml index 24a10cb..0b5fb8f 100644 --- a/resources/qml/history/HistoryListView.qml +++ b/resources/qml/history/HistoryListView.qml @@ -1,16 +1,18 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 as Controls +import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import "../global" Item { id: baseItem + property alias listViewModel: listView.model property bool selectable: false property var selectedIndices: [] property Component delegate + readonly property int contentHeight: listView.contentHeight function requestDeletion(index) { selectedIndices.push(index) @@ -55,6 +57,7 @@ Item { focus: true clip: true spacing: Utils.dp(5) + interactive: false delegate: Item { id: delegateItem @@ -104,7 +107,7 @@ Item { width: delegateItem.width height: delegateItem.height - Controls.CheckBox { + CheckBox { id: checkBox width: Utils.dp(40) height: parent.height @@ -118,7 +121,7 @@ Item { anchors.right: parent.right height: Constants.history_section_height sourceComponent: baseItem.delegate - property var modelItem: model + property var historyModelItem: model } states: [ diff --git a/resources/qml/history/HistoryListViewDelegate.qml b/resources/qml/history/HistoryListViewDelegate.qml index 485d9fe..c86cbd9 100644 --- a/resources/qml/history/HistoryListViewDelegate.qml +++ b/resources/qml/history/HistoryListViewDelegate.qml @@ -11,8 +11,6 @@ Item { id: baseItem - width: parent.width - HistoryListViewDelegateContent { showDetail: baseItem.showDetail listModel: baseItem.listModel diff --git a/resources/qml/history/HistoryListViewDelegateContent.qml b/resources/qml/history/HistoryListViewDelegateContent.qml index 71ca9b6..575ba75 100644 --- a/resources/qml/history/HistoryListViewDelegateContent.qml +++ b/resources/qml/history/HistoryListViewDelegateContent.qml @@ -5,34 +5,31 @@ import QtQuick.Controls.Styles 1.4 import "../global" Item { - property bool showDetail: false - - property var listModel - id: baseItem - width: parent.width - - HistoryItemImage { - id: categoryImage - imageUrl: modelItem ? modelItem.provider_icon : "" - visible: !showDetail - } + property bool showDetail: false + property var listModel Rectangle { id: background color: "white" - anchors.left: showDetail ? parent.left : categoryImage.right - anchors.leftMargin: showDetail ? Utils.dp(5) : 0 + anchors.left: parent.left + anchors.leftMargin: Utils.dp(5) anchors.right: parent.right anchors.rightMargin: Utils.dp(5) anchors.top: parent.top anchors.bottom: parent.bottom + HistoryItemImage { + id: categoryImage + imageUrl: historyModelItem ? historyModelItem.providerIcon : "" + visible: !showDetail + } + Rectangle { anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Utils.dp(3) + anchors.left: showDetail ? parent.left : categoryImage.right + anchors.leftMargin: showDetail ? Utils.dp(5) : 0 anchors.right: detailsLink.left Column { @@ -46,60 +43,97 @@ Item { id: dateTimeText verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.label_font_size font.capitalization: Font.AllUppercase color: Constants.blue text: { - if (!modelItem) { - return ""; + if (!historyModelItem) { + return "" } - else if (Utils.isToday(modelItem.dateTime)) { + else if (Utils.isToday(historyModelItem.dateTime)) { return qsTr("today") } - else if (Utils.isYesterday(modelItem.dateTime)) { + else if (Utils.isYesterday(historyModelItem.dateTime)) { return qsTr("yesterday") } - else if (Utils.isThisWeek(modelItem.dateTime)) { - return modelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) + else if (Utils.isThisWeek(historyModelItem.dateTime)) { + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) } - return modelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) } } Text { id: subjectText + anchors.left: parent.left + anchors.right: parent.right verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(14) - elide: Text.ElideRight - text: modelItem ? modelItem.subject : "" + font.pixelSize: Constants.label_font_size + wrapMode: Text.WordWrap + text: historyModelItem ? historyModelItem.subject : "" } Text { - id: addressText + id: purposeText + anchors.left: parent.left + anchors.right: parent.right verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(11) + font.pixelSize: Constants.small_font_size color: Constants.history_delegate_address_color - elide: Text.ElideRight - text: modelItem ? modelItem.provider_address_domain : "" + wrapMode: Text.WordWrap + text: !!historyModelItem.purpose ? historyModelItem.purpose : qsTr("Touch for more details") } } } MouseArea { anchors.fill: parent - onClicked: { - if(showDetail) { - push(detailsHistoryView, {modelItem: modelItem}) - } else { - push(providerHistoryView, { modelItem: modelItem}) + onClicked: if (showDetail) { + push(detailsHistoryView, { historyModelItem: historyModelItem }) + } + else { + historyModel.nameFilter.setProviderAddress(historyModelItem.providerAddress) + push(providerHistoryView, { historyModelItem: historyModelItem }) + } + } + + Item { + id: detailsInfoLink + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + height: Utils.dp(16) + width: height + + visible: showDetail + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + height: Utils.dp(16) + + border.color: PlatformConstants.grey_light + border.width: 1 + radius: height + + color: PlatformConstants.grey_light + Text { + anchors.centerIn: parent + + text: "i" + font.bold: true + color: Constants.primary_text } } } HistoryDetails { id: detailsLink - providerAddress: modelItem ? modelItem.provider_address : "" - listItemIndex: modelItem ? modelItem.index : -1 + providerAddress: historyModelItem ? historyModelItem.providerAddress : "" + listItemIndex: historyModelItem ? historyModelItem.index : -1 listModel: baseItem.listModel visible: !showDetail } diff --git a/resources/qml/history/HistoryView.qml b/resources/qml/history/HistoryView.qml index 6422751..baeb73f 100644 --- a/resources/qml/history/HistoryView.qml +++ b/resources/qml/history/HistoryView.qml @@ -62,7 +62,7 @@ SectionPage { anchors.centerIn: parent text: qsTr("Currently there are no history entries.") wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size visible: historyListView.count === 0 } diff --git a/resources/qml/history/HistoryViewDetails.qml b/resources/qml/history/HistoryViewDetails.qml index 31f22e7..b872808 100644 --- a/resources/qml/history/HistoryViewDetails.qml +++ b/resources/qml/history/HistoryViewDetails.qml @@ -1,63 +1,66 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.0 import QtQuick.Layouts 1.2 - import "../" import "../global" SectionPage { id: root - property var modelItem + property var historyModelItem leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: modelItem ? modelItem.subject : ""; font.bold: true } - titleBarColor: Category.displayColor(modelItem ? modelItem.provider_category : "") + headerTitleBarAction: TitleBarAction { text: historyModelItem ? historyModelItem.subject : ""; font.bold: true } + titleBarColor: Category.displayColor(historyModelItem ? historyModelItem.providerCategory : "") - content: Column { + content: Item { + height: pane.height + 2 * Constants.component_spacing width: root.width - Item { width: parent.width; height: Utils.dp(10)} - Pane { - id: pane - title: qsTr("Provider Information") + Column { + anchors.fill: parent + anchors.margins: Constants.component_spacing - LabeledText { - label: qsTr("Provider name") - text: modelItem ? modelItem.subject : "" - width: parent.width - } + Pane { + id: pane + title: qsTr("Provider Information") - LabeledText { - label: qsTr("Purpose") - text: modelItem ? modelItem.purpose : "" - width: parent.width - } - - LabeledText { - label: qsTr("Date") - text:{ - if (!modelItem) { - return ""; - } - return modelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + LabeledText { + label: qsTr("Provider name") + text: historyModelItem ? historyModelItem.subject : "" + width: parent.width } - width: parent.width - fontUppercase: Font.AllUppercase - } - LabeledText { - label: qsTr("Requested data") - text: modelItem ? modelItem.requestedData : "" - width: parent.width - } + LabeledText { + label: qsTr("Purpose") + text: historyModelItem ? historyModelItem.purpose : "" + width: parent.width + } - LabeledText { - label: qsTr("Terms of usage") - text: modelItem ? modelItem.termsOfUsage : "" - width: parent.width + LabeledText { + label: qsTr("Date") + text:{ + if (!historyModelItem) { + return ""; + } + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + } + width: parent.width + fontUppercase: Font.AllUppercase + } + + LabeledText { + label: qsTr("Requested data") + text: historyModelItem ? historyModelItem.requestedData : "" + width: parent.width + } + + LabeledText { + label: qsTr("Terms of usage") + text: historyModelItem ? historyModelItem.termsOfUsage : "" + width: parent.width + } } } } - } diff --git a/resources/qml/history/HistoryViewPage.qml b/resources/qml/history/HistoryViewPage.qml index a4a7f2b..e26651b 100644 --- a/resources/qml/history/HistoryViewPage.qml +++ b/resources/qml/history/HistoryViewPage.qml @@ -1,36 +1,33 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.6 import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 as QtControls +import QtQuick.Controls 2.0 import "../" import "../global" SectionPage { id: baseItem - - property var modelItem + property var historyModelItem + readonly property real headerHeight: Utils.dp(200) + ProviderModelItem { + id: provider + modelItem: baseItem.historyModelItem + } leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: modelItem ? modelItem.subject : ""; font.bold: true } - titleBarColor: modelItem ? Category.displayColor(modelItem.provider_category) : "" + headerTitleBarAction: TitleBarAction { text: historyModelItem ? historyModelItem.subject : ""; font.bold: true } + titleBarColor: !!provider.category ? Category.displayColor(provider.category) : "" - readonly property real headerHeight: Utils.dp(200) header: ProviderHeader { id: providerHeader width: baseItem.width - height: headerHeight - - address: modelItem ? modelItem.provider_address : "" - providerIcon: !modelItem ? "" : modelItem.provider_icon !== "" ? modelItem.provider_icon : Category.buttonImageSource(modelItem.provider_category) - providerImage: !modelItem ? "" : modelItem.provider_image !== "" ? modelItem.provider_image : Category.backgroundImageSource(modelItem.provider_category) - transparentColor: modelItem ? Category.displayColor(modelItem.provider_category) : "" + selectedProvider: provider } content: Item { + height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing width: baseItem.width - height: baseItem.height CustomSwipeBar { id: swipeBar @@ -40,49 +37,43 @@ SectionPage { } Rectangle { - anchors.fill: swipeView - color: Constants.background_color - } - - QtControls.SwipeView { - id: swipeView + id: swipeViewBackground anchors.top: swipeBar.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - width: baseItem.width - currentIndex: swipeBar.currentIndex - clip: true + anchors.horizontalCenter: swipeBar.horizontalCenter + height: swipeView.height + 2 * Constants.component_spacing + width: parent.width - Item { - Rectangle { - anchors.fill: parent + SwipeView { + id: swipeView + height: Math.max(providerInfo.contentHeight, detailsHistoryListView.contentHeight) + anchors.margins: Constants.component_spacing + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right - ProviderContactTab { - anchors.fill: parent + currentIndex: swipeBar.currentIndex + clip: true - homepage: modelItem ? modelItem.provider_homepage : "" - phone: modelItem ? modelItem.provider_phone : "" - email: modelItem ? modelItem.provider_email : "" - postalAddress: modelItem ? modelItem.provider_postaladdress : "" - } - } - } - - HistoryListView { - id: detailsHistoryListView - - onVisibleChanged: { - if (visible) { - historyModel.filter.setFilterFixedString(modelItem.subject) - } + ProviderContactTab { + id: providerInfo + contactModel: provider.contactModel } - listViewModel: historyModel.filter - delegate: HistoryListViewDelegate { - id: detailsHistoryDelegate - showDetail: true - listModel: historyModel.filter + HistoryListView { + id: detailsHistoryListView + + onVisibleChanged: { + if (visible) { + historyModel.filter.setFilterFixedString(historyModelItem.subject) + } + } + + listViewModel: historyModel.filter + delegate: HistoryListViewDelegate { + id: detailsHistoryDelegate + showDetail: true + listModel: historyModel.filter + } } } } diff --git a/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml b/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml index fdbe4db..828b819 100644 --- a/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml +++ b/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml @@ -1,108 +1,142 @@ import QtQuick 2.5 +import ".." import "../global" + Item { - height: Math.max(requireddata.height, optionaldata.height, providerinformation.height) + Utils.dp(40) + id: root + height: infoPane.height + 2 * Constants.component_spacing Column { - id: requireddata + id: infoPane anchors.top: parent.top - anchors.topMargin: Utils.dp(20) anchors.left: parent.left - anchors.leftMargin: Utils.dp(20) - width: (parent.width - Utils.dp(60)) / 3 - - Pane { - width: parent.width - - DataGroup{ - title: qsTr("Required Data") - chat: chatModel.required - } - } - } - - Column { - id: optionaldata - anchors.top: parent.top - anchors.topMargin: Utils.dp(20) - anchors.horizontalCenter: parent.horizontalCenter - width: (parent.width - Utils.dp(60)) / 3 - - spacing: Utils.dp(30) - - Pane { - anchors.left: parent.left - anchors.right: parent.right - Column { - anchors.left: parent.left - anchors.right: parent.right - - ProviderInfoSection { - imageSource: "qrc:///images/iOS/ProviderPurpose.png" - title: qsTr("Purpose for reading out requested data") - name: certificateDescriptionModel.purpose - showForwardAction: false - } - } - } - Button { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Identify now") - onClicked: { - if (applicationModel.currentWorkflow === "") { - selfAuthenticationModel.startWorkflow(); - } - else if (applicationModel.currentWorkflow === "authentication") { - chatModel.transferAccessRights() - authModel.continueWorkflow() - } - } - } - - Pane { - width: parent.width - - DataGroup { - title: qsTr("Optional Data") - chat: chatModel.optional - } - } - } - - Column { - id: providerinformation - anchors.top: parent.top - anchors.topMargin: Utils.dp(20) anchors.right: parent.right - anchors.rightMargin: Utils.dp(20) - width: (parent.width - Utils.dp(60)) / 3 + anchors.margins: Constants.component_spacing + + spacing: Constants.pane_spacing Pane { - id: pane - Text { - height: implicitHeight * 2 - verticalAlignment: Text.AlignVCenter - text: qsTr("Provider Information") - color: Constants.blue - font.pixelSize: Constants.header_font_size - elide: Text.ElideRight + Row { + height: providerEntries.height + width: parent.width + spacing: Constants.pane_spacing + + Item { + height: providerEntries.height + width: (parent.width - Constants.pane_spacing) / 2 + + Column { + id: providerEntries + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + spacing: Constants.pane_spacing + + ProviderInfoSection { + imageSource: "qrc:///images/provider/information.svg" + title: qsTr("Service provider") + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + name: certificateDescriptionModel.purpose + } + } + + MouseArea { + anchors.fill: parent + onClicked: push(certificateDescriptionPage) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false + } + } + + + Item { + height: parent.height + width: (parent.width - Constants.pane_spacing) / 2 + + Button { + id: button + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + text: qsTr("Identify now") + onClicked: { + if (applicationModel.currentWorkflow === "") { + selfAuthenticationModel.startWorkflow(); + } + else if (applicationModel.currentWorkflow === "authentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + } + } + } } + } - Repeater { - id: listView - model: certificateDescriptionModel + Pane { + Column { + height: childrenRect.height + width: parent.width + spacing: Utils.dp(30) + + Column { + id: transactionInfo - LabeledText { - id: delegate - label: model.label - text: model.text width: parent.width + visible: !!transactionInfoText.text + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: qsTr("Transactional information") + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } + + Text { + id: transactionInfoText + + width: parent.width + font.pixelSize: Constants.normal_font_size + text: authModel.transactionInfo + wrapMode: Text.WordWrap + } + } + + Row { + width: parent.width + spacing: Constants.pane_spacing + + DataGroup { + id: requiredData + width: optionalData.visible ? parent.width * 0.63 : parent.width + + title: qsTr("Required Data") + columns: optionalData.visible ? 2 : 3 + chat: chatModel.required + } + + DataGroup { + id: optionalData + width: parent.width * 0.37 - Constants.pane_spacing + + title: qsTr("Optional Data") + chat: chatModel.optional + } } } } } } - diff --git a/resources/qml/identify/+android/DataGroup.qml b/resources/qml/identify/+android/DataGroup.qml index 87e6f7d..28aa72b 100644 --- a/resources/qml/identify/+android/DataGroup.qml +++ b/resources/qml/identify/+android/DataGroup.qml @@ -10,23 +10,22 @@ import "../global" Rectangle { id: root property string title; + property int columns: 1 property var chat width: parent.width height: column.height - color: "white" + visible: repeater.count > 0 Column { id: column - anchors.verticalCenter: parent.verticalCenter + anchors.top: parent.top anchors.left: parent.left - anchors.leftMargin: Utils.dp(20) anchors.right: parent.right - anchors.rightMargin: anchors.leftMargin Text { - height: implicitHeight * 2 - verticalAlignment: Text.AlignVCenter + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop text: title color: Constants.blue font.pixelSize: Constants.header_font_size @@ -41,8 +40,8 @@ Rectangle { id: emptyText anchors.verticalCenter: parent.verticalCenter width: parent.width - font.pixelSize: Utils.sp(14) - text: qsTr("No data available") + font.pixelSize: Constants.normal_font_size + text: qsTr("No data requested") } Rectangle { anchors.top: parent.bottom @@ -53,47 +52,61 @@ Rectangle { } } - Repeater { - id: repeater - model: chat - visible: repeater.count > 0 + Grid { + id: grid + columns: root.columns + columnSpacing: Constants.pane_spacing + width: parent.width + verticalItemAlignment: Grid.AlignBottom + + Repeater { + id: repeater + model: chat + visible: repeater.count > 0 - Rectangle { - width: parent.width - height: Utils.dp(40) - color: "white" - Text { - id: text - anchors.verticalCenter: parent.verticalCenter - width: parent.width - font.pixelSize: Utils.sp(14) - text: name - } Rectangle { - anchors.top: parent.bottom - anchors.topMargin: -height - height: 1 - width: parent.width - color: Constants.grey - } - CheckBox { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: optional - checked: selected - } + width: (grid.width - ((grid.columns - 1) * grid.columnSpacing)) / grid.columns + height: Utils.dp(40) + color: "white" + + Text { + id: text + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: checkBox.left + font.pixelSize: Constants.normal_font_size + text: name + wrapMode: Text.WordWrap + } - MouseArea { - anchors.fill: parent - enabled: optional - onClicked: selected = !selected Rectangle { - anchors.centerIn: parent - width: root.width - height: parent.height - color: Constants.accent_color - opacity: parent.pressed ? 0.5 : 0 - Behavior on opacity { NumberAnimation { duration: 100 } } + anchors.top: parent.bottom + anchors.topMargin: -height + height: 1 + width: parent.width + color: Constants.grey + } + + GCheckBox { + id: checkBox + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + visible: optional + checked: selected + } + + MouseArea { + anchors.fill: parent + enabled: optional + onClicked: selected = !selected + Rectangle { + anchors.centerIn: parent + width: root.width + height: parent.height + color: Constants.accent_color + opacity: parent.pressed ? 0.5 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + } } } } diff --git a/resources/qml/identify/+android/IdentifyViewContent.qml b/resources/qml/identify/+android/IdentifyViewContent.qml index c34bd75..d34b5d6 100644 --- a/resources/qml/identify/+android/IdentifyViewContent.qml +++ b/resources/qml/identify/+android/IdentifyViewContent.qml @@ -1,39 +1,69 @@ import QtQuick 2.5 +import ".." import "../global" + Item { height: identifycolumn.height + Utils.dp(30) Column { id: identifycolumn anchors.top: parent.top - anchors.topMargin: Utils.dp(20) anchors.left: parent.left anchors.right: parent.right + anchors.margins: Constants.component_spacing - spacing: Utils.dp(30) + spacing: Constants.component_spacing Pane { - width: parent.width - Column { - anchors.left: parent.left - anchors.right: parent.right + Item { + width: parent.width + height: providerEntries.height - ProviderInfoSection { - imageSource: "qrc:///images/iOS/ProviderInformation.png" - title: qsTr("Service provider") - name: certificateDescriptionModel.subjectName + Column { + id: providerEntries + anchors.top: parent.top + anchors.left: parent.left + anchors.right: forwardAction.left + spacing: Constants.pane_spacing + + ProviderInfoSection { + imageSource: "qrc:///images/provider/information.svg" + title: qsTr("Service provider") + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + name: certificateDescriptionModel.purpose + } } - ProviderInfoSection { - imageSource: "qrc:///images/iOS/ProviderPurpose.png" - title: qsTr("Purpose for reading out requested data") - name: certificateDescriptionModel.purpose - showForwardAction: false + + Text { + id: forwardAction + anchors.right: parent.right + anchors.verticalCenter: providerEntries.verticalCenter + + text: ">" + font.pixelSize: Utils.sp(22) + color: Constants.grey + } + + MouseArea { + anchors.fill: parent + onClicked: push(certificateDescriptionPage) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false } } } + Button { anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Identify now") @@ -43,7 +73,7 @@ Item { } else if (applicationModel.currentWorkflow === "authentication") { chatModel.transferAccessRights() - authModel.continueWorkflow() + numberModel.continueWorkflow() } } } @@ -51,20 +81,40 @@ Item { Pane { width: parent.width - DataGroup{ + Column { + id: transactionInfo + + width: parent.width + visible: !!transactionInfoText.text + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: qsTr("Transactional information") + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } + + Text { + id: transactionInfoText + + width: parent.width + font.pixelSize: Constants.normal_font_size + text: authModel.transactionInfo + wrapMode: Text.WordWrap + } + } + + DataGroup { title: qsTr("Required Data") chat: chatModel.required } - } - Pane { - width: parent.width - - DataGroup{ + DataGroup { title: qsTr("Optional Data") chat: chatModel.optional } } } } - diff --git a/resources/qml/identify/+android/IdentifyViewHeader.qml b/resources/qml/identify/+android/IdentifyViewHeader.qml index e25dc90..d51a2d4 100644 --- a/resources/qml/identify/+android/IdentifyViewHeader.qml +++ b/resources/qml/identify/+android/IdentifyViewHeader.qml @@ -12,7 +12,6 @@ Item { id: header /* this is interpreted by the SectionPage component */ readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : 0 - readonly property int stopFlickOn: Constants.titlebar_height Image { id: dna @@ -31,16 +30,13 @@ Item { anchors.fill: parent color: Constants.blue opacity: Math.min(1, 0.5 + parent.transition() * 0.5) - Behavior on opacity { - NumberAnimation {} - } } } Item { id: information height: Math.max(npa.height, text.height) - anchors.margins: Utils.dp(15) + anchors.margins: Constants.component_spacing anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -52,18 +48,18 @@ Item { height: Utils.dp(60) width: height - source: "qrc:///images/npa.ico" + source: "qrc:///images/npa.svg" } Text { id: text anchors.verticalCenter: npa.verticalCenter anchors.left: npa.right - anchors.leftMargin: Utils.dp(15) + anchors.leftMargin: Constants.component_spacing anchors.right: parent.right text: (applicationModel.currentWorkflow !== "authentication") ? qsTr("Hello, here you have the opportunity to view the stored data on your identity card.") : - qsTr("Hello, \"%1\", wants to read your data").arg(certificateDescriptionModel.subjectName) + qsTr("Hello, \"%1\" wants to read your data.").arg(certificateDescriptionModel.subjectName) wrapMode: Text.WordWrap font.pixelSize: Constants.normal_font_size } diff --git a/resources/qml/identify/+android/ProviderInfoSection.qml b/resources/qml/identify/+android/ProviderInfoSection.qml deleted file mode 100644 index 92f049d..0000000 --- a/resources/qml/identify/+android/ProviderInfoSection.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 -import QtQuick.Controls.Styles 1.4 - -import "../" -import "../global" - -Rectangle { - - property string imageSource; - property string title; - property string name; - property bool showForwardAction: true; - - width: parent.width - height: Utils.dp(60) - color: "white" - clip: true - - Image { - id: image - anchors.verticalCenter: parent.verticalCenter - - height: parent.height - width: parent.width * 0.15 - - source: imageSource - fillMode: Image.PreserveAspectFit - } - LabeledText { - id: providerTitle - anchors.verticalCenter: image.verticalCenter - anchors.left: image.right - anchors.right: forwardAction.right - - label: title - text: name - } - Text { - id: forwardAction - anchors.right: parent.right - anchors.rightMargin: Utils.dp(18) - anchors.verticalCenter: parent.verticalCenter - - text: ">" - font.pixelSize: Utils.sp(22) - color: Constants.grey - visible: showForwardAction - } - - MouseArea { - anchors.fill: parent - enabled: showForwardAction - onClicked: push(certificateDescriptionPage, {providerName: name}) - } - - CertificateDescriptionPage { - id: certificateDescriptionPage - visible: false - } -} diff --git a/resources/qml/identify/CertificateDescriptionPage.qml b/resources/qml/identify/CertificateDescriptionPage.qml index f6368b4..cc22eef 100644 --- a/resources/qml/identify/CertificateDescriptionPage.qml +++ b/resources/qml/identify/CertificateDescriptionPage.qml @@ -10,33 +10,43 @@ SectionPage { id: root leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: name } + headerTitleBarAction: TitleBarAction { text: name; font.bold: true } - content: Column { + property string name + + content: Item + { + height: pane.height + 2 * Constants.component_spacing width: root.width - Item { width: parent.width; height: Utils.dp(10)} - Pane { - id: pane + Column + { + anchors.fill: parent + anchors.margins: Constants.component_spacing - Text { - height: implicitHeight * 2 - verticalAlignment: Text.AlignVCenter - text: qsTr("Provider Information") - color: Constants.blue - font.pixelSize: Constants.header_font_size - elide: Text.ElideRight - } + Pane { + id: pane - Repeater { - id: listView - model: certificateDescriptionModel + Text { + height: implicitHeight * 2 + verticalAlignment: Text.AlignVCenter + text: qsTr("Provider Information") + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } - LabeledText { - id: delegate - label: model.label - text: model.text - width: parent.width + Repeater { + id: listView + model: certificateDescriptionModel + + LabeledText { + id: delegate + label: model.label + text: model.text + textFormat: Text.PlainText + width: parent.width + } } } } diff --git a/resources/qml/identify/DataGroup.qml b/resources/qml/identify/DataGroup.qml index 0e2ab51..1b0470e 100644 --- a/resources/qml/identify/DataGroup.qml +++ b/resources/qml/identify/DataGroup.qml @@ -24,7 +24,7 @@ Item { verticalAlignment: Text.AlignVCenter text: title color: Constants.grey - font.pixelSize: Utils.sp(12) + font.pixelSize: Constants.header_font_size font.capitalization: Font.AllUppercase elide: Text.ElideRight } @@ -48,8 +48,11 @@ Item { anchors.left: parent.left anchors.leftMargin: Utils.dp(20) anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: anchors.leftMargin + anchors.right: checkBox.left width: parent.width - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap text: name } Rectangle { @@ -60,7 +63,8 @@ Item { anchors.right: dataGroup.right color: Constants.grey } - CheckBox { + GCheckBox { + id: checkBox anchors.right: parent.right anchors.rightMargin: Utils.dp(20) anchors.verticalCenter: parent.verticalCenter diff --git a/resources/qml/identify/EnterPinView.qml b/resources/qml/identify/EnterPinView.qml deleted file mode 100644 index fa93e61..0000000 --- a/resources/qml/identify/EnterPinView.qml +++ /dev/null @@ -1,22 +0,0 @@ -import QtQuick 2.5 - -import ".." -import "../global" - -SectionPage -{ - property alias state: pinpad.state - - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify") } - - PinPad { - id: pinpad - anchors.fill: parent - - onPinEntered: { - authModel.continueWorkflow() - identifyView.push(identifyProgressView) - } - } -} diff --git a/resources/qml/identify/IdentifyController.qml b/resources/qml/identify/IdentifyController.qml index ca19f56..b0b8057 100644 --- a/resources/qml/identify/IdentifyController.qml +++ b/resources/qml/identify/IdentifyController.qml @@ -1,12 +1,31 @@ import QtQuick 2.5 -import QtQml.StateMachine 1.0 import "../" Item { id: controller + readonly property string statePrefix: readerType === "BLUETOOTH" ? "bt_" : "nfc_" property string readerType + property bool showRemoveCardFeedback: false + + states: [ + State { + when: authModel.currentState === "StateGetTcToken" && !connectivityManager.networkInterfaceActive + StateChangeScript { + script: identifyView.push(checkConnectivityView) + } + }, + State { + when: authModel.currentState === "StateGetTcToken" && connectivityManager.networkInterfaceActive + StateChangeScript { + script: { + identifyView.push(identifyProgressView) + numberModel.continueWorkflow() + } + } + } + ] Connections { target: authModel @@ -16,31 +35,36 @@ Item { break; case "StateGetTcToken": enterPinView.state = "INITIAL" - identifyView.push(identifyProgressView) navBar.lockedAndHidden = true navBar.state = "identify" navBar.currentIndex = 0 - setIdentifyWorkflowStateAndContinue("initial") - break; + identifyWorkflow.state = "initial" + break case "StateEditAccessRights": if (applicationModel.currentWorkflow === "selfauthentication") { identifyView.push(identifyWorkflow) chatModel.transferAccessRights() - authModel.continueWorkflow() + numberModel.continueWorkflow() } if (applicationModel.currentWorkflow === "authentication") { identifyView.push(identifyEditChatView) } + readerType = Qt.platform.os === "android" ? "NFC" : "PCSC" + break + case "StateSelectReaderType": + authModel.setReaderType(readerType); + setIdentifyWorkflowStateAndContinue("initial") break case "StateSelectNfcReader": - readerType = "nfc_" identifyView.push(identifyWorkflow) setIdentifyWorkflowStateAndContinue("connect") break case "StateSelectBluetoothReader": - readerType = "bt_" identifyView.push(identifyWorkflow) - setIdentifyWorkflowStateAndContinue("connect") + setIdentifyWorkflowState("connect") + if (applicationModel.bluetoothEnabled && !applicationModel.locationPermissionRequired) { + numberModel.continueWorkflow() + } break case "StateConnectCard": setIdentifyWorkflowStateAndContinue("card") @@ -54,15 +78,27 @@ Item { case "StateEstablishPacePin": setIdentifyWorkflowStateAndRequestInput("identify_enterpin", "PIN") break + case "StateEstablishPacePuk": + authModel.cancelWorkflowOnPinBlocked() + break + case "StateCleanUpReaderManager": + controller.showRemoveCardFeedback = numberModel.cardConnected && !authModel.isError; + numberModel.continueWorkflow() + break; case "FinalState": navBar.lockedAndHidden = true + if (controller.showRemoveCardFeedback) { + controller.showRemoveCardFeedback = false + qmlExtension.showFeedback(qsTr("You may now remove your ID card from the device.")) + } + if (authModel.error) identifyView.push(identifyResult) else { if (applicationModel.currentWorkflow === "selfauthentication") { identifyView.push(selfAuthenticationData) } else { - authModel.continueWorkflow() + numberModel.continueWorkflow() titleBar.reset() identifyView.pop(null) navBar.lockedAndHidden = false @@ -70,22 +106,26 @@ Item { } break default: - authModel.continueWorkflow() + numberModel.continueWorkflow() } } } + function setIdentifyWorkflowState(pState) { + identifyWorkflow.state = statePrefix + pState + } + function setIdentifyWorkflowStateAndContinue(pState) { - identifyWorkflow.state = readerType + pState - authModel.continueWorkflow() + setIdentifyWorkflowState(pState); + numberModel.continueWorkflow() } function setIdentifyWorkflowStateAndRequestInput(pState, pInput) { - identifyWorkflow.state = readerType + pState + identifyWorkflow.state = statePrefix + pState if (authModel.isBasicReader()) { identifyView.push(enterPinView, {state: pInput}) } else { - authModel.continueWorkflow() + numberModel.continueWorkflow() } } } diff --git a/resources/qml/identify/IdentifyView.qml b/resources/qml/identify/IdentifyView.qml index a40509d..eae8b83 100644 --- a/resources/qml/identify/IdentifyView.qml +++ b/resources/qml/identify/IdentifyView.qml @@ -23,7 +23,9 @@ SectionPage width: identifyEditChatView.width } - IdentifyController {} + IdentifyController { + id: identifyController + } SelfAuthenticationData { id: selfAuthenticationData @@ -37,7 +39,14 @@ SectionPage EnterPinView { id: enterPinView + leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") } visible: false + + onPinEntered: { + numberModel.continueWorkflow() + identifyView.push(identifyProgressView) + } } ProgressView { @@ -49,13 +58,23 @@ SectionPage subText: qsTr("Please wait a moment...") } + ProgressView { + id: checkConnectivityView + leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } + visible: false + text: qsTr("No network connectivity") + subText: qsTr("Please enable the network interface or cancel the workflow.") + subTextColor: Constants.red + } + ResultView { id: identifyResult headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } isError: authModel.resultString text: authModel.resultString onClicked: { - authModel.continueWorkflow() + numberModel.continueWorkflow() titleBar.reset() identifyView.pop(null) navBar.lockedAndHidden = false diff --git a/resources/qml/identify/IdentifyViewContent.qml b/resources/qml/identify/IdentifyViewContent.qml index 05ed4f0..1cb328b 100644 --- a/resources/qml/identify/IdentifyViewContent.qml +++ b/resources/qml/identify/IdentifyViewContent.qml @@ -1,20 +1,22 @@ import QtQuick 2.5 +import ".." import "../global" + Column{ spacing: Utils.dp(30) Column { width: parent.width ProviderInfoSection { - imageSource: "qrc:///images/iOS/ProviderInformation.png" + imageSource: "qrc:///images/provider/information.svg" title: qsTr("Service provider") name: certificateDescriptionModel.subjectName SeparatorLine {} } ProviderInfoSection { - imageSource: "qrc:///images/iOS/ProviderPurpose.png" + imageSource: "qrc:///images/provider/purpose.svg" title: qsTr("Purpose for reading out requested data") name: certificateDescriptionModel.purpose showForwardAction: false @@ -30,7 +32,7 @@ Column{ } else if (applicationModel.currentWorkflow === "authentication") { chatModel.transferAccessRights() - authModel.continueWorkflow() + numberModel.continueWorkflow() } } } diff --git a/resources/qml/identify/IdentifyViewHeader.qml b/resources/qml/identify/IdentifyViewHeader.qml index 92fa668..6ca24a5 100644 --- a/resources/qml/identify/IdentifyViewHeader.qml +++ b/resources/qml/identify/IdentifyViewHeader.qml @@ -38,7 +38,7 @@ Rectangle { height: Utils.dp(50) width: height - source: "qrc:///images/npa.ico" + source: "qrc:///images/npa.svg" fillMode: Image.Stretch } @@ -53,7 +53,7 @@ Rectangle { text: applicationModel.currentWorkflow !== "authentication" ? qsTr("Hello, here you have the") : qsTr("Hello,") wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size } Text { @@ -68,9 +68,9 @@ Rectangle { text: applicationModel.currentWorkflow !== "authentication" ? qsTr("opportunity to view the stored data on your identity card.") : - qsTr("\"%1\",
wants to read your data").arg(certificateDescriptionModel.subjectName) + qsTr("\"%1\"
wants to read your data").arg(certificateDescriptionModel.subjectName) wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size } } } diff --git a/resources/qml/identify/IdentifyWorkflow.qml b/resources/qml/identify/IdentifyWorkflow.qml index b90b3d7..e229d48 100644 --- a/resources/qml/identify/IdentifyWorkflow.qml +++ b/resources/qml/identify/IdentifyWorkflow.qml @@ -16,8 +16,8 @@ SectionPage state: parent.state visible: parent.state.indexOf("nfc_") === 0 onAbortNfc: { + identifyController.readerType = "BLUETOOTH" authModel.abortCardSelection() - authModel.setReaderType("BLUETOOTH"); } } @@ -27,5 +27,9 @@ SectionPage anchors.fill: parent state: parent.state visible: parent.state.indexOf("bt_") === 0 + onAbortBluetooth: { + identifyController.readerType = "NFC" + authModel.abortCardSelection() + } } } diff --git a/resources/qml/identify/SelfAuthenticationData.qml b/resources/qml/identify/SelfAuthenticationData.qml index 9132d61..c78246f 100644 --- a/resources/qml/identify/SelfAuthenticationData.qml +++ b/resources/qml/identify/SelfAuthenticationData.qml @@ -1,4 +1,4 @@ -import QtQuick 2.5 +import QtQuick 2.7 import "../" import "../global" @@ -9,56 +9,56 @@ SectionPage { headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } function close() { - selfAuthenticationModel.continueWorkflow() + numberModel.continueWorkflow() pop(null) navBar.lockedAndHidden = false } - Item { - anchors.fill: parent + content: Item { + height: content.height + okButton.height + Constants.component_spacing + width: root.width - Item { - id: message - height: Utils.dp(120) - width: resultImage.width + successText.width - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top + Column { + id: content + width: parent.width + padding: Constants.component_spacing + spacing: Constants.component_spacing - Image { - id: resultImage - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - height: Utils.dp(100) - width: height - fillMode: Image.PreserveAspectFit - source: "qrc:///images/iOS/gruener_Haken.svg" + Item { + id: message + height: Utils.dp(60) + width: resultImage.width + Constants.component_spacing + successText.width + anchors.horizontalCenter: parent.horizontalCenter + + Image { + id: resultImage + anchors.top: parent.top + anchors.verticalCenter: parent.verticalCenter + height: parent.height + width: height + fillMode: Image.PreserveAspectFit + source: "qrc:///images/gruener_Haken.svg" + } + + Text { + id: successText + anchors.left: resultImage.right + anchors.leftMargin: Constants.component_spacing + anchors.verticalCenter: resultImage.verticalCenter + text: qsTr("Successfull reading data") + font.pixelSize: PlatformConstants.is_tablet ? Constants.header_font_size : Constants.normal_font_size + color: Constants.blue + } } - Text { - id: successText - anchors.left: resultImage.right - anchors.verticalCenter: resultImage.verticalCenter - text: qsTr("Successfull reading data") - font.pixelSize: PlatformConstants.is_tablet ? Constants.header_font_size : Constants.normal_font_size - color: Constants.blue - } - } - - Pane { - id: pane - anchors.top: message.bottom - anchors.bottom: okButton.top - anchors.bottomMargin: Utils.dp(30) - - Flickable { - id: paneflick - height: pane.height - 2 * pane.margin - width: pane.width - 2 * pane.margin - contentWidth: grid.width - contentHeight: grid.height + Pane { + id: pane + anchors.leftMargin: Constants.component_spacing + anchors.rightMargin: Constants.component_spacing Grid { id: grid + width: parent.width columns: PlatformConstants.is_tablet ? 3 : 1 spacing: Utils.dp(15) verticalItemAlignment: Grid.AlignBottom @@ -68,31 +68,20 @@ SectionPage { LabeledText { label: name text: value === "" ? "---" : value - width: (pane.width - 2 * pane.margin - (grid.columns - 1) * grid.spacing) / grid.columns + width: (pane.width - 2 * Constants.pane_padding - (grid.columns - 1) * grid.spacing) / grid.columns } } } } } + } - Image { - source: "qrc:///images/android/android_arrow_back.svg" - height: Utils.dp(60) - width: Utils.dp(60) - anchors.horizontalCenter: pane.horizontalCenter - anchors.verticalCenter: pane.top - visible: paneflick.atYBeginning && !paneflick.atYEnd && !paneflick.moving - rotation: 90 - fillMode: Image.PreserveAspectFit - } - - Button { - id: okButton - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(30) - text: qsTr("Ok") - onClicked: root.close() - } + Button { + id: okButton + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Constants.component_spacing + text: qsTr("Ok") + onClicked: root.close() } } diff --git a/resources/qml/main.qml b/resources/qml/main.qml index 1949b8b..61ae09f 100644 --- a/resources/qml/main.qml +++ b/resources/qml/main.qml @@ -14,7 +14,10 @@ ApplicationWindow { title: "Governikus AusweisApp2" color: Constants.background_color + readonly property var startTime : new Date().getTime() + property var lastCloseInvocation: 0 property int leftOverlayMargin: 0 + property var splasScreenClosed: false QtQuickControls14.Action { shortcut: "Ctrl+Alt+R" @@ -23,6 +26,7 @@ ApplicationWindow { header: TitleBar { id: titleBar + visible: splasScreenClosed titleBarOpacity: contentArea.getVisibleItem() && contentArea.getVisibleItem().stack.currentItem ? contentArea.getVisibleItem().stack.currentItem.titleBarOpacity : 1 @@ -62,6 +66,7 @@ ApplicationWindow { Navigation { id: navBar + visible: splasScreenClosed anchors.left: parent.left anchors.top: PlatformConstants.leftNavigation ? parent.top : undefined anchors.right: PlatformConstants.bottomNavigation ? parent.right : undefined @@ -69,28 +74,71 @@ ApplicationWindow { } onClosing: { - var activeStackView = contentArea.getVisibleItem().stack + var visibleItem = contentArea.getVisibleItem() - if (activeStackView.depth <= 1) { - if (navBar.isOpen) { - // FIXME: - // On Android the closing event is caught by the Drawer, so the app is never quit - plugin.fireQuitApplicationRequest() - return + if (visibleItem) + { + var activeStackView = visibleItem.stack + + if (activeStackView.depth <= 1 && (!activeStackView.currentItem.leftTitleBarAction || activeStackView.currentItem.leftTitleBarAction.state === "")) { + var currentTime = new Date().getTime(); + if( currentTime - lastCloseInvocation < 1000 ) { + plugin.fireQuitApplicationRequest() + return + } + + lastCloseInvocation = currentTime + qmlExtension.showFeedback(qsTr("Press the back button twice to close the app.")) } - else { - navBar.open() - } - } - else if (activeStackView.currentItem.leftTitleBarAction) { - if (navBar.isOpen) { - navBar.close() - } - else { - activeStackView.currentItem.leftTitleBarAction.clicked() + else if (activeStackView.currentItem.leftTitleBarAction) { + if (navBar.isOpen) { + navBar.close() + } + else { + activeStackView.currentItem.leftTitleBarAction.clicked() + } } } close.accepted = false } + + Rectangle { + id: splashScreen + anchors.fill: parent + color: appWindow.color + visible: !splasScreenClosed + + Image { + source: "qrc:/images/npa.svg" + height: appWindow.height * 0.42 + width: height + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } + } + + + function hideSplashScreen() { + if(splasScreenClosed) + { + return; + } + + contentArea.visible = false; + + var TIMEOUT = 2500; + var remaining = startTime + TIMEOUT - new Date().getTime(); + var timer = Qt.createQmlObject("import QtQuick 2.0; Timer {}", appWindow); + timer.interval = remaining > 0 ? remaining : 0; + timer.repeat = false; + timer.triggered.connect(function(){ + contentArea.visible = true + splasScreenClosed = true + if (!applicationModel.currentWorkflow) { + navBar.lockedAndHidden = false + } + }) + timer.start(); + } } diff --git a/resources/qml/more/DeveloperView.qml b/resources/qml/more/DeveloperView.qml index 36ded47..2086f8c 100644 --- a/resources/qml/more/DeveloperView.qml +++ b/resources/qml/more/DeveloperView.qml @@ -11,83 +11,87 @@ SectionPage { leftTitleBarAction: TitleBarMenuAction { state: stack.depth > 1 ? "back" : ""; onClicked: pop() } headerTitleBarAction: TitleBarAction { text: qsTr("Developer options"); font.bold: true } - - content: Column { + content: Item + { + height: pane.height + 2 * Constants.component_spacing width: root.width - Item { width: pane.width; height: pane.margin } - Pane { - id: pane - height: root.height - width: root.width - GroupBox { - title: "Change the layout style:" - height: implicitHeight - width: implicitWidth + Column + { + anchors.fill: parent + anchors.margins: Constants.component_spacing - RowLayout { - anchors.fill: parent + Pane { + id: pane - RadioButton { - text: "iOS" - checked: plugin.platformStyle === text.toLowerCase() - onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } - } - RadioButton { - text: "Android" - checked: plugin.platformStyle === text.toLowerCase() - onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } - } - RadioButton { - text: "Tablet,Android" - checked: plugin.platformStyle === text.toLowerCase() - onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } + GroupBox { + title: "Change the layout style:" + height: implicitHeight + width: implicitWidth + + RowLayout { + anchors.fill: parent + + RadioButton { + text: "iOS" + checked: plugin.platformStyle === text.toLowerCase() + onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } + } + RadioButton { + text: "Android" + checked: plugin.platformStyle === text.toLowerCase() + onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } + } + RadioButton { + text: "Tablet,Android" + checked: plugin.platformStyle === text.toLowerCase() + onCheckedChanged: if (checked) { plugin.applyPlatformStyle(text.toLowerCase()) } + } } } - } - GroupBox { - title: "Developer Mode:" - height: implicitHeight - width: implicitWidth + GroupBox { + title: "Developer Mode:" + height: implicitHeight + width: implicitWidth - RowLayout { - anchors.fill: parent + RowLayout { + anchors.fill: parent - RadioButton { - text: "Enabled" - checked: settingsModel.developerMode - onCheckedChanged: if (checked) { settingsModel.developerMode = true } - } - RadioButton { - text: "Disabled" - checked: !settingsModel.developerMode - onCheckedChanged: if (checked) { settingsModel.developerMode = false } + RadioButton { + text: "Enabled" + checked: settingsModel.developerMode + onCheckedChanged: if (checked) { settingsModel.developerMode = true } + } + RadioButton { + text: "Disabled" + checked: !settingsModel.developerMode + onCheckedChanged: if (checked) { settingsModel.developerMode = false } + } } } - } - GroupBox { - title: "Use test uri for selfauthentication:" - height: implicitHeight - width: implicitWidth + GroupBox { + title: "Use test uri for selfauthentication:" + height: implicitHeight + width: implicitWidth - RowLayout { - anchors.fill: parent + RowLayout { + anchors.fill: parent - RadioButton { - text: "Enabled" - checked: settingsModel.useSelfauthenticationTestUri - onCheckedChanged: if (checked) { settingsModel.useSelfauthenticationTestUri = true } - } - RadioButton { - text: "Disabled" - checked: !settingsModel.useSelfauthenticationTestUri - onCheckedChanged: if (checked) { settingsModel.useSelfauthenticationTestUri = false } + RadioButton { + text: "Enabled" + checked: settingsModel.useSelfauthenticationTestUri + onCheckedChanged: if (checked) { settingsModel.useSelfauthenticationTestUri = true } + } + RadioButton { + text: "Disabled" + checked: !settingsModel.useSelfauthenticationTestUri + onCheckedChanged: if (checked) { settingsModel.useSelfauthenticationTestUri = false } + } } } } } } - } diff --git a/resources/qml/more/Feedback.qml b/resources/qml/more/Feedback.qml new file mode 100644 index 0000000..b873622 --- /dev/null +++ b/resources/qml/more/Feedback.qml @@ -0,0 +1,112 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import "../" +import "../global" + + +SectionPage { + id: root + headerTitleBarAction: TitleBarAction { text: qsTr("Dialog & Feedback"); font.bold: true } + + Component { + id: lineSeparator + Rectangle { + height: 1 + color: Constants.grey + } + } + Component { + id: subMenu + Item { + height: column.height + Column { + id: column + anchors.left: parent.left + anchors.right: parent.right + spacing: Constants.component_spacing + Text { + width: parent.width + font.pixelSize: Utils.sp(18) + color: Constants.blue + wrapMode: Text.WordWrap + text: titleText + } + Text { + width: parent.width + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + text: descriptionText + } + } + MouseArea { + anchors.fill: parent + onClicked: onClickFunction() + } + } + } + + content: Item { + width: root.width + height: childrenRect.height + + Column { + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + spacing: Constants.component_spacing + padding: Constants.component_spacing + + Text { + id: title + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("Your opinion matters") + font.pixelSize: Constants.header_font_size + color: Constants.blue + wrapMode: Text.WordWrap + } + Text { + id: subtitle + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("We are happy about every feedback on our software.") + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + } + + Pane { + Loader { + readonly property string titleText: qsTr("Rate AusweisApp2") + readonly property string descriptionText: qsTr("Please rate us on the Google Play Store.") + function onClickFunction() { Qt.openUrlExternally("market://details?id=com.governikus.ausweisapp2") } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Share") + readonly property string descriptionText: qsTr("Tell your friends about AusweisApp2.") + readonly property string shareTitle: qsTr("Share with") + readonly property string share: qsTr("I'm using AusweisApp2, download it here for Android: " + + "https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2") + function onClickFunction() { qmlExtension.shareText(share, shareTitle) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Report error") + readonly property string descriptionText: qsTr("You found a bug? Please tell us, so we can fix it.") + readonly property string emailAddress: "support.ausweisapp2@governikus.de" + readonly property string emailSubject: qsTr("Android log file") + readonly property string emailBody: qsTr("") + function onClickFunction() { qmlExtension.mailLog(emailAddress, emailSubject, emailBody) } + width: parent.width + sourceComponent: subMenu + } + } + } + } +} diff --git a/resources/qml/more/Information.qml b/resources/qml/more/Information.qml new file mode 100644 index 0000000..e9d01bc --- /dev/null +++ b/resources/qml/more/Information.qml @@ -0,0 +1,118 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import "../" +import "../global" + + +SectionPage { + id: root + headerTitleBarAction: TitleBarAction { text: qsTr("Information & Help"); font.bold: true } + + Component { + id: lineSeparator + Rectangle { + height: 1 + color: Constants.grey + } + } + Component { + id: subMenu + Item { + height: column.height + Column { + id: column + anchors.left: parent.left + anchors.right: parent.right + spacing: Constants.component_spacing + Text { + width: parent.width + font.pixelSize: Utils.sp(18) + color: Constants.blue + wrapMode: Text.WordWrap + text: titleText + } + Text { + width: parent.width + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + text: descriptionText + } + } + MouseArea { + anchors.fill: parent + onClicked: onClickFunction() + } + } + } + VersionInformation { + id: versionInformationPage + visible: false + } + + content: Item { + width: root.width + height: childrenRect.height + + Column { + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + spacing: Constants.component_spacing + padding: Constants.component_spacing + + Text { + id: title + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("You need help?") + font.pixelSize: Constants.header_font_size + color: Constants.blue + wrapMode: Text.WordWrap + } + Text { + id: subtitle + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("Here you are in the right place.") + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + } + + Pane { + Loader { + readonly property string titleText: qsTr("FAQ") + readonly property string descriptionText: qsTr("Do you have questions how to use AusweisApp2?") + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/")) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Support") + readonly property string descriptionText: qsTr("You need further help?") + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/service/support/")) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Version information") + readonly property string descriptionText: qsTr("Here you can see detailed information about AusweisApp2.") + function onClickFunction() { push(versionInformationPage) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Software license") + readonly property string descriptionText: qsTr("Read the software license text on the application homepage.") + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/download/")) } + width: parent.width + sourceComponent: subMenu + } + } + } + } +} diff --git a/resources/qml/more/MoreView.qml b/resources/qml/more/MoreView.qml index f14d05a..5125aed 100644 --- a/resources/qml/more/MoreView.qml +++ b/resources/qml/more/MoreView.qml @@ -22,25 +22,25 @@ SectionPage { MoreViewMenuItem { text: qsTr("Version information") - imageSource: "qrc:///images/information.png" + imageSource: "qrc:///images/npa.svg" onClicked: push(versionInformationPage) } MoreViewMenuItem { text: qsTr("FAQ") - imageSource: "qrc:///images/more/icon_mehr_info.svg" + imageSource: "qrc:///images/iOS/more/icon_mehr_info.svg" onClicked: Qt.openUrlExternally("https://www.ausweisapp.bund.de/service/haeufig-gestellte-fragen/") } MoreViewMenuItem { text: qsTr("Support") - imageSource: "qrc:///images/more/icon_mehr_fragen.svg" + imageSource: "qrc:///images/iOS/more/icon_mehr_fragen.svg" onClicked: push(supportPage) } MoreViewMenuItem { text: qsTr("Rate app"); - imageSource: "qrc:///images/more/icon_mehr_favorit.svg"; + imageSource: "qrc:///images/iOS/more/icon_mehr_favorit.svg"; // Use Qt.platform.os here instead of platformstyle because rating market URLs on iOS doesn't work and vice versa onClicked: { if (Qt.platform.os === "android") { @@ -54,8 +54,8 @@ SectionPage { MoreViewMenuItem { text: qsTr("Share"); - imageSource: "qrc:///images/more/icon_mehr_upload.svg"; - onClicked: shareUtil.shareText(qsTr("I'm using Ausweisapp2, download it here for Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2&hl=de or here for iOS: https://itunes.apple.com/de/app/wikipedia-mobile/id324715238?mt=8"), qsTr("Share with")) + imageSource: "qrc:///images/iOS/more/icon_mehr_upload.svg"; + onClicked: qmlExtension.shareText(qsTr("I'm using Ausweisapp2, download it here for Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2&hl=de or here for iOS: https://itunes.apple.com/de/app/wikipedia-mobile/id324715238?mt=8"), qsTr("Share with")) } MoreViewMenuItem { diff --git a/resources/qml/more/VersionInformation.qml b/resources/qml/more/VersionInformation.qml index 51c105e..d3e5654 100644 --- a/resources/qml/more/VersionInformation.qml +++ b/resources/qml/more/VersionInformation.qml @@ -12,25 +12,30 @@ SectionPage leftTitleBarAction: TitleBarMenuAction { state: stack.depth > 1 ? "back" : ""; onClicked: pop() } headerTitleBarAction: TitleBarAction { text: qsTr("Version Information"); font.bold: true } - - content: Column{ + content: Item + { + height: pane.height + 2 * Constants.component_spacing width: root.width - Item { width: parent.width; height: Constants.titlebar_height } - Pane { - id: pane - width: root.width - height: childrenRect.height - Repeater { - model: versionInformationModel - LabeledText { - id: delegate - label: model.label - text: model.text - width: pane.width + Column + { + anchors.fill: parent + anchors.margins: Constants.component_spacing + + Pane { + id: pane + + Repeater { + model: versionInformationModel + + LabeledText { + id: delegate + label: model.label + text: model.text + width: pane.width + } } } } } - } diff --git a/resources/qml/pin/+android/PinViewContent.qml b/resources/qml/pin/+android/PinViewContent.qml index 29083c2..b6a98b3 100644 --- a/resources/qml/pin/+android/PinViewContent.qml +++ b/resources/qml/pin/+android/PinViewContent.qml @@ -4,26 +4,31 @@ import "../global" Item { + readonly property int spacing: (height - pinIcon.height - pinHeader.height - pinDesc.height - govButton.height - Utils.dp(40)) / 3 + Image { id: pinIcon - height: parent.height * 0.5 + height: parent.height * 0.25 width: height anchors.top: parent.top + anchors.topMargin: spacing anchors.horizontalCenter: parent.horizontalCenter fillMode: Image.PreserveAspectFit smooth: true source: "qrc:///images/icon_Pin.svg" + sourceSize.height: 256 } Text { id: pinHeader - text: qsTr("PIN") + text: qsTr("PIN Management") anchors.top: pinIcon.bottom + anchors.topMargin: spacing anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: Constants.header_font_size @@ -33,14 +38,14 @@ Item { Text { id: pinDesc + anchors.margins: Utils.dp(10) anchors.top: pinHeader.bottom - anchors.bottom: govButton.top + anchors.topMargin: Utils.dp(10) anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Here you can change your PIN.
We should add some more useful information here! This is just an example to fill a text field.") + text: qsTr("You have the opportunity to change your transport PIN into a personal PIN. You can also change the PIN at any time or unblock the PIN using the personal unblocking key (PUK). The transport PIN and the PUK can be found in the letter sent to you by your competent authority.") font.pixelSize: Constants.normal_font_size horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter width: parent.width - Utils.dp(60) wrapMode: Text.WordWrap } @@ -52,7 +57,7 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.bottomMargin: Utils.dp(30) - text: qsTr("Change Pin now") + text: qsTr("Change PIN now") onClicked: changePinModel.startWorkflow() } } diff --git a/resources/qml/pin/ChangePinController.qml b/resources/qml/pin/ChangePinController.qml index eed8446..8813ba5 100644 --- a/resources/qml/pin/ChangePinController.qml +++ b/resources/qml/pin/ChangePinController.qml @@ -6,7 +6,9 @@ import "../" Item { id: controller + readonly property string statePrefix: readerType === "BLUETOOTH" ? "bt_" : "nfc_" property string readerType + property bool showRemoveCardFeedback: false Connections { target: changePinModel @@ -15,17 +17,26 @@ Item { case "": break case "StateSelectReaderType": - pinView.pop(null) - pinView.push(pinWorkflow) + if(pinView.stack.currentItem !== pinWorkflow) + { + pinView.pop(null) + pinView.push(pinWorkflow) + readerType = Qt.platform.os === "android" ? "NFC" : "PCSC" + } navBar.lockedAndHidden = true enterPinView.state = "INITIAL" + changePinModel.setReaderType(readerType) setPinWorkflowStateAndContinue("initial") + break case "StateSelectBluetoothReader": - readerType = "bt_" - setPinWorkflowStateAndContinue("connect") + readerType = "BLUETOOTH" + setPinWorkflowState("connect") + if (applicationModel.bluetoothEnabled && !applicationModel.locationPermissionRequired) { + numberModel.continueWorkflow() + } break case "StateSelectNfcReader": - readerType = "nfc_" + readerType = "NFC" setPinWorkflowStateAndContinue("connect") break case "StateConnectCard": @@ -46,28 +57,40 @@ Item { case "StateChangePin": setPinWorkflowStateAndRequestInput("enternewpin", "PIN_NEW") break + case "StateCleanUpReaderManager": + controller.showRemoveCardFeedback = numberModel.cardConnected && changePinModel.changedPinSuccessfully; + numberModel.continueWorkflow() + break; case "FinalState": + if (controller.showRemoveCardFeedback) { + controller.showRemoveCardFeedback = false + qmlExtension.showFeedback(qsTr("You may now remove your ID card from the device.")) + } pinView.push(pinResult) navBar.lockedAndHidden = true break default: - changePinModel.continueWorkflow() + numberModel.continueWorkflow() } } } + function setPinWorkflowState(pState) { + pinWorkflow.state = statePrefix + pState + } + function setPinWorkflowStateAndContinue(pState) { - pinWorkflow.state = readerType + pState - changePinModel.continueWorkflow() + setPinWorkflowState(pState) + numberModel.continueWorkflow() } function setPinWorkflowStateAndRequestInput(pState, pInput) { - pinWorkflow.state = readerType + pState + pinWorkflow.state = statePrefix + pState if (changePinModel.isBasicReader()) { pinView.push(enterPinView, {state: pInput}) } else { - changePinModel.continueWorkflow() + numberModel.continueWorkflow() } } } diff --git a/resources/qml/pin/EnterPinView.qml b/resources/qml/pin/EnterPinView.qml deleted file mode 100644 index 8def1f5..0000000 --- a/resources/qml/pin/EnterPinView.qml +++ /dev/null @@ -1,21 +0,0 @@ -import QtQuick 2.5 - -import ".." - -SectionPage -{ - property alias state: pinpad.state - - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: changePinModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Change PIN") } - - PinPad { - id: pinpad - anchors.fill: parent - - onPinEntered: { - changePinModel.continueWorkflow() - pinView.push(pinProgressView) - } - } -} diff --git a/resources/qml/pin/PinView.qml b/resources/qml/pin/PinView.qml index 123aca6..95c4270 100644 --- a/resources/qml/pin/PinView.qml +++ b/resources/qml/pin/PinView.qml @@ -12,9 +12,11 @@ SectionPage { id: baseItem disableFlicking: true - headerTitleBarAction: TitleBarAction { text: "Pin"; font.bold: true } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } - ChangePinController {} + ChangePinController { + id: changePinControllern + } content: PinViewContent { height: baseItem.height @@ -28,11 +30,11 @@ SectionPage { ResultView { id: pinResult - headerTitleBarAction: TitleBarAction { text: qsTr("Pin"); font.bold: true } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } isError: !changePinModel.changedPinSuccessfully text: changePinModel.resultString onClicked: { - changePinModel.continueWorkflow() + numberModel.continueWorkflow() pop(null) navBar.lockedAndHidden = false } @@ -41,13 +43,20 @@ SectionPage { EnterPinView { id: enterPinView + leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: changePinModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Change PIN") } visible: false + + onPinEntered: { + numberModel.continueWorkflow() + pinView.push(pinProgressView) + } } ProgressView { id: pinProgressView leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: changePinModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Pin"); font.bold: true } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } visible: false text: qsTr("Processing...") } diff --git a/resources/qml/pin/PinViewContent.qml b/resources/qml/pin/PinViewContent.qml index 7aad8f7..195cc8c 100644 --- a/resources/qml/pin/PinViewContent.qml +++ b/resources/qml/pin/PinViewContent.qml @@ -4,14 +4,16 @@ import "../global" Item { + readonly property int spacing: (height - pinHeader.height - pinDesc.height - pinIcon.height - govButton.height - Utils.dp(40)) / 3 + Text { id: pinHeader - text: qsTr("Change Pin") + text: qsTr("PIN Management") anchors.top: parent.top + anchors.topMargin: spacing anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: Utils.dp(10) font.pixelSize: Constants.header_font_size color: Constants.blue @@ -22,14 +24,14 @@ Item { width: parent.width * 0.9 - text: qsTr("Here you can change your PIN.
We should add some more useful information here! This is just an example to fill a text field.") + text: qsTr("You have the opportunity to change your transport PIN into a personal PIN. You can also change the PIN at any time or unblock the PIN using the personal unblocking key (PUK). The transport PIN and the PUK can be found in the letter sent to you by your competent authority.") font.pixelSize: Constants.normal_font_size horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap anchors.top: pinHeader.bottom + anchors.topMargin: Utils.dp(10) anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: Utils.dp(30) } Image { @@ -38,15 +40,13 @@ Item { fillMode: Image.PreserveAspectFit smooth: true source: "qrc:///images/icon_Pin.svg" + sourceSize.height: 256 - width: parent.width * 2 + width: parent.width anchors.top: pinDesc.bottom - anchors.bottom: govButton.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.margins: 10 + anchors.topMargin: spacing + anchors.horizontalCenter: parent.horizontalCenter } Button { @@ -56,7 +56,7 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.bottomMargin: Utils.dp(30) - text: qsTr("Change Pin now") + text: qsTr("Change PIN now") onClicked: changePinModel.startWorkflow() } } diff --git a/resources/qml/pin/PinWorkflow.qml b/resources/qml/pin/PinWorkflow.qml index 05948a2..6908372 100644 --- a/resources/qml/pin/PinWorkflow.qml +++ b/resources/qml/pin/PinWorkflow.qml @@ -7,7 +7,7 @@ SectionPage { id: baseItem leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: {changePinModel.cancelWorkflow()} } - headerTitleBarAction: TitleBarAction { text: qsTr("Pin"); font.bold: true } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } NfcWorkflow { @@ -15,8 +15,8 @@ SectionPage state: parent.state visible: parent.state.indexOf("nfc_") === 0 onAbortNfc: { + changePinControllern.readerType = "BLUETOOTH" changePinModel.abortCardSelection() - changePinModel.setReaderType("BLUETOOTH"); } } @@ -26,5 +26,9 @@ SectionPage anchors.fill: parent state: parent.state visible: parent.state.indexOf("bt_") === 0 + onAbortBluetooth: { + changePinControllern.readerType = "NFC" + changePinModel.abortCardSelection() + } } } diff --git a/resources/qml/provider/+android/+tablet/AdditionalResultsCard.qml b/resources/qml/provider/+android/+tablet/AdditionalResultsCard.qml deleted file mode 100644 index dcf20c8..0000000 --- a/resources/qml/provider/+android/+tablet/AdditionalResultsCard.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 - -import "../../../global" - -Rectangle { - id: baseItem - - readonly property int sidePadding: width * 0.0512 - readonly property int headerHeight: height * 0.4752 - readonly property int infoTextHeight: height * 0.3168 - readonly property int infoTextFontSize: Constants.normal_font_size - readonly property int footerHeight: height - (headerHeight + infoTextHeight) - readonly property int borderWidth: 2 - readonly property color titleBarColor: Constants.blue - - property int totalHits: citizenItem.hits + insuranceItem.hits + financeItem.hits + otherItem.hits - - visible: totalHits > 0 - - AdditionalResultsItem { - id: citizenItem - - providerCategory: "citizen" - } - - AdditionalResultsItem { - id: insuranceItem - - providerCategory: "insurance" - } - - AdditionalResultsItem { - id: financeItem - - providerCategory: "finance" - } - - AdditionalResultsItem { - id: otherItem - - providerCategory: "other" - } - - Column { - height: baseItem.height - width: baseItem.width - anchors.centerIn: parent - - Image { - id: backgroundImage - - source: Category.backgroundImageSource("all") - height: baseItem.headerHeight - width: parent.width - fillMode: Image.Stretch - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - id: iconBackground - - anchors.centerIn: icon - height: icon.height - width: height - radius: width * 0.5 - border.width: 0 - color: Constants.all_image_background_color - } - - Image { - id: icon - source: "qrc:///images/All.png" - - anchors.horizontalCenter: backgroundImage.horizontalCenter - anchors.bottom: backgroundImage.bottom - anchors.bottomMargin: Utils.dp(20) - fillMode: Image.PreserveAspectFit - width: backgroundImage.width * 0.26 - height: width - } - } - - Rectangle { - id: textRectangle - - readonly property int infoTextFontSize: Constants.small_font_size - height: baseItem.infoTextHeight + baseItem.sidePadding - width: parent.width - - Text { - text: '' + qsTr("Additional results: ") + baseItem.totalHits + '' - - anchors.centerIn: parent - - font.bold: true - font.pixelSize: baseItem.infoTextFontSize - color: PlatformConstants.dark_grey_secondary_text - } - } - - Rectangle { - height: baseItem.footerHeight - width: parent.width - color: baseItem.titleBarColor - } - } - - MouseArea { - anchors.fill: parent - - onClicked: { - citizenItem.selectCategoryIfMatching() - insuranceItem.selectCategoryIfMatching() - financeItem.selectCategoryIfMatching() - otherItem.selectCategoryIfMatching() - } - } -} diff --git a/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml b/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml index bc8c840..7841fae 100644 --- a/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml +++ b/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml @@ -1,26 +1,70 @@ import QtQuick 2.6 +import QtQuick.Layouts 1.2 -import "../../../global" +import "../global" - -Item { +Rectangle { id: baseItem + height: column.height - property string providerCategory - property int hits: providerModel.categoryFilter.matchesForExcludedCategory(providerCategory) + property int headerHeight: 0 + property int textHeight: 0 + property int footerHeight: 0 + property int totalHits: providerModel.additionalResultCount - Connections { - target: providerModel.categoryFilter - onFireCriteriaChanged: { - hits = providerModel.categoryFilter.matchesForExcludedCategory(providerCategory) + visible: totalHits > 0 + + Column { + id: column + width: baseItem.width + + Image { + id: backgroundImage + source: Category.backgroundImageSource("all") + asynchronous: true + height: baseItem.headerHeight + width: parent.width + fillMode: Image.PreserveAspectCrop + anchors.horizontalCenter: parent.horizontalCenter + + Image { + id: icon + source: Category.imageSource("all") + asynchronous: true + height: backgroundImage.height * 0.5 + width: height + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter: backgroundImage.horizontalCenter + anchors.bottom: backgroundImage.bottom + anchors.bottomMargin: Utils.dp(20) + } + } + + Rectangle { + id: textRectangle + height: baseItem.textHeight + width: parent.width + + Text { + text: '' + qsTr("Additional results:") + " " + baseItem.totalHits + '' + + anchors.centerIn: parent + + font.bold: true + font.pixelSize: Constants.normal_font_size + color: PlatformConstants.dark_grey_secondary_text + } + } + + Rectangle { + height: baseItem.footerHeight + width: parent.width + color: Constants.blue } } - visible: false - - function selectCategoryIfMatching() { - if (baseItem.hits > 0) { - providerModel.categoryFilter.updateCategorySelection(baseItem.providerCategory, true) - } + MouseArea { + anchors.fill: parent + onClicked: providerModel.addAdditionalResultCategories() } } diff --git a/resources/qml/provider/+android/+tablet/CategoryCheckbox.qml b/resources/qml/provider/+android/+tablet/CategoryCheckbox.qml index 9b6b6cd..93115c6 100644 --- a/resources/qml/provider/+android/+tablet/CategoryCheckbox.qml +++ b/resources/qml/provider/+android/+tablet/CategoryCheckbox.qml @@ -5,59 +5,44 @@ import "../../../global" Item { id: baseItem - height: parent.height width: mainContent.width anchors.verticalCenter: parent.verticalCenter property string category: "" - property string imageSource: "" - property string text: "" - property bool checked: false - - onCheckedChanged: providerModel.categoryFilter.updateCategorySelection(category, checked) - - Connections { - target: providerModel.categoryFilter - onFireCriteriaChanged: { - baseItem.checked = providerModel.categoryFilter.isSelected(category) - } - } + property alias imageSource: icon.source + property alias text: label.text Row { id: mainContent - height: parent.height spacing: Utils.dp(5) anchors.verticalCenter: parent.verticalCenter Image { id: icon - source: baseItem.imageSource - - fillMode: Image.PreserveAspectFit height: baseItem.height * 0.7 width: height + fillMode: Image.PreserveAspectFit anchors.verticalCenter: parent.verticalCenter } Text { - text: baseItem.text - color: "black" - font.pixelSize: Utils.sp(16) + id: label + font.pixelSize: Constants.normal_font_size anchors.verticalCenter: parent.verticalCenter } - CheckBox { + GCheckBox { + id: checkbox anchors.verticalCenter: parent.verticalCenter visible: true - checked: baseItem.checked + checked: providerModel.categories.indexOf(baseItem.category) !== -1 } } MouseArea { anchors.fill: parent - enabled: true - onClicked: baseItem.checked = !baseItem.checked + onClicked: providerModel.updateCategorySelection(category, !checkbox.checked) } } diff --git a/resources/qml/provider/+android/+tablet/ProviderCard.qml b/resources/qml/provider/+android/+tablet/ProviderCard.qml index 206b1e2..8ea4121 100644 --- a/resources/qml/provider/+android/+tablet/ProviderCard.qml +++ b/resources/qml/provider/+android/+tablet/ProviderCard.qml @@ -5,91 +5,62 @@ import "../../../global" Rectangle { id: baseItem + height: column.height + color: Category.displayColor(providerModel.providerCategory) - readonly property int sidePadding: width * 0.0512 - readonly property int nameFontSize: Constants.normal_font_size - readonly property int homepageFontSize: Constants.normal_font_size + property int headerHeight: 0 + property int textHeight: 0 + property int footerHeight: 0 - readonly property int headerHeight: height * 0.4752 - readonly property int nameHeight: height * 0.3168 - readonly property int footerHeight: height - (headerHeight + nameHeight) - - property string providerCategory: "" - property string headerImage: "" - property string headerIcon: "" - property string providerName: "" - property string providerShortDescription: "" - property string providerLongDescription: "" - property string providerAddress: "" - property string providerHomepageBase: "" - property string providerEmail: "" - property string providerPhone: "" - property string providerPostalAddress: "" - - property var pushFunction: function(providerDetails) {} - - border.width: 2 - border.color: "black" + property var providerModel: null + property var pushFunction: function(model) {} Column { - height: baseItem.height + id: column width: baseItem.width Image { - source: baseItem.headerImage !== "" ? baseItem.headerImage : - Category.backgroundImageSource(baseItem.providerCategory) - + source: providerModel.providerImage !== "" ? providerModel.providerImage : + Category.backgroundImageSource(providerModel.providerCategory) + asynchronous: true height: baseItem.headerHeight width: parent.width - fillMode: Image.Stretch + fillMode: Image.PreserveAspectCrop anchors.horizontalCenter: parent.horizontalCenter } ProviderCardNameRow { - headerIcon: baseItem.headerIcon - nameHeight: baseItem.nameHeight - providerCategory: baseItem.providerCategory - sidePadding: baseItem.sidePadding + height: baseItem.textHeight + providerName: providerModel.providerLongName !== "" ? providerModel.providerLongName : providerModel.providerShortName + headerIcon: providerModel.providerIcon + providerCategory: providerModel.providerCategory } Rectangle { - color: Category.displayColor(baseItem.providerCategory) + color: Category.displayColor(providerModel.providerCategory) height: baseItem.footerHeight width: parent.width Text { - text: baseItem.providerHomepageBase + text: providerModel.providerHomepageBase anchors.centerIn: parent - leftPadding: baseItem.sidePadding - rightPadding: baseItem.sidePadding + leftPadding: Constants.pane_padding + rightPadding: Constants.pane_padding elide: Text.ElideRight maximumLineCount: 1 - font.pixelSize: baseItem.homepageFontSize + font.pixelSize: Constants.normal_font_size color: "white" + + scale: Math.min(1, parent.width / (contentWidth + leftPadding + rightPadding)) } } } MouseArea { anchors.fill: parent - onClicked: baseItem.pushFunction( - { - selectedCategory: baseItem.providerCategory, - shortName: baseItem.providerName, - longName: baseItem.providerName, - shortDescription: baseItem.providerShortDescription, - longDescription: baseItem.providerLongDescription, - address: baseItem.providerAddress, - homepage: "", - homepageBase: baseItem.providerHomepageBase, - phone: baseItem.providerPhone, - email: baseItem.providerEmail, - postalAddress: baseItem.providerPostalAddress, - providerIcon: baseItem.headerIcon, - providerImage: baseItem.headerImage - }) + onClicked: baseItem.pushFunction(providerModel) } } diff --git a/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml b/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml index e3a89a1..f09ca6a 100644 --- a/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml +++ b/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml @@ -4,59 +4,45 @@ import "../../../global" Rectangle { - id: baseItem - - readonly property int nameFontSize: Constants.small_font_size + readonly property int padding: Constants.pane_padding / 2 + property string providerName property string headerIcon property int nameHeight property string providerCategory - property int sidePadding - height: baseItem.nameHeight + baseItem.sidePadding width: parent.width - Row { - id: nameRow - + Image { + id: image + source: parent.headerIcon !== "" ? + parent.headerIcon : + Category.buttonImageSource(parent.providerCategory) + asynchronous: true height: parent.height - width: parent.width - anchors.centerIn: parent + width: height + fillMode: Image.PreserveAspectFit + anchors.top: parent.top + anchors.topMargin: -parent.padding + anchors.left: parent.left + anchors.leftMargin: parent.padding + } - leftPadding: baseItem.sidePadding - rightPadding: baseItem.sidePadding - spacing: baseItem.sidePadding * 1.3333 - - Image { - source: baseItem.headerIcon !== "" ? - baseItem.headerIcon : - Category.buttonImageSource(baseItem.providerCategory) - - fillMode: Image.PreserveAspectFit - height: width - width: nameRow.width / 3 - nameRow.spacing - anchors.top: parent.top - anchors.topMargin: -baseItem.sidePadding - } - - Text { - text: '' + providerName + '' - - property int customLineHeight: nameRow.height * 0.90 / 4 - width: nameRow.width * 2 / 3 - baseItem.sidePadding - anchors.top: parent.top - elide: Text.ElideRight - maximumLineCount: 4 - wrapMode: Text.Wrap - lineHeightMode: Text.FixedHeight - lineHeight: customLineHeight - - topPadding: (nameRow.height - 4 * customLineHeight) / 2 - rightPadding: baseItem.sidePadding - - font.bold: true - font.pixelSize: baseItem.nameFontSize - color: PlatformConstants.dark_grey_secondary_text - } + Text { + text: '' + providerName + '' + anchors.left: image.right + anchors.leftMargin: parent.padding + anchors.top: parent.top + anchors.topMargin: parent.height * 0.05 + anchors.right: parent.right + anchors.rightMargin: parent.padding + elide: Text.ElideRight + maximumLineCount: 4 + wrapMode: Text.Wrap + lineHeightMode: Text.FixedHeight + lineHeight: parent.height * 0.90 / 4 + font.bold: true + font.pixelSize: Constants.small_font_size + color: PlatformConstants.dark_grey_secondary_text } } diff --git a/resources/qml/provider/+android/+tablet/ProviderContactInfo.qml b/resources/qml/provider/+android/+tablet/ProviderContactInfo.qml index 3bc61f1..8cdcbd2 100644 --- a/resources/qml/provider/+android/+tablet/ProviderContactInfo.qml +++ b/resources/qml/provider/+android/+tablet/ProviderContactInfo.qml @@ -6,106 +6,48 @@ import "../global" Rectangle { id: baseItem + property alias contactModel: contactListView.model - height: parent.height - - readonly property int providerContactInfoItemHeight: Utils.dp(60) - - property color backgroundColor: PlatformConstants.blue - property string homepage: "" - property string email: "" - property string phone: "" - property string postalAddress: "" + onHeightChanged: { info.scalingAllowed = true; info.updateScaleFactor() } + onVisibleChanged: info.scalingAllowed = visible Column { - height: parent.height - width: parent.width + id: info + width: baseItem.width / info.scaleFactor // fill whole width + transform: Scale { yScale: info.scaleFactor; xScale: info.scaleFactor } + property bool scalingAllowed: true + property real scaleFactor: 1 + + function updateScaleFactor() { + if (scalingAllowed) { + scalingAllowed = false; // just scale once to prevent flickering of height and a corresponding deadlock + scaleFactor = height > 0 && baseItem.height > 0 ? baseItem.height/height : 1 + } + } + onHeightChanged: info.updateScaleFactor() Text { - id: contactText text: qsTr("Contact") - - padding: Utils.dp(19) + padding: Constants.component_spacing font.pixelSize: Constants.header_font_size color: "white" } - - Flickable { - id: info - height: parent.height - contactText.height - width: parent.width - - contentHeight: baseItem.providerContactInfoItemHeight * 4 + 3 - contentWidth: width - - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.StopAtBounds - - Item { - height: info.contentHeight + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + height: contactListView.height + ListView { + id: contactListView width: parent.width - - Rectangle { - anchors.fill: infoTable - color: baseItem.backgroundColor - } - - Column { - id: infoTable - - height: info.contentHeight - width: parent.width - anchors.centerIn: parent - - ProviderContactInfoItem { - height: baseItem.providerContactInfoItemHeight - backgroundColor: baseItem.backgroundColor - imageSource: Utils.providerIconSource("url") - itemText: baseItem.homepage - } - - Rectangle { - anchors.left: infoTable.left - height: 1 - width: parent.width - color: "white" - } - - ProviderContactInfoItem { - height: baseItem.providerContactInfoItemHeight - backgroundColor: baseItem.backgroundColor - imageSource: Utils.providerIconSource("mail") - itemText: baseItem.email - } - - Rectangle { - anchors.left: infoTable.left - height: 1 - width: parent.width - color: "white" - } - - ProviderContactInfoItem { - height: baseItem.providerContactInfoItemHeight - backgroundColor: baseItem.backgroundColor - imageSource: Utils.providerIconSource("telefon") - itemText: baseItem.phone - } - - Rectangle { - anchors.left: infoTable.left - height: 1 - width: parent.width - color: "white" - } - - ProviderContactInfoItem { - height: baseItem.providerContactInfoItemHeight - backgroundColor: baseItem.backgroundColor - imageSource: Utils.providerIconSource("adresse") - itemText: baseItem.postalAddress - } + height: contentHeight + interactive: false + spacing: 2 + delegate: ProviderContactInfoItem { + width: contactListView.width + color: baseItem.color + imageSource: Qt.resolvedUrl(model.iconSource) + itemText: !!model.text ? model.text : qsTr("Unknown") + link: model.link } } } diff --git a/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml b/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml index fab5b16..f44f1ac 100644 --- a/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml +++ b/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml @@ -3,61 +3,43 @@ import QtQuick 2.6 import "../global" -Item { +Rectangle { id: baseItem + property alias imageSource: image.source + property alias itemText: text.text + property url link + height: Math.max(Utils.dp(60), text.height + Utils.dp(10)) - property color backgroundColor: PlatformConstants.blue - property string imageSource: "" - property string itemText: "" - - width: parent.width - - Rectangle { - anchors.fill: itemRow - color: baseItem.backgroundColor - } - - Row { - id: itemRow - + Item { + id: iconItem height: parent.height - width: parent.width - padding: Utils.dp(10) - spacing: Utils.dp(10) + width: Math.min(height, Utils.dp(60)) + anchors.left: parent.left - Rectangle { - height: parent.height - width: height - color: baseItem.backgroundColor - anchors.verticalCenter: parent.verticalCenter - - Image { - source: baseItem.imageSource - - height: width - width: parent.width * 0.5 - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - - } + Image { + id: image + width: parent.width * 0.5 + height: width + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit } + } + Text { + id: text + anchors.left: iconItem.right + anchors.leftMargin: Utils.dp(10) + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Constants.normal_font_size + color: "white" + linkColor: color + elide: Text.ElideRight + wrapMode: Text.WordWrap + } - Rectangle { - height: parent.height - width: parent.width - parent.height - color: baseItem.backgroundColor - anchors.verticalCenter: parent.verticalCenter - - Text { - text: baseItem.itemText !== "" ? baseItem.itemText : qsTr("Unknown") - - rightPadding: Utils.dp(10) - width: parent.width - rightPadding - font.pixelSize: Constants.normal_font_size - color: "white" - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - } + MouseArea { + anchors.fill: parent + enabled: !!baseItem.link + onClicked: Qt.openUrlExternally(baseItem.link) } } diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml b/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml index 3093868..1f31e43 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml @@ -5,53 +5,39 @@ import "../global" Item { id: baseItem + height: button.height + Constants.component_spacing + width: parent.width + property string selectedCategory: "" property string providerIcon: "" property string address: "" property color titleBarColor - readonly property int customWidth: Utils.dp(24) - - Rectangle { - height: parent.height - width: parent.width - - anchors.fill: baseItem - color: Constants.background_color + Image { + id: icon + source: baseItem.providerIcon !== "" ? baseItem.providerIcon : + Category.buttonImageSource(baseItem.selectedCategory) + asynchronous: true + height: 2 * baseItem.height + width: height + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.verticalCenter: baseItem.top } - Column { - id: buttonBarContent + Button { + id: button + text: qsTr("ONLINE APPLICATION") + buttonColor: baseItem.titleBarColor + anchors.left: icon.right + anchors.leftMargin: Constants.component_spacing + anchors.bottom: icon.bottom + enabled: baseItem.address !== "" - height: parent.height - width: parent.width - 2 * baseItem.customWidth - anchors.left: parent.left - anchors.top: parent.top - anchors.leftMargin: baseItem.customWidth - topPadding: -2 * baseItem.customWidth - spacing: baseItem.customWidth - - Image { - id: icon - source: baseItem.providerIcon !== "" ? baseItem.providerIcon : - Category.buttonImageSource(baseItem.selectedCategory) - - fillMode: Image.PreserveAspectFit - height: 4 * baseItem.customWidth - width: height - anchors.left: parent.left - } - - Button { - text: qsTr("ONLINE-APPLICATION") - buttonColor: baseItem.titleBarColor - anchors.left: parent.left - enabled: baseItem.address !== "" - - onClicked: { - if (baseItem.address !== "") { - Qt.openUrlExternally(baseItem.address) - } + onClicked: { + if (baseItem.address !== "") { + Qt.openUrlExternally(baseItem.address) } } } diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml b/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml index 1ee0f15..f901d82 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml @@ -3,50 +3,23 @@ import QtQuick 2.6 import "../global" -Rectangle { +Column { id: baseItem - - color: Constants.background_color + spacing: Constants.pane_spacing property string description: "" - readonly property int frameThickness: Utils.dp(10) + Text { + font.pixelSize: Constants.header_font_size + color: PlatformConstants.blue_primary + text: qsTr("Description") + } - Rectangle { - radius: Utils.dp(5) - height: baseItem.height - 2 * baseItem.frameThickness - width: baseItem.width - 2 * baseItem.frameThickness - anchors.top: parent.top - anchors.topMargin: baseItem.frameThickness - anchors.left: parent.left - anchors.leftMargin: baseItem.frameThickness - - color: "white" - - Column { - id: descriptionContent - - spacing: baseItem.frameThickness - width: parent.width - 2 * parent.radius - anchors.top: parent.top - anchors.topMargin: parent.radius - anchors.left: parent.left - anchors.leftMargin: parent.radius - - Text { - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - text: qsTr("Description") - } - - Text { - font.pixelSize: Constants.normal_font_size - text: baseItem.description - maximumLineCount: 3 - width: parent.width - elide: Text.ElideRight - wrapMode: Text.Wrap - } - } + Text { + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignJustify + text: baseItem.description + width: parent.width + wrapMode: Text.Wrap } } diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailHistory.qml b/resources/qml/provider/+android/+tablet/ProviderDetailHistory.qml index b92214d..f61e750 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistory.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailHistory.qml @@ -3,98 +3,42 @@ import QtQuick 2.6 import "../global" -Rectangle { +Column { id: baseItem + spacing: Constants.pane_spacing - color: Constants.background_color - - property string providerName: "" property var openHistoryInfoFunc: function() { } - readonly property int frameThickness: Utils.dp(10) - readonly property int historySpacing: Utils.dp(1) readonly property int historyItemHeight: Utils.dp(66) readonly property int historyItemMargin: Utils.dp(8) - Rectangle { - id: frame + Text { + id: headerText - radius: Utils.dp(5) - height: baseItem.height - 2 * baseItem.frameThickness - width: baseItem.width - 2 * baseItem.frameThickness - anchors.top: parent.top - anchors.topMargin: baseItem.frameThickness - anchors.left: parent.left - anchors.leftMargin: baseItem.frameThickness + font.pixelSize: Constants.header_font_size + color: PlatformConstants.blue_primary + text: qsTr("History") + } - color: "white" + Repeater { + model: historyModel.nameFilter - Column { - id: mainColumn + ProviderDetailHistoryItem { + itemHeight: baseItem.historyItemHeight + itemMargin: baseItem.historyItemMargin - spacing: baseItem.frameThickness - height: frame.height - 2 * frame.radius - width: frame.width - 2 * frame.radius - anchors.top: parent.top - anchors.topMargin: parent.radius - anchors.left: parent.left - anchors.leftMargin: parent.radius + width: parent.width - Text { - id: headerText + providerName: subject + providerPostalAddress: providerPostalAddress + dateTime: model.dateTime + infoText: qsTr("Purpose for reading out requested data") + purposeText: purpose + requestedDataText: requestedData + termsOfUsageText: termsOfUsage - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - text: qsTr("History") - } - - Flickable { - id: history - - height: mainColumn.height - mainColumn.spacing - headerText.height - width: mainColumn.width - - contentHeight: infoTable.height - contentWidth: width - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.StopAtBounds - - Rectangle { - anchors.fill: infoTable - - color: "black" - } - - Column { - id: infoTable - - width: history.width - spacing: baseItem.historySpacing - - Repeater { - model: historyModel.nameFilter - - ProviderDetailHistoryItem { - itemHeight: baseItem.historyItemHeight - itemMargin: baseItem.historyItemMargin - - width: parent.width - - providerName: subject - providerPostalAddress: provider_postaladdress - timeText: dateTime - infoText: qsTr("Purpose for reading out requested data") - purposeText: purpose - requestedDataText: requestedData - termsOfUsageText: termsOfUsage - - openInfoFunction: baseItem.openHistoryInfoFunc - } - } - } - } + openInfoFunction: baseItem.openHistoryInfoFunc } } } diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml index f6d39ed..cb283c4 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml @@ -14,11 +14,6 @@ Rectangle { property string termsOfUsageText: "" property string internalState: "off" - readonly property int infoMargin: Utils.dp(16) - readonly property int infoPadding: infoMargin / 2 - readonly property int infoSpacing: Utils.dp(16) - readonly property int leftInfoRowHeight: Utils.dp(60) - color: "transparent" Rectangle { @@ -28,216 +23,100 @@ Rectangle { opacity: 0.4 } - Row { - id: infoRow + Flickable { + anchors.fill: baseItem + anchors.margins: Constants.component_spacing + contentHeight: infoRow.height - height: baseItem.height - 2 * baseItem.infoMargin - width: baseItem.width - 2 * baseItem.infoMargin - baseItem.infoSpacing - anchors.top: baseItem.top - anchors.topMargin: baseItem.infoMargin - anchors.left: baseItem.left - anchors.leftMargin: baseItem.infoMargin + onContentYChanged: { + if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } - spacing: baseItem.infoSpacing + Row { + id: infoRow + height: childrenRect.height + spacing: Constants.component_spacing - Rectangle { - id: leftInfo - - height: infoRow.height - width: infoRow.width * 2 / 5 - radius: Utils.dp(5) - - anchors.top: parent.top - - color: "white" + property int maxContentHeight: Math.max(leftPane.contentHeight, rightPane.contentHeight) Column { - id: leftInfoColumn + width: baseItem.width / 3 - height: parent.height - width: parent.width - 2 * baseItem.infoMargin + Pane { + id: leftPane + height: childrenRect.height + verticalSpace - padding: baseItem.infoPadding - spacing: baseItem.infoSpacing - anchors.top: parent.top - anchors.left: parent.left - anchors.leftMargin: baseItem.infoMargin + readonly property int contentHeight: childrenRect.height + property int verticalSpace: infoRow.maxContentHeight - contentHeight - Row { - height: baseItem.leftInfoRowHeight - width: parent.width - anchors.left: parent.left - - Image { - id: purposeIcon - - anchors.verticalCenter: parent.verticalCenter - height: parent.height - width: height - - source: "qrc:///images/iOS/ProviderPurpose.png" - fillMode: Image.PreserveAspectFit + ProviderInfoSection { + imageSource: "qrc:///images/provider/information.svg" + title: qsTr("Service provider") + name: baseItem.providerName } - LabeledText { - id: purposeItem - - label: qsTr("Purpose for reading out requested data") - text: baseItem.purposeText - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - purposeIcon.width - } - } - - Row { - height: baseItem.leftInfoRowHeight - width: parent.width - anchors.left: parent.left - - Image { - id: informationIcon - - anchors.verticalCenter: parent.verticalCenter - height: parent.height - width: height - - source: "qrc:///images/iOS/ProviderInformation.png" - fillMode: Image.PreserveAspectFit + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + name: baseItem.purposeText } - LabeledText { - id: informationItem - - label: qsTr("Provider information") - text: baseItem.providerName - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - informationIcon.width + Text { + id: readDataTitle + width: parent.width + font.pixelSize: Constants.header_font_size + color: PlatformConstants.blue_primary + text: qsTr("Read data") } - } - Text { - id: readDataTitle + Column { + id: infoTable - width: parent.width - anchors.left: parent.left - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary + width: parent.width + spacing: 1 - text: qsTr("Read data") - } + Repeater { + model: baseItem.requestedDataText.split(",") - Flickable { - id: readData + Item { + id: textItem - height: leftInfoColumn.height - - (readDataTitle.height + 2 * leftInfoColumn.padding + - 3 * leftInfoColumn.spacing + - 2 * baseItem.leftInfoRowHeight) - width: leftInfoColumn.width + height: Utils.dp(32) + width: infoTable.width - anchors.left: parent.left + Rectangle { + anchors.fill: textItem + color: "white" + } - contentHeight: readDataContent.height - contentWidth: width - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.StopAtBounds + Text { + text: modelData.trim() - Item { - id: readDataContent - - height: infoTable.height - width: readData.width - - Rectangle { - anchors.fill: infoTable - - color: "black" - } - - Column { - id: infoTable - - width: parent.width - anchors.left: parent.left - spacing: 1 - - Repeater { - model: baseItem.requestedDataText.split(",") - - Item { - id: textItem - - height: Utils.dp(32) - width: infoTable.width - - Rectangle { - anchors.fill: textItem - color: "white" - } - - Text { - text: modelData.trim() - - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Constants.normal_font_size - } + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Constants.normal_font_size } } } } } } - } - - Rectangle { - id: rightInfo - - height: infoRow.height - width: infoRow.width * 3 / 5 - radius: Utils.dp(5) - - anchors.top: parent.top - - color: "white" Column { - id: termsOfUsage + width: baseItem.width / 3 * 2 - 3 * Constants.component_spacing - height: parent.height - width: parent.width - 2 * baseItem.infoMargin + Pane { + id: rightPane + height: childrenRect.height + verticalSpace - padding: baseItem.infoPadding - spacing: baseItem.infoSpacing - anchors.top: parent.top - anchors.left: parent.left - anchors.leftMargin: baseItem.infoMargin + readonly property int contentHeight: childrenRect.height + property int verticalSpace: infoRow.maxContentHeight - contentHeight - Text { - id: termsOfUsageTitle - - text: qsTr("Terms of usage") - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - } - - - Flickable { - id: termsOfUsageData - - height: termsOfUsage.height - - (termsOfUsageTitle.height + 2 * termsOfUsage.padding + leftInfoColumn.spacing) - width: termsOfUsage.width - - anchors.left: parent.left - - contentHeight: termsOfUsageTextItem.height - contentWidth: width - clip: true - flickableDirection: Flickable.VerticalFlick - boundsBehavior: Flickable.StopAtBounds + Text { + id: termsOfUsageTitle + text: qsTr("Terms of usage") + font.pixelSize: Constants.header_font_size + color: PlatformConstants.blue_primary + } Text { id: termsOfUsageTextItem diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml index dded9fe..3e438be 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml @@ -11,7 +11,7 @@ Item { property string providerName: "" property string providerPostalAddress: "" - property string timeText: "" + property var dateTime: "" property string infoText: "" property string purposeText: "" property string requestedDataText: "" @@ -45,25 +45,34 @@ Item { anchors.topMargin: baseItem.itemMargin Text { - text: timeText height: baseItem.lineHeight - color: PlatformConstants.blue_primary + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.label_font_size + font.capitalization: Font.AllUppercase + color: Constants.blue + text: { + if (!new Date(dateTime)) { + return "" + } + else if (Utils.isToday(dateTime)) { + return qsTr("today") + } + else if (Utils.isYesterday(dateTime)) { + return qsTr("yesterday") + } + else if (Utils.isThisWeek(dateTime)) { + return dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) + } + return dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + } } - Text { - text: infoText + LabeledText { + label: infoText + text: !!purposeText ? purposeText : qsTr("Touch for more details") + width: parent.width height: baseItem.lineHeight } - - Text { - text: purposeText - height: baseItem.lineHeight - color: PlatformConstants.blue_primary - font.bold: true - font.pixelSize: Constants.normal_font_size - elide: Text.ElideRight - maximumLineCount: 1 - } } Item { diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailView.qml b/resources/qml/provider/+android/+tablet/ProviderDetailView.qml index 1885ab4..b4af925 100644 --- a/resources/qml/provider/+android/+tablet/ProviderDetailView.qml +++ b/resources/qml/provider/+android/+tablet/ProviderDetailView.qml @@ -5,85 +5,38 @@ import ".." import "../global" -Item { +SectionPage { id: baseItem - - // Details are passed through modelItem when called from HistoryViewPage, - // otherwise they must be set explicitly - property var modelItem: null - - onModelItemChanged: { - if (modelItem !== null) { - selectedCategory = modelItem.provider_category - shortName = modelItem.provider_shortname - longName = modelItem.provider_longname - shortDescription = modelItem.provider_shortdescription - longDescription = modelItem.provider_longdescription - address = modelItem.provider_address - homepage = modelItem.provider_homepage - homepageBase = modelItem.provider_homepage_base - phone = modelItem.provider_phone - email = modelItem.provider_email - postalAddress = modelItem.provider_postaladdress - providerIcon = modelItem.provider_icon - providerImage = modelItem.provider_image - } - } - - property string selectedCategory - property string shortName - property string longName - property string shortDescription - property string longDescription - property string address - property string homepage - property string homepageBase - property string phone - property string email - property string postalAddress - property string providerIcon - property string providerImage - - function historyInfoIsOpen() { - return providerDetailsHistoryInfo.visible - } - - function closeHistoryInfo() { - providerDetailsHistoryInfo.visible = false - } - - property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction { + readonly property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction { state: "back" onClicked: { - if (baseItem.historyInfoIsOpen()) { - baseItem.closeHistoryInfo() + if (providerDetailsHistoryInfo.visible) { + providerDetailsHistoryInfo.visible = false } else { pop() } } } - - property TitleBarAction headerTitleBarAction: TitleBarAction { text: shortName; font.bold: true } - property Item rightTitleBarAction: Item {} - property color titleBarColor: Category.displayColor(selectedCategory) - + readonly property TitleBarAction headerTitleBarAction: TitleBarAction { text: provider.shortName; font.bold: true } + readonly property Item rightTitleBarAction: Item {} + readonly property color titleBarColor: Category.displayColor(provider.category) readonly property real titleBarOpacity: 1 - Column { + property alias historyModelItem: provider.modelItem + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } + + + content: Column { id: mainContent - - height: parent.height - width: parent.width - - readonly property real contactRatio: 0.5 - readonly property real buttonBarRatio: 0.25 - readonly property real extraInfoRatio: 0.25 + height: childrenRect.height + Constants.component_spacing + width: baseItem.width Row { - id: contactInfo - - height: parent.height * mainContent.contactRatio + height: baseItem.height / 2 width: parent.width Item { @@ -93,87 +46,106 @@ Item { Image { id: image - source: baseItem.providerImage !== "" ? baseItem.providerImage : - Category.backgroundImageSource(baseItem.selectedCategory) - - fillMode: Image.PreserveAspectFit + source: !!provider.image ? provider.image : Category.backgroundImageSource(provider.category) + asynchronous: true height: parent.height + fillMode: Image.PreserveAspectFit anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter } Image { - id: imageBackgroundLeft - source: Category.gradientImageSource(baseItem.selectedCategory) - - fillMode: Image.Stretch - anchors.right: imageBackgroundRight.left - anchors.top: parent.top height: parent.height width: height / 2 + anchors.right: image.right + anchors.top: parent.top + fillMode: Image.Stretch + source: Category.gradientImageSource(provider.category) + } Rectangle { - id: imageBackgroundRight + anchors.left: image.right anchors.right: parent.right anchors.top: parent.top height: parent.height - width: height - color: baseItem.titleBarColor } } - ProviderContactInfo { - backgroundColor: baseItem.titleBarColor - color: baseItem.titleBarColor + Rectangle { + height: parent.height width: baseItem.width / 3 + color: baseItem.titleBarColor - homepage: baseItem.homepageBase - email: baseItem.email - phone: baseItem.phone - postalAddress: baseItem.postalAddress + ProviderContactInfo { + color: baseItem.titleBarColor + height: parent.height + width: baseItem.width / 3 - Constants.component_spacing + + contactModel: provider.contactModel + } } } Row { id: lowerRow + height: childrenRect.height + width: parent.width - height: mainContent.height * (mainContent.buttonBarRatio + mainContent.extraInfoRatio) - width: baseItem.width + property int maxContentHeight: Math.max(leftPane.contentHeight + buttonBar.height, rightPane.contentHeight) Column { id: leftColumn - - height: lowerRow.height width: lowerRow.width * 2 / 3 - anchors.top: lowerRow.top + spacing: Constants.pane_spacing ProviderDetailButtonBar { - selectedCategory: baseItem.selectedCategory - providerIcon: baseItem.providerIcon - address: baseItem.address + id: buttonBar + selectedCategory: provider.category + providerIcon: provider.icon + address: provider.address titleBarColor: baseItem.titleBarColor - - height: mainContent.height * mainContent.buttonBarRatio - width: leftColumn.width - anchors.left: leftColumn.left } - ProviderDetailDescription { - height: mainContent.height * mainContent.extraInfoRatio - width: leftColumn.width - anchors.left: leftColumn.left + Pane { + id: leftPane + anchors.leftMargin: Constants.component_spacing + anchors.rightMargin: Constants.component_spacing + height: childrenRect.height - buttonBar.height + verticalSpace - description: baseItem.longDescription + readonly property int contentHeight: childrenRect.height + property int verticalSpace: lowerRow.maxContentHeight - contentHeight + + ProviderDetailDescription { + id: descriptionData + width: parent.width + description: provider.longDescription + } } } - ProviderDetailHistory { - height: lowerRow.height - width: lowerRow.width / 3 - anchors.top: lowerRow.top - openHistoryInfoFunc: baseItem.openHistoryInfoFunc + Column { + width: lowerRow.width / 3 - Constants.component_spacing + + Item { + height: Constants.component_spacing + width: Constants.component_spacing + } + + Pane { + id: rightPane + height: childrenRect.height + verticalSpace + + readonly property int contentHeight: childrenRect.height + property int verticalSpace: lowerRow.maxContentHeight - contentHeight + + ProviderDetailHistory { + id: historyData + width: parent.width + openHistoryInfoFunc: baseItem.openHistoryInfoFunc + } + } } } } @@ -194,8 +166,8 @@ Item { height: parent.height width: parent.width - anchors.top: mainContent.top - anchors.left: mainContent.left + anchors.top: baseItem.top + anchors.left: baseItem.left visible: false } diff --git a/resources/qml/provider/+android/+tablet/ProviderView.qml b/resources/qml/provider/+android/+tablet/ProviderView.qml index 428dd62..e3e3ee6 100644 --- a/resources/qml/provider/+android/+tablet/ProviderView.qml +++ b/resources/qml/provider/+android/+tablet/ProviderView.qml @@ -10,9 +10,9 @@ Item { property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction {} property TitleBarAction headerTitleBarAction: TitleBarAction { text: qsTr("Provider"); font.bold: true } - property Item rightTitleBarAction: TitleBarSearchAction { - availableWidth: baseItem.width - leftTitleBarAction.contentWidth - onSearchTextChanged: providerModel.categoryFilter.updateSearchString(searchText) + property Item rightTitleBarAction: SearchBar { + availableWidth: baseItem.width + onSearchTextChanged: providerModel.searchString = searchText } property color titleBarColor: Constants.blue @@ -28,9 +28,9 @@ Item { visible: false } - function pushProviderDetails(providerDetails) { - historyModel.nameFilter.setProviderAddress(providerDetails['address']) - push(providerDetailView, providerDetails) + function pushProviderDetails(model) { + historyModel.nameFilter.setProviderAddress(model.providerAddress) + push(providerDetailView, {providerModelItem: model}) } Column { @@ -55,6 +55,9 @@ Item { padding: Utils.dp(30) spacing: Utils.dp(30) + transformOrigin: Item.Center + scale: Math.min(parent.width / width, 1) + CategoryCheckbox { id: checkBoxCitizen @@ -108,72 +111,59 @@ Item { id: noResultsText anchors.centerIn: mainPane - text: qsTr("No results found") + text: qsTr("No match found") wrapMode: Text.WordWrap - font.pixelSize: Utils.sp(18) + font.pixelSize: Constants.normal_font_size visible: !flickable.visible } Flickable { id: flickable - - readonly property int paddingWidth: Utils.dp(10) - readonly property int spacingWidth: Utils.dp(20) - + anchors.fill: mainPane clip: true flickableDirection: Flickable.VerticalFlick visible: grid.hasResults contentHeight: grid.height contentWidth: parent.width - height: mainPane.height - width: mainPane.width - anchors.centerIn: parent + onContentYChanged: { + if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } Grid { id: grid - columns: 4 - padding: flickable.paddingWidth - spacing: flickable.spacingWidth + columns: Math.floor((parent.width - Constants.component_spacing) / (Utils.dp(196) + Constants.component_spacing)) + padding: Constants.component_spacing + spacing: Constants.component_spacing width: parent.width - property int cardHeight: (flickable.height - 2 * grid.padding - grid.spacing) / 2 - property int cardWidth: (flickable.width - 2 * grid.padding - (grid.columns - 1) * - grid.spacing) / grid.columns - property bool hasResults: gridRepeater.count > 0 || additionalResults.visible + property int cardHeight: (flickable.height - Constants.component_spacing) / 2 + property int cardWidth: (flickable.width - (grid.columns + 1) * Constants.component_spacing) / grid.columns + property bool hasResults: gridRepeater.count > 0 || additionalResults.totalHits > 0 Repeater { id: gridRepeater - model: providerModel.categoryFilter + model: providerModel ProviderCard { - pushFunction: baseItem.pushProviderDetails - - height: grid.cardHeight width: grid.cardWidth - - providerCategory: category - headerImage: image - headerIcon: icon - providerName: longName !== "" ? longName : shortName - providerShortDescription: shortDescription - providerLongDescription: longDescription - providerAddress: address - providerHomepageBase: homepagebase - providerEmail: email - providerPhone: phone - providerPostalAddress: postalAddress + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) + pushFunction: baseItem.pushProviderDetails + providerModel: model } } - AdditionalResultsCard { + AdditionalResultsItem { id: additionalResults - - height: grid.cardHeight width: grid.cardWidth + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) } } } diff --git a/resources/qml/provider/+android/ProviderDetailView.qml b/resources/qml/provider/+android/ProviderDetailView.qml index 1a8ca65..ee03ea4 100644 --- a/resources/qml/provider/+android/ProviderDetailView.qml +++ b/resources/qml/provider/+android/ProviderDetailView.qml @@ -1,7 +1,6 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.6 import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 as QtControls +import QtQuick.Controls 2.0 import "../" import "../global" @@ -10,57 +9,43 @@ SectionPage { id: baseItem leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } + headerTitleBarAction: TitleBarAction { text: provider.shortName } + titleBarColor: Category.displayColor(provider.category) - headerTitleBarAction: TitleBarAction { text: shortName } + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } - titleBarColor: Category.displayColor(selectedCategory) - - property var selectedProviderModel: ({}) - - property string selectedCategory - - readonly property real headerHeight: Utils.dp(200) - - // Details - property string shortName - property string longName - property string shortDescription - property string longDescription - property string address - property string homepage - property string phone - property string email - property string postalAddress - property string providerIcon - property string providerImage header: ProviderHeader { + id: ownHeader width: baseItem.width - height: headerHeight - - address: baseItem.address - providerIcon: baseItem.providerIcon !== "" ? baseItem.providerIcon : Category.buttonImageSource(baseItem.selectedCategory) - providerImage: baseItem.providerImage !== "" ? baseItem.providerImage : Category.backgroundImageSource(baseItem.selectedCategory) - transparentColor: Category.displayColor(selectedCategory) + selectedProvider: provider } content: Item { + height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing width: baseItem.width - height: baseItem.height - QtControls.TabBar { + TabBar { id: swipeBar - height: firstButton.height + height: firstButton.implicitHeight anchors.top: parent.top - anchors.topMargin: Utils.dp(20) + anchors.topMargin: Constants.component_spacing anchors.left: parent.left anchors.right: parent.right currentIndex: swipeView.currentIndex - QtControls.TabButton { + TabButton { id: firstButton padding: Utils.dp(10) + // TODO: Workaround, use contentItem when switching to Qt 5.7.1 + // See https://bugreports.qt.io/browse/QTBUG-50992 + text: qsTr("DESCRIPTION") + +/* contentItem: Text { text: qsTr("DESCRIPTION") font.pixelSize: Constants.normal_font_size @@ -70,10 +55,16 @@ SectionPage { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } +*/ } - QtControls.TabButton { + TabButton { padding: Utils.dp(10) + // TODO: Workaround, use contentItem when switching to Qt 5.7.1 + // See https://bugreports.qt.io/browse/QTBUG-50992 + text: qsTr("CONTACT") + +/* contentItem: Text { text: qsTr("CONTACT") font.pixelSize: Constants.normal_font_size @@ -83,41 +74,39 @@ SectionPage { horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } +*/ } } Rectangle { - anchors.fill: flickable - } - - Flickable { - id: flickable + id: swipeViewBackground anchors.top: swipeBar.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - flickableDirection: Flickable.VerticalFlick - clip: true + anchors.horizontalCenter: swipeBar.horizontalCenter + height: swipeView.height + 2 * Constants.component_spacing + width: parent.width - QtControls.SwipeView { + SwipeView { id: swipeView - anchors.fill: parent - anchors.margins: Utils.dp(20) + height: Math.max(providerText.contentHeight, providerInfo.contentHeight) + anchors.margins: Constants.component_spacing + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + currentIndex: swipeBar.currentIndex clip: true Text { - text: longDescription ? longDescription : qsTr("Description not available") - + id: providerText + text: !!provider.longDescription ? provider.longDescription : qsTr("Description not available") + horizontalAlignment: Text.AlignJustify wrapMode: Text.WordWrap - font.pixelSize: Utils.dp(16) + font.pixelSize: Constants.normal_font_size } ProviderContactTab { - homepage: baseItem.homepage ? baseItem.homepage : "" - phone: baseItem.phone ? baseItem.phone : "" - email: baseItem.email ? baseItem.email : "" - postalAddress: baseItem.postalAddress ? baseItem.postalAddress : "" + id: providerInfo + contactModel: provider.contactModel } } } diff --git a/resources/qml/provider/+android/ProviderStyle.qml b/resources/qml/provider/+android/ProviderStyle.qml index ae41dae..a862b17 100644 --- a/resources/qml/provider/+android/ProviderStyle.qml +++ b/resources/qml/provider/+android/ProviderStyle.qml @@ -35,6 +35,4 @@ Item { readonly property color providerListDetailsLinkColor: Constants.primary_text readonly property color providerListDetailsLinkBackground: PlatformConstants.grey_light readonly property string providerListDetailsLinkPosition: "top" - - readonly property int providerHeaderHeight: Utils.dp(180) } diff --git a/resources/qml/provider/+android/ProviderView.qml b/resources/qml/provider/+android/ProviderView.qml new file mode 100644 index 0000000..873cae9 --- /dev/null +++ b/resources/qml/provider/+android/ProviderView.qml @@ -0,0 +1,114 @@ +import QtQuick 2.5 + +import "../" +import "../../" +import "../../global" + +SectionPage { + id: baseItem + + readonly property var category: providerModel.categories.length === 0 ? "" : providerModel.categories[0] + + Component.onCompleted: providerModel.sortByCategoryFirst(true) + + onCategoryChanged: { + providerModel.sortByCategoryFirst(category === "") + } + + ProviderStyle { + id: providerStyle + } + + leftTitleBarAction: TitleBarMenuAction { + state: category !== "" ? "back" : "" + onClicked: { + if (state === "back") { + providerModel.setCategorySelection("") + } + } + } + + headerTitleBarAction: TitleBarAction { + text: Category.displayString(category) + font.bold: true + } + + rightTitleBarAction: SearchBar { + availableWidth: baseItem.width - Constants.menubar_width + onSearchTextChanged: providerModel.searchString = searchText + } + + titleBarColor: Category.displayColor(category) + + ProviderDetailView { + id: providerDetailView + visible: false + } + + header: ProviderHeader { + width: baseItem.width + selectedCategory: category + } + + content: Column { + width: baseItem.width + + Rectangle { + height: Utils.dp(200) + width: parent.width + color: Constants.background_color + visible: providerModel.rowCount === 0 && !additionalResults.visible + + Text { + anchors.centerIn: parent + text: qsTr("No match found") + font.pixelSize: Constants.normal_font_size + } + } + + ProviderSectionDelegate { + id: allSection + sectionName: "all" + visible: providerModel.searchString === "" && providerModel.categories.length === 0 + height: visible ? Constants.provider_section_height : 0 + } + + ListView { + id: providerListMain + height: childrenRect.height + width: baseItem.width + interactive: false + visible: category === "" + + model: providerModel + + delegate: ProviderViewDelegate { + height: visible ? Constants.provider_section_height : 0 + visible: providerModel.searchString !== "" + } + + section.property: "providerCategory" + section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart + section.delegate: ProviderSectionDelegate { + sectionName: section + } + } + + ListView { + id: providerListSection + height: childrenRect.height + width: baseItem.width + interactive: false + visible: !providerListMain.visible + + model: providerModel + + delegate: ProviderViewDelegate {} + } + + AdditionalResultsItem { + id: additionalResults + width: parent.width + } + } +} diff --git a/resources/qml/provider/+android/ProviderViewDelegate.qml b/resources/qml/provider/+android/ProviderViewDelegate.qml index 161500f..0fadff5 100644 --- a/resources/qml/provider/+android/ProviderViewDelegate.qml +++ b/resources/qml/provider/+android/ProviderViewDelegate.qml @@ -54,7 +54,7 @@ Rectangle { anchors.rightMargin: Utils.dp(5) verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.normal_font_size color: providerStyle.subjectTextColor font.bold: providerStyle.subjectTextFontBold elide: Text.ElideRight @@ -75,7 +75,7 @@ Rectangle { font.pixelSize: providerStyle.addressTextFontSize color: providerStyle.addressTextColor elide: Text.ElideRight - text: addressDomain + text: providerAddressDomain } Item { @@ -114,23 +114,7 @@ Rectangle { MouseArea { anchors.fill: parent - onClicked: { - push(providerDetailView, - { - selectedCategory: category, - shortName: model.shortName, - longName: model.longName, - shortDescription: model.shortDescription, - longDescription: model.longDescription, - address: model.address, - homepage: model.homepage, - phone: model.phone, - email: model.email, - postalAddress: model.postalAddress, - providerIcon: model.icon, - providerImage: model.image - }) - } + onClicked: push(providerDetailView, {providerModelItem: model}) } Rectangle { diff --git a/resources/qml/provider/+android/ProviderViewHeader.qml b/resources/qml/provider/+android/ProviderViewHeader.qml deleted file mode 100644 index 8f272aa..0000000 --- a/resources/qml/provider/+android/ProviderViewHeader.qml +++ /dev/null @@ -1,154 +0,0 @@ -import QtQuick 2.5 - -import "../global" - - -Rectangle { - id: baseItem - - // Properties that are set by ProviderSectionView. - property string selectedCategory: "" - - property bool withButtons: true - - /* This is interpreted by the SectionPage component. */ - readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : 0 - readonly property int stopFlickOn: height - Constants.titlebar_height - - property color shadowColor: selectedCategory === "" ? Constants.blue : Category.displayColor(selectedCategory) - - property string foregroundImageSource: selectedCategory === "all" ? "qrc:///images/All.png" : "" - - property string backgroundImageSource: selectedCategory === "" ? "qrc:///images/provider/categoryIcons/+android/General_bg.png" : - Category.backgroundImageSource(selectedCategory) - - readonly property double iconHeightRatio: 0.3 - - readonly property double iconVerticalMarginRatio: 0.2 - - property int maxContentY: withButtons ? parent.height * (iconHeightRatio + iconVerticalMarginRatio) : - height / 2 - - readonly property string searchText: "" - - ProviderStyle { - id: providerStyle - } - - height: providerStyle.providerHeaderHeight - - function definedContentY() { - // For some reason contentY is sometimes set to undefined. - return typeof(contentY) === "undefined" ? 0 : contentY - } - - function currentMargin() { - // Height of button icons. - var H = height * iconHeightRatio - - // Initial inferior margin for button icons. - var M = height * iconVerticalMarginRatio - - var y = definedContentY() - - return -2 * y * (M + H) / (3 * M + 2 * H) + M - } - - Image { - id: backgroundImage - - width: parent.width - source: baseItem.backgroundImageSource - anchors.top: parent.top - anchors.bottom: parent.bottom - - Rectangle { - id: shadow - anchors.fill: parent - color: baseItem.shadowColor - - opacity: baseItem.definedContentY() <= maxContentY ? 0.5 : 1 - Behavior on opacity { - NumberAnimation {} - } - } - - Rectangle { - id: iconBackground - - anchors.centerIn: icon - height: icon.height - width: height - radius: width * 0.5 - - border.width: 0 - color: Constants.all_image_background_color - - visible: baseItem.foregroundImageSource !== "" - - opacity: baseItem.definedContentY() <= maxContentY ? 1 : 0 - Behavior on opacity { - NumberAnimation {} - } - } - - Image { - id: icon - source: baseItem.foregroundImageSource - - anchors.horizontalCenter: backgroundImage.horizontalCenter - anchors.bottom: backgroundImage.bottom - anchors.bottomMargin: Utils.dp(20) - - fillMode: Image.PreserveAspectFit - width: baseItem.width * 0.26 - height: width - - visible: baseItem.foregroundImageSource !== "" - - opacity: baseItem.definedContentY() <= maxContentY ? 1 : 0 - Behavior on opacity { - NumberAnimation {} - } - } - } - - Row { - id: iconsRow - - height: parent.height * iconHeightRatio - width: parent.width * 0.9 - - visible: withButtons - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: baseItem.currentMargin() - - Repeater { - model: ["citizen", "insurance", "finance", "other"] - - Rectangle { - height: parent.height - width: parent.width * 0.25 - color: "transparent" - - Image { - source: Category.buttonImageSource(modelData) - opacity: 1.0 - - anchors.fill: parent - - fillMode: Image.PreserveAspectFit - } - - MouseArea { - anchors.fill: parent - onClicked: { - push(categoryProviderView, {selectedCategory: modelData}) - } - } - } - } - } -} diff --git a/resources/qml/provider/+android/SearchBar.qml b/resources/qml/provider/+android/SearchBar.qml new file mode 100644 index 0000000..99683d2 --- /dev/null +++ b/resources/qml/provider/+android/SearchBar.qml @@ -0,0 +1,67 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import "../global" + + +Row { + id: root + + property int availableWidth: 0 + readonly property int contentWidth: root.implicitWidth + readonly property alias searchText: searchField.displayText + + anchors.top: parent ? parent.top : undefined + anchors.right: parent ? parent.right : undefined + anchors.bottom: parent ? parent.bottom : undefined + spacing: Constants.titlebar_padding + + GTextField { + id: searchField + height: parent.height + width: root.availableWidth - parent.spacing - iconItem.width - 2 * Constants.titlebar_padding + + visible: false + + onAccepted: { + iconItem.forceActiveFocus(Qt.MouseFocusReason) + } + + Behavior on visible { + PropertyAnimation { + duration: 150 + } + } + } + + Image { + id: iconItem + + height: parent.height + width: height + fillMode: Image.PreserveAspectFit + source: "qrc:///images/android/search_icon.svg" + + MouseArea { + anchors.fill: parent + onClicked: { + // Storage of the new value is needed because the query + // of searchField.visible still delivers the old value. + var searchFieldVisible = !searchField.visible + + if (searchFieldVisible) { + iconItem.source = "qrc:///images/android/search_cancel.svg" + searchField.forceActiveFocus(Qt.MouseFocusReason) + Qt.inputMethod.show() + } else { + iconItem.source = "qrc:///images/android/search_icon.svg" + iconItem.forceActiveFocus(Qt.MouseFocusReason) + searchField.text = "" + Qt.inputMethod.hide() + } + + searchField.visible = searchFieldVisible + } + } + } +} diff --git a/resources/qml/provider/+android/TitleBarSearchAction.qml b/resources/qml/provider/+android/TitleBarSearchAction.qml deleted file mode 100644 index a9fa698..0000000 --- a/resources/qml/provider/+android/TitleBarSearchAction.qml +++ /dev/null @@ -1,69 +0,0 @@ -import QtQuick 2.5 - -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../global" - - -Row { - id: root - - property int availableWidth: 0 - readonly property int contentWidth: root.implicitWidth - readonly property alias searchText: searchField.text - - anchors.top: parent ? parent.top : undefined - anchors.topMargin: Utils.dp(10) - anchors.bottom: parent ? parent.bottom : undefined - anchors.bottomMargin: anchors.topMargin - spacing: Utils.dp(24) - - TextField { - id: searchField - height: parent.height - width: root.availableWidth - iconItem.width - 2 * parent.spacing - horizontalAlignment: Text.AlignLeft - visible: false - property string savedText: "" - - Behavior on visible { - PropertyAnimation { - duration: 150 - } - } - - onVisibleChanged: { - // When search bar becomes visible again, restore saved search text. - if (visible) { - text = savedText - } - else { - savedText = text - text = "" - } - } - - style: TextFieldStyle { - background: Rectangle { - radius: Utils.dp(6) - } - } - } - - Image { - id: iconItem - - height: parent.height - width: height - fillMode: Image.PreserveAspectFit - source: "qrc:///images/magnifying-glass.png" - - MouseArea { - anchors.fill: parent - onClicked: { - searchField.visible = !searchField.visible - } - } - } -} diff --git a/resources/qml/provider/AdditionalResultsItem.qml b/resources/qml/provider/AdditionalResultsItem.qml index 0940753..9e38859 100644 --- a/resources/qml/provider/AdditionalResultsItem.qml +++ b/resources/qml/provider/AdditionalResultsItem.qml @@ -1,2 +1,58 @@ -Item { +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import "../global" + +Rectangle { + id: baseItem + height: Constants.provider_section_height + + property int totalHits: providerModel.additionalResultCount + + visible: totalHits > 0 && providerModel.categories.length > 0 && providerModel.categories.indexOf("all") === -1 + + Item { + anchors.fill: parent + anchors.topMargin: Utils.dp(5) + anchors.bottomMargin: Utils.dp(5) + + Image { + id: allImage + source: Category.imageSource("all") + asynchronous: true + height: parent.height + width: parent.width * 0.15 + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: providerStyle.leftIconMargin + } + + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: allImage.right + anchors.leftMargin: providerStyle.leftProviderListMargin + color: providerStyle.categoryColor + font.pixelSize: providerStyle.categoryFontPixelSize + font.bold: providerStyle.categoryFontBold + elide: Text.ElideRight + text: '' + qsTr("Additional results:") + " " + baseItem.totalHits + '' + } + + Text { + anchors.right: parent.right + anchors.rightMargin: Utils.dp(5) + anchors.verticalCenter: parent.verticalCenter + + text: ">" + color: Constants.grey + font.pixelSize: Constants.normal_font_size + visible: providerStyle.showCategoryRightArrow + } + + MouseArea { + anchors.fill: parent + onClicked: providerModel.setCategorySelection("") + } + } } diff --git a/resources/qml/provider/ProviderDelegateModel.qml b/resources/qml/provider/ProviderDelegateModel.qml index 4cc96c8..86d8d81 100644 --- a/resources/qml/provider/ProviderDelegateModel.qml +++ b/resources/qml/provider/ProviderDelegateModel.qml @@ -25,7 +25,7 @@ DelegateModel { var validFilterString = filterString ? filterString : "" return entry.model.display.toLowerCase().search(validFilterString.toLowerCase()) !== -1 || - entry.model.address.toLowerCase().search(validFilterString.toLowerCase()) !== -1 + entry.model.providerAddress.toLowerCase().search(validFilterString.toLowerCase()) !== -1 } function filterBy(filterString) { diff --git a/resources/qml/provider/ProviderDetailView.qml b/resources/qml/provider/ProviderDetailView.qml index 48ba77c..fc6ca20 100644 --- a/resources/qml/provider/ProviderDetailView.qml +++ b/resources/qml/provider/ProviderDetailView.qml @@ -9,36 +9,20 @@ import "../global" SectionPage { id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: shortName } - titleBarColor: Category.displayColor(selectedCategory) + headerTitleBarAction: TitleBarAction { text: provider.shortName } + titleBarColor: Category.displayColor(provider.category) - property var selectedProviderModel: ({}) + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } - property string selectedCategory - - // Details - property string shortName - property string longName - property string shortDescription - property string longDescription - property string address - property string homepage - property string phone - property string email - property string postalAddress - property string providerIcon - property string providerImage ProviderHeader { id: header - - height: Utils.dp(200) - - address: parent.address - providerIcon: parent.providerIcon !== "" ? parent.providerIcon : Category.imageSource(parent.selectedCategory) - providerImage: parent.providerImage !== "" ? parent.providerImage : Category.backgroundImageSource(parent.selectedCategory) + width: baseItem.width + selectedProvider: provider } @@ -120,17 +104,14 @@ SectionPage clip: true Text { - text: longDescription ? longDescription : qsTr("Description not avaible") + text: !!provider.longDescription ? provider.longDescription : qsTr("Description not avaible") wrapMode: Text.WordWrap font.pixelSize: Utils.dp(16) } ProviderContactTab { - homepage: baseItem.homepage ? baseItem.homepage : "" - phone: baseItem.phone ? baseItem.phone : "" - email: baseItem.email ? baseItem.email : "" - postalAddress: baseItem.postalAddress ? baseItem.postalAddress : "" + contactModel: provider.contactModel } } } diff --git a/resources/qml/provider/ProviderSectionDelegate.qml b/resources/qml/provider/ProviderSectionDelegate.qml new file mode 100644 index 0000000..f8007c6 --- /dev/null +++ b/resources/qml/provider/ProviderSectionDelegate.qml @@ -0,0 +1,68 @@ +import QtQuick 2.7 + +import "../" +import "../global" + +Rectangle { + property string sectionName: "" + + width: parent.width + height: Constants.provider_section_height + clip: true + + Item { + anchors.fill: parent + anchors.topMargin: Utils.dp(5) + anchors.bottomMargin: Utils.dp(5) + + Image { + id: sectionImage + source: Category.imageSource(sectionName) + asynchronous: true + height: parent.height + width: parent.width * 0.15 + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: providerStyle.leftIconMargin + } + + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: sectionImage.right + anchors.leftMargin: providerStyle.leftProviderListMargin + color: providerStyle.categoryColor + font.pixelSize: providerStyle.categoryFontPixelSize + font.bold: providerStyle.categoryFontBold + elide: Text.ElideRight + text: Category.displayString(sectionName) + } + + Text { + anchors.right: parent.right + anchors.rightMargin: Utils.dp(5) + anchors.verticalCenter: parent.verticalCenter + + text: ">" + color: Constants.grey + font.pixelSize: Constants.normal_font_size + visible: providerStyle.showCategoryRightArrow + } + + MouseArea { + anchors.fill: parent + onClicked: { + providerModel.setCategorySelection(sectionName) + } + } + } + + Rectangle { + width: parent.width * 0.85 + anchors.top: parent.bottom + anchors.topMargin: -height + anchors.right: parent.right + height: 1 + color: Constants.grey + } +} diff --git a/resources/qml/provider/ProviderSectionView.qml b/resources/qml/provider/ProviderSectionView.qml deleted file mode 100644 index 1c7f4a6..0000000 --- a/resources/qml/provider/ProviderSectionView.qml +++ /dev/null @@ -1,68 +0,0 @@ -import QtQuick 2.5 - -import "../" -import "../global" - -SectionPage { - id: baseItem - - ProviderStyle { - id: providerStyle - } - - property string searchText: "" - property string selectedCategory: "" - - onSelectedCategoryChanged: { - providerModel.filter.setFilterFixedString(selectedCategory === "all" ? "" : selectedCategory) - } - - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: {baseItem.contentY=0; pop()} } - - headerTitleBarAction: TitleBarAction { text: Category.displayString(selectedCategory); font.bold: true } - - rightTitleBarAction: TitleBarSearchAction { - availableWidth: baseItem.width - leftTitleBarAction.contentWidth - onSearchTextChanged: baseItem.searchText = searchText - } - - titleBarColor: Category.displayColor(selectedCategory) - - header: ProviderViewHeader { - id: providerViewHeader - - selectedCategory: baseItem.selectedCategory - withButtons: false - width: baseItem.width - onSearchTextChanged: baseItem.searchText = searchText - } - - - content: Item { - - height: Math.max(providerList.height, baseItem.height) - width: baseItem.width - - Rectangle { - anchors.fill: providerList - color: Constants.background_color - } - - ListView { - id: providerList - - height: contentHeight - width: baseItem.width - - section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart - - model: ProviderDelegateModel { - model: providerModel.filter - searchText: baseItem.searchText - delegate: ProviderViewDelegate { - height: Constants.provider_section_height - } - } - } - } -} diff --git a/resources/qml/provider/ProviderStyle.qml b/resources/qml/provider/ProviderStyle.qml index c7224ea..cb3dd13 100644 --- a/resources/qml/provider/ProviderStyle.qml +++ b/resources/qml/provider/ProviderStyle.qml @@ -9,7 +9,7 @@ Item { readonly property string headerBackgroundInProviderView: "" // Provider category list properties - readonly property int categoryFontPixelSize: Utils.sp(14) + readonly property int categoryFontPixelSize: Constants.normal_font_size readonly property bool categoryFontBold: false readonly property color categoryColor: Constants.accent_color readonly property int leftIconMargin: Utils.dp(0) diff --git a/resources/qml/provider/ProviderView.qml b/resources/qml/provider/ProviderView.qml index 91c627e..fae5176 100644 --- a/resources/qml/provider/ProviderView.qml +++ b/resources/qml/provider/ProviderView.qml @@ -3,201 +3,105 @@ import QtQuick 2.5 import "../" import "../global" + SectionPage { id: baseItem + readonly property var category: providerModel.categories.length === 0 ? "" : providerModel.categories[0] + + Component.onCompleted: providerModel.sortByCategoryFirst(true) + + onCategoryChanged: { + providerModel.sortByCategoryFirst(category === "") + } + ProviderStyle { id: providerStyle } + leftTitleBarAction: TitleBarMenuAction { + state: category !== "" ? "back" : "" + onClicked: { + if (state === "back") { + providerModel.setCategorySelection("") + } + } + } + headerTitleBarAction: TitleBarAction { text: qsTr("Provider"); font.bold: true } - rightTitleBarAction: TitleBarSearchAction { - availableWidth: baseItem.width - leftTitleBarAction.contentWidth - Constants.menubar_width - onSearchTextChanged: baseItem.searchText = searchText - } - - ProviderSectionView { - id: categoryProviderView - visible: false - } + titleBarColor: Category.displayColor(category) ProviderDetailView { id: providerDetailView visible: false } - property string searchText: "" - - header: ProviderViewHeader { - id: providerViewHeader - + header: SearchBar { width: baseItem.width - - onSearchTextChanged: baseItem.searchText = searchText + color: Category.displayColor(category) + onSearchTextChanged: providerModel.searchString = searchText } content: Column { - height: Math.max(providerList.height, baseItem.height) width: baseItem.width Rectangle { + height: Utils.dp(200) + width: parent.width + color: Constants.background_color + visible: providerModel.rowCount === 0 && !additionalResults.visible + + Text { + anchors.centerIn: parent + text: qsTr("No match found") + font.pixelSize: Constants.normal_font_size + } + } + + ProviderSectionDelegate { id: allSection + sectionName: "all" + visible: providerModel.searchString === "" && providerModel.categories.length === 0 + height: visible ? Constants.provider_section_height : 0 + } + ListView { + id: providerListMain + height: childrenRect.height width: baseItem.width - height: Constants.provider_section_height - color: "white" - visible: baseItem.searchText === "" + interactive: false + visible: category === "" - Item { - anchors.fill: parent - anchors.topMargin: Utils.dp(5) - anchors.bottomMargin: Utils.dp(5) + model: providerModel - Rectangle { - id: iconBackground - - anchors.centerIn: allImage - height: allImage.height - width: height - radius: width * 0.5 - - border.width: 0 - color: Constants.all_image_background_color - } - - - Image { - id: allImage - source: "qrc:///images/All.png" - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: providerStyle.leftIconMargin - height: parent.height - width: parent.width * 0.15 - fillMode: Image.PreserveAspectFit - } - - Text { - anchors.verticalCenter: parent.verticalCenter - anchors.left: allImage.right - anchors.leftMargin: providerStyle.leftProviderListMargin - font.pixelSize: providerStyle.categoryFontPixelSize - font.bold: providerStyle.categoryFontBold - color: providerStyle.categoryColor - elide: Text.ElideRight - text: qsTr("All") - } - - Text { - anchors.right: parent.right - anchors.rightMargin: Utils.dp(5) - anchors.verticalCenter: parent.verticalCenter - - text: ">" - color: Constants.grey - font.pixelSize: Utils.sp(14) - visible: providerStyle.showCategoryRightArrow - } - - MouseArea { - anchors.fill: parent - onClicked: { - push(categoryProviderView, {selectedCategory: "all"}) - } - } + delegate: ProviderViewDelegate { + height: visible ? Constants.provider_section_height : 0 + visible: providerModel.searchString !== "" } - Rectangle { - width: parent.width * 0.85 - anchors.top: parent.bottom - anchors.topMargin: -height - anchors.right: parent.right - height: 1 - color: Constants.grey + section.property: "providerCategory" + section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart + section.delegate: ProviderSectionDelegate { + sectionName: section } } ListView { - id: providerList - height: contentHeight + id: providerListSection + height: childrenRect.height width: baseItem.width + interactive: false + visible: !providerListMain.visible - section.property: "category" - section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart + model: providerModel - model: ProviderDelegateModel { - model: providerModel.sortModel - searchText: baseItem.searchText - delegate: ProviderViewDelegate { - height: visible ? Constants.provider_section_height : 0 - visible: baseItem.searchText !== "" - } - } + delegate: ProviderViewDelegate {} + } - section.delegate: Rectangle { - id: sectionDelegate - width: parent.width - height: Constants.provider_section_height - visible: baseItem.searchText === "" - color: "white" - clip: true - - Item { - anchors.fill: parent - anchors.topMargin: Utils.dp(5) - anchors.bottomMargin: Utils.dp(5) - - Image { - id: sectionImage - source: Category.imageSource(section) - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: providerStyle.leftIconMargin - height: parent.height - width: parent.width * 0.15 - fillMode: Image.PreserveAspectFit - } - - Text { - anchors.verticalCenter: parent.verticalCenter - anchors.left: sectionImage.right - anchors.leftMargin: providerStyle.leftProviderListMargin - color: providerStyle.categoryColor - font.pixelSize: providerStyle.categoryFontPixelSize - font.bold: providerStyle.categoryFontBold - elide: Text.ElideRight - text: Category.displayString(section) - } - - Text { - anchors.right: parent.right - anchors.rightMargin: Utils.dp(5) - anchors.verticalCenter: parent.verticalCenter - - text: ">" - color: Constants.grey - font.pixelSize: Utils.sp(14) - visible: providerStyle.showCategoryRightArrow - } - - MouseArea { - anchors.fill: parent - onClicked: { - push(categoryProviderView, {selectedCategory: section}) - } - } - } - - Rectangle { - width: parent.width * 0.85 - anchors.top: parent.bottom - anchors.topMargin: -height - anchors.right: parent.right - height: 1 - color: Constants.grey - } - } + AdditionalResultsItem { + id: additionalResults + width: parent.width } } } diff --git a/resources/qml/provider/ProviderViewDelegate.qml b/resources/qml/provider/ProviderViewDelegate.qml index 50f3f4a..d957c20 100644 --- a/resources/qml/provider/ProviderViewDelegate.qml +++ b/resources/qml/provider/ProviderViewDelegate.qml @@ -37,7 +37,7 @@ Rectangle { id: subjectText width: parent.width verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.normal_font_size elide: Text.ElideRight text: display } @@ -47,10 +47,10 @@ Rectangle { width: parent.width verticalAlignment: Text.AlignVCenter - font.pixelSize: Utils.sp(11) + font.pixelSize: Constants.small_font_size color: Constants.blue_dark elide: Text.ElideRight - text: addressDomain + text: providerAddressDomain } } Item { @@ -81,22 +81,6 @@ Rectangle { MouseArea { anchors.fill: parent - onClicked: { - push(providerDetailView, - { - selectedCategory: category, - shortName: model.shortName, - longName: model.longName, - shortDescription: model.shortDescription, - longDescription: model.longDescription, - address: model.address, - homepage: model.homepage, - phone: model.phone, - email: model.email, - postalAddress: model.postalAddress, - providerIcon: model.icon, - providerImage: model.image - }) - } + onClicked: push(providerDetailView, {providerModelItem: model}) } } diff --git a/resources/qml/provider/ProviderViewHeader.qml b/resources/qml/provider/ProviderViewHeader.qml deleted file mode 100644 index 8846b39..0000000 --- a/resources/qml/provider/ProviderViewHeader.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Rectangle { - id: baseItem - - property alias searchText: searchBar.searchText - - // Properties that are set by ProviderSectionView. - property string selectedCategory: "" - - property bool withButtons: false - - height: Constants.titlebar_height + Constants.searchbar_height - - SearchBar { - id: searchBar - - anchors.right: parent.right - anchors.bottom: parent.bottom - - width: parent.width - - searchBarColor: baseItem.selectedCategory === "" ? Constants.blue : Category.displayColor(baseItem.selectedCategory) - } -} diff --git a/resources/qml/provider/SearchBar.qml b/resources/qml/provider/SearchBar.qml index 455d266..7115613 100644 --- a/resources/qml/provider/SearchBar.qml +++ b/resources/qml/provider/SearchBar.qml @@ -4,20 +4,20 @@ import QtQuick.Controls.Styles 1.4 import "../global" + Rectangle { id: baseItem + height: Constants.titlebar_height + Constants.searchbar_height readonly property alias searchText: searchField.text - property color searchBarColor: Constants.blue - - color: searchBarColor - height: Constants.searchbar_height - MouseArea { id: pageArea onClicked: pageArea.focus = true - anchors.fill: parent + + height: Constants.searchbar_height + width: parent.width + anchors.bottom: parent.bottom Rectangle { anchors.left: parent.left @@ -49,9 +49,9 @@ Rectangle { anchors.right: parent.right anchors.rightMargin: Utils.dp(8) anchors.verticalCenter: parent.verticalCenter - width: Utils.dp(sourceSize.width / 2) - height: Utils.dp(sourceSize.height / 2) - source: "qrc:///images/text-edit-x.png" + width: Utils.dp(64) + height: Utils.dp(64) + source: "qrc:///images/iOS/search_cancel.svg" visible: searchField.text.length > 0 MouseArea { @@ -77,7 +77,7 @@ Rectangle { height: textEditX.height width: textEditX.width fillMode: Image.PreserveAspectFit - source: "qrc:///images/magnifying-glass.png" + source: "qrc:///images/iOS/search_icon.svg" visible: searchField.text.trim().length === 0 } @@ -88,7 +88,7 @@ Rectangle { anchors.verticalCenter: glassIcon.verticalCenter text: qsTr("Search") color: Constants.grey - font.pixelSize: Utils.sp(14) + font.pixelSize: Constants.normal_font_size visible: searchField.text.trim().length === 0 } } @@ -103,7 +103,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter clip: true font.family: "Helvetica" - font.pixelSize: Utils.sp(15) + font.pixelSize: Constants.normal_font_size color: "white" text: qsTr("Cancel") onClicked: { diff --git a/resources/qml/provider/TitleBarSearchAction.qml b/resources/qml/provider/TitleBarSearchAction.qml deleted file mode 100644 index 5eaeb49..0000000 --- a/resources/qml/provider/TitleBarSearchAction.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.5 - -Item { - property int availableWidth: 0 - readonly property string searchText: "" -} diff --git a/resources/qml_stationary/AusweisApp2/Global/Category.js b/resources/qml_stationary/AusweisApp2/Global/Category.js new file mode 100644 index 0000000..1fc8189 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/Category.js @@ -0,0 +1,86 @@ +var CATEGORY_COLOR_ALL = "#659bcd" +var CATEGORY_COLOR_CITIZEN = "#aa4079" +var CATEGORY_COLOR_INSURANCE = "#52539f" +var CATEGORY_COLOR_FINANCE = "#ecc758" +var CATEGORY_COLOR_OTHER = "#00868e" + +function displayString(cat) { + if (cat === "all") { + return qsTr("Provider") + } + if (cat === "citizen") { + return qsTr("Citizen services") + } + if (cat === "insurance") { + return qsTr("Insurances") + } + if (cat === "finance") { + return qsTr("Financials") + } + return qsTr("Other services") +} + +function displayColor(cat) { + if (cat === "all") { + return CATEGORY_COLOR_ALL + } + if (cat === "citizen") { + return CATEGORY_COLOR_CITIZEN + } + if (cat === "insurance") { + return CATEGORY_COLOR_INSURANCE + } + if (cat === "finance") { + return CATEGORY_COLOR_FINANCE + } + return CATEGORY_COLOR_OTHER +} + + +var CATEGORY_TO_IMAGE_NAME = { + "all": "General", + "citizen": "CitizenServices", + "insurance": "Insurances", + "finance": "Financials" +} + + +function imageName(cat) { + return cat in CATEGORY_TO_IMAGE_NAME ? CATEGORY_TO_IMAGE_NAME[cat] : "OtherServices" +} + + +function getPlatform() { +// return plugin.platformStyle.indexOf("android") !== -1 ? "+android/" : "" + return "+android/" +} + + +function gradientImageSource(cat) { + if (cat !== "citizen" && cat !== "insurance" && cat !== "finance") { + return "qrc:///images/provider/gradient-other.png" + } + else { + return "qrc:///images/provider/gradient-" + cat + ".png" + } +} + + +function backgroundImageSource(cat) { + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_bg.svg" +} + + +function buttonImageSource(cat) { + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_button.svg" +} + + +function imageSource(cat) { + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + ".svg" +} + + +function sectionImageSource(cat) { + return "qrc:///images/provider/categoryIcons/" + getPlatform() + imageName(cat) + "_section.svg" +} diff --git a/resources/qml_stationary/AusweisApp2/Global/CheckBox.qml b/resources/qml_stationary/AusweisApp2/Global/CheckBox.qml new file mode 100644 index 0000000..0b290bd --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/CheckBox.qml @@ -0,0 +1,12 @@ +import QtQuick 2.5 + +import "." + +Image { + property bool checked + + source: checked ? "qrc:///images/iOS/CheckedCheckbox.png" : "" + height: Utils.dp(20) + width: height + fillMode: Image.PreserveAspectFit +} diff --git a/resources/qml_stationary/AusweisApp2/Global/Constants.qml b/resources/qml_stationary/AusweisApp2/Global/Constants.qml new file mode 100644 index 0000000..b550b22 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/Constants.qml @@ -0,0 +1,49 @@ +pragma Singleton + +import QtQuick 2.5 + +import "." + +Item { + readonly property color all_image_background_color: PlatformConstants.all_image_background_color + readonly property bool use_history_list_delete_area: PlatformConstants.use_history_list_delete_area + + readonly property color background_color: "#dcebf6" + readonly property color blue: PlatformConstants.blue + readonly property color blue_dark: PlatformConstants.blue_dark + readonly property color blue_light: PlatformConstants.blue_light + readonly property color green: "#a3cb7f" + readonly property color red: "#cc0000" + readonly property color grey: "#8e8e93" + + readonly property color primary_text: PlatformConstants.primary_text + readonly property color secondary_text: PlatformConstants.secondary_text + readonly property color accent_color: PlatformConstants.accent_color + readonly property color second_accent_color: PlatformConstants.second_accent_color + + readonly property int header_font_size: Utils.sp(40) + readonly property int normal_font_size: Utils.sp(29) + readonly property int label_font_size: Utils.sp(25) + readonly property int small_font_size: Utils.sp(22) + + readonly property int titlebar_height: Utils.dp(48) + readonly property int titlebar_font_size: PlatformConstants.titlebar_font_size + + readonly property int menubar_width: Utils.dp(60) + + readonly property int searchbar_height: Utils.dp(48) + + readonly property int provider_section_height: PlatformConstants.provider_section_height + + readonly property int history_section_height: PlatformConstants.history_section_height + readonly property int history_delegate_spacing: PlatformConstants.history_delegate_spacing + readonly property color history_delegate_address_color: PlatformConstants.history_delegate_address_color + + readonly property int button_height: PlatformConstants.button_height + + readonly property int tabbar_height: Utils.dp(48) + + readonly property int component_spacing: Utils.dp(20) + readonly property int pane_padding: Utils.dp(20) + readonly property int pane_spacing: Utils.dp(20) +} diff --git a/resources/qml_stationary/AusweisApp2/Global/Pane.qml b/resources/qml_stationary/AusweisApp2/Global/Pane.qml new file mode 100644 index 0000000..1c7706b --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/Pane.qml @@ -0,0 +1,50 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "." + + +Rectangle { + id: root + property alias title: titleText.text + default property alias paneChildren: paneContent.children + + anchors.left: parent.left + anchors.right: parent.right + height: childrenRect.height + color: "white" + radius: 16 + + Column { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Constants.pane_padding + anchors.rightMargin: Constants.pane_padding + + Text { + id: titleText + height: implicitHeight * 2 + width: parent.width + visible: text !== "" + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.header_font_size + color: Constants.blue + } + Item { width: parent.width; height: Constants.pane_padding } + Column { + id: paneContent + width: parent.width + spacing: Constants.pane_spacing + } + Item { width: parent.width; height: Constants.pane_padding } + } + + layer.enabled: true + layer.effect: DropShadow { + radius: 8 + samples: 8 + source: root + color: Constants.grey + verticalOffset: 2 + } +} diff --git a/resources/qml_stationary/AusweisApp2/Global/PlatformConstants.qml b/resources/qml_stationary/AusweisApp2/Global/PlatformConstants.qml new file mode 100644 index 0000000..9295d03 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/PlatformConstants.qml @@ -0,0 +1,37 @@ +pragma Singleton + +import QtQuick 2.5 + +import "Utils.js" as Utils + +Item { + // Android-specific constants + readonly property color blue_primary: "#659bcd" + readonly property color blue_primary_dark: "#324d66" + readonly property color lila_accent_color: "#7879b2" + readonly property color green_second_accent_color: "#a3cb7f" + readonly property color white_primary_text: "#ffffff" + readonly property color dark_grey_secondary_text: "#444444" + readonly property color grey_light: "#bbbbbb" + readonly property color grey_border: "lightslategrey" + + readonly property color all_image_background_color: "#dcebf6" + readonly property color blue: blue_primary + readonly property color blue_dark: blue_primary_dark + readonly property color blue_light: blue_primary + readonly property color primary_text: white_primary_text + readonly property color secondary_text: dark_grey_secondary_text + readonly property color accent_color: lila_accent_color + readonly property color second_accent_color: green_second_accent_color + readonly property int titlebar_font_size: Utils.sp(18) + readonly property int provider_section_height: Utils.dp(62) + readonly property int history_section_height: Utils.dp(120) + readonly property int history_delegate_spacing: Utils.dp(10) + readonly property color history_delegate_address_color: lila_accent_color + readonly property int button_height: Utils.dp(36) + readonly property bool use_history_list_delete_area: false + + readonly property bool is_tablet: true + readonly property bool leftNavigation: true + readonly property bool bottomNavigation: false +} diff --git a/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml b/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml new file mode 100644 index 0000000..510a6b0 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml @@ -0,0 +1,92 @@ +import QtQuick 2.7 + + +/* + * Convenience utility to access properties of a ProviderModel item + * This ensures having always a defined string, i.e. a non-null string object. + */ +Item { + id: baseItem + property var modelItem + + readonly property string category: !!modelItem && !!modelItem.providerCategory ? modelItem.providerCategory : "" + readonly property string shortName: !!modelItem && !!modelItem.providerShortName ? modelItem.providerShortName : "" + readonly property string longName: !!modelItem && !!modelItem.providerLongName ? modelItem.providerLongName : "" + readonly property string shortDescription: !!modelItem && !!modelItem.providerShortDescription ? modelItem.providerShortDescription : "" + readonly property string longDescription: !!modelItem && !!modelItem.providerLongDescription ? modelItem.providerLongDescription : "" + readonly property string address: !!modelItem && !!modelItem.providerAddress ? modelItem.providerAddress : "" + readonly property string addressDomain: !!modelItem && !!modelItem.providerAddressDomain ? modelItem.providerAddressDomain : "" + readonly property string homepage: !!modelItem && !!modelItem.providerHomepage ? modelItem.providerHomepage : "" + readonly property string homepageBase: !!modelItem && !!modelItem.providerHomepageBase ? modelItem.providerHomepageBase : "" + readonly property string phone: !!modelItem && !!modelItem.providerPhone ? modelItem.providerPhone : "" + readonly property string phoneCost: !!modelItem && !!modelItem.providerPhoneCost ? modelItem.providerPhoneCost : "" + readonly property string email: !!modelItem && !!modelItem.providerEmail ? modelItem.providerEmail : "" + readonly property string postalAddress: !!modelItem && !!modelItem.providerPostalAddress ? modelItem.providerPostalAddress : "" + readonly property string icon: !!modelItem && !!modelItem.providerIcon ? modelItem.providerIcon : "" + readonly property string image: !!modelItem && !!modelItem.providerImage ? modelItem.providerImage : "" + + readonly property ListModel contactModel: ListModel { + readonly property alias homepage: baseItem.homepage + readonly property alias email: baseItem.email + readonly property alias phone: baseItem.phone + readonly property alias phoneCost: baseItem.phoneCost + readonly property string phoneDisplayString: { + var s = "" + if (!!phone) { + s = '' + phone + "" + if (!!phoneCost) { + s += "
" + phoneCost + } + } + return s + } + readonly property alias postalAddress: baseItem.postalAddress + + function removeHtml(htmlString) { + return htmlString.replace(/<\/?[a-z][a-z0-9]*[^>]*>/ig, " "); + } + + onHomepageChanged: { + setProperty(0, "text", !!homepage ? '' + homepage + "" : "") + setProperty(0, "link", !!homepage ? homepage : "") + } + onEmailChanged: { + setProperty(1, "text", !!email ? '' + email + "" : "") + setProperty(1, "link", !!email ? "mailto:" + email : "") + } + onPhoneDisplayStringChanged: { + setProperty(2, "text", phoneDisplayString) + } + onPostalAddressChanged: { + setProperty(3, "text", postalAddress) + } + + ListElement { + iconSource: "qrc:///images/provider/+tablet/url.png" + label: qsTr("Homepage") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/+tablet/mail.png" + label: qsTr("E-Mail") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/+tablet/telefon.png" + label: qsTr("Phone") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/+tablet/adresse.png" + label: qsTr("Contact") + text: "" + link: "" + } + } +} diff --git a/resources/qml_stationary/AusweisApp2/Global/Utils.js b/resources/qml_stationary/AusweisApp2/Global/Utils.js new file mode 100644 index 0000000..3469eb6 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/Utils.js @@ -0,0 +1,57 @@ + +function escapeHtml(str) +{ + return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} + +function isToday(date) +{ + var today = new Date; + return isSameDate(today, date); +} + +function isYesterday(date) +{ + var yesterday = new Date; + yesterday.setDate(yesterday.getDate() - 1); + return isSameDate(yesterday, date); +} + +function isThisWeek(date) +{ + var monday = new Date; + monday.setDate(monday.getDate()-monday.getDay()); + + date.setDate(date.getDate()-date.getDay()); + + return isSameDate(monday, date); +} + +function isSameDate(one, another) +{ + return one.getFullYear() === another.getFullYear() && one.getMonth() === another.getMonth() && one.getDate() === another.getDate(); +} + +function getRandomInt(min, max) +{ + return Math.floor(Math.random() * (max - min)) + min; +} + +var contentScaleFactor = screenDpi / 160 + +function dp(value) +{ + return value * contentScaleFactor +} + +function sp(value) +{ + var textScale = 1 + return dp(value) * textScale +} + + +// TODO: Use proper path for stationary +function providerIconSource(baseName) { + return "qrc:///images/provider/+tablet/" + baseName + ".png" +} diff --git a/resources/qml_stationary/AusweisApp2/Global/qmldir b/resources/qml_stationary/AusweisApp2/Global/qmldir new file mode 100644 index 0000000..9511f37 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Global/qmldir @@ -0,0 +1,8 @@ +module Global +singleton Constants 1.0 Constants.qml +singleton PlatformConstants 1.0 PlatformConstants.qml +Category 1.0 Category.js +CheckBox 1.0 CheckBox.qml +Pane 1.0 Pane.qml +Utils 1.0 Utils.js +ProviderModelItem 1.0 ProviderModelItem.qml diff --git a/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml b/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml new file mode 100644 index 0000000..51e177a --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml @@ -0,0 +1,181 @@ +import AusweisApp2.Global 1.0 + +import QtQml 2.2 +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.3 + + +Item { + id: baseItem + + Column { + id: header + width: parent.width + spacing: Constants.pane_spacing + + Text { + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("This page displays the history of your successful authentications. " + + "Double-click on a service provider for more information. " + + "You can delete parts or the entire history. " + + "You can also save the history as a PDF file.") + } + + Item { + height: searchField.height + width: parent.width + + Text { + id: searchLabel + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Search:") + textFormat: Text.StyledText + } + TextField { + id: searchField + anchors.left: searchLabel.right + anchors.leftMargin: Constants.pane_spacing + anchors.right: parent.right + onTextChanged: historyModel.searchFilter.setFilterString(text) + } + } + } + + Item { + anchors.top: header.bottom + anchors.topMargin: header.spacing + anchors.bottom: footer.top + anchors.bottomMargin: header.spacing + width: parent.width + + Text { + anchors.centerIn: parent + text: qsTr("No history entry available") + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: !scrollView.visible + } + + ScrollView { + id: scrollView + width: parent.width + anchors.fill: parent + anchors.topMargin: 1 + anchors.bottomMargin: 1 + clip: true + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn + visible: listView.count > 0 + + Rectangle { + width: baseItem.width + height: listView.contentHeight + color: PlatformConstants.grey_border + + } + + ListView { + id: listView + width: parent.width + spacing: 1 + model: historyModel.searchFilter + + delegate: ListViewDelegate { + width: parent.width + height: Utils.dp(120) + historyModelItem: model + onShowHistoryDetails:widgetPlugin.showDetailDialog(model.termsOfUsage) + } + } + } + + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: PlatformConstants.grey_border + } + Rectangle { + anchors.bottom: parent.bottom + anchors.bottomMargin: height + width: parent.width + height: 1 + color: PlatformConstants.grey_border + } + } + + Rectangle { + id: footer + width: parent.width + height: Utils.dp(50) + anchors.bottom: parent.bottom + + RowLayout { + anchors.fill: parent + spacing: Constants.pane_spacing + + Text { + text: qsTr("History:") + } + + CheckBox { + checked: historyModel.enabled + onCheckedChanged: historyModel.enabled = checked + } + + Item { + // Quickfix because CheckBox text turns into a black box sometimes + // TODO: Use text property from checkbox + height: childrenRect.height + width: childrenRect.width + + Text { + anchors.left: parent.left + anchors.leftMargin: -Constants.pane_spacing + text: qsTr("save") + } + } + + Item { + Layout.fillWidth: true + } + + Button { + text: qsTr("Delete History") + enabled: listView.count > 0 + onClicked: deleteConfirmationDialog.open() + } + + Button { + text: qsTr("Save as PDF") + enabled: listView.count > 0 + onClicked: fileDialog.open() + } + } + } + + + MessageDialog { + id: deleteConfirmationDialog + icon: StandardIcon.Question + modality: Qt.ApplicationModal + standardButtons: StandardButton.Yes | StandardButton.No + title: qsTr("Delete history") + text: qsTr("Do you really want to delete the history?") + onYes: { historyModel.removeRows(0, historyModel.rowCount()) } + } + FileDialog { + id: fileDialog + modality: Qt.ApplicationModal + selectExisting: false + title: Qt.application.name + " - " + qsTr("Save history") + folder: shortcuts.home + nameFilters: [qsTr("PDF Documents (*.pdf)")] + onAccepted: { + qmlExtension.exportHistory(fileDialog.fileUrls) + } + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegate.qml b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegate.qml new file mode 100644 index 0000000..c1d7daa --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegate.qml @@ -0,0 +1,55 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + + +Rectangle { + id: baseItem + property var historyModelItem + signal showHistoryDetails + + Item { + id: sectionImage + height: parent.height + width: Utils.dp(80) + + Rectangle { + id: providerImage + anchors.fill: parent + anchors.margins: Utils.dp(10) + color: baseItem.historyModelItem ? Category.displayColor(baseItem.historyModelItem.providerCategory) : Category.displayColor("unknown" ) + visible: !!providerIconSource + readonly property string providerIconSource: baseItem.historyModelItem ? baseItem.historyModelItem.providerIcon : "" + + Image { + source: parent.providerIconSource + anchors.fill: parent + anchors.margins: Utils.dp(10) + asynchronous: true + fillMode: Image.PreserveAspectFit + } + } + Image { + id: categoryImage + anchors.fill: parent + anchors.margins: Utils.dp(10) + source: baseItem.historyModelItem ? Category.sectionImageSource(baseItem.historyModelItem.providerCategory) : Category.sectionImageSource("unknown") + asynchronous: true + clip: true + visible: !providerImage.visible + } + } + + ListViewDelegateContent { + anchors.left: sectionImage.right + anchors.right: parent.right + height: parent.height + historyModelItem: baseItem.historyModelItem + } + + MouseArea { + anchors.fill: parent + onDoubleClicked: baseItem.showHistoryDetails() + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml new file mode 100644 index 0000000..2235007 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml @@ -0,0 +1,54 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +Item { + id: baseItem + property var historyModelItem + readonly property string providerName: !!historyModelItem.providerLongName ? historyModelItem.providerLongName : historyModelItem.providerShortName + + + Text { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.verticalCenter + anchors.margins: Utils.dp(15) + anchors.bottomMargin: 0 + + verticalAlignment: Text.AlignVCenter + font.capitalization: Font.AllUppercase + elide: Text.ElideRight + text: { + if (!historyModelItem) { + return ""; + } + else if (Utils.isToday(historyModelItem.dateTime)) { + return qsTr("today") + } + else if (Utils.isYesterday(historyModelItem.dateTime)) { + return qsTr("yesterday") + } + else if (Utils.isThisWeek(historyModelItem.dateTime)) { + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) + } + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + } + } + Text { + anchors.top: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Utils.dp(15) + anchors.topMargin: 0 + + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.small_font_size + elide: Text.ElideRight + color: Constants.blue_dark + text: !!providerName ? providerName : historyModelItem.subject + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/History/qmldir b/resources/qml_stationary/AusweisApp2/Views/History/qmldir new file mode 100644 index 0000000..f426001 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/History/qmldir @@ -0,0 +1,2 @@ +module AusweisApp2.Views.History +HistoryView 1.0 HistoryView.qml diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml new file mode 100644 index 0000000..c4019ba --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml @@ -0,0 +1,46 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + + +Rectangle { + id: baseItem + readonly property int totalHits: providerModel.additionalResultCount + + visible: totalHits > 0 && providerModel.categories.length > 0 && providerModel.categories.indexOf("all") === -1 + + Image { + id: backgroundImage + anchors.margins: Utils.dp(10) + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + width: Utils.dp(60) + source: Category.backgroundImageSource("all") + asynchronous: true + clip: true + Image { + id: foregroundImage + anchors.fill: parent + anchors.margins: parent.anchors.margins + source: Category.imageSource("all") + asynchronous: true + clip: true + fillMode: Image.PreserveAspectFit + } + } + + Text { + text: qsTr("Additional results in other categories: %1").arg(baseItem.totalHits) + anchors.verticalCenter: parent.verticalCenter + anchors.left: backgroundImage.right + anchors.margins: Utils.dp(15) + anchors.right: parent.right + } + + MouseArea { + anchors.fill: parent + onDoubleClicked: providerModel.addAdditionalResultCategories() + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/CategoryCheckbox.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/CategoryCheckbox.qml new file mode 100644 index 0000000..b43aab8 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/CategoryCheckbox.qml @@ -0,0 +1,52 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +Item { + id: baseItem + height: parent.height + width: mainContent.width + anchors.verticalCenter: parent.verticalCenter + + property string category: "" + property alias imageSource: icon.source + property alias text: label.text + + Row { + id: mainContent + height: parent.height + spacing: Utils.dp(5) + anchors.verticalCenter: parent.verticalCenter + + Image { + id: icon + height: baseItem.height * 0.7 + width: height + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: label + font.pixelSize: Constants.small_font_size + anchors.verticalCenter: parent.verticalCenter + } + + CheckBox { + id: checkbox + anchors.verticalCenter: parent.verticalCenter + visible: true + checked: providerModel.categories.indexOf(baseItem.category) !== -1 + + // TODO: At this time there is no way to select and toggle the checkbox with keyboard. + // Depending on the selection model in future the following line is needed. + // onCheckedChanged: providerModel.updateCategorySelection(category, checked) + } + } + + MouseArea { + anchors.fill: parent + onClicked: providerModel.updateCategorySelection(category, !checkbox.checked) + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCard.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCard.qml new file mode 100644 index 0000000..5c7da83 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCard.qml @@ -0,0 +1,55 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + + +Rectangle { + id: baseItem + property var providerModelItem: null + signal showProviderDetails + + Item { + id: sectionImage + height: parent.height + width: Utils.dp(80) + + Rectangle { + id: providerImage + anchors.fill: parent + anchors.margins: Utils.dp(10) + color: baseItem.providerModelItem ? Category.displayColor(baseItem.providerModelItem.providerCategory) : Category.displayColor("unknown" ) + visible: !!providerIconSource + readonly property string providerIconSource: baseItem.providerModelItem ? baseItem.providerModelItem.providerIcon : "" + + Image { + source: parent.providerIconSource + anchors.fill: parent + anchors.margins: Utils.dp(10) + asynchronous: true + fillMode: Image.PreserveAspectFit + } + } + Image { + id: categoryImage + anchors.fill: parent + anchors.margins: Utils.dp(10) + source: baseItem.providerModelItem ? Category.sectionImageSource(baseItem.providerModelItem.providerCategory) : Category.sectionImageSource("unknown") + asynchronous: true + clip: true + visible: !providerImage.visible + } + } + ProviderCardInfoItem { + height: parent.height + anchors.left: sectionImage.right + anchors.right: parent.right + providerName: !!providerModelItem.providerLongName ? providerModelItem.providerLongName : providerModelItem.providerShortName + providerAddressDomain: providerModelItem.providerAddressDomain + } + + MouseArea { + anchors.fill: parent + onDoubleClicked: baseItem.showProviderDetails() + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCardInfoItem.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCardInfoItem.qml new file mode 100644 index 0000000..89e7aff --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderCardInfoItem.qml @@ -0,0 +1,40 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 + + +Rectangle { + id: baseItem + + property alias providerName: subjectText.text + property alias providerAddressDomain: addressText.text + + Text { + id: subjectText + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.verticalCenter + anchors.margins: Utils.dp(15) + anchors.bottomMargin: 0 + + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + Text { + id: addressText + anchors.top: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Utils.dp(15) + anchors.topMargin: 0 + + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.small_font_size + elide: Text.ElideRight + color: Constants.blue_dark + } +} + diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml new file mode 100644 index 0000000..bbca995 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml @@ -0,0 +1,166 @@ +import AusweisApp2.Global 1.0 +import AusweisApp2.Views.ProviderDetails 1.0 + +import QtQml 2.2 +import QtQuick 2.6 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.3 + + +Rectangle { + id: baseItem + property color titleBarColor: Constants.blue + readonly property real titleBarOpacity: 1 + readonly property int headerHeight: Utils.dp(54) + readonly property int separatorHeight: Utils.dp(2) + color: "white" + + Column { + id: header + width: parent.width + spacing: Constants.pane_spacing + + Text { + width: parent.width + text: qsTr("

This section lists offers of service providers that support online identification. " + + "Click on an entry to go to the provider's web site. This section will be continuously updated with further applications for " + + "the online identification function.

") + wrapMode: Text.Wrap + } + + Item { + height: searchField.height + width: parent.width + + Text { + id: searchLabel + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Search:") + textFormat: Text.StyledText + } + TextField { + id: searchField + anchors.left: searchLabel.right + anchors.leftMargin: Constants.pane_spacing + anchors.right: parent.right + text: "" + onTextChanged: providerModel.searchString = text + } + } + + Row { + id: checkBoxesItem + height: Utils.dp(40) + anchors.horizontalCenter: parent.horizontalCenter + padding: space + readonly property real space: (parent.width - checkBoxCitizen.width - checkBoxInsurance.width - checkBoxFinance.width - checkBoxOther.width) / 5 + spacing: space + + CategoryCheckbox { + id: checkBoxCitizen + category: "citizen" + imageSource: Category.imageSource("citizen") + text: qsTr("Citizen services") + } + + CategoryCheckbox { + id: checkBoxInsurance + category: "insurance" + imageSource: Category.imageSource("insurance") + text: qsTr("Insurances") + } + + CategoryCheckbox { + id: checkBoxFinance + category: "finance" + imageSource: Category.imageSource("finance") + text: qsTr("Financials") + } + + CategoryCheckbox { + id: checkBoxOther + category: "other" + imageSource: Category.imageSource("other") + text: qsTr("Other services") + } + } + } + + Item { + anchors.top: header.bottom + anchors.topMargin: header.spacing + anchors.bottom: parent.bottom + width: parent.width + + Text { + anchors.centerIn: parent + text: qsTr("No match found") + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: !scrollView.visible + } + ScrollView { + id: scrollView + anchors.fill: parent + anchors.topMargin: 1 + anchors.bottomMargin: 1 + clip: true + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn + visible: tableRepeater.count > 0 || additionalResults.totalHits > 0 + + Rectangle { + width: baseItem.width + height: table.height + color: PlatformConstants.grey_border + + Column { + id: table + width: parent.width + spacing: 1 + + Repeater { + id: tableRepeater + model: providerModel + + ProviderCard { + height: Utils.dp(120) + width: parent.width + providerModelItem: model + onShowProviderDetails: { + historyModel.nameFilter.setProviderAddress(model.providerAddress) + providerDetailsDialog.providerModelItem = model + providerDetailsDialog.visible = true + } + } + } + AdditionalResultsItem { + id: additionalResults + width: parent.width + height: Utils.dp(120) + } + } + } + } + + Rectangle { + anchors.top: parent.top + width: parent.width + height: 1 + color: PlatformConstants.grey_border + } + Rectangle { + anchors.bottom: parent.bottom + width: parent.width + height: 1 + color: PlatformConstants.grey_border + } + } + + + ProviderDetailsDialog { + id: providerDetailsDialog + visible: false + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/qmldir b/resources/qml_stationary/AusweisApp2/Views/Provider/qmldir new file mode 100644 index 0000000..9601e44 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/qmldir @@ -0,0 +1,2 @@ +module AusweisApp2.Views.Provider +ProviderView 1.0 ProviderView.qml diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml new file mode 100644 index 0000000..442ffcf --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml @@ -0,0 +1,52 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import AusweisApp2.Global 1.0 + + +Rectangle { + id: baseItem + + property alias contactModel: contactListView.model + + Column { + id: info + width: baseItem.width / info.scaleFactor // fill whole width + transform: Scale { yScale: info.scaleFactor; xScale: info.scaleFactor } + + readonly property real scaleFactor: { + var unscaledElementsAccumulatedHeight = 3 + var factor = height > baseItem.height ? (baseItem.height - unscaledElementsAccumulatedHeight) / height : 1 + if (factor <= 0) { + return 1 + } + return factor + } + + Text { + text: qsTr("Contact") + padding: Constants.component_spacing + font.pixelSize: Constants.header_font_size + color: "white" + } + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + height: contactListView.height + ListView { + id: contactListView + width: parent.width + height: contentHeight + interactive: false + spacing: 2 + delegate: ProviderContactInfoItem { + width: contactListView.width + color: baseItem.color + imageSource: Qt.resolvedUrl(model.iconSource) + itemText: !!model.text ? model.text : qsTr("Unknown") + link: model.link + } + } + } + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfoItem.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfoItem.qml new file mode 100644 index 0000000..bd15dd8 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfoItem.qml @@ -0,0 +1,45 @@ +import QtQuick 2.6 + +import AusweisApp2.Global 1.0 + + +Rectangle { + id: baseItem + property alias imageSource: image.source + property alias itemText: text.text + property url link + height: Math.max(Utils.dp(60), text.height + Utils.dp(10)) + + Item { + id: iconItem + height: parent.height + width: Math.min(height, Utils.dp(60)) + anchors.left: parent.left + + Image { + id: image + width: parent.width * 0.5 + height: width + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + } + } + Text { + id: text + anchors.left: iconItem.right + anchors.leftMargin: Utils.dp(10) + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Constants.normal_font_size + color: "white" + linkColor: color + elide: Text.ElideRight + wrapMode: Text.WordWrap + } + + MouseArea { + anchors.fill: parent + enabled: !!baseItem.link + onClicked: Qt.openUrlExternally(baseItem.link) + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml new file mode 100644 index 0000000..55ca344 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml @@ -0,0 +1,47 @@ +import QtQuick 2.6 +import QtQuick.Controls 1.4 + +import AusweisApp2.Global 1.0 + + +Item { + id: baseItem + + height: button.height + Constants.component_spacing + width: parent.width + + property string selectedCategory: "" + property string providerIcon: "" + property string address: "" + property color titleBarColor + + Image { + id: icon + source: baseItem.providerIcon !== "" ? baseItem.providerIcon : + Category.buttonImageSource(baseItem.selectedCategory) + asynchronous: true + height: 2 * baseItem.height + width: height + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.verticalCenter: baseItem.top + } + + Button { + id: button + text: qsTr("ONLINE-APPLICATION") + // TODO: Use custom button +// buttonColor: baseItem.titleBarColor + anchors.left: icon.right + anchors.leftMargin: Constants.component_spacing + anchors.bottom: icon.bottom + enabled: baseItem.address !== "" + + onClicked: { + if (baseItem.address !== "") { + Qt.openUrlExternally(baseItem.address) + } + } + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml new file mode 100644 index 0000000..b96b42c --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml @@ -0,0 +1,31 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Controls 1.4 + + +ScrollView { + id: baseItem + property string description: "" + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn + + Column { + spacing: Constants.pane_spacing + + Text { +// font.pixelSize: Constants.header_font_size + color: PlatformConstants.blue_primary + text: qsTr("Description") + } + + Text { +// font.pixelSize: Constants.normal_font_size + text: baseItem.description + width: baseItem.width - Utils.dp(50) + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignJustify + } + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailView.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailView.qml new file mode 100644 index 0000000..8b6b829 --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailView.qml @@ -0,0 +1,140 @@ +import AusweisApp2.Global 1.0 + +import QtQuick 2.6 +import QtQuick.Controls 1.4 + + +Item { + id: baseItem + + property alias providerModelItem: provider.modelItem + + ProviderModelItem { + id: provider + } + + function historyInfoIsOpen() { + return providerDetailsHistoryInfo.visible + } + + function closeHistoryInfo() { + providerDetailsHistoryInfo.visible = false + } + + property color titleBarColor: Category.displayColor(provider.category) + + + Rectangle { + id: titleBar + height: Utils.dp(40) + width: baseItem.width + color: baseItem.titleBarColor + + Text { + text: provider.shortName + font.bold: true + color: "white" + + anchors.left: titleBar.left + anchors.leftMargin: Constants.component_spacing + anchors.verticalCenter: titleBar.verticalCenter + } + } + + Row { + id: header + height: Utils.dp(300) + width: parent.width + anchors.top: titleBar.bottom + + Item { + height: parent.height + width: baseItem.width * 2 / 3 + anchors.top: parent.top + + Image { + id: image + source: provider.image !== "" ? provider.image : + Category.backgroundImageSource(provider.category) + asynchronous: true + height: parent.height + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + } + + Image { + height: parent.height + width: height / 2 + anchors.right: image.right + anchors.top: parent.top + fillMode: Image.Stretch + source: Category.gradientImageSource(provider.category) + + } + + Rectangle { + anchors.left: image.right + anchors.right: parent.right + anchors.top: parent.top + height: parent.height + color: baseItem.titleBarColor + } + } + + Rectangle { + height: parent.height + width: baseItem.width / 3 + color: baseItem.titleBarColor + + ProviderContactInfo { + color: baseItem.titleBarColor + height: parent.height + width: baseItem.width / 3 - Constants.component_spacing + contactModel: provider.contactModel + } + } + } + + ProviderDetailButtonBar { + id: buttonBar + selectedCategory: provider.category + providerIcon: provider.icon + address: provider.address + titleBarColor: baseItem.titleBarColor + anchors.top: header.bottom + } + + Pane { + id: leftPane + anchors.margins: Constants.component_spacing + anchors.top: buttonBar.bottom + anchors.bottom: closeButton.top + + ProviderDetailDescription { + id: descriptionData + width: parent.width + height: leftPane.height - 2 * Constants.pane_padding + description: provider.longDescription + } + } + + Button { + id: closeButton + text: "Close" + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Constants.component_spacing + onClicked: close() + } + + property var openHistoryInfoFunc: function(entryInfo) { + providerDetailsHistoryInfo.visible = true + + providerDetailsHistoryInfo.providerName = entryInfo['providerName'] + providerDetailsHistoryInfo.providerPostalAddress = entryInfo['providerPostalAddress'] + providerDetailsHistoryInfo.purposeText = entryInfo['purposeText'] + providerDetailsHistoryInfo.requestedDataText = entryInfo['requestedDataText'] + providerDetailsHistoryInfo.termsOfUsageText = entryInfo['termsOfUsageText'] + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml new file mode 100644 index 0000000..14ed85d --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml @@ -0,0 +1,31 @@ +import QtQuick 2.6 +import QtQuick.Controls 1.4 +import QtQuick.Window 2.2 + +import AusweisApp2.Global 1.0 +import AusweisApp2.Views.Provider 1.0 + +Window { + id: baseItem + title: qsTr("Provider details") + height: Utils.dp(900) + minimumHeight: Utils.dp(700) + width: Utils.dp(1200) + minimumWidth: Utils.dp(800) + modality: Qt.ApplicationModal + color: Constants.background_color + + property var providerModelItem: null + + ProviderDetailView { + anchors.centerIn: parent + height: parent.height + width: parent.width + providerModelItem: baseItem.providerModelItem + } + + Connections { + target: applicationModel + onCurrentWorkflowChanged: if (!!applicationModel.currentWorkflow) {baseItem.close()} + } +} diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/qmldir b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/qmldir new file mode 100644 index 0000000..0c43e6d --- /dev/null +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/qmldir @@ -0,0 +1,7 @@ +module AusweisApp2.Views.ProviderDetails +ProviderDetailsDialog 1.0 ProviderDetailsDialog.qml +ProviderContactInfoItem 1.0 ProviderContactInfoItem.qml +ProviderContactInfo 1.0 ProviderContactInfo.qml +ProviderDetailButtonBar 1.0 ProviderDetailButtonBar.qml +ProviderDetailDescription 1.0 ProviderDetailDescription.qml +ProviderDetailView 1.0 ProviderDetailView.qml diff --git a/resources/qml_stationary/HistoryWidgetQmlPlugin.qml b/resources/qml_stationary/HistoryWidgetQmlPlugin.qml new file mode 100644 index 0000000..2d2c73c --- /dev/null +++ b/resources/qml_stationary/HistoryWidgetQmlPlugin.qml @@ -0,0 +1,3 @@ +import AusweisApp2.Views.History 1.0 + +HistoryView {} diff --git a/resources/qml_stationary/ProviderWidgetQmlPlugin.qml b/resources/qml_stationary/ProviderWidgetQmlPlugin.qml new file mode 100644 index 0000000..90e2c69 --- /dev/null +++ b/resources/qml_stationary/ProviderWidgetQmlPlugin.qml @@ -0,0 +1,4 @@ +import AusweisApp2.Views.Provider 1.0 + +ProviderView { +} diff --git a/resources/qtquickcontrols2.conf b/resources/qtquickcontrols2.conf new file mode 100644 index 0000000..caace6d --- /dev/null +++ b/resources/qtquickcontrols2.conf @@ -0,0 +1,2 @@ +[Controls] +Style=Default diff --git a/resources/translations/ausweisapp2_de.ts b/resources/translations/ausweisapp2_de.ts index cbc1ffe..50b70fd 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -30,12 +30,18 @@ - AdditionalResultsCard + AdditionalResultsItem - - Additional results: + + + Additional results: Weitere Ergebnisse: + + + Additional results in other categories: %1 + Weitere Ergebnisse in anderen Kategorien: %1 + AppQtMainWidget @@ -69,11 +75,6 @@ Settings Einstellungen - - - &Help - &Hilfe - Minimise @@ -174,6 +175,11 @@ &Setup assistant &Einrichtungsassistent + + + &Help + &Hilfe + &Diagnosis @@ -183,106 +189,156 @@ BluetoothWorkflow - - Enter PUK... - Bitte geben Sie nun Ihre PUK am Gerät ein... + + Enable Bluetooth + Bluetooth aktivieren - - Enter CAN... - Bitte geben Sie nun Ihre CAN am Gerät ein... + + Continue + Fortsetzen - - Enter PIN... - Bitte geben Sie nun Ihre PIN am Gerät ein... + + Bluetooth is not supported by your device.<br/>Please try NFC. + Ihr Gerät unterstützt kein Bluetooth.<br/>Bitte versuchen Sie NFC. - - Enter new PIN... - Bitte geben Sie nun Ihre neue PIN am Gerät ein... + + Bluetooth is switched off.<br/>Please enable Bluetooth. + Bluetooth ist deaktiviert.<br/>Bitte aktivieren Sie Bluetooth. - + + No paired and activated Bluetooth device was detected. The AusweisApp2 needs access to your location in order to discover available devices. You can grant this permission after clicking the continue button. + Es konnte kein verbundener, eingeschalteter Bluetooth-Kartenleser erkannt werden. Zur Erkennung benötigt die AusweisApp2 Zugriff auf Ihren Standort. Nach Klicken auf den Weiter-Knopf können Sie die benötigte Freigabe erteilen. + + + Establish connection - Verbindung herstellen + Verbindung wird hergestellt - + Determine card - Karte auswählen + Ermittle Ausweis - + Change PIN PIN ändern - + Authenticate Jetzt ausweisen - - Establish connection... - Verbindung wird hergestellt... + + The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function. + Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an Ihre zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren. - - Insert card... - Ausweis ins Gerät legen... + + Connecting... + Verbinde... + + + + Please insert your ID card. + Bitte legen Sie Ihren Ausweis ein. + + + + Please enter your old PIN or your initial transport PIN first. + Geben Sie bitte zunächst Ihre alte PIN bzw. die Transport-PIN ein. + + + + Please enter your personal PIN. + Geben Sie bitte Ihre persönliche PIN ein. + + + + You have entered the wrong PIN twice. For a third attempt, you have to enter your six-digit card access number first. You can find your card access number on the front of your ID card. + Sie haben Ihre PIN zweimal falsch eingegeben. Für einen dritten Versuch müssen Sie vorher Ihre 6-stellige Zugangsnummer eingeben. Sie finden Ihre Zugangsnummer auf der Vorderseite Ihres Ausweises. + + + + You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking. + Sie haben Ihre PIN dreimal falsch eingegeben. Ihre PIN ist jetzt gesperrt. Zum Entsperren geben Sie bitte Ihre PUK ein. + + + + Please enter a new arbitrary 6-digit PIN. + Geben Sie hier bitte eine von Ihnen frei wählbare, 6-stellige PIN ein. + + + + Use NFC instead of<br/>Bluetooth card reader + NFC anstatt Bluetooth<br/>Kartenleser benutzen BusyOverlay - The process is started … - Der Vorgang wird gestartet… + The process is started... + Der Vorgang wird gestartet... Category - + + Provider Anbieter - + + All + Alle + + + + Citizen services Bürgerdienste - + + Insurances Versicherungen - + + Financials Finanzen - + + Other services Weitere Services - CertificateDescription + CertificateDescriptionPage - - see details under more... - siehe Details unter mehr... + + Provider Information + Anbieterinformationen - CertificateDescriptionPage + ChangePinController - - Provider Information - Anbieterinformationen + + You may now remove your ID card from the device. + Sie können nun Ihr Ausweisdokument vom Gerät entfernen. @@ -321,24 +377,32 @@ CustomSwipeBar - Contact Kontakt - History Verlauf + + + CONTACT + KONTAKT + + + + HISTORY + VERLAUF + DataGroup - - No data available - Keine Daten verfügbar + + No data requested + Keine Daten erforderlich @@ -384,8 +448,8 @@ - Save… - Speichern… + Save as... + Speichern... @@ -396,137 +460,107 @@ EnterPinView - - Identify - Ausweisen + + The entered PIN does not match the new PIN. Please correct your input. + Die eingegebene PIN stimmt nicht mit Ihrer neuen PIN überein. Bitte korrigieren Sie Ihre PIN-Eingabe. - - Change PIN - PIN ändern + + You have entered the wrong PIN twice. For a third attempt, you have to enter your six-digit card access number first. You can find your card access number on the front of your ID card. + Sie haben Ihre PIN zweimal falsch eingegeben. Für einen dritten Versuch müssen Sie vorher Ihre 6-stellige Zugangsnummer eingeben. Sie finden Ihre Zugangsnummer auf der Vorderseite Ihres Ausweises. + + + + You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking. + Sie haben Ihre PIN dreimal falsch eingegeben. Ihre PIN ist jetzt gesperrt. Zum Entsperren geben Sie bitte Ihre PUK ein. + + + + Please enter a new arbitrary 6-digit PIN. + Geben Sie hier bitte eine von Ihnen frei wählbare, 6-stellige PIN ein. + + + + Please confirm your new PIN by re-entering your personal PIN. + Bestätigen Sie bitte die PIN-Änderung durch die erneute Eingabe Ihrer persönlichen PIN. + + + + Please enter your personal PIN. + Geben Sie bitte Ihre persönliche PIN ein. + + + + Please enter your old PIN or your initial transport PIN first. + Geben Sie bitte zunächst Ihre alte PIN bzw. die Transport-PIN ein. - FvUpdateWindow + Feedback - - Software Update - Software-Aktualisierung + + Dialog & Feedback + Dialog & Rückmeldung - - A new version of %1 is available! - Es ist eine neue Version der %1 verfügbar! + + Your opinion matters + Ihre Meinung zählt - - %1 %2 is now available - you have %3. Would you like to download it now? - %1 %2 ist jetzt verfügbar, Ihre Version ist %3. Wollen Sie die neue Version jetzt herunterladen? + + We are happy about every feedback on our software. + Wir freuen uns über Ihre Rückmeldung zu unserem Programm. - - Release Notes: - Aktualisierungshinweise: + + Rate AusweisApp2 + Bewerten Sie die AusweisApp2 - - The update file is located at: - Die Aktualisierungsdatei finden Sie hier: + + Please rate us on the Google Play Store. + Bitte bewerten Sie uns im Google Play Store. - - <a href="%1">%1</a> - <a href="%1">%1</a> + + Share + Teilen - - Download this update and close "%1". Install the update and start "%1" again. - Laden Sie die aktuelle Version der Software herunter und schließen Sie die "%1". Installieren Sie die neue Software-Version und starten Sie anschließend die "%1" erneut. + + Tell your friends about AusweisApp2. + Erzählen Sie Ihren Freunden und Bekannten von der AusweisApp2. - - When you click "Download update", this link will be opened in your browser. - Wenn Sie "Aktualisierung herunterladen" klicken, wird dieser Link in Ihrem Browser geöffnet. + + Share with + Teilen mit - - Skip update - Aktualisierung auslassen + + I'm using AusweisApp2, download it here for Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2 + Ich verwende die AusweisApp2, laden Sie die AusweisApp2 für Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2 - - Remind me later - Später erinnern + + Report error + Melden Sie einen Fehler - - Download update - Aktualisierung herunterladen + + You found a bug? Please tell us, so we can fix it. + Sie haben einen Fehler gefunden? Teilen Sie ihn uns mit, damit wir ihn beheben können. - - skip update of current version - Aktualisierung der aktuellen Version auslassen + + Android log file + Android Protokolle - - remind me later for this available version - Später an diese verfügbare Version erinnern - - - - download available version - Verfügbare Version herunterladen - - - - FvUpdater - - - Unable to open this link in a browser. Please copy and paste the link into the address bar of your browser. - Der Link konnte im Browser nicht geöffnet werden. Bitte kopieren Sie den Link aus dieser Meldung und fögen ihn manuell in die Adressleiste Ihres Browsers ein. - - - - An error occurred. Please contact our support at <a href="https://www.ausweisapp.bund.de/en/service/support/">AusweisApp2 Support</a>. - Ein Fehler ist aufgetreten. Bitte kontaktieren Sie unseren Support unter <a href="https://www.ausweisapp.bund.de/service/support/">AusweisApp2 Support</a>. - - - - Feed parsing failed: %1 %2. - Analyse der Eingabe fehlgeschlagen: %1 %2. - - - - - - Your software is up to date. - Ihre Software ist auf aktuellem Stand. - - - - Feed error: "release notes" link is empty - Eingabefehler: Der Link "Release-Notes" ist leer - - - - Feed error: invalid "release notes" link - Eingabefehler: Ungültiger Link zu den Release-Notes - - - - Feed error: invalid "enclosure" with the download link - Eingabefehler: Ungültige Einschließung im Download-Link - - - - Error - Fehler - - - - Information - Information + + <Please describe the error> + <Bitte beschreiben Sie den Fehler> @@ -615,12 +649,12 @@ HistoryDetails - + Delete Löschen - + Go to online application Gehe zu Online-Anwendung @@ -628,7 +662,7 @@ HistoryListView - + Delete Löschen @@ -636,25 +670,30 @@ HistoryListViewDelegateContent - + today heute - + yesterday gestern - + dddd dddd - + MM/dd/yyyy dd.MM.yyyy + + + Touch for more details + Berühren Sie hier für mehr Details + HistoryView @@ -665,8 +704,8 @@ Verlauf - - + + Currently there are no history entries. Derzeit gibt es keine Einträge im Verlauf. @@ -681,41 +720,96 @@ Delete all Alle löschen + + + This page displays the history of your successful authentications. Double-click on a service provider for more information. You can delete parts or the entire history. You can also save the history as a PDF file. + Auf dieser Seite sehen Sie den Verlauf Ihrer erfolgreichen Authentisierungen. Mit einem Doppelklick erhalten Sie weitere Informationen zum ausgewählten Diensteanbieter. Den Verlauf können Sie in Teilen oder auch komplett löschen. Es ist darüber hinaus auch möglich, den Verlauf zu speichern. + + + + Search: + Suche: + + + + No history entry available + Kein Eintrag vorhanden + + + + History: + Verlauf: + + + + save + speichern + + + + Delete History + Verlauf löschen + + + + Save as PDF + Speichern als PDF + + + + Delete history + Verlauf löschen + + + + Do you really want to delete the history? + Möchten Sie den Verlauf wirklich löschen? + + + + Save history + Verlauf speichern + + + + PDF Documents (*.pdf) + PDF Dokumente (*.pdf) + HistoryViewDetails - + Provider Information Anbieterinformationen - + Provider name Anbieter - + Purpose Zweck - + Date Datum - + MM/dd/yyyy dd.MM.yyyy - + Requested data Angeforderte Daten - + Terms of usage Nutzungsbedingungen @@ -725,7 +819,7 @@ This page displays the history of your successful authentications. Double-click on a service provider for more information. You can delete parts or the entire history. You can also save the history as a PDF file. - Auf dieser Seite sehen Sie den Verlauf Ihrer erfolgreichen Authentisierungen. Mit einem Doppelklick erhalten Sie weitere Informationen zum ausgewählten Diensteanbieter. Den Verlauf können Sie in Teilen oder auch komplett löschen. Es ist darüber hinaus auch möglich, den Verlauf zu speichern. + Auf dieser Seite sehen Sie den Verlauf Ihrer erfolgreichen Authentisierungen. Mit einem Doppelklick erhalten Sie weitere Informationen zum ausgewählten Diensteanbieter. Es ist darüber hinaus auch möglich, den Verlauf zu speichern. @@ -734,13 +828,13 @@ - Delete history… - Verlauf löschen… + Delete history... + Verlauf löschen... - Save as PDF… - Als PDF speichern… + Save as PDF... + Als PDF speichern... @@ -778,22 +872,42 @@ Verlauf als PDF speichern + + IdentifyController + + + You may now remove your ID card from the device. + Sie können nun Ihr Ausweisdokument vom Gerät entfernen. + + IdentifyView - - + + + + Identify Ausweisen - + Please wait a moment... Bitte warten Sie einen Moment... - + + No network connectivity + Keine Netzwerkverbindung + + + + Please enable the network interface or cancel the workflow. + Bitte stellen Sie eine Internetverbindung her oder beenden Sie den Vorgang. + + + Processing In Arbeit @@ -801,41 +915,43 @@ IdentifyViewContent - - + + + Service provider Diensteanbieter - - - + + + Purpose for reading out requested data Zweck des Auslesevorgangs - - - + + + Identify now Jetzt ausweisen - - Provider Information - Anbieterinformationen + + + Transactional information + Transaktionsinformationen - - - + + + Required Data Erforderliche Daten - - - + + + Optional Data Optionale Daten @@ -843,14 +959,14 @@ IdentifyViewHeader - + Hello, here you have the opportunity to view the stored data on your identity card. - Hallo, hier haben Sie die Möglichkeit die auf Ihrem Personalausweis hinterlegten Daten einzusehen. + Hallo, hier haben Sie die Möglichkeit, die auf Ihrem Personalausweis hinterlegten Daten einzusehen. - - Hello, "%1", wants to read your data - Hallo, "%1", möchte auf Ihre Daten zugreifen + + Hello, "%1" wants to read your data. + Hallo, "%1" möchte Ihre Daten auslesen. @@ -865,12 +981,12 @@ opportunity to view the stored data on your identity card. - Möglichkeit die auf Ihrem Personalausweis hinterlegten Daten einzusehen. + Möglichkeit, die auf Ihrem Personalausweis hinterlegten Daten einzusehen. - "%1",<br>wants to read your data - "%1",<br>möchte auf Ihre Daten zugreifen + "%1"<br>wants to read your data + "%1"<br>möchte Ihre Daten auslesen @@ -881,6 +997,102 @@ Ausweisen + + Information + + + Information & Help + Information & Hilfe + + + + You need help? + Benötigen Sie Hilfe? + + + + Here you are in the right place. + Dann sind Sie hier richtig. + + + + FAQ + Häufig gestellte Fragen + + + + Do you have questions how to use AusweisApp2? + Haben Sie Fragen zur Nutzung der AusweisApp2? + + + + https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/ + https://www.ausweisapp.bund.de/service/haeufig-gestellte-fragen/ + + + + Support + Unterstützung + + + + You need further help? + Benötigen Sie weitere Hilfe? + + + + https://www.ausweisapp.bund.de/en/service/support/ + https://www.ausweisapp.bund.de/service/support/ + + + + Version information + Versionsinformationen + + + + Here you can see detailed information about AusweisApp2. + Hier finden Sie detaillierte Informationen zur AusweisApp2. + + + + Software license + Softwarelizenz + + + + Read the software license text on the application homepage. + Lesen Sie die Softwarelizenz auf der Internetseite der Anwedung. + + + + https://www.ausweisapp.bund.de/en/download/ + https://www.ausweisapp.bund.de/download/ + + + + ListViewDelegateContent + + + today + heute + + + + yesterday + gestern + + + + dddd + dddd + + + + MM/dd/yyyy + dd.MM.yyyy + + LogFilesDialog @@ -895,12 +1107,12 @@ - Save… - Speichern… + Save... + Speichern... - Delete old files… + Delete old files... Alte Dateien löschen... @@ -980,56 +1192,21 @@ - Pin - Pin + PIN Management + PIN-Verwaltung - Versioninformation - Versionsinformationen + Dialog & Feedback + Dialog & Rückmeldung - FAQ - FAQ + Info & Help + Information & Hilfe - - https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/ - https://www.ausweisapp.bund.de/service/haeufig-gestellte-fragen/ - - - - Support - Support - - - - https://www.ausweisapp.bund.de/en/service/support/ - https://www.ausweisapp.bund.de/service/support/ - - - - Rate app - Bewerten - - - - Share... - Teilen... - - - - I'm using AusweisApp2, download it here for Android: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2 or here for iOS: https://itunes.apple.com/de/app/wikipedia-mobile/id324715238?mt=8 - Ich benutze die AusweisApp2, du kannst sie hier für Android herunterladen: https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2 oder hier für iOS: https://itunes.apple.com/de/app/wikipedia-mobile/id324715238?mt=8 - - - - Share with - Teilen mit - - - + Developer options Entwickleroptionen @@ -1040,74 +1217,46 @@ - NfcConnectionIndication + NfcWorkflow - + + Enable NFC + NFC aktivieren + + + + NFC is not supported by your device.<br/>Please try Bluetooth. + Ihr Gerät unterstützt kein NFC.<br/>Bitte versuchen Sie Bluetooth. + + + + NFC is switched off.<br/>Please enable NFC. + NFC ist nicht aktiv.<br/>Bitte aktivieren Sie NFC. + + + Establish connection - Verbindung herstellen + Verbindung wird hergestellt - - Your phone does not support the - Ihr Telefon unterstützt nicht + + Your device does not meet the technical requirements (Extended Length not supported). You require an additional Bluetooth card reader to use the online identification function with this device. + Ihr Gerät erfüllt leider nicht die technischen Voraussetzungen (Extended Length). Sie können die Online-Ausweisfunktion daher mit diesem Gerät nur über einen separaten Bluetooth-Leser nutzen. - - required extended length ADPUs. - die erforderliche extended length der ADPU. + + The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function. + Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an Ihre zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren. - - Please place your smartphone - Bitte platzieren Sie ihr Telefon + + Please place your device<br/>on your ID card. + Bitte platzieren Sie Ihr Gerät<br/>über Ihrem Personalausweis. - - NFC not supported - NFC wird nicht unterstützt - - - - on your id card - über Ihrem Personalausweis - - - - or switched off - oder ist abgeschaltet - - - - PinPad - - - Enter your CAN - Geben Sie Ihre CAN ein - - - - Enter your PUK - Geben Sie Ihre PUK ein - - - - Enter your new PIN - Geben Sie Ihre neue PIN ein - - - - Enter your new PIN again - Geben Sie Ihre neue PIN erneut ein - - - - Enter your PIN - Geben Sie Ihre PIN ein - - - - The PIN does not match. - Die PIN stimmt nicht überein. + + Use Bluetooth card reader<br/>instead of NFC + Bluetooth Kartenleser<br/>anstatt NFC benutzen @@ -1174,18 +1323,18 @@ Anderenfalls können Sie nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. <html> <h4>eID feature deactivated</h4> -<p>The eID function of your ID card is deactivated. Please contact your citizen centre to activate the eID function.</p> +<p>The eID function of your ID card is deactivated. Please contact your competent authority to activate the eID function.</p> </html> <html> <h4>Online-Ausweisfunktion deaktiviert</h4> -<p>Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an die für Sie zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren.</p> +<p>Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an Ihre zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren.</p> </html> Select a secure PIN that consists of six digits. Do not select a number that can be guessed easily, such as "123456", your date of birth or any other number that is printed on your ID card. -When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by Bundesdruckerei GmbH onhebalf of your citizen centre. +When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by your competent authority. Please note that the PIN may only consist of digits (0-9). Wählen Sie für Ihre 6-stellige PIN eine Zahlenkombination, die nicht leicht zu erraten ist, also weder "123456", noch Ihr Geburtsdatum oder andere Zahlen, die auf dem Ausweisdokument aufgedruckt sind. @@ -1243,15 +1392,6 @@ Bei der erstmaligen PIN-Änderung geben Sie bitte in das Feld "Aktuelle PIN deactivatedReaderImageLabel deactivatedReaderImageLabel - - - You have entered the wrong PIN three times. The online identification function is now blocked. Please use your personal unblocking key (PUK) to unblock your ID card. You received the PUK with the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre. - -Please note that you can only use the PUK to unblock the eID function. If you have forgotten your PIN, you can have a new PIN set at the citizen centre. - Sie haben Ihre PIN dreimal falsch eingegeben. Die Online-Ausweisfunktion ist jetzt blockiert. Die Blockierung können Sie mit Ihrer Entsperrnummer (PUK) aufheben. Sie finden Ihre PUK in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. - -Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis entsperren. Sollten Sie Ihre PIN vergessen haben, können Sie von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde eine neue PIN setzen lassen. - Click on "Change PIN" to enter your card access number and then set a new PIN. You can find your card access number on the front side of your ID card next to the date of expiry. On the electronic residence permit the card access number is printed above your signature. @@ -1284,25 +1424,40 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - successful pin change icon - pin änderung erfolgreich icon + successful PIN change icon + PIN änderung erfolgreich icon no id card icon Kein Ausweisdokument icon + + + You have entered the wrong PIN three times. The online identification function is now blocked. Please use your personal unblocking key (PUK) to unblock your ID card. You received the PUK with the letter sent to you by your competent authority. + +Please note that you can only use the PUK to unblock the eID function. If you have forgotten your PIN, you can have a new PIN set at your competent authority. + Sie haben Ihre PIN dreimal falsch eingegeben. Die Online-Ausweisfunktion wurde blockiert. Benutzen Sie bitte Ihre Entsperrnummer (PUK) um die Blockierung aufzuheben. Sie finden Ihre PUK in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. + +Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entsperren können. Sollten Sie Ihre PIN vergessen haben, können Sie von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde eine neue PIN setzen lassen. + PinView - - - Pin - Pin + + + + PIN Management + PIN-Verwaltung - + + Change PIN + PIN ändern + + + Processing... In Arbeit... @@ -1310,48 +1465,43 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent PinViewContent - - PIN - PIN + + + PIN Management + PIN-Verwaltung - - - Here you can change your PIN.<br>We should add some more useful information here! This is just an example to fill a text field. - Hier können Sie Ihre PIN ändern.<br>Hier sollten mal mehr Informationen stehen. Viele Grüße von der CeBIT! Danke. + + + You have the opportunity to change your transport PIN into a personal PIN. You can also change the PIN at any time or unblock the PIN using the personal unblocking key (PUK). The transport PIN and the PUK can be found in the letter sent to you by your competent authority. + Hier haben Sie die Möglichkeit, Ihre Transport-PIN in eine persönliche PIN zu ändern. Zudem können Sie jederzeit Ihre persönliche PIN ändern oder eine Blockierung mit Hilfe der Entsperrnummer (PUK) aufheben. Sie finden Ihre initiale PIN und die PUK in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. - + - Change Pin now - Jetzt Pin ändern - - - - Change Pin - PIN ändern + Change PIN now + Jetzt PIN ändern PinWorkflow - Pin - Pin + PIN Management + PIN-Verwaltung ProviderContactInfo - + + Contact Kontakt - - - ProviderContactInfoItem - + + Unknown Unbekannt @@ -1359,38 +1509,29 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent ProviderContactTab - - Homepage - Homepage - - - - Phone - Telefon - - - - E-Mail - E-Mail - - - - Contact - Kontakt + + Unknown + Unbekannt ProviderDetailButtonBar - - ONLINE-APPLICATION + + ONLINE APPLICATION Online-Anwendung + + + ONLINE-APPLICATION + ONLINE-ANWENDUNG + ProviderDetailDescription - + + Description Beschreibung @@ -1398,12 +1539,12 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent ProviderDetailHistory - + History Verlauf - + Purpose for reading out requested data Zweck des Auslesevorgangs @@ -1411,105 +1552,189 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent ProviderDetailHistoryInfo - + Purpose for reading out requested data Zweck des Auslesevorgangs - - Provider information - Anbieterinformationen + + Service provider + Diensteanbieter - + Read data Daten auslesen - + Terms of usage Nutzungsbedingungen + + ProviderDetailHistoryItem + + + today + heute + + + + yesterday + gestern + + + + dddd + dddd + + + + MM/dd/yyyy + dd.MM.yyyy + + + + Touch for more details + Berühren Sie hier für mehr Details + + ProviderDetailView - + DESCRIPTION BESCHREIBUNG - + CONTACT KONTAKT - + Description Beschreibung - + Contact Kontakt - + Description not available Beschreibung nicht verfügbar - + Description not avaible Beschreibung nicht verfügbar + + ProviderDetailsDialog + + + Provider details + Anbieterdetails + + ProviderHeader - + - Online-Application + Online Application Online-Anwendung + + ProviderInfoSection + + + + Touch for more details + Berühren Sie hier für mehr Details + + + + ProviderModelItem + + + + Homepage + Homepage + + + + + E-Mail + E-Mail + + + + + Phone + Telefon + + + + + Contact + Kontakt + + ProviderView - + Provider Anbieter - + + Citizen services Bürgerdienste - + + Insurances Versicherungen - + + Financials Finanzen - + + Other services Weitere Services - - No results found - Keine Ergebnisse gefunden + + + + + No match found + Kein Ergebnis gefunden - - All - Alle + + <html><head><body><p>This section lists offers of service providers that support online identification. Click on an entry to go to the provider&apos;s web site. This section will be continuously updated with further applications for the online identification function.</p></body></html> + <html><head><body><p>Dieser Bereich enthält eine Liste von Anbietern, die eine Online-Authentisierung anbieten. Diese Liste wird ständig aktualisiert.</p></body></html> + + + + Search: + Suche: @@ -1548,39 +1773,6 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Bitte geben Sie Ihre Suche ein - - ProxySettingsWidget - - - no proxy - kein Proxy - - - - use system settings - Systemeinstellungen verwenden - - - - <h4>Is your network connected by proxy to the Internet?</h4> -<p>In most cases no proxy is used. If you cannot answer the question or if you are insecure please ask your system administrator.</p> - <h4>Ist Ihr Netzwerk über einen Proxy-Server mit dem Internet verbunden?</h4> -<p>In den meisten Fällen wird kein Proxy-Server verwendet. Wenn Sie die Frage nicht beantworten können oder sich unsicher sind, wenden Sie sich bitte an Ihren Systemadministrator.</p> - - - - QObject - - - Error while connecting to the server. The SSL certificate uses an unsupported key algorithm or length. - Fehler bei der Verbindung zum Server. Der Verschlüsselungsalgorithmus oder die Länge des Schlüssels im SSL-Zertifikat des Servers wird nicht unterstützt. - - - - hash of certificate not in certificate description - Hashwert des Zertifikats nicht in Zertifikatsbeschreibung - - RandomPinDialog @@ -1605,7 +1797,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - pin field + PIN field PIN-Eingabefeld @@ -1643,8 +1835,8 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent ResultView - - + + Ok Ok @@ -1670,12 +1862,12 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Ausweisen - + Successfull reading data Daten erfolgreich gelesen - + Ok Ok @@ -1702,13 +1894,13 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - See my personal data now… - Meine Daten jetzt einsehen… + See my personal data now... + Meine Daten jetzt einsehen... - Use the button 'See my personal data now…' to display the data stored on your ID card. An Internet connection is required to display the data. Your personal data is neither saved nor processed in any way. - Über die Schaltfläche "Meine Daten jetzt einsehen…" können Sie sich die im Chip Ihres Ausweisdokuments gespeicherten Daten anzeigen lassen. Um die Daten anzeigen zu können, benötigt diese Anwendung eine Internetverbindung. Es erfolgt keine Speicherung oder Weiterverarbeitung Ihrer persönlichen Daten. + Use the button 'See my personal data now...' to display the data stored on your ID card. An Internet connection is required to display the data. Your personal data is neither saved nor processed in any way. + Über die Schaltfläche "Meine Daten jetzt einsehen..." können Sie sich die im Chip Ihres Ausweisdokuments gespeicherten Daten anzeigen lassen. Um die Daten anzeigen zu können, benötigt diese Anwendung eine Internetverbindung. Es erfolgt keine Speicherung oder Weiterverarbeitung Ihrer persönlichen Daten. @@ -1730,8 +1922,8 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - Diagnosis… - Diagnose… + Diagnosis... + Diagnose... @@ -1758,8 +1950,8 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - <html><head/><body><p align="justify">Information on the service provider who wants to read out data from your ID card is given here. For further information press the button &quot;more…&quot;.</p></body></html> - <html><head/><body><p align="justify">Hier erhalten Sie Informationen über den Diensteanbieter, der die Daten aus Ihrem Personalausweis auslesen möchte. Für weitere Informationen drücken Sie bitte die Schaltfläche &quot;mehr…&quot;.</p></body></html> + <html><head/><body><p align="justify">Information on the service provider who wants to read out data from your ID card is given here. For further information press the button &quot;more...&quot;.</p></body></html> + <html><head/><body><p align="justify">Hier erhalten Sie Informationen über den Diensteanbieter, der die Daten aus Ihrem Personalausweis auslesen möchte. Für weitere Informationen drücken Sie bitte die Schaltfläche &quot;mehr...&quot;.</p></body></html> @@ -1779,7 +1971,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent more... - mehr… + mehr... @@ -1807,14 +1999,6 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Details - - StepChooseDeviceWidget - - - Scan - Suchen - - SupportView @@ -1850,31 +2034,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Support is available from 9.00 to 17.00 on Monday-Friday, except on national holidays. - Unser Support ist erreichbarvon Montag bis Freitag 09:00-17:00, außer an Feiertagen. - - - - SwitchToBluetooth - - - - Bluetooth not supported - Bluetooth wird nicht unterstützt - - - - or via - oder über - - - - Bluetooth reader - Bluetoothkartenleser - - - - or switched off - oder ist abgeschaltet + Unser Support ist erreichbar von Montag bis Freitag 09:00-17:00, außer an Feiertagen. @@ -1888,21 +2048,79 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent TitleBarAction - + Cancel Abbrechen - + Edit Bearbeiten - + < back < Zurück + + UpdateWindow + + + Software Update + Software-Aktualisierung + + + + A new version of AusweisApp2 is available! + Eine aktuellere Version der AusweisApp2 ist verfügbar! + + + + AusweisApp2 %1 is now available - you have %2. Would you like to download it now? + AusweisApp2 %1 ist jetzt verfügbar - Sie haben %2. Wollen Sie die neue Version jetzt herunterladen? + + + + The update file is located at: + Die Aktualisierungsdatei finden Sie hier: + + + + <a href="%1">%1</a> + <a href="%1">%1</a> + + + + Release Notes: + Aktualisierungshinweise: + + + + Download this update and close current "AusweisApp2". Install the update and start "AusweisApp2" again. + Laden Sie die Aktualisierung herunter und beenden Sie die laufende "AusweisApp2". Installieren Sie das Update und starten "AusweisApp2" erneut. + + + + When you click "Download update", this link will be opened in your browser. + Wenn Sie "Aktualisierung herunterladen" klicken, wird dieser Link in Ihrem Browser geöffnet. + + + + Skip update + Aktualisierung auslassen + + + + Remind me later + Später erinnern + + + + Download update + Aktualisierung herunterladen + + VersionInformation @@ -1939,14 +2157,6 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Der Entwicklermodus richtet sich an Integratoren / Entwickler für neue Dienste. Aus diesem Grund funktioniert der Entwicklermodus lediglich in der Test-PKI. Durch Aktivierung des Entwicklermodus werden einige Sicherheitsprüfungen abgestellt. Die Authentisierung wird auch dann weitergeführt, wenn die AusweisApp2 im Normalbetrieb die Authentisierung mit einer Fehlermeldung abbrechen würde. Der übergangene Fehler im Entwicklermodus wird im angehängten Fenster unterhalb der AusweisApp2 angezeigt. - - governikus::AbstractState - - - The ID card has been removed. The process is aborted. - Das Ausweisdokument wurde entfernt. Der Vorgang wird abgebrochen. - - governikus::AccessRoleAndRightsUtil @@ -2116,52 +2326,52 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::AppQtGui - + AusweisApp2 was started. AusweisApp2 wurde gestartet. - + Don't show this dialog again. Diesen Hinweis nicht mehr anzeigen. - + Open Öffnen - + The developer mode is enabled. Der Entwicklermodus ist aktiviert. - + Do you want to disable the developer mode? Möchten Sie den Entwicklermodus deaktivieren? - + Did you change the initial transport PIN already?<br><br>Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. Online identification with transport PIN is not possible. Haben Sie Ihre Transport-PIN schon geändert? <br><br>Bevor Sie das erste mal die Online-Ausweisfunktion nutzen können, müssen Sie Ihre Transport-PIN durch eine persönliche, 6-stellige PIN ersetzen. Die Online-Ausweisfunktion ist mit der Transport-PIN nicht möglich. - + No, change transport PIN now Nein, PIN jetzt ändern - + Exit AusweisApp2 AusweisApp2 beenden - + The user interface of the %1 is closed. Die Benutzeroberfläche der %1 wird geschlossen. - + The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface. Das Programm steht weiterhin im Infobereich zur Verfügung. Klicken Sie auf das Symbol der %1, um die Anwendung wieder zu öffnen. @@ -2210,37 +2420,37 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::CertificateDescriptionModel - + Service provider Diensteanbieter - + Certificate issuer - Inhaber + Aussteller des Berechtigungszertifikats - + Name, address and mail address of the service provider Name, Adresse und E-Mail vom Diensteanbieter - + Purpose Zweck - + Indication of the bodies responsible for the service provider, that verify the compliance with data security regulations Angabe der für den Dienstanbieter zuständigen Datenschutzaufsicht - + Service provider information Dienstanbieterinformationen - + Validity Gültigkeit @@ -2371,7 +2581,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Diagnosis is running... - Diagnose läuft… + Diagnose läuft... @@ -2500,39 +2710,6 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Dateipfad: %1 - - governikus::ErrorMessage - - - An error occurred. Please contact our support at <a href="https://www.ausweisapp.bund.de/en/service/support/">AusweisApp2 Support</a>. - Ein Fehler ist aufgetreten. Bitte kontaktieren Sie unseren Support unter <a href="https://www.ausweisapp.bund.de/service/support/">AusweisApp2 Support</a>. - - - - Application was invoked with wrong parameters. - Die Anwendung wurde mit falschen Parametern aufgerufen. - - - - It wasn't possible to connect to the server: a secure connection could not be established. - Verbindung zum Server nicht möglich: Es konnte keine sichere Verbindung aufgebaut werden. - - - - It wasn't possible to connect to the server: the server sent a non-standard response. - Verbindung zum Server nicht möglich: Ungültige Antwort vom Server erhalten. - - - - Establishing a connection is taking too long. - Das Herstellen einer Verbindung dauert zu lang. - - - - Establishing a connection via the proxy did not succeed. - Die Verbindung zum Proxyserver konnte nicht hergestellt werden. - - governikus::GeneralSettingsWidget @@ -2541,65 +2718,338 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Allgemein + + governikus::GlobalStatus + + + No error occurred. + Es ist kein Fehler aufgetreten. + + + + An unexpected error has occurred during processing. + Während der Verarbeitung ist ein unerwarteter Fehler aufgetreten. + + + + The ID card has been removed. The process is aborted. + Das Ausweisdokument wurde entfernt. Der Vorgang wird abgebrochen. + + + + The authenticity of your ID card could not be confirmed. + Die Echtheit Ihres Ausweisdokuments konnte nicht bestätigt werden. + + + + The program received an unknown message from the server. + Die Anwendung hat eine unbekannte Nachricht vom Server erhalten. + + + + The program received an unexpected message from the server. + Die Anwendung hat eine nicht erwartete Nachricht vom Server erhalten. + + + + After three wrong entries your PIN is blocked. Using the online identification function is no longer possible. + Nach dreimaliger Falscheingabe ist Ihre PIN gesperrt. Die Nutzung der Online-Ausweisfunktion ist nun nicht mehr möglich. + + + + Pre-verification failed. + Eine oder mehrere Zertifikatsprüfungen schlugen fehl. + + + + No unique AT CVC + Kein eindeutiges AT CVC + + + + No unique DV CVC + Kein eindeutiges DV CVC + + + + Authentication failed. + Die Authentisierung ist fehlgeschlagen. + + + + No certificate description available. + Keine Zertifikatsbeschreibung vorhanden. + + + + No subject url available in certificate description. + Es konnte keine URL in der Zertifikatsbeschreibung gefunden werden. + + + + The certificate description does not match the certificate. + Die Zertifikatsbeschreibung passt nicht zum Zertifikat. + + + + The subject URL in the certificate description and the TCToken URL don't satisfy the same origin policy. + Die URL in der Zertifikatsbeschreibung und die TCToken-URL erfüllen die Same-Origin-Policy nicht. + + + + Failed to establish secure connection + Die sichere Verbindung konnte nicht aufgebaut werden + + + + The program received an error from the server. + Die Anwendung hat einen Fehler vom Server erhalten. + + + + Hash of certificate not in certificate description + Hashwert des Zertifikats nicht in Zertifikatsbeschreibung + + + + Received no data. + Keine Daten erhalten. + + + + An error occurred. Please contact our support at <a href="https://www.ausweisapp.bund.de/en/service/support/">AusweisApp2 Support</a>. + Ein Fehler ist aufgetreten. Bitte kontaktieren Sie unseren Support unter <a href="https://www.ausweisapp.bund.de/service/support/">AusweisApp2 Support</a>. + + + + Using the developer mode is only allowed in a test environment. + Der Entwicklermodus darf nur in einer Testumgebung verwendet werden. + + + + Establishing a connection is taking too long. + Der Verbindungsaufbau dauert zu lange. + + + + Establishing a connection via the proxy did not succeed. + Der Verbindungsaufbau über den Proxy war nicht erfolgreich. + + + + It wasn't possible to connect to the server: the server sent a non-standard response. + Die Verbindung zum Server ist fehlgeschlagen: Der Server hat eine nicht-standard Antwort gesendet. + + + + It wasn't possible to connect to the server: a secure connection could not be established. + Die Verbindung zum Server ist fehlgeschlagen: Es konnte keine sichere Verbindung aufgebaut werden. + + + + Application was invoked with wrong parameters. + Die Anwendung wurde mit den falschen Parametern aufgerufen. + + + + An unknown network error occurred. + Ein unbekannter Netzwerkfehler ist aufgetreten. + + + + The selected card reader cannot be accessed anymore. + Das ausgewählte Kartenlesegerät kann nicht mehr angesprochen werden. + + + + An error occurred while communicating with the card reader. + Bei der Kommunikation mit dem Kartenlesegerät ist ein Fehler aufgetreten. + + + + The server provided no or incomplete information. Your personal data could not be read out. + Der Server lieferte keine oder nur unvollständige Informationen. Ihre persönlichen Daten konnten nicht ausgelesen werden. + + + + Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length. + Fehler bei der Verbindung mit dem Diensteanbieter. Der Verschlüsselungsalgorithmus oder die Länge des Schlüssels der SSL-Verbindung wird nicht unterstützt. + + + + Error while connecting to the server. The SSL certificate uses an unsupported key algorithm or length. + Fehler bei der Verbindung zum Server. Der Verschlüsselungsalgorithmus oder die Länge des Schlüssels im SSL-Zertifikat des Servers wird nicht unterstützt. + + + + Empty redirect URL + Leere Redirect-URL + + + + Expected redirect, got %1 + Erwartete HTTP-redirect, tatsächlich erhalten: %1 + + + + Invalid scheme: %1 + Ungültiges URL-Schema: %1 + + + + Malformed redirect URL: %1 + Nicht wohlgeformte Redirect-URL: %1 + + + + The process was cancelled by the user. + Der Benutzer hat den Vorgang abgebrochen. + + + + The maximum time was exceeded during input process. + Bei der Eingabe wurde die maximale Zeit überschritten. + + + + Card does not exist + Karte nicht vorhanden + + + + An error occurred while communicating with the ID card. + Bei der Kommunikation mit dem Kartenlesegerät ist ein Fehler aufgetreten. + + + + A protocol error has occurred. + Ein Protokollfehler ist aufgetreten. + + + + The given PIN is invalid. + Die eingegebene PIN ist ungültig. + + + + The given card access number (CAN) is invalid. + Die eingegebene Zugangsnummer (CAN) ist ungültig. + + + + The given PUK is invalid. + Die eingegebene PUK ist ungültig. + + + + The PIN was blocked after too many unsuccessful attempts. + Die PIN ist nach zu vielen Fehlversuchen gesperrt. + + + + The PIN is not blocked. + Die PIN ist nicht gesperrt. + + + + The PUK was used ten times and is set inoperative. Please contact the competent authority that issued your ID document to unlock the PIN. + Die eingegebene PUK wurde zehn Mal verwendet und ist außer Betrieb. Bitte kontaktieren Sie die für die Ausgabe Ihres Ausweisdokuments zuständige Behörde um Ihre PIN zu entsperren. + + + + The new PIN and the confirmation do not match. + Die neue PIN und ihre Wiederholung stimmen nicht überein. + + + + The length of the new PIN is not valid. + Die neue PIN hat eine ungültige Länge. + + + + An error occurred while connecting to a reader device. + Es ist ein Fehler während des Verbindungsaufbaus zu einem Kartenleser aufgetreten. + + + + An error occurred while scanning for reader devices. + Es ist ein Fehler während der Suche nach einem Kartenleser aufgetreten. + + + + The remote reader connection was closed properly. + Die Verbindung zum Remote-Lesegerät wurde ordnungsgemäß geschlossen. + + + + The remote card reader connection was not closed properly. + Die Verbindung zum Remote-Lesegerät wurde abgebrochen. + + + + Undefined error code occured when the remote card reader connection was closed. + Unbekannter Fehler beim Beenden der Verbindung zum Remote-Lesegerät. + + governikus::GuiUtils - + Wrong card access number (CAN) Falsche Zugangsnummer (CAN) - + The given card access number (CAN) is not correct. You have one more try to enter the correct PIN. Please mind that you have to acknowledge this last try with your card access number (CAN). Die eingegebene Zugangsnummer (CAN) ist nicht korrekt. Sie haben noch eine weitere Möglichkeit die korrekte PIN einzugeben. Beachten Sie, dass Sie diesen letzten Versuch mit der Zugangsnummer (CAN) bestätigen müssen. - + Wrong PUK Falsche PUK - + PUK is inoperative PUK ist außer Betrieb - + Please enter your PUK again. Bitte geben Sie Ihre PUK erneut ein. - - You have correctly entered the PUK ten times and have thus reached the maximum count. The PUK is now inoperative and can no longer be used for unblocking the PIN. Please address the citizen centre that has issued your ID card for unblocking your PIN. + + You have correctly entered the PUK ten times and have thus reached the maximum count. The PUK is now inoperative and can no longer be used for unblocking the PIN. Please address your competent authority that has issued your ID card for unblocking your PIN. Sie haben die PUK zehn Mal korrekt eingegeben und damit die maximale Anzahl erreicht. Die PUK ist daher außer Betrieb und kann nicht mehr zum Entsperren der PIN verwendet werden. Bitte wenden Sie sich zum Entsperren der PIN an die zuständige Behörde, die Ihr Ausweisdokument ausgegeben hat. - + Wrong PIN Falsche PIN - + After three wrong entries your PIN is blocked. Using the online identification function is no longer possible. </p><p>You can unblock your PIN in the following dialog. The program supports you with the steps now required. Ihre PIN ist nach dreimaliger Fehleingabe gesperrt. Die Nutzung der Online-Ausweisfunktion ist in diesem Zustand nicht mehr möglich.</p><p>Sie können die PIN im folgenden Dialog entsperren. Die Anwendung unterstützt Sie in den nun notwendigen Schritten. - + The given PIN is not correct. You have one more try to enter the correct PIN. Please mind that you have to acknowledge this last try with your card access number (CAN). Die eingegebene PIN ist nicht korrekt. Sie haben noch eine weitere Möglichkeit die korrekte PIN einzugeben. Beachten Sie, dass Sie diesen letzten Versuch mit der Zugangsnummer (CAN) bestätigen müssen. - + The given PIN is not correct. You have %1 tries to enter the correct PIN. Die eingegebene PIN ist nicht korrekt. Sie haben noch %1 weitere Möglichkeiten die korrekte PIN einzugeben. - + PIN blocked PIN gesperrt - + After three wrong entries your PIN is blocked. Using the online identification function is no longer possible. <br/>You can unblock the PIN as follows:<ol><li> Select the "Settings" function.</li><li>Select the "PIN Management" tab. </li><li>Follow the instructions on the screen.</li></ol>Note: You will find the PUK in the letter you received during the application for the ID card in the "Unblocking key PUK" section. Further information is available on the site <a href="http://www.personalausweisportal.de">http://www.personalausweisportal.de</a>.<br>Do you want to unblock the PIN now? Sie haben Ihre PIN dreimal falsch eingegeben. Die Online-Ausweisfunktion ist jetzt blockiert. Die Blockierung können Sie mit Ihrer Entsperrnummer (PUK) aufheben. Sie finden Ihre PUK in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis entsperren. Sollten Sie Ihre PIN vergessen haben, können Sie von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde eine neue PIN setzen lassen.<br>Wollen Sie die Blockierung nun aufheben? @@ -2612,92 +3062,67 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Anbieterinformationen + + governikus::HistoryModelSearchFilter + + + MM/dd/yyyy + dd.MM.yyyy + + governikus::HistoryWidget - + History Verlauf - + Date Datum - + Details Details - + + + + MM/dd/yyyy hh:mm AP + dd.MM.yyyy HH:mm + + + Date: Datum: - + <b>Provider:</b> <b>Diensteanbieter:</b> - + <b>Purpose:</b> <b>Zweck:</b> - + <b>Data:</b> <b>Daten:</b> - - PDF Documents (*.pdf) - PDF-Dokumente (*.pdf) - - - - </h1><h3>AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior).</h3></td> - </h1><h3>Die AusweisApp2 ist ein Produkt der Governikus GmbH & Co. KG - im Auftrag des Bundesministeriums des Innern.</h3></td> - - - + Save history Verlauf speichern - - <td valign='middle'><h1>History - - <td valign='middle'><h1>Verlauf - - - - - <td valign='middle'><br><h3>At %1 %2 the following data were saved: - <td valign='middle'><br><h3>Am %1 um %2 wurden folgende Daten gespeichert: - - - - <h3>For further information, please see <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a></h3> - <h3>Weitere Informationen finden Sie unter <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a></h3> - - - - <tr><td><b>Date</b></td><td><b>Details</b></td></tr> - <tr><td><b>Datum</b></td><td><b>Details</b></td></tr> - - - - <td>Provider:</td> - <td>Diensteanbieter:</td> - - - - <td>Purpose:</td> - <td>Zweck:</td> - - - - <td>Data:</td> - <td>Daten:</td> + + PDF Documents (*.pdf) + PDF Dokumente (*.pdf) @@ -2766,7 +3191,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::LogHandler - + An error occurred in log handling: %1 Es ist ein Fehler bei der Protokollverwaltung aufgetreten: %1 @@ -2797,31 +3222,97 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::NumberModel - + You have entered a wrong PIN, please try again. Sie haben eine falsche PIN eingegeben. Bitte versuchen Sie es erneut. - - You have entered a wrong PIN two times. You have one try left before the PIN is blocked. You have to enter your CAN first. - Sie haben Ihre PIN zweimal falsch eingegeben und haben noch einen Versuch bevor die PIN geblockt wird. Bitte geben Sie zuerst ihre CAN ein. + + You have entered the wrong PIN twice. For a third attempt, you have to enter your six-digit card access number first. You can find your card access number on the front of your ID card. + Sie haben Ihre PIN zweimal falsch eingegeben. Für einen dritten Versuch müssen Sie vorher Ihre 6-stellige Zugangsnummer eingeben. Sie finden Ihre Zugangsnummer auf der Vorderseite Ihres Ausweises. - - You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter your PUK now for unblocking. - Sie haben Ihre PIN dreimal falsch eingegeben. Ihre PIN ist gesperrt. Sie müssen erst Ihre PUK zum entsperren eingeben. + + You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking. + Sie haben Ihre PIN dreimal falsch eingegeben. Ihre PIN ist jetzt gesperrt. Zum Entsperren geben Sie bitte Ihre PUK ein. - + You have entered a wrong CAN, please try again. - Sie haben eine falsche CAN eingegeben. Bitte versuche Sie es erneut. + Sie haben eine falsche CAN eingegeben. Bitte versuchen Sie es erneut. - + You have entered a wrong PUK. Please try again. Sie haben eine falsche PUK eingegeben. Bitte versuchen Sie es erneut. + + governikus::PdfCreator + + + History + Verlauf + + + + AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior). + Die AusweisApp2 ist ein Produkt der Governikus GmbH & Co. KG - im Auftrag des Bundesministeriums des Innern. + + + + For further information, please see <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a> + Mehr Information finden Sie auf <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a> + + + + governikus::PdfExport + + + MM/dd/yyyy + dd.MM.yyyy + + + + hh:mm AP + HH:mm + + + + At %1 %2 the following data were saved: + Die folgenden Daten wurden hier %1 %2 gespeichert: + + + + Date + Datum + + + + Details + Details + + + + MM/dd/yyyy hh:mm AP + dd.MM.yyyy HH:mm + + + + Provider: + Diensteanbieter: + + + + Purpose: + Zweck: + + + + Data: + Daten: + + governikus::PinSettingsInfoWidget @@ -2835,7 +3326,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent PIN Management - ng + PIN-Verwaltung @@ -2877,6 +3368,49 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Kein Kartenleser icon + + governikus::ProviderModel + + + %1 seconds free, afterwards + %1 Sekunde frei, danach + + + + landline costs %1; + Festnetzpreis %1; + + + + mobile costs may vary. + Mobilfunkpreise abweichen. + + + + mobile costs %1 + Mobilfunkpreise max. %1 + + + + %1/min + %1/min + + + + %1/call + %1/Anruf + + + + %1 EUR + %1 EUR + + + + %1 ct + %1 ct + + governikus::ProviderWidget @@ -2896,11 +3430,11 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - governikus::ProxySettingsWidget + governikus::QmlExtension - - Extended - Erweitert + + Send application log per email... + Anwendungsprotokoll per E-Mail senden... @@ -2984,275 +3518,123 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Nicht installiert - - governikus::ReleaseNotesDownloader - - - <h4>Download of release notes failed</h4> - <h4>Herunterladen der Release Notes schlug fehl</h4> - - governikus::Result - + An unexpected error has occurred during processing. Während der Verarbeitung ist ein unerwarteter Fehler aufgetreten. - + Use of the function by the client application is not permitted. Für die Operation fehlen die benötigten Rechte. - + An internal error has occurred during processing. Während der Verarbeitung ist ein interner Fehler aufgetreten. - + There was some problem with a provided or omitted parameter. Ein fehlerhafter Parameter wurde übermittelt. - + The API function is unknown. Die Schnittstellenfunktion ist unbekannt. - + The framework or layer has not been initialized. Die Schnittstelle ist nicht initialisiert. - - + + The active session has been terminated. Die aktuelle Sitzung wurde beendet. - - - + + + A Communication error occurred during processing. Während der Verarbeitung ist ein Verbindungsfehler aufgetreten. - - + + The operation was terminated as the set time was exceeded. Der Vorgang wurde wegen einer Zeitüberschreitung abgebrochen. - + The operation was aborted as an invalid channel handle was used. Der Vorgang wurde wegen einer ungültigen Verbindung abgebrochen. - + A trusted channel could not be opened. Es konnte keine sichere Verbindung hergestellt werden. - + The operation was aborted as an unknown protocol was used. Der Vorgang wurde wegen der Verwendung eines unbekannten Protokolls abgebrochen. - + The operation was aborted as an unknown cipher suite was used. Der Vorgang wurde wegen der Verwendung eines unbekannten Verschlüsselungsalgorithmus abgebrochen. - + The operation was aborted as an unknown web service binding was used. Der Vorgang wurde wegen der Verwendung eines unbekannten Webservice-Bindings abgebrochen. - - The operation was aborted due to cancellation by user. - Der Benutzer hat den Vorgang abgebrochen. - - - + Signature certificate key generation is not possible. Die Erzeugung eines Schlüssels für das Signaturzertifikat war nicht möglich. - + + The operation was aborted due to cancellation by user. + Der Benutzer hat den Vorgang abgebrochen. + + + One or more certificate checks failed. The operation will be aborted due to security reasons. Eine oder mehrere Zertifikatsprüfungen schlugen fehl. Der Vorgang wird aus Sicherheitsgründen abgebrochen. - - This action cannot be performed. The online identification function of your ID card is deactivated. Please contact your citizen centre to activate the online identification function. - Diese Aktion kann leider nicht durchgeführt werden. Die Online-Ausweisfunktion Ihres Ausweisdokuments ist nicht aktiviert. Bitte wenden Sie sich an die für Sie zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren. + + This action cannot be performed. The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function. + Diese Aktion kann leider nicht durchgeführt werden. Die Online-Ausweisfunktion Ihres Ausweisdokuments ist nicht aktiviert. Bitte wenden Sie sich an Ihre zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren. - + The authenticity of your ID card could not be verified. Please make sure that you are using a genuine ID card. Please note that test applications require the use of a test ID card. Die Echtheit Ihres Ausweisdokuments konnte nicht überprüft werden. Bitte stellen Sie sicher, dass Sie ein echtes Ausweisdokument verwenden. Bitte beachten Sie, dass Sie bei Testanwendungen einen Testausweis verwenden müssen. - + The age verification failed. Die Altersverifikation war nicht erfolgreich. - + The community verification failed. Die Wohnortverifikation war nicht erfolgreich. - + The ID card is invalid or disabled. Das Ausweisdokument ist ungültig oder gesperrt. - - governikus::ReturnCodeUtil - - - No error occurred. - Es ist kein Fehler aufgetreten. - - - - no error - kein Fehler - - - - - Card does not exist - Karte nicht vorhanden - - - - The maximum time was exceeded during input process. - Bei der Eingabe wurde die maximale Zeit überschritten. - - - - A timeout occurred during input process - Zeitüberschreitung bei der Eingabe - - - - The input is invalid. - Die Eingabe ist ungültig. - - - - invalid input - ungültige Eingabe - - - - - - - An error occurred while communicating with the card reader. - Bei der Kommunikation mit dem Kartenlesegerät ist ein Fehler aufgetreten. - - - - - The process was cancelled by the user. - Der Benutzer hat den Vorgang abgebrochen. - - - - - The new PIN and the confirmation do not match. - Die neue PIN und ihre Wiederholung stimmen nicht überein. - - - - The PIN was blocked after too many unsuccessful attempts. - Die PIN ist nach zu vielen Fehlversuchen gesperrt. - - - - PIN is blocked - PIN gesperrt - - - - - The length of the new PIN is not valid. - Die neue PIN hat eine ungültige Länge. - - - - - A protocol error has occurred. - Ein Protokollfehler ist aufgetreten. - - - - - The PIN is not blocked. - Die PIN ist nicht gesperrt. - - - - - Unexpected transmit status - Status des Transmits ist unerwartet - - - - The given card access number (CAN) is invalid. - Die eingegebene Zugangsnummer (CAN) ist ungültig. - - - - given card access number (CAN) is invalid - eingegebene Zugangsnummer (CAN) ungültig - - - - The given PIN is invalid. - Die eingegebene PIN ist ungültig. - - - - given PIN is invalid - eingegebene PIN ungültig - - - - The given PUK is invalid. - Die eingegebene PUK ist ungültig. - - - - The PUK was used ten times and is set inoperative. - Die eingegebene PUK wurde zehn Mal verwendet und ist außer Betrieb. - - - - PUK is inoperative - PUK ist außer Betrieb - - - - given PUK is invalid - eingegebene PUK ungültig - - - - Unknown error - Unbekannter Fehler - - - - - An unknown error occurred: - Es ist ein unbekannter Fehler aufgetreten: - - governikus::SelfAuthenticationData @@ -3285,7 +3667,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - dd.MM.yyyy + MM/dd/yyyy dd.MM.yyyy @@ -3332,112 +3714,117 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::SelfInfoWidget - + dd.MM.yyyy dd.MM.yyyy - + Document type: Dokumentenart: - + Issuing country: Ausstellender Staat: - + Doctoral degree: Doktorgrad: - + Given name(s): Vorname(n): - + Family name: Familienname: - + Religious / artistic name: Ordens- / Künstlername: - - - + + + Address: Anschrift: - + Birth name: Geburtsname: - + Date of birth: Geburtsdatum: - + Place of birth: Geburtsort: - + Nationality: Staatsangehörigkeit: - + Residence permit I: Nebenbestimmungen I: - + Save as PDF... - Als PDF speichern… + Als PDF speichern... - - </h1><h3>AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior).</h3></td> - </h1><h3>Die AusweisApp2 ist ein Produkt der Governikus GmbH & Co. KG - im Auftrag des Bundesministeriums des Innern.</h3></td> + + MM/dd/yyyy + dd.MM.yyyy - + + hh:mm AP + HH:mm + + + + At %1 %2 the following data has been read out of your ID card: + Die folgenden Daten wurden hier %1 %2 aus Ihrem Ausweisdokument ausgelesen: + + + + Entry + Eintrag + + + + Content + Inhalt + + + save id card data as pdf Daten des Ausweisdokuments als PDF speichern - + Save Speichern - + PDF Documents PDF-Dokumente - - - <td valign='middle'><h1>ID card info - - <td valign='middle'><h1>Ausweis Auskunft - - - - - <td valign='middle'><br><h3>At %1 %2 the following data has been read out of your ID card: - <td valign='middle'><br><h3>Am %1 um %2 wurden folgende Daten aus Ihrem Ausweisdokument ausgelesen: - - - - <h3>For further information, please see <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a></h3> - <h3>Weitere Informationen finden Sie unter <a href='https://www.ausweisapp.bund.de/'>https://www.ausweisapp.bund.de/</a></h3> - governikus::SelfInformationWidget @@ -3478,326 +3865,147 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent - Einrichtungsassistent - + <div align="right">Step %1 of %2</div><div align="left">Introduction</div> <div align="right">Schritt %1 von %2</div><div align="left">Einleitung</div> - + Welcome to the AusweisApp2 setup assistant. This assistant will guide you through the setup process in %1 steps. The setup assistant can be cancelled at any time and can be started again later from the Help menu. Willkommen zum Einrichtungsassistenten der AusweisApp2. Sie werden in %1 Schritten durch die Einrichtung geführt. Sie können diesen Einrichtungsassistenten jederzeit abbrechen und später über das Hilfe-Menü erneut starten. - + Introduction Step %1 of %2. Welcome to the AusweisApp2 setup assistant. This assistant will guide you through the setup process in %2 steps. The setup assistant can be cancelled at any time and can be started again later from the Help menu. Einleitung Schritt %1 von %2. Willkommen zum Einrichtungsassistenten der AusweisApp2. Sie werden in %2 Schritten durch die Einrichtung geführt. Sie können diesen Einrichtungsassistenten jederzeit abbrechen und später über das Hilfe-Menü erneut starten. - + <br><b>History</b><br><br>AusweisApp2 offers saving the course of your authentications in a history. Subsequently you can activate this option. <br><b>Verlauf</b><br><br>Die AusweisApp2 bietet Ihnen die Möglichkeit, durchgeführte Authentisierungen in einem Verlauf zu speichern. Nachfolgend haben Sie die Möglichkeit, diese Option zu aktivieren. - + History. AusweisApp2 offers saving the course of your authentications in a history. Subsequently you can activate this option. Verlauf. Die AusweisApp2 bietet Ihnen die Möglichkeit, durchgeführte Authentisierungen in einem Verlauf zu speichern. Nachfolgend haben Sie die Möglichkeit, diese Option zu aktivieren. - + <div align="right">Step %1 of %2</div><div align="left">Card Reader</div> <div align="right">Schritt %1 von %2</div><div align="left">Kartenleser</div> - + Card Reader Step %1 of %2. In order to be able to use the online identification function with AusweisApp2, you need a card reader. Please make sure that you have connected a suitable card reader and that the drivers required for your card reader are installed on your system. The following list shows all suitable card readers. For each card reader you will find a link to the manufacturer's website, where you can download the most recent drivers. Kartenleser Schritt %1 von %2. Um die Online-Ausweisfunktion mit der AusweisApp2 nutzen zu können benötigen Sie ein Kartenlesegerät. Stellen Sie sicher, dass Sie ein geeignetes Kartenlesegerät angeschlossen haben und dass die für Ihr Kartenlesegerät benötigten Treiber auf Ihrem System installiert sind. Die folgende Übersicht zeigt alle geeigneten Kartenlesegeräte. Zu jedem Kartenlesegerät ist ein Link zur Herstellerseite angegeben, dort können die aktuellen Treiber heruntergeladen werden. - + <div align="right">Step %1 of %2</div><div align="left">Firefox extension NoScript</div> <div align="right">Schritt %1 of %2</div><div align="left">Firefox-Erweiterung NoScript</div> - - The Firefox browser extension NoScript was found on your computer. The configuration of this extension may block authentication requests from being passed to %1. Refer to the online help for further details. - Die Firefox-Erweiterung NoScript wurde auf Ihrem System gefunden. Die Konfiguration dieser Erweiterung kann Authentisierungs-Aufrufe für die %1 blockieren. Weitere Informationen erhalten Sie in der Online-Hilfe. - - - + Firefox extension NoScript Step %1 of %2. Firefox-Erweiterung NoScript Schritt %1 von %2. - - <b>Personal 6-digit PIN</b><br><br>Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre. + + <b>Personal 6-digit PIN</b><br><br>Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by your competent authority. <b>Persönliche 6-stellige PIN</b><br><br>Vor der ersten Nutzung der Online-Ausweisfunktion müssen Sie die Transport-PIN durch eine persönliche 6-stellige PIN ersetzen. Die PIN-Verwaltung der AusweisApp2 bietet Ihnen dazu die Möglichkeit. Für das Ersetzen der Transport-PIN benötigen Sie den PIN-Brief, welcher Ihnen von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde zugesandt wurde. - - Personal 6-digit PIN. Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre. + + Personal 6-digit PIN. Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by your competent authority. Personal 6-digit PIN. Vor der ersten Nutzung der Online-Ausweisfunktion müssen Sie die Transport-PIN durch eine persönliche 6-stellige PIN ersetzen. Die PIN-Verwaltung der AusweisApp2 bietet Ihnen dazu die Möglichkeit. Für das Ersetzen der Transport-PIN benötigen Sie den PIN-Brief, welcher Ihnen von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde zugesandt wurde. - + Change PIN PIN ändern - + <br>AusweisApp2 is now ready for use. You can further configure AusweisApp2 via the "Settings" dialog from the navigation section. AusweisApp2 uses the proxy settings configured in your system. This setup assistant can be started at any time from the "Help" menu. The "Finish" button closes the setup assistant. <br>Sie können die AusweisApp2 nun verwenden. Weitere Einstellungen können Sie über die Funktion "Einstellungen" im Navigationsbereich vornehmen. Die AusweisApp2 verwendet die in Ihrem System konfigurierten Proxy-Einstellungen. Sie können diesen Einrichtungsassistenten jederzeit über das Menü "Hilfe" erneut starten. Die Schaltfläche "Abschließen" schließt den Einrichtungsassistenten und öffnet die Dialogseite "Einstellungen". - + Almost done! Step %1 of %2. AusweisApp2 is now ready for use. You can further configure AusweisApp2 via the Settings dialog from the navigation section. AusweisApp2 uses the proxy settings configured in your system. This setup assistant can be started at any time from the Help menu. The Finish button closes the setup assistant. Fast fertig! Schritt %1 von %2. Sie können die AusweisApp2 nun verwenden. Weitere Einstellungen können Sie über die Funktion Einstellungen im Navigationsbereich vornehmen. Die AusweisApp2 verwendet die in Ihrem System konfigurierten Proxy-Einstellungen. Sie können diesen Einrichtungsassistenten jederzeit über das Menü Hilfe erneut starten. Die Schaltfläche Abschließen; schließt den Einrichtungsassistenten und öffnet die Dialogseite der Funktion Einstellungen. - + In order to be able to use the online identification function with AusweisApp2, you need a card reader. Please make sure that you have connected a suitable card reader and that the drivers required for your card reader are installed on your system. The following list shows all suitable card readers. For each card reader you will find a link to the manufacturer's website, where you can download the most recent drivers. Um die Online-Ausweisfunktion mit der AusweisApp2 nutzen zu können benötigen Sie ein Kartenlesegerät. Stellen Sie sicher, dass Sie ein geeignetes Kartenlesegerät angeschlossen haben und dass die für Ihr Kartenlesegerät benötigten Treiber auf Ihrem System installiert sind. Die folgende Übersicht zeigt alle geeigneten Kartenlesegeräte. Zu jedem Kartenlesegerät ist ein Link zur Herstellerseite angegeben, dort können die aktuellen Treiber heruntergeladen werden. - + Reader Kartenleser - - + + Name / Manufacturer Name / Hersteller - + Web page Webseite - + reader icon Kartenleser Icon - - <div align="right">Step %1 of %2</div><div align="left">Almost done!</div> - <div align="right">Schritt %1 von %2</div><div align="left">Fast fertig!</div> + + The Firefox browser extension NoScript was found on your computer. The configuration of this extension may block authentication requests from being passed to %1. Refer to the online help for further details. + Die Firefox-Erweiterung NoScript wurde auf Ihrem System gefunden. Die Konfiguration dieser Erweiterung kann Authentisierungs-Aufrufe für die %1 blockieren. Weitere Informationen erhalten Sie in der Online-Hilfe. - + + <div align="right">Step %1 of %2</div><div align="left">Almost done!</div> + <div align="right">Step %1 of %2</div><div align="left">Fast fertig!</div> + + + History: Verlauf: - + save speichern - + save history Verlauf speichern - - governikus::StateCertificateDescriptionCheck - - - No certificate description available. - Keine Zertifikatsbeschreibung vorhanden. - - - - No subject url available in certificate description. - Es konnte keine URL in der Zertifikatsbeschreibung gefunden werden. - - - - The certificate description does not match the certificate. - Die Zertifikatsbeschreibung passt nicht zum Zertifikat. - - - - The subject URL in the certificate description and the TCToken URL don't satisfy the same origin policy. - Die URL in der Zertifikatsbeschreibung und die TCToken-URL erfüllen die Same-Origin-Policy nicht. - - governikus::StateChangePin - - Pin successfully changed - Pin erfolgreich geändert - - - - governikus::StateCheckCertificates - - - Hash of certificate not in certificate description - Hashwert des Zertifikats nicht in Zertifikatsbeschreibung - - - - governikus::StateCheckRefreshAddress - - - - - Failed to establish secure connection - Die sichere Verbindung konnte nicht aufgebaut werden - - - - Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length. - Fehler bei der Verbindung mit dem Diensteanbieter. Der Verschlüsselungsalgorithmus oder die Länge des Schlüssels der SSL-Verbindung wird nicht unterstützt. - - - - Expected redirect, got %1 - Erwartete HTTP-redirect, tatsächlich erhalten: %1 - - - - Empty redirect URL - Leere Redirect-URL - - - - Malformed redirect URL: %1 - Nicht wohlgeformte Redirect-URL: %1 - - - - Invalid scheme: %1 - Ungültiges URL-Schema: %1 - - - - governikus::StateConnectCard - - - An error occurred while communicating with the card reader. - Bei der Kommunikation mit dem Kartenlesegerät ist ein Fehler aufgetreten. - - - - governikus::StateDidAuthenticateEac2 - - - - Authentication failed. - Die Authentisierung ist fehlgeschlagen. + + You have successfully changed your PIN. + Sie haben Ihre PIN erfolgreich geändert. governikus::StateEstablishPacePuk - - Pin successfully unblocked - Pin erfolgreich entsperrt - - - - governikus::StateExtractCvcsFromEac1IntputType - - - - No unique AT CVC - Kein eindeutiges AT CVC - - - - - No unique DV CVC - Kein eindeutiges DV CVC - - - - governikus::StateGenericSendReceive - - - Failed to establish secure connection - Die sichere Verbindung konnte nicht aufgebaut werden - - - - The program received an error from the server. - Die Anwendung hat einen Fehler vom Server erhalten. - - - - The program received an unknown message from the server. - Die Anwendung hat eine unbekannte Nachricht vom Server erhalten. - - - - The program received an unexpected message from the server. - Die Anwendung hat eine nicht erwartete Nachricht vom Server erhalten. - - - - governikus::StateGetSelfAuthenticationData - - - Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length. - Fehler bei der Verbindung mit dem Diensteanbieter. Der Verschlüsselungsalgorithmus oder die Länge des Schlüssels der SSL-Verbindung wird nicht unterstützt. - - - - Failed to establish secure connection - Die sichere Verbindung konnte nicht aufgebaut werden - - - - - The server provided no or incomplete information. Your personal data could not be read out. - Der Server lieferte keine oder nur unvollständige Informationen. Ihre persönlichen Daten konnten nicht ausgelesen werden. - - - - governikus::StateGetTcToken - - - Received no data. - Keine Daten erhalten. - - - - governikus::StatePreVerification - - - Using the developer mode is only allowed in a test environment. - Der Entwicklermodus darf nur in einer Testumgebung verwendet werden. - - - - - - Pre-verification failed. - Eine oder mehrere Zertifikatsprüfungen schlugen fehl. - - - - governikus::StateProcessCertificatesFromEac2 - - - The authenticity of your ID card could not be confirmed. - Die Echtheit Ihres Ausweisdokuments konnte nicht bestätigt werden. - - - - governikus::StateSelectBluetoothReader - - - The selected card reader cannot be accessed anymore. - Das ausgewählte Kartenlesegerät kann nicht mehr angesprochen werden. + + PIN successfully unblocked + PIN erfolgreich entsperrt governikus::StateWriteHistory - + Validity: %1 - %2 Gültigkeit: @@ -3807,7 +4015,7 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::StepAdviseUserToRemoveCardGui - + You may now remove your ID card from the card reader. Sie können nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. @@ -3828,119 +4036,121 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::StepAuthenticationEac1Widget - + Validity: %1 - %2 Gültigkeit: %1 - %2 - - - + + Only digits (0-9) are permitted. Es sind nur Ziffern (0-9) erlaubt. - + Card is being verified Karte wird geprüft - + Service provider is verified Diensteanbieter wird geprüft - + Reading data Daten werden gelesen - + Service provider is being verified Diensteanbieter wird geprüft - - - - - - - - + + + + + + Identify now Jetzt ausweisen - + + See details under more... + Weitere Details unter "mehr..." + + + OK OK - + Identify Ausweisen - + Identification successful Ausweisen erfolgreich - + The process was cancelled by the user Der Benutzer hat den Vorgang abgebrochen - + Result Ergebnis - + Please pay attention to the display of your card reader. Bitte beachten Sie die Anzeige auf Ihrem Kartenlesegerät. - + Please enter your six-digit card access number (CAN) and your PIN for identification. Bitte geben Sie Ihre 6-stellige Zugangsnummer (CAN) und Ihre PIN ein, um sich auszuweisen. - + Please enter your six digit PIN for identification Bitte geben Sie Ihre 6-stellige PIN ein, um sich auszuweisen - + Service provider: Diensteanbieter: - + Certificate issuer: Aussteller des Berechtigungszertifikats: - + Card access number (CAN): Zugangsnummer (CAN): - - + + open on screen password dialog Öffnen Sie den Bildschirmtastatur-Passwortdialog - + More information with TAB Weitere Informationen mit dem Tabulator - + PIN: PIN: @@ -3958,69 +4168,55 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Diagnose - + No card reader detected. Please make sure that a card reader is connected. Es wurde kein Kartenlesegerät erkannt. Bitte stellen Sie sicher, dass ein Kartenlesegerät angeschlossen ist. - + If you need help or have problems with your card reader click on the "Diagnosis" button for further information. Wenn Sie Hilfe benötigen oder Probleme mit Ihrem Kartenlesegerät haben, klicken Sie auf die Schaltfläche "Diagnose" für weitere Informationen. - + Please place an ID card on the card reader. Bitte legen Sie ein Ausweisdokument auf. - + If you have already placed an ID card on your card reader, click on "Diagnosis" for further information. Sollten Sie bereits Ihr Ausweisdokument aufgelegt haben, klicken Sie auf die Schaltfläche "Diagnose" für weitere Informationen. - + Please place only one ID card on the card reader. Bitte legen Sie nur ein Ausweisdokument auf. - + Please make sure that only one card reader with an ID card on it is connected to your computer. If you have already placed an ID card on your card reader, click on "Diagnosis" for further information. Bitte stellen Sie sicher, dass an Ihrem Computer nur ein Kartenlesegerät mit aufliegendem Ausweisdokument angeschlossen ist. Sollten Sie bereits ein Ausweisdokument aufgelegt haben, klicken Sie auf die Schaltfläche "Diagnose" für weitere Informationen. - - - governikus::StepChooseDeviceWidget - - Please connect your tablet/smartphone with the Reiner SCT cyberJack wave now. You can find a detailled description in the online help. - Bitte verbinden Sie nun Ihr Tablet / Smartphone mit dem Reiner SCT cyberJack wave. Eine detaillierte Beschreibung hierzu finden Sie in der Online-Hilfe. + + Online identification function is disabled. + Die Online-Ausweisfunktion ist deaktiviert. - - - Not connected - Nicht verbunden - - - - No ID card found - Kein Ausweisdokument gefunden - - - - ID card found - Ausweisdokument gefunden + + This action cannot be performed. The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function. + Diese Aktion kann leider nicht durchgeführt werden. Die Online-Ausweisfunktion Ihres Ausweisdokuments ist nicht aktiviert. Bitte wenden Sie sich an Ihre zuständige Behörde, um die Online-Ausweisfunktion zu aktivieren. governikus::StepErrorGui - + Sorry, that should not have happened! Please contact the support team. Entschuldigung, das hätte nicht passieren dürfen! Bitte kontaktieren Sie das Support Team. - + Error Fehler @@ -4033,6 +4229,29 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Schließen + + governikus::UpdateWindow + + + Your software is up to date. + Ihre Software ist auf aktuellem Stand. + + + + Unable to open this link in a browser. Please copy and paste the link into the address bar of your browser. + Der Link konnte im Browser nicht geöffnet werden. Bitte kopieren Sie den Link aus dieser Meldung und fügen Sie ihn manuell in die Adressleiste Ihres Browsers ein. + + + + Updates + Aktualisierungen + + + + <h4>Download of release notes failed</h4> + <h4>Herunterladen der Versionshinweise schlug fehl</h4> + + governikus::VersionInformationModel @@ -4061,37 +4280,42 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent Build-Datum - + + VersionCode + Versions-Code + + + System version Systemversion - + Kernel Kernel - + Architecture Architektur - + Compiled architecture Kompilierte Architektur - + Device Gerät - + Qt Version Qt-Version - + OpenSSL Version OpenSSL-Version @@ -4099,75 +4323,75 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::WebserviceActivationContext - - - + + + The browser connection was lost. Die Verbindung zum Browser ging verloren. - - + + Cannot start authentication Authentisierungsvorgang kann nicht gestartet werden - + An operation is already in progress. Ein Vorgang ist bereits in Arbeit. - + Would you like to try again? Möchten Sie es erneut versuchen? - + Try again Erneut versuchen - + 400 Bad Request 400 Ungültige Anfrage - + 404 Not found 404 Nicht gefunden - + Invalid request Ungültige Anfrage - + Your browser sent a request that couldn't be interpreted. Ihr Browser hat eine Anfrage gesendet, die nicht interpretiert werden konnte. - + Error message Fehlermeldung - + Would you like to report this error? Möchten Sie diesen Fehler melden? - + https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/ https://www.ausweisapp.bund.de/feedback/melden-sie-einen-fehler/ - + Report now Jetzt melden - + The connection to the bowser was lost. No forwarding was executed. Please try to call the URL again manually: <a href='%1'>%2</a> Die Verbindung zum Browser ging verloren. Es konnte keine Weiterleitung durchgeführt werden. Bitte versuchen Sie die URL manuell aufzurufen: <a href='%1'>%2</a> @@ -4175,63 +4399,63 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::WebserviceActivationHandler - + An unknown program uses the required port (%1). Please exit the other program and try again! Eine unbekannte Anwendung verwendet den benötigten Port (%1) bereits. Bitte beenden Sie zuerst die andere Anwendung und versuchen Sie es anschließend erneut! - + Another program (%1) uses the required port (%2). Please exit this other program and try again! Eine andere Anwendung (%1) verwendet den benötigten Port (%2) bereits. Bitte beenden Sie zuerst die andere Anwendung und versuchen Sie es anschließend erneut! - + 404 Not found 404 Nicht gefunden - + Invalid request Ungültige Anfrage - + Your browser sent a request that couldn't be interpreted. Fehlermeldung Ihr Browser hat eine Anfrage gesendet, die nicht interpretiert werden konnte. - + Error message Fehlermeldung - + Unknown request: %1 Unbekannte Anfrage: %1 - + Would you like to report this error? Möchten Sie diesen Fehler melden? - + https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/ https://www.ausweisapp.bund.de/feedback/melden-sie-einen-fehler/ - + Report now Jetzt melden - + You tried to start a newer version (%1) of currently running application. Please stop the current version (%2) and start again! Sie versuchen eine neuere Version (%1) der aktuell laufenden Anwendung zu starten. Bitte beenden Sie zuerst die andere Version (%2) und versuchen Sie es anschließend erneut! - + You tried to start an older version (%1) of currently running application. Please open the currently running version (%2)! Sie versuchen eine ältere Version (%1) der aktuell laufenden Anwendung zu starten. Bitte öffnen Sie die aktuell laufende Version (%2)! @@ -4239,22 +4463,22 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::WorkflowAuthenticateQtGui - + Identify Ausweisen - + Cancel Abbrechen - + <b>Do you really want to cancel?</b> <b>Wollen Sie wirklich abbrechen?</b> - + You can as well identity later by calling the service provider's Internet page again. Sie können sich auch später ausweisen, indem Sie erneut auf die Internetseite des Diensteanbieters gehen. @@ -4275,9 +4499,17 @@ Bitte beachten Sie: Sie können mit Ihrer PUK lediglich Ihren Online-Ausweis ent governikus::WorkflowSelfInfoQtGui - + Identify Ausweisen + + main + + + Press the back button twice to close the app. + Drücken Sie zweimal die Zurück-Taste, um die Anwendung zu schließen. + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ea35eaa..0a27950 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,19 +1,19 @@ +ADD_SUBDIRECTORY(external) ADD_SUBDIRECTORY(global) ADD_SUBDIRECTORY(card) ADD_SUBDIRECTORY(network) -ADD_SUBDIRECTORY(external) ADD_SUBDIRECTORY(settings) ADD_SUBDIRECTORY(services) ADD_SUBDIRECTORY(activation) ADD_SUBDIRECTORY(core) ADD_SUBDIRECTORY(jsonapi) ADD_SUBDIRECTORY(websocket) -ADD_SUBDIRECTORY(cli) ADD_SUBDIRECTORY(aidl) - -IF(TARGET Qt5::Qml) - ADD_SUBDIRECTORY(qml) +IF(DESKTOP) + ADD_SUBDIRECTORY(cli) + ADD_SUBDIRECTORY(export) ENDIF() +ADD_SUBDIRECTORY(qml) # Use this if we can use QSvgPlugin without Widgets # IF(TARGET Qt5::Widgets) @@ -24,8 +24,17 @@ ENDIF() FILE(GLOB TRANSLATION_FILES ${RESOURCES_DIR}/translations/*.ts) + +FOREACH(filepath ${TRANSLATION_FILES}) + GET_FILENAME_COMPONENT(filename "${filepath}" NAME) + STRING(REGEX MATCH "_(.*)\.ts$" _unused "${filename}") + LIST(APPEND USED_TRANSLATIONS ${CMAKE_MATCH_1}) +ENDFOREACH() + SET_PROPERTY(SOURCE ${TRANSLATION_FILES} PROPERTY OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translations) -FILE(COPY ${QT_TRANSLATIONS_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILES_MATCHING REGEX "qt_|qtbase_") +FOREACH(locale ${USED_TRANSLATIONS}) + FILE(COPY ${QT_TRANSLATIONS_DIR} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILES_MATCHING REGEX "qtbase_${locale}") +ENDFOREACH() OPTION(UPDATE_TRANSLATIONS "Update translations/*.ts files (WARNING: make clean will delete the *.ts files!)") IF(UPDATE_TRANSLATIONS) @@ -33,9 +42,9 @@ IF(UPDATE_TRANSLATIONS) SET(LUPDATE_OPTIONS -extensions c,cpp,h,ui,m,mm,qml,js -no-ui-lines) IF(UPDATE_TRANSLATIONS_NO_OBSOLETE) - QT5_CREATE_TRANSLATION(QM_FILES ${SRC_DIR} ${RESOURCES_DIR}/qml ${TRANSLATION_FILES} OPTIONS ${LUPDATE_OPTIONS} -no-obsolete) + QT5_CREATE_TRANSLATION(QM_FILES ${SRC_DIR} ${RESOURCES_DIR} ${TRANSLATION_FILES} OPTIONS ${LUPDATE_OPTIONS} -no-obsolete) ELSE() - QT5_CREATE_TRANSLATION(QM_FILES ${SRC_DIR} ${RESOURCES_DIR}/qml ${TRANSLATION_FILES} OPTIONS ${LUPDATE_OPTIONS}) + QT5_CREATE_TRANSLATION(QM_FILES ${SRC_DIR} ${RESOURCES_DIR} ${TRANSLATION_FILES} OPTIONS ${LUPDATE_OPTIONS}) ENDIF() ADD_CUSTOM_TARGET(update.translations DEPENDS ${QM_FILES}) @@ -112,7 +121,7 @@ ELSE() ADD_STRING_DEFINITION(${PROJECT_VERSION} "VERSION" ${MAIN_CPP} ${WINDOWS_RC}) ENDIF() -TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCard AusweisAppCli AusweisAppCore AusweisAppGlobal AusweisAppExternalHttpParser AusweisAppNetwork AusweisAppActivation AusweisAppActivationInternal) +TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCard AusweisAppCore AusweisAppGlobal AusweisAppExternalHttpParser AusweisAppNetwork AusweisAppActivation AusweisAppActivationInternal) SET_TARGET_PROPERTIES(AusweisApp PROPERTIES OUTPUT_NAME "${EXECUTABLE_BASE_NAME}") SET_TARGET_PROPERTIES(AusweisApp PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME AusweisApp2) SET_TARGET_PROPERTIES(AusweisApp PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER com.governikus.ausweisapp2) @@ -130,8 +139,10 @@ IF(IOS) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Window.2) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQml/Models.2) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQml/StateMachine) - TARGET_LINK_LIBRARIES(AusweisApp -lQt5PlatformSupport -lQt5Network -lQt5Gui -lQt5Core -lQt5Bluetooth -lQt5Svg -lQt5Quick -lQt5Qml) + TARGET_LINK_LIBRARIES(AusweisApp -lQt5Network -lQt5Gui -lQt5Core -lQt5Bluetooth -lQt5Svg -lQt5Quick -lQt5Qml) + TARGET_LINK_LIBRARIES(AusweisApp -lqtlibpng -lQt5GraphicsSupport -lQt5FontDatabaseSupport -lQt5ClipboardSupport) TARGET_LINK_LIBRARIES(AusweisApp -lqios -lqsvg -lqtpcre -lqtfreetype -lqtquick2plugin -ldialogplugin -lqquicklayoutsplugin -lmodelsplugin -lwindowplugin -lqtqmlstatemachine) + TARGET_LINK_LIBRARIES(AusweisApp "-lc++ -lz -lm -u _qt_registerPlatformPlugin") TARGET_LINK_LIBRARIES(AusweisApp ${IOS_ASSETSLIBRARY} ${IOS_UIKIT} ${IOS_COREBLUETOOTH} ${IOS_COREFOUNDATION} ${IOS_OPENGLES} ${IOS_FOUNDATION} ${IOS_QUARTZCORE} ${IOS_CORETEXT} ${IOS_COREGRAPHICS} ${IOS_SECURITY} ${IOS_SYSTEMCONFIGURATION} ${IOS_MOBILECORESERVICES} ${IOS_AUDIOTOOLBOX}) @@ -179,29 +190,21 @@ IF(LINUX OR ANDROID OR IOS) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardBluetooth) ENDIF() -IF(NOT ANDROID AND NOT IOS) - TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardPcsc AusweisAppCardDrivers AusweisAppExternalFervor AusweisAppActivationWebservice) -ENDIF() - IF(WIN32) TARGET_LINK_LIBRARIES(AusweisApp ${WIN_DEFAULT_LIBS}) ENDIF() -IF(IOS OR ANDROID OR ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") +IF(IOS OR ANDROID OR WINDOWS_STORE OR ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") TARGET_LINK_LIBRARIES(AusweisApp AusweisAppQml) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppJsonApi AusweisAppAidl) ENDIF() IF(DESKTOP) - TARGET_LINK_LIBRARIES(AusweisApp AusweisAppWidget) + TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardPcsc AusweisAppCardDrivers AusweisAppActivationWebservice) + TARGET_LINK_LIBRARIES(AusweisApp AusweisAppWidget AusweisAppCli) ENDIF() IF(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") TARGET_LINK_LIBRARIES(AusweisApp AusweisAppJsonApi AusweisAppWebSocket) - IF(ANDROID) - INCLUDE(AndroidNdkGdb) - android_ndk_gdb_enable() - android_ndk_gdb_debuggable(AusweisApp) - ENDIF() ENDIF() diff --git a/src/CommandLineParser.cpp b/src/CommandLineParser.cpp index 8b6a155..cc97dae 100644 --- a/src/CommandLineParser.cpp +++ b/src/CommandLineParser.cpp @@ -11,8 +11,12 @@ #include "view/UILoader.h" #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -#include "GuiProfile.h" -#include "WebserviceActivationHandler.h" +#include "HttpServer.h" + +#ifndef Q_OS_WINRT + #include "GuiProfile.h" +#endif + #endif #ifndef QT_NO_DEBUG @@ -38,7 +42,7 @@ QString defaultUi(const QVector& pPlugins) QStringList list; for (auto entry : pPlugins) { - list << getEnumName(entry).remove(prefixUi); + list << QString(getEnumName(entry)).remove(prefixUi); } return list.join(','); } @@ -80,7 +84,7 @@ void CommandLineParser::addOptions() mParser.addOption(mOptionKeepLog); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) mParser.addOption(mOptionShowWindow); #endif @@ -111,7 +115,7 @@ void CommandLineParser::parse(QCoreApplication* pApp) LogHandler::getInstance().setAutoRemove(false); } -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) if (mParser.isSet(mOptionShowWindow)) { GuiProfile::getProfile().setShowWindow(true); @@ -142,9 +146,9 @@ void CommandLineParser::parse(QCoreApplication* pApp) { bool converted = false; const uint port = mParser.value(mOptionPort).toUInt(&converted); - if (converted && port < 65536) + if (converted && port < USHRT_MAX) { - WebserviceActivationHandler::PORT = port; + HttpServer::cPort = static_cast(port); } else { @@ -158,9 +162,9 @@ void CommandLineParser::parse(QCoreApplication* pApp) { bool converted = false; const uint port = mParser.value(mOptionPortWebSocket).toUInt(&converted); - if (converted && port < 65536) + if (converted && port < USHRT_MAX) { - UIPlugInWebSocket::setPort(port); + UIPlugInWebSocket::setPort(static_cast(port)); } else { @@ -176,12 +180,14 @@ void CommandLineParser::parseUiPlugin() if (mParser.isSet(mOptionUi)) { QVector selectedPlugins; - const auto& availablePlugins = EnumUIPlugInName::getList(); - for (const auto& parsedUiOption : mParser.values(mOptionUi)) + const auto& availablePlugins = Enum::getList(); + const auto& requestedUis = mParser.values(mOptionUi); + + for (const auto& parsedUiOption : requestedUis) { for (auto availablePluginEntry : availablePlugins) { - if (parsedUiOption.compare(getEnumName(availablePluginEntry).remove(prefixUi), Qt::CaseInsensitive) == 0) + if (parsedUiOption.compare(QString(getEnumName(availablePluginEntry)).remove(prefixUi), Qt::CaseInsensitive) == 0) { selectedPlugins << availablePluginEntry; } diff --git a/src/MetaTypeRegister.cpp b/src/MetaTypeRegister.cpp new file mode 100644 index 0000000..74a4095 --- /dev/null +++ b/src/MetaTypeRegister.cpp @@ -0,0 +1,51 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "MetaTypeRegister.h" + +#include "DatagramHandler.h" +#include "ReaderManagerWorker.h" + +#include "command/BaseCardCommand.h" +#include "command/CreateCardConnectionCommand.h" + +#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + #include "messages/BluetoothMessage.h" +#endif + +#if defined(Q_OS_IOS) +#include +#include +#include +#endif + +namespace governikus +{ + +namespace MetaTypes +{ +void registerMetaTypes() +{ + DatagramHandler::registerMetaTypes(); + ReaderManagerWorker::registerMetaTypes(); + + BaseCardCommand::registerMetaTypes(); + CreateCardConnectionCommand::registerMetaTypes(); + +#if defined(Q_OS_IOS) + // Used in card/bluetooth/BluetoothReaderManagerPlugin_p_ios + // TODO: These types should be registered by Qt but apparently they are not. + qRegisterMetaType("QBluetoothDeviceInfo"); + qRegisterMetaType("QLowEnergyCharacteristic"); + qRegisterMetaType("QLowEnergyDescriptor"); +#endif + +#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + BluetoothMessage::registerMetaTypes(); +#endif +} + + +} +} diff --git a/src/MetaTypeRegister.h b/src/MetaTypeRegister.h new file mode 100644 index 0000000..edea70e --- /dev/null +++ b/src/MetaTypeRegister.h @@ -0,0 +1,16 @@ +/*! + * \brief Function to register all meta types to be used with Qt. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + + +#pragma once + +namespace governikus +{ +namespace MetaTypes +{ +void registerMetaTypes(); +} +} diff --git a/src/activation/CMakeLists.txt b/src/activation/CMakeLists.txt index 3403786..422fa2e 100644 --- a/src/activation/CMakeLists.txt +++ b/src/activation/CMakeLists.txt @@ -1,6 +1,15 @@ ADD_SUBDIRECTORY(base) -ADD_SUBDIRECTORY(customscheme) -ADD_SUBDIRECTORY(intent) -ADD_SUBDIRECTORY(webservice) +IF(IOS) + ADD_SUBDIRECTORY(customscheme) +ENDIF() + +IF(ANDROID) + ADD_SUBDIRECTORY(intent) +ENDIF() + +IF(DESKTOP) + ADD_SUBDIRECTORY(webservice) +ENDIF() + ADD_SUBDIRECTORY(internal) diff --git a/src/activation/base/ActivationContext.h b/src/activation/base/ActivationContext.h index 583bd4c..4a80f7f 100644 --- a/src/activation/base/ActivationContext.h +++ b/src/activation/base/ActivationContext.h @@ -4,8 +4,8 @@ #pragma once +#include "GlobalStatus.h" #include "HttpStatusCode.h" -#include "Result.h" #include #include @@ -27,7 +27,7 @@ class ActivationContext ActivationContext(); virtual ~ActivationContext(); - virtual QUrl getActivationURL() = 0; + virtual QUrl getActivationURL() const = 0; /*! * Sends a processing status response to the caller. @@ -48,14 +48,14 @@ class ActivationContext * * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. */ - virtual bool sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) = 0; + virtual bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) = 0; /*! * Sends a redirect to the caller. * * \return true, if sending succeeded, false otherwise. On failure an error message can be retrieved via getSendError. */ - virtual bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) = 0; + virtual bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) = 0; /*! * Returns the last error that occurred during a send operation. diff --git a/src/activation/base/ActivationHandler.cpp b/src/activation/base/ActivationHandler.cpp index 27dae13..81d2493 100644 --- a/src/activation/base/ActivationHandler.cpp +++ b/src/activation/base/ActivationHandler.cpp @@ -53,7 +53,8 @@ const QVector& ActivationHandler::getInstances() if (instances.isEmpty()) { qCDebug(activation) << "Try to register plugin"; - for (auto plugin : QPluginLoader::staticPlugins()) + const auto& plugins = QPluginLoader::staticPlugins(); + for (const auto& plugin : plugins) { if (isPlugIn(plugin.metaData())) { diff --git a/src/activation/customscheme/CustomSchemeActivationContext.cpp b/src/activation/customscheme/CustomSchemeActivationContext.cpp index 74eeefc..3e2b343 100644 --- a/src/activation/customscheme/CustomSchemeActivationContext.cpp +++ b/src/activation/customscheme/CustomSchemeActivationContext.cpp @@ -34,13 +34,13 @@ CustomSchemeActivationContext::~CustomSchemeActivationContext() * Therefore we open the URL during deletion, which takes place when authentication * has finished and the AuthMdel is deleted. */ - qDebug() << "Redirecting now to URL " << mRedirectAddress; + qDebug() << "Perform redirect to URL" << mRedirectAddress; QDesktopServices::openUrl(mRedirectAddress); } } -QUrl CustomSchemeActivationContext::getActivationURL() +QUrl CustomSchemeActivationContext::getActivationURL() const { return mActivationUrl; } @@ -61,20 +61,20 @@ bool CustomSchemeActivationContext::sendOperationAlreadyActive() } -bool CustomSchemeActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) +bool CustomSchemeActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) { Q_UNUSED(pStatusCode); - Q_UNUSED(pResult); + Q_UNUSED(pStatus); // probably we emit a signal, that will be caught by the AppController // so that then UI can display some message or so? return true; } -bool CustomSchemeActivationContext::sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) +bool CustomSchemeActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) { - mRedirectAddress = UrlUtil::addMajorMinor(pRedirectAddress, pResult); - qDebug() << "Redirect URL:" << mRedirectAddress; + mRedirectAddress = UrlUtil::addMajorMinor(pRedirectAddress, pStatus); + qDebug() << "Determined redirect URL" << mRedirectAddress; return true; /* diff --git a/src/activation/customscheme/CustomSchemeActivationContext.h b/src/activation/customscheme/CustomSchemeActivationContext.h index f8a7c2c..5f4a57d 100644 --- a/src/activation/customscheme/CustomSchemeActivationContext.h +++ b/src/activation/customscheme/CustomSchemeActivationContext.h @@ -22,18 +22,14 @@ class CustomSchemeActivationContext public: CustomSchemeActivationContext(const QUrl& pActivationUrl); - virtual ~CustomSchemeActivationContext(); - QUrl getActivationURL() override; + QUrl getActivationURL() const override; bool sendProcessing() override; - bool sendOperationAlreadyActive() override; - - bool sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) override; - - bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) override; + bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; + bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pResult) override; }; } /* namespace governikus */ diff --git a/src/activation/customscheme/CustomSchemeActivationHandler.h b/src/activation/customscheme/CustomSchemeActivationHandler.h index ffa1518..b1b22f1 100644 --- a/src/activation/customscheme/CustomSchemeActivationHandler.h +++ b/src/activation/customscheme/CustomSchemeActivationHandler.h @@ -23,7 +23,7 @@ class CustomSchemeActivationHandler Q_PLUGIN_METADATA(IID "governikus.ActivationHandler" FILE "metadata.json") Q_INTERFACES(governikus::ActivationHandler) - protected: + private: void onCustomUrl(const QUrl& pUrl); public: diff --git a/src/activation/intent/CMakeLists.txt b/src/activation/intent/CMakeLists.txt index 966b9bd..0988902 100644 --- a/src/activation/intent/CMakeLists.txt +++ b/src/activation/intent/CMakeLists.txt @@ -1,4 +1,4 @@ ADD_PLATFORM_LIBRARY(AusweisAppActivationIntent) -TARGET_LINK_LIBRARIES(AusweisAppActivationIntent Qt5::Core AusweisAppGlobal AusweisAppNetwork AusweisAppActivation AusweisAppActivationCustomScheme) +TARGET_LINK_LIBRARIES(AusweisAppActivationIntent Qt5::Core Qt5::Gui AusweisAppGlobal AusweisAppNetwork AusweisAppActivation) TARGET_COMPILE_DEFINITIONS(AusweisAppActivationIntent PRIVATE QT_STATICPLUGIN) diff --git a/src/activation/intent/IntentActivationContext.cpp b/src/activation/intent/IntentActivationContext.cpp new file mode 100644 index 0000000..3b058df --- /dev/null +++ b/src/activation/intent/IntentActivationContext.cpp @@ -0,0 +1,75 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "IntentActivationContext.h" + +#include "UrlUtil.h" + +#include + + +using namespace governikus; + + +IntentActivationContext::IntentActivationContext(const QUrl& pActivationUrl) + : ActivationContext() + , mActivationUrl(pActivationUrl) + , mRedirectAddress() +{ +} + + +IntentActivationContext::~IntentActivationContext() +{ + if (!mRedirectAddress.isEmpty()) + { + /* + * Opening an URL on Android will bring the browser to the foreground, our app + * will go to the background, causing the authentication controller to stop. + * + * Therefore we open the URL during deletion, which takes place when authentication + * has finished and the AuthMdel is deleted. + */ + qDebug() << "Perform redirect to URL" << mRedirectAddress; + QDesktopServices::openUrl(mRedirectAddress); + } +} + + +QUrl IntentActivationContext::getActivationURL() const +{ + return mActivationUrl; +} + + +bool IntentActivationContext::sendProcessing() +{ + // nothing to be done in this case + return true; +} + + +bool IntentActivationContext::sendOperationAlreadyActive() +{ + // TODO: handle this + // probably we emit a signal, that will be caught by the AppController + // so that then UI can display some message or so? + return true; +} + + +bool IntentActivationContext::sendErrorPage(HttpStatusCode, const GlobalStatus&) +{ + // the error is displayed in the application, + // so here is nothing to be done in this case + return true; +} + + +bool IntentActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) +{ + mRedirectAddress = UrlUtil::addMajorMinor(pRedirectAddress, pStatus); + qDebug() << "Determined redirect URL" << mRedirectAddress; + return true; +} diff --git a/src/activation/intent/IntentActivationContext.h b/src/activation/intent/IntentActivationContext.h new file mode 100644 index 0000000..a7aca5d --- /dev/null +++ b/src/activation/intent/IntentActivationContext.h @@ -0,0 +1,34 @@ +/*! + * \brief Implementation of ActivationContext for Intent + * based activation on Android systems. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "ActivationContext.h" + + +namespace governikus +{ + +class IntentActivationContext + : public ActivationContext +{ + const QUrl mActivationUrl; + QUrl mRedirectAddress; + + public: + IntentActivationContext(const QUrl& pActivationUrl); + virtual ~IntentActivationContext(); + + QUrl getActivationURL() const override; + + bool sendProcessing() override; + bool sendOperationAlreadyActive() override; + bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; + bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pResult) override; +}; + +} /* namespace governikus */ diff --git a/src/activation/intent/IntentActivationHandler.cpp b/src/activation/intent/IntentActivationHandler.cpp index aeda1f8..e043ee5 100644 --- a/src/activation/intent/IntentActivationHandler.cpp +++ b/src/activation/intent/IntentActivationHandler.cpp @@ -6,9 +6,9 @@ #include "IntentActivationHandler.h" -#include +#include "IntentActivationContext.h" + #include -#include #ifdef Q_OS_ANDROID #include @@ -32,50 +32,30 @@ JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_MainActivity_triggerActiv { auto handler = ActivationHandler::getInstance(); Q_ASSERT(handler); - handler->onCustomUrl(QUrl(lastIntentString)); + handler->onIntent(QUrl(lastIntentString)); } } } -namespace governikus -{ -/*! - * Accessor of Java class MainActivitiy - */ -class MainActivityAccessor -{ - public: - static QString getInitialIntent() - { - return QAndroidJniObject::callStaticObjectMethod("com/governikus/ausweisapp2/MainActivity", "getInitialIntent").toString(); - } - - -}; - -} #endif -IntentActivationHandler::IntentActivationHandler() - : CustomSchemeActivationHandler() -{ -} - - -IntentActivationHandler::~IntentActivationHandler() +void IntentActivationHandler::onIntent(const QUrl& pUrl) { + qCDebug(activation) << "Got new authentication request"; + qCDebug(activation) << "Request URL:" << pUrl; + Q_EMIT fireAuthenticationRequest(new IntentActivationContext(pUrl)); } bool IntentActivationHandler::start() { #ifdef Q_OS_ANDROID - QString initialIntent = MainActivityAccessor::getInitialIntent(); + const QString& initialIntent = QAndroidJniObject::callStaticObjectMethod("com/governikus/ausweisapp2/MainActivity", "getInitialIntent").toString(); if (!initialIntent.isNull()) { - onCustomUrl(initialIntent); + onIntent(initialIntent); } return true; diff --git a/src/activation/intent/IntentActivationHandler.h b/src/activation/intent/IntentActivationHandler.h index 82e6426..0367f2b 100644 --- a/src/activation/intent/IntentActivationHandler.h +++ b/src/activation/intent/IntentActivationHandler.h @@ -6,7 +6,7 @@ #pragma once -#include "CustomSchemeActivationHandler.h" +#include "ActivationHandler.h" #ifdef Q_OS_ANDROID #include @@ -23,12 +23,12 @@ namespace governikus { /*! - * This ActivationHandler implements an API by opening custom URLs with scheme 'eid', + * This ActivationHandler implements an API by opening custom URLs registered in the Android manifest, * as specified by TR-03124-1. * The URL is passed by an Android Intent mechanism to the application. */ class IntentActivationHandler - : public CustomSchemeActivationHandler + : public ActivationHandler { Q_OBJECT Q_PLUGIN_METADATA(IID "governikus.ActivationHandler" FILE "metadata.json") @@ -38,9 +38,11 @@ class IntentActivationHandler friend void::Java_com_governikus_ausweisapp2_MainActivity_triggerActivation(JNIEnv*, jobject, jstring); #endif + private: + void onIntent(const QUrl& pUrl); + public: - IntentActivationHandler(); - virtual ~IntentActivationHandler(); + IntentActivationHandler() = default; virtual bool start() override; virtual void stop() override; diff --git a/src/activation/intent/MainActivity.java b/src/activation/intent/MainActivity.java index 18c528c..6e84823 100644 --- a/src/activation/intent/MainActivity.java +++ b/src/activation/intent/MainActivity.java @@ -50,13 +50,19 @@ public class MainActivity extends QtActivity void enable() { - mAdapter.enableForegroundDispatch(mActivity, mPendingIntent, mFilters, mTechLists); + if (mAdapter != null) + { + mAdapter.enableForegroundDispatch(mActivity, mPendingIntent, mFilters, mTechLists); + } } void disable() { - mAdapter.disableForegroundDispatch(mActivity); + if (mAdapter != null) + { + mAdapter.disableForegroundDispatch(mActivity); + } } diff --git a/src/activation/internal/InternalActivationContext.cpp b/src/activation/internal/InternalActivationContext.cpp index 1d33d59..8f14792 100644 --- a/src/activation/internal/InternalActivationContext.cpp +++ b/src/activation/internal/InternalActivationContext.cpp @@ -23,7 +23,7 @@ InternalActivationContext::~InternalActivationContext() } -QUrl InternalActivationContext::getActivationURL() +QUrl InternalActivationContext::getActivationURL() const { return mTcTokenUrl; } @@ -41,17 +41,17 @@ bool InternalActivationContext::sendOperationAlreadyActive() } -bool InternalActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) +bool InternalActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) { Q_UNUSED(pStatusCode) - Q_UNUSED(pResult) + Q_UNUSED(pStatus) return true; } -bool InternalActivationContext::sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) +bool InternalActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) { Q_UNUSED(pRedirectAddress) - Q_UNUSED(pResult) + Q_UNUSED(pStatus) return true; } diff --git a/src/activation/internal/InternalActivationContext.h b/src/activation/internal/InternalActivationContext.h index f75f81c..ba313e8 100644 --- a/src/activation/internal/InternalActivationContext.h +++ b/src/activation/internal/InternalActivationContext.h @@ -21,11 +21,11 @@ class InternalActivationContext InternalActivationContext(const QUrl& pUrl); virtual ~InternalActivationContext(); - QUrl getActivationURL() override; + QUrl getActivationURL() const override; bool sendProcessing() override; bool sendOperationAlreadyActive() override; - bool sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) override; - bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) override; + bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; + bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override; }; } /* namespace governikus */ diff --git a/src/activation/webservice/CMakeLists.txt b/src/activation/webservice/CMakeLists.txt index 8d98163..f5a42df 100644 --- a/src/activation/webservice/CMakeLists.txt +++ b/src/activation/webservice/CMakeLists.txt @@ -1,4 +1,4 @@ ADD_PLATFORM_LIBRARY(AusweisAppActivationWebservice) -TARGET_LINK_LIBRARIES(AusweisAppActivationWebservice Qt5::Core AusweisAppGlobal AusweisAppNetwork AusweisAppActivation AusweisAppExternalQHttpServer) +TARGET_LINK_LIBRARIES(AusweisAppActivationWebservice Qt5::Core AusweisAppGlobal AusweisAppNetwork AusweisAppActivation) TARGET_COMPILE_DEFINITIONS(AusweisAppActivationWebservice PRIVATE QT_STATICPLUGIN) diff --git a/src/activation/webservice/WebserviceActivationContext.cpp b/src/activation/webservice/WebserviceActivationContext.cpp index d424f44..2cb5760 100644 --- a/src/activation/webservice/WebserviceActivationContext.cpp +++ b/src/activation/webservice/WebserviceActivationContext.cpp @@ -8,8 +8,6 @@ #include "Template.h" #include "UrlUtil.h" -#include "qhttpserver/qhttprequest.h" -#include "qhttpserver/qhttpresponse.h" #include #include @@ -20,19 +18,17 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(activation) -void WebserviceActivationContext::setCommonHeaders(QSharedPointer pResponse) +void WebserviceActivationContext::setCommonHeaders(HttpResponse& pResponse) { - WebserviceActivationContext::setServerHeader(*pResponse.data()); - pResponse->setHeader(QStringLiteral("Connection"), QStringLiteral("close")); - pResponse->setHeader(QStringLiteral("Cache-Control"), QStringLiteral("no-cache, no-store")); - pResponse->setHeader(QStringLiteral("Pragma"), QStringLiteral("no-cache")); + pResponse.setHeader(QByteArrayLiteral("Connection"), QByteArrayLiteral("close")); + pResponse.setHeader(QByteArrayLiteral("Cache-Control"), QByteArrayLiteral("no-cache, no-store")); + pResponse.setHeader(QByteArrayLiteral("Pragma"), QByteArrayLiteral("no-cache")); } -WebserviceActivationContext::WebserviceActivationContext(QSharedPointer pRequest, QSharedPointer pResponse) +WebserviceActivationContext::WebserviceActivationContext(const QSharedPointer& pRequest) : ActivationContext() , mRequest(pRequest) - , mResponse(pResponse) { } @@ -42,32 +38,28 @@ WebserviceActivationContext::~WebserviceActivationContext() } -QUrl WebserviceActivationContext::getActivationURL() +QUrl WebserviceActivationContext::getActivationURL() const { - return mRequest->url(); + return mRequest->getUrl(); } bool WebserviceActivationContext::sendProcessing() { - if (mResponse->getState() != QAbstractSocket::ConnectedState) + if (!mRequest->isConnected()) { mSendError = tr("The browser connection was lost."); return false; } - WebserviceActivationContext::setServerHeader(*mResponse.data()); - mResponse->setHeader(QStringLiteral("Content-Length"), QStringLiteral("0")); - mResponse->writeHead(QHttpResponse::STATUS_PROCESSING); - // allow final writing in StateRedirectBrowser - mResponse->clearHeaders(); + mRequest->send(HttpStatusCode::PROCESSING); return true; } bool WebserviceActivationContext::sendOperationAlreadyActive() { - if (mResponse->getState() != QAbstractSocket::ConnectedState) + if (!mRequest->isConnected()) { mSendError = tr("The browser connection was lost."); return false; @@ -78,22 +70,21 @@ bool WebserviceActivationContext::sendOperationAlreadyActive() htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Cannot start authentication")); htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("An operation is already in progress.")); htmlTemplate.setContextParameter(QStringLiteral("CONTENT_HEADER"), tr("Would you like to try again?")); - htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), mRequest->url().toString()); + htmlTemplate.setContextParameter(QStringLiteral("CONTENT_LINK"), mRequest->getUrl().toString()); htmlTemplate.setContextParameter(QStringLiteral("CONTENT_BUTTON"), tr("Try again")); QByteArray htmlPage = htmlTemplate.render().toUtf8(); - WebserviceActivationContext::setServerHeader(*mResponse.data()); - mResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("text/html; charset=utf-8")); - mResponse->setHeader(QStringLiteral("Content-Length"), QString::number(htmlPage.size())); - mResponse->writeHead(QHttpResponse::STATUS_NOT_FOUND); - mResponse->end(htmlPage); + HttpResponse response; + response.setStatus(HttpStatusCode::NOT_FOUND); + response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); + mRequest->send(response); return true; } -bool WebserviceActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) +bool WebserviceActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) { - if (mResponse->getState() != QAbstractSocket::ConnectedState) + if (!mRequest->isConnected()) { mSendError = tr("The browser connection was lost."); return false; @@ -116,27 +107,27 @@ bool WebserviceActivationContext::sendErrorPage(HttpStatusCode pStatusCode, cons htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Invalid request")); htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your browser sent a request that couldn't be interpreted.")); htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE_LABEL"), tr("Error message")); - htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE"), pResult.getMessage()); + htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE"), pStatus.toErrorDescription(true)); htmlTemplate.setContextParameter(QStringLiteral("REPORT_HEADER"), tr("Would you like to report this error?")); htmlTemplate.setContextParameter(QStringLiteral("REPORT_LINK"), tr("https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/")); htmlTemplate.setContextParameter(QStringLiteral("REPORT_BUTTON"), tr("Report now")); QByteArray htmlPage = htmlTemplate.render().toUtf8(); - setCommonHeaders(mResponse); - mResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("text/html; charset=utf-8")); - mResponse->setHeader(QStringLiteral("Content-Length"), QString::number(htmlPage.size())); - mResponse->writeHead(static_cast(pStatusCode)); - mResponse->end(htmlPage); + HttpResponse response; + setCommonHeaders(response); + response.setStatus(pStatusCode); + response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); + mRequest->send(response); return true; } -bool WebserviceActivationContext::sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) +bool WebserviceActivationContext::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) { - QUrl redirectAddressWithResult = UrlUtil::addMajorMinor(pRedirectAddress, pResult); + QUrl redirectAddressWithResult = UrlUtil::addMajorMinor(pRedirectAddress, pStatus); qCDebug(activation) << "Redirect URL:" << redirectAddressWithResult; - if (mResponse->getState() != QAbstractSocket::ConnectedState) + if (!mRequest->isConnected()) { mSendError = tr("The connection to the bowser was lost. No forwarding was executed. Please try to" " call the URL again manually: %2").arg(redirectAddressWithResult.toString(), redirectAddressWithResult.host()); @@ -144,19 +135,10 @@ bool WebserviceActivationContext::sendRedirect(const QUrl& pRedirectAddress, con } qCDebug(activation) << "Redirecting now to URL:" << redirectAddressWithResult; - setCommonHeaders(mResponse); - mResponse->setHeader(QStringLiteral("Location"), QString::fromLatin1(redirectAddressWithResult.toEncoded())); - mResponse->setHeader(QStringLiteral("Content-Length"), QStringLiteral("0")); - mResponse->writeHead(QHttpResponse::STATUS_SEE_OTHER); - mResponse->end(); + HttpResponse response; + setCommonHeaders(response); + response.setHeader(QByteArrayLiteral("Location"), redirectAddressWithResult.toEncoded()); + response.setStatus(HttpStatusCode::SEE_OTHER); + mRequest->send(response); return true; } - - -void WebserviceActivationContext::setServerHeader(QHttpResponse& pReply) -{ - /* - * According to TR-03124-1, chapter 2.2.2.1, the Server-header shall have the following form: - */ - pReply.setHeader(QStringLiteral("Server"), QCoreApplication::applicationName() + "/" + QCoreApplication::applicationVersion() + " (TR-03124-1/1.2)"); -} diff --git a/src/activation/webservice/WebserviceActivationContext.h b/src/activation/webservice/WebserviceActivationContext.h index e6baeeb..ca5a264 100644 --- a/src/activation/webservice/WebserviceActivationContext.h +++ b/src/activation/webservice/WebserviceActivationContext.h @@ -7,15 +7,10 @@ #pragma once #include "ActivationContext.h" -#include "qhttpserver/qhttprequest.h" -#include "qhttpserver/qhttpresponse.h" +#include "HttpRequest.h" #include - -class QHttpResponse; - - namespace governikus { @@ -24,27 +19,24 @@ class WebserviceActivationContext { Q_OBJECT - const QSharedPointer mRequest; - const QSharedPointer mResponse; + const QSharedPointer mRequest; - void setCommonHeaders(QSharedPointer pResponse); + void setCommonHeaders(HttpResponse& pResponse); public: - WebserviceActivationContext(QSharedPointer pRequest, QSharedPointer pResponse); + WebserviceActivationContext(const QSharedPointer& pRequest); virtual ~WebserviceActivationContext(); - QUrl getActivationURL() override; + QUrl getActivationURL() const override; bool sendProcessing() override; bool sendOperationAlreadyActive() override; - bool sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) override; + bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; - bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) override; - - static void setServerHeader(QHttpResponse& pReply); + bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override; }; } /* namespace governikus */ diff --git a/src/activation/webservice/WebserviceActivationHandler.cpp b/src/activation/webservice/WebserviceActivationHandler.cpp index 687c77d..ce0f304 100644 --- a/src/activation/webservice/WebserviceActivationHandler.cpp +++ b/src/activation/webservice/WebserviceActivationHandler.cpp @@ -6,6 +6,7 @@ #include "WebserviceActivationHandler.h" +#include "EnvHolder.h" #include "HttpServerStatusParser.h" #include "Template.h" #include "VersionInfo.h" @@ -21,12 +22,9 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(activation) -quint16 WebserviceActivationHandler::PORT = 24727; - - WebserviceActivationHandler::WebserviceActivationHandler() : ActivationHandler() - , mHttpServer() + , mServer() { } @@ -36,34 +34,31 @@ WebserviceActivationHandler::~WebserviceActivationHandler() } -quint16 WebserviceActivationHandler::getServerPort() -{ - return mHttpServer.serverPort(); -} - - void WebserviceActivationHandler::stop() { - mHttpServer.close(); + mServer.reset(); } bool WebserviceActivationHandler::start() { - if (mHttpServer.listen(QHostAddress::LocalHost, PORT)) + mServer = EnvHolder::shared(); + + if (mServer->isListening()) { - connect(&mHttpServer, &QHttpServer::newRequest, this, &WebserviceActivationHandler::onNewRequest); - qCDebug(activation) << "Listening on port:" << mHttpServer.serverPort(); + connect(mServer.data(), &HttpServer::fireNewHttpRequest, this, &WebserviceActivationHandler::onNewRequest); return true; } - HttpServerStatusParser parser(PORT); + + const int port = HttpServer::cPort; + HttpServerStatusParser parser(port); QString serverAppName = parser.request() ? parser.getVersionInfo().getName() : parser.getServerHeader(); if (serverAppName.startsWith(VersionInfo::getInstance().getName())) { - qDebug() << "We are already started... calling ShowUI"; + qCDebug(activation) << "We are already started... calling ShowUI"; HttpServerRequestor requestor; - if (requestor.request(HttpServerRequestor::createUrl("ShowUI=" + UiModule::CURRENT, PORT)).isNull()) + if (requestor.request(HttpServerRequestor::createUrl("ShowUI=" + UiModule::CURRENT, port)).isNull()) { qCWarning(activation) << "ShowUI request timed out"; } @@ -72,55 +67,52 @@ bool WebserviceActivationHandler::start() { qCCritical(activation) << "Cannot start application. Port on localhost is already bound by another program:" << serverAppName; - QString msg = serverAppName.isEmpty() ? tr("An unknown program uses the required port (%1). Please exit the other program and try again!").arg(PORT) : - tr("Another program (%1) uses the required port (%2). Please exit this other program and try again!").arg(serverAppName).arg(PORT); + QString msg = serverAppName.isEmpty() ? tr("An unknown program uses the required port (%1). Please exit the other program and try again!").arg(port) : + tr("Another program (%1) uses the required port (%2). Please exit this other program and try again!").arg(serverAppName).arg(port); Q_EMIT fireShowUserInformation(msg); } + + mServer.reset(); return false; } -void WebserviceActivationHandler::onNewRequest(QSharedPointer pRequest, QSharedPointer pResponse) +void WebserviceActivationHandler::onNewRequest(const QSharedPointer& pRequest) { - qCDebug(activation) << "Got new request"; - qCDebug(activation) << "Request URL:" << pRequest->url(); - qCDebug(activation) << "Request User-Agent:" << pRequest->header(QStringLiteral("User-Agent")); - - if (pRequest->url().path() == QLatin1String("/eID-Client")) + const auto& url = pRequest->getUrl(); + if (url.path() == QLatin1String("/eID-Client")) { - const auto urlParameter = getQueryParameter(pRequest->url()); + const auto urlParameter = getQueryParameter(url); if (urlParameter.contains(QLatin1String("showui"))) { qCDebug(activation) << "Request type: showui"; UiModule module = Enum::fromString(urlParameter.value(QLatin1String("showui")).toUpper(), UiModule::DEFAULT); - handleShowUiRequest(module, pRequest, pResponse); + handleShowUiRequest(module, pRequest); return; } else if (urlParameter.contains(QLatin1String("status"))) { qCDebug(activation) << "Request type: status"; StatusFormat statusFormat = Enum::fromString(urlParameter.value(QLatin1String("status")).toUpper(), StatusFormat::PLAIN); - handleStatusRequest(statusFormat, pResponse); + handleStatusRequest(statusFormat, pRequest); return; } else if (urlParameter.contains(QLatin1String("tctokenurl"))) { - qDebug(activation) << "Request type: authentication"; - Q_EMIT fireAuthenticationRequest(new WebserviceActivationContext(pRequest, pResponse)); + qCDebug(activation) << "Request type: authentication"; + Q_EMIT fireAuthenticationRequest(new WebserviceActivationContext(pRequest)); return; } } - else if (pRequest->url().path() == QLatin1String("/favicon.ico")) + else if (url.path() == QLatin1String("/favicon.ico")) { - qCDebug(activation) << "Request image:" << pRequest->url().path(); - handleImageRequest(pResponse, QStringLiteral(":/images/npa.ico")); // it MUST be an ICO! + handleImageRequest(pRequest, QStringLiteral(":/images/npa.ico")); // it MUST be an ICO! return; } - else if (pRequest->url().path().startsWith(QLatin1String("/images/")) && !pRequest->url().path().contains(QLatin1String("../"))) + else if (url.path().startsWith(QLatin1String("/images/")) && !url.path().contains(QLatin1String("../"))) { - qCDebug(activation) << "Request image:" << pRequest->url().path(); - handleImageRequest(pResponse, QStringLiteral(":%1").arg(pRequest->url().path())); + handleImageRequest(pRequest, QStringLiteral(":%1").arg(url.path())); return; } @@ -131,29 +123,24 @@ void WebserviceActivationHandler::onNewRequest(QSharedPointer pReq htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER"), tr("Invalid request")); htmlTemplate.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), tr("Your browser sent a request that couldn't be interpreted.")); htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE_LABEL"), tr("Error message")); - htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE"), tr("Unknown request: %1").arg(pRequest->url().toString())); + htmlTemplate.setContextParameter(QStringLiteral("ERROR_MESSAGE"), tr("Unknown request: %1").arg(url.toString())); htmlTemplate.setContextParameter(QStringLiteral("REPORT_HEADER"), tr("Would you like to report this error?")); htmlTemplate.setContextParameter(QStringLiteral("REPORT_LINK"), tr("https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/")); htmlTemplate.setContextParameter(QStringLiteral("REPORT_BUTTON"), tr("Report now")); QByteArray htmlPage = htmlTemplate.render().toUtf8(); - WebserviceActivationContext::setServerHeader(*pResponse.data()); - pResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("text/html; charset=utf-8")); - pResponse->setHeader(QStringLiteral("Content-Length"), QString::number(htmlPage.size())); - pResponse->writeHead(QHttpResponse::STATUS_NOT_FOUND); - pResponse->end(htmlPage); + HttpResponse response; + response.setStatus(HttpStatusCode::NOT_FOUND); + response.setBody(htmlPage, QByteArrayLiteral("text/html; charset=utf-8")); + pRequest->send(response); } -void WebserviceActivationHandler::handleShowUiRequest(UiModule pUiModule, QSharedPointer pRequest, QSharedPointer pResponse) +void WebserviceActivationHandler::handleShowUiRequest(UiModule pUiModule, const QSharedPointer& pRequest) { - WebserviceActivationContext::setServerHeader(*pResponse.data()); - pResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("text/plain; charset=utf-8")); - pResponse->setHeader(QStringLiteral("Content-Length"), QString::number(0)); - pResponse->writeHead(QHttpResponse::STATUS_OK); - pResponse->end(); + pRequest->send(HttpStatusCode::OK); - QString userAgent = pRequest->header(QStringLiteral("User-Agent")); + QString userAgent = QString::fromLatin1(pRequest->getHeader(QByteArrayLiteral("user-agent"))); if (userAgent.startsWith(QCoreApplication::applicationName())) { QString version = userAgent.remove(QCoreApplication::applicationName() + '/').split(' ').at(0); @@ -177,79 +164,66 @@ void WebserviceActivationHandler::handleShowUiRequest(UiModule pUiModule, QShare } -void WebserviceActivationHandler::handleImageRequest(QSharedPointer pResponse, const QString& pImagePath) +void WebserviceActivationHandler::handleImageRequest(const QSharedPointer& pRequest, const QString& pImagePath) { - QByteArray content; - QString contentType; - QHttpResponse::StatusCode statusCode; + HttpResponse response; QFile imageFile(pImagePath); if (imageFile.open(QIODevice::ReadOnly)) { - content = imageFile.readAll(); + response.setStatus(HttpStatusCode::OK); + response.setBody(imageFile.readAll(), guessImageContentType(pImagePath)); imageFile.close(); - contentType = guessImageContentType(pImagePath); - statusCode = QHttpResponse::STATUS_OK; } else { qCCritical(activation) << "Unknown image file requested" << pImagePath; - content = QByteArrayLiteral("Not found"); - contentType = QStringLiteral("text/plain; charset=utf-8"); - statusCode = QHttpResponse::STATUS_NOT_FOUND; + response.setStatus(HttpStatusCode::NOT_FOUND); + response.setBody(QByteArrayLiteral("Not found"), QByteArrayLiteral("text/plain; charset=utf-8")); } - WebserviceActivationContext::setServerHeader(*pResponse); - pResponse->setHeader(QStringLiteral("Content-Type"), contentType); - pResponse->setHeader(QStringLiteral("Content-Length"), QString::number(content.size())); - pResponse->writeHead(statusCode); - pResponse->end(content); + pRequest->send(response); } -QString WebserviceActivationHandler::guessImageContentType(const QString& pFileName) const +QByteArray WebserviceActivationHandler::guessImageContentType(const QString& pFileName) const { if (pFileName.endsWith(QLatin1String(".ico"), Qt::CaseInsensitive)) { - return QStringLiteral("image/x-icon"); + return QByteArrayLiteral("image/x-icon"); } if (pFileName.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) || pFileName.endsWith(QLatin1String(".jpeg"), Qt::CaseInsensitive)) { - return QStringLiteral("image/jpeg"); + return QByteArrayLiteral("image/jpeg"); } if (pFileName.endsWith(QLatin1String(".png"), Qt::CaseInsensitive)) { - return QStringLiteral("image/png"); + return QByteArrayLiteral("image/png"); } if (pFileName.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) { - return QStringLiteral("image/svg+xml"); + return QByteArrayLiteral("image/svg+xml"); } - qWarning() << "Unknown content type, returing default for image" << pFileName; - return QStringLiteral("image"); + qCWarning(activation) << "Unknown content type, returing default for image" << pFileName; + return QByteArrayLiteral("image"); } -void WebserviceActivationHandler::handleStatusRequest(StatusFormat pStatusFormat, QSharedPointer pResponse) +void WebserviceActivationHandler::handleStatusRequest(StatusFormat pStatusFormat, const QSharedPointer& pRequest) { qCDebug(activation) << "Create response with status format:" << pStatusFormat; - QByteArray versionInfo; + + HttpResponse response(HttpStatusCode::OK); switch (pStatusFormat) { case StatusFormat::PLAIN: - pResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("text/plain; charset=utf-8")); - versionInfo = VersionInfo::getInstance().toText().toUtf8(); + response.setBody(VersionInfo::getInstance().toText().toUtf8(), QByteArrayLiteral("text/plain; charset=utf-8")); break; case StatusFormat::JSON: - pResponse->setHeader(QStringLiteral("Content-Type"), QStringLiteral("application/json")); - versionInfo = VersionInfo::getInstance().toJson(); + response.setBody(VersionInfo::getInstance().toJson(), QByteArrayLiteral("application/json")); break; } - WebserviceActivationContext::setServerHeader(*pResponse.data()); - pResponse->setHeader(QStringLiteral("Access-Control-Allow-Origin"), QStringLiteral("*")); - pResponse->setHeader(QStringLiteral("Content-Length"), QString::number(versionInfo.size())); - pResponse->writeHead(QHttpResponse::STATUS_OK); - pResponse->end(versionInfo); + pRequest->send(response); } diff --git a/src/activation/webservice/WebserviceActivationHandler.h b/src/activation/webservice/WebserviceActivationHandler.h index 1853cb8..e657981 100644 --- a/src/activation/webservice/WebserviceActivationHandler.h +++ b/src/activation/webservice/WebserviceActivationHandler.h @@ -6,11 +6,8 @@ #pragma once - #include "ActivationHandler.h" -#include "qhttpserver/qhttprequest.h" -#include "qhttpserver/qhttpresponse.h" -#include "qhttpserver/qhttpserver.h" +#include "HttpServer.h" class test_WebserviceActivationHandler; @@ -28,29 +25,26 @@ class WebserviceActivationHandler Q_PLUGIN_METADATA(IID "governikus.ActivationHandler" FILE "metadata.json") Q_INTERFACES(governikus::ActivationHandler) - friend class::test_WebserviceActivationHandler; + private: + friend class::test_WebserviceActivationHandler; + QSharedPointer mServer; - QHttpServer mHttpServer; + static void addStatusLine(QString& pContent, StatusFormat pStatusFormat, const QString& pKey, const QString& pValue); - static void addStatusLine(QString& pContent, StatusFormat pStatusFormat, const QString& pKey, const QString& pValue); - - void handleImageRequest(QSharedPointer pResponse, const QString& pImagePath); - QString guessImageContentType(const QString& pFileName) const; - void handleShowUiRequest(UiModule pUiModule, QSharedPointer pRequest, QSharedPointer pResponse); - void handleStatusRequest(StatusFormat pStatusFormat, QSharedPointer pResponse); + void handleImageRequest(const QSharedPointer& pRequest, const QString& pImagePath); + QByteArray guessImageContentType(const QString& pFileName) const; + void handleShowUiRequest(UiModule pUiModule, const QSharedPointer& pRequest); + void handleStatusRequest(StatusFormat pStatusFormat, const QSharedPointer& pRequest); private Q_SLOTS: - void onNewRequest(QSharedPointer pRequest, QSharedPointer pResponse); + void onNewRequest(const QSharedPointer& pRequest); public: - static quint16 PORT; WebserviceActivationHandler(); virtual ~WebserviceActivationHandler(); - quint16 getServerPort(); virtual bool start() override; virtual void stop() override; - }; } /* namespace governikus */ diff --git a/src/aidl/AidlBinder.java b/src/aidl/AidlBinder.java index fcc3fe2..a903bf4 100644 --- a/src/aidl/AidlBinder.java +++ b/src/aidl/AidlBinder.java @@ -115,15 +115,14 @@ class AidlBinder extends IAusweisApp2Sdk.Stub } - // FIXME This function is meant to return void istead of java.lang.Object but JNI does not like void - public synchronized Object aidlReceive(String pMessageToClient) + public synchronized void aidlReceive(String pMessageToClient) { Log.d(LOG_TAG, "Android service: Passing JSON to client"); if (mCallback == null) { Log.d(LOG_TAG, "Android service: Callback not connected."); - return null; + return; } try @@ -139,8 +138,6 @@ class AidlBinder extends IAusweisApp2Sdk.Stub { handleRemoteException(e); } - - return null; } diff --git a/src/aidl/PskManager.cpp b/src/aidl/PskManager.cpp index 1010c7a..6ceb337 100644 --- a/src/aidl/PskManager.cpp +++ b/src/aidl/PskManager.cpp @@ -24,19 +24,19 @@ PskManager & PskManager::getInstance() } -QString PskManager::generatePsk(const QString& pClientPartialPsk) +QByteArray PskManager::generatePsk(const QByteArray& pClientPartialPsk) { const static int TIMESTAMP_BYTE_COUNT = 64 / 8; const static int RANDOM_BYTE_COUNT = 256; - QMutexLocker locker(&mPskMutex); + const QMutexLocker locker(&mPskMutex); QByteArray timeStampBytes; timeStampBytes.reserve(TIMESTAMP_BYTE_COUNT); qint64 timeStamp = QDateTime::currentMSecsSinceEpoch(); for (int i = 0; i < TIMESTAMP_BYTE_COUNT; i++) { - timeStampBytes += timeStamp & 0xFF; + timeStampBytes += static_cast(timeStamp & 0xFF); timeStamp >>= 8; } @@ -48,11 +48,11 @@ QString PskManager::generatePsk(const QString& pClientPartialPsk) std::mt19937& generator = randomizer.getGenerator(); for (int i = 0; i < RANDOM_BYTE_COUNT; i += 4) { - const qint32 randomNumber = generator(); - randomBytes += (char) randomNumber & 0xFF; - randomBytes += (char) (randomNumber >> 8) & 0xFF; - randomBytes += (char) (randomNumber >> 16) & 0xFF; - randomBytes += (char) (randomNumber >> 24) & 0xFF; + const auto randomNumber = generator(); + randomBytes += static_cast(randomNumber & 0xFF); + randomBytes += static_cast((randomNumber >> 8) & 0xFF); + randomBytes += static_cast((randomNumber >> 16) & 0xFF); + randomBytes += static_cast((randomNumber >> 24) & 0xFF); } QByteArray mServerInputBytes; @@ -60,31 +60,30 @@ QString PskManager::generatePsk(const QString& pClientPartialPsk) mServerInputBytes += timeStampBytes; mServerInputBytes += randomBytes; - QString clientPartialPsk = pClientPartialPsk.trimmed(); - if (clientPartialPsk.startsWith(QLatin1String("0x"))) + auto clientPartialPsk = pClientPartialPsk.trimmed(); + if (clientPartialPsk.startsWith("0x")) { clientPartialPsk = clientPartialPsk.mid(2, -1); } - const QByteArray clientInputBytes = QByteArray::fromHex(clientPartialPsk.toLatin1()); + const auto& clientInputBytes = QByteArray::fromHex(clientPartialPsk); QCryptographicHash hashFunction(QCryptographicHash::Sha256); hashFunction.addData(mServerInputBytes); hashFunction.addData(clientInputBytes); - mPsk = hashFunction.result(); - - return QString::fromLatin1(mPsk.toHex()); + mPsk = hashFunction.result().toHex(); + return mPsk; } QByteArray PskManager::getPsk() { - QMutexLocker locker(&mPskMutex); + const QMutexLocker locker(&mPskMutex); return mPsk; } bool PskManager::isSecureRandomPsk() { - QMutexLocker locker(&mPskMutex); + const QMutexLocker locker(&mPskMutex); return mSecureRandomPsk; } diff --git a/src/aidl/PskManager.h b/src/aidl/PskManager.h index 318b9ab..6429a5a 100644 --- a/src/aidl/PskManager.h +++ b/src/aidl/PskManager.h @@ -24,7 +24,7 @@ class PskManager public: static PskManager& getInstance(); - QString generatePsk(const QString& pClientPartialPsk); + QByteArray generatePsk(const QByteArray& pClientPartialPsk = QByteArray()); QByteArray getPsk(); bool isSecureRandomPsk(); }; diff --git a/src/aidl/UIPlugInAidl.cpp b/src/aidl/UIPlugInAidl.cpp index 90905d6..8d71f55 100644 --- a/src/aidl/UIPlugInAidl.cpp +++ b/src/aidl/UIPlugInAidl.cpp @@ -40,7 +40,7 @@ UIPlugInAidl::UIPlugInAidl() { mJsonApi = qobject_cast(UILoader::getInstance().getLoaded(UIPlugInName::UIPlugInJsonApi)); Q_ASSERT(mJsonApi); - connect(mJsonApi, &UIPlugInJsonApi::fireMessage, this, &UIPlugInAidl::onToSend); + connect(mJsonApi, &UIPlugInJsonApi::fireMessage, this, &UIPlugInAidl::onToSend, Qt::QueuedConnection); mInitializationSuccessfull = true; } @@ -88,7 +88,9 @@ void UIPlugInAidl::onWorkflowStarted(QSharedPointer pContext) void UIPlugInAidl::onWorkflowFinished(QSharedPointer pContext) { - mContext = pContext; + Q_UNUSED(pContext); + + mContext.clear(); } @@ -115,8 +117,7 @@ void UIPlugInAidl::onToSend(const QByteArray& pMessage) QAndroidJniObject jsonAndroidString = QAndroidJniObject::fromString(json); QAndroidJniObject aidlBinder = QtAndroid::androidService().callObjectMethod("getAidlBinder", "()Lcom/governikus/ausweisapp2/AidlBinder;"); - // FIXME This function is meant to return void istead of java.lang.Object but JNI does not like void - aidlBinder.callObjectMethod("aidlReceive", "(Ljava/lang/String;)Ljava/lang/Object;", jsonAndroidString.object()); + aidlBinder.callMethod("aidlReceive", "(Ljava/lang/String;)V", jsonAndroidString.object()); #else Q_UNUSED(pMessage); #endif @@ -140,7 +141,7 @@ JNIEXPORT jstring JNICALL Java_com_governikus_ausweisapp2_AidlBinder_resetValidS Q_UNUSED(pObj); const char* nativeString = pEnv->GetStringUTFChars(pClientPartialPsk, 0); - const QString clientPartialPsk = QString::fromUtf8(nativeString); + const auto& clientPartialPsk = QByteArray(nativeString); pEnv->ReleaseStringUTFChars(pClientPartialPsk, nativeString); @@ -153,8 +154,8 @@ JNIEXPORT jstring JNICALL Java_com_governikus_ausweisapp2_AidlBinder_resetValidS QMetaObject::invokeMethod(plugin, "reset", Qt::BlockingQueuedConnection); - const QString finalPsk = PskManager::getInstance().generatePsk(clientPartialPsk); - return pEnv->NewStringUTF(finalPsk.toUtf8().constData()); + const auto& finalPsk = PskManager::getInstance().generatePsk(clientPartialPsk); + return pEnv->NewStringUTF(finalPsk.constData()); } diff --git a/src/aidl/UIPlugInAidl.h b/src/aidl/UIPlugInAidl.h index 023ac24..f544efd 100644 --- a/src/aidl/UIPlugInAidl.h +++ b/src/aidl/UIPlugInAidl.h @@ -35,9 +35,9 @@ class UIPlugInAidl static UIPlugInAidl* getInstance(bool pBlock = true); bool isSuccessfullInitialized(); Q_INVOKABLE void onReceived(const QByteArray& pMessage); - void reset(); private Q_SLOTS: + void reset(); virtual void doShutdown() override; virtual void onWorkflowStarted(QSharedPointer pContext) override; virtual void onWorkflowFinished(QSharedPointer pContext) override; diff --git a/src/card/CMakeLists.txt b/src/card/CMakeLists.txt index e1cf96a..d8ffa35 100644 --- a/src/card/CMakeLists.txt +++ b/src/card/CMakeLists.txt @@ -1,8 +1,8 @@ ADD_SUBDIRECTORY(base) -ADD_SUBDIRECTORY(drivers) -IF(NOT ANDROID AND NOT IOS) +IF(DESKTOP) ADD_SUBDIRECTORY(pcsc) + ADD_SUBDIRECTORY(drivers) ENDIF() IF(ANDROID) @@ -12,3 +12,5 @@ ENDIF() IF(LINUX OR ANDROID OR IOS) ADD_SUBDIRECTORY(bluetooth) ENDIF() + +ADD_SUBDIRECTORY(remote) diff --git a/src/card/base/Apdu.cpp b/src/card/base/Apdu.cpp index e2d102e..a94b869 100644 --- a/src/card/base/Apdu.cpp +++ b/src/card/base/Apdu.cpp @@ -24,7 +24,7 @@ Apdu::~Apdu() } -size_t Apdu::length() const +int Apdu::length() const { return mBuffer.size(); } @@ -48,7 +48,7 @@ bool CommandApdu::isExtendedLength() const // no data, short le: size == 5 // no data, extended le: size == 7, high order le byte == 0 // data, with/without le: high order size byte == 0 <=> extended data length - return mBuffer.size() > 5 && mBuffer.at(4) == static_cast(0x00); + return length() > 5 && mBuffer.at(4) == char(0x00); } @@ -84,10 +84,10 @@ CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteAr return; } - mBuffer.append(pCla); - mBuffer.append(pIns); - mBuffer.append(pP1); - mBuffer.append(pP2); + mBuffer += pCla; + mBuffer += pIns; + mBuffer += pP1; + mBuffer += pP2; // // according to ISO 7816 Part 4, chapter 5.1 @@ -96,16 +96,16 @@ CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteAr { if (CommandApdu::isExtendedLength(pData, pLe)) { - mBuffer.append(char(0x00)); - mBuffer.append(pData.size() >> 8 & 0xff); - mBuffer.append(pData.size() & 0xff); + mBuffer += char(0x00); + mBuffer += static_cast(pData.size() >> 8 & 0xff); + mBuffer += static_cast(pData.size() & 0xff); } else { - mBuffer.append(pData.size() & 0xff); + mBuffer += static_cast(pData.size() & 0xff); } - mBuffer.append(pData); + mBuffer += pData; } if (pLe > 0) @@ -114,11 +114,11 @@ CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteAr { if (pData.isEmpty()) { - mBuffer.append(char(0x00)); + mBuffer += char(0x00); } - mBuffer.append(pLe >> 8 & 0xff); + mBuffer += static_cast(pLe >> 8 & 0xff); } - mBuffer.append(pLe & 0xff); + mBuffer += static_cast(pLe & 0xff); } } @@ -130,19 +130,19 @@ CommandApdu::~CommandApdu() char CommandApdu::getCLA() const { - return mBuffer.size() > 0 ? mBuffer.at(0) : 0; + return length() > 0 ? mBuffer.at(0) : 0; } char CommandApdu::getINS() const { - return mBuffer.size() > 1 ? mBuffer.at(1) : 0; + return length() > 1 ? mBuffer.at(1) : 0; } char CommandApdu::getP1() const { - return mBuffer.size() > 2 ? mBuffer.at(2) : 0; + return length() > 2 ? mBuffer.at(2) : 0; } @@ -160,7 +160,7 @@ static inline int readLength(const QByteArray& pByteArray, int pOffset) int CommandApdu::getLc() const { - if (mBuffer.size() <= 5) + if (length() <= 5) { return 0; } @@ -170,7 +170,7 @@ int CommandApdu::getLc() const return static_cast(mBuffer.at(4)); } // extended length command apdu - if (mBuffer.size() <= 6) + if (length() <= 6) { qCCritical(card) << "Cannot determine Lc, returning 0"; return 0; @@ -187,7 +187,7 @@ int CommandApdu::getLe() const // no data (so lc==0): we have 4 bytes header and the le field is prefixed with 0 byte // with data: we have 4 bytes header, lc field encoded in 3 bytes and the data field int offset = lc == 0 ? 5 : 7 + lc; - if (mBuffer.size() < offset + 2) + if (length() < offset + 2) { return 0; } @@ -197,7 +197,7 @@ int CommandApdu::getLe() const // no data (so lc==0): we have 4 bytes header // with data: we have 4 bytes header, lc field encoded in 1 byte and the data field int offset = lc == 0 ? 4 : 5 + lc; - if (mBuffer.size() < offset + 1) + if (length() < offset + 1) { return 0; } @@ -253,37 +253,38 @@ QByteArray ResponseApdu::getData() const int ResponseApdu::getDataLength() const { - return mBuffer.size() - 2; + return length() - 2; } StatusCode ResponseApdu::getReturnCode() const { - unsigned int sw1 = getSW1(); - unsigned int sw2 = getSW2(); - return StatusCode(((sw1 << 8) & 0xff00) + (sw2 & 0xff)); + // avoid "undefined-behavior" with explicit "uint" variable + const uint sw1 = static_cast(getSW1()); + const uchar sw2 = static_cast(getSW2()); + return StatusCode((sw1 << 8) + sw2); } -int ResponseApdu::getSW1() const +char ResponseApdu::getSW1() const { - if (mBuffer.size() < 2) + if (length() < 2) { qCCritical(card) << "Buffer too short, returning 0"; return 0; } - return mBuffer.at(mBuffer.size() - 2); + return mBuffer.at(length() - 2); } -int ResponseApdu::getSW2() const +char ResponseApdu::getSW2() const { - if (mBuffer.size() < 1) + if (length() < 1) { qCCritical(card) << "Buffer too short, returning 0"; return 0; } - return mBuffer.at(mBuffer.size() - 1); + return mBuffer.at(length() - 1); } diff --git a/src/card/base/Apdu.h b/src/card/base/Apdu.h index 5ab5e6c..ee7885f 100644 --- a/src/card/base/Apdu.h +++ b/src/card/base/Apdu.h @@ -78,7 +78,7 @@ class Apdu static const char CLA_COMMAND_CHAINING = 0x10; static const char CLA_SECURE_MESSAGING = 0x0c; const QByteArray& getBuffer() const; - size_t length() const; + int length() const; }; class CommandApdu @@ -117,8 +117,8 @@ class ResponseApdu QByteArray getData() const; int getDataLength() const; StatusCode getReturnCode() const; - int getSW1() const; - int getSW2() const; + char getSW1() const; + char getSW2() const; }; } /* namespace governikus */ diff --git a/src/card/base/Card.cpp b/src/card/base/Card.cpp index b113987..b8ef63e 100644 --- a/src/card/base/Card.cpp +++ b/src/card/base/Card.cpp @@ -22,8 +22,28 @@ Card::~Card() } -ReturnCode Card::destroyPaceChannel() +CardReturnCode Card::establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) +{ + Q_UNUSED(pPinId); + Q_UNUSED(pChat); + Q_UNUSED(pCertificateDescription); + Q_UNUSED(pChannelOutput); + Q_UNUSED(pTimeoutSeconds); + qCWarning(card) << "Establishment of PACE channel not supported"; + return CardReturnCode::COMMAND_FAILED; +} + + +CardReturnCode Card::destroyPaceChannel() { qCWarning(card) << "Destruction of PACE channel not supported"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; +} + + +CardReturnCode Card::setEidPin(quint8 pTimeoutSeconds) +{ + Q_UNUSED(pTimeoutSeconds); + qCWarning(card) << "Setting eID PIN is not supported"; + return CardReturnCode::COMMAND_FAILED; } diff --git a/src/card/base/Card.h b/src/card/base/Card.h index 2b0b32f..479fa24 100644 --- a/src/card/base/Card.h +++ b/src/card/base/Card.h @@ -9,9 +9,9 @@ #pragma once #include "Apdu.h" +#include "CardReturnCode.h" #include "Commands.h" #include "EstablishPACEChannel.h" -#include "ReturnCode.h" #include "SmartCardDefinitions.h" #include @@ -33,12 +33,12 @@ class Card /*! * Establish a connection to the smart card */ - virtual ReturnCode connect() = 0; + virtual CardReturnCode connect() = 0; /*! * Destroys the previously established connection to the smart card */ - virtual ReturnCode disconnect() = 0; + virtual CardReturnCode disconnect() = 0; /*! * Is the smart card connected, i.e. has a connection successfully been established? @@ -50,22 +50,22 @@ class Card * The command APDU buffer is transmitted to the card. * The response APDU buffer is filled with the data returned from the card. */ - virtual ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) = 0; + virtual CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) = 0; /*! * Establishes a PACE channel, i.e. the corresponding reader is no basic reader. */ - virtual ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds = 60) = 0; + virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds = 60); /*! * Destroys an existing PACE channel, i.e. the corresponding reader is no basic reader. */ - virtual ReturnCode destroyPaceChannel(); + virtual CardReturnCode destroyPaceChannel(); /*! * Sets a new eID PIN, i.e. the corresponding reader is no basic reader. */ - virtual ReturnCode setEidPin(unsigned int pTimeoutSeconds) = 0; + virtual CardReturnCode setEidPin(quint8 pTimeoutSeconds); }; diff --git a/src/card/base/CardConnection.cpp b/src/card/base/CardConnection.cpp index a1c10cf..092cd65 100644 --- a/src/card/base/CardConnection.cpp +++ b/src/card/base/CardConnection.cpp @@ -7,7 +7,7 @@ using namespace governikus; -CardConnection::CardConnection(QSharedPointer pCardConnectionWorker) +CardConnection::CardConnection(const QSharedPointer& pCardConnectionWorker) : QObject() , mCardConnectionWorker(pCardConnectionWorker) , mReaderInfo() @@ -47,7 +47,7 @@ EstablishPaceChannelCommand* CardConnection::createEstablishPaceChannelCommand(P } -SetEidPinCommand* CardConnection::createSetEidPinCommand(const QString& pNewPin, uint pTimeoutSeconds) +SetEidPinCommand* CardConnection::createSetEidPinCommand(const QString& pNewPin, quint8 pTimeoutSeconds) { return new SetEidPinCommand(mCardConnectionWorker, pNewPin, pTimeoutSeconds); } diff --git a/src/card/base/CardConnection.h b/src/card/base/CardConnection.h index b0bef09..fe5ed4a 100644 --- a/src/card/base/CardConnection.h +++ b/src/card/base/CardConnection.h @@ -53,7 +53,7 @@ class CardConnection UnblockPinCommand* createUnblockPinCommand(const QString& pPuk); EstablishPaceChannelCommand* createEstablishPaceChannelCommand(PACE_PIN_ID pPacePinId, const QString& pPacePin, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription); - SetEidPinCommand* createSetEidPinCommand(const QString& pNewPin, uint pTimeoutSeconds = 60); + SetEidPinCommand* createSetEidPinCommand(const QString& pNewPin, quint8 pTimeoutSeconds); DestroyPaceChannelCommand* createDestroyPaceChannelCommand(); DidAuthenticateEAC1Command* createDidAuthenticateEAC1Command(); @@ -87,7 +87,7 @@ class CardConnection void onReaderInfoChanged(const ReaderInfo& pReaderInfo); public: - CardConnection(QSharedPointer pCardConnectionWorker); + CardConnection(const QSharedPointer& pCardConnectionWorker); /*! * Destroys the CardConnection and disconnects from the card. @@ -144,7 +144,7 @@ class CardConnection template QMetaObject::Connection callSetEidPinCommand(const typename QtPrivate::FunctionPointer::Object* pReceiver, T pFunc, const QString& pNewPin, - uint pTimeoutSeconds = 60) + quint8 pTimeoutSeconds = 60) { auto command = createSetEidPinCommand(pNewPin, pTimeoutSeconds); return call(command, pReceiver, pFunc); diff --git a/src/card/base/CardConnectionWorker.cpp b/src/card/base/CardConnectionWorker.cpp index 5b6315e..6962392 100644 --- a/src/card/base/CardConnectionWorker.cpp +++ b/src/card/base/CardConnectionWorker.cpp @@ -65,21 +65,21 @@ void CardConnectionWorker::onReaderInfoChanged(const QString& pReaderName) } -ReturnCode CardConnectionWorker::transmit(const CommandApdu& pCommandApdu, ResponseApdu& pResponseApdu) +CardReturnCode CardConnectionWorker::transmit(const CommandApdu& pCommandApdu, ResponseApdu& pResponseApdu) { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } if (mSecureMessaging) { CommandApdu securedCommandApdu = mSecureMessaging->encrypt(pCommandApdu); ResponseApdu securedResponseApdu; - ReturnCode returnCode = mReader->getCard()->transmit(securedCommandApdu, securedResponseApdu); + CardReturnCode returnCode = mReader->getCard()->transmit(securedCommandApdu, securedResponseApdu); if (!mSecureMessaging->decrypt(securedResponseApdu, pResponseApdu)) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } return returnCode; } @@ -87,35 +87,35 @@ ReturnCode CardConnectionWorker::transmit(const CommandApdu& pCommandApdu, Respo } -ReturnCode CardConnectionWorker::readFile(const FileRef& pFileRef, QByteArray& pFileContent) +CardReturnCode CardConnectionWorker::readFile(const FileRef& pFileRef, QByteArray& pFileContent) { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } ResponseApdu selectRes; CommandApdu select = SelectBuilder(pFileRef).build(); - ReturnCode returnCode = transmit(select, selectRes); - if (returnCode != ReturnCode::OK || selectRes.getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = transmit(select, selectRes); + if (returnCode != CardReturnCode::OK || selectRes.getReturnCode() != StatusCode::SUCCESS) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } while (true) { ResponseApdu res; - ReadBinaryBuilder rb(pFileContent.count(), 0xff); + ReadBinaryBuilder rb(static_cast(pFileContent.count()), 0xff); returnCode = transmit(rb.build(), res); - if (returnCode != ReturnCode::OK) + if (returnCode != CardReturnCode::OK) { break; } - pFileContent.append(res.getData()); + pFileContent += res.getData(); if (res.getData().size() != 0xff && res.getReturnCode() == StatusCode::END_OF_FILE) { - return ReturnCode::OK; + return CardReturnCode::OK; } if (res.getReturnCode() != StatusCode::SUCCESS) { @@ -123,7 +123,7 @@ ReturnCode CardConnectionWorker::readFile(const FileRef& pFileRef, QByteArray& p } } - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } @@ -139,7 +139,7 @@ bool CardConnectionWorker::stopSecureMessaging() } -ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPinValue, EstablishPACEChannelOutput& pChannelOutput) { @@ -147,7 +147,7 @@ ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, } -ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPinValue, const QByteArray& pChat, const QByteArray& pCertificateDescription, @@ -155,9 +155,9 @@ ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } - ReturnCode returnCode; + CardReturnCode returnCode; qCInfo(support) << "Starting PACE for" << pPinId; if (mReader->getReaderInfo().isBasicReader()) @@ -167,13 +167,13 @@ ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, paceHandler.setChat(pChat); returnCode = paceHandler.establishPaceChannel(pPinId, pPinValue); - if (returnCode == ReturnCode::OK) + if (returnCode == CardReturnCode::OK) { pChannelOutput.setCarCurr(paceHandler.getCarCurr()); pChannelOutput.setCarPrev(paceHandler.getCarPrev()); pChannelOutput.setIdIcc(paceHandler.getIdIcc()); pChannelOutput.setEfCardAccess(getEfCardAccess()->getContentBytes()); - pChannelOutput.setPaceReturnCode(ReturnCode::OK); + pChannelOutput.setPaceReturnCode(CardReturnCode::OK); mSecureMessaging.reset(new SecureMessaging(paceHandler.getPaceProtocol(), paceHandler.getEncryptionKey(), paceHandler.getMacKey())); } } @@ -189,11 +189,11 @@ ReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, } -ReturnCode CardConnectionWorker::destroyPaceChannel() +CardReturnCode CardConnectionWorker::destroyPaceChannel() { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } qCInfo(support) << "Destroying PACE channel"; @@ -211,11 +211,11 @@ ReturnCode CardConnectionWorker::destroyPaceChannel() } -ReturnCode CardConnectionWorker::setEidPin(const QString& pNewPin, unsigned int pTimeoutSeconds) +CardReturnCode CardConnectionWorker::setEidPin(const QString& pNewPin, quint8 pTimeoutSeconds) { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } if (mReader->getReaderInfo().isBasicReader()) @@ -223,12 +223,12 @@ ReturnCode CardConnectionWorker::setEidPin(const QString& pNewPin, unsigned int Q_ASSERT(!pNewPin.isEmpty()); ResetRetryCounterBuilder commandBuilder(pNewPin.toUtf8()); ResponseApdu response; - if (transmit(commandBuilder.build(), response) != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + if (transmit(commandBuilder.build(), response) != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "Modify PIN failed"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } - return ReturnCode::OK; + return CardReturnCode::OK; } else { @@ -238,11 +238,11 @@ ReturnCode CardConnectionWorker::setEidPin(const QString& pNewPin, unsigned int } -ReturnCode CardConnectionWorker::updateRetryCounter() +CardReturnCode CardConnectionWorker::updateRetryCounter() { if (!hasCard()) { - return ReturnCode::NO_CARD; + return CardReturnCode::CARD_NOT_FOUND; } return mReader->updateRetryCounter(sharedFromThis()); } diff --git a/src/card/base/CardConnectionWorker.h b/src/card/base/CardConnectionWorker.h index 3a85c7e..17a9b9e 100644 --- a/src/card/base/CardConnectionWorker.h +++ b/src/card/base/CardConnectionWorker.h @@ -7,11 +7,11 @@ #pragma once #include "Apdu.h" +#include "CardReturnCode.h" #include "Commands.h" #include "EstablishPACEChannel.h" #include "FileRef.h" #include "Reader.h" -#include "ReturnCode.h" #include "SmartCardDefinitions.h" #include "asn1/SecurityInfos.h" #include "pace/SecureMessaging.h" @@ -32,7 +32,7 @@ class CardConnectionWorker Q_OBJECT /*! - * The connection talks to the Card hold by the Reader + * The connection talks to the Card held by the Reader */ QPointer mReader; @@ -64,18 +64,18 @@ class CardConnectionWorker Q_INVOKABLE ReaderInfo getReaderInfo() const; - virtual ReturnCode updateRetryCounter(); + virtual CardReturnCode updateRetryCounter(); - virtual ReturnCode readFile(const FileRef& pFileRef, QByteArray& pFileContent); + virtual CardReturnCode readFile(const FileRef& pFileRef, QByteArray& pFileContent); - virtual ReturnCode transmit(const CommandApdu& pCommandApdu, ResponseApdu& pResponseApdu); + virtual CardReturnCode transmit(const CommandApdu& pCommandApdu, ResponseApdu& pResponseApdu); /*! * Performs PACE and establishes a PACE channel. * If the Reader is a basic reader and the PACE channel is successfully established, the subsequent transmits will be secured using, secure messaging. * I. e., a secure messaging channel is established. */ - virtual ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, + virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPinValue, EstablishPACEChannelOutput& pChannelOutput); @@ -84,7 +84,7 @@ class CardConnectionWorker * If the Reader is a basic reader and the PACE channel is successfully established, the subsequent transmits will be secured using, secure messaging. * I. e., a secure messaging channel is established. */ - virtual ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, + virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPinValue, const QByteArray& pChat, const QByteArray& pCertificateDescription, @@ -93,14 +93,14 @@ class CardConnectionWorker /*! * Destroys a previously established PACE channel. */ - virtual ReturnCode destroyPaceChannel(); + virtual CardReturnCode destroyPaceChannel(); /*! * Destroys an established secure messaging channel, if there is one. */ virtual bool stopSecureMessaging(); - virtual ReturnCode setEidPin(const QString& pNewPin, unsigned int pTimeoutSeconds); + virtual CardReturnCode setEidPin(const QString& pNewPin, quint8 pTimeoutSeconds); Q_SIGNALS: void fireRetryCounterPotentiallyChanged(); diff --git a/src/card/base/CardInfo.cpp b/src/card/base/CardInfo.cpp index b60e355..104c169 100644 --- a/src/card/base/CardInfo.cpp +++ b/src/card/base/CardInfo.cpp @@ -24,7 +24,6 @@ using namespace governikus; CardInfo::CardInfo(CardType pCardType, QSharedPointer pEfCardAccess, int pRetryCounter, bool pPinDeactivated) : mCardType(pCardType) , mEfCardAccess(pEfCardAccess) - , mSlotHandle(QString::fromLatin1(QByteArray::number(qrand()).toHex())) , mRetryCounter(pRetryCounter) , mPinDeactivated(pPinDeactivated) { @@ -43,12 +42,6 @@ QSharedPointer CardInfo::getEfCardAccess() const } -const QString& CardInfo::getSlotHandle() const -{ - return mSlotHandle; -} - - QString CardInfo::getEidApplicationPath() const { return mCardType == CardType::EID_CARD ? QStringLiteral("e80704007f00070302") : QString(); @@ -103,12 +96,12 @@ bool CardInfoFactory::isGermanEidCard(const QSharedPointer // 0. Select the master file CommandApdu command = SelectBuilder(FileRef::masterFile()).build(); ResponseApdu response; - ReturnCode returnCode = pCardConnectionWorker->transmit(command, response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = pCardConnectionWorker->transmit(command, response); + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "Cannot select MF"; - if (returnCode != ReturnCode::OK) + if (returnCode != CardReturnCode::OK) { qCDebug(card) << "CardConnectionWorker return code" << returnCode; } @@ -124,7 +117,7 @@ bool CardInfoFactory::isGermanEidCard(const QSharedPointer // 1. CL=00, INS=A4=SELECT, P1= 02, P2=0C, Lc=02, Data=2F00 (FI of EF.DIR), Le=absent command = SelectBuilder(FileRef::efDir()).build(); returnCode = pCardConnectionWorker->transmit(command, response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "Cannot select EF.DIR"; return false; @@ -133,7 +126,7 @@ bool CardInfoFactory::isGermanEidCard(const QSharedPointer // 2. CL=00, INS=B0=Read Binary, P1=00, P2=00 (no offset), Lc=00, Le=5A command = CommandApdu(QByteArray::fromHex("00B000005A")); returnCode = pCardConnectionWorker->transmit(command, response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "Cannot read EF.DIR"; return false; @@ -156,7 +149,7 @@ bool CardInfoFactory::isGermanEidCard(const QSharedPointer QSharedPointer CardInfoFactory::readEfCardAccess(const QSharedPointer& pCardConnectionWorker) { QByteArray efCardAccessBytes; - if (pCardConnectionWorker->readFile(FileRef::efCardAccess(), efCardAccessBytes) != ReturnCode::OK) + if (pCardConnectionWorker->readFile(FileRef::efCardAccess(), efCardAccessBytes) != CardReturnCode::OK) { qCCritical(card) << "Error while reading EF.CardAccess: Cannot read EF.CardAccess"; return QSharedPointer(); @@ -177,7 +170,7 @@ bool CardInfoFactory::checkEfCardAccess(const QSharedPointer& pEfC * At least one PACEInfo must have standardized domain parameters */ bool containsStandardizedDomainParameters = false; - const auto& infos = pEfCardAccess->getSecurityInfos(); + const auto& infos = pEfCardAccess->getPACEInfos(); for (const auto& paceInfo : infos) { if (paceInfo->isStandardizedDomainParameters()) diff --git a/src/card/base/CardInfo.h b/src/card/base/CardInfo.h index 4d5d1cc..bca4191 100644 --- a/src/card/base/CardInfo.h +++ b/src/card/base/CardInfo.h @@ -29,7 +29,6 @@ class CardInfo { CardType mCardType; QSharedPointer mEfCardAccess; - QString mSlotHandle; int mRetryCounter; bool mPinDeactivated; @@ -40,12 +39,13 @@ class CardInfo QSharedPointer getEfCardAccess() const; - const QString& getSlotHandle() const; - QString getEidApplicationPath() const; int getRetryCounter() const; + /*! + * The online identification function has not been activated by the competent authority. + */ bool isPinDeactivated() const; friend class Reader; diff --git a/src/card/base/Commands.cpp b/src/card/base/Commands.cpp index 8870b63..231cf59 100644 --- a/src/card/base/Commands.cpp +++ b/src/card/base/Commands.cpp @@ -5,7 +5,10 @@ */ #include "Commands.h" + #include "FileRef.h" +#include "SecureMessagingResponse.h" +#include "asn1/ASN1Util.h" #include @@ -14,39 +17,6 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -namespace -{ - -QByteArray buildAsn1Structure(char pTag, const QByteArray& pData, bool pAlreadyAsn1Encoded = false) -{ - if (pAlreadyAsn1Encoded) - { - return pData; - } - QByteArray result; - result.append(pTag); - result.append(static_cast(pData.size())); - result.append(pData); - return result; -} - - -QByteArray buildAsn1Structure(const char* const pTag, const QByteArray& pData, bool pAlreadyAsn1Encoded = false) -{ - if (pAlreadyAsn1Encoded) - { - return pData; - } - QByteArray result; - result.append(pTag); - result.append(static_cast(pData.size())); - result.append(pData); - return result; -} - - -} - /* * The base class CommandApduBuilder @@ -137,24 +107,23 @@ MSEBuilder::MSEBuilder(P1 p1, P2 p2) } -void MSEBuilder::setAuxiliaryData(const QByteArray& pData, bool pAlreadyAsn1Encoded) +void MSEBuilder::setAuxiliaryData(const QByteArray& pData) { - static const char TAG_AUXILIARY_DATA = 0x67; - mAuxiliaryData = buildAsn1Structure(TAG_AUXILIARY_DATA, pData, pAlreadyAsn1Encoded); + mAuxiliaryData = pData; } void MSEBuilder::setOid(const QByteArray& pData) { static const char TAG_OID = char(0x80); - mOid = buildAsn1Structure(TAG_OID, pData); + mOid = Asn1Util::encode(TAG_OID, pData); } void MSEBuilder::setPublicKey(const QByteArray& pData) { static const char TAG_PUBLIC_KEY = char(0x83); - mPublicKey = buildAsn1Structure(TAG_PUBLIC_KEY, pData); + mPublicKey = Asn1Util::encode(TAG_PUBLIC_KEY, pData); } @@ -162,29 +131,28 @@ void MSEBuilder::setPublicKey(PACE_PIN_ID pPin) { static const char TAG_PUBLIC_KEY = char(0x83); QByteArray data; - data.append(static_cast(pPin)); - mPublicKey = buildAsn1Structure(TAG_PUBLIC_KEY, data); + data += Enum::getValue(pPin); + mPublicKey = Asn1Util::encode(TAG_PUBLIC_KEY, data); } void MSEBuilder::setPrivateKey(const QByteArray& pData) { static const char TAG_PRIVATE_KEY = char(0x84); - mPrivateKey = buildAsn1Structure(TAG_PRIVATE_KEY, pData); + mPrivateKey = Asn1Util::encode(TAG_PRIVATE_KEY, pData); } void MSEBuilder::setEphemeralPublicKey(const QByteArray& pData) { static const char TAG_EPHEMERAL_PUBLIC_KEY = char(0x91); - mEphemeralPublicKey = buildAsn1Structure(TAG_EPHEMERAL_PUBLIC_KEY, pData); + mEphemeralPublicKey = Asn1Util::encode(TAG_EPHEMERAL_PUBLIC_KEY, pData); } -void MSEBuilder::setChat(const QByteArray& pData, bool pAlreadyAsn1Encoded) +void MSEBuilder::setChat(const QByteArray& pData) { - static const char* const TAG_CHAT = "\x7F\x4C"; - mChat = buildAsn1Structure(TAG_CHAT, pData, pAlreadyAsn1Encoded); + mChat = pData; } @@ -193,12 +161,12 @@ CommandApdu MSEBuilder::build() static const char INS = 0x22; QByteArray data; - data.append(mOid); - data.append(mPublicKey); - data.append(mPrivateKey); - data.append(mAuxiliaryData); - data.append(mEphemeralPublicKey); - data.append(mChat); + data += mOid; + data += mPublicKey; + data += mPrivateKey; + data += mAuxiliaryData; + data += mEphemeralPublicKey; + data += mChat; return CommandApdu(CommandApdu::CLA, INS, static_cast(mP1), static_cast(mP2), data); } @@ -217,17 +185,15 @@ PSOBuilder::PSOBuilder(P1 p1, P2 p2) } -void PSOBuilder::setCertificateBody(const QByteArray& pData, bool pAlreadyAsn1Encoded) +void PSOBuilder::setCertificateBody(const QByteArray& pData) { - static const char* const TAG_CERT_BODY = "\x7F\x4E"; - mCertificateBody = buildAsn1Structure(TAG_CERT_BODY, pData, pAlreadyAsn1Encoded); + mCertificateBody = pData; } -void PSOBuilder::setSignature(const QByteArray& pData, bool pAlreadyAsn1Encoded) +void PSOBuilder::setSignature(const QByteArray& pData) { - static const char* const TAG_SIGNATURE = "\x5F\x37"; - mSignature = buildAsn1Structure(TAG_SIGNATURE, pData, pAlreadyAsn1Encoded); + mSignature = pData; } @@ -236,8 +202,8 @@ CommandApdu PSOBuilder::build() static const int INS = 0x2a; QByteArray data; - data.append(mCertificateBody); - data.append(mSignature); + data += mCertificateBody; + data += mSignature; return CommandApdu(CommandApdu::CLA, INS, char(mP1), char(mP2), data); } @@ -283,28 +249,28 @@ GABuilder::GABuilder(char pClassByte) void GABuilder::setCaEphemeralPublicKey(const QByteArray& pData) { static const char TAG_EPHEMERAL_PUBLIC_KEY = char(0x80); - mCaEphemeralPublicKey = buildAsn1Structure(TAG_EPHEMERAL_PUBLIC_KEY, pData); + mCaEphemeralPublicKey = Asn1Util::encode(TAG_EPHEMERAL_PUBLIC_KEY, pData); } void GABuilder::setPaceMappingData(const QByteArray& pData) { static const char TAG_PACE_MAPPING_DATA = char(0x81); - mPaceMappingData = buildAsn1Structure(TAG_PACE_MAPPING_DATA, pData); + mPaceMappingData = Asn1Util::encode(TAG_PACE_MAPPING_DATA, pData); } void GABuilder::setPaceEphemeralPublicKey(const QByteArray& pData) { static const char TAG_PACE_EPHEMERAL_PUBLIC_KEY = char(0x83); - mPaceEphemeralPublicKey = buildAsn1Structure(TAG_PACE_EPHEMERAL_PUBLIC_KEY, pData); + mPaceEphemeralPublicKey = Asn1Util::encode(TAG_PACE_EPHEMERAL_PUBLIC_KEY, pData); } void GABuilder::setPaceAuthenticationToken(const QByteArray& pData) { static const char TAG_PACE_AUTHENTICATION_TOKEN = char(0x85); - mPaceAuthenticationToken = buildAsn1Structure(TAG_PACE_AUTHENTICATION_TOKEN, pData); + mPaceAuthenticationToken = Asn1Util::encode(TAG_PACE_AUTHENTICATION_TOKEN, pData); } @@ -316,27 +282,27 @@ CommandApdu GABuilder::build() QByteArray data; if (!mCaEphemeralPublicKey.isNull()) { - data.append(mCaEphemeralPublicKey); + data += mCaEphemeralPublicKey; } else if (!mPaceMappingData.isNull()) { - data.append(mPaceMappingData); + data += mPaceMappingData; } else if (!mPaceEphemeralPublicKey.isNull()) { - data.append(mPaceEphemeralPublicKey); + data += mPaceEphemeralPublicKey; } else if (!mPaceAuthenticationToken.isNull()) { - data.append(mPaceAuthenticationToken); + data += mPaceAuthenticationToken; } - data = buildAsn1Structure(TAG_DYNAMIC_AUTHENTICATION_DATA, data); + data = Asn1Util::encode(TAG_DYNAMIC_AUTHENTICATION_DATA, data); return CommandApdu(mClassByte, INS, 0, 0, data, Apdu::SHORT_MAX_LE); } -ReadBinaryBuilder::ReadBinaryBuilder(uint pOffset, uint pLe) +ReadBinaryBuilder::ReadBinaryBuilder(uint pOffset, int pLe) : CommandApduBuilder() , mOffset(pOffset) , mLe(pLe) @@ -347,7 +313,7 @@ ReadBinaryBuilder::ReadBinaryBuilder(uint pOffset, uint pLe) CommandApdu ReadBinaryBuilder::build() { static const char INS = char(0xB0); - return CommandApdu(CommandApdu::CLA, INS, (mOffset & 0xff00) >> 8, mOffset & 0xff, QByteArray(), mLe); + return CommandApdu(CommandApdu::CLA, INS, static_cast((mOffset & 0xff00) >> 8), static_cast(mOffset & 0xff), QByteArray(), mLe); } @@ -360,87 +326,84 @@ ResetRetryCounterBuilder::ResetRetryCounterBuilder(const QByteArray& pPin) CommandApdu ResetRetryCounterBuilder::build() { - static const int INS = 0x2c; + static const char INS = 0x2c; // P1: 2 (change), 3 (unblock) - int p1 = mPin.isNull() ? 3 : 2; + char p1 = mPin.isNull() ? 3 : 2; // P2: 3 (PIN) (2 (CAN) -- not used) // data: new PIN, when changing return CommandApdu(CommandApdu::CLA, INS, p1, 3, mPin); } -QByteArray PinModifyBuilder::createChangeEidPinCommandData(unsigned int pTimeoutSeconds) const +QByteArray PinModifyBuilder::createChangeEidPinCommandData(quint8 pTimeoutSeconds) const { // According to ISO-7816-4, 7.5.10 RESET RETRY COUNTER command - QByteArray abData = QByteArray().append("00").append("2C").append("02").append("03"); + QByteArray abData = QByteArrayLiteral("002C0203"); return createCommandData(pTimeoutSeconds, 0x00, 0x01, 0x02, QByteArray::fromHex(abData)); } -QByteArray PinModifyBuilder::createCommandData(unsigned int pTimeoutSeconds, char pMsgIndex1, char pMsgIndex2, char pMsgIndex3, const QByteArray& pAbData) const +QByteArray PinModifyBuilder::createCommandData(quint8 pTimeoutSeconds, char pMsgIndex1, char pMsgIndex2, char pMsgIndex3, const QByteArray& pAbData) const { - if (pTimeoutSeconds > 255) - { - qCWarning(card) << "Timeout must fit in one byte, set to 255"; - pTimeoutSeconds = 255; - } - // as defined in PC/SC, Part 10 "IFDs with Secure PIN Entry Capabilities" QByteArray command; // bTimeOut (timeout in seconds) - command.append(pTimeoutSeconds) + command += static_cast(pTimeoutSeconds); // bTimeOut2 (timeout in seconds after first key pressed) - .append(pTimeoutSeconds) + command += static_cast(pTimeoutSeconds); // bmFormatString (PIN format): system unit is bytes (0x80), ASCII format (0x02) - .append(char(0x82)) + command += char(0x82); // bmPINBlockString (PIN block size and length info): PIN not in APDU command - .append(static_cast(0)) + command += char(0x00); // bmPINLengthFormat (format of PIN length field in APDU command): PIN not in APDU command - .append(static_cast(0)) + command += char(0x00); // bInsertionOffsetOld (insertion position offset for old PIN) - .append(static_cast(0)) + command += char(0x00); // bInsertionOffsetNew BYTE (insertion position offset for new PIN) - .append(static_cast(0)) + command += char(0x00); // wPINMaxExtraDigit USHORT (0xXXYY, min (XX) and max (length) of new PIN) - .append(0x06).append(0x06) + command += 0x06; + command += 0x06; // bConfirmPIN (PIN confirmation options): confirm new PIN (0x01) - .append(0x01) + command += 0x01; // bEntryValidationCondition (new PIN validation options): validation key pressed (0x02) - .append(0x02) + command += 0x02; // bNumberMessage (number of display messages to be sent) - .append(0x02) + command += 0x02; // wLangId (language ID for display messages): German (0x0407) - .append(0x07).append(0x04) + command += 0x07; + command += 0x04; // bMsgIndex1 (index (into reader table) of first message to display) - .append(pMsgIndex1) + command += pMsgIndex1; // bMsgIndex2 (index (into reader table) of second message to display) - .append(pMsgIndex2) + command += pMsgIndex2; // bMsgIndex3 (index (into reader table) of third message to display) - .append(pMsgIndex3) + command += pMsgIndex3; // bTeoPrologue (T1 only: I-block prologue field to use): fill with 0 - .append(static_cast(0)).append(static_cast(0)).append(static_cast(0)); + command += char(0x00); + command += char(0x00); + command += char(0x00); - if (pAbData.size() > 255) + if (pAbData.size() > 0xFF) { - qCCritical(card) << "abData sizes greater than 255 currently not supported."; + qCCritical(card) << "abData size bigger than 0xFF currently not supported."; + Q_ASSERT(pAbData.size() <= 0xFF); + return QByteArray(); } // ulDataLength (length of the APDU to be sent to ICC) - command.append(pAbData.size()).append(static_cast(0x00)).append(static_cast(0x00)).append(static_cast(0x00)) - .append(pAbData); + command += static_cast(pAbData.size()); + command += char(0x00); + command += char(0x00); + command += char(0x00); + command += pAbData; return command; } -CommandApdu PinModifyBuilder::createCommandDataCcid(unsigned int pTimeoutSeconds) const +CommandApdu PinModifyBuilder::createCommandDataCcid(quint8 pTimeoutSeconds) const { - if (pTimeoutSeconds > 255) - { - qCWarning(card) << "Timeout must fit in one byte, set to 255"; - pTimeoutSeconds = 255; - } - // According to TR-03119 the command data has to be the full PC_to_RDR_Secure structure // According to Reiner SCT the firmware is implemented in such a way, that the command // data is expected as abPINOperationDataStucture @@ -449,43 +412,47 @@ CommandApdu PinModifyBuilder::createCommandDataCcid(unsigned int pTimeoutSeconds QByteArray abPINDataStructure; // bTimeOut (timeout in seconds) - abPINDataStructure.append(pTimeoutSeconds); + abPINDataStructure += static_cast(pTimeoutSeconds); // bmFormatString (PIN format): system unit is bytes (0x80), ASCII format (0x02) - abPINDataStructure.append(char(0x82)); + abPINDataStructure += char(0x82); // bmPINBlockString (PIN block size and length info): PIN not in APDU command - abPINDataStructure.append(static_cast(0)); + abPINDataStructure += char(0x00); // bmPINLengthFormat (format of PIN length field in APDU command): PIN not in APDU command - abPINDataStructure.append(static_cast(0)); + abPINDataStructure += char(0x00); // bInsertionOffsetOld (insertion position offset for old PIN) - abPINDataStructure.append(static_cast(0)); + abPINDataStructure += char(0x00); // bInsertionOffsetNew BYTE (insertion position offset for new PIN) - abPINDataStructure.append(static_cast(0)); + abPINDataStructure += char(0x00); // wPINMaxExtraDigit USHORT (0xXXYY, min (XX) and max (length) of new PIN) - abPINDataStructure.append(0x06).append(0x06); + abPINDataStructure += char(0x06); + abPINDataStructure += char(0x06); // bConfirmPIN (PIN confirmation options): confirm new PIN (0x01) - abPINDataStructure.append(0x01); + abPINDataStructure += char(0x01); // bEntryValidationCondition (new PIN validation options): validation key pressed (0x02) - abPINDataStructure.append(0x02); + abPINDataStructure += char(0x02); // bNumberMessage (number of display messages to be sent) - abPINDataStructure.append(0x02); + abPINDataStructure += char(0x02); // wLangId (language ID for display messages): German (0x0407) - abPINDataStructure.append(0x07).append(0x04); + abPINDataStructure += char(0x07); + abPINDataStructure += char(0x04); // bMsgIndex1 (index (into reader table) of first message to display) - abPINDataStructure.append(0x01); + abPINDataStructure += char(0x01); // bMsgIndex2 (index (into reader table) of second message to display) - abPINDataStructure.append(0x02); + abPINDataStructure += char(0x02); // bMsgIndex3 (index (into reader table) of third message to display) - abPINDataStructure.append(static_cast(0)); + abPINDataStructure += char(0x00); // bTeoPrologue (T1 only: I-block prologue field to use): fill with 0 - abPINDataStructure.append(static_cast(0)).append(static_cast(0)).append(static_cast(0)); + abPINDataStructure += char(0x00); + abPINDataStructure += char(0x00); + abPINDataStructure += char(0x00); // abData (APDU to be sent to ICC) - abPINDataStructure.append(static_cast(0x00)) // CLA: command - .append(static_cast(0x2c)) // INS: Reset Retry Counter - .append(static_cast(0x02)) // P1: new PIN/CAN - .append(static_cast(0x03)); // P2: PIN + abPINDataStructure += char(0x00); // CLA: command + abPINDataStructure += char(0x2c); // INS: Reset Retry Counter + abPINDataStructure += char(0x02); // P1: new PIN/CAN + abPINDataStructure += char(0x03); // P2: PIN QByteArray abPINOperationDataStucture; - abPINOperationDataStucture.append(0x01); //bPINOperation - abPINOperationDataStucture.append(abPINDataStructure); //abPINDataStructure + abPINOperationDataStucture += char(0x01); //bPINOperation + abPINOperationDataStucture += abPINDataStructure; //abPINDataStructure // boxing command according to TR-03119 return CommandApdu(char(0xFF), char(0x9A), 0x04, 0x10, abPINOperationDataStucture); @@ -496,7 +463,7 @@ void PinModifyOutput::parse(const QByteArray& pData) { if (pData.size() != 2) { - mReturnCode = ReturnCode::UNKNOWN; + mReturnCode = CardReturnCode::UNKNOWN; } const int errorCode = static_cast(pData.at(0)) << 8 | static_cast(pData.at(1)); @@ -504,42 +471,42 @@ void PinModifyOutput::parse(const QByteArray& pData) { case 0x6400: // operation timed out - mReturnCode = ReturnCode::TIME_OUT; + mReturnCode = CardReturnCode::INPUT_TIME_OUT; break; case 0x6401: // operation canceled by "Cancel" button - mReturnCode = ReturnCode::CANCELLATION_BY_USER; + mReturnCode = CardReturnCode::CANCELLATION_BY_USER; break; case 0x6402: // the two new PIN entries don't match - mReturnCode = ReturnCode::NEW_PINS_DONT_MATCH; + mReturnCode = CardReturnCode::NEW_PIN_MISMATCH; break; case 0x6403: // entered PIN too short/long - mReturnCode = ReturnCode::NEW_PIN_TOO_SHORT_OR_LONG; + mReturnCode = CardReturnCode::NEW_PIN_INVALID_LENGTH; break; case 0x6b80: // invalid parameter in passed structure - mReturnCode = ReturnCode::COMMAND_FAILED; + mReturnCode = CardReturnCode::COMMAND_FAILED; break; case 0x6982: // terminal is not authorized to unblock or change the PIN - mReturnCode = ReturnCode::UNKNOWN; + mReturnCode = CardReturnCode::UNKNOWN; break; case 0x9000: // success - mReturnCode = ReturnCode::OK; + mReturnCode = CardReturnCode::OK; break; default: qCDebug(card) << "unknown error:" << pData.toHex(); - mReturnCode = ReturnCode::UNKNOWN; + mReturnCode = CardReturnCode::UNKNOWN; break; } } @@ -551,7 +518,7 @@ void PinModifyOutput::parseFromCcid(const QByteArray& pData) } -ReturnCode PinModifyOutput::getReturnCode() const +CardReturnCode PinModifyOutput::getReturnCode() const { return mReturnCode; } diff --git a/src/card/base/Commands.h b/src/card/base/Commands.h index c349c56..c9f140e 100644 --- a/src/card/base/Commands.h +++ b/src/card/base/Commands.h @@ -5,16 +5,18 @@ #pragma once #include "Apdu.h" +#include "CardReturnCode.h" #include "FileRef.h" -#include "ReturnCode.h" #include "SmartCardDefinitions.h" #include "asn1/Chat.h" #include + namespace governikus { +// TODO: brauchen wir das wirklich? template QByteArray toBigEndian(T pDataToConvert) { uchar converted[sizeof(T)]; @@ -29,7 +31,7 @@ template QByteArray toBigEndian(T pDataToConvert) } } - return QByteArray().append(reinterpret_cast(&converted[position]), sizeof(T) - position); + return QByteArray(reinterpret_cast(&converted[position]), static_cast(sizeof(T) - position)); } @@ -51,12 +53,12 @@ class SelectBuilder const FileRef mFileRef; public: - enum class P1 : int + enum class P1 : char { SELECT_MF = 0x00, CHILD_DF = 0x01, CHILD_EF = 0x02, PARENT_DF = 0x03, APPLICATION_ID = 0x04, ABS_PATH = 0x08, REL_PATH = 0x09, }; - enum class P2 : int + enum class P2 : char { FCI = 0x00, FCP = 0x04, FMD = 0x08, NONE = 0x0c, }; @@ -97,13 +99,13 @@ class MSEBuilder }; MSEBuilder(P1 p1, P2 p2); - void setAuxiliaryData(const QByteArray& pData, bool pAlreadyAsn1Encoded = false); + void setAuxiliaryData(const QByteArray& pData); void setOid(const QByteArray& pData); void setPublicKey(const QByteArray& pData); void setPublicKey(PACE_PIN_ID pPin); void setPrivateKey(const QByteArray& pData); void setEphemeralPublicKey(const QByteArray& pData); - void setChat(const QByteArray& pData, bool pAlreadyAsn1Encoded); + void setChat(const QByteArray& pData); CommandApdu build() override; private: @@ -132,8 +134,8 @@ class PSOBuilder }; PSOBuilder(P1 p1, P2 p2); - void setCertificateBody(const QByteArray& pData, bool pAlreadyAsn1Encoded = false); - void setSignature(const QByteArray& pData, bool pAlreadyAsn1Encoded = false); + void setCertificateBody(const QByteArray& pData); + void setSignature(const QByteArray& pData); CommandApdu build() override; private: @@ -178,10 +180,11 @@ class ReadBinaryBuilder : public CommandApduBuilder { private: - uint mOffset, mLe; + uint mOffset; + int mLe; public: - ReadBinaryBuilder(uint pOffset, uint pLe); + ReadBinaryBuilder(uint pOffset, int pLe); CommandApdu build() override; }; @@ -200,26 +203,26 @@ class ResetRetryCounterBuilder class PinModifyBuilder { private: - QByteArray createCommandData(unsigned int pTimeoutSeconds, char pMsgIndex1, char pMsgIndex2, char pMsgIndex3, const QByteArray& pAbData) const; + QByteArray createCommandData(quint8 pTimeoutSeconds, char pMsgIndex1, char pMsgIndex2, char pMsgIndex3, const QByteArray& pAbData) const; public: - QByteArray createChangeEidPinCommandData(unsigned int pTimeoutSeconds) const; + QByteArray createChangeEidPinCommandData(quint8 pTimeoutSeconds) const; /** * According to DWG_Smart-Card_CCID_Rev110.pdf as mentioned in [TR-03110]. */ - CommandApdu createCommandDataCcid(unsigned int pTimeoutSeconds) const; + CommandApdu createCommandDataCcid(quint8 pTimeoutSeconds) const; }; class PinModifyOutput { private: - ReturnCode mReturnCode; + CardReturnCode mReturnCode; public: void parse(const QByteArray& pData); void parseFromCcid(const QByteArray& pData); - ReturnCode getReturnCode() const; + CardReturnCode getReturnCode() const; }; } /* namespace governikus */ diff --git a/src/card/base/DestroyPACEChannel.cpp b/src/card/base/DestroyPACEChannel.cpp index 8f8728f..e9ebdc8 100644 --- a/src/card/base/DestroyPACEChannel.cpp +++ b/src/card/base/DestroyPACEChannel.cpp @@ -12,15 +12,12 @@ QByteArray DestroyPACEChannelBuilder::createCommandData() { // Command data according to PC/SC Part 10 amendment 1.1 static const char INDEX_DESTROY_PACE_CHANNEL = 0x03; - QByteArray inputData; QByteArray commandData; - commandData.append(INDEX_DESTROY_PACE_CHANNEL); - commandData.append((inputData.size() >> 0) & 0xff); - commandData.append((inputData.size() >> 8) & 0xff); - commandData.append(inputData); + commandData += INDEX_DESTROY_PACE_CHANNEL; + commandData += char(0x00); + commandData += char(0x00); return commandData; - } diff --git a/src/card/base/EstablishPACEChannel.cpp b/src/card/base/EstablishPACEChannel.cpp index 268aae8..cf55921 100644 --- a/src/card/base/EstablishPACEChannel.cpp +++ b/src/card/base/EstablishPACEChannel.cpp @@ -94,21 +94,41 @@ QByteArray EstablishPACEChannelBuilder::createCommandData() static const char INDEX_ESTABLISH_PACE_CHANNEL = 0x02; QByteArray inputData; - inputData.append(static_cast(mPinId)); + inputData += static_cast(mPinId); - inputData.append(mChat.size()); - inputData.append(mChat); + if (mChat.size() > 0xFF) + { + qCCritical(card) << "Certificate Holder Authorization Template of size > 0xFF not supported"; + Q_ASSERT(mChat.size() <= 0xFF); + return QByteArray(); + } + inputData += static_cast(mChat.size()); + inputData += mChat; - inputData.append(static_cast(0)); - inputData.append((mCertificateDescription.size() >> 0) & 0xff); - inputData.append((mCertificateDescription.size() >> 8) & 0xff); - inputData.append(mCertificateDescription); + inputData += char(0x00); // length of PIN + + if (mCertificateDescription.size() > 0xFFFF) + { + qCCritical(card) << "Certificate Description of size > 0xFFFF not supported"; + Q_ASSERT(mCertificateDescription.size() <= 0xFFFF); + return QByteArray(); + } + inputData += static_cast((mCertificateDescription.size() >> 0) & 0xff); + inputData += static_cast((mCertificateDescription.size() >> 8) & 0xff); + inputData += mCertificateDescription; QByteArray commandData; - commandData.append(INDEX_ESTABLISH_PACE_CHANNEL); - commandData.append((inputData.size() >> 0) & 0xff); - commandData.append((inputData.size() >> 8) & 0xff); - commandData.append(inputData); + commandData += (INDEX_ESTABLISH_PACE_CHANNEL); + + if (inputData.size() > 0xFFFF) + { + qCCritical(card) << "InputData of size > 0xFFFF not supported"; + Q_ASSERT(inputData.size() <= 0xFFFF); + return QByteArray(); + } + commandData += static_cast((inputData.size() >> 0) & 0xff); + commandData += static_cast((inputData.size() >> 8) & 0xff); + commandData += inputData; return commandData; } @@ -125,7 +145,7 @@ CommandApdu EstablishPACEChannelBuilder::createCommandDataCcid() } if (!mCertificateDescription.isEmpty()) { - const unsigned char* unsignedCharPointer = reinterpret_cast(mCertificateDescription.data()); + const uchar* unsignedCharPointer = reinterpret_cast(mCertificateDescription.constData()); decodeAsn1Object(&channelInput->mCertificateDescription, &unsignedCharPointer, mCertificateDescription.size()); } @@ -137,7 +157,7 @@ CommandApdu EstablishPACEChannelBuilder::createCommandDataCcid() EstablishPACEChannelOutput::EstablishPACEChannelOutput() - : mPaceReturnCode(ReturnCode::UNKNOWN) + : mPaceReturnCode(CardReturnCode::UNKNOWN) , mEfCardAccess() , mCarCurr() , mCarPrev() @@ -146,7 +166,7 @@ EstablishPACEChannelOutput::EstablishPACEChannelOutput() } -ReturnCode EstablishPACEChannelOutput::getPaceReturnCode() const +CardReturnCode EstablishPACEChannelOutput::getPaceReturnCode() const { return mPaceReturnCode; } @@ -204,15 +224,15 @@ void EstablishPACEChannelOutput::setIdIcc(const QByteArray& pIDicc) } -void EstablishPACEChannelOutput::setPaceReturnCode(ReturnCode pPaceReturnCode) +void EstablishPACEChannelOutput::setPaceReturnCode(CardReturnCode pPaceReturnCode) { mPaceReturnCode = pPaceReturnCode; } -uint EstablishPACEChannelOutput::parseUSHORT(const QByteArray& pData, int pOffset) +int EstablishPACEChannelOutput::parseUSHORT(const QByteArray& pData, int pOffset) { - uint len = static_cast(pData.at(pOffset)); + int len = static_cast(pData.at(pOffset)); len += (static_cast(pData.at(pOffset + 1)) << 8); return len; } @@ -223,7 +243,7 @@ QByteArray EstablishPACEChannelOutput::reverse(const QByteArray& pArrayToReverse QByteArray reversed; for (int i = pArrayToReverse.size() - 1; i >= 0; i--) { - reversed.append(pArrayToReverse.at(i)); + reversed += (pArrayToReverse.at(i)); } return reversed; } @@ -239,13 +259,13 @@ void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PI quint32 paceReturnCode; QDataStream(reverse(pControlOutput.mid(0, 4))) >> paceReturnCode; mPaceReturnCode = parseReturnCode(paceReturnCode, pPinId); - if (mPaceReturnCode == ReturnCode::UNKNOWN) + if (mPaceReturnCode == CardReturnCode::UNKNOWN) { mPaceReturnCode = PersoSimWorkaround::parsingEstablishPACEChannelOutput(pControlOutput, pPinId); } - uint dataLength = parseUSHORT(pControlOutput.mid(4, 2), 0); - if (static_cast(pControlOutput.size()) < 6 + dataLength) + int dataLength = parseUSHORT(pControlOutput.mid(4, 2), 0); + if (pControlOutput.size() < 6 + dataLength) { qCWarning(card) << "Output of EstablishPACEChannel has wrong size"; return; @@ -263,10 +283,10 @@ void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PI //status += static_cast(pControlOutput.at(it)); ++it; - uint lengthCardAccess = parseUSHORT(pControlOutput, it); + int lengthCardAccess = parseUSHORT(pControlOutput, it); it += 2; - mEfCardAccess.append(pControlOutput.mid(it, lengthCardAccess)); + mEfCardAccess = (pControlOutput.mid(it, lengthCardAccess)); it += lengthCardAccess; if (it >= pControlOutput.size()) @@ -276,21 +296,21 @@ void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PI return; } - uint length_CARcurr = static_cast(pControlOutput.at(it)); + int length_CARcurr = pControlOutput.at(it); ++it; - mCarCurr.append(pControlOutput.mid(it, length_CARcurr)); + mCarCurr = (pControlOutput.mid(it, length_CARcurr)); it += length_CARcurr; qCDebug(card) << "mCarCurr" << mCarCurr; - uint length_CARprev = static_cast(pControlOutput.at(it)); + int length_CARprev = pControlOutput.at(it); ++it; - mCarPrev.append(pControlOutput.mid(it, length_CARprev)); + mCarPrev = (pControlOutput.mid(it, length_CARprev)); it += length_CARprev; qCDebug(card) << "mCarPrev" << mCarPrev; - uint length_IDicc = parseUSHORT(pControlOutput, it); + int length_IDicc = parseUSHORT(pControlOutput, it); it += 2; - mIdIcc.append(pControlOutput.mid(it, length_IDicc)); + mIdIcc = (pControlOutput.mid(it, length_IDicc)); } @@ -359,14 +379,14 @@ void EstablishPACEChannelOutput::parseFromCcid(const QByteArray& pOutput, PACE_P } -ReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId) +CardReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId) { // error codes from the reader switch (pPaceReturnCode) { case 0: // no error - return ReturnCode::OK; + return CardReturnCode::OK; case 0xd0000001: // Inconsistent lengths in input case 0xd0000002: // Unexpected data in input @@ -375,18 +395,18 @@ ReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, case 0xe0000002: // Unexpected or missing object in TLV response case 0xe0000003: // Unknown PIN-ID case 0xe0000006: // Wrong Authentication Token - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; // 0xf00663c2 -- invalid PIN? case 0xf0100001: // Communication abort (e.g. card removed during protocol) case 0xf0100002: // No card - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; case 0xf0200001: // Abort - return ReturnCode::CANCELLATION_BY_USER; + return CardReturnCode::CANCELLATION_BY_USER; case 0xf0200002: // Timeout - return ReturnCode::TIME_OUT; + return CardReturnCode::INPUT_TIME_OUT; } // Error codes wrapping error codes from the card. The format is 0xXXXXYYZZ, where XXXX identifies @@ -411,17 +431,17 @@ ReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, case PACE_PIN_ID::PACE_MRZ: // No separate error code (yet). case PACE_PIN_ID::PACE_CAN: - return ReturnCode::CAN_INVALID; + return CardReturnCode::INVALID_CAN; case PACE_PIN_ID::PACE_PIN: - return ReturnCode::PIN_INVALID; + return CardReturnCode::INVALID_PIN; case PACE_PIN_ID::PACE_PUK: - return ReturnCode::PUK_INVALID; + return CardReturnCode::INVALID_PUK; } } break; } - return ReturnCode::UNKNOWN; + return CardReturnCode::UNKNOWN; } diff --git a/src/card/base/EstablishPACEChannel.h b/src/card/base/EstablishPACEChannel.h index 75ad0a1..1f7e589 100644 --- a/src/card/base/EstablishPACEChannel.h +++ b/src/card/base/EstablishPACEChannel.h @@ -7,7 +7,7 @@ #pragma once #include "Apdu.h" -#include "ReturnCode.h" +#include "CardReturnCode.h" #include "SmartCardDefinitions.h" #include "asn1/ASN1TemplateUtil.h" #include "asn1/CertificateDescription.h" @@ -97,14 +97,14 @@ DECLARE_ASN1_OBJECT(ESTABLISHPACECHANNELOUTPUT) class EstablishPACEChannelOutput { private: - ReturnCode mPaceReturnCode; + CardReturnCode mPaceReturnCode; QByteArray mEfCardAccess; QByteArray mCarCurr; QByteArray mCarPrev; QByteArray mIdIcc; - static uint parseUSHORT(const QByteArray& pData, int pOffset); + static int parseUSHORT(const QByteArray& pData, int pOffset); static QByteArray reverse(const QByteArray& pArrayToReverse); @@ -121,8 +121,8 @@ class EstablishPACEChannelOutput */ void parseFromCcid(const QByteArray& pOutput, PACE_PIN_ID pPinId); - ReturnCode getPaceReturnCode() const; - void setPaceReturnCode(ReturnCode); + CardReturnCode getPaceReturnCode() const; + void setPaceReturnCode(CardReturnCode); QByteArray getEfCardAccess() const; void setEfCardAccess(const QByteArray&); @@ -136,7 +136,7 @@ class EstablishPACEChannelOutput QByteArray getCARprev() const; void setCarPrev(const QByteArray&); - static ReturnCode parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId); + static CardReturnCode parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId); }; diff --git a/src/card/base/ExtendedLengthApduSupportCode.cpp b/src/card/base/ExtendedLengthApduSupportCode.cpp new file mode 100644 index 0000000..3cde9c7 --- /dev/null +++ b/src/card/base/ExtendedLengthApduSupportCode.cpp @@ -0,0 +1,7 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "ExtendedLengthApduSupportCode.h" + +#include "moc_ExtendedLengthApduSupportCode.cpp" diff --git a/src/card/base/ExtendedLengthApduSupportCode.h b/src/card/base/ExtendedLengthApduSupportCode.h new file mode 100644 index 0000000..aa6422d --- /dev/null +++ b/src/card/base/ExtendedLengthApduSupportCode.h @@ -0,0 +1,18 @@ +/*! + * Definition of enum ExtendedLengthApduSupportCode. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "EnumHelper.h" + +namespace governikus +{ +defineEnumType(ExtendedLengthApduSupportCode, + UNKNOWN = -1, + NOT_SUPPORTED = 0, + SUPPORTED = 1, + INVALID = 2) +} diff --git a/src/card/base/FileRef.cpp b/src/card/base/FileRef.cpp index f77117c..421761e 100644 --- a/src/card/base/FileRef.cpp +++ b/src/card/base/FileRef.cpp @@ -11,13 +11,13 @@ using namespace governikus; FileRef FileRef::efDir() { - return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("2f00")); + return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("2f00")); } FileRef FileRef::masterFile() { - return FileRef(static_cast(SelectBuilder::P1::SELECT_MF), QByteArray::fromHex("3f00")); + return FileRef(static_cast(SelectBuilder::P1::SELECT_MF), QByteArray::fromHex("3f00")); } @@ -26,7 +26,7 @@ FileRef FileRef::efCardAccess() /* * File ID 011C specified in TR-03110-3 */ - return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("011c")); + return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("011c")); } @@ -35,17 +35,17 @@ FileRef FileRef::efCardSecurity() /* * File ID 011D specified in TR-03110-3 */ - return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("011d")); + return FileRef(static_cast(SelectBuilder::P1::CHILD_EF), QByteArray::fromHex("011d")); } FileRef FileRef::appESign() { - return FileRef(static_cast(SelectBuilder::P1::APPLICATION_ID), QByteArray::fromHex("a000000167455349474e")); + return FileRef(static_cast(SelectBuilder::P1::APPLICATION_ID), QByteArray::fromHex("a000000167455349474e")); } -FileRef::FileRef(int pType, const QByteArray& pPath) +FileRef::FileRef(char pType, const QByteArray& pPath) : type(pType) , path(pPath) { diff --git a/src/card/base/FileRef.h b/src/card/base/FileRef.h index e7a10a6..73c05fd 100644 --- a/src/card/base/FileRef.h +++ b/src/card/base/FileRef.h @@ -13,9 +13,9 @@ namespace governikus struct FileRef { - FileRef(int pType, const QByteArray& pPath); + FileRef(char pType, const QByteArray& pPath); - const int type; + const char type; const QByteArray path; static FileRef masterFile(); diff --git a/src/card/base/InputAPDUInfo.h b/src/card/base/InputAPDUInfo.h index 0cd1447..354b259 100644 --- a/src/card/base/InputAPDUInfo.h +++ b/src/card/base/InputAPDUInfo.h @@ -42,7 +42,7 @@ class InputAPDUInfo void addAcceptableStatusCode(const QByteArray& pStatusCode) { - mAcceptableStatusCodes.append(pStatusCode); + mAcceptableStatusCodes += pStatusCode; } diff --git a/src/card/base/PersoSimWorkaround.h b/src/card/base/PersoSimWorkaround.h index 5f03e4d..66b1618 100644 --- a/src/card/base/PersoSimWorkaround.h +++ b/src/card/base/PersoSimWorkaround.h @@ -46,7 +46,7 @@ class PersoSimWorkaround * * As soon as PersoSim is fixed in that point, we will remove the workaround. */ - static ReturnCode parsingEstablishPACEChannelOutput(const QByteArray& pControlOutput, PACE_PIN_ID pPinId) + static CardReturnCode parsingEstablishPACEChannelOutput(const QByteArray& pControlOutput, PACE_PIN_ID pPinId) { quint32 paceReturnCode; QDataStream(pControlOutput.mid(0, 4)) >> paceReturnCode; diff --git a/src/card/base/Reader.cpp b/src/card/base/Reader.cpp index 4ae19fe..adf0b98 100644 --- a/src/card/base/Reader.cpp +++ b/src/card/base/Reader.cpp @@ -47,7 +47,7 @@ QSharedPointer Reader::createCardConnectionWorker() return QSharedPointer(); } - if (currentCard->connect() != ReturnCode::OK) + if (currentCard->connect() != CardReturnCode::OK) { qCCritical(card) << "Cannot connect to card"; return QSharedPointer(); @@ -89,13 +89,13 @@ void Reader::updateRetryCounterIfNecessary() } -ReturnCode Reader::updateRetryCounter(QSharedPointer pCardConnectionWorker) +CardReturnCode Reader::updateRetryCounter(QSharedPointer pCardConnectionWorker) { int newRetryCounter = -1; bool newPinDeactivated = false; - ReturnCode returnCode = getRetryCounter(pCardConnectionWorker, newRetryCounter, newPinDeactivated); - if (returnCode == ReturnCode::OK) + CardReturnCode returnCode = getRetryCounter(pCardConnectionWorker, newRetryCounter, newPinDeactivated); + if (returnCode == CardReturnCode::OK) { bool changed = (newRetryCounter != mReaderInfo.getRetryCounter()) || (newPinDeactivated != mReaderInfo.isPinDeactivated()); qCInfo(support) << "retrieved retry counter:" << newRetryCounter << ", was:" << mReaderInfo.getRetryCounter() << ", PIN deactivated:" << newPinDeactivated; @@ -113,16 +113,16 @@ ReturnCode Reader::updateRetryCounter(QSharedPointer pCard } -ReturnCode Reader::getRetryCounter(QSharedPointer pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated) +CardReturnCode Reader::getRetryCounter(QSharedPointer pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated) { if (!mReaderInfo.getCardInfo().getEfCardAccess()) { qCCritical(card) << "Cannot get EF.CardAccess"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } // we don't need to establish PACE with this protocol (i.e. we don't need to support it), so we just take the fist one - QSharedPointer paceInfo = mReaderInfo.getCardInfo().getEfCardAccess()->getSecurityInfos().at(0); + const auto& paceInfo = mReaderInfo.getCardInfo().getEfCardAccess()->getPACEInfos().at(0); QByteArray cryptographicMechanismReference = paceInfo->getProtocolValueBytes(); QByteArray referencePrivateKey = paceInfo->getParameterId(); @@ -135,8 +135,8 @@ ReturnCode Reader::getRetryCounter(QSharedPointer pCardCon mseBuilder.setPrivateKey(referencePrivateKey); ResponseApdu mseSetAtResponse; - ReturnCode returnCode = pCardConnectionWorker->transmit(mseBuilder.build(), mseSetAtResponse); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = pCardConnectionWorker->transmit(mseBuilder.build(), mseSetAtResponse); + if (returnCode != CardReturnCode::OK) { return returnCode; } @@ -162,7 +162,7 @@ ReturnCode Reader::getRetryCounter(QSharedPointer pCardCon pPinDeactivated = statusCode == StatusCode::PIN_DEACTIVATED; - return ReturnCode::OK; + return CardReturnCode::OK; } @@ -192,11 +192,6 @@ void Reader::onRetryCounterPotentiallyChanged() } -ConnectableReader::ConnectableReader() -{ -} - - ConnectableReader::~ConnectableReader() { } diff --git a/src/card/base/Reader.h b/src/card/base/Reader.h index 7a4cb2e..533fabd 100644 --- a/src/card/base/Reader.h +++ b/src/card/base/Reader.h @@ -5,6 +5,7 @@ #pragma once #include "Card.h" +#include "DeviceError.h" #include "ReaderInfo.h" #include @@ -44,7 +45,7 @@ class Reader void updateRetryCounterIfNecessary(); - ReturnCode getRetryCounter(QSharedPointer pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated); + CardReturnCode getRetryCounter(QSharedPointer pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated); void fireUpdateSignal(CardEvent pCardEvent); @@ -79,13 +80,14 @@ class Reader */ QSharedPointer createCardConnectionWorker(); - ReturnCode updateRetryCounter(QSharedPointer pCardConnectionWorker); + CardReturnCode updateRetryCounter(QSharedPointer pCardConnectionWorker); Q_SIGNALS: void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); void fireCardRetryCounterChanged(const QString& pReaderName); - void fireReaderPropertiesUpdated(); + void fireReaderPropertiesUpdated(const QString& pReaderName); + void fireReaderDeviceError(DeviceError pDeviceError); public Q_SLOTS: void onRetryCounterPotentiallyChanged(); @@ -95,9 +97,12 @@ class Reader class ConnectableReader + : public Reader { + Q_OBJECT + public: - ConnectableReader(); + using Reader::Reader; virtual ~ConnectableReader(); virtual void connectReader() = 0; diff --git a/src/card/base/ReaderManager.cpp b/src/card/base/ReaderManager.cpp index 6996bdb..060e48d 100644 --- a/src/card/base/ReaderManager.cpp +++ b/src/card/base/ReaderManager.cpp @@ -58,6 +58,7 @@ void ReaderManager::init() connect(&mThread, &QThread::started, mWorker.data(), &ReaderManagerWorker::onThreadStarted); connect(&mThread, &QThread::finished, mWorker.data(), &QObject::deleteLater); + connect(mWorker.data(), &ReaderManagerWorker::fireInitialized, this, &ReaderManager::fireInitialized); connect(mWorker.data(), &ReaderManagerWorker::fireStatusChanged, this, &ReaderManager::fireStatusChanged); connect(mWorker.data(), &ReaderManagerWorker::fireCardInserted, this, &ReaderManager::fireCardInserted); @@ -65,6 +66,7 @@ void ReaderManager::init() connect(mWorker.data(), &ReaderManagerWorker::fireCardRetryCounterChanged, this, &ReaderManager::fireCardRetryCounterChanged); connect(mWorker.data(), &ReaderManagerWorker::fireReaderPropertiesUpdated, this, &ReaderManager::fireReaderPropertiesUpdated); connect(mWorker.data(), &ReaderManagerWorker::fireReaderAdded, this, &ReaderManager::fireReaderAdded); + connect(mWorker.data(), &ReaderManagerWorker::fireReaderDeviceError, this, &ReaderManager::fireReaderDeviceError); connect(mWorker.data(), &ReaderManagerWorker::fireReaderConnected, this, &ReaderManager::fireReaderConnected); connect(mWorker.data(), &ReaderManagerWorker::fireReaderRemoved, this, &ReaderManager::fireReaderRemoved); diff --git a/src/card/base/ReaderManager.h b/src/card/base/ReaderManager.h index 7bf1788..b9114a2 100644 --- a/src/card/base/ReaderManager.h +++ b/src/card/base/ReaderManager.h @@ -4,6 +4,7 @@ #pragma once +#include "DeviceError.h" #include "Reader.h" #include "ReaderManagerWorker.h" #include "command/CreateCardConnectionCommand.h" @@ -43,14 +44,14 @@ class ReaderManager /*! * Stops started scan for devices. - * Be aware that some plugins doesn't finished the whole scan if you + * Be aware that some plugins don't finish the whole scan if you * abort it with stopScan! */ void stopScan(); QVector getPlugInInfos() const; QVector getReaderInfos(ReaderManagerPlugInType pType) const; - QVector getReaderInfos(const QVector& pTypes = EnumReaderManagerPlugInType::getList()) const; + QVector getReaderInfos(const QVector& pTypes = Enum::getList()) const; ReaderInfo getReaderInfo(const QString& pReaderName) const; /*! @@ -85,13 +86,15 @@ class ReaderManager Q_SIGNALS: void fireStatusChanged(const ReaderManagerPlugInInfo& pInfo); void fireReaderAdded(const QString& pReaderName); + void fireReaderDeviceError(DeviceError pDeviceError); void fireReaderConnected(const QString& pReaderName); void fireReaderRemoved(const QString& pReaderName); - void fireReaderPropertiesUpdated(); + void fireReaderPropertiesUpdated(const QString& pReaderName); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); void fireCardRetryCounterChanged(const QString& pReaderName); void fireReaderEvent(); + void fireInitialized(); public Q_SLOTS: /*! diff --git a/src/card/base/ReaderManagerPlugIn.cpp b/src/card/base/ReaderManagerPlugIn.cpp index dfee170..87eb9ee 100644 --- a/src/card/base/ReaderManagerPlugIn.cpp +++ b/src/card/base/ReaderManagerPlugIn.cpp @@ -8,11 +8,9 @@ using namespace governikus; -ReaderManagerPlugIn::ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, bool pPlugInEnabled) : mInfo(pPlugInType, pPlugInEnabled) -{ -} - - -ReaderManagerPlugIn::~ReaderManagerPlugIn() +ReaderManagerPlugIn::ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, + bool pAvailable, + bool pPlugInEnabled) + : mInfo(pPlugInType, pPlugInEnabled, pAvailable) { } diff --git a/src/card/base/ReaderManagerPlugIn.h b/src/card/base/ReaderManagerPlugIn.h index 369f5fe..8dbc262 100644 --- a/src/card/base/ReaderManagerPlugIn.h +++ b/src/card/base/ReaderManagerPlugIn.h @@ -9,6 +9,7 @@ #pragma once +#include "DeviceError.h" #include "ReaderManagerPlugInInfo.h" #include @@ -36,6 +37,12 @@ class ReaderManagerPlugIn } + void setReaderInfoAvailable(bool pAvailable) + { + mInfo.setAvailable(pAvailable); + } + + void setReaderInfoValue(ReaderManagerPlugInInfo::Key pKey, const QVariant& pValue) { mInfo.setValue(pKey, pValue); @@ -43,8 +50,10 @@ class ReaderManagerPlugIn public: - ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, bool pPlugInEnabled = false); - virtual ~ReaderManagerPlugIn(); + ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, + bool pAvailable = false, + bool pPlugInEnabled = false); + virtual ~ReaderManagerPlugIn() = default; const ReaderManagerPlugInInfo& getInfo() const { @@ -80,11 +89,12 @@ class ReaderManagerPlugIn void fireStatusChanged(const ReaderManagerPlugInInfo& pInfo); void fireReaderAdded(const QString& pReaderName); void fireReaderConnected(const QString& pReaderName); + void fireReaderDeviceError(DeviceError pDeviceError); void fireReaderRemoved(const QString& pReaderName); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); void fireCardRetryCounterChanged(const QString& pReaderName); - void fireReaderPropertiesUpdated(); + void fireReaderPropertiesUpdated(const QString& pReaderName); }; } /* namespace governikus */ diff --git a/src/card/base/ReaderManagerPlugInInfo.cpp b/src/card/base/ReaderManagerPlugInInfo.cpp index 100877f..af71a77 100644 --- a/src/card/base/ReaderManagerPlugInInfo.cpp +++ b/src/card/base/ReaderManagerPlugInInfo.cpp @@ -9,10 +9,11 @@ using namespace governikus; -ReaderManagerPlugInInfo::ReaderManagerPlugInInfo(ReaderManagerPlugInType pType, bool pEnabled) +ReaderManagerPlugInInfo::ReaderManagerPlugInInfo(ReaderManagerPlugInType pType, bool pEnabled, bool pAvailable) : mType(pType) , mValues() , mEnabled(pEnabled) + , mAvailable(pAvailable) { } diff --git a/src/card/base/ReaderManagerPlugInInfo.h b/src/card/base/ReaderManagerPlugInInfo.h index e44d15c..6a07f01 100644 --- a/src/card/base/ReaderManagerPlugInInfo.h +++ b/src/card/base/ReaderManagerPlugInInfo.h @@ -32,8 +32,9 @@ class ReaderManagerPlugInInfo }; public: - ReaderManagerPlugInInfo(ReaderManagerPlugInType pType = ReaderManagerPlugInType::UNKNOWN, bool pEnabled = false); - + ReaderManagerPlugInInfo(ReaderManagerPlugInType pType = ReaderManagerPlugInType::UNKNOWN, + bool pEnabled = false, + bool pAvailable = false); const ReaderManagerPlugInType& getPlugInType() const { @@ -74,10 +75,26 @@ class ReaderManagerPlugInInfo } + /*! + * Is there a device/interface? + */ + bool isAvailable() const + { + return mAvailable; + } + + + void setAvailable(bool pAvailable) + { + mAvailable = pAvailable; + } + + private: ReaderManagerPlugInType mType; QMap mValues; bool mEnabled; + bool mAvailable; }; } /* namespace governikus */ diff --git a/src/card/base/ReaderManagerWorker.cpp b/src/card/base/ReaderManagerWorker.cpp index 1be7d5b..f01db76 100644 --- a/src/card/base/ReaderManagerWorker.cpp +++ b/src/card/base/ReaderManagerWorker.cpp @@ -18,7 +18,6 @@ ReaderManagerWorker::ReaderManagerWorker() , mPlugIns() , mScanStarted(false) { - qRegisterMetaType >("QSharedPointer"); } @@ -40,13 +39,16 @@ void ReaderManagerWorker::onThreadStarted() qCDebug(card) << "Thread started"; registerPlugIns(); + + Q_EMIT fireInitialized(); } void ReaderManagerWorker::registerPlugIns() { qCDebug(card) << "Try to register plugins"; - for (auto plugin : QPluginLoader::staticPlugins()) + const auto& plugins = QPluginLoader::staticPlugins(); + for (const auto& plugin : plugins) { if (isPlugIn(plugin.metaData())) { @@ -85,6 +87,7 @@ void ReaderManagerWorker::registerPlugIn(ReaderManagerPlugIn* pPlugIn) connect(pPlugIn, &ReaderManagerPlugIn::fireCardRetryCounterChanged, this, &ReaderManagerWorker::fireCardRetryCounterChanged); connect(pPlugIn, &ReaderManagerPlugIn::fireReaderAdded, this, &ReaderManagerWorker::fireReaderAdded); connect(pPlugIn, &ReaderManagerPlugIn::fireReaderConnected, this, &ReaderManagerWorker::fireReaderConnected); + connect(pPlugIn, &ReaderManagerPlugIn::fireReaderDeviceError, this, &ReaderManagerWorker::fireReaderDeviceError); connect(pPlugIn, &ReaderManagerPlugIn::fireReaderRemoved, this, &ReaderManagerWorker::fireReaderRemoved); connect(pPlugIn, &ReaderManagerPlugIn::fireReaderPropertiesUpdated, this, &ReaderManagerWorker::fireReaderPropertiesUpdated); } @@ -152,7 +155,8 @@ QVector ReaderManagerWorker::getReaderInfos(const QVectorgetInfo().getPlugInType())) { - for (const Reader* reader : plugIn->getReader()) + const auto& readerList = plugIn->getReader(); + for (const Reader* reader : readerList) { list += reader->getReaderInfo(); } @@ -175,9 +179,10 @@ Reader* ReaderManagerWorker::getReader(const QString& pReaderName) const { Q_ASSERT(thread() == QThread::currentThread()); - for (auto plugin : mPlugIns) + for (auto plugin : qAsConst(mPlugIns)) { - for (Reader* reader : plugin->getReader()) + const auto& readerList = plugin->getReader(); + for (Reader* reader : readerList) { if (reader->getName() == pReaderName) { @@ -208,7 +213,7 @@ void ReaderManagerWorker::connectReader(const QString& pReaderName) { Q_ASSERT(thread() == QThread::currentThread()); - if (ConnectableReader* reader = dynamic_cast(getReader(pReaderName))) + if (ConnectableReader* reader = qobject_cast(getReader(pReaderName))) { reader->connectReader(); } @@ -219,7 +224,7 @@ void ReaderManagerWorker::disconnectReader(const QString& pReaderName) { Q_ASSERT(thread() == QThread::currentThread()); - if (ConnectableReader* reader = dynamic_cast(getReader(pReaderName))) + if (ConnectableReader* reader = qobject_cast(getReader(pReaderName))) { reader->disconnectReader(); } @@ -230,8 +235,19 @@ void ReaderManagerWorker::disconnectAllReaders() { Q_ASSERT(thread() == QThread::currentThread()); - for (auto& info : getReaderInfos(EnumReaderManagerPlugInType::getList())) + for (auto& info : getReaderInfos(Enum::getList())) { disconnectReader(info.getName()); } } + + +void ReaderManagerWorker::registerMetaTypes() +{ + static bool registered = false; + if (!registered) + { + qRegisterMetaType >("QSharedPointer"); + registered = true; + } +} diff --git a/src/card/base/ReaderManagerWorker.h b/src/card/base/ReaderManagerWorker.h index c51c518..7459a76 100644 --- a/src/card/base/ReaderManagerWorker.h +++ b/src/card/base/ReaderManagerWorker.h @@ -7,6 +7,7 @@ #pragma once #include "CardConnectionWorker.h" +#include "DeviceError.h" #include "ReaderInfo.h" #include "ReaderManagerPlugIn.h" #include "ReaderManagerPlugInInfo.h" @@ -44,17 +45,20 @@ class ReaderManagerWorker Q_INVOKABLE void connectReader(const QString& pReaderName); Q_INVOKABLE void disconnectReader(const QString& pReaderName); Q_INVOKABLE void disconnectAllReaders(); + static void registerMetaTypes(); Q_SIGNALS: void fireStatusChanged(const ReaderManagerPlugInInfo& pInfo); void fireReaderAdded(const QString& pReaderName); void fireReaderConnected(const QString& pReaderName); + void fireReaderDeviceError(DeviceError pDeviceError); void fireReaderRemoved(const QString& pReaderName); - void fireReaderPropertiesUpdated(); + void fireReaderPropertiesUpdated(const QString& pReaderName); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); void fireCardRetryCounterChanged(const QString& pReaderName); void fireCardConnectionWorkerCreated(const QSharedPointer& pCardConnectionWorker); + void fireInitialized(); public Q_SLOTS: void onThreadStarted(); diff --git a/src/card/base/SmartCardDefinitions.h b/src/card/base/SmartCardDefinitions.h index d94bc27..96a334c 100644 --- a/src/card/base/SmartCardDefinitions.h +++ b/src/card/base/SmartCardDefinitions.h @@ -30,7 +30,7 @@ defineEnumType(CardType, UNKNOWN, EID_CARD) -defineEnumType(PACE_PIN_ID, +defineTypedEnumType(PACE_PIN_ID, char, PACE_MRZ = 0x01, PACE_CAN = 0x02, PACE_PIN = 0x03, diff --git a/src/card/base/SupportedReaders.cpp b/src/card/base/SupportedReaders.cpp index 9b2a917..b87cf40 100644 --- a/src/card/base/SupportedReaders.cpp +++ b/src/card/base/SupportedReaders.cpp @@ -17,22 +17,22 @@ defineSingleton(SupportedReaders) SupportedReaders::SupportedReaders() : mWhiteList( -{ - {ReaderType::REINER_cyberJack_RFID_komfort, regex("REINER SCT cyberJack RFID komfort")}, - {ReaderType::REINER_cyberJack_RFID_standard, regex("REINER SCT cyberJack RFID standard")}, - {ReaderType::REINER_cyberJack_RFID_basis, regex("REINER SCT cyberJack RFID basis")}, - {ReaderType::REINER_cyberJack_wave, regex("REINER SCT cyberJack wave")}, - {ReaderType::KOBIL_IDToken, regex("KOBIL (Systems )?IDToken")}, - {ReaderType::SCM_SDI010, regex("SDI010 (USB )?(Smart Card|Contactless) Reader")}, - {ReaderType::SCM_SDI011, regex("SDI011 (USB )?(Smart Card|Contactless) Reader")}, - {ReaderType::SCM_SCL011_Contactless_Reader, regex("(SCM Microsystems Inc. )?SCL011 Contactless Reader")}, - {ReaderType::ACS_ACR1281_PICC_Reader, regex("ACS ACR1281 PICC Reader")}, - {ReaderType::OMNIKEY_CardMan_5x21_CL, regex("OMNIKEY CardMan 5(x|3)21")}, - {ReaderType::OMNIKEY_4121_CL, regex("OMNIKEY 4121-CL")}, - {ReaderType::FEIG_OBID_myAXXESS_basic, regex("FEIG ELECTRONIC GmbH OBID myAXXESS basic")}, - {ReaderType::Gemalto_Prox_SU, regex("Gemalto Prox( |-)SU")}, - {ReaderType::Gemalto_Prox_DU, regex("Gemalto Prox(-DU| Dual)")} -}) + { + {ReaderType::REINER_cyberJack_RFID_komfort, regex("REINER SCT cyberJack RFID komfort")}, + {ReaderType::REINER_cyberJack_RFID_standard, regex("REINER SCT cyberJack RFID standard")}, + {ReaderType::REINER_cyberJack_RFID_basis, regex("REINER SCT cyberJack RFID basis")}, + {ReaderType::REINER_cyberJack_wave, regex("REINER SCT cyberJack wave")}, + {ReaderType::KOBIL_IDToken, regex("KOBIL (Systems )?IDToken")}, + {ReaderType::SCM_SDI010, regex("SDI010 (USB )?(Smart Card|Contactless) Reader")}, + {ReaderType::SCM_SDI011, regex("SDI011 (USB )?(Smart Card|Contactless) Reader")}, + {ReaderType::SCM_SCL011_Contactless_Reader, regex("(SCM Microsystems Inc. )?SCL011 Contactless Reader")}, + {ReaderType::ACS_ACR1281_PICC_Reader, regex("ACS ACR1281 PICC Reader")}, + {ReaderType::OMNIKEY_CardMan_5x21_CL, regex("OMNIKEY CardMan 5(x|3)21")}, + {ReaderType::OMNIKEY_4121_CL, regex("OMNIKEY 4121-CL")}, + {ReaderType::FEIG_OBID_myAXXESS_basic, regex("FEIG ELECTRONIC GmbH OBID myAXXESS basic")}, + {ReaderType::Gemalto_Prox_SU, regex("Gemalto Prox( |-)SU")}, + {ReaderType::Gemalto_Prox_DU, regex("Gemalto Prox(-DU| Dual)")} + }) { } diff --git a/src/card/base/asn1/ASN1TemplateUtil.h b/src/card/base/asn1/ASN1TemplateUtil.h index e7740eb..fbdd71f 100644 --- a/src/card/base/asn1/ASN1TemplateUtil.h +++ b/src/card/base/asn1/ASN1TemplateUtil.h @@ -99,18 +99,16 @@ void freeAsn1Object(T*) template QSharedPointer decodeObject(const QByteArray& pData) { - { - const char* tmp = pData.constData(); - const unsigned char** dataPointer = reinterpret_cast(&tmp); + const char* tmp = pData.constData(); + const unsigned char** dataPointer = reinterpret_cast(&tmp); - T* object = nullptr; - decodeAsn1Object(&object, dataPointer, pData.length()); - static auto deleter = [](T* pTypeObject) - { - freeAsn1Object(pTypeObject); - }; - return QSharedPointer(object, deleter); - } + T* object = nullptr; + decodeAsn1Object(&object, dataPointer, pData.length()); + static auto deleter = [](T* pTypeObject) + { + freeAsn1Object(pTypeObject); + }; + return QSharedPointer(object, deleter); } diff --git a/src/card/base/asn1/ASN1Util.cpp b/src/card/base/asn1/ASN1Util.cpp index bed76f6..f1981fa 100644 --- a/src/card/base/asn1/ASN1Util.cpp +++ b/src/card/base/asn1/ASN1Util.cpp @@ -1,5 +1,7 @@ #include "asn1/ASN1Util.h" +#include "SecureMessagingResponse.h" + #include #include #include @@ -126,7 +128,7 @@ QByteArray Asn1BCDDateUtil::convertFromQDateToUnpackedBCD(QDate pDate) // convert to unpacked BCD digits for (int i = 0; i <= 5; i++) { - aBCD[i] = aBCD[i] - 0x30; + aBCD[i] = static_cast(aBCD[i] - 0x30); } return aBCD; @@ -154,3 +156,16 @@ QDate Asn1BCDDateUtil::convertFromUnpackedBCDToQDate(ASN1_OCTET_STRING* pDateBCD return QDate(year, month, day); } + + +QByteArray Asn1Util::encode(char pTagByte, const QByteArray& pData) +{ + // 1. encode as ASN1_OCTET_STRING using our template utils + // (in fact SM_CHECKSUM ::= [8E] IMPLICIT OCTET STRING) + auto octetString = newObject(); + Asn1OctetStringUtil::setValue(pData, octetString.data()); + auto encodedOctetString = encodeObject(octetString.data()); + + // 2. replace the tag byte + return encodedOctetString.replace(0, 1, QByteArray(1, pTagByte)); +} diff --git a/src/card/base/asn1/ASN1Util.h b/src/card/base/asn1/ASN1Util.h index d551955..c6f0706 100644 --- a/src/card/base/asn1/ASN1Util.h +++ b/src/card/base/asn1/ASN1Util.h @@ -23,6 +23,19 @@ namespace governikus { +class Asn1Util +{ + Asn1Util() = delete; + ~Asn1Util() = delete; + + public: + /*! + * Encodes the data as ASN.1 object with specified tag byte. + */ + static QByteArray encode(char pTagByte, const QByteArray& pData); +}; + + /*! * Utility for OpenSSL type ASN1_OBJECT, i.e. ASN.1 type OBJECT_IDENTIFIER */ diff --git a/src/card/base/asn1/AccessRoleAndRight.cpp b/src/card/base/asn1/AccessRoleAndRight.cpp index 6ced376..4818369 100644 --- a/src/card/base/asn1/AccessRoleAndRight.cpp +++ b/src/card/base/asn1/AccessRoleAndRight.cpp @@ -51,47 +51,47 @@ const QList& AccessRoleAndRightsUtil::allRights() { if (mAllRights.isEmpty()) { - mAllRights.append(AccessRight::WRITE_DG17); - mAllRights.append(AccessRight::WRITE_DG18); - mAllRights.append(AccessRight::WRITE_DG19); - mAllRights.append(AccessRight::WRITE_DG20); - mAllRights.append(AccessRight::WRITE_DG21); + mAllRights += AccessRight::WRITE_DG17; + mAllRights += AccessRight::WRITE_DG18; + mAllRights += AccessRight::WRITE_DG19; + mAllRights += AccessRight::WRITE_DG20; + mAllRights += AccessRight::WRITE_DG21; - mAllRights.append(AccessRight::RFU_32); - mAllRights.append(AccessRight::RFU_31); - mAllRights.append(AccessRight::RFU_30); - mAllRights.append(AccessRight::RFU_29); + mAllRights += AccessRight::RFU_32; + mAllRights += AccessRight::RFU_31; + mAllRights += AccessRight::RFU_30; + mAllRights += AccessRight::RFU_29; - mAllRights.append(AccessRight::READ_DG21); - mAllRights.append(AccessRight::READ_DG20); - mAllRights.append(AccessRight::READ_DG19); - mAllRights.append(AccessRight::READ_DG18); - mAllRights.append(AccessRight::READ_DG17); - mAllRights.append(AccessRight::READ_DG16); - mAllRights.append(AccessRight::READ_DG15); - mAllRights.append(AccessRight::READ_DG14); - mAllRights.append(AccessRight::READ_DG13); - mAllRights.append(AccessRight::READ_DG12); - mAllRights.append(AccessRight::READ_DG11); - mAllRights.append(AccessRight::READ_DG10); - mAllRights.append(AccessRight::READ_DG09); - mAllRights.append(AccessRight::READ_DG08); - mAllRights.append(AccessRight::READ_DG07); - mAllRights.append(AccessRight::READ_DG06); - mAllRights.append(AccessRight::READ_DG05); - mAllRights.append(AccessRight::READ_DG04); - mAllRights.append(AccessRight::READ_DG03); - mAllRights.append(AccessRight::READ_DG02); - mAllRights.append(AccessRight::READ_DG01); + mAllRights += AccessRight::READ_DG21; + mAllRights += AccessRight::READ_DG20; + mAllRights += AccessRight::READ_DG19; + mAllRights += AccessRight::READ_DG18; + mAllRights += AccessRight::READ_DG17; + mAllRights += AccessRight::READ_DG16; + mAllRights += AccessRight::READ_DG15; + mAllRights += AccessRight::READ_DG14; + mAllRights += AccessRight::READ_DG13; + mAllRights += AccessRight::READ_DG12; + mAllRights += AccessRight::READ_DG11; + mAllRights += AccessRight::READ_DG10; + mAllRights += AccessRight::READ_DG09; + mAllRights += AccessRight::READ_DG08; + mAllRights += AccessRight::READ_DG07; + mAllRights += AccessRight::READ_DG06; + mAllRights += AccessRight::READ_DG05; + mAllRights += AccessRight::READ_DG04; + mAllRights += AccessRight::READ_DG03; + mAllRights += AccessRight::READ_DG02; + mAllRights += AccessRight::READ_DG01; - mAllRights.append(AccessRight::INSTALL_QUAL_CERT); - mAllRights.append(AccessRight::INSTALL_CERT); - mAllRights.append(AccessRight::PIN_MANAGEMENT); - mAllRights.append(AccessRight::CAN_ALLOWED); - mAllRights.append(AccessRight::PRIVILEGED_TERMINAL); - mAllRights.append(AccessRight::RESTRICTED_IDENTIFICATION); - mAllRights.append(AccessRight::COMMUNITY_ID_VERIFICATION); - mAllRights.append(AccessRight::AGE_VERIFICATION); + mAllRights += AccessRight::INSTALL_QUAL_CERT; + mAllRights += AccessRight::INSTALL_CERT; + mAllRights += AccessRight::PIN_MANAGEMENT; + mAllRights += AccessRight::CAN_ALLOWED; + mAllRights += AccessRight::PRIVILEGED_TERMINAL; + mAllRights += AccessRight::RESTRICTED_IDENTIFICATION; + mAllRights += AccessRight::COMMUNITY_ID_VERIFICATION; + mAllRights += AccessRight::AGE_VERIFICATION; } return mAllRights; diff --git a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp index d1341e3..f2c6d8e 100644 --- a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp +++ b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp @@ -111,7 +111,7 @@ QSharedPointer AuthenticatedAuxiliaryData::decode(co auxDate.clear(); break; } - oids.append(oid); + oids += oid; } oids.removeOne(KnownOIDs::AuxilaryData::id_CommunityID); oids.removeOne(KnownOIDs::AuxilaryData::id_DateOfBirth); diff --git a/src/card/base/asn1/CVCertificate.cpp b/src/card/base/asn1/CVCertificate.cpp index 1d233dd..93c5c68 100644 --- a/src/card/base/asn1/CVCertificate.cpp +++ b/src/card/base/asn1/CVCertificate.cpp @@ -75,7 +75,7 @@ QVector > CVCertificate::fromHex(const QByteArrayL { if (auto cvc = CVCertificate::fromHex(hexBytes)) { - cvcs.append(cvc); + cvcs += cvc; } } return cvcs; @@ -141,6 +141,24 @@ bool CVCertificate::isIssuedBy(const CVCertificate& pIssuer) const bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2) +{ + return QSharedPointer(pCvc1) == QSharedPointer(pCvc2); +} + + +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2) +{ + return QSharedPointer(pCvc1) == pCvc2; +} + + +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2) +{ + return pCvc1 == QSharedPointer(pCvc2); +} + + +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2) { if ((pCvc1.isNull() && !pCvc2.isNull()) || (!pCvc1.isNull() && pCvc2.isNull())) { @@ -166,7 +184,7 @@ QDebug operator <<(QDebug pDbg, const governikus::CVCertificate& pCvc) } -QDebug operator<<(QDebug pDbg, QSharedPointer& pCvc) +QDebug operator<<(QDebug pDbg, const QSharedPointer& pCvc) { if (pCvc == nullptr) { @@ -181,6 +199,15 @@ QDebug operator<<(QDebug pDbg, QSharedPointer& pCvc) } +QDebug operator<<(QDebug pDbg, QSharedPointer& pCvc) +{ + const QSharedPointer constPtr(pCvc); + pDbg << constPtr; + + return pDbg; +} + + QDebug operator<<(QDebug pDbg, const QVector >& pCvcs) { QDebugStateSaver saver(pDbg); diff --git a/src/card/base/asn1/CVCertificate.h b/src/card/base/asn1/CVCertificate.h index cd4375d..1801158 100644 --- a/src/card/base/asn1/CVCertificate.h +++ b/src/card/base/asn1/CVCertificate.h @@ -78,8 +78,12 @@ DECLARE_ASN1_OBJECT(CVCertificate) bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2); +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2); +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2); +bool operator==(const QSharedPointer& pCvc1, const QSharedPointer& pCvc2); QDebug operator<<(QDebug pDbg, const governikus::CVCertificate& pCvc); +QDebug operator<<(QDebug pDbg, const QSharedPointer& pCvc); QDebug operator<<(QDebug pDbg, QSharedPointer& pCvc); QDebug operator<<(QDebug pDbg, const QVector >& pCvcs); diff --git a/src/card/base/asn1/CVCertificateChainBuilder.cpp b/src/card/base/asn1/CVCertificateChainBuilder.cpp index 28d4f82..b29b9ea 100644 --- a/src/card/base/asn1/CVCertificateChainBuilder.cpp +++ b/src/card/base/asn1/CVCertificateChainBuilder.cpp @@ -12,7 +12,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -bool CVCertificateChainBuilder::isChild(const QSharedPointer& pChild, const QSharedPointer& pParent) +bool CVCertificateChainBuilder::isChild(const QSharedPointer& pChild, const QSharedPointer& pParent) { // self signed CVCs are the root of a chain, no other parent possible. return !pChild->isIssuedBy(*pChild) && pChild->isIssuedBy(*pParent); @@ -104,7 +104,7 @@ CVCertificateChain CVCertificateChainBuilder::getChainForCertificationAuthority( } -CVCertificateChain CVCertificateChainBuilder::getChainStartingWith(const QSharedPointer& pChainRoot) const +CVCertificateChain CVCertificateChainBuilder::getChainStartingWith(const QSharedPointer& pChainRoot) const { qCDebug(card) << "Get chain for root" << pChainRoot; for (const auto& chain : getChains()) diff --git a/src/card/base/asn1/CVCertificateChainBuilder.h b/src/card/base/asn1/CVCertificateChainBuilder.h index 72b177f..65573c1 100644 --- a/src/card/base/asn1/CVCertificateChainBuilder.h +++ b/src/card/base/asn1/CVCertificateChainBuilder.h @@ -22,7 +22,7 @@ class CVCertificateChainBuilder private: bool mProductive; - static bool isChild(const QSharedPointer& pChild, const QSharedPointer& pParent); + static bool isChild(const QSharedPointer& pChild, const QSharedPointer& pParent); void removeInvalidChains(); @@ -46,7 +46,7 @@ class CVCertificateChainBuilder * occurred ( e.g. the last element in the list is no terminal CVC), an invalid chain * is returned (see CVCertificateChain::isValid()). */ - CVCertificateChain getChainStartingWith(const QSharedPointer& pChainRoot) const; + CVCertificateChain getChainStartingWith(const QSharedPointer& pChainRoot) const; /*! diff --git a/src/card/base/asn1/CertificateDescription.cpp b/src/card/base/asn1/CertificateDescription.cpp index 449a926..5f6832c 100644 --- a/src/card/base/asn1/CertificateDescription.cpp +++ b/src/card/base/asn1/CertificateDescription.cpp @@ -36,7 +36,7 @@ QStringList takeWhileNonEmpty(const QStringList& lines) } -QString getField(const QString& pData, const QStringList& pSearchItems, const QString& pDefaultValue) +QString getField(const QString& pData, const QStringList& pSearchItems) { static const QString NEW_LINE("\r\n"); @@ -56,7 +56,7 @@ QString getField(const QString& pData, const QStringList& pSearchItems, const QS } } - return pDefaultValue; + return QString(); } @@ -243,23 +243,23 @@ QSet CertificateDescription::getCommCertificates() const QString CertificateDescription::getServiceProviderAddress() const { static const QStringList SEARCH_ITEMS({ - QStringLiteral("Name, Anschrift und E-Mail-Adresse des Diensteanbieters:\r\n") - }); + QStringLiteral("Name, Anschrift und E-Mail-Adresse des Diensteanbieters:\r\n") + }); - return getField(getTermsOfUsage(), SEARCH_ITEMS, QString()); + return getField(getTermsOfUsage(), SEARCH_ITEMS); } QString CertificateDescription::getPurpose() const { static const QStringList SEARCH_ITEMS({ - QStringLiteral("Gesch\u00E4ftszweck:\r\n"), - QStringLiteral("Zweck des Auslesevorgangs:\r\n"), - QStringLiteral("Verwendung der Daten:\r\n"), - QStringLiteral("Zweck der Daten\u00FCbermittlung:\r\n") - }); + QStringLiteral("Gesch\u00E4ftszweck:\r\n"), + QStringLiteral("Zweck des Auslesevorgangs:\r\n"), + QStringLiteral("Verwendung der Daten:\r\n"), + QStringLiteral("Zweck der Daten\u00FCbermittlung:\r\n") + }); - return getField(getTermsOfUsage(), SEARCH_ITEMS, tr("see details under more...")); + return getField(getTermsOfUsage(), SEARCH_ITEMS); } @@ -269,5 +269,5 @@ QString CertificateDescription::getDataSecurityOfficer() const "Hinweis auf die f\u00FCr den Diensteanbieter zust\u00E4ndigen Stellen, " "die die Einhaltung der Vorschriften zum Datenschutz kontrollieren:\r\n")}); - return getField(getTermsOfUsage(), SEARCH_ITEMS, QString()); + return getField(getTermsOfUsage(), SEARCH_ITEMS); } diff --git a/src/card/base/asn1/ChainBuilder.h b/src/card/base/asn1/ChainBuilder.h index e8481c7..0645fde 100644 --- a/src/card/base/asn1/ChainBuilder.h +++ b/src/card/base/asn1/ChainBuilder.h @@ -44,7 +44,7 @@ class ChainBuilder if (mIsChildFunc(elem, pChain.last())) { QVector extendedChain(pChain); - extendedChain.append(elem); + extendedChain += elem; buildChain(pAllElements, extendedChain); chainComplete = false; } diff --git a/src/card/base/asn1/Chat.cpp b/src/card/base/asn1/Chat.cpp index 5af4d89..42590e6 100644 --- a/src/card/base/asn1/Chat.cpp +++ b/src/card/base/asn1/Chat.cpp @@ -214,7 +214,8 @@ bool CHAT::hasAccessRight(AccessRight pAccessRight) const void CHAT::removeAllAccessRights() { - for (auto accessRight : getAccessRights()) + const auto& rights = getAccessRights(); + for (auto accessRight : rights) { removeAccessRight(accessRight); } @@ -229,6 +230,11 @@ void CHAT::removeAccessRight(AccessRight pAccessRight) void chat_st::setTemplateBit(uint pBitIndex, bool pOn) { + if (pBitIndex > 39) + { + qCritical() << "Setting template bit > 39 not supported"; + return; + } if (mTemplate->length == 0) { static const unsigned char nullBytes[5] = { @@ -237,15 +243,16 @@ void chat_st::setTemplateBit(uint pBitIndex, bool pOn) ASN1_OCTET_STRING_set(mTemplate, nullBytes, 5); } - quint8 byteNumber = 4 - (pBitIndex / 8); + // because pBitIndex < 40, it follows that pBitIndex / 8 <= 4, so byteNumber has no underflow + quint8 byteNumber = static_cast(4 - (pBitIndex / 8)); quint8 bitNumberInByte = pBitIndex % 8; if (pOn) { - mTemplate->data[byteNumber] |= (0x01 << bitNumberInByte); + mTemplate->data[byteNumber] = static_cast(mTemplate->data[byteNumber] | (0x01 << bitNumberInByte)); } else { - mTemplate->data[byteNumber] &= ~(0x01 << bitNumberInByte); + mTemplate->data[byteNumber] = static_cast(mTemplate->data[byteNumber] & ~(0x01 << bitNumberInByte)); } } diff --git a/src/card/base/asn1/ChipAuthenticationInfo.cpp b/src/card/base/asn1/ChipAuthenticationInfo.cpp index cff438a..a4166af 100644 --- a/src/card/base/asn1/ChipAuthenticationInfo.cpp +++ b/src/card/base/asn1/ChipAuthenticationInfo.cpp @@ -61,7 +61,7 @@ bool ChipAuthenticationInfo::acceptsProtocol(const ASN1_OBJECT* pObjectIdentifie } -ChipAuthenticationInfo::ChipAuthenticationInfo(QSharedPointer pDelegate) +ChipAuthenticationInfo::ChipAuthenticationInfo(const QSharedPointer& pDelegate) : SecurityInfo() , mDelegate(pDelegate) { diff --git a/src/card/base/asn1/ChipAuthenticationInfo.h b/src/card/base/asn1/ChipAuthenticationInfo.h index 039df4f..06851e2 100644 --- a/src/card/base/asn1/ChipAuthenticationInfo.h +++ b/src/card/base/asn1/ChipAuthenticationInfo.h @@ -42,9 +42,9 @@ DECLARE_ASN1_FUNCTIONS(chipauthenticationinfo_st) class ChipAuthenticationInfo : public SecurityInfo { - QSharedPointer mDelegate; + const QSharedPointer mDelegate; - ChipAuthenticationInfo(QSharedPointer pDelegate); + ChipAuthenticationInfo(const QSharedPointer& pDelegate); ASN1_OBJECT* getProtocolObjectIdentifier() const override; @@ -53,7 +53,7 @@ class ChipAuthenticationInfo public: static QSharedPointer decode(const QByteArray& pBytes) { - if (QSharedPointer delegate = decodeObject(pBytes)) + if (const auto& delegate = decodeObject(pBytes)) { if (ChipAuthenticationInfo::acceptsProtocol(delegate->mProtocol)) { diff --git a/src/card/base/asn1/EFCardSecurity.cpp b/src/card/base/asn1/EFCardSecurity.cpp index 6b5e68e..1845a43 100644 --- a/src/card/base/asn1/EFCardSecurity.cpp +++ b/src/card/base/asn1/EFCardSecurity.cpp @@ -86,7 +86,13 @@ QSharedPointer EFCardSecurity::decode(const QByteArray& pBytes) } -EFCardSecurity::EFCardSecurity(QSharedPointer pSecurityInfos) +const QSharedPointer& EFCardSecurity::getSecurityInfos() const +{ + return mSecurityInfos; +} + + +EFCardSecurity::EFCardSecurity(const QSharedPointer& pSecurityInfos) : mSecurityInfos(pSecurityInfos) { } diff --git a/src/card/base/asn1/EFCardSecurity.h b/src/card/base/asn1/EFCardSecurity.h index 46543f4..238a314 100644 --- a/src/card/base/asn1/EFCardSecurity.h +++ b/src/card/base/asn1/EFCardSecurity.h @@ -87,22 +87,16 @@ namespace governikus */ class EFCardSecurity { - QSharedPointer mSecurityInfos; + const QSharedPointer mSecurityInfos; - EFCardSecurity(QSharedPointer pSecurityInfos); + EFCardSecurity(const QSharedPointer& pSecurityInfos); Q_DISABLE_COPY(EFCardSecurity) public: static QSharedPointer fromHex(const QByteArray& pHexString); static QSharedPointer decode(const QByteArray& pBytes); - template QVector > getSecurityInfos() const - { - Q_ASSERT(mSecurityInfos != nullptr); - return mSecurityInfos->getSecurityInfos(); - } - - + const QSharedPointer& getSecurityInfos() const; }; template<> diff --git a/src/card/base/asn1/EcdsaPublicKey.cpp b/src/card/base/asn1/EcdsaPublicKey.cpp index 8ca8411..99e5bf3 100644 --- a/src/card/base/asn1/EcdsaPublicKey.cpp +++ b/src/card/base/asn1/EcdsaPublicKey.cpp @@ -156,7 +156,7 @@ void EcdsaPublicKey::initEcKey() } QSharedPointer generator = EcUtil::create(EC_POINT_new(group.data())); - if (!EC_POINT_oct2point(group.data(), generator.data(), mBasePoint->data, mBasePoint->length, nullptr)) + if (!EC_POINT_oct2point(group.data(), generator.data(), mBasePoint->data, static_cast(mBasePoint->length), nullptr)) { qCCritical(card) << "Cannot convert generator"; return; @@ -195,7 +195,7 @@ void EcdsaPublicKey::initEcKey() } QSharedPointer publicPoint = EcUtil::create(EC_POINT_new(group.data())); - if (!EC_POINT_oct2point(group.data(), publicPoint.data(), mPublicPoint->data, mPublicPoint->length, nullptr)) + if (!EC_POINT_oct2point(group.data(), publicPoint.data(), mPublicPoint->data, static_cast(mPublicPoint->length), nullptr)) { qCCritical(card) << "Cannot convert public point"; return; diff --git a/src/card/base/asn1/PACEInfo.cpp b/src/card/base/asn1/PACEInfo.cpp index 5edc1cd..e9e30be 100644 --- a/src/card/base/asn1/PACEInfo.cpp +++ b/src/card/base/asn1/PACEInfo.cpp @@ -74,7 +74,7 @@ bool PACEInfo::acceptsProtocol(const ASN1_OBJECT* pObjectIdentifier) } -PACEInfo::PACEInfo(QSharedPointer pDelegate) +PACEInfo::PACEInfo(const QSharedPointer& pDelegate) : SecurityInfo() , mDelegate(pDelegate) { diff --git a/src/card/base/asn1/PACEInfo.h b/src/card/base/asn1/PACEInfo.h index 0789835..e39e9b4 100644 --- a/src/card/base/asn1/PACEInfo.h +++ b/src/card/base/asn1/PACEInfo.h @@ -63,9 +63,9 @@ DECLARE_ASN1_FUNCTIONS(paceinfo_st) class PACEInfo : public SecurityInfo { - const QSharedPointer mDelegate; + const QSharedPointer mDelegate; - PACEInfo(QSharedPointer pDelegate); + PACEInfo(const QSharedPointer& pDelegate); ASN1_OBJECT* getProtocolObjectIdentifier() const override; @@ -74,7 +74,7 @@ class PACEInfo public: static QSharedPointer decode(const QByteArray& pBytes) { - if (QSharedPointer delegate = decodeObject(pBytes)) + if (const auto& delegate = decodeObject(pBytes)) { if (PACEInfo::acceptsProtocol(delegate->mProtocol)) { diff --git a/src/card/base/asn1/SecurityInfo.cpp b/src/card/base/asn1/SecurityInfo.cpp index 75078d1..d5ba44c 100644 --- a/src/card/base/asn1/SecurityInfo.cpp +++ b/src/card/base/asn1/SecurityInfo.cpp @@ -47,7 +47,7 @@ SecurityInfo::SecurityInfo() } -SecurityInfo::SecurityInfo(QSharedPointer pDelegate) +SecurityInfo::SecurityInfo(const QSharedPointer& pDelegate) : mDelegate(pDelegate) { Q_ASSERT(pDelegate != nullptr); @@ -75,26 +75,3 @@ QByteArray SecurityInfo::getProtocol() const SecurityInfo::~SecurityInfo() { } - - -QSharedPointer SecurityInfoFactory::createSecurityInfo(const QByteArray& pBytes) -{ - if (QSharedPointer pi = PACEInfo::decode(pBytes)) - { - qCDebug(card) << "Parsed PACEInfo"; - return pi; - } - else if (QSharedPointer cai = ChipAuthenticationInfo::decode(pBytes)) - { - qCDebug(card) << "Parsed ChipAuthenticationInfo"; - return cai; - } - - if (QSharedPointer secInfo = SecurityInfo::decode(pBytes)) - { - qCDebug(card) << "Parsed SecurityInfo for protocol" << secInfo->getProtocol(); - return secInfo; - } - qCCritical(card) << "Cannot parse as SecurityInfo" << pBytes.toHex(); - return QSharedPointer(); -} diff --git a/src/card/base/asn1/SecurityInfo.h b/src/card/base/asn1/SecurityInfo.h index b24ecdf..49584bf 100644 --- a/src/card/base/asn1/SecurityInfo.h +++ b/src/card/base/asn1/SecurityInfo.h @@ -44,9 +44,9 @@ DECLARE_STACK_OF(securityinfo_st) */ class SecurityInfo { - const QSharedPointer mDelegate; + const QSharedPointer mDelegate; - SecurityInfo(QSharedPointer pDelegate); + SecurityInfo(const QSharedPointer& pDelegate); Q_DISABLE_COPY(SecurityInfo) /* @@ -61,7 +61,7 @@ class SecurityInfo public: static QSharedPointer decode(const QByteArray& pBytes) { - if (QSharedPointer delegate = decodeObject(pBytes)) + if (const auto& delegate = decodeObject(pBytes)) { return QSharedPointer(new SecurityInfo(delegate)); } @@ -83,12 +83,6 @@ class SecurityInfo }; -class SecurityInfoFactory -{ - public: - static QSharedPointer createSecurityInfo(const QByteArray& pBytes); -}; - DECLARE_ASN1_OBJECT(securityinfo_st) } /* namespace governikus */ diff --git a/src/card/base/asn1/SecurityInfos.cpp b/src/card/base/asn1/SecurityInfos.cpp index 14fc7b2..483e666 100644 --- a/src/card/base/asn1/SecurityInfos.cpp +++ b/src/card/base/asn1/SecurityInfos.cpp @@ -44,27 +44,51 @@ QSharedPointer SecurityInfos::decode(const QByteArray& pBytes) return QSharedPointer(); } - QVector > securityInfos; + QVector > securityInfos; + QVector > paceInfos; + QVector > chipAuthenticationInfos; for (int i = 0; i < SKM_sk_num(securityinfo_st, securityInfosStruct.data()); ++i) { securityinfo_st* secInfoStruct = SKM_sk_value(securityinfo_st, securityInfosStruct.data(), i); - QByteArray secInfoStructBytes = encodeObject(secInfoStruct); - auto securityInfo = SecurityInfoFactory::createSecurityInfo(secInfoStructBytes); - if (securityInfo == nullptr) + QByteArray bytes = encodeObject(secInfoStruct); + + if (auto pi = PACEInfo::decode(bytes)) { + qCDebug(card) << "Parsed PACEInfo"; + paceInfos << pi; + securityInfos << pi; + } + else if (auto cai = ChipAuthenticationInfo::decode(bytes)) + { + qCDebug(card) << "Parsed ChipAuthenticationInfo"; + chipAuthenticationInfos << cai; + securityInfos << cai; + } + else if (auto secInfo = SecurityInfo::decode(bytes)) + { + qCDebug(card) << "Parsed SecurityInfo for protocol" << secInfo->getProtocol(); + securityInfos << secInfo; + } + else + { + qCCritical(card) << "Cannot parse as SecurityInfo" << pBytes.toHex(); return QSharedPointer(); } - securityInfos += securityInfo; } - return QSharedPointer(new SecurityInfos(pBytes, securityInfos)); + return QSharedPointer(new SecurityInfos(pBytes, securityInfos, paceInfos, chipAuthenticationInfos)); } -SecurityInfos::SecurityInfos(const QByteArray& pBytes, const QVector >& pSecurityInfos) +SecurityInfos::SecurityInfos(const QByteArray& pBytes, + const QVector >& pSecurityInfos, + const QVector >& pPACEInfos, + const QVector >& pChipAuthenticationInfos) : mContentBytes(pBytes) , mSecurityInfos(pSecurityInfos) + , mPACEInfos(pPACEInfos) + , mChipAuthenticationInfos(pChipAuthenticationInfos) { } @@ -73,3 +97,21 @@ const QByteArray& SecurityInfos::getContentBytes() const { return mContentBytes; } + + +const QVector >& SecurityInfos::getSecurityInfos() const +{ + return mSecurityInfos; +} + + +const QVector >& SecurityInfos::getPACEInfos() const +{ + return mPACEInfos; +} + + +const QVector >& SecurityInfos::getChipAuthenticationInfos() const +{ + return mChipAuthenticationInfos; +} diff --git a/src/card/base/asn1/SecurityInfos.h b/src/card/base/asn1/SecurityInfos.h index d27bb91..a5c0b92 100644 --- a/src/card/base/asn1/SecurityInfos.h +++ b/src/card/base/asn1/SecurityInfos.h @@ -8,6 +8,8 @@ #pragma once +#include "ChipAuthenticationInfo.h" +#include "PACEInfo.h" #include "SecurityInfo.h" #include @@ -30,33 +32,24 @@ DECLARE_ASN1_OBJECT(securityinfos_st) class SecurityInfos { const QByteArray mContentBytes; - const QVector > mSecurityInfos; + const QVector > mSecurityInfos; + const QVector > mPACEInfos; + const QVector > mChipAuthenticationInfos; - SecurityInfos(const QByteArray& pBytes, const QVector >& pSecurityInfos); + SecurityInfos(const QByteArray& pBytes, + const QVector >& pSecurityInfos, + const QVector >& pPACEInfos, + const QVector >& pChipAuthenticationInfos); Q_DISABLE_COPY(SecurityInfos) public: static QSharedPointer fromHex(const QByteArray& pHexString); static QSharedPointer decode(const QByteArray& pBytes); - template QVector > getSecurityInfos() const - { - QVector > list; - for (const auto& elem : mSecurityInfos) - { - const auto castedElem = elem.dynamicCast(); - if (castedElem.isNull()) - { - // cast failed, e.g. it's not of type T, so skip this element - continue; - } - list += castedElem; - } - return list; - } - - const QByteArray& getContentBytes() const; + const QVector >& getSecurityInfos() const; + const QVector >& getPACEInfos() const; + const QVector >& getChipAuthenticationInfos() const; }; diff --git a/src/card/base/asn1/SignatureChecker.cpp b/src/card/base/asn1/SignatureChecker.cpp index 1328c0c..d205ffe 100644 --- a/src/card/base/asn1/SignatureChecker.cpp +++ b/src/card/base/asn1/SignatureChecker.cpp @@ -21,11 +21,6 @@ SignatureChecker::SignatureChecker(const QVector > } -SignatureChecker::~SignatureChecker() -{ -} - - bool SignatureChecker::check() { if (mCertificateChain.isEmpty()) @@ -61,7 +56,7 @@ bool SignatureChecker::check() } -bool SignatureChecker::checkSignature(QSharedPointer pCert, QSharedPointer pSigningCert, const EC_KEY* pKey) +bool SignatureChecker::checkSignature(const QSharedPointer& pCert, const QSharedPointer& pSigningCert, const EC_KEY* pKey) { // We duplicate the key because we modify it by setting the public point. QSharedPointer signingKey = EcUtil::create(EC_KEY_dup(pKey)); @@ -69,7 +64,7 @@ bool SignatureChecker::checkSignature(QSharedPointer pCert, QShar QByteArray uncompPublicPoint = pSigningCert->getBody().getPublicKey().getUncompressedPublicPoint(); const unsigned char* uncompPublicPointData = reinterpret_cast(uncompPublicPoint.constData()); - int uncompPublicPointLen = uncompPublicPoint.size(); + size_t uncompPublicPointLen = static_cast(uncompPublicPoint.size()); EC_POINT* publicPoint = EC_POINT_new(EC_KEY_get0_group(signingKey.data())); const EC_GROUP* ecGroup = EC_KEY_get0_group(signingKey.data()); diff --git a/src/card/base/asn1/SignatureChecker.h b/src/card/base/asn1/SignatureChecker.h index 01b4984..b142375 100644 --- a/src/card/base/asn1/SignatureChecker.h +++ b/src/card/base/asn1/SignatureChecker.h @@ -17,11 +17,11 @@ class SignatureChecker private: const QVector > mCertificateChain; - bool checkSignature(QSharedPointer pCert, QSharedPointer pSigningCert, const EC_KEY* pKey); + bool checkSignature(const QSharedPointer& pCert, const QSharedPointer& pSigningCert, const EC_KEY* pKey); public: SignatureChecker(const QVector >& pCertificateChain); - virtual ~SignatureChecker(); + ~SignatureChecker() = default; bool check(); }; diff --git a/src/card/base/command/BaseCardCommand.cpp b/src/card/base/command/BaseCardCommand.cpp index 387bc23..2ac6d39 100644 --- a/src/card/base/command/BaseCardCommand.cpp +++ b/src/card/base/command/BaseCardCommand.cpp @@ -16,10 +16,9 @@ using namespace governikus; BaseCardCommand::BaseCardCommand(QSharedPointer pCardConnectionWorker) : mCardConnectionWorker(pCardConnectionWorker) - , mReturnCode(ReturnCode::UNKNOWN) + , mReturnCode(CardReturnCode::UNKNOWN) { Q_ASSERT(mCardConnectionWorker); - qRegisterMetaType >("QSharedPointer"); } @@ -40,10 +39,10 @@ void BaseCardCommand::execute() } -ReturnCode BaseCardCommand::checkRetryCounterAndPrepareForPace(const QString& pCan) +CardReturnCode BaseCardCommand::checkRetryCounterAndPrepareForPace(const QString& pCan) { - ReturnCode returnCode = mCardConnectionWorker->updateRetryCounter(); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = mCardConnectionWorker->updateRetryCounter(); + if (returnCode != CardReturnCode::OK) { return returnCode; } @@ -58,10 +57,21 @@ ReturnCode BaseCardCommand::checkRetryCounterAndPrepareForPace(const QString& pC case 2: case 3: // only PIN required - return ReturnCode::OK; + return CardReturnCode::OK; default: qCWarning(card) << "Card blocked or deactivated."; - return ReturnCode::PIN_BLOCKED; + return CardReturnCode::PIN_BLOCKED; + } +} + + +void BaseCardCommand::registerMetaTypes() +{ + static bool registered = false; + if (!registered) + { + qRegisterMetaType >("QSharedPointer"); + registered = true; } } diff --git a/src/card/base/command/BaseCardCommand.h b/src/card/base/command/BaseCardCommand.h index a2cffaa..0f54255 100644 --- a/src/card/base/command/BaseCardCommand.h +++ b/src/card/base/command/BaseCardCommand.h @@ -7,7 +7,7 @@ #pragma once #include "CardConnectionWorker.h" -#include "ReturnCode.h" +#include "CardReturnCode.h" #include @@ -30,22 +30,24 @@ class BaseCardCommand protected: QSharedPointer mCardConnectionWorker; - ReturnCode mReturnCode; + CardReturnCode mReturnCode; BaseCardCommand(QSharedPointer pCardConnectionWorker); - ReturnCode checkRetryCounterAndPrepareForPace(const QString& pCan); + CardReturnCode checkRetryCounterAndPrepareForPace(const QString& pCan); virtual void internalExecute() = 0; virtual ~BaseCardCommand(); public: - ReturnCode getReturnCode() const + CardReturnCode getReturnCode() const { return mReturnCode; } + static void registerMetaTypes(); + Q_SIGNALS: void commandDone(QSharedPointer pCommand); }; diff --git a/src/card/base/command/CreateCardConnectionCommand.cpp b/src/card/base/command/CreateCardConnectionCommand.cpp index a06afcf..c2f90b7 100644 --- a/src/card/base/command/CreateCardConnectionCommand.cpp +++ b/src/card/base/command/CreateCardConnectionCommand.cpp @@ -17,7 +17,6 @@ CreateCardConnectionCommand::CreateCardConnectionCommand(const QString& pReaderN , mReaderManagerWorker(pReaderManagerWorker) , mCardConnection(nullptr) { - qRegisterMetaType >("QSharedPointer"); } @@ -54,3 +53,14 @@ QSharedPointer CreateCardConnectionCommand::getCardConnection() { return mCardConnection; } + + +void CreateCardConnectionCommand::registerMetaTypes() +{ + static bool registered = false; + if (!registered) + { + qRegisterMetaType >("QSharedPointer"); + registered = true; + } +} diff --git a/src/card/base/command/CreateCardConnectionCommand.h b/src/card/base/command/CreateCardConnectionCommand.h index 8f83c05..58f5230 100644 --- a/src/card/base/command/CreateCardConnectionCommand.h +++ b/src/card/base/command/CreateCardConnectionCommand.h @@ -36,6 +36,7 @@ class CreateCardConnectionCommand CreateCardConnectionCommand(const QString& pReaderName, const QPointer& pReaderManagerWorker); Q_INVOKABLE void execute(); QSharedPointer getCardConnection() const; + static void registerMetaTypes(); private Q_SLOTS: void onCardConnectionWorkerCreated(QSharedPointer pCardConnectionWorker); diff --git a/src/card/base/command/DestroyPaceChannelCommand.cpp b/src/card/base/command/DestroyPaceChannelCommand.cpp index 571fb8a..e68cae4 100644 --- a/src/card/base/command/DestroyPaceChannelCommand.cpp +++ b/src/card/base/command/DestroyPaceChannelCommand.cpp @@ -24,5 +24,5 @@ DestroyPaceChannelCommand::~DestroyPaceChannelCommand() void DestroyPaceChannelCommand::internalExecute() { - mCardConnectionWorker->destroyPaceChannel(); + mReturnCode = mCardConnectionWorker->destroyPaceChannel(); } diff --git a/src/card/base/command/DidAuthenticateEAC1Command.cpp b/src/card/base/command/DidAuthenticateEAC1Command.cpp index ac02e84..8d4bc14 100644 --- a/src/card/base/command/DidAuthenticateEAC1Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC1Command.cpp @@ -33,10 +33,10 @@ void DidAuthenticateEAC1Command::internalExecute() { GetChallengeResponse response; mReturnCode = mCardConnectionWorker->transmit(GetChallengeBuilder().build(), response); - if (mReturnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + if (mReturnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "GetChallenge failed"; - mReturnCode = ReturnCode::GET_CHALLENGE_FAILED; + mReturnCode = CardReturnCode::GET_CHALLENGE_FAILED; return; } mChallenge = response.getChallenge(); diff --git a/src/card/base/command/DidAuthenticateEAC2Command.cpp b/src/card/base/command/DidAuthenticateEAC2Command.cpp index f8e0b47..c0034b0 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC2Command.cpp @@ -7,7 +7,6 @@ #include "CardConnection.h" #include "DidAuthenticateEAC2Command.h" #include "GeneralAuthenticateResponse.h" -#include "ReturnCodeUtil.h" #include "asn1/ChipAuthenticationInfo.h" #include "asn1/EFCardSecurity.h" @@ -44,7 +43,7 @@ DidAuthenticateEAC2Command::~DidAuthenticateEAC2Command() void DidAuthenticateEAC2Command::internalExecute() { mReturnCode = putCertificateChain(mCvcChain); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { return; } @@ -73,7 +72,7 @@ void DidAuthenticateEAC2Command::internalExecute() compressedEphemeralPublicKey, signature); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { return; } @@ -82,40 +81,39 @@ void DidAuthenticateEAC2Command::internalExecute() QByteArray efCardSecurityBytes; qCDebug(card) << "Performing Read EF.CardSecurity"; mReturnCode = mCardConnectionWorker->readFile(FileRef::efCardSecurity(), efCardSecurityBytes); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { return; } - mEfCardSecurityAsHex.append(efCardSecurityBytes.toHex()); + mEfCardSecurityAsHex += efCardSecurityBytes.toHex(); QSharedPointer efCardSecurity = EFCardSecurity::decode(efCardSecurityBytes); if (efCardSecurity == nullptr) { qCCritical(card) << "Cannot parse EF.CardSecurity"; - mReturnCode = ReturnCode::PROTOCOL_ERROR; + mReturnCode = CardReturnCode::PROTOCOL_ERROR; return; } - QVector > chipAuthenticationInfoList = efCardSecurity->getSecurityInfos(); + const auto& chipAuthenticationInfoList = efCardSecurity->getSecurityInfos()->getChipAuthenticationInfos(); if (chipAuthenticationInfoList.isEmpty()) { qCCritical(card) << "No ChipAuthenticationInfo found in EF.CardAccess"; - mReturnCode = ReturnCode::PROTOCOL_ERROR; + mReturnCode = CardReturnCode::PROTOCOL_ERROR; return; } // we do not know of any procedural rule to determine the ChipAuthenticationInfo, so we just take the first one - QSharedPointer chipAuthenticationInfo = chipAuthenticationInfoList.at(0); + const auto& chipAuthenticationInfo = chipAuthenticationInfoList.at(0); qCDebug(card) << "Chose ChipAuthenticationInfo(0): protocol" << chipAuthenticationInfo->getProtocol() << ", keyId" << chipAuthenticationInfo->getKeyId().toHex(); mReturnCode = performChipAuthentication(chipAuthenticationInfo, ephemeralPublicKey, mNonceAsHex, mAuthTokenAsHex); - if (ReturnCode::OK == mReturnCode) + if (CardReturnCode::OK == mReturnCode) { mCardConnectionWorker->stopSecureMessaging(); } - return; } -ReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertificateChain& pCvcChain) +CardReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertificateChain& pCvcChain) { for (const auto& cvCertificate : pCvcChain) { @@ -126,8 +124,8 @@ ReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertificateCh ResponseApdu mseResult; qCDebug(card) << "Performing TA MSE:Set DST"; qCDebug(card) << "Sending CAR" << car; - ReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); + if (returnCode != CardReturnCode::OK) { qCWarning(card) << "TA MSE:Set DST failed."; return returnCode; @@ -136,18 +134,18 @@ ReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertificateCh if (mseResult.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "TA MSE:Set DST failed: " << mseResult.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } PSOBuilder psoBuilder(PSOBuilder::P1::VERIFY, PSOBuilder::P2::CERTIFICATE); - psoBuilder.setCertificateBody(cvCertificate->getRawBody(), true); - psoBuilder.setSignature(cvCertificate->getRawSignature(), true); + psoBuilder.setCertificateBody(cvCertificate->getRawBody()); + psoBuilder.setSignature(cvCertificate->getRawSignature()); qCDebug(card) << "Performing TA PSO:Verify Certificate"; qCDebug(card) << "Sending certificate" << *cvCertificate; ResponseApdu psoResult; returnCode = mCardConnectionWorker->transmit(psoBuilder.build(), psoResult); - if (returnCode != ReturnCode::OK) + if (returnCode != CardReturnCode::OK) { return returnCode; } @@ -155,15 +153,15 @@ ReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertificateCh if (psoResult.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "TA PSO:Verify Certificate failed: " << psoResult.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } } - return ReturnCode::OK; + return CardReturnCode::OK; } -ReturnCode DidAuthenticateEAC2Command::performTerminalAuthentication(const QByteArray& taProtocol, +CardReturnCode DidAuthenticateEAC2Command::performTerminalAuthentication(const QByteArray& taProtocol, const QByteArray& chr, const QByteArray& auxiliaryData, const QByteArray& compressedEphemeralPublicKey, @@ -173,21 +171,21 @@ ReturnCode DidAuthenticateEAC2Command::performTerminalAuthentication(const QByte MSEBuilder mseBuilder(MSEBuilder::P1::SET_DST, MSEBuilder::P2::SET_AT); mseBuilder.setOid(taProtocol); mseBuilder.setPublicKey(chr); - mseBuilder.setAuxiliaryData(auxiliaryData, true); + mseBuilder.setAuxiliaryData(auxiliaryData); mseBuilder.setEphemeralPublicKey(compressedEphemeralPublicKey); ResponseApdu mseResult; qCDebug(card) << "Performing TA MSE:Set AT"; - ReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); + if (returnCode != CardReturnCode::OK) { - qCWarning(card) << "TA MSE:Set AT failed: " << ReturnCodeUtil::toString(returnCode); + qCWarning(card) << "TA MSE:Set AT failed: " << CardReturnCodeUtil::toGlobalStatus(returnCode); return returnCode; } if (mseResult.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "TA MSE:Set AT failed: " << mseResult.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } ResponseApdu eaResult; @@ -195,22 +193,22 @@ ReturnCode DidAuthenticateEAC2Command::performTerminalAuthentication(const QByte eaBuilder.setSignature(signature); qCDebug(card) << "Performing TA External Authenticate"; returnCode = mCardConnectionWorker->transmit(eaBuilder.build(), eaResult); - if (returnCode != ReturnCode::OK) + if (returnCode != CardReturnCode::OK) { - qCWarning(card) << "TA External Authenticate failed: " << ReturnCodeUtil::toString(returnCode); + qCWarning(card) << "TA External Authenticate failed: " << CardReturnCodeUtil::toGlobalStatus(returnCode); return returnCode; } if (eaResult.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "TA External Authenticate failed: " << eaResult.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } - return ReturnCode::OK; + return CardReturnCode::OK; } -ReturnCode DidAuthenticateEAC2Command::performChipAuthentication(QSharedPointer pChipAuthInfo, +CardReturnCode DidAuthenticateEAC2Command::performChipAuthentication(QSharedPointer pChipAuthInfo, const QByteArray& ephemeralPublicKey, QByteArray& pNonceAsHex, QByteArray& pAuthTokenAsHex) @@ -221,15 +219,15 @@ ReturnCode DidAuthenticateEAC2Command::performChipAuthentication(QSharedPointer< mseBuilder.setPrivateKey(pChipAuthInfo->getKeyId()); qCDebug(card) << "Performing CA MSE:Set AT"; - ReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), mseResult); + if (returnCode != CardReturnCode::OK) { return returnCode; } if (mseResult.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "CA MSE:Set AT failed: " << mseResult.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } GAChipAuthenticationResponse gaResponse; @@ -238,17 +236,17 @@ ReturnCode DidAuthenticateEAC2Command::performChipAuthentication(QSharedPointer< qCDebug(card) << "Performing CA General Authenticate"; returnCode = mCardConnectionWorker->transmit(gaBuilder.build(), gaResponse); - if (returnCode != ReturnCode::OK) + if (returnCode != CardReturnCode::OK) { return returnCode; } if (gaResponse.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "CA General Authenticate failed: " << gaResponse.getReturnCode(); - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } - pNonceAsHex.append(gaResponse.getNonce().toHex()); - pAuthTokenAsHex.append(gaResponse.getAuthenticationToken().toHex()); + pNonceAsHex += gaResponse.getNonce().toHex(); + pAuthTokenAsHex += gaResponse.getAuthenticationToken().toHex(); - return ReturnCode::OK; + return CardReturnCode::OK; } diff --git a/src/card/base/command/DidAuthenticateEAC2Command.h b/src/card/base/command/DidAuthenticateEAC2Command.h index a112453..1299fa1 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.h +++ b/src/card/base/command/DidAuthenticateEAC2Command.h @@ -31,13 +31,13 @@ class DidAuthenticateEAC2Command QByteArray mNonceAsHex; QByteArray mAuthTokenAsHex; - ReturnCode putCertificateChain(const CVCertificateChain& pCvcChain); - ReturnCode performTerminalAuthentication(const QByteArray& taProtocol, + CardReturnCode putCertificateChain(const CVCertificateChain& pCvcChain); + CardReturnCode performTerminalAuthentication(const QByteArray& taProtocol, const QByteArray& chr, const QByteArray& auxiliaryData, const QByteArray& compressedEphemeralPublicKey, const QByteArray& signature); - ReturnCode performChipAuthentication(QSharedPointer pChipAuthInfo, + CardReturnCode performChipAuthentication(QSharedPointer pChipAuthInfo, const QByteArray& ephemeralPublicKey, QByteArray& pNonceAsHex, QByteArray& pAuthTokenAsHex); diff --git a/src/card/base/command/SetEidPinCommand.cpp b/src/card/base/command/SetEidPinCommand.cpp index 3d256dd..5cf6d8f 100644 --- a/src/card/base/command/SetEidPinCommand.cpp +++ b/src/card/base/command/SetEidPinCommand.cpp @@ -12,7 +12,7 @@ using namespace governikus; SetEidPinCommand::SetEidPinCommand(QSharedPointer pCardConnectionWorker, - const QString& pNewPin, unsigned int pTimeoutSeconds) + const QString& pNewPin, quint8 pTimeoutSeconds) : BaseCardCommand(pCardConnectionWorker) , mNewPin(pNewPin) , mTimeoutSeconds(pTimeoutSeconds) diff --git a/src/card/base/command/SetEidPinCommand.h b/src/card/base/command/SetEidPinCommand.h index c75c1cb..7873b46 100644 --- a/src/card/base/command/SetEidPinCommand.h +++ b/src/card/base/command/SetEidPinCommand.h @@ -21,10 +21,8 @@ class SetEidPinCommand Q_OBJECT private: - /* QString mOldPin; */ QString mNewPin; - /* QString mCan; */ - unsigned int mTimeoutSeconds; + quint8 mTimeoutSeconds; protected: virtual void internalExecute() override; @@ -32,7 +30,7 @@ class SetEidPinCommand public: SetEidPinCommand(QSharedPointer pCardConnectionWorker, - const QString& pNewPin, unsigned int pTimeoutSeconds = 90); + const QString& pNewPin, quint8 pTimeoutSeconds); }; } /* namespace governikus */ diff --git a/src/card/base/command/TransmitCommand.cpp b/src/card/base/command/TransmitCommand.cpp index c7bd3b5..eb3b755 100644 --- a/src/card/base/command/TransmitCommand.cpp +++ b/src/card/base/command/TransmitCommand.cpp @@ -5,9 +5,8 @@ */ #include "CardConnection.h" +#include "CardReturnCode.h" #include "InputAPDUInfo.h" -#include "ReturnCode.h" -#include "ReturnCodeUtil.h" #include "TransmitCommand.h" #include @@ -43,13 +42,14 @@ void TransmitCommand::internalExecute() CommandApdu request(QByteArray::fromHex(inputApduInfo.getInputApdu())); mReturnCode = mCardConnectionWorker->transmit(request, response); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { - qCWarning(card) << "Transmit unsuccessful. Return code " << ReturnCodeUtil::toString(mReturnCode); + qCWarning(card) << "Transmit unsuccessful. Return code:" << CardReturnCodeUtil::toGlobalStatus(mReturnCode); + return; } - mOutputApduAsHex.append(response.getBuffer().toHex()); + mOutputApduAsHex += response.getBuffer().toHex(); if (!inputApduInfo.getAcceptableStatusCodes().isEmpty()) { bool isAcceptable = false; @@ -72,11 +72,11 @@ void TransmitCommand::internalExecute() if (!isAcceptable) { qCWarning(card) << "Transmit unsuccessful. StatusCode does not start with acceptable status code" << inputApduInfo.getAcceptableStatusCodes(); - mReturnCode = ReturnCode::UNEXPECTED_TRANSMIT_STATUS; + mReturnCode = CardReturnCode::UNEXPECTED_TRANSMIT_STATUS; return; } } } qCDebug(card) << "transmit end"; - mReturnCode = ReturnCode::OK; + mReturnCode = CardReturnCode::OK; } diff --git a/src/card/base/command/UnblockPinCommand.cpp b/src/card/base/command/UnblockPinCommand.cpp index d45461d..96d6aa7 100644 --- a/src/card/base/command/UnblockPinCommand.cpp +++ b/src/card/base/command/UnblockPinCommand.cpp @@ -27,20 +27,20 @@ UnblockPinCommand::~UnblockPinCommand() void UnblockPinCommand::internalExecute() { mReturnCode = mCardConnectionWorker->updateRetryCounter(); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { return; } if (mCardConnectionWorker->getReaderInfo().getRetryCounter() != 0 || mCardConnectionWorker->getReaderInfo().isPinDeactivated()) { - mReturnCode = ReturnCode::PIN_NOT_BLOCKED; + mReturnCode = CardReturnCode::PIN_NOT_BLOCKED; return; } EstablishPACEChannelOutput output; mReturnCode = mCardConnectionWorker->establishPaceChannel(PACE_PIN_ID::PACE_PUK, mPuk, output); - if (mReturnCode != ReturnCode::OK) + if (mReturnCode != CardReturnCode::OK) { return; } @@ -48,8 +48,8 @@ void UnblockPinCommand::internalExecute() // unblock PIN (reset retry counter) ResponseApdu response; mReturnCode = mCardConnectionWorker->transmit(ResetRetryCounterBuilder().build(), response); - if (mReturnCode == ReturnCode::OK && response.getSW1() == EnumSW1::getValue(SW1::ERROR_COMMAND_NOT_ALLOWED)) + if (mReturnCode == CardReturnCode::OK && response.getSW1() == Enum::getValue(SW1::ERROR_COMMAND_NOT_ALLOWED)) { - mReturnCode = ReturnCode::PUK_INOPERATIVE; + mReturnCode = CardReturnCode::PUK_INOPERATIVE; } } diff --git a/src/card/base/pace/CipherMac.cpp b/src/card/base/pace/CipherMac.cpp index dbb951c..113dca9 100644 --- a/src/card/base/pace/CipherMac.cpp +++ b/src/card/base/pace/CipherMac.cpp @@ -54,7 +54,7 @@ CipherMac::CipherMac(const QByteArray& pPaceAlgorithm, const QByteArray& pKeyByt return; } mCtx = CMAC_CTX_new(); - if (!CMAC_Init(mCtx, pKeyBytes.constData(), pKeyBytes.size(), cipher, nullptr)) + if (!CMAC_Init(mCtx, mKeyBytes.constData(), static_cast(mKeyBytes.size()), cipher, nullptr)) { qCCritical(card) << "Error on CMAC_Init"; } @@ -91,7 +91,7 @@ QByteArray CipherMac::generate(const QByteArray& pMessage) return QByteArray(); } - if (!CMAC_Update(mCtx, pMessage.constData(), pMessage.size())) + if (!CMAC_Update(mCtx, pMessage.constData(), static_cast(pMessage.size()))) { qCCritical(card) << "Error on CMAC_Update"; return QByteArray(); @@ -104,15 +104,26 @@ QByteArray CipherMac::generate(const QByteArray& pMessage) return QByteArray(); } - Q_ASSERT(mac_len > 0); - QVector mac(mac_len); + if (mac_len <= 0) + { + qCCritical(card) << "Got negative mac_len" << mac_len; + Q_ASSERT(mac_len > 0); + return QByteArray(); + } + if (mac_len > INT_MAX) + { + qCCritical(card) << "mac_len out of range" << mac_len; + Q_ASSERT(mac_len <= INT_MAX); + return QByteArray(); + } + QVector mac(static_cast(mac_len)); if (!CMAC_Final(mCtx, mac.data(), &mac_len)) { qCCritical(card) << "Error on CMAC_Final"; return QByteArray(); } - QByteArray value(reinterpret_cast(mac.data()), mac_len); + QByteArray value(reinterpret_cast(mac.data()), static_cast(mac_len)); // Use only 8 bytes, according to TR 03110 Part 3, A.2.4.2, E.2.2.2 return value.left(8); diff --git a/src/card/base/pace/KeyAgreement.cpp b/src/card/base/pace/KeyAgreement.cpp index e386917..e31589a 100644 --- a/src/card/base/pace/KeyAgreement.cpp +++ b/src/card/base/pace/KeyAgreement.cpp @@ -4,7 +4,6 @@ #include "Commands.h" #include "PersoSimWorkaround.h" -#include "ReturnCodeUtil.h" #include "asn1/PACEInfo.h" #include "pace/CipherMac.h" #include "pace/KeyAgreement.h" @@ -22,10 +21,10 @@ Q_DECLARE_LOGGING_CATEGORY(card) template -static QString getResponseErrorString(ReturnCode pReturnCode, const ResponseType& pResponse) +static QString getResponseErrorString(CardReturnCode pReturnCode, const ResponseType& pResponse) { - QString errorString = ReturnCodeUtil::toString(pReturnCode); - if (pReturnCode == ReturnCode::OK) + QString errorString = CardReturnCodeUtil::toGlobalStatus(pReturnCode).toErrorDescription(); + if (pReturnCode == CardReturnCode::OK) { errorString += QStringLiteral(" | ") + pResponse.getReturnCode(); } @@ -33,7 +32,7 @@ static QString getResponseErrorString(ReturnCode pReturnCode, const ResponseType } -QSharedPointer KeyAgreement::create(QSharedPointer pPaceInfo, +QSharedPointer KeyAgreement::create(const QSharedPointer& pPaceInfo, QSharedPointer pCardConnectionWorker) { if (pPaceInfo->getKeyAgreementType() == KeyAgreementType::ECDH) @@ -48,7 +47,7 @@ QSharedPointer KeyAgreement::create(QSharedPointer pPace } -KeyAgreement::KeyAgreement(QSharedPointer pPaceInfo, QSharedPointer pCardConnectionWorker) +KeyAgreement::KeyAgreement(const QSharedPointer& pPaceInfo, const QSharedPointer& pCardConnectionWorker) : mCardConnectionWorker(pCardConnectionWorker) , mEncryptionKey() , mMacKey() @@ -143,8 +142,8 @@ QByteArray KeyAgreement::transmitGAEncryptedNonce() GABuilder builder(CommandApdu::CLA_COMMAND_CHAINING); GAEncryptedNonceResponse response; - ReturnCode returnCode = mCardConnectionWorker->transmit(builder.build(), response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = mCardConnectionWorker->transmit(builder.build(), response); + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCCritical(card) << "Error on GA (Encrypted Nonce):" << getResponseErrorString(returnCode, response); return QByteArray(); @@ -159,8 +158,8 @@ QByteArray KeyAgreement::transmitGAEphemeralPublicKey(const QByteArray& pEphemer commandBuilder.setPaceEphemeralPublicKey(pEphemeralPublicKey); GAPerformKeyAgreementResponse response; - ReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCCritical(card) << "Error on GA(Perform Key Agreement):" << getResponseErrorString(returnCode, response); return QByteArray(); @@ -176,8 +175,8 @@ QByteArray KeyAgreement::transmitGAMappingData(const QByteArray& pMappingData) commandBuilder.setPaceMappingData(pMappingData); GAMapNonceResponse response; - ReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); - if (returnCode != ReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); + if (returnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCCritical(card) << "Error on GA(Mapping Data):" << getResponseErrorString(returnCode, response); return QByteArray(); @@ -192,8 +191,8 @@ QSharedPointer KeyAgreement::transmitGAMutualAut commandBuilder.setPaceAuthenticationToken(pMutualAuthenticationData); QSharedPointer response(new GAMutualAuthenticationResponse()); - ReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), *response); - if (returnCode != ReturnCode::OK || response->getReturnCode() != StatusCode::SUCCESS) + CardReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), *response); + if (returnCode != CardReturnCode::OK || response->getReturnCode() != StatusCode::SUCCESS) { qCCritical(card) << "Error on GA(Mutual Authentication):" << getResponseErrorString(returnCode, *response); } diff --git a/src/card/base/pace/KeyAgreement.h b/src/card/base/pace/KeyAgreement.h index 6e79f43..8a66197 100644 --- a/src/card/base/pace/KeyAgreement.h +++ b/src/card/base/pace/KeyAgreement.h @@ -32,15 +32,15 @@ enum class KeyAgreementStatus class KeyAgreement { private: - QSharedPointer mCardConnectionWorker; + const QSharedPointer mCardConnectionWorker; QByteArray mEncryptionKey; QByteArray mMacKey; QByteArray mCarCurr, mCarPrev; /*! - * \brief Determine the card's nonce. The encrypted nonce will be decrypted using the supplied pin. + * \brief Determine the card's nonce. The encrypted nonce will be decrypted using the supplied PIN. * This represents the first step "General Authenticate" of TR-03110 Part 3, page 47. - * \param pPin pin for decryption of the nonce + * \param pPin PIN for decryption of the nonce * \return the decrypted nonce */ QByteArray determineNonce(const QString& pPin); @@ -74,10 +74,10 @@ class KeyAgreement KeyAgreementStatus performMutualAuthenticate(); protected: - QSharedPointer mPaceInfo; + const QSharedPointer mPaceInfo; KeyDerivationFunction mKeyDerivationFunction; - KeyAgreement(QSharedPointer pPaceInfo, QSharedPointer pCardConnectionWorker); + KeyAgreement(const QSharedPointer& pPaceInfo, const QSharedPointer& pCardConnectionWorker); /*! * \brief Transmit the General Authenticate (Mapping Data) command to the card. @@ -121,7 +121,7 @@ class KeyAgreement * \param pReader the reader to transmit card commands * \return new instance */ - static QSharedPointer create(QSharedPointer pPaceInfo, + static QSharedPointer create(const QSharedPointer& pPaceInfo, QSharedPointer pCardConnectionWorker); virtual ~KeyAgreement(); diff --git a/src/card/base/pace/KeyDerivationFunction.cpp b/src/card/base/pace/KeyDerivationFunction.cpp index 98aee2a..cebfb43 100644 --- a/src/card/base/pace/KeyDerivationFunction.cpp +++ b/src/card/base/pace/KeyDerivationFunction.cpp @@ -81,7 +81,7 @@ QByteArray KeyDerivationFunction::pi(const QString& pSecret) } -QByteArray KeyDerivationFunction::deriveKey(const QByteArray& pK, const QByteArray& pNonce, uint32_t pC) +QByteArray KeyDerivationFunction::deriveKey(const QByteArray& pK, const QByteArray& pNonce, quint32 pC) { if (!isInitialized()) { @@ -90,23 +90,23 @@ QByteArray KeyDerivationFunction::deriveKey(const QByteArray& pK, const QByteArr } QByteArray dataBytes(pK); - dataBytes.append(pNonce); - dataBytes.append((pC >> 24) & 0xFF); - dataBytes.append((pC >> 16) & 0xFF); - dataBytes.append((pC >> 8) & 0xFF); - dataBytes.append(pC & 0xFF); + dataBytes += pNonce; + dataBytes += static_cast((pC >> 24) & 0xFF); + dataBytes += static_cast((pC >> 16) & 0xFF); + dataBytes += static_cast((pC >> 8) & 0xFF); + dataBytes += static_cast(pC & 0xFF); QByteArray hashBytes; if (mHashAlgorithm == QCryptographicHash::Sha1) { char md[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(dataBytes.constData()), dataBytes.size(), reinterpret_cast(md)); + SHA1(reinterpret_cast(dataBytes.constData()), static_cast(dataBytes.size()), reinterpret_cast(md)); hashBytes.append(md, mKeySize); } else if (mHashAlgorithm == QCryptographicHash::Sha256) { char md[SHA256_DIGEST_LENGTH]; - SHA256(reinterpret_cast(dataBytes.constData()), dataBytes.size(), reinterpret_cast(md)); + SHA256(reinterpret_cast(dataBytes.constData()), static_cast(dataBytes.size()), reinterpret_cast(md)); hashBytes.append(md, mKeySize); } return hashBytes; diff --git a/src/card/base/pace/KeyDerivationFunction.h b/src/card/base/pace/KeyDerivationFunction.h index d43804e..37a9735 100644 --- a/src/card/base/pace/KeyDerivationFunction.h +++ b/src/card/base/pace/KeyDerivationFunction.h @@ -20,7 +20,7 @@ class KeyDerivationFunction private: QCryptographicHash::Algorithm mHashAlgorithm; int mKeySize; - QByteArray deriveKey(const QByteArray& pK, const QByteArray& pNonce, uint32_t pC); + QByteArray deriveKey(const QByteArray& pK, const QByteArray& pNonce, quint32 pC); public: /*! diff --git a/src/card/base/pace/PaceHandler.cpp b/src/card/base/pace/PaceHandler.cpp index d5d8272..c0683c7 100644 --- a/src/card/base/pace/PaceHandler.cpp +++ b/src/card/base/pace/PaceHandler.cpp @@ -43,26 +43,26 @@ QByteArray PaceHandler::getPaceProtocol() const } -ReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin) +CardReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin) { auto efCardAccess = mCardConnectionWorker->getReaderInfo().getCardInfo().getEfCardAccess(); if (!efCardAccess) { - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } if (!initialize(efCardAccess)) { - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } if (!transmitMSESetAT(pPinId)) { - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } KeyAgreementStatus keyAgreementStatus = mKeyAgreement->perform(pPin); if (keyAgreementStatus == KeyAgreementStatus::PROTOCOLL_ERROR) { - return ReturnCode::PROTOCOL_ERROR; + return CardReturnCode::PROTOCOL_ERROR; } else if (keyAgreementStatus == KeyAgreementStatus::FAILED) { @@ -71,13 +71,13 @@ ReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& case PACE_PIN_ID::PACE_MRZ: // No separate error code (yet). case PACE_PIN_ID::PACE_CAN: - return ReturnCode::CAN_INVALID; + return CardReturnCode::INVALID_CAN; case PACE_PIN_ID::PACE_PIN: - return ReturnCode::PIN_INVALID; + return CardReturnCode::INVALID_PIN; case PACE_PIN_ID::PACE_PUK: - return ReturnCode::PUK_INVALID; + return CardReturnCode::INVALID_PUK; } } mEncryptionKey = mKeyAgreement->getEncryptionKey(); @@ -86,7 +86,7 @@ ReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& mCarPrev = mKeyAgreement->getCarPrev(); mIdIcc = mKeyAgreement->getCompressedCardPublicKey(); qCDebug(card) << "Pace channel established"; - return ReturnCode::OK; + return CardReturnCode::OK; } @@ -97,7 +97,7 @@ bool PaceHandler::initialize(const QSharedPointer& pEfCardAc return false; } - const auto& infos = pEfCardAccess->getSecurityInfos(); + const auto& infos = pEfCardAccess->getPACEInfos(); for (const auto& paceInfo : infos) { if (isSupportedProtocol(paceInfo)) @@ -117,7 +117,7 @@ bool PaceHandler::initialize(const QSharedPointer& pEfCardAc } -bool PaceHandler::isSupportedProtocol(const QSharedPointer& pPaceInfo) const +bool PaceHandler::isSupportedProtocol(const QSharedPointer& pPaceInfo) const { const auto protocol = pPaceInfo->getProtocol(); @@ -146,12 +146,12 @@ bool PaceHandler::transmitMSESetAT(PACE_PIN_ID pPinId) mseBuilder.setPrivateKey(mPaceInfo->getParameterId()); if (!mChat.isNull()) { - mseBuilder.setChat(mChat, true); + mseBuilder.setChat(mChat); } ResponseApdu response; - ReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), response); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), response); + if (returnCode != CardReturnCode::OK) { qCCritical(card) << "Error on MSE:Set AT"; return false; diff --git a/src/card/base/pace/PaceHandler.h b/src/card/base/pace/PaceHandler.h index 30cb1e9..1dc88c2 100644 --- a/src/card/base/pace/PaceHandler.h +++ b/src/card/base/pace/PaceHandler.h @@ -30,7 +30,7 @@ class PaceHandler private: const QSharedPointer mCardConnectionWorker; QSharedPointer mKeyAgreement; - QSharedPointer mPaceInfo; + QSharedPointer mPaceInfo; QByteArray mIdIcc; QByteArray mEncryptionKey; QByteArray mMacKey; @@ -40,7 +40,7 @@ class PaceHandler /*! * \brief checks for implementation support */ - bool isSupportedProtocol(const QSharedPointer& pPaceInfo) const; + bool isSupportedProtocol(const QSharedPointer& pPaceInfo) const; /*! * \brief Perform initialization of the handler. During initialization the PACE protocol parameters to be used are determined. @@ -67,7 +67,7 @@ class PaceHandler * \param pPin the PIN value, e.g. "123456" * \return false on any errors during establishment */ - ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin); + CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin); /*! * \brief The certificate holder authorization template to be supplied to the card. May be empty diff --git a/src/card/base/pace/SecureMessaging.cpp b/src/card/base/pace/SecureMessaging.cpp index 4bf1a94..dabb461 100644 --- a/src/card/base/pace/SecureMessaging.cpp +++ b/src/card/base/pace/SecureMessaging.cpp @@ -63,9 +63,9 @@ QByteArray SecureMessaging::padToCipherBlockSize(const QByteArray& pData) const int paddingSize = (remainder == 0) ? mCipher.getBlockSize() : mCipher.getBlockSize() - remainder; QByteArray paddedData; - paddedData.append(pData); - paddedData.append(ISO_LEADING_PAD_BYTE); - paddedData.append(QByteArray().fill(ISO_PAD_BYTE, paddingSize - 1)); + paddedData += pData; + paddedData += ISO_LEADING_PAD_BYTE; + paddedData += QByteArray(paddingSize - 1, ISO_PAD_BYTE); return paddedData; } @@ -124,7 +124,7 @@ CommandApdu SecureMessaging::encrypt(const CommandApdu& pCommandApdu) securedLe = encodeObject(protectedLeObject.data()); } QByteArray mac = createMac(securedHeader, formattedEncryptedData, securedLe); - QByteArray securedData = QByteArray().append(formattedEncryptedData).append(securedLe).append(mac); + QByteArray securedData = formattedEncryptedData + securedLe + mac; int newLe = createNewLe(securedData, pCommandApdu.getLe()); return CommandApdu(securedHeader, securedData, newLe); @@ -134,10 +134,10 @@ CommandApdu SecureMessaging::encrypt(const CommandApdu& pCommandApdu) QByteArray SecureMessaging::createSecuredHeader(const CommandApdu& pCommandApdu) const { QByteArray securedHeader; - securedHeader.append((pCommandApdu.getCLA() & 0xF0) | Apdu::CLA_SECURE_MESSAGING); - securedHeader.append(pCommandApdu.getINS()); - securedHeader.append(pCommandApdu.getP1()); - securedHeader.append(pCommandApdu.getP2()); + securedHeader += static_cast((pCommandApdu.getCLA() & 0xF0) | Apdu::CLA_SECURE_MESSAGING); + securedHeader += pCommandApdu.getINS(); + securedHeader += pCommandApdu.getP1(); + securedHeader += pCommandApdu.getP2(); return securedHeader; } @@ -149,9 +149,9 @@ QByteArray SecureMessaging::createSecuredLe(int pLe) { if (pLe > Apdu::SHORT_MAX_LE) { - buffer.append(pLe >> 0x08 & 0xff); + buffer += static_cast(pLe >> 0x08 & 0xff); } - buffer.append(pLe >> 0x00 & 0xff); + buffer += static_cast(pLe >> 0x00 & 0xff); } return buffer; } @@ -163,8 +163,8 @@ QByteArray SecureMessaging::createMac(const QByteArray& pSecuredHeader, { QByteArray dataToMac(pSecuredHeader); dataToMac = padToCipherBlockSize(dataToMac); - dataToMac.append(pFormattedEncryptedData); - dataToMac.append(pSecuredLe); + dataToMac += pFormattedEncryptedData; + dataToMac += pSecuredLe; if (!pFormattedEncryptedData.isNull() || !pSecuredLe.isNull()) { dataToMac = padToCipherBlockSize(dataToMac); @@ -191,7 +191,7 @@ int SecureMessaging::createNewLe(const QByteArray& pSecuredData, int pOldLe) con QByteArray SecureMessaging::getSendSequenceCounter() const { QByteArray ssc = toBigEndian(mSendSequenceCounter); - return QByteArray().fill(0x00, mCipher.getBlockSize() - ssc.size()).append(ssc); + return QByteArray(mCipher.getBlockSize() - ssc.size(), 0x00) + ssc; } @@ -226,9 +226,9 @@ bool SecureMessaging::decrypt(const ResponseApdu& pEncryptedResponseApdu, Respon QByteArray dataToMac; if (!secureResponse.getEncryptedData().isEmpty()) { - dataToMac.append(secureResponse.getEncryptedDataObjectEncoded()); + dataToMac += secureResponse.getEncryptedDataObjectEncoded(); } - dataToMac.append(secureResponse.getSecuredStatusCodeObjectEncoded()); + dataToMac += secureResponse.getSecuredStatusCodeObjectEncoded(); dataToMac = padToCipherBlockSize(dataToMac); dataToMac.prepend(getSendSequenceCounter()); if (mCipherMac.generate(dataToMac) != secureResponse.getMac()) @@ -245,7 +245,7 @@ bool SecureMessaging::decrypt(const ResponseApdu& pEncryptedResponseApdu, Respon decryptedData = unpadFromCipherBlockSize(paddedDecryptedData); } - pDecryptedResponseApdu.setBuffer(decryptedData.append(secureResponse.getSecuredStatusCodeBytes())); + pDecryptedResponseApdu.setBuffer(decryptedData + secureResponse.getSecuredStatusCodeBytes()); qCDebug(secure) << "Plain ResponseApdu: " << pDecryptedResponseApdu.getBuffer().toHex(); diff --git a/src/card/base/pace/ec/EcUtil.h b/src/card/base/pace/ec/EcUtil.h index 168e6a2..4aca7f4 100644 --- a/src/card/base/pace/ec/EcUtil.h +++ b/src/card/base/pace/ec/EcUtil.h @@ -26,9 +26,9 @@ namespace governikus class EcUtil { public: - static QByteArray point2oct(QSharedPointer pCurve, const EC_POINT* pPoint); + static QByteArray point2oct(const QSharedPointer& pCurve, const EC_POINT* pPoint); - static QSharedPointer oct2point(QSharedPointer pCurve, const QByteArray& pCompressedData); + static QSharedPointer oct2point(const QSharedPointer& pCurve, const QByteArray& pCompressedData); static QSharedPointer create(EC_GROUP* pEcGroup); @@ -42,26 +42,39 @@ class EcUtil }; -inline QByteArray EcUtil::point2oct(QSharedPointer pCurve, const EC_POINT* pPoint) +inline QByteArray EcUtil::point2oct(const QSharedPointer& pCurve, const EC_POINT* pPoint) { size_t buf_size = EC_POINT_point2oct(pCurve.data(), pPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); - Q_ASSERT(buf_size > 0); - QVector buf(buf_size); + if (buf_size == 0) + { + qCCritical(card) << "Cannot encode elliptic curve point"; + Q_ASSERT(buf_size != 0); + return QByteArray(); + } + if (buf_size > INT_MAX) + { + qCCritical(card) << "Cannot encode elliptic curve point"; + Q_ASSERT(buf_size <= INT_MAX); + return QByteArray(); + } + + QVector buf(static_cast(buf_size)); if (!EC_POINT_point2oct(pCurve.data(), pPoint, POINT_CONVERSION_UNCOMPRESSED, buf.data(), buf_size, nullptr)) { qCCritical(card) << "Cannot encode elliptic curve point"; + return QByteArray(); } - QByteArray uncompressed(reinterpret_cast(buf.data()), buf_size); + QByteArray uncompressed(reinterpret_cast(buf.data()), static_cast(buf_size)); return uncompressed; } -inline QSharedPointer EcUtil::oct2point(QSharedPointer pCurve, const QByteArray& pCompressedData) +inline QSharedPointer EcUtil::oct2point(const QSharedPointer& pCurve, const QByteArray& pCompressedData) { QSharedPointer point = EcUtil::create(EC_POINT_new(pCurve.data())); - if (!EC_POINT_oct2point(pCurve.data(), point.data(), reinterpret_cast(pCompressedData.constData()), pCompressedData.size(), nullptr)) + if (!EC_POINT_oct2point(pCurve.data(), point.data(), reinterpret_cast(pCompressedData.constData()), static_cast(pCompressedData.size()), nullptr)) { qCCritical(card) << "Cannot decode elliptic curve point"; return QSharedPointer(); diff --git a/src/card/base/pace/ec/EcdhGenericMapping.cpp b/src/card/base/pace/ec/EcdhGenericMapping.cpp index b02fa49..efc4138 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.cpp +++ b/src/card/base/pace/ec/EcdhGenericMapping.cpp @@ -16,7 +16,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -EcdhGenericMapping::EcdhGenericMapping(QSharedPointer pCurve) +EcdhGenericMapping::EcdhGenericMapping(const QSharedPointer& pCurve) : DomainParameterMapping() , mCurve(pCurve) , mTerminalKey() @@ -73,7 +73,7 @@ QSharedPointer EcdhGenericMapping::generateEphemeralDomainParameters(c } -QSharedPointer EcdhGenericMapping::createNewGenerator(QSharedPointer pCardPubKey, QSharedPointer pS) +QSharedPointer EcdhGenericMapping::createNewGenerator(const QSharedPointer& pCardPubKey, const QSharedPointer& pS) { QSharedPointer H = EcUtil::create(EC_POINT_new(mCurve.data())); if (!EC_POINT_mul(mCurve.data(), H.data(), nullptr, pCardPubKey.data(), EC_KEY_get0_private_key(mTerminalKey.data()), nullptr)) @@ -92,7 +92,7 @@ QSharedPointer EcdhGenericMapping::createNewGenerator(QSharedPointer newGenerator) +void EcdhGenericMapping::setGenerator(const QSharedPointer& pNewGenerator) { QSharedPointer curveOrder = EcUtil::create(BN_new()); if (!EC_GROUP_get_order(mCurve.data(), curveOrder.data(), nullptr)) @@ -107,7 +107,7 @@ void EcdhGenericMapping::setGenerator(QSharedPointer newGenerator) return; } // Da Die Kurve Primordnung hat, entspricht die Ordnung des neuen Erzeugers der, des alten Erzeugers - if (!EC_GROUP_set_generator(mCurve.data(), newGenerator.data(), curveOrder.data(), curveCofactor.data())) + if (!EC_GROUP_set_generator(mCurve.data(), pNewGenerator.data(), curveOrder.data(), curveCofactor.data())) { qCCritical(card) << "Error EC_GROUP_set_generator"; return; diff --git a/src/card/base/pace/ec/EcdhGenericMapping.h b/src/card/base/pace/ec/EcdhGenericMapping.h index 8c52d21..76becdd 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.h +++ b/src/card/base/pace/ec/EcdhGenericMapping.h @@ -20,15 +20,15 @@ class EcdhGenericMapping : public DomainParameterMapping { private: - QSharedPointer mCurve; + const QSharedPointer mCurve; QSharedPointer mTerminalKey; - QSharedPointer createNewGenerator(QSharedPointer pCardPubKey, QSharedPointer pS); + QSharedPointer createNewGenerator(const QSharedPointer& pCardPubKey, const QSharedPointer& pS); - void setGenerator(QSharedPointer newGenerator); + void setGenerator(const QSharedPointer& pNewGenerator); public: - EcdhGenericMapping(QSharedPointer pCurve); + EcdhGenericMapping(const QSharedPointer& pCurve); virtual ~EcdhGenericMapping(); QByteArray generateTerminalMappingData() override; diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.cpp b/src/card/base/pace/ec/EcdhKeyAgreement.cpp index e5aa281..d6de17a 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.cpp +++ b/src/card/base/pace/ec/EcdhKeyAgreement.cpp @@ -21,35 +21,54 @@ Q_DECLARE_LOGGING_CATEGORY(card) Q_DECLARE_LOGGING_CATEGORY(secure) -QByteArray EcdhKeyAgreement::encodeUncompressedPublicKey(QSharedPointer pPaceInfo, QSharedPointer pCurve, QSharedPointer pPoint) +QByteArray EcdhKeyAgreement::encodeUncompressedPublicKey(const QSharedPointer& pPaceInfo, const QSharedPointer& pCurve, const QSharedPointer& pPoint) { QByteArray pointBytes = EcUtil::point2oct(pCurve, pPoint.data()); QByteArray publicKeyData; - publicKeyData.append(0x06); - publicKeyData.append(pPaceInfo->getProtocolValueBytes().size()); - publicKeyData.append(pPaceInfo->getProtocolValueBytes()); - publicKeyData.append(char(0x86)); - publicKeyData.append(pointBytes.size()); - publicKeyData.append(pointBytes); + publicKeyData += char(0x06); + const auto& protocolBytes = pPaceInfo->getProtocolValueBytes(); + if (protocolBytes.size() > 0xFF) + { + qCCritical(card) << "Protocol value bytes size > 0xFF not supported"; + Q_ASSERT(protocolBytes.size() <= 0xFF); + return QByteArray(); + } + publicKeyData += static_cast(protocolBytes.size()); + publicKeyData += protocolBytes; + publicKeyData += char(0x86); + if (pointBytes.size() > 0xFF) + { + qCCritical(card) << "Point bytes size > 0xFF not supported"; + Q_ASSERT(pointBytes.size() <= 0xFF); + return QByteArray(); + } + publicKeyData += static_cast(pointBytes.size()); + publicKeyData += pointBytes; QByteArray publicKey; - publicKey.append("\x7f\x49"); - publicKey.append(publicKeyData.size()); - publicKey.append(publicKeyData); + publicKey += QByteArray::fromHex("7F49"); + if (publicKeyData.size() > 0xFF) + { + qCCritical(card) << "Public key bytes size > 0xFF not supported"; + Q_ASSERT(publicKeyData.size() <= 0xFF); + return QByteArray(); + } + publicKey += static_cast(publicKeyData.size()); + publicKey += publicKeyData; return publicKey; } -QByteArray EcdhKeyAgreement::encodeCompressedPublicKey(QSharedPointer pCurve, QSharedPointer pPoint) +QByteArray EcdhKeyAgreement::encodeCompressedPublicKey(const QSharedPointer& pCurve, const QSharedPointer& pPoint) { QByteArray uncompressedPointBytes = EcUtil::point2oct(pCurve, pPoint.data()); return uncompressedPointBytes.mid(1, (uncompressedPointBytes.size() - 1) / 2); } -EcdhKeyAgreement::EcdhKeyAgreement(QSharedPointer pPaceInfo, QSharedPointer pCardConnectionWorker) +EcdhKeyAgreement::EcdhKeyAgreement(const QSharedPointer& pPaceInfo, const QSharedPointer& pCardConnectionWorker) : KeyAgreement(pPaceInfo, pCardConnectionWorker) , mMapping() , mEphemeralCurve() @@ -59,8 +78,8 @@ EcdhKeyAgreement::EcdhKeyAgreement(QSharedPointer pPaceInfo, QSharedPo } -QSharedPointer EcdhKeyAgreement::create(QSharedPointer pPaceInfo, - QSharedPointer pCardConnectionWorker) +QSharedPointer EcdhKeyAgreement::create(const QSharedPointer& pPaceInfo, + const QSharedPointer& pCardConnectionWorker) { QSharedPointer keyAgreement(new EcdhKeyAgreement(pPaceInfo, pCardConnectionWorker)); @@ -120,7 +139,7 @@ QSharedPointer EcdhKeyAgreement::determineEphemeralDomainParameters(co } -QSharedPointer EcdhKeyAgreement::performKeyExchange(QSharedPointer pCurve) +QSharedPointer EcdhKeyAgreement::performKeyExchange(const QSharedPointer& pCurve) { QSharedPointer terminalEphemeralKey = EcUtil::create(EC_KEY_new()); if (!EC_KEY_set_group(terminalEphemeralKey.data(), pCurve.data())) diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.h b/src/card/base/pace/ec/EcdhKeyAgreement.h index 7aef4ef..4759a07 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.h +++ b/src/card/base/pace/ec/EcdhKeyAgreement.h @@ -29,21 +29,21 @@ class EcdhKeyAgreement QSharedPointer mCardPublicKey; QSharedPointer determineEphemeralDomainParameters(const QByteArray& pNonce); - QSharedPointer performKeyExchange(QSharedPointer pCurve); + QSharedPointer performKeyExchange(const QSharedPointer& pCurve); - static QByteArray encodeUncompressedPublicKey(QSharedPointer pPaceInfo, QSharedPointer pCurve, QSharedPointer pPoint); - static QByteArray encodeCompressedPublicKey(QSharedPointer pCurve, QSharedPointer pPoint); + static QByteArray encodeUncompressedPublicKey(const QSharedPointer& pPaceInfo, const QSharedPointer& pCurve, const QSharedPointer& pPoint); + static QByteArray encodeCompressedPublicKey(const QSharedPointer& pCurve, const QSharedPointer& pPoint); QByteArray determineSharedSecret(const QByteArray& pNonce) override; QByteArray getUncompressedTerminalPublicKey() override; QByteArray getUncompressedCardPublicKey() override; QByteArray getCompressedCardPublicKey() override; - EcdhKeyAgreement(QSharedPointer pPaceInfo, QSharedPointer pCardConnectionWorker); + EcdhKeyAgreement(const QSharedPointer& pPaceInfo, const QSharedPointer& pCardConnectionWorker); public: - static QSharedPointer create(QSharedPointer pPaceInfo, - QSharedPointer pCardConnectionWorker); + static QSharedPointer create(const QSharedPointer& pPaceInfo, + const QSharedPointer& pCardConnectionWorker); virtual ~EcdhKeyAgreement(); }; diff --git a/src/card/base/pace/ec/EllipticCurveFactory.cpp b/src/card/base/pace/ec/EllipticCurveFactory.cpp index 9a49313..cb4b899 100644 --- a/src/card/base/pace/ec/EllipticCurveFactory.cpp +++ b/src/card/base/pace/ec/EllipticCurveFactory.cpp @@ -17,7 +17,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -QSharedPointer EllipticCurveFactory::create(QSharedPointer pPaceInfo) +QSharedPointer EllipticCurveFactory::create(const QSharedPointer& pPaceInfo) { if (pPaceInfo->isStandardizedDomainParameters()) { diff --git a/src/card/base/pace/ec/EllipticCurveFactory.h b/src/card/base/pace/ec/EllipticCurveFactory.h index ec0ff72..130f190 100644 --- a/src/card/base/pace/ec/EllipticCurveFactory.h +++ b/src/card/base/pace/ec/EllipticCurveFactory.h @@ -29,7 +29,7 @@ class EllipticCurveFactory * \param pPaceInfo PACEInfo element containing domain parameter * \return elliptic curve object */ - static QSharedPointer create(QSharedPointer pPaceInfo); + static QSharedPointer create(const QSharedPointer& pPaceInfo); /*! * \brief Creates a standardized elliptic curve with specified curve index.. diff --git a/src/card/bluetooth/AndroidBluetoothAdapter.cpp b/src/card/bluetooth/AndroidBluetoothAdapter.cpp index 518995d..e172566 100644 --- a/src/card/bluetooth/AndroidBluetoothAdapter.cpp +++ b/src/card/bluetooth/AndroidBluetoothAdapter.cpp @@ -46,8 +46,11 @@ QBluetoothDeviceInfo::CoreConfiguration AndroidBluetoothAdapter::fromAndroidDevi } -AndroidBluetoothAdapter::AndroidBluetoothAdapter(bool pStateOn, const QVector& pKnownBluetoothDevices) - : mStateOn(pStateOn) +AndroidBluetoothAdapter::AndroidBluetoothAdapter(bool pAvailable, + bool pStateOn, + const QVector& pKnownBluetoothDevices) + : mAvailable(pAvailable) + , mStateOn(pStateOn) , mBondedDevices(pKnownBluetoothDevices) { } @@ -55,42 +58,22 @@ AndroidBluetoothAdapter::AndroidBluetoothAdapter(bool pStateOn, const QVector bondedDevices; #ifdef Q_OS_ANDROID - QAndroidJniEnvironment env; - jclass adapterClass = env->FindClass("android/bluetooth/BluetoothAdapter"); - if (adapterClass == nullptr) + QAndroidJniObject adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter", "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter;"); + + if (!adapter.isValid()) { return AndroidBluetoothAdapter(); } - jmethodID defaultAdapter = env->GetStaticMethodID(adapterClass, "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter;"); - if (defaultAdapter == nullptr) - { - env->DeleteLocalRef(adapterClass); - return AndroidBluetoothAdapter(); - } + available = true; + stateOn = (adapter.callMethod("getState") == STATE_ON); - jobject adapterObject = env->CallStaticObjectMethod(adapterClass, defaultAdapter); - if (adapterObject == nullptr) - { - env->DeleteLocalRef(adapterClass); - return AndroidBluetoothAdapter(); - } - - QAndroidJniObject o(adapterObject); - if (!o.isValid()) - { - env->DeleteLocalRef(adapterObject); - env->DeleteLocalRef(adapterClass); - return AndroidBluetoothAdapter(); - } - - stateOn = (o.callMethod("getState") == STATE_ON); - - QAndroidJniObject deviceSet = o.callObjectMethod("getBondedDevices", "()Ljava/util/Set;"); + QAndroidJniObject deviceSet = adapter.callObjectMethod("getBondedDevices", "()Ljava/util/Set;"); for (QAndroidJniObject iter = deviceSet.callObjectMethod("iterator", "()Ljava/util/Iterator;"); (bool) iter.callMethod("hasNext", "()Z"); ) { QAndroidJniObject device = iter.callObjectMethod("next", "()Ljava/lang/Object;"); @@ -104,16 +87,13 @@ AndroidBluetoothAdapter AndroidBluetoothAdapter::getDefaultAdapter() QBluetoothDeviceInfo deviceInfo(QBluetoothAddress(address), name, deviceClass); deviceInfo.setCoreConfigurations(fromAndroidDeviceType(type)); deviceInfo.setCached(true); - bondedDevices.append(deviceInfo); + bondedDevices += deviceInfo; } - - env->DeleteLocalRef(adapterObject); - env->DeleteLocalRef(adapterClass); #else Q_UNUSED(STATE_ON) #endif - return AndroidBluetoothAdapter(stateOn, bondedDevices); + return AndroidBluetoothAdapter(available, stateOn, bondedDevices); } @@ -127,3 +107,9 @@ bool AndroidBluetoothAdapter::isStateOn() const { return mStateOn; } + + +bool AndroidBluetoothAdapter::isAvailable() const +{ + return mAvailable; +} diff --git a/src/card/bluetooth/AndroidBluetoothAdapter.h b/src/card/bluetooth/AndroidBluetoothAdapter.h index 0bd89b1..e9df1a8 100644 --- a/src/card/bluetooth/AndroidBluetoothAdapter.h +++ b/src/card/bluetooth/AndroidBluetoothAdapter.h @@ -18,12 +18,16 @@ namespace governikus class AndroidBluetoothAdapter { + private: + static QBluetoothDeviceInfo::CoreConfiguration fromAndroidDeviceType(quint32 pAndroidDeviceTypeConstant); - bool mStateOn; - QVector mBondedDevices; + bool mAvailable; + bool mStateOn; + QVector mBondedDevices; - AndroidBluetoothAdapter(bool pStateOn = false, const QVector& pKnownBluetoothDevices = QVector()); - static QBluetoothDeviceInfo::CoreConfiguration fromAndroidDeviceType(quint32 pAndroidDeviceTypeConstant); + AndroidBluetoothAdapter(bool pAvailable = false, + bool pStateOn = false, + const QVector& pKnownBluetoothDevices = QVector()); public: /*! @@ -40,6 +44,8 @@ class AndroidBluetoothAdapter * Returns true, if bluetooth is turned on. */ bool isStateOn() const; + + bool isAvailable() const; }; } /* namespace governikus */ diff --git a/src/card/bluetooth/BluetoothCard.cpp b/src/card/bluetooth/BluetoothCard.cpp index 9969960..be2ff9c 100644 --- a/src/card/bluetooth/BluetoothCard.cpp +++ b/src/card/bluetooth/BluetoothCard.cpp @@ -29,50 +29,52 @@ BluetoothCard::BluetoothCard(QSharedPointer pDevice) } -ReturnCode BluetoothCard::connect() +CardReturnCode BluetoothCard::connect() { if (isConnected()) { qCCritical(bluetooth) << "Card is already connected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } auto request = BluetoothMessageCreator::createSetTransportProtocolRequest(BluetoothTransportProtocol::T1); - auto response = SynchronousBtCall(mDevice).send(request); - if (response == nullptr) + auto response = SynchronousBtCall(mDevice).send(request, BluetoothMsgId::SetTransportProtocolResponse); + if (response.isNull()) { qCCritical(bluetooth) << "Response is empty"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } - else if (response->getResultCode() != BluetoothResultCode::Ok) + + auto resultCode = response.staticCast()->getResultCode(); + if (resultCode != BluetoothResultCode::Ok) { - qCCritical(bluetooth) << "Cannot set transport protocol on card" << response->getResultCode(); - return ReturnCode::COMMAND_FAILED; + qCCritical(bluetooth) << "Cannot set transport protocol on card" << resultCode; + return CardReturnCode::COMMAND_FAILED; } mConnected = true; - return ReturnCode::OK; + return CardReturnCode::OK; } -ReturnCode BluetoothCard::disconnect() +CardReturnCode BluetoothCard::disconnect() { if (!isConnected()) { qCCritical(bluetooth) << "Card is already disconnected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } auto request = BluetoothMessageCreator::createDisconnectRequest(); - auto response = SynchronousBtCall(mDevice).send(request, 1); + auto response = SynchronousBtCall(mDevice).send(request, BluetoothMsgId::DisconnectResponse, 1); mConnected = false; - if (response == nullptr) + if (response.isNull()) { qCCritical(bluetooth) << "Response is empty"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } - return ReturnCode::OK; + return CardReturnCode::OK; } @@ -82,44 +84,46 @@ bool BluetoothCard::isConnected() } -ReturnCode BluetoothCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) +CardReturnCode BluetoothCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { return transmit(pCmd, pRes, 30); } -ReturnCode BluetoothCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes, unsigned int pTimeoutSeconds) +CardReturnCode BluetoothCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes, quint8 pTimeoutSeconds) { if (!isConnected()) { qCCritical(bluetooth) << "Card is not connected, abort transmit"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } qCDebug(bluetooth) << "Transmit command APDU: " << pCmd.getBuffer().toHex(); auto request = BluetoothMessageCreator::createTransferApduRequest(pCmd.getBuffer()); - auto response = SynchronousBtCall(mDevice).send(request, pTimeoutSeconds); - if (response == nullptr) + auto response = SynchronousBtCall(mDevice).send(request, BluetoothMsgId::TransferApduResponse, pTimeoutSeconds); + if (response.isNull()) { qCCritical(bluetooth) << "Response is empty"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } - if (response->getResultCode() != BluetoothResultCode::Ok) + + auto apduResponse = response.staticCast(); + if (apduResponse->getResultCode() != BluetoothResultCode::Ok) { - qCCritical(bluetooth) << "TransferApduResponse failed : " << response->getResultCode(); - return ReturnCode::COMMAND_FAILED; + qCCritical(bluetooth) << "TransferApduResponse failed : " << apduResponse->getResultCode(); + return CardReturnCode::COMMAND_FAILED; } - pRes.setBuffer(response->getResponseAPDU()); + pRes.setBuffer(apduResponse->getResponseAPDU()); qCDebug(bluetooth) << "Transmit response APDU: " << pRes.getBuffer().toHex(); - return ReturnCode::OK; + return CardReturnCode::OK; } -ReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, - int pTimeoutSeconds) + quint8 pTimeoutSeconds) { EstablishPACEChannelBuilder builder; builder.setPinId(pPinId); @@ -128,8 +132,8 @@ ReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, ResponseApdu response; - ReturnCode returnCode = transmit(builder.createCommandDataCcid(), response, pTimeoutSeconds); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = transmit(builder.createCommandDataCcid(), response, pTimeoutSeconds); + if (returnCode != CardReturnCode::OK) { return returnCode; } @@ -139,7 +143,7 @@ ReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, } -ReturnCode BluetoothCard::destroyPaceChannel() +CardReturnCode BluetoothCard::destroyPaceChannel() { DestroyPACEChannelBuilder builder; ResponseApdu response; @@ -147,14 +151,14 @@ ReturnCode BluetoothCard::destroyPaceChannel() } -ReturnCode BluetoothCard::setEidPin(unsigned int pTimeoutSeconds) +CardReturnCode BluetoothCard::setEidPin(quint8 pTimeoutSeconds) { PinModifyBuilder builder; CommandApdu command = builder.createCommandDataCcid(pTimeoutSeconds); ResponseApdu response; - ReturnCode returnCode = transmit(command, response, pTimeoutSeconds); - if (returnCode != ReturnCode::OK) + CardReturnCode returnCode = transmit(command, response, pTimeoutSeconds); + if (returnCode != CardReturnCode::OK) { return returnCode; } diff --git a/src/card/bluetooth/BluetoothCard.h b/src/card/bluetooth/BluetoothCard.h index 736ff4a..cb0bd7a 100644 --- a/src/card/bluetooth/BluetoothCard.h +++ b/src/card/bluetooth/BluetoothCard.h @@ -25,22 +25,22 @@ class BluetoothCard bool mConnected; QSharedPointer mDevice; - ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes, unsigned int pTimeoutSeconds); + CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes, quint8 pTimeoutSeconds); public: BluetoothCard(QSharedPointer pDevice); - ReturnCode connect() override; - ReturnCode disconnect() override; + CardReturnCode connect() override; + CardReturnCode disconnect() override; bool isConnected() override; - ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; + CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) override; + CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; - ReturnCode destroyPaceChannel() override; + CardReturnCode destroyPaceChannel() override; - ReturnCode setEidPin(unsigned int pTimeoutSeconds) override; + CardReturnCode setEidPin(quint8 pTimeoutSeconds) override; }; } /* namespace governikus */ diff --git a/src/card/bluetooth/BluetoothReader.cpp b/src/card/bluetooth/BluetoothReader.cpp index 935333d..91b5f37 100644 --- a/src/card/bluetooth/BluetoothReader.cpp +++ b/src/card/bluetooth/BluetoothReader.cpp @@ -7,6 +7,7 @@ #include "BluetoothCard.h" #include "BluetoothDebug.h" #include "BluetoothReader.h" +#include "DeviceError.h" #include "SynchronousBtCall.h" #include "messages/BluetoothMessageCreator.h" #include "messages/BluetoothMessageParser.h" @@ -17,14 +18,14 @@ #include #include -Q_DECLARE_LOGGING_CATEGORY(card) +Q_DECLARE_LOGGING_CATEGORY(bluetooth) using namespace governikus; BluetoothReader::BluetoothReader(const QSharedPointer& pDevice) - : Reader(ReaderManagerPlugInType::BLUETOOTH, pDevice->getName(), ReaderType::REINER_cyberJack_wave) + : ConnectableReader(ReaderManagerPlugInType::BLUETOOTH, pDevice->getName(), ReaderType::REINER_cyberJack_wave) , mDevice(pDevice) , mLastCardEvent(CardEvent::NONE) , mCard() @@ -33,6 +34,7 @@ BluetoothReader::BluetoothReader(const QSharedPointer& pDev mReaderInfo.setConnected(false); connect(mDevice.data(), &CyberJackWaveDevice::fireInitialized, this, &BluetoothReader::onInitialized); connect(mDevice.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReader::onDisconnected); + connect(mDevice.data(), &CyberJackWaveDevice::fireError, this, &BluetoothReader::onError); connect(mDevice.data(), &CyberJackWaveDevice::fireStatusCharacteristicChanged, this, &BluetoothReader::onStatusCharacteristicChanged); } @@ -51,15 +53,22 @@ void BluetoothReader::connectReader() void BluetoothReader::onInitialized(const QBluetoothDeviceInfo&) { - qCDebug(card) << "Connected reader" << getName() << "is valid:" << mDevice->isValid(); + qCDebug(bluetooth) << "Connected reader" << getName() << "is valid:" << mDevice->isValid(); /* * Attention: This also triggers the pairing! * (Pairing is initiated by the device on the first write request with WriteMode::WriteWithResponse.) */ - auto protocolRequest = BluetoothMessageCreator::createSetTransportProtocolRequest(BluetoothTransportProtocol::T1); - auto protocolResponse = SynchronousBtCall(mDevice).send(protocolRequest); - if (protocolResponse == nullptr || protocolResponse->getResultCode() != BluetoothResultCode::Ok) + auto request = BluetoothMessageCreator::createSetTransportProtocolRequest(BluetoothTransportProtocol::T1); + auto response = SynchronousBtCall(mDevice).send(request, BluetoothMsgId::SetTransportProtocolResponse); + if (response.isNull()) + { + qCCritical(bluetooth) << "Response is empty"; + return; + } + + auto protocolResponse = response.staticCast(); + if (protocolResponse->getResultCode() != BluetoothResultCode::Ok) { qCCritical(bluetooth) << "Error setting transport protocol"; return; @@ -96,6 +105,15 @@ void BluetoothReader::onDisconnected(const QBluetoothDeviceInfo&) } +void BluetoothReader::onError(QLowEnergyController::Error pError) +{ + if (pError == QLowEnergyController::ConnectionError) + { + Q_EMIT fireReaderDeviceError(DeviceError::DEVICE_CONNECTION_ERROR); + } +} + + Reader::CardEvent BluetoothReader::updateCard() { CardEvent tmpEvent = mLastCardEvent; @@ -113,7 +131,7 @@ void BluetoothReader::onStatusCharacteristicChanged(const QByteArray& pValue) return; } - auto statusChange = messages.at(0)->get()->getStatusChange(); + auto statusChange = messages.at(0).staticCast()->getStatusChange(); if (mCard.isNull() && (statusChange == BluetoothStatusChange::CardInserted || statusChange == BluetoothStatusChange::CardReset)) { qCDebug(card) << "Card inserted" << getName(); diff --git a/src/card/bluetooth/BluetoothReader.h b/src/card/bluetooth/BluetoothReader.h index 4a8a872..76b85a2 100644 --- a/src/card/bluetooth/BluetoothReader.h +++ b/src/card/bluetooth/BluetoothReader.h @@ -22,8 +22,7 @@ namespace governikus class BluetoothReader - : public Reader - , public ConnectableReader + : public ConnectableReader { Q_OBJECT @@ -38,6 +37,7 @@ class BluetoothReader private Q_SLOTS: void onInitialized(const QBluetoothDeviceInfo& pInfo); void onDisconnected(const QBluetoothDeviceInfo& pInfo); + void onError(QLowEnergyController::Error pError); void onStatusCharacteristicChanged(const QByteArray& pValue); Q_SIGNALS: diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp b/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp index bbea775..0bcf44a 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp @@ -10,6 +10,7 @@ #include "BluetoothReader.h" #include "BluetoothReaderManagerPlugIn.h" #include "BluetoothReaderManagerPlugIn_p.h" +#include "DeviceError.h" #include @@ -28,6 +29,7 @@ BluetoothReaderManagerPlugIn::BluetoothReaderManagerPlugIn() , mInitializingDevices() , mReaders() , mScanInProgress(false) + , mTimerIdDiscoverPairedDevices(0) { connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothReaderManagerPlugIn::onDeviceDiscovered); connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothReaderManagerPlugIn::onDeviceDiscoveryFinished); @@ -41,6 +43,10 @@ void BluetoothReaderManagerPlugIn::init() ReaderManagerPlugIn::init(); Q_D(BluetoothReaderManagerPlugIn); d->init(); + + qCDebug(bluetooth) << "Handle already paired devices"; + d->handlePairedDevices(); + mTimerIdDiscoverPairedDevices = startTimer(1000); } @@ -110,7 +116,7 @@ void BluetoothReaderManagerPlugIn::onDeviceDiscovered(const QBluetoothDeviceInfo QString deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); if (mReaders.contains(deviceId)) { - mDiscoveredReadersInCurrentScan.append(deviceId); + mDiscoveredReadersInCurrentScan += deviceId; return; } if (mInitializingDevices.contains(deviceId)) @@ -138,7 +144,7 @@ void BluetoothReaderManagerPlugIn::onDeviceInitialized(const QBluetoothDeviceInf if (mReaders.contains(deviceId)) { qCDebug(bluetooth) << "Device is already determined as reader, skip further processing"; - mDiscoveredReadersInCurrentScan.append(deviceId); + mDiscoveredReadersInCurrentScan += deviceId; } else { @@ -149,8 +155,9 @@ void BluetoothReaderManagerPlugIn::onDeviceInitialized(const QBluetoothDeviceInf connect(reader, &Reader::fireCardInserted, this, &ReaderManagerPlugIn::fireCardInserted); connect(reader, &Reader::fireCardRemoved, this, &ReaderManagerPlugIn::fireCardRemoved); connect(reader, &Reader::fireCardRetryCounterChanged, this, &ReaderManagerPlugIn::fireCardRetryCounterChanged); + connect(reader, &Reader::fireReaderDeviceError, this, &ReaderManagerPlugIn::fireReaderDeviceError); - mDiscoveredReadersInCurrentScan.append(deviceId); + mDiscoveredReadersInCurrentScan += deviceId; mReaders.insert(deviceId, reader); connect(device.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReaderManagerPlugIn::onDeviceDisconnected); } @@ -190,6 +197,8 @@ void BluetoothReaderManagerPlugIn::onDeviceDiscoveryFinished() void BluetoothReaderManagerPlugIn::onDeviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error pError) { qCCritical(bluetooth) << "Error on Bluetooth device discovery" << pError; + + Q_EMIT fireReaderDeviceError(pError == QBluetoothDeviceDiscoveryAgent::PoweredOffError ? DeviceError::DEVICE_POWERED_OFF : DeviceError::DEVICE_SCAN_ERROR); } @@ -213,3 +222,16 @@ void BluetoothReaderManagerPlugIn::onRemoveReader(const QString& pDeviceId) delete reader; } } + + +void BluetoothReaderManagerPlugIn::timerEvent(QTimerEvent* pEvent) +{ + if (pEvent->timerId() == mTimerIdDiscoverPairedDevices) + { + Q_D(BluetoothReaderManagerPlugIn); + d->handlePairedDevices(); + return; + } + + ReaderManagerPlugIn::timerEvent(pEvent); +} diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn.h b/src/card/bluetooth/BluetoothReaderManagerPlugIn.h index 74669f1..c8c895d 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn.h +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn.h @@ -39,8 +39,10 @@ class BluetoothReaderManagerPlugIn QMap > mInitializingDevices; QMap mReaders; bool mScanInProgress; + int mTimerIdDiscoverPairedDevices; void onRemoveReader(const QString& pDeviceId); + void timerEvent(QTimerEvent* event) override; private Q_SLOTS: void onDeviceDisconnected(const QBluetoothDeviceInfo& pInfo); diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp index cb47815..4971e55 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp @@ -13,7 +13,6 @@ #include #include - Q_DECLARE_LOGGING_CATEGORY(bluetooth) using namespace governikus; @@ -64,7 +63,9 @@ BluetoothReaderManagerPlugInPrivate::BluetoothReaderManagerPlugInPrivate(Bluetoo void BluetoothReaderManagerPlugInPrivate::init() { Q_Q(BluetoothReaderManagerPlugIn); - q->setBluetoothStatus(AndroidBluetoothAdapter::getDefaultAdapter().isStateOn()); + const auto& adapter = AndroidBluetoothAdapter::getDefaultAdapter(); + q->setReaderInfoAvailable(adapter.isAvailable()); + q->setBluetoothStatus(adapter.isStateOn()); } @@ -87,20 +88,29 @@ void BluetoothReaderManagerPlugInPrivate::onScanStart() void BluetoothReaderManagerPlugInPrivate::handlePairedDevices() { - auto pairedDevices = AndroidBluetoothAdapter::getDefaultAdapter().getBondedDevices(); - if (pairedDevices.isEmpty()) + static QVector knownPairedDevices; + const QVector& currentlyPairedDevices = AndroidBluetoothAdapter::getDefaultAdapter().getBondedDevices(); + QVector newlyPairedDevices; + + for (const QBluetoothDeviceInfo& device : qAsConst(currentlyPairedDevices)) { - qCDebug(bluetooth) << "No paired devices found"; - } - else - { - qCDebug(bluetooth) << "Found" << pairedDevices.size() << "paired devices"; - Q_Q(BluetoothReaderManagerPlugIn); - for (QBluetoothDeviceInfo pairedDevice : pairedDevices) + if (!knownPairedDevices.contains(device)) { - q->onDeviceDiscovered(pairedDevice); + newlyPairedDevices.append(device); } } + + if (!newlyPairedDevices.isEmpty()) + { + qCDebug(bluetooth) << "Found" << newlyPairedDevices.size() << "paired devices"; + Q_Q(BluetoothReaderManagerPlugIn); + for (const QBluetoothDeviceInfo& device : qAsConst(newlyPairedDevices)) + { + q->onDeviceDiscovered(device); + } + } + + knownPairedDevices = currentlyPairedDevices; } diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_ios.mm b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_ios.mm index afd2d68..1550cf6 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_ios.mm +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_ios.mm @@ -18,15 +18,13 @@ BluetoothReaderManagerPlugInPrivate::BluetoothReaderManagerPlugInPrivate(Bluetoo : QObject(pPublic) , q_ptr(pPublic) { - qRegisterMetaType("QBluetoothDeviceInfo"); - qRegisterMetaType("QLowEnergyCharacteristic"); - qRegisterMetaType("QLowEnergyDescriptor"); } void BluetoothReaderManagerPlugInPrivate::init() { Q_Q(BluetoothReaderManagerPlugIn); + q->setReaderInfoAvailable(true); q->setBluetoothStatus(true); } diff --git a/src/card/bluetooth/CMakeLists.txt b/src/card/bluetooth/CMakeLists.txt index e7f7537..5badf80 100644 --- a/src/card/bluetooth/CMakeLists.txt +++ b/src/card/bluetooth/CMakeLists.txt @@ -2,3 +2,7 @@ ADD_PLATFORM_LIBRARY(AusweisAppCardBluetooth) TARGET_LINK_LIBRARIES(AusweisAppCardBluetooth Qt5::Core Qt5::Bluetooth AusweisAppGlobal AusweisAppCard) TARGET_COMPILE_DEFINITIONS(AusweisAppCardBluetooth PRIVATE QT_STATICPLUGIN) + +IF(ANDROID) + TARGET_LINK_LIBRARIES(AusweisAppCardBluetooth Qt5::AndroidExtras) +ENDIF() diff --git a/src/card/bluetooth/CyberJackWaveDevice.cpp b/src/card/bluetooth/CyberJackWaveDevice.cpp index 0d6a85b..d91a389 100644 --- a/src/card/bluetooth/CyberJackWaveDevice.cpp +++ b/src/card/bluetooth/CyberJackWaveDevice.cpp @@ -190,6 +190,7 @@ void CyberJackWaveDevice::onDeviceStateChanged(QLowEnergyController::ControllerS void CyberJackWaveDevice::onDeviceError(QLowEnergyController::Error pError) { qCDebug(bluetooth) << "Error" << pError << mLeController.errorString() << "on device" << mDeviceInfo; + Q_EMIT fireError(pError); } diff --git a/src/card/bluetooth/CyberJackWaveDevice.h b/src/card/bluetooth/CyberJackWaveDevice.h index ad76c02..34a033a 100644 --- a/src/card/bluetooth/CyberJackWaveDevice.h +++ b/src/card/bluetooth/CyberJackWaveDevice.h @@ -96,6 +96,7 @@ class CyberJackWaveDevice Q_SIGNALS: void fireInitialized(const QBluetoothDeviceInfo& pInfo); void fireDisconnected(const QBluetoothDeviceInfo& pInfo); + void fireError(QLowEnergyController::Error pError); void fireReadCharacteristicChanged(const QByteArray& pValue); void fireStatusCharacteristicChanged(const QByteArray& pValue); }; diff --git a/src/card/bluetooth/NotificationEnabler.cpp b/src/card/bluetooth/NotificationEnabler.cpp index 4dc356c..336245b 100644 --- a/src/card/bluetooth/NotificationEnabler.cpp +++ b/src/card/bluetooth/NotificationEnabler.cpp @@ -75,7 +75,8 @@ void NotificationEnabler::onDescriptorWritten(const QLowEnergyDescriptor& pDescr { return; } - if (mValueWritten == mValueConfirmed.append(pNewValue)) + mValueConfirmed += pNewValue; + if (mValueWritten == mValueConfirmed) { mEventLoop.quit(); } diff --git a/src/card/bluetooth/SynchronousBtCall.cpp b/src/card/bluetooth/SynchronousBtCall.cpp index 399333d..7268325 100644 --- a/src/card/bluetooth/SynchronousBtCall.cpp +++ b/src/card/bluetooth/SynchronousBtCall.cpp @@ -5,3 +5,57 @@ */ #include "SynchronousBtCall.h" + +#include +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(bluetooth) + +SynchronousBtCall::SynchronousBtCall(const QSharedPointer& pDevice) + : QObject() + , mDevice(pDevice) + , mEventLoop() + , mBuffer() + , mMessage() +{ + connect(mDevice.data(), &CyberJackWaveDevice::fireReadCharacteristicChanged, this, &SynchronousBtCall::onCharacteristicChanged); +} + + +QSharedPointer SynchronousBtCall::send(const BluetoothMessage& pRequest, BluetoothMsgId pResponseType, quint8 pTimeoutSeconds) +{ + Q_ASSERT(pTimeoutSeconds > 0); + QTimer::singleShot(pTimeoutSeconds * 1000, &mEventLoop, &QEventLoop::quit); + mDevice->write(pRequest.toData()); + mEventLoop.exec(); + + if (mMessage.isNull()) + { + qCCritical(bluetooth) << "No response received for " << pRequest.getBluetoothMsgId(); + return QSharedPointer(); + } + else if (mMessage->getBluetoothMsgId() != pResponseType) + { + qCCritical(bluetooth) << "Got unexpected response type " << mMessage->getBluetoothMsgId(); + return QSharedPointer(); + } + + return mMessage; +} + + +void SynchronousBtCall::onCharacteristicChanged(const QByteArray& pNewValue) +{ + { + mBuffer += pNewValue; + auto messages = BluetoothMessageParser(mBuffer).getMessages(); + if (!messages.isEmpty()) + { + qCDebug(bluetooth) << "Bluetooth message complete"; + mMessage = messages.at(0); + mEventLoop.quit(); + } + } +} diff --git a/src/card/bluetooth/SynchronousBtCall.h b/src/card/bluetooth/SynchronousBtCall.h index 119f376..4ce3efa 100644 --- a/src/card/bluetooth/SynchronousBtCall.h +++ b/src/card/bluetooth/SynchronousBtCall.h @@ -9,20 +9,12 @@ #pragma once - #include "CyberJackWaveDevice.h" #include "messages/BluetoothMessage.h" #include "messages/BluetoothMessageParser.h" - #include -#include #include -#include - - -Q_DECLARE_LOGGING_CATEGORY(bluetooth) - namespace governikus { @@ -33,59 +25,17 @@ class SynchronousBtCall Q_OBJECT private: - QSharedPointer mDevice; + const QSharedPointer mDevice; QEventLoop mEventLoop; QByteArray mBuffer; QSharedPointer mMessage; public: - SynchronousBtCall(QSharedPointer pDevice) - : QObject() - , mDevice(pDevice) - , mEventLoop() - , mBuffer() - , mMessage() - { - connect(mDevice.data(), &CyberJackWaveDevice::fireReadCharacteristicChanged, this, &SynchronousBtCall::onCharacteristicChanged); - } - - - template QSharedPointer send(const BluetoothMessage& pRequest, int pTimeoutSeconds = 20) - { - Q_ASSERT(pTimeoutSeconds > 0); - QTimer::singleShot(pTimeoutSeconds * 1000, &mEventLoop, &QEventLoop::quit); - mDevice->write(pRequest.toData()); - mEventLoop.exec(); - - if (mMessage == nullptr) - { - qCCritical(bluetooth) << "No response received for " << pRequest.getBluetoothMsgId(); - return QSharedPointer(); - } - - QSharedPointer response = mMessage.dynamicCast(); - if (response == nullptr) - { - qCCritical(bluetooth) << "Got unexpected response type " << mMessage->getBluetoothMsgId(); - } - return response; - } - + SynchronousBtCall(const QSharedPointer& pDevice); + QSharedPointer send(const BluetoothMessage& pRequest, BluetoothMsgId pResponseType, quint8 pTimeoutSeconds = 20); private Q_SLOTS: - void onCharacteristicChanged(const QByteArray& pNewValue) - { - mBuffer.append(pNewValue); - auto messages = BluetoothMessageParser(mBuffer).getMessages(); - if (!messages.isEmpty()) - { - qCDebug(bluetooth) << "Bluetooth message complete"; - mMessage = messages.at(0); - mEventLoop.quit(); - } - } - - + void onCharacteristicChanged(const QByteArray& pNewValue); }; } /* namespace governikus */ diff --git a/src/card/bluetooth/messages/BluetoothIDs.h b/src/card/bluetooth/messages/BluetoothIDs.h index 3079b2a..caf7778 100644 --- a/src/card/bluetooth/messages/BluetoothIDs.h +++ b/src/card/bluetooth/messages/BluetoothIDs.h @@ -13,7 +13,7 @@ namespace governikus { -defineEnumType(BluetoothMsgId, +defineTypedEnumType(BluetoothMsgId, char, ConnectRequest = 0x00, ConnectResponse = 0x01, DisconnectRequest = 0x02, @@ -36,7 +36,7 @@ defineEnumType(BluetoothMsgId, SetTransportProtocolRequest = 0x13, SetTransportProtocolResponse = 0x14) -defineEnumType(BluetoothParamId, +defineTypedEnumType(BluetoothParamId, char, MaxMsgSize = 0x00, ConnectionStatus = 0x01, ResultCode = 0x02, @@ -58,7 +58,7 @@ defineEnumType(BluetoothConnectionStatus, defineEnumType(BluetoothDisconnectionType, Graceful = 0x00, Immediate = 0x01) -defineEnumType(BluetoothResultCode, +defineTypedEnumType(BluetoothResultCode, char, Ok = 0x00, ErrorNoReasonDefined = 0x01, ErrorCardNotAccessible = 0x02, @@ -68,7 +68,7 @@ defineEnumType(BluetoothResultCode, ErrorDataNotAvailabe = 0x06, ErrorNotSupport = 0x07) -defineEnumType(BluetoothStatusChange, +defineTypedEnumType(BluetoothStatusChange, char, Unknown = 0x00, CardReset = 0x01, CardNotAccessible = 0x02, @@ -76,7 +76,7 @@ defineEnumType(BluetoothStatusChange, CardInserted = 0x04, CardRecovered = 0x05) -defineEnumType(BluetoothTransportProtocol, T0 = 0x00, T1 = 0x01) +defineTypedEnumType(BluetoothTransportProtocol, char, T0 = 0x00, T1 = 0x01) defineEnumType(BluetoothCardReaderStatus, Unknown = 0x00, CardInserted = 0x78, CardRemoved = 0x38) diff --git a/src/card/bluetooth/messages/BluetoothMessage.cpp b/src/card/bluetooth/messages/BluetoothMessage.cpp index 9a2038f..173d50f 100644 --- a/src/card/bluetooth/messages/BluetoothMessage.cpp +++ b/src/card/bluetooth/messages/BluetoothMessage.cpp @@ -6,9 +6,12 @@ #include "BluetoothMessage.h" +#include + +Q_DECLARE_LOGGING_CATEGORY(bluetooth) + using namespace governikus; -static int registerBluetoothMessagePtr = qRegisterMetaType("BluetoothMessage::Ptr"); QDebug operator<<(QDebug pDbg, const governikus::BluetoothMessage& pMsg) { @@ -21,7 +24,6 @@ BluetoothMessage::BluetoothMessage(BluetoothMsgId pMsgId) : mMsgId(pMsgId) , mMessageParameter() { - Q_UNUSED(registerBluetoothMessagePtr); } @@ -30,15 +32,22 @@ BluetoothMessage::~BluetoothMessage() } -void BluetoothMessage::addParameter(BluetoothMessageParameter::Ptr pMessageParameter) +BluetoothMessageParameter::Ptr BluetoothMessage::getParameter(BluetoothParamId pId) const { - mMessageParameter.append(pMessageParameter); + return mMessageParameter.value(pId); } -const BluetoothMessage::ParameterList& BluetoothMessage::getParameterList() const +void BluetoothMessage::addParameter(BluetoothMessageParameter::Ptr pMessageParameter) { - return mMessageParameter; + Q_ASSERT(!pMessageParameter.isNull()); + + if (mMessageParameter.contains(pMessageParameter->getParameterId())) + { + qCWarning(bluetooth) << "Parameter ID is already added:" << pMessageParameter->getParameterId(); + } + + mMessageParameter.insertMulti(pMessageParameter->getParameterId(), pMessageParameter); } @@ -51,14 +60,20 @@ BluetoothMsgId BluetoothMessage::getBluetoothMsgId() const QByteArray BluetoothMessage::toData() const { QByteArray data; - data.append(static_cast(mMsgId)); - data.append(static_cast(mMessageParameter.size())); - data.append(static_cast(0x00)); - data.append(static_cast(0x00)); - - for (const auto& parameter : getParameterList()) + data += Enum::getValue(mMsgId); + if (mMessageParameter.size() > CHAR_MAX) { - data.append(parameter->toData()); + qCCritical(bluetooth) << "Message parameter count > CHAR_MAX not supported"; + Q_ASSERT(mMessageParameter.size() <= CHAR_MAX); + return QByteArray(); + } + data += static_cast(mMessageParameter.size()); + data += char(0x00); + data += char(0x00); + + for (const auto& parameter : qAsConst(mMessageParameter)) + { + data += parameter->toData(); } return data; @@ -70,9 +85,20 @@ QString BluetoothMessage::toString() const static const QString paramDesc(QStringLiteral(" | Parameter: ")); QString str = getEnumName(mMsgId); - for (const auto& parameter : getParameterList()) + for (const auto& parameter : qAsConst(mMessageParameter)) { str += paramDesc + parameter->toString(); } return str; } + + +void BluetoothMessage::registerMetaTypes() +{ + static bool registered = false; + if (!registered) + { + qRegisterMetaType("BluetoothMessage::Ptr"); + registered = true; + } +} diff --git a/src/card/bluetooth/messages/BluetoothMessage.h b/src/card/bluetooth/messages/BluetoothMessage.h index ef03ecd..e212773 100644 --- a/src/card/bluetooth/messages/BluetoothMessage.h +++ b/src/card/bluetooth/messages/BluetoothMessage.h @@ -9,9 +9,12 @@ #pragma once #include "parameter/BluetoothMessageParameter.h" + #include #include +class test_BluetoothMessageParser; + namespace governikus { @@ -21,25 +24,12 @@ class BluetoothMessage typedef QSharedPointer Ptr; private: - typedef QVector ParameterList; - + friend class::test_BluetoothMessageParser; BluetoothMsgId mMsgId; - ParameterList mMessageParameter; + QMap mMessageParameter; protected: - template QSharedPointer getParameter() const - { - for (const auto& param : getParameterList()) - { - const auto t = param.dynamicCast(); - if (t) - { - return t; - } - } - return QSharedPointer(); - } - + BluetoothMessageParameter::Ptr getParameter(BluetoothParamId pId) const; public: BluetoothMessage(BluetoothMsgId pMsgId); @@ -52,17 +42,11 @@ class BluetoothMessage } - const ParameterList& getParameterList() const; BluetoothMsgId getBluetoothMsgId() const; QByteArray toData() const; QString toString() const; - template const T* get() const - { - return static_cast(this); - } - - + static void registerMetaTypes(); }; } /* namespace governikus */ diff --git a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp index c91146c..4ab2cb7 100644 --- a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp @@ -23,13 +23,13 @@ BluetoothMessageConnectResponse::~BluetoothMessageConnectResponse() BluetoothConnectionStatus BluetoothMessageConnectResponse::getConnectionStatus() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ConnectionStatus); + return param.staticCast()->getResultCode(); } unsigned int BluetoothMessageConnectResponse::getMaxMsgSize() const { - QSharedPointer param = getParameter(); - return param->getMaxMsgSize(); + const auto& param = getParameter(BluetoothParamId::MaxMsgSize); + return param.staticCast()->getMaxMsgSize(); } diff --git a/src/card/bluetooth/messages/BluetoothMessageCreator.cpp b/src/card/bluetooth/messages/BluetoothMessageCreator.cpp index f3d59c0..ba53b43 100644 --- a/src/card/bluetooth/messages/BluetoothMessageCreator.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageCreator.cpp @@ -15,7 +15,7 @@ using namespace governikus; -BluetoothMessageConnectRequest BluetoothMessageCreator::createConnectRequest(int pMaxMsgSize) +BluetoothMessageConnectRequest BluetoothMessageCreator::createConnectRequest(uint pMaxMsgSize) { BluetoothMessageConnectRequest msg; msg.copyParameter(BluetoothMessageParameterMaxMsgSize(pMaxMsgSize)); @@ -70,7 +70,7 @@ BluetoothMessageTransferCardReaderStatusRequest BluetoothMessageCreator::createT BluetoothMessageSetTransportProtocolRequest BluetoothMessageCreator::createSetTransportProtocolRequest(BluetoothTransportProtocol pProtocol) { BluetoothMessageSetTransportProtocolRequest msg; - msg.copyParameter(BluetoothMessageParameter(BluetoothParamId::TransportProtocol, getEnumByteValue(pProtocol))); + msg.copyParameter(BluetoothMessageParameter(BluetoothParamId::TransportProtocol, QByteArray(1, Enum::getValue(pProtocol)))); return msg; } diff --git a/src/card/bluetooth/messages/BluetoothMessageCreator.h b/src/card/bluetooth/messages/BluetoothMessageCreator.h index 3c547f6..881d896 100644 --- a/src/card/bluetooth/messages/BluetoothMessageCreator.h +++ b/src/card/bluetooth/messages/BluetoothMessageCreator.h @@ -110,7 +110,7 @@ class BluetoothMessageCreator Q_DISABLE_COPY(BluetoothMessageCreator) public: - static BluetoothMessageConnectRequest createConnectRequest(int pMaxMsgSize = 20); + static BluetoothMessageConnectRequest createConnectRequest(uint pMaxMsgSize = 20); static BluetoothMessageDisconnectRequest createDisconnectRequest(); static BluetoothMessageTransferApduRequest createTransferApduRequest(const QByteArray& pApdu); static BluetoothMessageTransferAtrRequest createTransferAtrRequest(); diff --git a/src/card/bluetooth/messages/BluetoothMessageParser.cpp b/src/card/bluetooth/messages/BluetoothMessageParser.cpp index a6cc283..091eec3 100644 --- a/src/card/bluetooth/messages/BluetoothMessageParser.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageParser.cpp @@ -55,7 +55,7 @@ void BluetoothMessageParser::parse() if (parseParameter(message, parameterCount)) { - mMessages.append(message); + mMessages += message; } else { @@ -74,7 +74,7 @@ bool BluetoothMessageParser::parseParameter(QSharedPointer pMe if (data.size() >= 4) { BluetoothParamId paramId = static_cast(data.at(0)); - ushort paramLength = getParamLength(data.at(2), data.at(3)); + ushort paramLength = getParamLength(static_cast(data.at(2)), static_cast(data.at(3))); data = data.mid(4); /*! @@ -107,7 +107,7 @@ bool BluetoothMessageParser::parseParameter(QSharedPointer pMe ushort BluetoothMessageParser::getParamLength(uchar pHigh, uchar pLow) const { - return (pHigh << 8) + pLow; + return static_cast((pHigh << 8) + pLow); } diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp index be9e376..c8f8547 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp @@ -1,13 +1,10 @@ -// -// BluetoothMessagePowerSimOffResponse.cpp -// AusweisApp2 -// -// Created by gov on 27.10.14. -// -// +/*! + * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + */ + +#include "messages/BluetoothMessagePowerSimOffResponse.h" #include "BluetoothIDs.h" -#include "messages/BluetoothMessagePowerSimOffResponse.h" #include "messages/parameter/BluetoothMessageParameterResultCode.h" using namespace governikus; @@ -26,6 +23,6 @@ BluetoothMessagePowerSimOffResponse::~BluetoothMessagePowerSimOffResponse() BluetoothResultCode BluetoothMessagePowerSimOffResponse::getResultCode() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ResultCode); + return param.staticCast()->getResultCode(); } diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp index b1c9142..a62ed23 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp @@ -22,6 +22,6 @@ BluetoothMessagePowerSimOnResponse::~BluetoothMessagePowerSimOnResponse() BluetoothResultCode BluetoothMessagePowerSimOnResponse::getResultCode() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ResultCode); + return param.staticCast()->getResultCode(); } diff --git a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp index 0c0f8ab..319d9c4 100644 --- a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp @@ -1,13 +1,10 @@ -// -// BluetoothMessageResetSimResponse.cpp -// AusweisApp2 -// -// Created by gov on 27.10.14. -// -// +/*! + * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + */ + +#include "messages/BluetoothMessageResetSimResponse.h" #include "BluetoothIDs.h" -#include "messages/BluetoothMessageResetSimResponse.h" #include "messages/parameter/BluetoothMessageParameterResultCode.h" using namespace governikus; @@ -26,6 +23,6 @@ BluetoothMessageResetSimResponse::~BluetoothMessageResetSimResponse() BluetoothResultCode BluetoothMessageResetSimResponse::getResultCode() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ResultCode); + return param.staticCast()->getResultCode(); } diff --git a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp index 2ca8061..79de393 100644 --- a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp @@ -22,6 +22,6 @@ BluetoothMessageSetTransportProtocolResponse::~BluetoothMessageSetTransportProto BluetoothResultCode BluetoothMessageSetTransportProtocolResponse::getResultCode() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ResultCode); + return param.staticCast()->getResultCode(); } diff --git a/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp b/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp index ec7174a..b045e63 100644 --- a/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp @@ -19,18 +19,12 @@ BluetoothMessageStatusInd::~BluetoothMessageStatusInd() } -BluetoothMessageParameterStatusChange::Ptr BluetoothMessageStatusInd::getParamStatusChange() const -{ - return getParameter(); -} - - BluetoothStatusChange BluetoothMessageStatusInd::getStatusChange() const { - auto ptr = getParamStatusChange(); - if (ptr) + const auto& param = getParameter(BluetoothParamId::StatusChange); + if (param) { - return ptr->getStatusChange(); + return param.staticCast()->getStatusChange(); } Q_ASSERT(false); // check for isValid before you call this diff --git a/src/card/bluetooth/messages/BluetoothMessageStatusInd.h b/src/card/bluetooth/messages/BluetoothMessageStatusInd.h index f51cc23..817f96f 100644 --- a/src/card/bluetooth/messages/BluetoothMessageStatusInd.h +++ b/src/card/bluetooth/messages/BluetoothMessageStatusInd.h @@ -25,7 +25,6 @@ class BluetoothMessageStatusInd BluetoothMessageStatusInd(); virtual ~BluetoothMessageStatusInd(); - BluetoothMessageParameterStatusChange::Ptr getParamStatusChange() const; BluetoothStatusChange getStatusChange() const; }; diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp index 9d0ee5f..dfce8a4 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp @@ -21,20 +21,19 @@ BluetoothMessageTransferApduResponse::~BluetoothMessageTransferApduResponse() BluetoothResultCode BluetoothMessageTransferApduResponse::getResultCode() const { - QSharedPointer param = getParameter(); - return param->getResultCode(); + const auto& param = getParameter(BluetoothParamId::ResultCode); + return param.staticCast()->getResultCode(); } bool BluetoothMessageTransferApduResponse::hasResponseAPDU() const { - QSharedPointer param = getParameter(); - return param; + return getParameter(BluetoothParamId::ResponseAPDU); } const QByteArray& BluetoothMessageTransferApduResponse::getResponseAPDU() const { - QSharedPointer param = getParameter(); - return param->getResponseApdu(); + const auto& param = getParameter(BluetoothParamId::ResponseAPDU); + return param.staticCast()->getResponseApdu(); } diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp index 978cc11..90667f7 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp @@ -19,10 +19,10 @@ BluetoothMessageTransferCardReaderStatusResponse::~BluetoothMessageTransferCardR BluetoothStatusChange BluetoothMessageTransferCardReaderStatusResponse::getStatusChange() const { - auto ptr = getParameter(); - if (ptr) + const auto& param = getParameter(BluetoothParamId::CardReaderStatus); + if (param) { - return ptr->getStatusChange(); + return param.staticCast()->getStatusChange(); } Q_ASSERT(false); // check for isValid before you call this diff --git a/src/card/bluetooth/messages/BluetoothUtils.cpp b/src/card/bluetooth/messages/BluetoothUtils.cpp index 07e9748..c5ad031 100644 --- a/src/card/bluetooth/messages/BluetoothUtils.cpp +++ b/src/card/bluetooth/messages/BluetoothUtils.cpp @@ -6,21 +6,32 @@ #include "BluetoothUtils.h" +#include + + using namespace governikus; +Q_DECLARE_LOGGING_CATEGORY(bluetooth) + ushort BluetoothUtils::getPaddingLength(ushort pParamLen, ushort pPaddingLen) { - int needsPaddingLen = pPaddingLen - (pParamLen % pPaddingLen); + ushort needsPaddingLen = static_cast(pPaddingLen - (pParamLen % pPaddingLen)); return needsPaddingLen == pPaddingLen ? 0 : needsPaddingLen; } void BluetoothUtils::addPadding(QByteArray& pData, const QByteArray& pContent, ushort pPaddingLen) { - ushort paddingLength = getPaddingLength(pContent.size(), pPaddingLen); + if (static_cast(pContent.size()) > USHRT_MAX) + { + qCCritical(bluetooth) << "Content buffer of size bigger than USHRT_MAX not supported"; + Q_ASSERT(static_cast(pContent.size()) <= USHRT_MAX); + return; + } + ushort paddingLength = getPaddingLength(static_cast(pContent.size()), pPaddingLen); for (ushort i = 0; i < paddingLength; ++i) { - pData.append(static_cast(0x00)); + pData += char(0x00); } } diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp index 76a79e1..3419559 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp @@ -7,8 +7,12 @@ #include "BluetoothMessageParameter.h" #include "messages/BluetoothUtils.h" +#include + using namespace governikus; +Q_DECLARE_LOGGING_CATEGORY(bluetooth) + QDebug operator<<(QDebug pDbg, const BluetoothMessageParameter& pMsg) { pDbg.nospace() << pMsg.toString(); @@ -62,12 +66,18 @@ bool BluetoothMessageParameter::isValid() const QByteArray BluetoothMessageParameter::toData() const { QByteArray data; - data.append(static_cast(mParamId)); - data.append(static_cast(0x00)); - data.append((mValue.size() & 0xFF00) >> 8); - data.append(mValue.size() & 0x00FF); + data += Enum::getValue(mParamId); + data += char(0x00); + if (mValue.size() > 0xFFFF) + { + qCCritical(bluetooth) << "Value of BluetoothMessageParameter of size > 0xFFFF not supported"; + Q_ASSERT(mValue.size() <= 0xFFFF); + return QByteArray(); + } + data += static_cast((mValue.size() >> 8) & 0xFF); + data += static_cast(mValue.size() & 0xFF); - data.append(mValue); + data += mValue; BluetoothUtils::addPadding(data, mValue); return data; } diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h index ef8239a..db27c27 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h @@ -64,13 +64,6 @@ class BluetoothMessageParameter virtual QString toString() const; virtual QString toStringValue() const; - - template const T* get() const - { - return static_cast(this); - } - - }; } /* namespace governikus */ diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp index cf78113..419e6ea 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp @@ -19,11 +19,11 @@ BluetoothMessageParameterMaxMsgSize::BluetoothMessageParameterMaxMsgSize(const Q mValid = false; return; } - mMaxMsgSize = pValue.at(1) | (pValue.at(0) << 8); + mMaxMsgSize = static_cast(pValue.at(1) | (pValue.at(0) << 8)); } -BluetoothMessageParameterMaxMsgSize::BluetoothMessageParameterMaxMsgSize(int pMaxMsgSize) +BluetoothMessageParameterMaxMsgSize::BluetoothMessageParameterMaxMsgSize(uint pMaxMsgSize) : BluetoothMessageParameter(BluetoothParamId::MaxMsgSize, QByteArray()) , mMaxMsgSize(0) { @@ -33,8 +33,8 @@ BluetoothMessageParameterMaxMsgSize::BluetoothMessageParameterMaxMsgSize(int pMa mValid = false; return; } - mValue.append((pMaxMsgSize >> 8) % 256); - mValue.append(pMaxMsgSize % 256); + mValue += static_cast((pMaxMsgSize >> 8) & 0xFF); + mValue += static_cast(pMaxMsgSize & 0xFF); mMaxMsgSize = pMaxMsgSize; } diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h index 51045f5..ca13e52 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h @@ -17,11 +17,11 @@ class BluetoothMessageParameterMaxMsgSize : public BluetoothMessageParameter { private: - unsigned int mMaxMsgSize; + uint mMaxMsgSize; public: BluetoothMessageParameterMaxMsgSize(const QByteArray& pValue); - BluetoothMessageParameterMaxMsgSize(int pMaxMsgSize); + BluetoothMessageParameterMaxMsgSize(uint pMaxMsgSize); virtual ~BluetoothMessageParameterMaxMsgSize(); unsigned int getMaxMsgSize() const; diff --git a/src/card/nfc/CMakeLists.txt b/src/card/nfc/CMakeLists.txt index 9a31619..4112805 100644 --- a/src/card/nfc/CMakeLists.txt +++ b/src/card/nfc/CMakeLists.txt @@ -2,3 +2,7 @@ ADD_PLATFORM_LIBRARY(AusweisAppCardNfc) TARGET_LINK_LIBRARIES(AusweisAppCardNfc Qt5::Core AusweisAppGlobal AusweisAppCard) TARGET_COMPILE_DEFINITIONS(AusweisAppCardNfc PRIVATE QT_STATICPLUGIN) + +IF(ANDROID) + TARGET_LINK_LIBRARIES(AusweisAppCardNfc Qt5::AndroidExtras) +ENDIF() diff --git a/src/card/nfc/NFCConnector.java b/src/card/nfc/NFCConnector.java index 5d63157..b634ed5 100644 --- a/src/card/nfc/NFCConnector.java +++ b/src/card/nfc/NFCConnector.java @@ -15,6 +15,7 @@ import android.nfc.TagLostException; import android.nfc.tech.IsoDep; import android.util.Log; + public class NFCConnector { @@ -107,51 +108,59 @@ public class NFCConnector private static final String LOG_TAG = "AusweisApp2"; + private static NFCConnector mSingleInstance = null; + + private Context mContext = null; + + private NfcAdapter mNfcAdapter = null; + + private boolean mNewTag = false; + + private IsoDep mTag = null; + + private ExtendedLengthApduSupportCode mExtendedLengthApduSupportStatus = ExtendedLengthApduSupportCode.UNKNOWN; + + + public static synchronized NFCConnector getInstance(Context context) + { + if (mSingleInstance == null) + { + Log.d(LOG_TAG, "NfcConnector singleton intialized."); + mSingleInstance = new NFCConnector(context); + } + + return mSingleInstance; + } + + + private NFCConnector(Context context) + { + super(); + mContext = context; + mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); + start(); + } + public synchronized void updateNfcTag(Tag inputTag) { if (inputTag != null&& Arrays.asList(inputTag.getTechList()).contains(IsoDep.class.getName())) { mTag = IsoDep.get(inputTag); - newTag = true; + mNewTag = true; + if (mExtendedLengthApduSupportStatus == ExtendedLengthApduSupportCode.UNKNOWN) + { + Log.i(LOG_TAG, "IsoDep.isExtendedLengthApduSupported " + mTag.isExtendedLengthApduSupported()); + Log.i(LOG_TAG, "IsoDep.getMaxTransceiveLength " + mTag.getMaxTransceiveLength()); + mExtendedLengthApduSupportStatus = mTag.getMaxTransceiveLength() > 499 ? ExtendedLengthApduSupportCode.SUPPORTED : ExtendedLengthApduSupportCode.NOT_SUPPORTED; + } } } - private Context context = null; - - private NfcAdapter nfcAdapter = null; - - private boolean newTag = false; - - private IsoDep mTag = null; - - private static NFCConnector singleInstance = null; - - private NFCConnector(Context context) - { - super(); - this.context = context; - this.nfcAdapter = NfcAdapter.getDefaultAdapter(this.context); - start(); - } - - - public static synchronized NFCConnector getInstance(Context context) - { - if (singleInstance == null) - { - Log.d(LOG_TAG, "NfcConnector singleton intialized."); - singleInstance = new NFCConnector(context); - } - - return singleInstance; - } - - public synchronized byte start() { - if (this.nfcAdapter == null) + if (mNfcAdapter == null) { return NfcConnectorCode.ERROR_NO_NFC.toByte(); } @@ -162,61 +171,109 @@ public class NFCConnector public synchronized byte stop() { - if (this.mTag != null) + if (mTag != null) { - if (this.mTag.isConnected()) + if (mTag.isConnected()) { try { - this.mTag.close(); + mTag.close(); } catch (IOException e) { // nothing } } - this.mTag = null; + mTag = null; } return NfcConnectorCode.SUCCESS.toByte(); } + public synchronized boolean connectCard() + { + if (mTag == null) + { + Log.e(LOG_TAG, "Tag is null"); + return false; + } + if (mTag.isConnected()) + { + Log.e(LOG_TAG, "Card is already connected"); + return false; + } + try + { + mTag.connect(); + return true; + } + catch (IOException e) + { + Log.e(LOG_TAG, "Cannot connect card", e); + } + return false; + } + + + public synchronized boolean disconnectCard() + { + if (mTag == null) + { + Log.e(LOG_TAG, "Tag is null"); + return false; + } + if (!mTag.isConnected()) + { + Log.e(LOG_TAG, "Card is not connected"); + return false; + } + try + { + mTag.close(); + return true; + } + catch (IOException e) + { + Log.e(LOG_TAG, "Cannot disconnect card", e); + } + return false; + } + + + public synchronized boolean isCardConnected() + { + return mTag != null&& mTag.isConnected(); + } + + public synchronized byte[] sendData(byte[] data) { - if (this.nfcAdapter == null) + if (mNfcAdapter == null) { return ERROR_NO_NFC_BYTE; } - if (this.mTag == null) + if (mTag == null) { return ERROR_NO_TAG_BYTE; } + if (!mTag.isConnected()) + { + Log.e(LOG_TAG, "Card is not connected"); + return ERROR_CONNECT_BYTE; + } try { - if (!this.mTag.isConnected()) - { - try - { - this.mTag.connect(); - } - catch (IOException e) - { - this.mTag = null; - return ERROR_CONNECT_BYTE; - } - } - byte[] cardAnswer; try { - cardAnswer = this.mTag.transceive(data); + cardAnswer = mTag.transceive(data); } catch (TagLostException e) { - this.mTag = null; + mTag = null; return ERROR_TAG_LOST_BYTE; } catch (IOException e) @@ -237,42 +294,55 @@ public class NFCConnector } - private static boolean isExtendedLengthApduSupported(IsoDep pTag) - { - return pTag.isExtendedLengthApduSupported() && pTag.getMaxTransceiveLength() > 499; - } - - public synchronized byte getExtendedLengthApduSupportStatus() { - if (mTag == null) - { - return ExtendedLengthApduSupportCode.UNKNOWN.toByte(); - } - return isExtendedLengthApduSupported(mTag) ? ExtendedLengthApduSupportCode.SUPPORTED.toByte() : ExtendedLengthApduSupportCode.NOT_SUPPORTED.toByte(); + return mExtendedLengthApduSupportStatus.toByte(); } public synchronized byte isCardPresent() { - if (this.nfcAdapter == null) + if (mNfcAdapter == null) { return NfcConnectorCode.ERROR_NO_NFC.toByte(); } - if (this.mTag == null || !isExtendedLengthApduSupported(mTag)) + if (mTag == null) { return NfcCardCode.NO_CARD.toByte(); } - if (this.newTag) + if (!mTag.isConnected()) { - this.newTag = false; - - return NfcCardCode.NEW_CARD.toByte(); + try + { + mTag.connect(); + if (!mTag.isConnected()) + { + return NfcCardCode.NO_CARD.toByte(); + } + mTag.close(); + } + catch (IOException e) + { + return NfcCardCode.NO_CARD.toByte(); + } } - return NfcCardCode.SAME_CARD.toByte(); + if (!mNewTag) + { + return NfcCardCode.SAME_CARD.toByte(); + } + mNewTag = false; + + if (!mTag.isExtendedLengthApduSupported()) + { + Log.i(LOG_TAG, "New NFC tag found with insufficient characteristics " + mTag.getTag().toString()); + return NfcCardCode.NO_CARD.toByte(); + } + + Log.i(LOG_TAG, "New NFC tag found with sufficient characteristics " + mTag.getTag().toString()); + return NfcCardCode.NEW_CARD.toByte(); } diff --git a/src/card/nfc/NfcBridge.cpp b/src/card/nfc/NfcBridge.cpp index 110044c..2497611 100644 --- a/src/card/nfc/NfcBridge.cpp +++ b/src/card/nfc/NfcBridge.cpp @@ -22,7 +22,7 @@ Q_DECLARE_LOGGING_CATEGORY(card_nfc) NfcBridge::NfcBridge() #ifdef Q_OS_ANDROID - : mJavaConnector(getJavaParent().callObjectMethod("getNfcConnector", "()Lcom/governikus/ausweisapp2/NFCConnector;")) + : mJavaConnector(QtAndroid::androidContext().callObjectMethod("getNfcConnector", "()Lcom/governikus/ausweisapp2/NFCConnector;")) #endif { } @@ -40,22 +40,9 @@ NfcBridge& NfcBridge::getInstance() #ifdef Q_OS_ANDROID -QAndroidJniObject NfcBridge::getJavaParent() -{ - if (QtAndroid::androidActivity().isValid()) - { - qCDebug(card_nfc) << "Parent is an activity."; - return QtAndroid::androidActivity(); - } - - qCDebug(card_nfc) << "Parent is a service."; - return QtAndroid::androidService(); -} - - QAndroidJniObject NfcBridge::getApplicationContext() { - QAndroidJniObject application = getJavaParent().callObjectMethod("getApplication", "()Landroid/app/Application;"); + QAndroidJniObject application = QtAndroid::androidContext().callObjectMethod("getApplication", "()Landroid/app/Application;"); if (application == nullptr) { qCCritical(card_nfc) << "Cannot get application"; @@ -96,9 +83,22 @@ QByteArray NfcBridge::convert(const jbyteArray& pData) } +QAndroidJniObject NfcBridge::getNfcAdapter() +{ + QAndroidJniObject context = getApplicationContext(); + if (context == nullptr) + { + qCCritical(card_nfc) << "Cannot get context"; + return QAndroidJniObject(); + } + + return QAndroidJniObject::callStaticObjectMethod("android/nfc/NfcAdapter", "getDefaultAdapter", "(Landroid/content/Context;)Landroid/nfc/NfcAdapter;", context.object()); +} + + #endif -NfcCardCode NfcBridge::getCardStatus() +NfcCardCode NfcBridge::getCardStatus() const { #ifdef Q_OS_ANDROID if (isValid()) @@ -112,7 +112,46 @@ NfcCardCode NfcBridge::getCardStatus() } -ExtendedLengthApduSupportCode NfcBridge::getExtendedLengthApduSupportStatus() +bool NfcBridge::connectCard() const +{ +#ifdef Q_OS_ANDROID + if (isValid()) + { + return static_cast(mJavaConnector.callMethod("connectCard")); + } + +#endif + return false; +} + + +bool NfcBridge::disconnectCard() const +{ +#ifdef Q_OS_ANDROID + if (isValid()) + { + return static_cast(mJavaConnector.callMethod("disconnectCard")); + } + +#endif + return false; +} + + +bool NfcBridge::isCardConnected() const +{ +#ifdef Q_OS_ANDROID + if (isValid()) + { + return static_cast(mJavaConnector.callMethod("isCardConnected")); + } + +#endif + return false; +} + + +ExtendedLengthApduSupportCode NfcBridge::getExtendedLengthApduSupportStatus() const { #ifdef Q_OS_ANDROID if (isValid()) @@ -126,17 +165,11 @@ ExtendedLengthApduSupportCode NfcBridge::getExtendedLengthApduSupportStatus() } -bool NfcBridge::isNfcEnabled() +bool NfcBridge::isNfcEnabled() const { #ifdef Q_OS_ANDROID - QAndroidJniObject context = getApplicationContext(); - if (context == nullptr) - { - qCCritical(card_nfc) << "Cannot get context"; - return false; - } + auto nfcAdapter = getNfcAdapter(); - QAndroidJniObject nfcAdapter = QAndroidJniObject::callStaticObjectMethod("android/nfc/NfcAdapter", "getDefaultAdapter", "(Landroid/content/Context;)Landroid/nfc/NfcAdapter;", context.object()); if (nfcAdapter == nullptr) { qCWarning(card_nfc) << "Cannot get default NfcAdapter"; @@ -152,7 +185,19 @@ bool NfcBridge::isNfcEnabled() } -bool NfcBridge::isValid() +bool NfcBridge::isNfcAvailable() const +{ +#ifdef Q_OS_ANDROID + return getNfcAdapter() != nullptr; + +#else + return false; + +#endif +} + + +bool NfcBridge::isValid() const { #ifdef Q_OS_ANDROID return mJavaConnector != nullptr; diff --git a/src/card/nfc/NfcBridge.h b/src/card/nfc/NfcBridge.h index aa4faad..758e513 100644 --- a/src/card/nfc/NfcBridge.h +++ b/src/card/nfc/NfcBridge.h @@ -35,8 +35,8 @@ class NfcBridge #ifdef Q_OS_ANDROID QAndroidJniObject mJavaConnector; - static QAndroidJniObject getJavaParent(); static QAndroidJniObject getApplicationContext(); + static QAndroidJniObject getNfcAdapter(); static QByteArray convert(const jbyteArray& pData); static jbyteArray convert(const QByteArray& pData); #endif @@ -50,10 +50,14 @@ class NfcBridge public: static NfcBridge& getInstance(); - bool isValid(); - bool isNfcEnabled(); - NfcCardCode getCardStatus(); - ExtendedLengthApduSupportCode getExtendedLengthApduSupportStatus(); + bool isValid() const; + bool isNfcEnabled() const; + bool isNfcAvailable() const; + NfcCardCode getCardStatus() const; + bool connectCard() const; + bool disconnectCard() const; + bool isCardConnected() const; + ExtendedLengthApduSupportCode getExtendedLengthApduSupportStatus() const; bool start(); bool stop(); QByteArray sendData(const QByteArray& pData); diff --git a/src/card/nfc/NfcCard.cpp b/src/card/nfc/NfcCard.cpp index 06e2ab9..fad92cb 100644 --- a/src/card/nfc/NfcCard.cpp +++ b/src/card/nfc/NfcCard.cpp @@ -13,7 +13,6 @@ Q_DECLARE_LOGGING_CATEGORY(card_nfc) NfcCard::NfcCard() : Card() - , mConnected(false) { } @@ -23,39 +22,41 @@ NfcCard::~NfcCard() } -ReturnCode NfcCard::connect() +CardReturnCode NfcCard::connect() { - if (isConnected()) +#ifdef Q_OS_ANDROID + if (NfcBridge::getInstance().connectCard()) { - qCCritical(card_nfc) << "Card is already connected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::OK; } - - mConnected = true; - return ReturnCode::OK; +#endif + return CardReturnCode::COMMAND_FAILED; } -ReturnCode NfcCard::disconnect() +CardReturnCode NfcCard::disconnect() { - if (!isConnected()) +#ifdef Q_OS_ANDROID + if (NfcBridge::getInstance().disconnectCard()) { - qCCritical(card_nfc) << "Card is already disconnected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::OK; } - - mConnected = false; - return ReturnCode::OK; +#endif + return CardReturnCode::COMMAND_FAILED; } bool NfcCard::isConnected() { - return mConnected; +#ifdef Q_OS_ANDROID + return NfcBridge::getInstance().isCardConnected(); + +#endif + return false; } -ReturnCode NfcCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) +CardReturnCode NfcCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { #ifdef Q_OS_ANDROID qCDebug(card_nfc) << "Transmit command APDU: " << pCmd.getBuffer().toHex(); @@ -64,7 +65,7 @@ ReturnCode NfcCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) if (recvBuffer.isEmpty()) { qCWarning(card_nfc) << "No response received"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } NfcConnectorCode status = static_cast(recvBuffer.at(0)); @@ -72,42 +73,22 @@ ReturnCode NfcCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { pRes.setBuffer(recvBuffer.mid(1)); qCDebug(card_nfc) << "Transmit response APDU: " << pRes.getBuffer().toHex(); - return ReturnCode::OK; + return CardReturnCode::OK; } else if (status == NfcConnectorCode::ERROR_TAG_LOST || status == NfcConnectorCode::ERROR_NO_TAG) { qCWarning(card_nfc) << "Transmit error: " << status; Q_EMIT fireCardRemoved(); - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } else { qCWarning(card_nfc) << "Transmit error: " << status; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } #endif Q_UNUSED(pCmd); Q_UNUSED(pRes); - return ReturnCode::UNDEFINED; -} - - -ReturnCode NfcCard::establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) -{ - Q_UNUSED(pPinId); - Q_UNUSED(pChat); - Q_UNUSED(pCertificateDescription); - Q_UNUSED(pChannelOutput); - Q_UNUSED(pTimeoutSeconds); - qCWarning(card_nfc) << "NFC does not support establishPaceChannel"; - return ReturnCode::COMMAND_FAILED; -} - - -ReturnCode NfcCard::setEidPin(unsigned int pTimeoutSeconds) -{ - Q_UNUSED(pTimeoutSeconds); - qCWarning(card_nfc) << "NFC does not support setEidPin"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::UNDEFINED; } diff --git a/src/card/nfc/NfcCard.h b/src/card/nfc/NfcCard.h index 1080a03..4b436c9 100644 --- a/src/card/nfc/NfcCard.h +++ b/src/card/nfc/NfcCard.h @@ -15,9 +15,6 @@ class NfcCard { Q_OBJECT - private: - bool mConnected; - Q_SIGNALS: void fireCardRemoved(); @@ -25,15 +22,11 @@ class NfcCard NfcCard(); virtual ~NfcCard(); - virtual ReturnCode connect() override; - virtual ReturnCode disconnect() override; + virtual CardReturnCode connect() override; + virtual CardReturnCode disconnect() override; virtual bool isConnected() override; - virtual ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - - virtual ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) override; - - virtual ReturnCode setEidPin(unsigned int pTimeoutSeconds) override; + virtual CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; }; } /* namespace governikus */ diff --git a/src/card/nfc/NfcReader.cpp b/src/card/nfc/NfcReader.cpp index 4873fa3..0c53b2a 100644 --- a/src/card/nfc/NfcReader.cpp +++ b/src/card/nfc/NfcReader.cpp @@ -43,7 +43,7 @@ Reader::CardEvent NfcReader::updateCard() if (mReaderInfo.getExtendedLengthApduSupportCode() != code) { mReaderInfo.setExtendedLengthApduSupportCode(code); - Q_EMIT fireReaderPropertiesUpdated(); + Q_EMIT fireReaderPropertiesUpdated(getName()); } if (mCard.isNull() && NfcBridge::getInstance().getCardStatus() == NfcCardCode::NEW_CARD) @@ -57,19 +57,11 @@ Reader::CardEvent NfcReader::updateCard() return CardEvent::CARD_INSERTED; } - if (!mCard.isNull()) + if (!mCard.isNull() && NfcBridge::getInstance().getCardStatus() == NfcCardCode::NO_CARD) { - QSharedPointer cardConnection = createCardConnectionWorker(); - static CommandApdu selectMfCommand = SelectBuilder(FileRef::masterFile()).build(); - static ResponseApdu response; - const QSignalBlocker blockFireCardRemoved(mCard.data()); - if (!cardConnection.isNull() && cardConnection->transmit(selectMfCommand, response) != ReturnCode::OK) - { - qCDebug(card_nfc) << "Card removed"; - mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); - mCard.reset(); - return CardEvent::CARD_REMOVED; - } + mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); + mCard.reset(); + return CardEvent::CARD_REMOVED; } #endif @@ -84,5 +76,4 @@ void NfcReader::onCardRemoved() mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); mCard.reset(); Q_EMIT fireCardRemoved(getName()); - } diff --git a/src/card/nfc/NfcReaderManagerPlugIn.cpp b/src/card/nfc/NfcReaderManagerPlugIn.cpp index b70753f..339ecd2 100644 --- a/src/card/nfc/NfcReaderManagerPlugIn.cpp +++ b/src/card/nfc/NfcReaderManagerPlugIn.cpp @@ -47,7 +47,7 @@ JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_NfcAdapterStateChangeRece NfcReaderManagerPlugIn::NfcReaderManagerPlugIn() - : ReaderManagerPlugIn(ReaderManagerPlugInType::NFC) + : ReaderManagerPlugIn(ReaderManagerPlugInType::NFC, NfcBridge::getInstance().isNfcAvailable()) , mInitialized(false) , mReaderList() { diff --git a/src/card/pcsc/PcscCard.cpp b/src/card/pcsc/PcscCard.cpp index 0b4264e..c1c3157 100644 --- a/src/card/pcsc/PcscCard.cpp +++ b/src/card/pcsc/PcscCard.cpp @@ -62,12 +62,12 @@ void PcscCard::sendSCardStatus() } -ReturnCode PcscCard::connect() +CardReturnCode PcscCard::connect() { if (PcscCard::isConnected()) { qCCritical(card_pcsc) << "Card is already connected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } PCSC_INT shareMode = SCARD_SHARE_SHARED; @@ -75,33 +75,33 @@ ReturnCode PcscCard::connect() PCSC_RETURNCODE returnCode = SCardConnect(mContextHandle, mReader->getState().szReader, shareMode, preferredProtocols, &mCardHandle, &mProtocol); qCDebug(card_pcsc) << "SCardConnect for " << mReader->getName() << " : " << PcscUtils::toString(returnCode) << " cardHandle: " << mCardHandle << " protocol: T" << (mProtocol - 1); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } returnCode = SCardBeginTransaction(mCardHandle); qCDebug(card_pcsc) << "SCardBeginTransaction for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { SCardDisconnect(mCardHandle, SCARD_LEAVE_CARD); - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8) { mTimer.start(); } - return ReturnCode::OK; + return CardReturnCode::OK; } -ReturnCode PcscCard::disconnect() +CardReturnCode PcscCard::disconnect() { if (!PcscCard::isConnected()) { qCCritical(card_pcsc) << "Card is already disconnected"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } mTimer.stop(); @@ -113,7 +113,7 @@ ReturnCode PcscCard::disconnect() mProtocol = 0; qCDebug(card_pcsc) << "SCardDisconnect for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); - return returnCode == SCARD_S_SUCCESS ? ReturnCode::OK : ReturnCode::COMMAND_FAILED; + return returnCode == PcscUtils::Scard_S_Success ? CardReturnCode::OK : CardReturnCode::COMMAND_FAILED; } @@ -123,19 +123,19 @@ bool PcscCard::isConnected() } -ReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) +CardReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { if (!isConnected()) { qCCritical(card_pcsc) << "Card is not connected, abort transmit"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } QByteArray receiveBuffer; PCSC_RETURNCODE returnCode = transmit(pCmd.getBuffer(), receiveBuffer); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } ResponseApdu tempResponse; @@ -146,9 +146,9 @@ ReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) qCDebug(card_pcsc) << "got SW1 == 0x6c, retransmitting with new Le:" << tempResponse.getSW2(); CommandApdu retransmitCommand(pCmd.getCLA(), pCmd.getINS(), pCmd.getP1(), pCmd.getP2(), pCmd.getData(), tempResponse.getSW2()); returnCode = transmit(retransmitCommand.getBuffer(), receiveBuffer); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } } @@ -158,19 +158,19 @@ ReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) qCDebug(card_pcsc) << "got SW1 == 0x61, getting response with Le:" << tempResponse.getSW2(); CommandApdu getResponseCommand(0, char(0xC0), 0, 0, QByteArray(), tempResponse.getSW2()); returnCode = transmit(getResponseCommand.getBuffer(), tempReceiveBuffer); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } tempResponse.setBuffer(tempReceiveBuffer); // cut off sw1 and sw2 receiveBuffer.resize(receiveBuffer.size() - 2); - receiveBuffer.append(tempReceiveBuffer); + receiveBuffer += tempReceiveBuffer; } pRes.setBuffer(receiveBuffer); - return ReturnCode::OK; + return CardReturnCode::OK; } @@ -193,7 +193,7 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, QByteArray& pR default: qCDebug(card_pcsc) << "unsupported protocol"; - return SCARD_E_PROTO_MISMATCH; + return PcscUtils::Scard_E_Proto_Mismatch; } SCARD_IO_REQUEST recvPci; @@ -201,19 +201,19 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, QByteArray& pR recvPci.cbPciLength = sizeof(SCARD_IO_REQUEST); pReceiveBuffer.fill(0x00, 8192); - PCSC_INT bytesReceived = pReceiveBuffer.size(); + PCSC_INT bytesReceived = static_cast(pReceiveBuffer.size()); PCSC_RETURNCODE returnCode = transmit(pSendBuffer, pReceiveBuffer, sendPci, recvPci, bytesReceived); /* * Reconnecting makes only sense, when no secure messaging channel is active. * Otherwise the secure messaging channel is destroyed and the transmit will fail anyway. */ - if (returnCode == SCARD_W_RESET_CARD && !CommandApdu::isSecureMessaging(pSendBuffer)) + if (returnCode == PcscUtils::Scard_W_Reset_Card && !CommandApdu::isSecureMessaging(pSendBuffer)) { returnCode = SCardReconnect(mCardHandle, SCARD_SHARE_SHARED, mProtocol, SCARD_RESET_CARD, nullptr); qCDebug(card_pcsc) << "Reconnect to Card"; - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCCritical(card_pcsc) << "SCardReconnect failed:" << PcscUtils::toString(returnCode); return returnCode; @@ -221,22 +221,28 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, QByteArray& pR returnCode = SCardBeginTransaction(mCardHandle); qCDebug(card_pcsc) << "SCardBeginTransaction:" << PcscUtils::toString(returnCode); - bytesReceived = pReceiveBuffer.size(); + bytesReceived = static_cast(pReceiveBuffer.size()); returnCode = transmit(pSendBuffer, pReceiveBuffer, sendPci, recvPci, bytesReceived); } - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { return returnCode; } - pReceiveBuffer.resize(bytesReceived); + if (bytesReceived > INT_MAX) + { + qCCritical(card_pcsc) << "Max allowed receive buffer size exceeded"; + Q_ASSERT(bytesReceived <= INT_MAX); + return PcscUtils::Scard_F_Unknown_Error; + } + pReceiveBuffer.resize(static_cast(bytesReceived)); qCDebug(card_pcsc) << "SCardTransmit resBuffer " << pReceiveBuffer.toHex(); if (pReceiveBuffer.size() < 2) { qCCritical(card_pcsc) << "Response buffer smaller than 2"; - return SCARD_F_UNKNOWN_ERROR; + return PcscUtils::Scard_F_Unknown_Error; } - return SCARD_S_SUCCESS; + return PcscUtils::Scard_S_Success; } @@ -247,22 +253,22 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, PCSC_INT& pBytesReceived) { qCDebug(card_pcsc) << "SCardTransmit cmdBuffer " << pSendBuffer.toHex(); - PCSC_RETURNCODE returnCode = SCardTransmit(mCardHandle, pSendPci, reinterpret_cast(pSendBuffer.data()), pSendBuffer.size(), &pRecvPci, reinterpret_cast(pReceiveBuffer.data()), &pBytesReceived); + PCSC_RETURNCODE returnCode = SCardTransmit(mCardHandle, pSendPci, reinterpret_cast(pSendBuffer.data()), static_cast(pSendBuffer.size()), &pRecvPci, reinterpret_cast(pReceiveBuffer.data()), &pBytesReceived); qCDebug(card_pcsc) << "SCardTransmit for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); return returnCode; } -ReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, - EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) + EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) { Q_UNUSED(pTimeoutSeconds); if (!mReader->hasFeature(FeatureID::EXECUTE_PACE)) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::EXECUTE_PACE); @@ -273,10 +279,10 @@ ReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, QByteArray controlRes; PCSC_RETURNCODE returnCode = control(cmdID, builder.createCommandData(), controlRes); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Control to establish PACE channel failed"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } pChannelOutput.parse(controlRes, pPinId); @@ -284,23 +290,23 @@ ReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, } -ReturnCode PcscCard::destroyPaceChannel() +CardReturnCode PcscCard::destroyPaceChannel() { if (!mReader->hasFeature(FeatureID::EXECUTE_PACE)) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::EXECUTE_PACE); DestroyPACEChannelBuilder builder; QByteArray controlRes; PCSC_RETURNCODE returnCode = control(cmdID, builder.createCommandData(), controlRes); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Control to destroy PACE channel failed"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } - return ReturnCode::OK; + return CardReturnCode::OK; } @@ -312,39 +318,50 @@ PCSC_RETURNCODE PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCntrInp PCSC_RETURNCODE returnCode = SCardControl(mCardHandle, pCntrCode, pCntrInput.constData(), - pCntrInput.size(), + static_cast(pCntrInput.size()), buffer, sizeof(buffer), &len); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { len = 0; } - Q_ASSERT(sizeof(buffer) >= len); - pCntrOutput.append(buffer, len); + if (sizeof(buffer) < len) + { + qCCritical(card_pcsc) << "Buffer size smaller than read length"; + Q_ASSERT(sizeof(buffer) >= len); + return PcscUtils::Scard_F_Unknown_Error; + } + if (len > INT_MAX) + { + qCCritical(card_pcsc) << "Read length bigger than INT_MAX"; + Q_ASSERT(len <= INT_MAX); + return PcscUtils::Scard_F_Unknown_Error; + } + pCntrOutput.append(buffer, static_cast(len)); qCDebug(card_pcsc) << "SCardControl for " << mReader->getName() << " : " << PcscUtils::toString(returnCode) << " " << pCntrOutput.toHex(); return returnCode; } -ReturnCode PcscCard::setEidPin(unsigned int pTimeoutSeconds) +CardReturnCode PcscCard::setEidPin(uchar pTimeoutSeconds) { if (!mReader->hasFeature(FeatureID::MODIFY_PIN_DIRECT)) { - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::MODIFY_PIN_DIRECT); PinModifyBuilder builder; QByteArray controlRes; PCSC_RETURNCODE pcscReturnCode = control(cmdID, builder.createChangeEidPinCommandData(pTimeoutSeconds), controlRes); - if (pcscReturnCode != SCARD_S_SUCCESS) + if (pcscReturnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Modify PIN failed"; - return ReturnCode::COMMAND_FAILED; + return CardReturnCode::COMMAND_FAILED; } PinModifyOutput output; diff --git a/src/card/pcsc/PcscCard.h b/src/card/pcsc/PcscCard.h index 32d8681..353d6d1 100644 --- a/src/card/pcsc/PcscCard.h +++ b/src/card/pcsc/PcscCard.h @@ -9,9 +9,9 @@ #pragma once #include "Card.h" +#include "CardReturnCode.h" #include "PcscReader.h" #include "PcscUtils.h" -#include "ReturnCode.h" #include #include @@ -50,17 +50,17 @@ class PcscCard PcscCard(PcscReader* pPcscReader); virtual ~PcscCard(); - virtual ReturnCode connect() override; - virtual ReturnCode disconnect() override; + virtual CardReturnCode connect() override; + virtual CardReturnCode disconnect() override; virtual bool isConnected() override; - virtual ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; + virtual CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - virtual ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) override; + virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; - virtual ReturnCode destroyPaceChannel() override; + virtual CardReturnCode destroyPaceChannel() override; - virtual ReturnCode setEidPin(unsigned int pTimeoutSeconds) override; + virtual CardReturnCode setEidPin(uchar pTimeoutSeconds) override; }; } /* namespace governikus */ diff --git a/src/card/pcsc/PcscReader.cpp b/src/card/pcsc/PcscReader.cpp index 88b8421..75507ac 100644 --- a/src/card/pcsc/PcscReader.cpp +++ b/src/card/pcsc/PcscReader.cpp @@ -28,7 +28,7 @@ PcscReader::PcscReader(const QString& pReaderName) PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); qCDebug(card_pcsc) << "SCardEstablishContext: " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Cannot establish context"; return; @@ -45,7 +45,7 @@ PcscReader::PcscReader(const QString& pReaderName) #endif returnCode = readReaderFeaturesAndPACECapabilities(); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Features / Capabilities not successful: " << returnCode; return; @@ -90,57 +90,57 @@ PCSC_INT PcscReader::getFeatureValue(FeatureID pFeatureID) } -static QString SCARD_STATE_toString(int i) +template static QString SCARD_STATE_toString(T i) { - QString sb = QString().sprintf("(%#x)", i); + QString sb = QString().sprintf("(%#lx)", static_cast(i)); if ((i & SCARD_STATE_UNAWARE) != 0) { - sb.append(" UNAWARE"); + sb += QStringLiteral(" UNAWARE"); } if ((i & SCARD_STATE_IGNORE) != 0) { - sb.append(" IGNORE"); + sb += QStringLiteral(" IGNORE"); } if ((i & SCARD_STATE_CHANGED) != 0) { - sb.append(" CHANGED"); + sb += QStringLiteral(" CHANGED"); } if ((i & SCARD_STATE_UNKNOWN) != 0) { - sb.append(" UNKNOWN"); + sb += QStringLiteral(" UNKNOWN"); } if ((i & SCARD_STATE_UNAVAILABLE) != 0) { - sb.append(" UNAVAILABLE"); + sb += QStringLiteral(" UNAVAILABLE"); } if ((i & SCARD_STATE_EMPTY) != 0) { - sb.append(" EMPTY"); + sb += QStringLiteral(" EMPTY"); } if ((i & SCARD_STATE_PRESENT) != 0) { - sb.append(" PRESENT"); + sb += QStringLiteral(" PRESENT"); } if ((i & SCARD_STATE_ATRMATCH) != 0) { - sb.append(" ATRMATCH"); + sb += QStringLiteral(" ATRMATCH"); } if ((i & SCARD_STATE_EXCLUSIVE) != 0) { - sb.append(" EXCLUSIVE"); + sb += QStringLiteral(" EXCLUSIVE"); } if ((i & SCARD_STATE_INUSE) != 0) { - sb.append(" INUSE"); + sb += QStringLiteral(" INUSE"); } if ((i & SCARD_STATE_MUTE) != 0) { - sb.append(" MUTE"); + sb += QStringLiteral(" MUTE"); } if ((i & SCARD_STATE_UNPOWERED) != 0) { - sb.append(" UNPOWERED"); + sb += QStringLiteral(" UNPOWERED"); } return sb; } @@ -158,11 +158,11 @@ bool PcscReader::hasPaceCapability(PaceCapabilityId pPaceCapability) Reader::CardEvent PcscReader::updateCard() { PCSC_RETURNCODE returnCode = SCardGetStatusChange(mContextHandle, 0, &mReaderState, 1); - if (returnCode == SCARD_E_TIMEOUT) + if (returnCode == PcscUtils::Scard_E_Timeout) { return Reader::CardEvent::NONE; } - else if (returnCode == SCARD_E_UNKNOWN_READER) + else if (returnCode == PcscUtils::Scard_E_Unknown_Reader) { qCWarning(card_pcsc) << "SCardGetStatusChange: " << PcscUtils::toString(returnCode); qCWarning(card_pcsc) << "Reader unknown, stop updating reader information"; @@ -173,7 +173,7 @@ Reader::CardEvent PcscReader::updateCard() } return Reader::CardEvent::NONE; } - else if (returnCode != SCARD_S_SUCCESS) + else if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "SCardGetStatusChange: " << PcscUtils::toString(returnCode); qCWarning(card_pcsc) << "Cannot update reader"; @@ -250,7 +250,7 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() qCDebug(card_pcsc) << str; PCSC_RETURNCODE returnCode = SCardConnect(mContextHandle, mReaderState.szReader, SCARD_SHARE_DIRECT, PROTOCOL, &cardHandle, &protocol); qCDebug(card_pcsc) << "SCardConnect for " << mReaderInfo.getName() << ": " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { return returnCode; } @@ -269,20 +269,32 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() PCSC_INT clen = 0; returnCode = SCardControl(cardHandle, CM_IOCTL_GET_FEATURE_REQUEST, inBuffer1, 2, buffer, sizeof(buffer), &clen); - Q_ASSERT(sizeof(buffer) >= clen); qCDebug(card_pcsc) << "SCardControl for " << mReaderInfo.getName() << ": " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + + if (returnCode != PcscUtils::Scard_S_Success) { clen = 0; } + if (sizeof(buffer) < clen) + { + qCCritical(card_pcsc) << "Buffer size smaller than read length"; + Q_ASSERT(sizeof(buffer) >= clen); + return PcscUtils::Scard_F_Unknown_Error; + } + if (clen > INT_MAX) + { + qCCritical(card_pcsc) << "Read length > INT_MAX not supported"; + Q_ASSERT(clen <= INT_MAX); + return PcscUtils::Scard_F_Unknown_Error; + } - qCDebug(card_pcsc) << "FEATURES:" << QByteArray(buffer, clen).toHex(); + qCDebug(card_pcsc) << "FEATURES:" << QByteArray(buffer, static_cast(clen)).toHex(); mReaderFeatures = PcscReaderFeature(buffer, clen); qCDebug(card_pcsc) << "FEATURES:" << mReaderFeatures.toString(); if (mReaderFeatures.getFeatures().contains(FeatureID::EXECUTE_PACE)) { - int cmdID = mReaderFeatures.getFeatures().find(FeatureID::EXECUTE_PACE).value(); + PCSC_INT cmdID = mReaderFeatures.getFeatures().find(FeatureID::EXECUTE_PACE).value(); clen = 0; @@ -291,20 +303,33 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() }; // idx for GetReaderPACECapabilities (0x01), length (0, 0) qCDebug(card_pcsc) << "SCardControl ... "; returnCode = SCardControl(cardHandle, cmdID, inBuffer2, 3, buffer, sizeof(buffer), &clen); - Q_ASSERT(sizeof(buffer) >= clen); qCDebug(card_pcsc) << "SCardControl for " << mReaderInfo.getName() << ": " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + + if (returnCode != PcscUtils::Scard_S_Success) { clen = 0; } + if (sizeof(buffer) < clen) + { + qCCritical(card_pcsc) << "Buffer size smaller than read length"; + Q_ASSERT(sizeof(buffer) >= clen); + return PcscUtils::Scard_F_Unknown_Error; + } + if (clen > INT_MAX) + { + qCCritical(card_pcsc) << "Read length bigger than INT_MAX"; + Q_ASSERT(clen <= INT_MAX); + return PcscUtils::Scard_F_Unknown_Error; + } + + qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << QByteArray(buffer, static_cast(clen)).toHex(); + mPaceCapabilities = PcscReaderPaceCapability(buffer, clen); + qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << mPaceCapabilities.toString(); } else { clen = 0; } - qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << QByteArray(buffer, clen).toHex(); - mPaceCapabilities = PcscReaderPaceCapability(buffer, clen); - qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << mPaceCapabilities.toString(); // disconnect returnCode = SCardDisconnect(cardHandle, SCARD_LEAVE_CARD); diff --git a/src/card/pcsc/PcscReaderFeature.cpp b/src/card/pcsc/PcscReaderFeature.cpp index ba95086..78a8886 100644 --- a/src/card/pcsc/PcscReaderFeature.cpp +++ b/src/card/pcsc/PcscReaderFeature.cpp @@ -33,7 +33,7 @@ template static QString toStringListing(const T& pList) } -const QMap& PcscReaderFeature::getFeatures() const +const QMap& PcscReaderFeature::getFeatures() const { return mFeatures; } @@ -64,8 +64,8 @@ PcscReaderFeature::PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength) // skip length byte (always 1 byte : 0x04) ++runner; - int value = 0; - value += *runner++ << 24 & 0xff000000; + PCSC_INT value = 0; + value += static_cast(*runner++) << 24 & 0xff000000; value += *runner++ << 16 & 0x00ff0000; value += *runner++ << 8 & 0x0000ff00; value += *runner++ << 0 & 0x000000ff; @@ -102,11 +102,11 @@ PcscReaderPaceCapability::PcscReaderPaceCapability(const char* pCapabilitiesTLV, } // in contrast to PCSC 10 Amendment 1: the output data of GetReaderPACECapabilities on Reiner SCT Konfort is of size 1! - for (PaceCapabilityId capability : EnumPaceCapabilityId::getList()) + for (PaceCapabilityId capability : Enum::getList()) { if (pCapabilitiesTLV[6] & static_cast(capability)) { - mPaceCapabilities.append(capability); + mPaceCapabilities += capability; } } } diff --git a/src/card/pcsc/PcscReaderFeature.h b/src/card/pcsc/PcscReaderFeature.h index aede0db..541e4ef 100644 --- a/src/card/pcsc/PcscReaderFeature.h +++ b/src/card/pcsc/PcscReaderFeature.h @@ -36,13 +36,13 @@ defineEnumType(FeatureID, class PcscReaderFeature { private: - QMap mFeatures; + QMap mFeatures; public: PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength = 0); QString toString() const; - const QMap& getFeatures() const; + const QMap& getFeatures() const; }; defineEnumType(PaceCapabilityId, ESIGN = 0x10, EID = 0x20, GENERIC = 0x40, DESTROY_CHANNEL = 0x80) diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.cpp b/src/card/pcsc/PcscReaderManagerPlugIn.cpp index 21f6250..478e712 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.cpp +++ b/src/card/pcsc/PcscReaderManagerPlugIn.cpp @@ -17,7 +17,7 @@ Q_DECLARE_LOGGING_CATEGORY(card_pcsc) PcscReaderManagerPlugIn::PcscReaderManagerPlugIn() - : ReaderManagerPlugIn(ReaderManagerPlugInType::PCSC) + : ReaderManagerPlugIn(ReaderManagerPlugInType::PCSC, true) , mContextHandle(0) , mReaderState() , mTimerId(0) @@ -40,7 +40,7 @@ PcscReaderManagerPlugIn::~PcscReaderManagerPlugIn() while (!mReaders.isEmpty()) { - removeReader(mReaders.first()->getName()); + removeReader(qAsConst(mReaders).first()->getName()); } } @@ -55,9 +55,9 @@ void PcscReaderManagerPlugIn::init() { ReaderManagerPlugIn::init(); PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - setReaderInfoEnabled(returnCode == SCARD_S_SUCCESS); + setReaderInfoEnabled(returnCode == PcscUtils::Scard_S_Success); qCDebug(card_pcsc) << "SCardEstablishContext: " << PcscUtils::toString(returnCode); - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Not started: Cannot establish context"; } @@ -81,7 +81,7 @@ void PcscReaderManagerPlugIn::shutdown() PCSC_RETURNCODE returnCode = SCardReleaseContext(mContextHandle); qCDebug(card_pcsc) << "SCardReleaseContext: " << PcscUtils::toString(returnCode); mContextHandle = 0; - if (returnCode != SCARD_S_SUCCESS) + if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "Error releasing context"; } @@ -122,11 +122,11 @@ void PcscReaderManagerPlugIn::updateReaders() } PCSC_RETURNCODE returnCode = readReaderNames(readersToAdd); - if (returnCode != SCARD_S_SUCCESS && returnCode != SCARD_E_NO_READERS_AVAILABLE) + if (returnCode != PcscUtils::Scard_S_Success && returnCode != PcscUtils::Scard_E_No_Readers_Available) { qCWarning(card_pcsc) << "Cannot update readers"; - if (returnCode == SCARD_E_NO_SERVICE && mTimerId != 0) + if (returnCode == PcscUtils::Scard_E_No_Service && mTimerId != 0) { // Work around for an issue on Linux: Sometimes when unplugging a reader // the library seems to get confused and any further calls with existing @@ -136,7 +136,7 @@ void PcscReaderManagerPlugIn::updateReaders() shutdown(); init(); } - else if (returnCode == SCARD_E_SERVICE_STOPPED && mTimerId != 0) + else if (returnCode == PcscUtils::Scard_E_Service_Stopped && mTimerId != 0) { // Work around for an issue on Windows 8.1: Sometimes when unplugging a reader // the library seems to get confused and any further calls with existing @@ -146,7 +146,7 @@ void PcscReaderManagerPlugIn::updateReaders() shutdown(); init(); } - else if (returnCode == SCARD_E_INVALID_HANDLE && mTimerId != 0) + else if (returnCode == PcscUtils::Scard_E_Invalid_Handle && mTimerId != 0) { // If the pc/sc daemon terminates on Linux, the handle is invalidated. We try // to restart the manager in this case. @@ -213,13 +213,13 @@ PCSC_RETURNCODE PcscReaderManagerPlugIn::readReaderNames(QStringList& pReaderNam { QVarLengthArray readers; - PCSC_INT maxReadersSize = readers.capacity(); + PCSC_INT maxReadersSize = static_cast(readers.capacity()); PCSC_RETURNCODE returnCode = SCardListReaders(mContextHandle, nullptr, readers.data(), &maxReadersSize); - if (returnCode == SCARD_E_NO_READERS_AVAILABLE) + if (returnCode == PcscUtils::Scard_E_No_Readers_Available) { return returnCode; } - else if (returnCode != SCARD_S_SUCCESS) + else if (returnCode != PcscUtils::Scard_S_Success) { qCWarning(card_pcsc) << "SCardListReaders: " << PcscUtils::toString(returnCode); qCWarning(card_pcsc) << "Cannot read reader names"; @@ -231,7 +231,7 @@ PCSC_RETURNCODE PcscReaderManagerPlugIn::readReaderNames(QStringList& pReaderNam while (pReader < end) { QString readerName = extractReaderName(pReader); - pReaderNames.append(readerName); + pReaderNames += readerName; // Advance to the next value. pReader += readerName.size() + 1; } diff --git a/src/card/pcsc/PcscUtils.cpp b/src/card/pcsc/PcscUtils.cpp index 5d98fe8..09067f2 100644 --- a/src/card/pcsc/PcscUtils.cpp +++ b/src/card/pcsc/PcscUtils.cpp @@ -11,191 +11,190 @@ using namespace governikus; QString PcscUtils::toString(PCSC_RETURNCODE pCode) { - switch (static_cast(pCode)) + switch (pCode) { - case SCARD_S_SUCCESS: + case Scard_S_Success: return QStringLiteral("SCARD_S_SUCCESS"); - case SCARD_F_INTERNAL_ERROR: + case Scard_F_Internal_Error: return QStringLiteral("SCARD_F_INTERNAL_ERROR"); - case SCARD_E_CANCELLED: + case Scard_E_Cancelled: return QStringLiteral("SCARD_E_CANCELLED"); - case SCARD_E_INVALID_HANDLE: + case Scard_E_Invalid_Handle: return QStringLiteral("SCARD_E_INVALID_HANDLE"); - case SCARD_E_INVALID_PARAMETER: + case Scard_E_Invalid_Parameter: return QStringLiteral("SCARD_E_INVALID_PARAMETER"); - case SCARD_E_INVALID_TARGET: + case Scard_E_Invalid_Target: return QStringLiteral("SCARD_E_INVALID_TARGET"); - case SCARD_E_NO_MEMORY: + case Scard_E_No_Memory: return QStringLiteral("SCARD_E_NO_MEMORY"); - case SCARD_F_WAITED_TOO_LONG: + case Scard_F_Waited_Too_Long: return QStringLiteral("SCARD_F_WAITED_TOO_LONG"); - case SCARD_E_INSUFFICIENT_BUFFER: + case Scard_E_Insufficient_Buffer: return QStringLiteral("SCARD_E_INSUFFICIENT_BUFFER"); - case SCARD_E_UNKNOWN_READER: + case Scard_E_Unknown_Reader: return QStringLiteral("SCARD_E_UNKNOWN_READER"); - case SCARD_E_TIMEOUT: + case Scard_E_Timeout: return QStringLiteral("SCARD_E_TIMEOUT"); - case SCARD_E_SHARING_VIOLATION: + case Scard_E_Sharing_Violation: return QStringLiteral("SCARD_E_SHARING_VIOLATION"); - case SCARD_E_NO_SMARTCARD: + case Scard_E_No_Smartcard: return QStringLiteral("SCARD_E_NO_SMARTCARD"); - case SCARD_E_UNKNOWN_CARD: + case Scard_E_Unknown_Card: return QStringLiteral("SCARD_E_UNKNOWN_CARD"); - case SCARD_E_CANT_DISPOSE: + case Scard_E_Cant_Dispose: return QStringLiteral("SCARD_E_CANT_DISPOSE"); - case SCARD_E_PROTO_MISMATCH: + case Scard_E_Proto_Mismatch: return QStringLiteral("SCARD_E_PROTO_MISMATCH"); - case SCARD_E_NOT_READY: + case Scard_E_Not_Ready: return QStringLiteral("SCARD_E_NOT_READY"); - case SCARD_E_INVALID_VALUE: + case Scard_E_Invalid_Value: return QStringLiteral("SCARD_E_INVALID_VALUE"); - case SCARD_E_SYSTEM_CANCELLED: + case Scard_E_System_Cancelled: return QStringLiteral("SCARD_E_SYSTEM_CANCELLED"); - case SCARD_F_COMM_ERROR: + case Scard_F_Comm_Error: return QStringLiteral("SCARD_F_COMM_ERROR"); - case SCARD_F_UNKNOWN_ERROR: + case Scard_F_Unknown_Error: return QStringLiteral("SCARD_F_UNKNOWN_ERROR"); - case SCARD_E_INVALID_ATR: + case Scard_E_Invalid_Atr: return QStringLiteral("SCARD_E_INVALID_ATR"); - case SCARD_E_NOT_TRANSACTED: + case Scard_E_Not_Transacted: return QStringLiteral("SCARD_E_NOT_TRANSACTED"); - case SCARD_E_READER_UNAVAILABLE: + case Scard_E_Reader_Unavailable: return QStringLiteral("SCARD_E_READER_UNAVAILABLE"); - case SCARD_P_SHUTDOWN: + case Scard_P_Shutdown: return QStringLiteral("SCARD_P_SHUTDOWN"); - case SCARD_E_PCI_TOO_SMALL: + case Scard_E_Pci_Too_Small: return QStringLiteral("SCARD_E_PCI_TOO_SMALL"); - case SCARD_E_READER_UNSUPPORTED: + case Scard_E_Reader_Unsupported: return QStringLiteral("SCARD_E_READER_UNSUPPORTED"); - case SCARD_E_DUPLICATE_READER: + case Scard_E_Duplicate_Reader: return QStringLiteral("SCARD_E_DUPLICATE_READER"); - case SCARD_E_CARD_UNSUPPORTED: + case Scard_E_Card_Unsupported: return QStringLiteral("SCARD_E_CARD_UNSUPPORTED"); - case SCARD_E_NO_SERVICE: + case Scard_E_No_Service: return QStringLiteral("SCARD_E_NO_SERVICE"); - case SCARD_E_SERVICE_STOPPED: + case Scard_E_Service_Stopped: return QStringLiteral("SCARD_E_SERVICE_STOPPED"); - case SCARD_E_UNEXPECTED: - return QStringLiteral("SCARD_E_UNEXPECTED"); - - case SCARD_E_ICC_INSTALLATION: + case Scard_E_Icc_Installation: return QStringLiteral("SCARD_E_ICC_INSTALLATION"); - case SCARD_E_ICC_CREATEORDER: + case Scard_E_Icc_Createorder: return QStringLiteral("SCARD_E_ICC_CREATEORDER"); - //case SCARD_E_UNSUPPORTED_FEATURE: return QStringLiteral("SCARD_E_UNSUPPORTED_FEATURE"); - case SCARD_E_DIR_NOT_FOUND: + // Scard_E_Unexpected has the same value as Scard_E_Unsupported_Feature, no + // separate case for it. + case Scard_E_Unsupported_Feature: + return QStringLiteral("SCARD_E_UNSUPPORTED_FEATURE"); + + case Scard_E_Dir_Not_Found: return QStringLiteral("SCARD_E_DIR_NOT_FOUND"); - case SCARD_E_FILE_NOT_FOUND: + case Scard_E_File_Not_Found: return QStringLiteral("SCARD_E_FILE_NOT_FOUND"); - case SCARD_E_NO_DIR: + case Scard_E_No_Dir: return QStringLiteral("SCARD_E_NO_DIR"); - case SCARD_E_NO_FILE: + case Scard_E_No_File: return QStringLiteral("SCARD_E_NO_FILE"); - case SCARD_E_NO_ACCESS: + case Scard_E_No_Access: return QStringLiteral("SCARD_E_NO_ACCESS"); - case SCARD_E_WRITE_TOO_MANY: + case Scard_E_Write_Too_Many: return QStringLiteral("SCARD_E_WRITE_TOO_MANY"); - case SCARD_E_BAD_SEEK: + case Scard_E_Bad_Seek: return QStringLiteral("SCARD_E_BAD_SEEK"); - case SCARD_E_INVALID_CHV: + case Scard_E_Invalid_Chv: return QStringLiteral("SCARD_E_INVALID_CHV"); - case SCARD_E_UNKNOWN_RES_MNG: + case Scard_E_Unknown_Res_Mng: return QStringLiteral("SCARD_E_UNKNOWN_RES_MNG"); - case SCARD_E_NO_SUCH_CERTIFICATE: + case Scard_E_No_Such_Certificate: return QStringLiteral("SCARD_E_NO_SUCH_CERTIFICATE"); - case SCARD_E_CERTIFICATE_UNAVAILABLE: + case Scard_E_Certificate_Unavailable: return QStringLiteral("SCARD_E_CERTIFICATE_UNAVAILABLE"); - case SCARD_E_NO_READERS_AVAILABLE: + case Scard_E_No_Readers_Available: return QStringLiteral("SCARD_E_NO_READERS_AVAILABLE"); - case SCARD_E_COMM_DATA_LOST: + case Scard_E_Comm_Data_Lost: return QStringLiteral("SCARD_E_COMM_DATA_LOST"); - case SCARD_E_NO_KEY_CONTAINER: + case Scard_E_No_Key_Container: return QStringLiteral("SCARD_E_NO_KEY_CONTAINER"); - case SCARD_E_SERVER_TOO_BUSY: + case Scard_E_Server_Too_Busy: return QStringLiteral("SCARD_E_SERVER_TOO_BUSY"); - case SCARD_W_UNSUPPORTED_CARD: + case Scard_W_Unsupported_Card: return QStringLiteral("SCARD_W_UNSUPPORTED_CARD"); - case SCARD_W_UNRESPONSIVE_CARD: + case Scard_W_Unresponsive_Card: return QStringLiteral("SCARD_W_UNRESPONSIVE_CARD"); - case SCARD_W_UNPOWERED_CARD: + case Scard_W_Unpowered_Card: return QStringLiteral("SCARD_W_UNPOWERED_CARD"); - case SCARD_W_RESET_CARD: + case Scard_W_Reset_Card: return QStringLiteral("SCARD_W_RESET_CARD"); - case SCARD_W_REMOVED_CARD: + case Scard_W_Removed_Card: return QStringLiteral("SCARD_W_REMOVED_CARD"); - case SCARD_W_SECURITY_VIOLATION: + case Scard_W_Security_Violation: return QStringLiteral("SCARD_W_SECURITY_VIOLATION"); - case SCARD_W_WRONG_CHV: + case Scard_W_Wrong_Chv: return QStringLiteral("SCARD_W_WRONG_CHV"); - case SCARD_W_CHV_BLOCKED: + case Scard_W_Chv_Blocked: return QStringLiteral("SCARD_W_CHV_BLOCKED"); - case SCARD_W_EOF: + case Scard_W_Eof: return QStringLiteral("SCARD_W_EOF"); - case SCARD_W_CANCELLED_BY_USER: + case Scard_W_Cancelled_By_User: return QStringLiteral("SCARD_W_CANCELLED_BY_USER"); - case SCARD_W_CARD_NOT_AUTHENTICATED: + case Scard_W_Card_Not_Authenticated: return QStringLiteral("SCARD_W_CARD_NOT_AUTHENTICATED"); - //case SCARD_W_CACHE_ITEM_NOT_FOUND: return QStringLiteral("SCARD_W_CACHE_ITEM_NOT_FOUND"); - //case SCARD_W_CACHE_ITEM_STALE: return QStringLiteral("SCARD_W_CACHE_ITEM_STALE"); default: return QStringLiteral("UNKNOWN_STATE (%1)").arg(pCode, 8, 16, QChar('0')); } diff --git a/src/card/pcsc/PcscUtils.h b/src/card/pcsc/PcscUtils.h index 099cf22..5aac998 100644 --- a/src/card/pcsc/PcscUtils.h +++ b/src/card/pcsc/PcscUtils.h @@ -12,6 +12,7 @@ #include #include +// TODO: Check these codes #ifdef Q_OS_WIN #include typedef LONG PCSC_RETURNCODE; @@ -33,7 +34,7 @@ typedef LPCBYTE PCSC_CUCHAR_PTR; // The return type is actually int32_t (in the system headers), but the return // code macros are defined without a cast operator, which makes them // unsigned int due to a missing cast. -typedef uint32_t PCSC_RETURNCODE; +typedef int64_t PCSC_RETURNCODE; typedef SCARDHANDLE PCSC_CARDHANDLE; typedef uint32_t PCSC_INT; typedef PCSC_INT* PCSC_INT_PTR; @@ -66,7 +67,148 @@ class PcscUtils public: static QString toString(PCSC_RETURNCODE pCode); + + /** + * Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx + */ + enum PcscReturnCode : PCSC_RETURNCODE + { + Scard_S_Success = static_cast(SCARD_S_SUCCESS), /**< No error was encountered. */ + Scard_F_Internal_Error = static_cast(SCARD_F_INTERNAL_ERROR), /**< An internal consistency check failed. */ + Scard_E_Cancelled = static_cast(SCARD_E_CANCELLED), /**< The action was cancelled by an SCardCancel request. */ + Scard_E_Invalid_Handle = static_cast(SCARD_E_INVALID_HANDLE), /**< The supplied handle was invalid. */ + Scard_E_Invalid_Parameter = static_cast(SCARD_E_INVALID_PARAMETER), /**< One or more of the supplied parameters could not be properly interpreted. */ + Scard_E_Invalid_Target = static_cast(SCARD_E_INVALID_TARGET), /**< Registry startup information is missing or invalid. */ + Scard_E_No_Memory = static_cast(SCARD_E_NO_MEMORY), /**< Not enough memory available to complete this command. */ + Scard_F_Waited_Too_Long = static_cast(SCARD_F_WAITED_TOO_LONG), /**< An internal consistency timer has expired. */ + Scard_E_Insufficient_Buffer = static_cast(SCARD_E_INSUFFICIENT_BUFFER), /**< The data buffer to receive returned data is too small for the returned data. */ + Scard_E_Unknown_Reader = static_cast(SCARD_E_UNKNOWN_READER), /**< The specified reader name is not recognized. */ + Scard_E_Timeout = static_cast(SCARD_E_TIMEOUT), /**< The user-specified timeout value has expired. */ + Scard_E_Sharing_Violation = static_cast(SCARD_E_SHARING_VIOLATION), /**< The smart card cannot be accessed because of other connections outstanding. */ + Scard_E_No_Smartcard = static_cast(SCARD_E_NO_SMARTCARD), /**< The operation requires a Smart Card, but no Smart Card is currently in the device. */ + Scard_E_Unknown_Card = static_cast(SCARD_E_UNKNOWN_CARD), /**< The specified smart card name is not recognized. */ + Scard_E_Cant_Dispose = static_cast(SCARD_E_CANT_DISPOSE), /**< The system could not dispose of the media in the requested manner. */ + Scard_E_Proto_Mismatch = static_cast(SCARD_E_PROTO_MISMATCH), /**< The requested protocols are incompatible with the protocol currently in use with the smart card. */ + Scard_E_Not_Ready = static_cast(SCARD_E_NOT_READY), /**< The reader or smart card is not ready to accept commands. */ + Scard_E_Invalid_Value = static_cast(SCARD_E_INVALID_VALUE), /**< One or more of the supplied parameters values could not be properly interpreted. */ + Scard_E_System_Cancelled = static_cast(SCARD_E_SYSTEM_CANCELLED), /**< The action was cancelled by the system, presumably to log off or shut down. */ + Scard_F_Comm_Error = static_cast(SCARD_F_COMM_ERROR), /**< An internal communications error has been detected. */ + Scard_F_Unknown_Error = static_cast(SCARD_F_UNKNOWN_ERROR), /**< An internal error has been detected, but the source is unknown. */ + Scard_E_Invalid_Atr = static_cast(SCARD_E_INVALID_ATR), /**< An ATR obtained from the registry is not a valid ATR string. */ + Scard_E_Not_Transacted = static_cast(SCARD_E_NOT_TRANSACTED), /**< An attempt was made to end a non-existent transaction. */ + Scard_E_Reader_Unavailable = static_cast(SCARD_E_READER_UNAVAILABLE), /**< The specified reader is not currently available for use. */ + Scard_P_Shutdown = static_cast(SCARD_P_SHUTDOWN), /**< The operation has been aborted to allow the server application to exit. */ + Scard_E_Pci_Too_Small = static_cast(SCARD_E_PCI_TOO_SMALL), /**< The PCI Receive buffer was too small. */ + Scard_E_Reader_Unsupported = static_cast(SCARD_E_READER_UNSUPPORTED), /**< The reader driver does not meet minimal requirements for support. */ + Scard_E_Duplicate_Reader = static_cast(SCARD_E_DUPLICATE_READER), /**< The reader driver did not produce a unique reader name. */ + Scard_E_Card_Unsupported = static_cast(SCARD_E_CARD_UNSUPPORTED), /**< The smart card does not meet minimal requirements for support. */ + Scard_E_No_Service = static_cast(SCARD_E_NO_SERVICE), /**< The Smart card resource manager is not running. */ + Scard_E_Service_Stopped = static_cast(SCARD_E_SERVICE_STOPPED), /**< The Smart card resource manager has shut down. */ + Scard_E_Unexpected = static_cast(SCARD_E_UNEXPECTED), /**< An unexpected card error has occurred. */ + Scard_E_Unsupported_Feature = static_cast(SCARD_E_UNSUPPORTED_FEATURE), /**< This smart card does not support the requested feature. */ + Scard_E_Icc_Installation = static_cast(SCARD_E_ICC_INSTALLATION), /**< No primary provider can be found for the smart card. */ + Scard_E_Icc_Createorder = static_cast(SCARD_E_ICC_CREATEORDER), /**< The requested order of object creation is not supported. */ + + Scard_E_Dir_Not_Found = static_cast(SCARD_E_DIR_NOT_FOUND), /**< The identified directory does not exist in the smart card. */ + Scard_E_File_Not_Found = static_cast(SCARD_E_FILE_NOT_FOUND), /**< The identified file does not exist in the smart card. */ + Scard_E_No_Dir = static_cast(SCARD_E_NO_DIR), /**< The supplied path does not represent a smart card directory. */ + Scard_E_No_File = static_cast(SCARD_E_NO_FILE), /**< The supplied path does not represent a smart card file. */ + Scard_E_No_Access = static_cast(SCARD_E_NO_ACCESS), /**< Access is denied to this file. */ + Scard_E_Write_Too_Many = static_cast(SCARD_E_WRITE_TOO_MANY), /**< The smart card does not have enough memory to store the information. */ + Scard_E_Bad_Seek = static_cast(SCARD_E_BAD_SEEK), /**< There was an error trying to set the smart card file object pointer. */ + Scard_E_Invalid_Chv = static_cast(SCARD_E_INVALID_CHV), /**< The supplied PIN is incorrect. */ + Scard_E_Unknown_Res_Mng = static_cast(SCARD_E_UNKNOWN_RES_MNG), /**< An unrecognized error code was returned from a layered component. */ + Scard_E_No_Such_Certificate = static_cast(SCARD_E_NO_SUCH_CERTIFICATE), /**< The requested certificate does not exist. */ + Scard_E_Certificate_Unavailable = static_cast(SCARD_E_CERTIFICATE_UNAVAILABLE), /**< The requested certificate could not be obtained. */ + Scard_E_No_Readers_Available = static_cast(SCARD_E_NO_READERS_AVAILABLE), /**< Cannot find a smart card reader. */ + Scard_E_Comm_Data_Lost = static_cast(SCARD_E_COMM_DATA_LOST), /**< A communications error with the smart card has been detected. Retry the operation. */ + Scard_E_No_Key_Container = static_cast(SCARD_E_NO_KEY_CONTAINER), /**< The requested key container does not exist on the smart card. */ + Scard_E_Server_Too_Busy = static_cast(SCARD_E_SERVER_TOO_BUSY), /**< The Smart Card Resource Manager is too busy to complete this operation. */ + + Scard_W_Unsupported_Card = static_cast(SCARD_W_UNSUPPORTED_CARD), /**< The reader cannot communicate with the card, due to ATR string configuration conflicts. */ + Scard_W_Unresponsive_Card = static_cast(SCARD_W_UNRESPONSIVE_CARD), /**< The smart card is not responding to a reset. */ + Scard_W_Unpowered_Card = static_cast(SCARD_W_UNPOWERED_CARD), /**< Power has been removed from the smart card, so that further communication is not possible. */ + Scard_W_Reset_Card = static_cast(SCARD_W_RESET_CARD), /**< The smart card has been reset, so any shared state information is invalid. */ + Scard_W_Removed_Card = static_cast(SCARD_W_REMOVED_CARD), /**< The smart card has been removed, so further communication is not possible. */ + + Scard_W_Security_Violation = static_cast(SCARD_W_SECURITY_VIOLATION), /**< Access was denied because of a security violation. */ + Scard_W_Wrong_Chv = static_cast(SCARD_W_WRONG_CHV), /**< The card cannot be accessed because the wrong PIN was presented. */ + Scard_W_Chv_Blocked = static_cast(SCARD_W_CHV_BLOCKED), /**< The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ + Scard_W_Eof = static_cast(SCARD_W_EOF), /**< The end of the smart card file has been reached. */ + Scard_W_Cancelled_By_User = static_cast(SCARD_W_CANCELLED_BY_USER), /**< The user pressed "Cancel" on a Smart Card Selection Dialog. */ + Scard_W_Card_Not_Authenticated = static_cast(SCARD_W_CARD_NOT_AUTHENTICATED) /**< No PIN was presented to the smart card. */ + }; + }; +/** + * Make sure we do not use these macros directly in our code. + */ +#undef SCARD_S_SUCCESS +#undef SCARD_F_INTERNAL_ERROR +#undef SCARD_E_CANCELLED +#undef SCARD_E_INVALID_HANDLE +#undef SCARD_E_INVALID_PARAMETER +#undef SCARD_E_INVALID_TARGET +#undef SCARD_E_NO_MEMORY +#undef SCARD_F_WAITED_TOO_LONG +#undef SCARD_E_INSUFFICIENT_BUFFER +#undef SCARD_E_UNKNOWN_READER +#undef SCARD_E_TIMEOUT +#undef SCARD_E_SHARING_VIOLATION +#undef SCARD_E_NO_SMARTCARD +#undef SCARD_E_UNKNOWN_CARD +#undef SCARD_E_CANT_DISPOSE +#undef SCARD_E_PROTO_MISMATCH +#undef SCARD_E_NOT_READY +#undef SCARD_E_INVALID_VALUE +#undef SCARD_E_SYSTEM_CANCELLED +#undef SCARD_F_COMM_ERROR +#undef SCARD_F_UNKNOWN_ERROR +#undef SCARD_E_INVALID_ATR +#undef SCARD_E_NOT_TRANSACTED +#undef SCARD_E_READER_UNAVAILABLE +#undef SCARD_P_SHUTDOWN +#undef SCARD_E_PCI_TOO_SMALL +#undef SCARD_E_READER_UNSUPPORTED +#undef SCARD_E_DUPLICATE_READER +#undef SCARD_E_CARD_UNSUPPORTED +#undef SCARD_E_NO_SERVICE +#undef SCARD_E_SERVICE_STOPPED +#undef SCARD_E_UNEXPECTED +#undef SCARD_E_UNSUPPORTED_FEATURE +#undef SCARD_E_ICC_INSTALLATION +#undef SCARD_E_ICC_CREATEORDER + +#undef SCARD_E_DIR_NOT_FOUND +#undef SCARD_E_FILE_NOT_FOUND +#undef SCARD_E_NO_DIR +#undef SCARD_E_NO_FILE +#undef SCARD_E_NO_ACCESS +#undef SCARD_E_WRITE_TOO_MANY +#undef SCARD_E_BAD_SEEK +#undef SCARD_E_INVALID_CHV +#undef SCARD_E_UNKNOWN_RES_MNG +#undef SCARD_E_NO_SUCH_CERTIFICATE +#undef SCARD_E_CERTIFICATE_UNAVAILABLE +#undef SCARD_E_NO_READERS_AVAILABLE +#undef SCARD_E_COMM_DATA_LOST +#undef SCARD_E_NO_KEY_CONTAINER +#undef SCARD_E_SERVER_TOO_BUSY + +#undef SCARD_W_UNSUPPORTED_CARD +#undef SCARD_W_UNRESPONSIVE_CARD +#undef SCARD_W_UNPOWERED_CARD +#undef SCARD_W_RESET_CARD +#undef SCARD_W_REMOVED_CARD + +#undef SCARD_W_SECURITY_VIOLATION +#undef SCARD_W_WRONG_CHV +#undef SCARD_W_CHV_BLOCKED +#undef SCARD_W_EOF +#undef SCARD_W_CANCELLED_BY_USER +#undef SCARD_W_CARD_NOT_AUTHENTICATED + + } /* namespace governikus */ diff --git a/src/card/remote/CMakeLists.txt b/src/card/remote/CMakeLists.txt new file mode 100644 index 0000000..40241f4 --- /dev/null +++ b/src/card/remote/CMakeLists.txt @@ -0,0 +1,5 @@ +ADD_PLATFORM_LIBRARY(AusweisAppCardRemote) + +TARGET_INCLUDE_DIRECTORIES(AusweisAppCardRemote SYSTEM PUBLIC) +TARGET_LINK_LIBRARIES(AusweisAppCardRemote Qt5::Core Qt5::WebSockets AusweisAppGlobal AusweisAppCard) +TARGET_COMPILE_DEFINITIONS(AusweisAppCardRemote PRIVATE QT_STATICPLUGIN) diff --git a/src/card/remote/DataChannel.cpp b/src/card/remote/DataChannel.cpp new file mode 100644 index 0000000..c8f331d --- /dev/null +++ b/src/card/remote/DataChannel.cpp @@ -0,0 +1,18 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "DataChannel.h" + + +using namespace governikus; + + +DataChannel::DataChannel() +{ +} + + +DataChannel::~DataChannel() +{ +} diff --git a/src/card/remote/DataChannel.h b/src/card/remote/DataChannel.h new file mode 100644 index 0000000..2998ace --- /dev/null +++ b/src/card/remote/DataChannel.h @@ -0,0 +1,36 @@ +/*! + * DataChannel.h + * + * \brief Interface modelling a component that can send and receive data blocks in the form + * of QByteArray objects. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "GlobalStatus.h" + +#include +#include + +namespace governikus +{ +class DataChannel + : public QObject +{ + Q_OBJECT + + public: + DataChannel(); + virtual ~DataChannel(); + + Q_INVOKABLE virtual void send(const QByteArray& pDataBlock) = 0; + Q_INVOKABLE virtual void close() = 0; + + Q_SIGNALS: + void fireReceived(const QByteArray& pDataBlock); + void fireClosed(GlobalStatus::Code pCloseCode); +}; + +} /* namespace governikus */ diff --git a/src/card/remote/NotificationHandler.cpp b/src/card/remote/NotificationHandler.cpp new file mode 100644 index 0000000..d5d2364 --- /dev/null +++ b/src/card/remote/NotificationHandler.cpp @@ -0,0 +1,51 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "NotificationHandler.h" + +#include + + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + + +using namespace governikus; + + +void NotificationHandler::onReceived(const QByteArray& pDataBlock) +{ + const QSharedPointer received = mParser.parse(pDataBlock); + if (received.isNull()) + { + qCWarning(card_remote) << "Invalid notification received:" << pDataBlock; + } + else + { + Q_EMIT fireReceived(received); + } +} + + +NotificationHandler::NotificationHandler(const QSharedPointer& pDataChannel) + : mDataChannel(pDataChannel) + , mParser() +{ + connect(mDataChannel.data(), &DataChannel::fireClosed, this, &NotificationHandler::fireClosed); + connect(mDataChannel.data(), &DataChannel::fireReceived, this, &NotificationHandler::onReceived); +} + + +NotificationHandler::~NotificationHandler() +{ + disconnect(mDataChannel.data(), &DataChannel::fireClosed, this, &NotificationHandler::fireClosed); + disconnect(mDataChannel.data(), &DataChannel::fireReceived, this, &NotificationHandler::onReceived); + + mDataChannel->close(); +} + + +void NotificationHandler::send(const QSharedPointer& pNotification) +{ + mDataChannel->send(pNotification->toJson().toJson()); +} diff --git a/src/card/remote/NotificationHandler.h b/src/card/remote/NotificationHandler.h new file mode 100644 index 0000000..cfa99d4 --- /dev/null +++ b/src/card/remote/NotificationHandler.h @@ -0,0 +1,40 @@ +/*! + * NotificationHandler.h + * + * \brief Class that dispatches incoming and outgoing remote card reader notifications. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "DataChannel.h" +#include "NotificationParser.h" +#include "RemoteCardNotifications.h" + +namespace governikus +{ +class NotificationHandler + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mDataChannel; + const NotificationParser mParser; + + private Q_SLOTS: + void onReceived(const QByteArray& pDataBlock); + + public: + NotificationHandler(const QSharedPointer& pDataChannel); + virtual ~NotificationHandler(); + + Q_INVOKABLE void send(const QSharedPointer& pNotification); + + Q_SIGNALS: + void fireReceived(const QSharedPointer& pNotification); + void fireClosed(GlobalStatus::Code pCloseCode); +}; + +} /* namespace governikus */ diff --git a/src/card/remote/NotificationParser.cpp b/src/card/remote/NotificationParser.cpp new file mode 100644 index 0000000..e416e58 --- /dev/null +++ b/src/card/remote/NotificationParser.cpp @@ -0,0 +1,663 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + + +#include "NotificationParser.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + +namespace governikus +{ + +class NotificationParserPrivate +{ + private: + QVector parseArrayOfInt(const QJsonArray& pArray) const; + + bool containsInvalidHexDigit(const QString& pString) const; + + QSharedPointer fail(const QString& pLogMessage) const; + + QSharedPointer parseRemoteReaderOffer(const QJsonObject& pJsonObject) const; + + QSharedPointer parseSetApiLevel(const QJsonObject& pJsonObject) const; + + QSharedPointer parseApiLevel(const QJsonObject& pJsonObject) const; + + CardDescription parseCardDescription(const QJsonValue& pJsonValue, bool& pResultOk) const; + + ReaderDescription parseReaderDescription(const QJsonObject& pJsonObject) const; + + QSharedPointer parseReaderList(const QJsonObject& pJsonObject) const; + + QSharedPointer parseReader(const QJsonObject& pJsonObject) const; + + QSharedPointer parseConnect(const QJsonObject& pJsonObject) const; + + QSharedPointer parseDisconnect(const QJsonObject& pJsonObject) const; + + QSharedPointer parseTransmit(const QJsonObject& pJsonObject) const; + + QSharedPointer parseTransmitResponse(const QJsonObject& pJsonObject) const; + + QSharedPointer parseUnsupported(const QJsonObject& pJsonObject) const; + + QSharedPointer parseCommand(const QJsonObject& pJsonObject) const; + + QSharedPointer parseMessage(const QJsonObject& pJsonObject) const; + + public: + NotificationParserPrivate() = default; + + ~NotificationParserPrivate() = default; + + QSharedPointer parse(const QByteArray& pJsonData) const; + + QSharedPointer parse(const QJsonDocument& pJsonDocument) const; +}; + + +QVector NotificationParserPrivate::parseArrayOfInt(const QJsonArray& pArray) const +{ + QVector result; + for (const QJsonValue& v : pArray) + { + if (!v.isDouble()) + { + qCWarning(card_remote) << "Expected number but found" << v.type(); + + continue; + } + + result += v.toInt(); + } + + return result; +} + + +bool NotificationParserPrivate::containsInvalidHexDigit(const QString& pString) const +{ + static const QChar A('A'); + static const QChar F('F'); + + const QString& uppercase = pString.toUpper(); + for (const QChar& c : uppercase) + { + if (c.isDigit() || (A <= c && c <= F)) + { + continue; + } + else + { + return true; + } + } + + return false; +} + + +QSharedPointer NotificationParserPrivate::fail(const QString& pLogMessage) const +{ + qCWarning(card_remote) << pLogMessage; + + return QSharedPointer(); +} + + +QSharedPointer NotificationParserPrivate::parseRemoteReaderOffer(const QJsonObject& pJsonObject) const +{ + static const QLatin1String DEVICE_NAME("deviceName"); + static const QLatin1String ENCRYPTED("encrypted"); + static const QLatin1String PORT("port"); + static const QLatin1String AVAILABLE_API_LEVELS("availableApiLevels"); + + const QJsonValue& deviceNameValue = pJsonObject.value(DEVICE_NAME); + if (!deviceNameValue.isString()) + { + return fail(QStringLiteral("The value of \"deviceName\" should be of type string")); + } + const QString& deviceName = deviceNameValue.toString(); + + const QJsonValue& encryptedValue = pJsonObject.value(ENCRYPTED); + if (!encryptedValue.isBool()) + { + return fail(QStringLiteral("The value of \"encrypted\" should be of type boolean")); + } + const bool encrypted = encryptedValue.toBool(); + + const QJsonValue& portValue = pJsonObject.value(PORT); + if (!portValue.isDouble()) + { + return fail(QStringLiteral("The value of \"port\" should be of type double")); + } + const long portLong = portValue.toInt(); + if (portLong <= 0 || portLong > static_cast(USHRT_MAX)) + { + return fail(QStringLiteral("Expected unsigned integer number (16 bit) for port number")); + } + const quint16 port = static_cast(portLong); + + const QJsonValue& availableApiLevelsValue = pJsonObject.value(AVAILABLE_API_LEVELS); + if (!availableApiLevelsValue.isArray()) + { + return fail(QStringLiteral("The value of \"availableApiLevels\" should be of type number array")); + } + const QVector& availableApiLevels = parseArrayOfInt(availableApiLevelsValue.toArray()); + + return QSharedPointer(new RemoteReaderOfferMsg(deviceName, encrypted, port, availableApiLevels)); +} + + +QSharedPointer NotificationParserPrivate::parseSetApiLevel(const QJsonObject& pJsonObject) const +{ + static const QLatin1String LEVEL("level"); + + const QJsonValue& levelValue = pJsonObject.value(LEVEL); + if (!levelValue.isDouble()) + { + return fail(QStringLiteral("The value of \"level\" should be of type double")); + } + const int level = levelValue.toInt(); + if (level <= 0) + { + return fail(QStringLiteral("Expected non-negative integer number for level")); + } + + return QSharedPointer(new SetApiLevelCmd(level)); +} + + +QSharedPointer NotificationParserPrivate::parseApiLevel(const QJsonObject& pJsonObject) const +{ + static const QLatin1String ERROR("error"); + static const QLatin1String AVAILABLE("available"); + static const QLatin1String CURRENT("current"); + + const QJsonValue& errorValue = pJsonObject.value(ERROR); + if (!errorValue.isString()) + { + return fail(QStringLiteral("The value of \"error\" should be of type string")); + } + const QString& error = errorValue.toString(); + + const QJsonValue& availableValue = pJsonObject.value(AVAILABLE); + if (!availableValue.isArray()) + { + return fail(QStringLiteral("The value of \"available\" should be of type number array")); + } + const QVector& available = parseArrayOfInt(availableValue.toArray()); + + const QJsonValue& currentValue = pJsonObject.value(CURRENT); + if (!currentValue.isDouble()) + { + return fail(QStringLiteral("The value of \"current\" should be of type integer")); + } + const int current = currentValue.toInt(); + if (current <= 0) + { + return fail(QStringLiteral("Expected non-negative integer number for level")); + } + + return QSharedPointer(new ApiLevelMsg(error, available, current)); +} + + +CardDescription NotificationParserPrivate::parseCardDescription(const QJsonValue& pJsonValue, bool& pResultOk) const +{ + static const QLatin1String EF_CARD_ACCESS("EFCardAccess"); + static const QLatin1String RETRY_COUNTER("retryCounter"); + static const QLatin1String PIN_DEACTIVATED("pinDeactivated"); + static const QLatin1String CONNECTED("connected"); + + pResultOk = false; + + // No card inserted: null + if (pJsonValue.isNull()) + { + pResultOk = true; + + return CardDescription(); + } + + // Not null: must be an object. + if (!pJsonValue.isObject()) + { + qCWarning(card_remote) << "A card must be either null or an object"; + + return CardDescription(); + } + + const QJsonObject& jsonObject = pJsonValue.toObject(); + const QJsonValue& efCardAccessValue = jsonObject.value(EF_CARD_ACCESS); + if (!efCardAccessValue.isString()) + { + qCWarning(card_remote) << "The value of \"EFCardAccess\" should be of type string"; + + return CardDescription(); + } + const QString& efCardAccessString = efCardAccessValue.toString(); + if (containsInvalidHexDigit(efCardAccessString)) + { + qCWarning(card_remote) << "The value of \"EFCardAccess\" should only contain hexadecimal digits"; + + return CardDescription(); + } + const QByteArray& efCardAccess = QByteArray::fromHex(efCardAccessString.toUtf8()); + + const QJsonValue& retryCounterValue = jsonObject.value(RETRY_COUNTER); + if (!retryCounterValue.isDouble()) + { + qCWarning(card_remote) << "The value of \"retryCounter\" should be of type integer"; + + return CardDescription(); + } + const int retryCounter = retryCounterValue.toInt(); + + const QJsonValue& pinDeactivatedValue = jsonObject.value(PIN_DEACTIVATED); + if (!pinDeactivatedValue.isBool()) + { + qCWarning(card_remote) << "The value of \"pinDeactivated\" should be of type boolean"; + + return CardDescription(); + } + const int pinDeactivated = pinDeactivatedValue.toBool(); + + const QJsonValue& connectedValue = jsonObject.value(CONNECTED); + if (!connectedValue.isBool()) + { + qCWarning(card_remote) << "The value of \"connected\" should be of type boolean"; + + return CardDescription(); + } + const int connected = connectedValue.toBool(); + + pResultOk = true; + + return CardDescription(efCardAccess, retryCounter, pinDeactivated, connected); +} + + +ReaderDescription NotificationParserPrivate::parseReaderDescription(const QJsonObject& pJsonObject) const +{ + static const QLatin1String NAME("name"); + static const QLatin1String ATTACHED("attached"); + static const QLatin1String EXTENDED_LENGTH("extendedLength"); + static const QLatin1String CARD("card"); + bool parseCardOk = false; + + const QJsonValue& nameValue = pJsonObject.value(NAME); + if (!nameValue.isString()) + { + qCWarning(card_remote) << "The value of \"name\" should be of type string"; + + return ReaderDescription(); + } + const QString& name = nameValue.toString(); + + const QJsonValue& attachedValue = pJsonObject.value(ATTACHED); + if (!attachedValue.isBool()) + { + qCWarning(card_remote) << "The value of \"attached\" should be of type boolean"; + + return ReaderDescription(); + } + const bool attached = attachedValue.toBool(); + + const QJsonValue& extendedLengthValue = pJsonObject.value(EXTENDED_LENGTH); + if (!extendedLengthValue.isString()) + { + qCWarning(card_remote) << "The value of \"extendedLength\" should be of type string"; + + return ReaderDescription(); + } + const ExtendedLengthApduSupportCode extendedLength = + Enum::fromString(extendedLengthValue.toString(), + ExtendedLengthApduSupportCode::INVALID); + if (extendedLength == ExtendedLengthApduSupportCode::INVALID) + { + qCWarning(card_remote) << "The value of \"extendedLength\" should be \"UNKNOWN\", \"SUPPORTED\" or \"UNSUPPORTED\""; + + return ReaderDescription(); + } + + const QJsonValue& cardValue = pJsonObject.value(CARD); + const CardDescription& card = parseCardDescription(cardValue, parseCardOk); + if (parseCardOk) + { + return ReaderDescription(name, attached, extendedLength, card); + } + else + { + qCWarning(card_remote) << "Cannot parse card description"; + + return ReaderDescription(); + } +} + + +QSharedPointer NotificationParserPrivate::parseReaderList(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READERS("readers"); + + const QJsonValue& readersValue = pJsonObject.value(QLatin1String(READERS)); + if (!readersValue.isArray()) + { + return fail(QStringLiteral("The value of \"readers\" should be an array")); + } + const QJsonArray& readersArray = readersValue.toArray(); + + QVector readers; + for (const QJsonValue readerValue : readersArray) + { + if (!readerValue.isObject()) + { + return fail(QStringLiteral("The \"readers\" should contain only objects")); + } + + const ReaderDescription& reader = parseReaderDescription(readerValue.toObject()); + if (reader.getExtendedLength() == ExtendedLengthApduSupportCode::INVALID) + { + return fail(QStringLiteral("Cannot parse an element of \"readers\"")); + } + + readers += reader; + } + + return QSharedPointer(new ReaderListMsg(readers)); +} + + +QSharedPointer NotificationParserPrivate::parseReader(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READER("reader"); + static const QLatin1String ERROR("error"); + + const QJsonValue& readerValue = pJsonObject.value(READER); + if (!readerValue.isObject()) + { + return fail(QStringLiteral("The value of \"reader\" should be of type object")); + } + const ReaderDescription& reader = parseReaderDescription(readerValue.toObject()); + if (reader.getExtendedLength() == ExtendedLengthApduSupportCode::INVALID) + { + return fail(QStringLiteral("Cannot parse \"reader\" object")); + } + + const QJsonValue& errorValue = pJsonObject.value(ERROR); + if (!errorValue.isString()) + { + return fail(QStringLiteral("The value of \"error\" should be of type string")); + } + const QString& error = errorValue.toString(); + + return QSharedPointer(new ReaderMsg(reader, error)); +} + + +QSharedPointer NotificationParserPrivate::parseConnect(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READER_NAME("readerName"); + + const QJsonValue& readerNameValue = pJsonObject.value(READER_NAME); + if (!readerNameValue.isString()) + { + return fail(QStringLiteral("The value of \"readerName\" should be of type string")); + } + const QString& readerName = readerNameValue.toString(); + + return QSharedPointer(new ConnectCmd(readerName)); +} + + +QSharedPointer NotificationParserPrivate::parseDisconnect(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READER_NAME("readerName"); + + const QJsonValue& readerNameValue = pJsonObject.value(READER_NAME); + if (!readerNameValue.isString()) + { + return fail(QStringLiteral("The value of \"readerName\" should be of type string")); + } + const QString& readerName = readerNameValue.toString(); + + return QSharedPointer(new DisconnectCmd(readerName)); +} + + +QSharedPointer NotificationParserPrivate::parseTransmit(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READER_NAME("readerName"); + static const QLatin1String COMMAND_APDU("commandApdu"); + + const QJsonValue& readerNameValue = pJsonObject.value(READER_NAME); + if (!readerNameValue.isString()) + { + return fail(QStringLiteral("The value of \"readerName\" should be of type string")); + } + const QString& readerName = readerNameValue.toString(); + + const QJsonValue& commandApduValue = pJsonObject.value(COMMAND_APDU); + if (!commandApduValue.isString()) + { + return fail(QStringLiteral("The value of \"commandApdu\" should be of type string")); + } + const QString& commandApduString = commandApduValue.toString(); + if (containsInvalidHexDigit(commandApduString)) + { + return fail(QStringLiteral("The value of \"commandApdu\" should only contain hexadecimal digits")); + } + const QByteArray& commandApdu = QByteArray::fromHex(commandApduString.toUtf8()); + + return QSharedPointer(new TransmitCmd(readerName, commandApdu)); +} + + +QSharedPointer NotificationParserPrivate::parseTransmitResponse(const QJsonObject& pJsonObject) const +{ + static const QLatin1String READER_NAME("readerName"); + static const QLatin1String ERROR("error"); + static const QLatin1String RESPONSE_APDU("responseApdu"); + + const QJsonValue& readerNameValue = pJsonObject.value(READER_NAME); + if (!readerNameValue.isString()) + { + return fail(QStringLiteral("The value of \"readerName\" should be of type string")); + } + const QString& readerName = readerNameValue.toString(); + + const QJsonValue& errorValue = pJsonObject.value(ERROR); + if (!errorValue.isString()) + { + return fail(QStringLiteral("The value of \"error\" should be of type string")); + } + const QString& error = errorValue.toString(); + + const QJsonValue& responseApduValue = pJsonObject.value(RESPONSE_APDU); + if (!responseApduValue.isString()) + { + return fail(QStringLiteral("The value of \"responseApdu\" should be of type string")); + } + const QString& responseApduString = responseApduValue.toString(); + if (containsInvalidHexDigit(responseApduString)) + { + return fail(QStringLiteral("The value of \"responseApdu\" should only contain hexadecimal digits")); + } + const QByteArray& responseApdu = QByteArray::fromHex(responseApduString.toUtf8()); + + return QSharedPointer(new TransmitResponseMsg(readerName, error, responseApdu)); +} + + +QSharedPointer NotificationParserPrivate::parseUnsupported(const QJsonObject& pJsonObject) const +{ + static const QLatin1String ERROR("error"); + + const QJsonValue& errorValue = pJsonObject.value(ERROR); + if (!errorValue.isString()) + { + return fail(QStringLiteral("The value of \"error\" should be of type string")); + } + const QString& error = errorValue.toString(); + + return QSharedPointer(new UnsupportedMsg(error)); +} + + +QSharedPointer NotificationParserPrivate::parseCommand(const QJsonObject& pJsonObject) const +{ + static const QString CMD("cmd"); + static const QSharedPointer sRemoteReaderDiscoverCmd(new RemoteReaderDiscoverCmd()); + static const QSharedPointer sGetApiLevelCmd(new GetApiLevelCmd()); + static const QSharedPointer sGetReaderListCmd(new GetReaderListCmd()); + + const QJsonValue& cmdValue = pJsonObject.value(CMD); + if (!cmdValue.isString()) + { + return fail(QStringLiteral("The value of \"cmd\" should be of type string")); + } + + const QString& cmd = cmdValue.toString(); + const CardNotificationType notificationType = Enum::fromString(cmd, CardNotificationType::UNSUPPORTED); + switch (notificationType) + { + case CardNotificationType::REMOTE_READER_DISCOVER: + return sRemoteReaderDiscoverCmd; + + case CardNotificationType::GET_API_LEVEL: + return sGetApiLevelCmd; + + case CardNotificationType::SET_API_LEVEL: + return parseSetApiLevel(pJsonObject); + + case CardNotificationType::GET_READER_LIST: + return sGetReaderListCmd; + + case CardNotificationType::CONNECT: + return parseConnect(pJsonObject); + + case CardNotificationType::DISCONNECT: + return parseDisconnect(pJsonObject); + + case CardNotificationType::TRANSMIT: + return parseTransmit(pJsonObject); + + default: + return fail(QStringLiteral("Unknown command: %1").arg(cmd)); + } +} + + +QSharedPointer NotificationParserPrivate::parseMessage(const QJsonObject& pJsonObject) const +{ + static const QString MSG("msg"); + + const QJsonValue& msgValue = pJsonObject.value(MSG); + if (!msgValue.isString()) + { + return fail(QStringLiteral("The value of \"msg\" should be of type string")); + } + + const QString& msg = msgValue.toString(); + const CardNotificationType notificationType = Enum::fromString(msg, CardNotificationType::UNSUPPORTED); + switch (notificationType) + { + case CardNotificationType::REMOTE_READER_OFFER: + return parseRemoteReaderOffer(pJsonObject); + + case CardNotificationType::API_LEVEL: + return parseApiLevel(pJsonObject); + + case CardNotificationType::READER_LIST: + return parseReaderList(pJsonObject); + + case CardNotificationType::READER: + return parseReader(pJsonObject); + + case CardNotificationType::TRANSMIT_RESPONSE: + return parseTransmitResponse(pJsonObject); + + case CardNotificationType::UNSUPPORTED: + return parseUnsupported(pJsonObject); + + default: + return fail(QStringLiteral("Unknown message: %1").arg(msg)); + } +} + + +QSharedPointer NotificationParserPrivate::parse(const QByteArray& pJsonData) const +{ + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(pJsonData, &error); + if (error.error != QJsonParseError::NoError) + { + qCWarning(card_remote) << pJsonData; + + return fail(QStringLiteral("Json parsing failed. Error at offset %1: %2").arg(error.offset).arg(error.errorString())); + } + + return parse(doc); +} + + +QSharedPointer NotificationParserPrivate::parse(const QJsonDocument& pJsonDocument) const +{ + const QJsonObject& rootObject = pJsonDocument.object(); + if (rootObject.isEmpty()) + { + return fail(QStringLiteral("Expected object at top level")); + } + + if (rootObject.contains(QStringLiteral("cmd"))) + { + return parseCommand(rootObject); + } + else if (rootObject.contains(QStringLiteral("msg"))) + { + return parseMessage(rootObject); + } + else + { + return fail(QStringLiteral("Root object has neither type cmd nor msg")); + } +} + + +} /* namespace governikus */ + + +using namespace governikus; + + +NotificationParser::NotificationParser() + : d_ptr(new NotificationParserPrivate()) +{ +} + + +NotificationParser::~NotificationParser() +{ +} + + +QSharedPointer NotificationParser::parse(const QByteArray& pJsonData) const +{ + Q_D(const NotificationParser); + + return d->parse(pJsonData); +} + + +QSharedPointer NotificationParser::parse(const QJsonDocument& pJsonDocument) const +{ + Q_D(const NotificationParser); + + return d->parse(pJsonDocument); +} diff --git a/src/card/remote/NotificationParser.h b/src/card/remote/NotificationParser.h new file mode 100644 index 0000000..1c15231 --- /dev/null +++ b/src/card/remote/NotificationParser.h @@ -0,0 +1,36 @@ +/*! + * NotificationParser.h + * + * \brief Class for parsing JSON data to remote card notification objects. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "RemoteCardNotifications.h" + +#include + +namespace governikus +{ +class NotificationParserPrivate; + +class NotificationParser +{ + Q_DECLARE_PRIVATE(NotificationParser) + + private: + const QScopedPointer d_ptr; + + public: + NotificationParser(); + + ~NotificationParser(); + + QSharedPointer parse(const QByteArray& pJsonData) const; + + QSharedPointer parse(const QJsonDocument& pJsonDocument) const; +}; + +} /* namespace governikus */ diff --git a/src/card/remote/RemoteCardNotifications.cpp b/src/card/remote/RemoteCardNotifications.cpp new file mode 100644 index 0000000..a2d87d5 --- /dev/null +++ b/src/card/remote/RemoteCardNotifications.cpp @@ -0,0 +1,860 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + + +#include "RemoteCardNotifications.h" + +#include +#include +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + +using namespace governikus; + + +QLatin1String RemoteCardNotification::getTypeName() const +{ + return getEnumName(getType()); +} + + +RemoteCardNotification::RemoteCardNotification() +{ +} + + +RemoteCardNotification::~RemoteCardNotification() +{ +} + + +RemoteReaderDiscoverCmd::RemoteReaderDiscoverCmd() +{ +} + + +CardNotificationType RemoteReaderDiscoverCmd::getType() const +{ + return CardNotificationType::REMOTE_READER_DISCOVER; +} + + +QJsonDocument RemoteReaderDiscoverCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + + QJsonObject result; + + result[CMD] = getTypeName(); + + return QJsonDocument(result); +} + + +void RemoteReaderDiscoverCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new RemoteReaderDiscoverCmd(*this)); + + pVisitor->process(message); +} + + +RemoteReaderOfferMsg::RemoteReaderOfferMsg(const QString& pDeviceName, bool pEncrypted, quint16 pPort, const QVector& pAvailableApiLevels) + : mDeviceName(pDeviceName) + , mEncrypted(pEncrypted) + , mPort(pPort) + , mAvailableApiLevels(pAvailableApiLevels) +{ +} + + +const QString& RemoteReaderOfferMsg::getDeviceName() const +{ + return mDeviceName; +} + + +bool RemoteReaderOfferMsg::isEncrypted() const +{ + return mEncrypted; +} + + +quint16 RemoteReaderOfferMsg::getPort() const +{ + return mPort; +} + + +const QVector& RemoteReaderOfferMsg::getAvailableApiLevels() const +{ + return mAvailableApiLevels; +} + + +CardNotificationType RemoteReaderOfferMsg::getType() const +{ + return CardNotificationType::REMOTE_READER_OFFER; +} + + +QJsonDocument RemoteReaderOfferMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String DEVICE_NAME("deviceName"); + static const QLatin1String ENCRYPTED("encrypted"); + static const QLatin1String PORT("port"); + static const QLatin1String AVAILABLE_API_LEVELS("availableApiLevels"); + + QJsonObject result; + + result[MSG] = getTypeName(); + result[DEVICE_NAME] = mDeviceName; + result[ENCRYPTED] = mEncrypted; + result[PORT] = mPort; + + QJsonArray levels; + for (auto level : mAvailableApiLevels) + { + levels.append(level); + } + result[AVAILABLE_API_LEVELS] = levels; + + return QJsonDocument(result); +} + + +void RemoteReaderOfferMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new RemoteReaderOfferMsg(*this)); + + pVisitor->process(message); +} + + +bool RemoteReaderOfferMsg::operator==(const RemoteReaderOfferMsg& pOther) const +{ + return mDeviceName == pOther.mDeviceName + && mEncrypted == pOther.mEncrypted + && mPort == pOther.mPort + && mAvailableApiLevels == pOther.mAvailableApiLevels; +} + + +bool RemoteReaderOfferMsg::isEqual(const RemoteReaderOfferMsg* const pOther) const +{ + return *this == *pOther; +} + + +GetApiLevelCmd::GetApiLevelCmd() +{ +} + + +CardNotificationType GetApiLevelCmd::getType() const +{ + return CardNotificationType::GET_API_LEVEL; +} + + +QJsonDocument GetApiLevelCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + + QJsonObject result; + + result[CMD] = getTypeName(); + + return QJsonDocument(result); +} + + +void GetApiLevelCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new GetApiLevelCmd(*this)); + + pVisitor->process(message); +} + + +SetApiLevelCmd::SetApiLevelCmd(int pLevel) + : mLevel(pLevel) +{ +} + + +int SetApiLevelCmd::getLevel() const +{ + return mLevel; +} + + +CardNotificationType SetApiLevelCmd::getType() const +{ + return CardNotificationType::SET_API_LEVEL; +} + + +QJsonDocument SetApiLevelCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + static const QLatin1String LEVEL("level"); + + QJsonObject result; + + result[CMD] = getTypeName(); + result[LEVEL] = mLevel; + + return QJsonDocument(result); +} + + +void SetApiLevelCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new SetApiLevelCmd(*this)); + + pVisitor->process(message); +} + + +ApiLevelMsg::ApiLevelMsg(const QString& pError, const QVector& pAvailable, int pCurrent) + : mError(pError) + , mAvailable(pAvailable) + , mCurrent(pCurrent) +{ +} + + +const QString& ApiLevelMsg::getError() const +{ + return mError; +} + + +const QVector& ApiLevelMsg::getAvailable() const +{ + return mAvailable; +} + + +int ApiLevelMsg::getCurrent() const +{ + return mCurrent; +} + + +CardNotificationType ApiLevelMsg::getType() const +{ + return CardNotificationType::API_LEVEL; +} + + +QJsonDocument ApiLevelMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String ERROR("error"); + static const QLatin1String AVAILABLE("available"); + static const QLatin1String CURRENT("current"); + + QJsonObject result; + + result[MSG] = getTypeName(); + result[ERROR] = mError; + + QJsonArray levels; + for (auto level : mAvailable) + { + levels.append(level); + } + result[AVAILABLE] = levels; + result[CURRENT] = mCurrent; + + return QJsonDocument(result); +} + + +void ApiLevelMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new ApiLevelMsg(*this)); + + pVisitor->process(message); +} + + +GetReaderListCmd::GetReaderListCmd() +{ +} + + +CardNotificationType GetReaderListCmd::getType() const +{ + return CardNotificationType::GET_READER_LIST; +} + + +QJsonDocument GetReaderListCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + + QJsonObject result; + + result[CMD] = getTypeName(); + + return QJsonDocument(result); +} + + +void GetReaderListCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new GetReaderListCmd(*this)); + + pVisitor->process(message); +} + + +CardDescription::CardDescription(const QByteArray& pEFCardAccess, int pRetryCounter, bool pPinDeactivated, bool pConnected) + : mEFCardAccess(pEFCardAccess) + , mRetryCounter(pRetryCounter) + , mPinDeactivated(pPinDeactivated) + , mConnected(pConnected) +{ +} + + +const QByteArray& CardDescription::getEFCardAccess() const +{ + return mEFCardAccess; +} + + +int CardDescription::getRetryCounter() const +{ + return mRetryCounter; +} + + +bool CardDescription::isPinDeactivated() const +{ + return mPinDeactivated; +} + + +bool CardDescription::isConnected() const +{ + return mConnected; +} + + +QJsonValue CardDescription::toJson() const +{ + static const QLatin1String EF_CARD_ACCESS("EFCardAccess"); + static const QLatin1String RETRY_COUNTER("retryCounter"); + static const QLatin1String PIN_DEACTIVATED("pinDeactivated"); + static const QLatin1String CONNECTED("connected"); + + if (mEFCardAccess.isEmpty()) + { + // null + return QJsonValue(); + } + else + { + QJsonObject result; + + result[EF_CARD_ACCESS] = QString::fromLatin1(mEFCardAccess.toHex()); + result[RETRY_COUNTER] = mRetryCounter; + result[PIN_DEACTIVATED] = mPinDeactivated; + result[CONNECTED] = mConnected; + + return result; + } +} + + +bool CardDescription::operator==(const CardDescription& pOther) const +{ + return mEFCardAccess == pOther.mEFCardAccess && + mRetryCounter == pOther.mRetryCounter && + mPinDeactivated == pOther.mPinDeactivated && + mConnected == pOther.mConnected; +} + + +ReaderDescription::ReaderDescriptionData::ReaderDescriptionData(const QString& pName, + bool pAttached, + ExtendedLengthApduSupportCode pExtendedLength, + const CardDescription& pCard) + : mName(pName) + , mAttached(pAttached) + , mExtendedLength(pExtendedLength) + , mCard(pCard) +{ +} + + +bool ReaderDescription::ReaderDescriptionData::operator==(const ReaderDescriptionData& pOther) const +{ + return mName == pOther.mName && + mAttached == pOther.mAttached && + mExtendedLength == pOther.mExtendedLength && + mCard == pOther.mCard; +} + + +ReaderDescription::ReaderDescription(const QString& pName, + bool pAttached, + ExtendedLengthApduSupportCode pExtendedLength, + const CardDescription& pCard) + : d(new ReaderDescriptionData(pName, pAttached, pExtendedLength, pCard)) +{ +} + + +bool ReaderDescription::hasCard() const +{ + return !d->mCard.getEFCardAccess().isEmpty(); +} + + +const QString& ReaderDescription::getName() const +{ + return d->mName; +} + + +bool ReaderDescription::isAttached() const +{ + return d->mAttached; +} + + +ExtendedLengthApduSupportCode ReaderDescription::getExtendedLength() const +{ + return d->mExtendedLength; +} + + +const CardDescription& ReaderDescription::getCard() const +{ + return d->mCard; +} + + +QJsonObject ReaderDescription::toJson() const +{ + static const QLatin1String NAME("name"); + static const QLatin1String ATTACHED("attached"); + static const QLatin1String EXTENDED_LENGTH("extendedLength"); + static const QLatin1String CARD("card"); + + QJsonObject result; + + result[NAME] = d->mName; + result[ATTACHED] = d->mAttached; + result[EXTENDED_LENGTH] = getEnumName(d->mExtendedLength); + result[CARD] = d->mCard.toJson(); + + return result; +} + + +bool ReaderDescription::operator==(const ReaderDescription& pOther) const +{ + return *d == *pOther.d; +} + + +ReaderListMsg::ReaderListMsg(const QVector& pReaders) + : mReaders(pReaders) +{ +} + + +const QVector& ReaderListMsg::getReaders() const +{ + return mReaders; +} + + +CardNotificationType ReaderListMsg::getType() const +{ + return CardNotificationType::READER_LIST; +} + + +QJsonDocument ReaderListMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String READERS("readers"); + + QJsonObject result; + + result[MSG] = getTypeName(); + + QJsonArray readers; + for (auto reader : mReaders) + { + readers.append(reader.toJson()); + } + result[READERS] = readers; + + return QJsonDocument(result); +} + + +void ReaderListMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new ReaderListMsg(*this)); + + pVisitor->process(message); +} + + +ReaderMsg::ReaderMsg(const ReaderDescription& pReader, const QString& pError) + : mReader(pReader) + , mError(pError) +{ +} + + +const ReaderDescription& ReaderMsg::getReader() const +{ + return mReader; +} + + +const QString& ReaderMsg::getError() const +{ + return mError; +} + + +CardNotificationType ReaderMsg::getType() const +{ + return CardNotificationType::READER; +} + + +QJsonDocument ReaderMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String READER("reader"); + static const QLatin1String ERROR("error"); + + QJsonObject result; + + result[MSG] = getTypeName(); + result[READER] = mReader.toJson(); + result[ERROR] = mError; + + return QJsonDocument(result); +} + + +void ReaderMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new ReaderMsg(*this)); + + pVisitor->process(message); +} + + +ConnectCmd::ConnectCmd(const QString& pReaderName) + : mReaderName(pReaderName) +{ +} + + +const QString& ConnectCmd::getReaderName() const +{ + return mReaderName; +} + + +CardNotificationType ConnectCmd::getType() const +{ + return CardNotificationType::CONNECT; +} + + +QJsonDocument ConnectCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + static const QLatin1String READER_NAME("readerName"); + + QJsonObject result; + + result[CMD] = getTypeName(); + result[READER_NAME] = mReaderName; + + return QJsonDocument(result); +} + + +void ConnectCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new ConnectCmd(*this)); + + pVisitor->process(message); +} + + +DisconnectCmd::DisconnectCmd(const QString& pReaderName) + : mReaderName(pReaderName) +{ +} + + +const QString& DisconnectCmd::getReaderName() const +{ + return mReaderName; +} + + +CardNotificationType DisconnectCmd::getType() const +{ + return CardNotificationType::DISCONNECT; +} + + +QJsonDocument DisconnectCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + static const QLatin1String READER_NAME("readerName"); + + QJsonObject result; + + result[CMD] = getTypeName(); + result[READER_NAME] = mReaderName; + + return QJsonDocument(result); +} + + +void DisconnectCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new DisconnectCmd(*this)); + + pVisitor->process(message); +} + + +TransmitCmd::TransmitCmd(const QString& pReaderName, const QByteArray& pCommandApdu) + : mReaderName(pReaderName) + , mCommandApdu(pCommandApdu) +{ +} + + +const QString& TransmitCmd::getReaderName() const +{ + return mReaderName; +} + + +const QByteArray& TransmitCmd::getCommandApdu() const +{ + return mCommandApdu; +} + + +CardNotificationType TransmitCmd::getType() const +{ + return CardNotificationType::TRANSMIT; +} + + +QJsonDocument TransmitCmd::toJson() const +{ + static const QLatin1String CMD("cmd"); + static const QLatin1String READER_NAME("readerName"); + static const QLatin1String COMMAND_APDU("commandApdu"); + + QJsonObject result; + + result[CMD] = getTypeName(); + result[READER_NAME] = mReaderName; + result[COMMAND_APDU] = QString::fromLatin1(mCommandApdu.toHex()); + + return QJsonDocument(result); +} + + +void TransmitCmd::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new TransmitCmd(*this)); + + pVisitor->process(message); +} + + +TransmitResponseMsg::TransmitResponseMsg(const QString& pReaderName, const QString& pError, const QByteArray& pResponseApdu) + : mReaderName(pReaderName) + , mError(pError) + , mResponseApdu(pResponseApdu) +{ +} + + +const QString& TransmitResponseMsg::getReaderName() const +{ + return mReaderName; +} + + +const QString& TransmitResponseMsg::getError() const +{ + return mError; +} + + +const QByteArray& TransmitResponseMsg::getResponseApdu() const +{ + return mResponseApdu; +} + + +CardNotificationType TransmitResponseMsg::getType() const +{ + return CardNotificationType::TRANSMIT_RESPONSE; +} + + +QJsonDocument TransmitResponseMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String READER_NAME("readerName"); + static const QLatin1String ERROR("error"); + static const QLatin1String RESPONSE_APDU("responseApdu"); + + QJsonObject result; + + result[MSG] = getTypeName(); + result[READER_NAME] = mReaderName; + result[ERROR] = mError; + result[RESPONSE_APDU] = QString::fromLatin1(mResponseApdu.toHex()); + + return QJsonDocument(result); +} + + +void TransmitResponseMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new TransmitResponseMsg(*this)); + + pVisitor->process(message); +} + + +UnsupportedMsg::UnsupportedMsg(const QString& pError) + : mError(pError) +{ +} + + +const QString& UnsupportedMsg::getError() const +{ + return mError; +} + + +CardNotificationType UnsupportedMsg::getType() const +{ + return CardNotificationType::UNSUPPORTED; +} + + +QJsonDocument UnsupportedMsg::toJson() const +{ + static const QLatin1String MSG("msg"); + static const QLatin1String ERROR("error"); + + QJsonObject result; + + result[MSG] = getEnumName(getType()); + result[ERROR] = mError; + + return QJsonDocument(result); +} + + +void UnsupportedMsg::accept(const QSharedPointer& pVisitor) const +{ + const QSharedPointer message(new UnsupportedMsg(*this)); + + pVisitor->process(message); +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +void NotificationVisitor::process(const QSharedPointer& /* pNotification */) +{ +} + + +#include "moc_RemoteCardNotifications.cpp" diff --git a/src/card/remote/RemoteCardNotifications.h b/src/card/remote/RemoteCardNotifications.h new file mode 100644 index 0000000..89f78e8 --- /dev/null +++ b/src/card/remote/RemoteCardNotifications.h @@ -0,0 +1,475 @@ +/*! + * RemoteCardNotifications.h + * + * \brief Classes that model remote card reader notifications. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "EnumHelper.h" +#include "ExtendedLengthApduSupportCode.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace governikus +{ +defineEnumType(CardNotificationType, + REMOTE_READER_DISCOVER, + REMOTE_READER_OFFER, + GET_API_LEVEL, + SET_API_LEVEL, + API_LEVEL, + GET_READER_LIST, + READER_LIST, + READER, + CONNECT, + DISCONNECT, + TRANSMIT, + TRANSMIT_RESPONSE, + UNSUPPORTED) + +class NotificationVisitor; + + +class RemoteCardNotification +{ + protected: + QLatin1String getTypeName() const; + + public: + RemoteCardNotification(); + + virtual ~RemoteCardNotification(); + + virtual CardNotificationType getType() const = 0; + + virtual QJsonDocument toJson() const = 0; + + virtual void accept(const QSharedPointer& pVisitor) const = 0; +}; + + +class RemoteReaderDiscoverCmd + : public RemoteCardNotification +{ + public: + RemoteReaderDiscoverCmd(); + + virtual ~RemoteReaderDiscoverCmd() = default; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class RemoteReaderOfferMsg + : public RemoteCardNotification +{ + private: + const QString mDeviceName; + + const bool mEncrypted; + + const quint16 mPort; + + const QVector mAvailableApiLevels; + + public: + RemoteReaderOfferMsg(const QString& pDeviceName, bool pEncrypted, quint16 pPort, const QVector& pAvailableApiLevels); + virtual ~RemoteReaderOfferMsg() = default; + + const QString& getDeviceName() const; + + bool isEncrypted() const; + + quint16 getPort() const; + + const QVector& getAvailableApiLevels() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; + + bool operator==(const RemoteReaderOfferMsg& pOther) const; + bool isEqual(const RemoteReaderOfferMsg* const pOther) const; +}; + + +class GetApiLevelCmd + : public RemoteCardNotification +{ + public: + GetApiLevelCmd(); + + virtual ~GetApiLevelCmd() = default; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class SetApiLevelCmd + : public RemoteCardNotification +{ + private: + const int mLevel; + + public: + SetApiLevelCmd(int pLevel); + + virtual ~SetApiLevelCmd() = default; + + int getLevel() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class ApiLevelMsg + : public RemoteCardNotification +{ + private: + const QString mError; + + const QVector mAvailable; + + const int mCurrent; + + public: + ApiLevelMsg(const QString& pError, const QVector& pAvailable, int pCurrent); + + virtual ~ApiLevelMsg() = default; + + const QString& getError() const; + + const QVector& getAvailable() const; + + int getCurrent() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class GetReaderListCmd + : public RemoteCardNotification +{ + public: + GetReaderListCmd(); + + virtual ~GetReaderListCmd() = default; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class CardDescription +{ + private: + const QByteArray mEFCardAccess; + + const int mRetryCounter; + + const bool mPinDeactivated; + + const bool mConnected; + + public: + CardDescription(const QByteArray& pEFCardAccess = QByteArray(), + int pRetryCounter = -1, + bool pPinDeactivated = true, + bool pConnected = false); + + ~CardDescription() = default; + + const QByteArray& getEFCardAccess() const; + + int getRetryCounter() const; + + bool isPinDeactivated() const; + + bool isConnected() const; + + QJsonValue toJson() const; + + bool operator ==(const CardDescription& pOther) const; +}; + + +class ReaderDescription +{ + private: + class ReaderDescriptionData + : public QSharedData + { + public: + const QString mName; + + const bool mAttached; + + const ExtendedLengthApduSupportCode mExtendedLength; + + const CardDescription mCard; + + ReaderDescriptionData(const QString& pName = QString(), + bool pAttached = false, + ExtendedLengthApduSupportCode pExtendedLength = ExtendedLengthApduSupportCode::INVALID, + const CardDescription& pCard = CardDescription()); + + bool operator==(const ReaderDescriptionData& pOther) const; + }; + + QSharedDataPointer d; + + public: + ReaderDescription(const QString& pName = QString(), + bool pAttached = false, + ExtendedLengthApduSupportCode pExtendedLength = ExtendedLengthApduSupportCode::INVALID, + const CardDescription& pCard = CardDescription()); + + ~ReaderDescription() = default; + + const QString& getName() const; + + bool isAttached() const; + + ExtendedLengthApduSupportCode getExtendedLength() const; + + bool hasCard() const; + + const CardDescription& getCard() const; + + QJsonObject toJson() const; + + bool operator ==(const ReaderDescription& pOther) const; +}; + + +class ReaderListMsg + : public RemoteCardNotification +{ + private: + const QVector mReaders; + + public: + ReaderListMsg(const QVector& pReaders); + + virtual ~ReaderListMsg() = default; + + const QVector& getReaders() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class ReaderMsg + : public RemoteCardNotification +{ + private: + const ReaderDescription mReader; + + const QString mError; + + public: + ReaderMsg(const ReaderDescription& pReader, const QString& pError); + + virtual ~ReaderMsg() = default; + + const ReaderDescription& getReader() const; + + const QString& getError() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class ConnectCmd + : public RemoteCardNotification +{ + private: + const QString mReaderName; + + public: + ConnectCmd(const QString& pReaderName); + + virtual ~ConnectCmd() = default; + + const QString& getReaderName() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class DisconnectCmd + : public RemoteCardNotification +{ + private: + const QString mReaderName; + + public: + DisconnectCmd(const QString& pReaderName); + + virtual ~DisconnectCmd() = default; + + const QString& getReaderName() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class TransmitCmd + : public RemoteCardNotification +{ + private: + const QString mReaderName; + + const QByteArray mCommandApdu; + + public: + TransmitCmd(const QString& pReaderName, const QByteArray& pCommandApdu); + + virtual ~TransmitCmd() = default; + + const QString& getReaderName() const; + + const QByteArray& getCommandApdu() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class TransmitResponseMsg + : public RemoteCardNotification +{ + private: + const QString mReaderName; + + const QString mError; + + const QByteArray mResponseApdu; + + public: + TransmitResponseMsg(const QString& pReaderName, const QString& pError, const QByteArray& pResponseApdu); + + virtual ~TransmitResponseMsg() = default; + + const QString& getReaderName() const; + + const QString& getError() const; + + const QByteArray& getResponseApdu() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class UnsupportedMsg + : public RemoteCardNotification +{ + private: + const QString mError; + + public: + UnsupportedMsg(const QString& pError); + + virtual ~UnsupportedMsg() = default; + + const QString& getError() const; + + virtual CardNotificationType getType() const override; + + virtual QJsonDocument toJson() const override; + + virtual void accept(const QSharedPointer& pVisitor) const override; +}; + + +class NotificationVisitor +{ + public: + NotificationVisitor() = default; + + virtual ~NotificationVisitor() = default; + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + + virtual void process(const QSharedPointer& pNotification); + +}; + + +} /* namespace governikus */ diff --git a/src/card/remote/WebSocketChannel.cpp b/src/card/remote/WebSocketChannel.cpp new file mode 100644 index 0000000..3db3627 --- /dev/null +++ b/src/card/remote/WebSocketChannel.cpp @@ -0,0 +1,61 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "WebSocketChannel.h" + + +using namespace governikus; + + +WebSocketChannel::WebSocketChannel(const QSharedPointer& pConnection) + : mConnection(pConnection) +{ + if (mConnection) + { + connect(mConnection.data(), &QWebSocket::textMessageReceived, this, &WebSocketChannel::onReceived); + connect(mConnection.data(), &QWebSocket::disconnected, this, &WebSocketChannel::onDisconnected); + } +} + + +WebSocketChannel::~WebSocketChannel() +{ + if (mConnection) + { + disconnect(mConnection.data(), &QWebSocket::textMessageReceived, this, &WebSocketChannel::onReceived); + disconnect(mConnection.data(), &QWebSocket::disconnected, this, &WebSocketChannel::onDisconnected); + } +} + + +void WebSocketChannel::send(const QByteArray& pDataBlock) +{ + if (mConnection) + { + mConnection->sendTextMessage(QString::fromUtf8(pDataBlock)); + } +} + + +void WebSocketChannel::close() +{ + if (mConnection) + { + mConnection->close(); + } +} + + +void WebSocketChannel::onReceived(const QString& pMessage) +{ + Q_EMIT fireReceived(pMessage.toUtf8()); +} + + +void WebSocketChannel::onDisconnected() +{ + Q_EMIT fireClosed(mConnection->closeCode() == QWebSocketProtocol::CloseCodeNormal ? + GlobalStatus::Code::RemoteReader_CloseCode_NormalClose : + GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); +} diff --git a/src/card/remote/WebSocketChannel.h b/src/card/remote/WebSocketChannel.h new file mode 100644 index 0000000..02a45a4 --- /dev/null +++ b/src/card/remote/WebSocketChannel.h @@ -0,0 +1,40 @@ +/*! + * WebSocketChannel.h + * + * \brief Implementation of DataChannel base on web sockets. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "DataChannel.h" + +#include +#include +#include + +namespace governikus +{ +class WebSocketChannel + : public DataChannel +{ + Q_OBJECT + + private: + const QSharedPointer mConnection; + + public: + WebSocketChannel(const QSharedPointer& pConnection); + virtual ~WebSocketChannel(); + + virtual void send(const QByteArray& pDataBlock) override; + virtual void close() override; + + private Q_SLOTS: + void onReceived(const QString& pMessage); + void onDisconnected(); + +}; + +} /* namespace governikus */ diff --git a/src/cli/ConsoleReader.cpp b/src/cli/ConsoleReader.cpp index d5fecac..3aff089 100644 --- a/src/cli/ConsoleReader.cpp +++ b/src/cli/ConsoleReader.cpp @@ -55,15 +55,6 @@ void ConsoleReader::init() } -QString ConsoleReader::requestText(const QString& pMsg) -{ - qFatal("Unimplemented on windows"); - - Q_UNUSED(pMsg); - return QString(); -} - - void ConsoleReader::shutdown() { mConsoleInputThread.reset(); @@ -116,44 +107,6 @@ QString ConsoleReader::readText() } -QString ConsoleReader::requestText(const QString& pMsg) -{ - Q_ASSERT(!mNotifier.isNull()); - - mNotifier->setEnabled(false); - qCInfo(cli) << pMsg; - - - // QTextStream::readText() may return without any data even if stdin is still open. - // Therefor we crick ourself in order to emulate a blocking readText() and be - // responsive to SIGTERM et al.. - - static const int TIMEOUT = 200; - - QString input; - while (mInputOpen && input.isEmpty()) - { - input = readText(); - if (input.isEmpty()) - { - QEventLoop loop; - connect(this, &ConsoleReader::fireShutdown, &loop, &QEventLoop::quit); - - QTimer timer; - timer.setSingleShot(true); - timer.setInterval(TIMEOUT); - timer.start(); - connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); - - loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); - } - } - - mNotifier->setEnabled(true); - return input; -} - - void ConsoleReader::shutdown() { Q_ASSERT(!mNotifier.isNull()); diff --git a/src/cli/ConsoleReader.h b/src/cli/ConsoleReader.h index ac8dad8..8105f87 100644 --- a/src/cli/ConsoleReader.h +++ b/src/cli/ConsoleReader.h @@ -52,7 +52,6 @@ class ConsoleReader QScopedPointer mNotifier; bool mInputOpen; - QString readText(); private Q_SLOTS: void onData(); @@ -64,7 +63,7 @@ class ConsoleReader void shutdown(); bool isInputOpen() const; - QString requestText(const QString& pMsg); + QString readText(); Q_SIGNALS: void fireShutdown(); diff --git a/src/cli/UIPlugInCli.cpp b/src/cli/UIPlugInCli.cpp index d0663ba..68e4213 100644 --- a/src/cli/UIPlugInCli.cpp +++ b/src/cli/UIPlugInCli.cpp @@ -4,8 +4,11 @@ #include "UIPlugInCli.h" +#include "states/StateEstablishPacePin.h" + #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -#include "WebserviceActivationHandler.h" +#include "EnvHolder.h" +#include "HttpServer.h" #endif #include @@ -20,6 +23,7 @@ UIPlugInCli::UIPlugInCli() : mReader() , mAvailableCommands() { + addCommand(QStringLiteral("cancel"), &UIPlugInCli::handleCancelWorkflow); addCommand(QStringLiteral("changepin"), &UIPlugInCli::handleChangePin); addCommand(QStringLiteral("enter-pin"), &UIPlugInCli::handleEnterPin); addCommand(QStringLiteral("help"), &UIPlugInCli::handleHelp); @@ -78,7 +82,7 @@ void UIPlugInCli::onCurrentStateChanged(const QString& pState) bool userInteractionRequired = false; - if (pState == QLatin1String("StateEstablishPacePin")) + if (AbstractState::isState(pState)) { userInteractionRequired = true; qCInfo(cli) << "enter-pin"; @@ -108,38 +112,80 @@ void UIPlugInCli::doInput(const QString& pData) void UIPlugInCli::handleChangePin() { + mOldPin.clear(); + mNewPin.clear(); + qCDebug(cli) << "Change PIN requested"; + qCInfo(cli) << "Please enter old PIN"; + disconnect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::doInput); + connect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleOldPinEntered); +} + + +void UIPlugInCli::handleOldPinEntered(const QString& pLine) +{ const QRegularExpression regexOldPin(QStringLiteral("^[0-9]{5,6}$")); - QString oldPin; - while (!regexOldPin.match(oldPin).hasMatch() && mReader.isInputOpen()) + if (regexOldPin.match(pLine).hasMatch() && mReader.isInputOpen()) { - oldPin = mReader.requestText(QStringLiteral("Please enter old PIN")); + mOldPin = pLine; + qCInfo(cli) << "Please enter new PIN"; + disconnect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleOldPinEntered); + connect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleNewPinEntered); } + else + { + qCInfo(cli) << "Please enter old PIN"; + } +} + +void UIPlugInCli::handleNewPinEntered(const QString& pLine) +{ const QRegularExpression regexNewPin(QStringLiteral("^[0-9]{6}$")); - QString newPin; - for (QString newPin2; (newPin != newPin2 || newPin.isEmpty()) && mReader.isInputOpen(); ) + if (regexNewPin.match(pLine).hasMatch() && mReader.isInputOpen()) { - while (!regexNewPin.match(newPin).hasMatch() && mReader.isInputOpen()) - { - newPin = mReader.requestText(QStringLiteral("Please enter new PIN")); - } - - if (mReader.isInputOpen()) - { - newPin2 = mReader.requestText(QStringLiteral("Please enter new PIN again")); - if (newPin != newPin2) - { - qCInfo(cli) << "PINs were not equal"; - } - } + mNewPin = pLine; + qCInfo(cli) << "Please enter new PIN again"; + disconnect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleNewPinEntered); + connect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleNewPinEnteredAgain); } + else + { + qCInfo(cli) << "Please enter new PIN"; + } +} - if (mReader.isInputOpen()) + +void UIPlugInCli::handleNewPinEnteredAgain(const QString& pLine) +{ + if (mNewPin != pLine) + { + qCInfo(cli) << "PINs were not equal"; + qCInfo(cli) << "Please enter new PIN"; + + disconnect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleNewPinEnteredAgain); + connect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::handleNewPinEntered); + } + else if (mReader.isInputOpen()) { qCDebug(cli) << "Start"; Q_EMIT fireChangePinRequest(); + connect(&mReader, &ConsoleReader::fireText, this, &UIPlugInCli::doInput); + } +} + + +void UIPlugInCli::handleCancelWorkflow() +{ + if (mContext.isNull()) + { + qCInfo(cli) << "error"; + } + else + { + Q_EMIT mContext->fireCancelWorkflow(); + qCInfo(cli) << "ok"; } } @@ -161,7 +207,7 @@ void UIPlugInCli::handleEnterPin() void UIPlugInCli::handleHelp() { - qCInfo(cli) << "Available commands:" << QStringList(mAvailableCommands.keys()).join(QStringLiteral(" | ")); + qCInfo(cli) << "Available commands:" << mAvailableCommands.keys().join(QStringLiteral(" | ")); } @@ -174,11 +220,7 @@ void UIPlugInCli::handlePing() void UIPlugInCli::handlePort() { #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - auto handler = ActivationHandler::getInstance(); - if (handler) - { - qCInfo(cli) << "Port:" << handler->getServerPort(); - } + qCInfo(cli) << "Port:" << EnvHolder::shared()->getServerPort(); #else qCInfo(cli) << "Port is undefined"; #endif diff --git a/src/cli/UIPlugInCli.h b/src/cli/UIPlugInCli.h index af27333..c0dc0d2 100644 --- a/src/cli/UIPlugInCli.h +++ b/src/cli/UIPlugInCli.h @@ -28,6 +28,8 @@ class UIPlugInCli typedef void (UIPlugInCli::* MemberFunc)(); private: + QString mOldPin; + QString mNewPin; ConsoleReader mReader; QMap > mAvailableCommands; QSharedPointer mContext; @@ -39,6 +41,7 @@ class UIPlugInCli } + void handleCancelWorkflow(); void handleChangePin(); void handleEnterPin(); void handleHelp(); @@ -60,6 +63,10 @@ class UIPlugInCli virtual void onWorkflowStarted(QSharedPointer pContext) override; virtual void onWorkflowFinished(QSharedPointer pContext) override; void onCurrentStateChanged(const QString& pState); + + void handleOldPinEntered(const QString& pLine); + void handleNewPinEntered(const QString& pLine); + void handleNewPinEnteredAgain(const QString& pLine); }; } /* namespace governikus */ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 446d81b..7a80b4e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,7 +1,11 @@ ADD_PLATFORM_LIBRARY(AusweisAppCore) -TARGET_LINK_LIBRARIES(AusweisAppCore Qt5::Network Qt5::Xml AusweisAppCard AusweisAppCardDrivers AusweisAppGlobal AusweisAppActivation AusweisAppSettings AusweisAppNetwork AusweisAppServices) +TARGET_LINK_LIBRARIES(AusweisAppCore Qt5::Network Qt5::Xml AusweisAppCard AusweisAppGlobal AusweisAppActivation AusweisAppSettings AusweisAppNetwork AusweisAppServices) IF(WIN32) TARGET_LINK_LIBRARIES(AusweisAppCore ${WIN_DEFAULT_LIBS}) ENDIF() + +IF(DESKTOP) + TARGET_LINK_LIBRARIES(AusweisAppCore AusweisAppCardDrivers) +ENDIF() diff --git a/src/core/CertificateChecker.cpp b/src/core/CertificateChecker.cpp index 34ad8b8..ea39e91 100644 --- a/src/core/CertificateChecker.cpp +++ b/src/core/CertificateChecker.cpp @@ -8,10 +8,6 @@ #include "CertificateChecker.h" -#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) -#include "HashAlgorithmUtil.h" -#endif - #include #include @@ -21,9 +17,9 @@ #include #include - using namespace governikus; + Q_DECLARE_LOGGING_CATEGORY(developermode) bool CertificateChecker::checkCertificate(const QSslCertificate& pCertificate, @@ -90,80 +86,68 @@ bool CertificateChecker::hasValidEphemeralKeyLength(const QSslKey& pEphemeralSer } -bool CertificateChecker::isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral) +CertificateChecker::CertificateStatus CertificateChecker::checkAndSaveCertificate(const QSslCertificate& pCertificate, const QUrl& pUrl, QSharedPointer pContext) { - switch (pKeyAlgorithm) + Q_ASSERT(!pContext.isNull()); + + if (!hasValidCertificateKeyLength(pCertificate)) { - case QSsl::KeyAlgorithm::Rsa: - { - bool sufficient = pKeyLength >= 2000; - if (!sufficient) - { - auto keySizeError = QStringLiteral("RSA key with insufficient key size found %1").arg(pKeyLength); - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCWarning(developermode) << keySizeError; - sufficient = true; - } - else - { - qWarning() << keySizeError; - } - } - return sufficient; - } - - case QSsl::KeyAlgorithm::Dsa: - { - bool sufficient = (pIsEphemeral ? pKeyLength >= 1024 : pKeyLength >= 2000); - if (!sufficient) - { - auto keySizeError = QStringLiteral("DSA key with insufficient key size found %1").arg(pKeyLength); - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCWarning(developermode) << keySizeError; - sufficient = true; - } - else - { - qWarning() << keySizeError; - } - } - return sufficient; - } - - case QSsl::KeyAlgorithm::Ec: - { - bool sufficient = pKeyLength >= 224; - if (!sufficient) - { - auto keySizeError = QStringLiteral("EC key with insufficient key size found %1").arg(pKeyLength); - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCWarning(developermode) << keySizeError; - sufficient = true; - } - else - { - qWarning() << keySizeError; - } - } - return sufficient; - } - - default: - auto algorithmError = QStringLiteral("Unknown algorithm used"); - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCWarning(developermode) << algorithmError; - } - else - { - qWarning() << algorithmError; - } + return CertificateStatus::Unsupported_Algorithm_Or_Length; } - return false; + // the call to cvc.isSyntaxValid is made to check, whether the cvc is set + // TODO: do it more explicitly, e.g. implement a method cvc.isNull or so + auto eac1 = pContext->getDidAuthenticateEac1(); + if (eac1 && pContext->getDvCvc()) + { + if (auto certificateDescription = eac1->getCertificateDescription()) + { + const QSet certHashes = certificateDescription->getCommCertificates(); + QCryptographicHash::Algorithm hashAlgo = pContext->getDvCvc()->getBody().getHashAlgorithm(); + if (!checkCertificate(pCertificate, hashAlgo, certHashes)) + { + auto hashError = QStringLiteral("hash of certificate not in certificate description"); + + if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + { + qCCritical(developermode) << hashError; + } + else + { + qCritical() << hashError; + return CertificateStatus::Hash_Not_In_Description; + } + } + } + } + + pContext->addCertificateData(pUrl, pCertificate); + return CertificateStatus::Good; +} + + +bool CertificateChecker::isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral) +{ + const auto& secureStorage = AppSettings::getInstance().getSecureStorage(); + const int minKeySize = pIsEphemeral ? secureStorage.getMinimumEphemeralKeySize(pKeyAlgorithm) : secureStorage.getMinimumStaticKeySize(pKeyAlgorithm); + + qDebug() << "Minimum requested key size" << minKeySize; + + bool sufficient = pKeyLength >= minKeySize; + if (!sufficient) + { + auto keySizeError = QStringLiteral("%1 key with insufficient key size found %2").arg(toString(pKeyAlgorithm)).arg(pKeyLength); + if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + { + qCWarning(developermode) << keySizeError; + sufficient = true; + } + else + { + qWarning() << keySizeError; + } + } + return sufficient; } diff --git a/src/core/CertificateChecker.h b/src/core/CertificateChecker.h index 8cb3067..4f2e3ea 100644 --- a/src/core/CertificateChecker.h +++ b/src/core/CertificateChecker.h @@ -9,6 +9,7 @@ #pragma once #include "AppSettings.h" +#include "context/AuthContext.h" #include #include @@ -29,9 +30,19 @@ namespace governikus */ class CertificateChecker { + Q_GADGET + static bool isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral); public: + enum class CertificateStatus + { + Good, + Unsupported_Algorithm_Or_Length, + Hash_Not_In_Description + }; + Q_ENUM(CertificateStatus) + static QString toString(QSsl::KeyAlgorithm pKeyAlgorithm); /*! @@ -55,45 +66,7 @@ class CertificateChecker * Checks and save certificate into given WorkflowContext * \return Returns a translated error string if an error happened, otherwise QString() */ - template static QString checkAndSaveCertificate(const QSslCertificate& pCertificate, const QUrl& pUrl, QSharedPointer pContext) - { - Q_ASSERT(!pContext.isNull()); - - if (!hasValidCertificateKeyLength(pCertificate)) - { - return QObject::tr("Error while connecting to the server. The SSL certificate uses an unsupported key algorithm or length."); - } - - // the call to cvc.isSyntaxValid is made to check, whether the cvc is set - auto eac1 = pContext->getDidAuthenticateEac1(); - if (eac1 && pContext->getDvCvc()) - { - if (auto certificateDescription = eac1->getCertificateDescription()) - { - const QSet certHashes = certificateDescription->getCommCertificates(); - QCryptographicHash::Algorithm hashAlgo = pContext->getDvCvc()->getBody().getHashAlgorithm(); - if (!checkCertificate(pCertificate, hashAlgo, certHashes)) - { - auto hashError = QStringLiteral("hash of certificate not in certificate description"); - - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCCritical(developermode) << hashError; - } - else - { - qCritical() << hashError; - return QObject::tr("hash of certificate not in certificate description"); - } - } - } - } - - pContext->addCertificateData(pUrl, pCertificate); - return QString(); - } - - + static CertificateStatus checkAndSaveCertificate(const QSslCertificate& pCertificate, const QUrl& pUrl, QSharedPointer pContext); }; } // namespace governikus diff --git a/src/core/NoScriptFinder.cpp b/src/core/NoScriptFinder.cpp index 628be96..0f75966 100644 --- a/src/core/NoScriptFinder.cpp +++ b/src/core/NoScriptFinder.cpp @@ -32,12 +32,12 @@ class NoScriptFinderPrivate { QStringList profileIniFiles; #if defined(Q_OS_LINUX) - profileIniFiles.append(QDir::homePath().append(QStringLiteral("/.mozilla/firefox/profiles.ini"))); + profileIniFiles += QDir::homePath() + QStringLiteral("/.mozilla/firefox/profiles.ini"); #elif defined(Q_OS_WIN32) - profileIniFiles.append(QDir::homePath().append(QStringLiteral("/AppData/Roaming/Mozilla/Firefox/profiles.ini"))); + profileIniFiles += QDir::homePath() + QStringLiteral("/AppData/Roaming/Mozilla/Firefox/profiles.ini"); #elif defined(Q_OS_MAC) - profileIniFiles.append(QDir::homePath().append(QStringLiteral("/Library/Application Support/Firefox/profiles.ini"))); - profileIniFiles.append(QDir::homePath().append(QStringLiteral("/Library/Mozilla/Firefox/profiles.ini"))); + profileIniFiles += QDir::homePath() + QStringLiteral("/Library/Application Support/Firefox/profiles.ini"); + profileIniFiles += QDir::homePath() + QStringLiteral("/Library/Mozilla/Firefox/profiles.ini"); #endif init(profileIniFiles); } diff --git a/src/core/SignalHandler.cpp b/src/core/SignalHandler.cpp index 9752226..67c0d1a 100644 --- a/src/core/SignalHandler.cpp +++ b/src/core/SignalHandler.cpp @@ -42,7 +42,7 @@ void SignalHandler::init() { #if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_OSX) initUnix(); -#elif defined(Q_OS_WIN) +#elif defined(Q_OS_WIN32) SetConsoleCtrlHandler((PHANDLER_ROUTINE) ctrlHandler, true); #endif diff --git a/src/core/context/AuthContext.cpp b/src/core/context/AuthContext.cpp index 21620b0..f541dd4 100644 --- a/src/core/context/AuthContext.cpp +++ b/src/core/context/AuthContext.cpp @@ -5,6 +5,7 @@ #include "AuthContext.h" #include "AppSettings.h" +#include "asn1/Chat.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" #include @@ -36,7 +37,9 @@ AuthContext::AuthContext(ActivationContext* pActivationContext) , mTransmitResponses() , mDisconnectResponse() , mStartPaosResponse() - , mEffectiveChat() + , mEffectiveAccessRights() + , mRequiredAccessRights() + , mOptionalAccessRights() , mCertificates() , mTerminalCvc() , mDvCvc() @@ -51,79 +54,108 @@ AuthContext::~AuthContext() } -bool AuthContext::sanitizeEffectiveAccessRights() +void AuthContext::initializeChat() +{ + Q_ASSERT(mTerminalCvc); + Q_ASSERT(mDIDAuthenticateEAC1); + + mRequiredAccessRights.clear(); + if (const auto& requiredChat = mDIDAuthenticateEAC1->getRequiredChat()) + { + mRequiredAccessRights = requiredChat.data()->getAccessRights(); + removeForbiddenAccessRights(mRequiredAccessRights); + } + + mOptionalAccessRights.clear(); + if (const auto& optionalChat = mDIDAuthenticateEAC1->getOptionalChat()) + { + mOptionalAccessRights = optionalChat.data()->getAccessRights(); + removeForbiddenAccessRights(mOptionalAccessRights); + + if (mOptionalAccessRights.size() > 0 && mRequiredAccessRights.size() > 0) + { + mOptionalAccessRights -= mRequiredAccessRights; + } + } + + if (mOptionalAccessRights.isEmpty() && mRequiredAccessRights.isEmpty()) + { + mOptionalAccessRights = mTerminalCvc->getBody().getCHAT().getAccessRights(); + removeForbiddenAccessRights(mOptionalAccessRights); + } + + mEffectiveAccessRights = mRequiredAccessRights + mOptionalAccessRights; + + Q_EMIT fireAuthenticationDataChanged(); + Q_EMIT fireEffectiveChatChanged(); +} + + +bool AuthContext::removeForbiddenAccessRights(QSet& pAccessRights) { bool changed = false; - if (!mEffectiveChat) + if (!mTerminalCvc) { return changed; } - const auto& effectiveAccessRights = mEffectiveChat->getAccessRights(); - for (const auto& right : effectiveAccessRights) + const auto& allowedCvcAccessRights = mTerminalCvc->getBody().getCHAT().getAccessRights(); + // TODO Don't display = Don't use: why? + const auto& allDisplayedOrderedRights = AccessRoleAndRightsUtil::allDisplayedOrderedRights().toSet(); + const auto& allowedAccessRights = allowedCvcAccessRights & allDisplayedOrderedRights; + + const auto rightsToCheck = pAccessRights; + for (const AccessRight& accessRight : rightsToCheck) { - if (mRequiredChat && mRequiredChat->hasAccessRight(right)) - { - continue; - } - if (mOptionalChat && mOptionalChat->hasAccessRight(right)) + if (allowedAccessRights.contains(accessRight)) { continue; } + qWarning() << "Access right" << accessRight << "is used in chat but it's not included in CVC or it's not allowed to display!"; + pAccessRights.remove(accessRight); changed = true; - mEffectiveChat->removeAccessRight(right); - qWarning() << "Access right" << right << "was in effective chat but not in required or optional chat!"; } - if (!mRequiredChat) + if (!mDIDAuthenticateEAC1) { return changed; } - const auto& requiredAccessRights = mRequiredChat->getAccessRights(); - for (const auto& right : requiredAccessRights) + const auto& auxiliaryData = mDIDAuthenticateEAC1->getAuthenticatedAuxiliaryData(); + if (pAccessRights.contains(AccessRight::AGE_VERIFICATION)) { - if (mEffectiveChat->hasAccessRight(right)) + if (!auxiliaryData || !auxiliaryData->hasAgeVerificationDate()) { - continue; + qWarning() << "AGE_VERIFICATION requested, but no age specified"; + pAccessRights.remove(AccessRight::AGE_VERIFICATION); + changed = true; + } + } + if (pAccessRights.contains(AccessRight::COMMUNITY_ID_VERIFICATION)) + { + if (!auxiliaryData || !auxiliaryData->hasCommunityID()) + { + qWarning() << "COMMUNITY_ID_VERIFICATION requested, but no community id specified"; + pAccessRights.remove(AccessRight::COMMUNITY_ID_VERIFICATION); + changed = true; } - changed = true; - mEffectiveChat->setAccessRight(right); - qWarning() << "Access right" << right << "is required but was not in effective chat!"; } return changed; } -bool AuthContext::setEffectiveChat(const QSharedPointer& pEffectiveChat) -{ - mEffectiveChat = pEffectiveChat; - bool changed = sanitizeEffectiveAccessRights(); - Q_EMIT fireEffectiveChatChanged(); - return !changed; -} - - bool AuthContext::addEffectiveAccessRight(AccessRight pAccessRight) { - Q_ASSERT(mEffectiveChat); - - if (mEffectiveChat->hasAccessRight(pAccessRight)) + if (mEffectiveAccessRights.contains(pAccessRight)) { return true; } - if (mRequiredChat && mRequiredChat->hasAccessRight(pAccessRight)) + if (mOptionalAccessRights.contains(pAccessRight)) { - mEffectiveChat->setAccessRight(pAccessRight); - Q_EMIT fireEffectiveChatChanged(); - return true; - } - if (mOptionalChat && mOptionalChat->hasAccessRight(pAccessRight)) - { - mEffectiveChat->setAccessRight(pAccessRight); + mEffectiveAccessRights += pAccessRight; Q_EMIT fireEffectiveChatChanged(); return true; } @@ -134,16 +166,14 @@ bool AuthContext::addEffectiveAccessRight(AccessRight pAccessRight) bool AuthContext::removeEffectiveAccessRight(AccessRight pAccessRight) { - Q_ASSERT(mEffectiveChat); - - if (mRequiredChat && mRequiredChat->hasAccessRight(pAccessRight)) + if (mRequiredAccessRights.contains(pAccessRight)) { return false; } - if (mEffectiveChat->hasAccessRight(pAccessRight)) + if (mEffectiveAccessRights.contains(pAccessRight)) { - mEffectiveChat->removeAccessRight(pAccessRight); + mEffectiveAccessRights -= pAccessRight; Q_EMIT fireEffectiveChatChanged(); } @@ -153,46 +183,44 @@ bool AuthContext::removeEffectiveAccessRight(AccessRight pAccessRight) bool AuthContext::setEffectiveAccessRights(const QSet& pAccessRights) { - Q_ASSERT(mEffectiveChat); + const auto oldRights = mEffectiveAccessRights; - const auto oldRights = mEffectiveChat->getAccessRights(); - - mEffectiveChat->removeAllAccessRights(); - for (auto& right : pAccessRights) + mEffectiveAccessRights.clear(); + if (!mRequiredAccessRights.isEmpty()) + { + mEffectiveAccessRights += mRequiredAccessRights; + } + for (const auto& effectiveRight : pAccessRights) { const QSignalBlocker blocker(this); - addEffectiveAccessRight(right); + addEffectiveAccessRight(effectiveRight); } - sanitizeEffectiveAccessRights(); - if (oldRights != mEffectiveChat->getAccessRights()) + if (oldRights != mEffectiveAccessRights) { Q_EMIT fireEffectiveChatChanged(); } - return pAccessRights == mEffectiveChat->getAccessRights(); + return pAccessRights == mEffectiveAccessRights; } -void AuthContext::setOptionalChat(const QSharedPointer& pOptionalChat) +void AuthContext::setTerminalCvc(const QSharedPointer& pTerminalCvc) { - mOptionalChat = pOptionalChat; - if (sanitizeEffectiveAccessRights()) - { - Q_EMIT fireEffectiveChatChanged(); - } - Q_EMIT fireOptionalChatChanged(); + mTerminalCvc = pTerminalCvc; + initializeChat(); } -void AuthContext::setRequiredChat(const QSharedPointer& pRequiredChat) +QByteArray AuthContext::encodeEffectiveChat() { - mRequiredChat = pRequiredChat; - if (sanitizeEffectiveAccessRights()) - { - Q_EMIT fireEffectiveChatChanged(); - } - Q_EMIT fireRequiredChatChanged(); + Q_ASSERT(mTerminalCvc); + + CHAT effectiveChat(mTerminalCvc->getBody().getCHAT()); + effectiveChat.removeAllAccessRights(); + effectiveChat.setAccessRights(mEffectiveAccessRights); + qDebug() << "Using effective chat:" << effectiveChat.encode().toHex(); + return effectiveChat.encode(); } diff --git a/src/core/context/AuthContext.h b/src/core/context/AuthContext.h index 3a277bf..aeb8425 100644 --- a/src/core/context/AuthContext.h +++ b/src/core/context/AuthContext.h @@ -18,7 +18,6 @@ #include "UrlUtil.h" #include "asn1/CVCertificate.h" #include "asn1/CVCertificateChainBuilder.h" -#include "asn1/Chat.h" #include "context/WorkflowContext.h" #include "paos/MessageIdHandler.h" #include "paos/invoke/DidAuthenticateResponseEac1.h" @@ -87,20 +86,20 @@ class AuthContext QVector > mTransmitResponses; QSharedPointer mDisconnectResponse; QSharedPointer mStartPaosResponse; - QSharedPointer mOptionalChat, mRequiredChat, mEffectiveChat; - QString mRequiredAge; + QSet mEffectiveAccessRights; + QSet mRequiredAccessRights; + QSet mOptionalAccessRights; QMultiMap mCertificates; QSharedPointer mTerminalCvc, mDvCvc; CVCertificateChainBuilder mCvcChainBuilderProd, mCvcChainBuilderTest; - bool sanitizeEffectiveAccessRights(); + void initializeChat(); + bool removeForbiddenAccessRights(QSet& pSet); Q_SIGNALS: void fireDidAuthenticateEac1Changed(); + void fireAuthenticationDataChanged(); void fireEffectiveChatChanged(); - void fireOptionalChatChanged(); - void fireRequiredChatChanged(); - void fireRequiredAgeChanged(); public: AuthContext(ActivationContext* pActivationContext); @@ -369,7 +368,7 @@ class AuthContext void addTransmitResponse(const QSharedPointer& pTransmitResponse) { Q_ASSERT(!pTransmitResponse.isNull()); - mTransmitResponses.append(pTransmitResponse); + mTransmitResponses += pTransmitResponse; } @@ -382,21 +381,34 @@ class AuthContext void addTransmit(const QSharedPointer& pTransmit) { Q_ASSERT(!pTransmit.isNull()); - mTransmits.append(pTransmit); + mTransmits += pTransmit; } - const QSharedPointer getEffectiveChat() const + QString getRequiredAge() { - return mEffectiveChat; + Q_ASSERT(mDIDAuthenticateEAC1); + Q_ASSERT(mDIDAuthenticateEAC1->getAuthenticatedAuxiliaryData()); + return mDIDAuthenticateEAC1->getAuthenticatedAuxiliaryData()->getRequiredAge(); } - /*! - * \return Returns false if the accessrights were - * not valid and an adjustment was made. - */ - bool setEffectiveChat(const QSharedPointer& pEffectiveChat); + const QSet& getOptionalAccessRights() const + { + return mOptionalAccessRights; + } + + + const QSet& getRequiredAccessRights() const + { + return mRequiredAccessRights; + } + + + const QSet getEffectiveAccessRights() const + { + return mEffectiveAccessRights; + } /*! @@ -418,37 +430,7 @@ class AuthContext bool setEffectiveAccessRights(const QSet& pAccessRights); - const QSharedPointer getOptionalChat() const - { - return mOptionalChat; - } - - - void setOptionalChat(const QSharedPointer& pOptionalChat); - - - const QSharedPointer getRequiredChat() const - { - return mRequiredChat; - } - - - void setRequiredChat(const QSharedPointer& pRequiredChat); - - const QString& getRequiredAge() - { - return mRequiredAge; - } - - - void setRequiredAge(const QString& pRequiredAge) - { - if (mRequiredAge != pRequiredAge) - { - mRequiredAge = pRequiredAge; - Q_EMIT fireRequiredAgeChanged(); - } - } + QByteArray encodeEffectiveChat(); const QSharedPointer& getStartPaos() const @@ -493,10 +475,7 @@ class AuthContext } - void setTerminalCvc(const QSharedPointer& terminalCvc) - { - mTerminalCvc = terminalCvc; - } + void setTerminalCvc(const QSharedPointer& pTerminalCvc); }; diff --git a/src/core/context/ChangePinContext.cpp b/src/core/context/ChangePinContext.cpp index 5b864ff..8039fe3 100644 --- a/src/core/context/ChangePinContext.cpp +++ b/src/core/context/ChangePinContext.cpp @@ -10,7 +10,6 @@ using namespace governikus; ChangePinContext::ChangePinContext() : WorkflowContext() , mNewPin() - , mPuk() , mSuccessMessage() { } @@ -32,22 +31,6 @@ void ChangePinContext::setNewPin(const QString& pNewPin) } -const QString& ChangePinContext::getPuk() const -{ - return mPuk; -} - - -void ChangePinContext::setPuk(const QString& pPuk) -{ - if (mPuk != pPuk) - { - mPuk = pPuk; - Q_EMIT firePukChanged(); - } -} - - const QString& ChangePinContext::getSuccessMessage() const { return mSuccessMessage; diff --git a/src/core/context/ChangePinContext.h b/src/core/context/ChangePinContext.h index cca2651..f389dbc 100644 --- a/src/core/context/ChangePinContext.h +++ b/src/core/context/ChangePinContext.h @@ -17,7 +17,6 @@ class ChangePinContext Q_OBJECT QString mNewPin; - QString mPuk; QString mSuccessMessage; public: @@ -26,15 +25,11 @@ class ChangePinContext const QString& getNewPin() const; void setNewPin(const QString& pNewPin); - const QString& getPuk() const; - void setPuk(const QString& pPuk); - const QString& getSuccessMessage() const; void setSuccessMessage(const QString& pSuccessMessage); Q_SIGNALS: void fireNewPinChanged(); - void firePukChanged(); void fireSuccessMessageChanged(); }; diff --git a/src/core/context/ReaderDriverContext.cpp b/src/core/context/ReaderDriverContext.cpp index c944568..133cc5c 100644 --- a/src/core/context/ReaderDriverContext.cpp +++ b/src/core/context/ReaderDriverContext.cpp @@ -4,16 +4,19 @@ #include "ReaderDriverContext.h" -#include "DeviceDescriptor.h" #include "ReaderManager.h" - using namespace governikus; ReaderDriverContext::ReaderDriverContext() - : mReaderDetector(QSharedPointer(new ReaderDetector(getDriverSettings()))) + : QObject() +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) + , mReaderDetector(QSharedPointer(new ReaderDetector(getDriverSettings()))) +#endif { + #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) connect(mReaderDetector.data(), &ReaderDetector::fireReaderChangeDetected, this, &ReaderDriverContext::fireReaderChangeDetected); + #endif } @@ -22,6 +25,7 @@ ReaderDriverContext::~ReaderDriverContext() } +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) QVector > ReaderDriverContext::attachedDevices() { const QVector readerInfos = ReaderManager::getInstance().getReaderInfos(); @@ -29,6 +33,9 @@ QVector > ReaderDriverContext::attachedDevices( } +#endif + + QSharedPointer ReaderDriverContext::getDriverSettings() const { QSharedPointer settings(new DriverSettings()); diff --git a/src/core/context/ReaderDriverContext.h b/src/core/context/ReaderDriverContext.h index 4b08444..2a51e92 100644 --- a/src/core/context/ReaderDriverContext.h +++ b/src/core/context/ReaderDriverContext.h @@ -9,14 +9,16 @@ #include "DriverSettings.h" -#include "ReaderDetector.h" +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) + #include "DeviceDescriptor.h" + #include "ReaderDetector.h" +#endif #include namespace governikus { -class DeviceDescriptor; class ReaderDriverContext : public QObject @@ -25,12 +27,16 @@ class ReaderDriverContext public: ReaderDriverContext(); - ~ReaderDriverContext(); + virtual ~ReaderDriverContext(); + #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) QVector > attachedDevices(); + #endif private: + #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) const QSharedPointer mReaderDetector; + #endif QSharedPointer getDriverSettings() const; diff --git a/src/core/context/WorkflowContext.cpp b/src/core/context/WorkflowContext.cpp index b870183..aeaecb4 100644 --- a/src/core/context/WorkflowContext.cpp +++ b/src/core/context/WorkflowContext.cpp @@ -15,11 +15,219 @@ WorkflowContext::WorkflowContext() , mCardConnection() , mCan() , mPin() + , mPuk() , mPaceOutputData() , mOldRetryCounter(-1) - , mLastPaceResult(ReturnCode::OK) - , mResult(Result::createOk()) + , mLastPaceResult(CardReturnCode::OK) + , mStatus(GlobalStatus::Code::No_Error) , mErrorReportedToUser(true) , mWorkflowFinished(false) { } + + +bool WorkflowContext::isErrorReportedToUser() const +{ + return mErrorReportedToUser; +} + + +void WorkflowContext::setErrorReportedToUser(bool pErrorReportedToUser) +{ + mErrorReportedToUser = pErrorReportedToUser; +} + + +void WorkflowContext::setStateApproved(bool pApproved) +{ + if (mStateApproved != pApproved) + { + mStateApproved = pApproved; + Q_EMIT fireStateApprovedChanged(); + } +} + + +bool WorkflowContext::isStateApproved() +{ + return mStateApproved; +} + + +const QString& WorkflowContext::getCurrentState() const +{ + return mCurrentState; +} + + +void WorkflowContext::setCurrentState(const QString& pNewState) +{ + if (mCurrentState != pNewState) + { + mCurrentState = pNewState; + Q_EMIT fireCurrentStateChanged(pNewState); + } +} + + +ReaderManagerPlugInType WorkflowContext::getReaderType() const +{ + return mReaderType; +} + + +void WorkflowContext::setReaderType(ReaderManagerPlugInType pReaderType) +{ + if (mReaderType != pReaderType) + { + mReaderType = pReaderType; + Q_EMIT fireReaderTypeChanged(); + } +} + + +const QString& WorkflowContext::getReaderName() const +{ + return mReaderName; +} + + +void WorkflowContext::setReaderName(const QString& pReaderName) +{ + if (mReaderName != pReaderName) + { + mReaderName = pReaderName; + Q_EMIT fireReaderNameChanged(); + } +} + + +const QSharedPointer& WorkflowContext::getCardConnection() const +{ + return mCardConnection; +} + + +void WorkflowContext::setCardConnection(const QSharedPointer& pCardConnection) +{ + if (mCardConnection != pCardConnection) + { + mCardConnection = pCardConnection; + Q_EMIT fireCardConnectionChanged(); + } +} + + +bool WorkflowContext::isPinBlocked() +{ + return mCardConnection != nullptr && mCardConnection->getReaderInfo().getRetryCounter() == 0; +} + + +const QString& WorkflowContext::getPuk() const +{ + return mPuk; +} + + +void WorkflowContext::setPuk(const QString& pPuk) +{ + if (mPuk != pPuk) + { + mPuk = pPuk; + Q_EMIT firePukChanged(); + } +} + + +const QString& WorkflowContext::getCan() const +{ + return mCan; +} + + +void WorkflowContext::setCan(const QString& pCan) +{ + if (mCan != pCan) + { + mCan = pCan; + Q_EMIT fireCanChanged(); + } +} + + +const QString& WorkflowContext::getPin() const +{ + return mPin; +} + + +void WorkflowContext::setPin(const QString& pPin) +{ + if (mPin != pPin) + { + mPin = pPin; + Q_EMIT firePinChanged(); + } +} + + +EstablishPACEChannelOutput* WorkflowContext::getPaceOutputData() const +{ + return mPaceOutputData.data(); +} + + +void WorkflowContext::setPaceOutputData(const EstablishPACEChannelOutput& pPaceOutputData) +{ + mPaceOutputData.reset(new EstablishPACEChannelOutput(pPaceOutputData)); +} + + +CardReturnCode WorkflowContext::getLastPaceResult() const +{ + return mLastPaceResult; +} + + +int WorkflowContext::getOldRetryCounter() const +{ + return mOldRetryCounter; +} + + +void WorkflowContext::setLastPaceResultAndRetryCounter(CardReturnCode pLastPaceResult, int pOldRetryCounter) +{ + if (mLastPaceResult != pLastPaceResult || mOldRetryCounter != pOldRetryCounter) + { + mLastPaceResult = pLastPaceResult; + mOldRetryCounter = pOldRetryCounter; + Q_EMIT fireLastPaceResultChanged(); + } +} + + +const GlobalStatus& WorkflowContext::getStatus() const +{ + return mStatus; +} + + +void WorkflowContext::setStatus(const GlobalStatus& pStatus) +{ + mStatus = pStatus; + mErrorReportedToUser = false; + Q_EMIT fireResultChanged(); +} + + +bool WorkflowContext::isWorkflowFinished() const +{ + return mWorkflowFinished; +} + + +void WorkflowContext::setWorkflowFinished(bool pWorkflowFinished) +{ + mWorkflowFinished = pWorkflowFinished; +} diff --git a/src/core/context/WorkflowContext.h b/src/core/context/WorkflowContext.h index 4b29900..415a7bf 100644 --- a/src/core/context/WorkflowContext.h +++ b/src/core/context/WorkflowContext.h @@ -7,6 +7,7 @@ #pragma once #include "CardConnection.h" +#include "GlobalStatus.h" #include "Result.h" #include @@ -27,10 +28,11 @@ class WorkflowContext QSharedPointer mCardConnection; QString mCan; QString mPin; + QString mPuk; QScopedPointer mPaceOutputData; int mOldRetryCounter; - ReturnCode mLastPaceResult; - Result mResult; + CardReturnCode mLastPaceResult; + GlobalStatus mStatus; bool mErrorReportedToUser; bool mWorkflowFinished; @@ -42,6 +44,7 @@ class WorkflowContext void fireCardConnectionChanged(); void fireCanChanged(); void firePinChanged(); + void firePukChanged(); void fireLastPaceResultChanged(); void fireResultChanged(); @@ -51,198 +54,46 @@ class WorkflowContext public: WorkflowContext(); + bool isErrorReportedToUser() const; + void setErrorReportedToUser(bool pErrorReportedToUser = true); - bool isErrorReportedToUser() const - { - return mErrorReportedToUser; - } + void setStateApproved(bool pApproved = true); + bool isStateApproved(); + const QString& getCurrentState() const; + void setCurrentState(const QString& pNewState); - void setErrorReportedToUser(bool pErrorReportedToUser = true) - { - mErrorReportedToUser = pErrorReportedToUser; - } + ReaderManagerPlugInType getReaderType() const; + void setReaderType(ReaderManagerPlugInType pReaderType); + const QString& getReaderName() const; + void setReaderName(const QString& pReaderName); - void setStateApproved(bool pApproved = true) - { - if (mStateApproved != pApproved) - { - mStateApproved = pApproved; - Q_EMIT fireStateApprovedChanged(); - } - } + const QSharedPointer& getCardConnection() const; + void setCardConnection(const QSharedPointer& pCardConnection); + const QString& getPuk() const; + void setPuk(const QString& pPuk); - bool isStateApproved() - { - return mStateApproved; - } + const QString& getCan() const; + void setCan(const QString& pCan); + const QString& getPin() const; + void setPin(const QString& pPin); - const QString& getCurrentState() const - { - return mCurrentState; - } + EstablishPACEChannelOutput* getPaceOutputData() const; + void setPaceOutputData(const EstablishPACEChannelOutput& pPaceOutputData); + bool isPinBlocked(); + CardReturnCode getLastPaceResult() const; + int getOldRetryCounter() const; + void setLastPaceResultAndRetryCounter(CardReturnCode pLastPaceResult, int pOldRetryCounter); - void setCurrentState(const QString& pNewState) - { - if (mCurrentState != pNewState) - { - mCurrentState = pNewState; - Q_EMIT fireCurrentStateChanged(pNewState); - } - } - - - ReaderManagerPlugInType getReaderType() const - { - return mReaderType; - } - - - void setReaderType(ReaderManagerPlugInType pReaderType) - { - if (mReaderType != pReaderType) - { - mReaderType = pReaderType; - Q_EMIT fireReaderTypeChanged(); - } - } - - - const QString& getReaderName() const - { - return mReaderName; - } - - - void setReaderName(const QString& pReaderName) - { - if (mReaderName != pReaderName) - { - mReaderName = pReaderName; - Q_EMIT fireReaderNameChanged(); - } - } - - - const QSharedPointer& getCardConnection() const - { - return mCardConnection; - } - - - void setCardConnection(const QSharedPointer& pCardConnection) - { - if (mCardConnection != pCardConnection) - { - mCardConnection = pCardConnection; - Q_EMIT fireCardConnectionChanged(); - } - } - - - bool isPinBlocked() - { - return mCardConnection != nullptr && mCardConnection->getReaderInfo().getRetryCounter() == 0; - } - - - const QString& getCan() const - { - return mCan; - } - - - void setCan(const QString& pCan) - { - if (mCan != pCan) - { - mCan = pCan; - Q_EMIT fireCanChanged(); - } - } - - - const QString& getPin() const - { - return mPin; - } - - - void setPin(const QString& pPin) - { - if (mPin != pPin) - { - mPin = pPin; - Q_EMIT firePinChanged(); - } - } - - - EstablishPACEChannelOutput* getPaceOutputData() const - { - return mPaceOutputData.data(); - } - - - void setPaceOutputData(const EstablishPACEChannelOutput& pPaceOutputData) - { - mPaceOutputData.reset(new EstablishPACEChannelOutput(pPaceOutputData)); - } - - - ReturnCode getLastPaceResult() const - { - return mLastPaceResult; - } - - - int getOldRetryCounter() const - { - return mOldRetryCounter; - } - - - void setLastPaceResultAndRetryCounter(ReturnCode pLastPaceResult, int pOldRetryCounter) - { - if (mLastPaceResult != pLastPaceResult || mOldRetryCounter != pOldRetryCounter) - { - mLastPaceResult = pLastPaceResult; - mOldRetryCounter = pOldRetryCounter; - Q_EMIT fireLastPaceResultChanged(); - } - } - - - const Result& getResult() const - { - return mResult; - } - - - void setResult(const Result& pResult) - { - mResult = pResult; - mErrorReportedToUser = false; - Q_EMIT fireResultChanged(); - } - - - bool isWorkflowFinished() const - { - return mWorkflowFinished; - } - - - void setWorkflowFinished(bool pWorkflowFinished) - { - mWorkflowFinished = pWorkflowFinished; - } - + const GlobalStatus& getStatus() const; + void setStatus(const GlobalStatus& pResult); + bool isWorkflowFinished() const; + void setWorkflowFinished(bool pWorkflowFinished); }; } /* namespace governikus */ diff --git a/src/core/controller/AppController.cpp b/src/core/controller/AppController.cpp index 2594b6a..e457992 100644 --- a/src/core/controller/AppController.cpp +++ b/src/core/controller/AppController.cpp @@ -40,14 +40,14 @@ AppController::AppController() setObjectName(QStringLiteral("AppController")); // read and apply the settings AppSettings::getInstance().load(); - NetworkManager::setProxy(AppSettings::getInstance().getProxySettings().getProxyType()); - - connect(&AppSettings::getInstance(), &AbstractSettings::fireSettingsChanged, this, &AppController::onAppSettingsChanged); LanguageLoader::getInstance().load(); ResourceLoader::getInstance().init(); +#ifndef QT_NO_NETWORKPROXY + NetworkManager::setApplicationProxyFactory(); connect(&NetworkManager::getGlobalInstance(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); +#endif connect(this, &AppController::fireShutdown, &NetworkManager::getGlobalInstance(), &NetworkManager::onShutdown, Qt::QueuedConnection); } @@ -84,8 +84,8 @@ bool AppController::start() ReaderManager::getInstance().init(); connect(this, &AppController::fireShutdown, &ReaderManager::getInstance(), &ReaderManager::shutdown, Qt::DirectConnection); + connect(&ReaderManager::getInstance(), &ReaderManager::fireInitialized, this, &AppController::fireStarted, Qt::QueuedConnection); - Q_EMIT fireStarted(); return true; } @@ -93,7 +93,9 @@ bool AppController::start() void AppController::onAuthenticationRequest(ActivationContext* pActivationContext) { QSharedPointer authContext(new AuthContext(pActivationContext)); +#ifndef QT_NO_NETWORKPROXY connect(&authContext->getNetworkManager(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); +#endif if (!startNewWorkflow(Action::AUTH, authContext)) { @@ -136,16 +138,6 @@ void AppController::onActiveControllerDone() } -void AppController::onAppSettingsChanged() -{ - bool proxySettingsChanged = AppSettings::getInstance().getProxySettings().isUnsaved(); - if (proxySettingsChanged) - { - NetworkManager::setProxy(AppSettings::getInstance().getProxySettings().getProxyType()); - } -} - - void AppController::onCloseReminderFinished(bool pDontRemindAgain) { if (pDontRemindAgain) @@ -171,7 +163,9 @@ void AppController::onSelfAuthenticationRequested() { qDebug() << "self authentication requested"; QSharedPointer context(new SelfAuthenticationContext(nullptr)); +#ifndef QT_NO_NETWORKPROXY connect(&context->getNetworkManager(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); +#endif startNewWorkflow(Action::SELF, context); } @@ -186,25 +180,25 @@ void AppController::doShutdown() static const int TIMER_INTERVAL = 50; timer->setInterval(TIMER_INTERVAL); connect(timer, &QTimer::timeout, [ = ](){ - // Only wait for connections created by the global network manager here. We assume, - // that each context has already cleaned up its own connections before discarding - // their NetworkManager instances. - const int openConnectionCount = NetworkManager::getGlobalInstance().getOpenConnectionCount(); - static int timesInvoked = 0; - static const int THREE_SECONDS = 3000; - if (openConnectionCount > 0) - { - if (++timesInvoked % (THREE_SECONDS / TIMER_INTERVAL) == 0) - { - qDebug() << "There are still" << openConnectionCount << "pending network connections"; - } - return; - } + // Only wait for connections created by the global network manager here. We assume, + // that each context has already cleaned up its own connections before discarding + // their NetworkManager instances. + const int openConnectionCount = NetworkManager::getGlobalInstance().getOpenConnectionCount(); + static int timesInvoked = 0; + static const int THREE_SECONDS = 3000; + if (openConnectionCount > 0) + { + if (++timesInvoked % (THREE_SECONDS / TIMER_INTERVAL) == 0) + { + qDebug() << "There are still" << openConnectionCount << "pending network connections"; + } + return; + } - timer->deleteLater(); - qDebug() << "Quit event loop of QCoreApplication"; - qApp->quit(); - }); + timer->deleteLater(); + qDebug() << "Quit event loop of QCoreApplication"; + qApp->quit(); + }); timer->start(); } @@ -217,8 +211,12 @@ void AppController::onUiPlugin(UIPlugIn* pPlugin) connect(this, &AppController::fireWorkflowFinished, pPlugin, &UIPlugIn::onWorkflowFinished); connect(this, &AppController::fireStarted, pPlugin, &UIPlugIn::onApplicationStarted); connect(this, &AppController::fireShowUi, pPlugin, &UIPlugIn::onShowUi); - connect(this, &AppController::fireProxyAuthenticationRequired, pPlugin, &UIPlugIn::onProxyAuthenticationRequired); connect(this, &AppController::fireShowUserInformation, pPlugin, &UIPlugIn::fireShowUserInformation); + +#ifndef QT_NO_NETWORKPROXY + connect(this, &AppController::fireProxyAuthenticationRequired, pPlugin, &UIPlugIn::onProxyAuthenticationRequired); +#endif + connect(pPlugin, &UIPlugIn::fireChangePinRequest, this, &AppController::onChangePinRequested, Qt::QueuedConnection); connect(pPlugin, &UIPlugIn::fireSelfAuthenticationRequested, this, &AppController::onSelfAuthenticationRequested, Qt::QueuedConnection); connect(pPlugin, &UIPlugIn::fireQuitApplicationRequest, this, &AppController::doShutdown); diff --git a/src/core/controller/AppController.h b/src/core/controller/AppController.h index 1bdbde9..381cbe4 100644 --- a/src/core/controller/AppController.h +++ b/src/core/controller/AppController.h @@ -53,14 +53,15 @@ class AppController void fireWorkflowStarted(QSharedPointer pContext); void fireWorkflowFinished(QSharedPointer pContext); void fireShowUi(UiModule pModule); - void fireProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); void fireShowUserInformation(const QString& pInformationMessage); +#ifndef QT_NO_NETWORKPROXY + void fireProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); +#endif private Q_SLOTS: void doShutdown(); void onUiPlugin(UIPlugIn* pPlugin); void onActiveControllerDone(); - void onAppSettingsChanged(); void onCloseReminderFinished(bool pDontRemindAgain); void onChangePinRequested(); void onSelfAuthenticationRequested(); diff --git a/src/core/controller/AuthController.cpp b/src/core/controller/AuthController.cpp index 4a54608..462ef57 100644 --- a/src/core/controller/AuthController.cpp +++ b/src/core/controller/AuthController.cpp @@ -17,6 +17,7 @@ #include "states/StateEACAdditionalInputType.h" #include "states/StateEstablishPaceCan.h" #include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" #include "states/StateGenericSendReceive.h" #include "states/StateGetTcToken.h" #include "states/StateInitializeFramework.h" @@ -57,6 +58,7 @@ AuthController::AuthController(QSharedPointer pContext) auto sUpdateRetryCounter = addAndConnectState(); auto sEstablishPaceCan = addAndConnectState(); auto sEstablishPacePin = addAndConnectState(); + auto sEstablishPacePuk = addAndConnectState(); auto sDidAuthenticateEac1 = addAndConnectState(); auto sSendDidAuthenticateResponseEac1 = addAndConnectState(); auto sEacAdditionalInputType = addAndConnectState(); @@ -127,10 +129,15 @@ AuthController::AuthController(QSharedPointer pContext) sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sSendDidAuthenticateResponseEac1); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireSuccess, sEstablishPacePin); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, sUpdateRetryCounter); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireSuccess, sEstablishPacePin); sEstablishPaceCan->addTransition(sEstablishPaceCan, &StateEstablishPaceCan::fireInvalidCan, sUpdateRetryCounter); sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); @@ -141,6 +148,7 @@ AuthController::AuthController(QSharedPointer pContext) sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireSuccess, sSendDidAuthenticateResponseEac1); sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); diff --git a/src/core/controller/ChangePinController.cpp b/src/core/controller/ChangePinController.cpp index d1fb1e8..c6018c9 100644 --- a/src/core/controller/ChangePinController.cpp +++ b/src/core/controller/ChangePinController.cpp @@ -47,7 +47,7 @@ ChangePinController::ChangePinController(QSharedPointer pConte sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sCleanUpReaderManager); sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, sUpdateRetryCounter); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInoperativePuk, sUpdateRetryCounter); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInoperativePuk, sCleanUpReaderManager); sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireSuccess, sCleanUpReaderManager); sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireError, sCleanUpReaderManager); sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireCancel, sCleanUpReaderManager); diff --git a/src/core/controller/DiagnosisController_osx.cpp b/src/core/controller/DiagnosisController_osx.cpp index f113867..c851cdc 100644 --- a/src/core/controller/DiagnosisController_osx.cpp +++ b/src/core/controller/DiagnosisController_osx.cpp @@ -219,7 +219,10 @@ void DiagnosisController::getPcscInfo(QVector& ? driverInfo.mBundleShortVersion : driverInfo.mBundleVersion; } - pDrivers.append(DiagnosisContext::ComponentInfo(driverPath, description, version, - driverInfo.mIfdManufacturer)); + pDrivers += DiagnosisContext::ComponentInfo( + driverPath, + description, + version, + driverInfo.mIfdManufacturer); } } diff --git a/src/core/controller/DiagnosisController_win.cpp b/src/core/controller/DiagnosisController_win.cpp index 5476de7..5c6e198 100644 --- a/src/core/controller/DiagnosisController_win.cpp +++ b/src/core/controller/DiagnosisController_win.cpp @@ -17,6 +17,7 @@ using namespace governikus; +#ifndef Q_OS_WINRT static QString getWindowsDirectoryPath() { UINT length = GetSystemWindowsDirectory(nullptr, 0); @@ -121,7 +122,7 @@ static void addWindowsComponentInfo(QVector& pC return; } - pComponents.append(DiagnosisContext::ComponentInfo(pFileName, description, version, company)); + pComponents += DiagnosisContext::ComponentInfo(pFileName, description, version, company); } @@ -211,9 +212,13 @@ static QString getWindowsServiceDriverFileName(const QString& pServiceName) } +#endif + + void DiagnosisController::getPcscInfo(QVector& pComponents, QVector& pDrivers) { +#ifndef Q_OS_WINRT addWindowsComponentInfo(pComponents, toAbsoluteWindowsDirectoryPath(QStringLiteral("System32\\WinSCard.dll"))); addWindowsComponentInfo(pComponents, toAbsoluteWindowsDirectoryPath(QStringLiteral("System32\\SCardDlg.dll"))); addWindowsComponentInfo(pComponents, toAbsoluteWindowsDirectoryPath(QStringLiteral("System32\\SCardSvr.dll"))); @@ -225,4 +230,5 @@ void DiagnosisController::getPcscInfo(QVector& const QString path = getWindowsServiceDriverFileName(moduleName); addWindowsComponentInfo(pDrivers, path); } +#endif } diff --git a/src/core/controller/SelfAuthController.cpp b/src/core/controller/SelfAuthController.cpp index 1e45a37..36cd9fc 100644 --- a/src/core/controller/SelfAuthController.cpp +++ b/src/core/controller/SelfAuthController.cpp @@ -18,6 +18,7 @@ #include "states/StateEACAdditionalInputType.h" #include "states/StateEstablishPaceCan.h" #include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" #include "states/StateGenericSendReceive.h" #include "states/StateGetSelfAuthenticationData.h" #include "states/StateGetTcToken.h" @@ -57,6 +58,7 @@ SelfAuthController::SelfAuthController(QSharedPointer auto sUpdateRetryCounter = addAndConnectState(); auto sEstablishPaceCan = addAndConnectState(); auto sEstablishPacePin = addAndConnectState(); + auto sEstablishPacePuk = addAndConnectState(); auto sDidAuthenticateEac1 = addAndConnectState(); auto sSendDidAuthenticateResponseEac1 = addAndConnectState(); auto sEacAdditionalInputType = addAndConnectState(); @@ -124,10 +126,15 @@ SelfAuthController::SelfAuthController(QSharedPointer sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sSendDidAuthenticateResponseEac1); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireSuccess, sEstablishPacePin); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, sUpdateRetryCounter); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireSuccess, sEstablishPacePin); sEstablishPaceCan->addTransition(sEstablishPaceCan, &StateEstablishPaceCan::fireInvalidCan, sUpdateRetryCounter); sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); diff --git a/src/core/paos/element/Eac1InputType.h b/src/core/paos/element/Eac1InputType.h index 3a8819d..c1f4225 100644 --- a/src/core/paos/element/Eac1InputType.h +++ b/src/core/paos/element/Eac1InputType.h @@ -24,11 +24,13 @@ class test_StateProcessCertificatesFromEac2; namespace governikus { +class TestAuthContext; class Eac1InputType { friend class DidAuthenticateEac1Parser; friend class::test_StatePrepareChat; + friend class TestAuthContext; friend class::test_StateExtractCvcsFromEac1InputType; friend class::test_StatePreVerification; friend class::test_StateCertificateDescriptionCheck; @@ -69,7 +71,7 @@ class Eac1InputType void appendCvcerts(QSharedPointer cvcert) { - mCvCertificates.append(cvcert); + mCvCertificates += cvcert; } diff --git a/src/core/paos/element/Eac2InputType.cpp b/src/core/paos/element/Eac2InputType.cpp index 529b037..65cd22a 100644 --- a/src/core/paos/element/Eac2InputType.cpp +++ b/src/core/paos/element/Eac2InputType.cpp @@ -54,11 +54,11 @@ void Eac2InputType::setSignature(const QString& signature) void Eac2InputType::appendCvcert(QSharedPointer cvcert) { - mCvCertificates.append(cvcert); + mCvCertificates += cvcert; } void Eac2InputType::appendCvcertAsBinary(const QByteArray& cvcertAsBinary) { - mCvCertificatesAsBinary.append(cvcertAsBinary); + mCvCertificatesAsBinary += cvcertAsBinary; } diff --git a/src/core/paos/invoke/PaosCreator.cpp b/src/core/paos/invoke/PaosCreator.cpp index 2f3db40..bfd655b 100644 --- a/src/core/paos/invoke/PaosCreator.cpp +++ b/src/core/paos/invoke/PaosCreator.cpp @@ -3,6 +3,7 @@ */ #include "PaosCreator.h" + #include "paos/ResponseType.h" #include @@ -77,8 +78,8 @@ QString PaosCreator::getNamespacePrefix(Namespace pPrefix, const QString& pSuffi { Q_ASSERT(pPrefix != Namespace::DEFAULT); Q_ASSERT(!value.isEmpty()); - value.append(':'); - value.append(pSuffix); + value += ':'; + value += pSuffix; } return value; } @@ -197,10 +198,11 @@ QDomElement PaosCreator::createResultElement() Result result = paosResponse->getResult(); element.appendChild(createTextElement(QStringLiteral("ResultMajor"), result.getMajorString())); - if (result.getMinor() != Result::Minor::null) + if (result.getMinor() != GlobalStatus::Code::Unknown_Error) { element.appendChild(createTextElement(QStringLiteral("ResultMinor"), result.getMinorString())); } + if (!result.getMessage().isNull()) { QDomElement resultElement = createTextElement(QStringLiteral("ResultMessage"), result.getMessage()); diff --git a/src/core/paos/retrieve/DidAuthenticateEac1.h b/src/core/paos/retrieve/DidAuthenticateEac1.h index 40a6a5b..96b73e6 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac1.h +++ b/src/core/paos/retrieve/DidAuthenticateEac1.h @@ -26,12 +26,14 @@ class test_StateCertificateDescriptionCheck; namespace governikus { +class TestAuthContext; class DIDAuthenticateEAC1 : public PaosMessage { friend class DidAuthenticateEac1Parser; friend class::test_StatePrepareChat; + friend class TestAuthContext; friend class::test_StatePreVerification; friend class::test_StateExtractCvcsFromEac1InputType; friend class::test_StateProcessCertificatesFromEac2; diff --git a/src/core/paos/retrieve/StartPaosResponse.cpp b/src/core/paos/retrieve/StartPaosResponse.cpp index fedd1a9..4d00586 100644 --- a/src/core/paos/retrieve/StartPaosResponse.cpp +++ b/src/core/paos/retrieve/StartPaosResponse.cpp @@ -12,7 +12,7 @@ StartPaosResponse::StartPaosResponse(const QByteArray& pXmlData) , ElementDetector(pXmlData) { parse(); - setResult(Result(mResultMajor, mResultMinor, mResultMessage, QString(), ReturnCode::UNDEFINED, Result::Origin::SERVER)); + setResult(Result(mResultMajor, mResultMinor, mResultMessage, Origin::Server)); } diff --git a/src/core/paos/retrieve/Transmit.h b/src/core/paos/retrieve/Transmit.h index 236c2ae..3258526 100644 --- a/src/core/paos/retrieve/Transmit.h +++ b/src/core/paos/retrieve/Transmit.h @@ -47,7 +47,7 @@ class Transmit void appendInputApduInfo(const InputAPDUInfo& pInfo) { - mInputApduInfos.append(pInfo); + mInputApduInfos += pInfo; } diff --git a/src/core/states/AbstractGenericState.h b/src/core/states/AbstractGenericState.h index 6bc41a9..1930932 100644 --- a/src/core/states/AbstractGenericState.h +++ b/src/core/states/AbstractGenericState.h @@ -27,7 +27,7 @@ class AbstractGenericState AbstractGenericState(const QSharedPointer& pContext, bool pConnectOnCardRemoved = true) : AbstractState(pContext, pConnectOnCardRemoved) { - Q_ASSERT(mContext.dynamicCast()); + Q_ASSERT(mContext.objectCast()); } diff --git a/src/core/states/AbstractState.cpp b/src/core/states/AbstractState.cpp index e618e3a..89b507c 100644 --- a/src/core/states/AbstractState.cpp +++ b/src/core/states/AbstractState.cpp @@ -5,6 +5,7 @@ */ #include "AbstractState.h" + #include "ReaderManager.h" #include @@ -75,7 +76,7 @@ void AbstractState::onEntry(QEvent* pEvent) mConnections += connect(mContext.data(), &WorkflowContext::fireCancelWorkflow, this, &AbstractState::onUserCancelled); mConnections += connect(mContext.data(), &WorkflowContext::fireStateApprovedChanged, this, &AbstractState::onStateApprovedChanged); - qCDebug(statemachine) << "Next state" << getStateName(); + qCDebug(statemachine) << "Next state is" << getStateName(); mContext->setCurrentState(getStateName()); } @@ -91,24 +92,20 @@ void AbstractState::onExit(QEvent* pEvent) mContext->setStateApproved(false); - qCDebug(statemachine) << "Leaving state" << getStateName() << "with result:"; - qCDebug(statemachine) << " " << mContext->getResult().getMajor(); - qCDebug(statemachine) << " " << mContext->getResult().getMinor(); - qCDebug(statemachine) << " " << mContext->getResult().getMinorDescription(); - qCDebug(statemachine) << " " << mContext->getResult().getMessage(); + qCDebug(statemachine) << "Leaving state" << getStateName() << "with status:" << mContext->getStatus(); } bool AbstractState::isCancellationByUser() { - return mContext->getResult().getMinor() == Result::Minor::SAL_Cancellation_by_User; + return mContext->getStatus().isCancellationByUser(); } void AbstractState::onUserCancelled() { qCInfo(support) << "Cancellation by user"; - setResult(Result::createCancelByUserError()); + setStatus(GlobalStatus::Code::Workflow_Cancellation_By_User); Q_EMIT fireCancel(); } @@ -117,17 +114,16 @@ void AbstractState::onCardRemoved(const QString& pReaderName) { if (pReaderName == mContext->getReaderName()) { - QString errorMessage = tr("The ID card has been removed. The process is aborted."); - setResult(Result::createCardRemovedError(errorMessage)); + setStatus(GlobalStatus::Code::Workflow_Card_Removed); Q_EMIT fireError(); } } -void AbstractState::setResult(const Result& pResult) +void AbstractState::setStatus(const GlobalStatus& pStatus) { - if (!pResult.isOk() && mContext->getResult().isOk()) + if (pStatus.isError() && mContext->getStatus().isNoError()) { - mContext->setResult(pResult); + mContext->setStatus(pStatus); } } diff --git a/src/core/states/AbstractState.h b/src/core/states/AbstractState.h index 68d6e34..ddce3fb 100644 --- a/src/core/states/AbstractState.h +++ b/src/core/states/AbstractState.h @@ -41,7 +41,7 @@ class AbstractState bool isCancellationByUser(); - void setResult(const Result& pResult); + void setStatus(const GlobalStatus& pStatus); public: static QString getClassName(const char* pName); diff --git a/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp b/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp index baec812..3205b71 100644 --- a/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp +++ b/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp @@ -13,7 +13,6 @@ #include "states/StateEditAccessRights.h" #include "states/StateExtractCvcsFromEac1IntputType.h" #include "states/StatePreVerification.h" -#include "states/StatePrepareChat.h" using namespace governikus; @@ -27,14 +26,12 @@ CompositeStateProcessCvcsAndSetRights::CompositeStateProcessCvcsAndSetRights(con auto sPreVerification = StateBuilder::createState(mContext); auto sCertificateDescriptionCheck = StateBuilder::createState(mContext); auto sCheckCertificates = StateBuilder::createState(mContext); - auto sPrepareChat = StateBuilder::createState(mContext); auto sEditAccessRights = StateBuilder::createState(mContext); sExtractCvcsFromEac1InputType->setParent(this); sPreVerification->setParent(this); sCertificateDescriptionCheck->setParent(this); sCheckCertificates->setParent(this); - sPrepareChat->setParent(this); sEditAccessRights->setParent(this); setInitialState(sExtractCvcsFromEac1InputType); @@ -51,14 +48,10 @@ CompositeStateProcessCvcsAndSetRights::CompositeStateProcessCvcsAndSetRights(con connect(sCertificateDescriptionCheck, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); connect(sCertificateDescriptionCheck, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); - sCheckCertificates->addTransition(sCheckCertificates, &AbstractState::fireSuccess, sPrepareChat); + sCheckCertificates->addTransition(sCheckCertificates, &AbstractState::fireSuccess, sEditAccessRights); connect(sCheckCertificates, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); connect(sCheckCertificates, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); - sPrepareChat->addTransition(sPrepareChat, &AbstractState::fireSuccess, sEditAccessRights); - connect(sPrepareChat, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sPrepareChat, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); - connect(sEditAccessRights, &AbstractState::fireSuccess, this, &CompositeStateProcessCvcsAndSetRights::fireSuccess); connect(sEditAccessRights, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); connect(sEditAccessRights, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); diff --git a/src/core/states/StateCertificateDescriptionCheck.cpp b/src/core/states/StateCertificateDescriptionCheck.cpp index 67a795e..ddacc7b 100644 --- a/src/core/states/StateCertificateDescriptionCheck.cpp +++ b/src/core/states/StateCertificateDescriptionCheck.cpp @@ -31,7 +31,7 @@ void StateCertificateDescriptionCheck::run() if (getContext()->getDidAuthenticateEac1()->getCertificateDescriptionAsBinary().isNull()) { qCritical() << "No certificate description available"; - setResult(Result::createParameterError(tr("No certificate description available."))); + setStatus(GlobalStatus::Code::Workflow_Certificate_No_Description); Q_EMIT fireError(); return; } @@ -39,7 +39,7 @@ void StateCertificateDescriptionCheck::run() if (getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl().isNull()) { qCritical() << "No subject url available in certificate description"; - setResult(Result::createParameterError(tr("No subject url available in certificate description."))); + setStatus(GlobalStatus::Code::Workflow_Certificate_No_Url_In_Description); Q_EMIT fireError(); return; } @@ -58,7 +58,7 @@ void StateCertificateDescriptionCheck::run() else { qCritical() << certificateHashError; - setResult(Result::createParameterError(tr("The certificate description does not match the certificate."))); + setStatus(GlobalStatus::Code::Workflow_Certificate_Hash_Error); Q_EMIT fireError(); return; } @@ -76,7 +76,7 @@ void StateCertificateDescriptionCheck::run() else { qCritical() << sameOriginPolicyError; - setResult(Result::createParameterError(tr("The subject URL in the certificate description and the TCToken URL don't satisfy the same origin policy."))); + setStatus(GlobalStatus::Code::Workflow_Certificate_Sop_Error); Q_EMIT fireError(); return; } diff --git a/src/core/states/StateChangePin.cpp b/src/core/states/StateChangePin.cpp index 3427f18..5aa5459 100644 --- a/src/core/states/StateChangePin.cpp +++ b/src/core/states/StateChangePin.cpp @@ -5,7 +5,6 @@ */ #include "ReaderManager.h" -#include "ReturnCodeUtil.h" #include "StateChangePin.h" #include @@ -23,33 +22,33 @@ void StateChangePin::run() auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection); - qDebug() << "Invoke set Eid pin command"; + qDebug() << "Invoke set Eid PIN command"; mConnections += cardConnection->callSetEidPinCommand(this, &StateChangePin::onSetEidPinDone, getContext()->getNewPin()); } void StateChangePin::onSetEidPinDone(QSharedPointer pCommand) { - const ReturnCode returnCode = pCommand->getReturnCode(); + const CardReturnCode returnCode = pCommand->getReturnCode(); switch (returnCode) { - case ReturnCode::OK: - getContext()->setSuccessMessage(tr("Pin successfully changed")); + case CardReturnCode::OK: + getContext()->setSuccessMessage(tr("You have successfully changed your PIN.")); Q_EMIT fireSuccess(); break; - case ReturnCode::CANCELLATION_BY_USER: - setResult(Result::createCancelByUserError()); + case CardReturnCode::CANCELLATION_BY_USER: + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireCancel(); break; - case ReturnCode::NEW_PINS_DONT_MATCH: - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(returnCode))); + case CardReturnCode::NEW_PIN_MISMATCH: + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireInvalidPin(); break; default: - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(returnCode))); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireError(); break; } diff --git a/src/core/states/StateCheckCertificates.cpp b/src/core/states/StateCheckCertificates.cpp index e22e9a9..1589085 100644 --- a/src/core/states/StateCheckCertificates.cpp +++ b/src/core/states/StateCheckCertificates.cpp @@ -39,7 +39,7 @@ void StateCheckCertificates::run() else { qCritical() << certificateDescError; - setResult(Result::createTrustedChannelEstablishmentError(tr("Hash of certificate not in certificate description"))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description); Q_EMIT fireError(); return; } diff --git a/src/core/states/StateCheckError.cpp b/src/core/states/StateCheckError.cpp index eebd302..f3bbbde 100644 --- a/src/core/states/StateCheckError.cpp +++ b/src/core/states/StateCheckError.cpp @@ -16,7 +16,7 @@ StateCheckError::StateCheckError(const QSharedPointer& pContext void StateCheckError::run() { - if (getContext()->getResult().isOk() || getContext()->isErrorReportedToUser()) + if (getContext()->getStatus().isNoError() || getContext()->isErrorReportedToUser()) { Q_EMIT fireSuccess(); return; diff --git a/src/core/states/StateCheckRefreshAddress.cpp b/src/core/states/StateCheckRefreshAddress.cpp index b0cbe7d..fe80874 100644 --- a/src/core/states/StateCheckRefreshAddress.cpp +++ b/src/core/states/StateCheckRefreshAddress.cpp @@ -7,6 +7,7 @@ #include "StateCheckRefreshAddress.h" #include "CertificateChecker.h" +#include "HttpStatusCode.h" #include "NetworkManager.h" #include "StateRedirectBrowser.h" #include "TlsConfiguration.h" @@ -130,22 +131,17 @@ void StateCheckRefreshAddress::sendGetRequest() void StateCheckRefreshAddress::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(pErrors)) + if (TlsConfiguration::containsFatalError(mReply, pErrors)) { - reportCommunicationError(tr("Failed to establish secure connection")); - } - else - { - qDebug() << "Ignore SSL errors on QNetworkReply"; - mReply->ignoreSslErrors(); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Ssl_Establishment_Error)); } } -void StateCheckRefreshAddress::reportCommunicationError(const QString& pMessage) +void StateCheckRefreshAddress::reportCommunicationError(const GlobalStatus& pStatus) { - qCritical() << pMessage; - setResult(Result::createCommunicationError(pMessage)); + qCritical() << pStatus; + setStatus(pStatus); Q_EMIT fireError(); } @@ -167,16 +163,23 @@ bool StateCheckRefreshAddress::checkSslConnectionAndSaveCertificate(const QSslCo qDebug() << "Used server certificate:" << pSslConfiguration.peerCertificate(); qDebug() << "Used ephemeral server key:" << pSslConfiguration.ephemeralServerKey(); - QString errorMsg = CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), mUrl, getContext()); - if (!errorMsg.isNull()) + switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), mUrl, getContext())) { - reportCommunicationError(errorMsg); - return false; + case CertificateChecker::CertificateStatus::Good: + break; + + case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length)); + return false; + + case CertificateChecker::CertificateStatus::Hash_Not_In_Description: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description)); + return false; } + if (!CertificateChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) { - errorMsg = tr("Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length."); - reportCommunicationError(errorMsg); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length)); return false; } @@ -193,27 +196,48 @@ void StateCheckRefreshAddress::onNetworkReply() if (mReply->error() != QNetworkReply::NoError) { qCritical() << "An error occured: " << mReply->errorString(); - reportCommunicationError(NetworkManager::getLocalizedErrorString(mReply.data())); + switch (NetworkManager::toNetworkError(mReply.data())) + { + case NetworkManager::NetworkError::TimeOut: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_TimeOut)); + break; + + case NetworkManager::NetworkError::ProxyError: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Proxy_Error)); + break; + + case NetworkManager::NetworkError::SslError: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Ssl_Establishment_Error)); + break; + + case NetworkManager::NetworkError::OtherError: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Other_Error)); + break; + } return; } - if (statusCode != 302 && statusCode != 303 && statusCode != 307) + + if (statusCode != HttpStatusCode::FOUND && statusCode != HttpStatusCode::SEE_OTHER && statusCode != HttpStatusCode::TEMPORARY_REDIRECT) { qCritical() << "Got unexpected status code: " << statusCode; - reportCommunicationError(tr("Expected redirect, got %1").arg(QString::number(statusCode))); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Expected_Redirect, QString::number(statusCode))); return; } + if (redirectUrl.isEmpty()) { qCritical() << "Got empty redirect URL"; - reportCommunicationError(tr("Empty redirect URL")); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url)); return; } + if (!redirectUrl.isValid()) { qCritical() << "Got malformed redirect URL:" << redirectUrl; - reportCommunicationError(tr("Malformed redirect URL: %1").arg(QString::fromLatin1(redirectUrl.toEncoded()))); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url, QString::fromLatin1(redirectUrl.toEncoded()))); return; } + if (redirectUrl.scheme() != QLatin1String("https")) { auto httpsError = QStringLiteral("Redirect URL is not https: %1").arg(redirectUrl.toString()); @@ -225,7 +249,7 @@ void StateCheckRefreshAddress::onNetworkReply() else { qCritical() << httpsError; - reportCommunicationError(tr("Invalid scheme: %1").arg(redirectUrl.scheme())); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Invalid_Scheme, redirectUrl.scheme())); return; } } @@ -279,7 +303,7 @@ void StateCheckRefreshAddress::fetchServerCertificate() mReply = mNetworkManager.get(request); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDoneFetchingServerCertificate); - mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrorsFetchingServerCertificate); + mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); mConnections += connect(mReply.data(), QOverload::of(&QNetworkReply::error), this, &StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate); } @@ -309,20 +333,6 @@ void StateCheckRefreshAddress::doneSuccess() } -void StateCheckRefreshAddress::onSslErrorsFetchingServerCertificate(const QList& pErrors) -{ - if (TlsConfiguration::containsFatalError(pErrors)) - { - reportCommunicationError(tr("Failed to establish secure connection")); - } - else - { - qDebug() << "Ignore SSL errors on QSslSocket"; - mReply->ignoreSslErrors(); - } -} - - void StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate(QNetworkReply::NetworkError pError) { if (mCertificateFetched && pError == QNetworkReply::NetworkError::OperationCanceledError) @@ -330,5 +340,5 @@ void StateCheckRefreshAddress::onNetworkErrorFetchingServerCertificate(QNetworkR return; } qCritical() << "An error occured fetching the server certificate: " << mReply->errorString(); - reportCommunicationError(tr("Failed to establish secure connection")); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url)); } diff --git a/src/core/states/StateCheckRefreshAddress.h b/src/core/states/StateCheckRefreshAddress.h index b8a9e7e..1c5a905 100644 --- a/src/core/states/StateCheckRefreshAddress.h +++ b/src/core/states/StateCheckRefreshAddress.h @@ -47,14 +47,13 @@ class StateCheckRefreshAddress void fetchServerCertificate(); bool checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration); void doneSuccess(); - void reportCommunicationError(const QString& pMessage); + void reportCommunicationError(const GlobalStatus& pStatus); private Q_SLOTS: void onSslHandshakeDone(); void onNetworkReply(); void onSslErrors(const QList& errors); void onSslHandshakeDoneFetchingServerCertificate(); - void onSslErrorsFetchingServerCertificate(const QList& errors); void onNetworkErrorFetchingServerCertificate(QNetworkReply::NetworkError pError); }; diff --git a/src/core/states/StateConnectCard.cpp b/src/core/states/StateConnectCard.cpp index 6a85b3a..dd750b6 100644 --- a/src/core/states/StateConnectCard.cpp +++ b/src/core/states/StateConnectCard.cpp @@ -20,7 +20,7 @@ void StateConnectCard::run() qDebug() << "StateConnectCard::run()"; mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StateConnectCard::onCardInserted); mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StateConnectCard::onReaderRemoved); - mConnections += connect(getContext().data(), &WorkflowContext::fireAbortCardSelection, this, &StateConnectCard::fireAbort); + mConnections += connect(getContext().data(), &WorkflowContext::fireAbortCardSelection, this, &StateConnectCard::onAbort); onCardInserted(); } @@ -30,8 +30,11 @@ void StateConnectCard::onCardInserted() ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); if (readerInfo.getCardType() == CardType::EID_CARD) { - qDebug() << "Card has been inserted, trying to connect"; - mConnections += ReaderManager::getInstance().callCreateCardConnectionCommand(readerInfo.getName(), this, &StateConnectCard::onCommandDone); + if (!readerInfo.isPinDeactivated()) + { + qDebug() << "Card has been inserted, trying to connect"; + mConnections += ReaderManager::getInstance().callCreateCardConnectionCommand(readerInfo.getName(), this, &StateConnectCard::onCommandDone); + } } } @@ -41,7 +44,8 @@ void StateConnectCard::onCommandDone(QSharedPointer qDebug() << "Card connection command completed"; if (pCommand->getCardConnection() == nullptr) { - error(tr("An error occurred while communicating with the card reader.")); + setStatus(GlobalStatus::Code::Workflow_Reader_Communication_Error); + Q_EMIT fireError(); return; } @@ -51,13 +55,6 @@ void StateConnectCard::onCommandDone(QSharedPointer } -void StateConnectCard::error(const QString& pText) -{ - setResult(Result::createCommunicationError(pText)); - Q_EMIT fireError(); -} - - void StateConnectCard::onReaderRemoved(const QString& pReaderName) { if (pReaderName == getContext()->getReaderName()) @@ -65,3 +62,14 @@ void StateConnectCard::onReaderRemoved(const QString& pReaderName) Q_EMIT fireReaderRemoved(); } } + + +void StateConnectCard::onAbort() +{ + ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); + if (readerInfo.isValid() && readerInfo.isConnected()) + { + ReaderManager::getInstance().disconnectReader(readerInfo.getName()); + } + Q_EMIT fireAbort(); +} diff --git a/src/core/states/StateConnectCard.h b/src/core/states/StateConnectCard.h index 70706ac..1f9189f 100644 --- a/src/core/states/StateConnectCard.h +++ b/src/core/states/StateConnectCard.h @@ -17,13 +17,13 @@ class StateConnectCard friend class StateBuilder; StateConnectCard(const QSharedPointer& pContext); - void error(const QString& pText); virtual void run() override; private Q_SLOTS: void onCardInserted(); void onCommandDone(QSharedPointer pCommand); void onReaderRemoved(const QString& pReaderName); + void onAbort(); Q_SIGNALS: void fireAbort(); diff --git a/src/core/states/StateDestroyPace.cpp b/src/core/states/StateDestroyPace.cpp index e49ff57..11e1082 100644 --- a/src/core/states/StateDestroyPace.cpp +++ b/src/core/states/StateDestroyPace.cpp @@ -7,8 +7,6 @@ #include "StateDestroyPace.h" -#include "ReturnCodeUtil.h" - using namespace governikus; diff --git a/src/core/states/StateDidAuthenticateEac1.cpp b/src/core/states/StateDidAuthenticateEac1.cpp index 39475ef..c6b5724 100644 --- a/src/core/states/StateDidAuthenticateEac1.cpp +++ b/src/core/states/StateDidAuthenticateEac1.cpp @@ -6,7 +6,6 @@ #include "CardConnection.h" #include "Result.h" -#include "ReturnCodeUtil.h" #include "StateDidAuthenticateEac1.h" #include "asn1/CVCertificateChainBuilder.h" @@ -27,7 +26,7 @@ void StateDidAuthenticateEac1::run() Q_ASSERT(!getContext()->getDidAuthenticateEac1().isNull()); Q_ASSERT(getContext()->getPaceOutputData() != nullptr); Q_ASSERT(getContext()->getCardConnection()); - Q_ASSERT(getContext()->getEffectiveChat()); + Q_ASSERT(!getContext()->encodeEffectiveChat().isEmpty()); auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection); @@ -37,14 +36,14 @@ void StateDidAuthenticateEac1::run() void StateDidAuthenticateEac1::onCardCommandDone(QSharedPointer pCommand) { - ReturnCode result = pCommand->getReturnCode(); - if (result == ReturnCode::OK) + CardReturnCode result = pCommand->getReturnCode(); + if (result == CardReturnCode::OK) { auto eac1Command = pCommand.staticCast(); const QByteArray& challenge = eac1Command->getChallenge(); QSharedPointer eac1Response = getContext()->getDidAuthenticateResponseEac1(); - eac1Response->setCertificateHolderAuthorizationTemplate(getContext()->getEffectiveChat()->encode().toHex()); + eac1Response->setCertificateHolderAuthorizationTemplate(getContext()->encodeEffectiveChat().toHex()); eac1Response->setChallenge(challenge.toHex()); auto paceOutput = getContext()->getPaceOutputData(); @@ -59,7 +58,7 @@ void StateDidAuthenticateEac1::onCardCommandDone(QSharedPointer } else { - setResult(Result::createError(result)); + setStatus(CardReturnCodeUtil::toGlobalStatus(result)); Q_EMIT fireError(); } } diff --git a/src/core/states/StateDidAuthenticateEac2.cpp b/src/core/states/StateDidAuthenticateEac2.cpp index 455b060..23354e0 100644 --- a/src/core/states/StateDidAuthenticateEac2.cpp +++ b/src/core/states/StateDidAuthenticateEac2.cpp @@ -37,7 +37,7 @@ void StateDidAuthenticateEac2::run() auto cvcChain = getContext()->getChainForCertificationAuthority(*getContext()->getPaceOutputData()); if (!cvcChain.isValid()) { - setResult(Result::createNoPermissionError(tr("Authentication failed."))); + setStatus(GlobalStatus::Code::Workflow_No_Permission_Error); Q_EMIT fireError(); return; } @@ -49,9 +49,9 @@ void StateDidAuthenticateEac2::run() void StateDidAuthenticateEac2::onCardCommandDone(QSharedPointer pCommand) { - if (pCommand->getReturnCode() != ReturnCode::OK) + if (pCommand->getReturnCode() != CardReturnCode::OK) { - setResult(Result::createNoPermissionError(tr("Authentication failed."))); + setStatus(GlobalStatus::Code::Workflow_No_Permission_Error); Q_EMIT fireError(); } diff --git a/src/core/states/StateEstablishPaceCan.cpp b/src/core/states/StateEstablishPaceCan.cpp index 03b3a29..2f8e63c 100644 --- a/src/core/states/StateEstablishPaceCan.cpp +++ b/src/core/states/StateEstablishPaceCan.cpp @@ -7,9 +7,6 @@ #include "StateEstablishPaceCan.h" -#include "ReturnCodeUtil.h" - - using namespace governikus; StateEstablishPaceCan::StateEstablishPaceCan(const QSharedPointer& pContext) @@ -23,7 +20,7 @@ void StateEstablishPaceCan::run() auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection); - qDebug() << "Establish Pace connection with Can"; + qDebug() << "Establish Pace connection with CAN"; mConnections += cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPaceCan::onEstablishConnectionDone, PACE_PIN_ID::PACE_CAN, getContext()->getCan()); getContext()->setCan(QString()); } @@ -31,34 +28,34 @@ void StateEstablishPaceCan::run() void StateEstablishPaceCan::onUserCancelled() { - getContext()->setLastPaceResultAndRetryCounter(ReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); + getContext()->setLastPaceResultAndRetryCounter(CardReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); AbstractState::onUserCancelled(); } void StateEstablishPaceCan::onEstablishConnectionDone(QSharedPointer pCommand) { - const ReturnCode returnCode = pCommand->getReturnCode(); + const CardReturnCode returnCode = pCommand->getReturnCode(); switch (returnCode) { - case ReturnCode::OK: + case CardReturnCode::OK: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); Q_EMIT fireSuccess(); break; - case ReturnCode::CANCELLATION_BY_USER: + case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setResult(Result::createCancelByUserError()); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireCancel(); break; - case ReturnCode::CAN_INVALID: + case CardReturnCode::INVALID_CAN: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); Q_EMIT fireInvalidCan(); break; default: - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(returnCode))); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireError(); break; } diff --git a/src/core/states/StateEstablishPaceCan.h b/src/core/states/StateEstablishPaceCan.h index 151ca1a..504ba80 100644 --- a/src/core/states/StateEstablishPaceCan.h +++ b/src/core/states/StateEstablishPaceCan.h @@ -1,6 +1,6 @@ /*! * \brief Controller for the step that tries to establish a PACE - * connection using the card's Can. + * connection using the card's CAN. * * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG */ diff --git a/src/core/states/StateEstablishPacePin.cpp b/src/core/states/StateEstablishPacePin.cpp index efbca3c..0c8e05c 100644 --- a/src/core/states/StateEstablishPacePin.cpp +++ b/src/core/states/StateEstablishPacePin.cpp @@ -5,8 +5,8 @@ */ -#include "ReturnCodeUtil.h" #include "StateEstablishPacePin.h" + #include "context/AuthContext.h" @@ -24,7 +24,7 @@ void StateEstablishPacePin::run() Q_ASSERT(cardConnection); QByteArray certificateDescription, effectiveChat; - if (auto authContext = getContext().dynamicCast()) + if (auto authContext = getContext().objectCast()) { // if PACE is performed for authentication purposes, // the chat and certificate description need to be send @@ -32,12 +32,12 @@ void StateEstablishPacePin::run() // in other scenarios, e.g. for changing the PIN, the data // is not needed Q_ASSERT(authContext->getDidAuthenticateEac1()); - Q_ASSERT(authContext->getEffectiveChat()); + Q_ASSERT(!authContext->encodeEffectiveChat().isEmpty()); certificateDescription = authContext->getDidAuthenticateEac1()->getCertificateDescriptionAsBinary(); - effectiveChat = authContext->getEffectiveChat()->encode(); + effectiveChat = authContext->encodeEffectiveChat(); } - qDebug() << "Establish connection using Pin"; + qDebug() << "Establish connection using PIN"; mConnections += cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPacePin::onEstablishConnectionDone, PACE_PIN_ID::PACE_PIN, @@ -50,38 +50,38 @@ void StateEstablishPacePin::run() void StateEstablishPacePin::onUserCancelled() { - getContext()->setLastPaceResultAndRetryCounter(ReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); + getContext()->setLastPaceResultAndRetryCounter(CardReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); AbstractState::onUserCancelled(); } void StateEstablishPacePin::onEstablishConnectionDone(QSharedPointer pCommand) { - ReturnCode returnCode = pCommand->getReturnCode(); + CardReturnCode returnCode = pCommand->getReturnCode(); auto paceCommand = pCommand.staticCast(); getContext()->setPaceOutputData(paceCommand->getPaceOutput()); switch (returnCode) { - case ReturnCode::OK: + case CardReturnCode::OK: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); Q_EMIT fireSuccess(); break; - case ReturnCode::CANCELLATION_BY_USER: + case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setResult(Result::createCancelByUserError()); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireCancel(); break; - case ReturnCode::PIN_INVALID: + case CardReturnCode::INVALID_PIN: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); Q_EMIT fireInvalidPin(); break; default: - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(returnCode))); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireError(); break; } diff --git a/src/core/states/StateEstablishPacePuk.cpp b/src/core/states/StateEstablishPacePuk.cpp index b2fe24e..ee076d9 100644 --- a/src/core/states/StateEstablishPacePuk.cpp +++ b/src/core/states/StateEstablishPacePuk.cpp @@ -7,7 +7,7 @@ #include "StateEstablishPacePuk.h" -#include "ReturnCodeUtil.h" +#include "context/ChangePinContext.h" using namespace governikus; @@ -23,7 +23,7 @@ void StateEstablishPacePuk::run() auto cardConnection = getContext()->getCardConnection(); Q_ASSERT(cardConnection); - qDebug() << "Invoke unblock pin command"; + qDebug() << "Invoke unblock PIN command"; mConnections += cardConnection->callUnblockPinCommand(this, &StateEstablishPacePuk::onEstablishConnectionDone, getContext()->getPuk()); getContext()->setPuk(QString()); } @@ -31,40 +31,44 @@ void StateEstablishPacePuk::run() void StateEstablishPacePuk::onUserCancelled() { - getContext()->setLastPaceResultAndRetryCounter(ReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); + getContext()->setLastPaceResultAndRetryCounter(CardReturnCode::CANCELLATION_BY_USER, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); AbstractState::onUserCancelled(); } void StateEstablishPacePuk::onEstablishConnectionDone(QSharedPointer pCommand) { - ReturnCode returnCode = pCommand->getReturnCode(); + CardReturnCode returnCode = pCommand->getReturnCode(); switch (returnCode) { - case ReturnCode::OK: + case CardReturnCode::OK: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - getContext()->setSuccessMessage(tr("Pin successfully unblocked")); + if (auto changePinContext = getContext().objectCast()) + { + changePinContext->setSuccessMessage(tr("PIN successfully unblocked")); + } Q_EMIT fireSuccess(); break; - case ReturnCode::CANCELLATION_BY_USER: + case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setResult(Result::createCancelByUserError()); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireCancel(); break; - case ReturnCode::PUK_INVALID: + case CardReturnCode::INVALID_PUK: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); Q_EMIT fireInvalidPuk(); break; - case ReturnCode::PUK_INOPERATIVE: + case CardReturnCode::PUK_INOPERATIVE: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireInoperativePuk(); break; default: - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(returnCode))); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireError(); break; } diff --git a/src/core/states/StateEstablishPacePuk.h b/src/core/states/StateEstablishPacePuk.h index 731c5f4..1bdb974 100644 --- a/src/core/states/StateEstablishPacePuk.h +++ b/src/core/states/StateEstablishPacePuk.h @@ -1,6 +1,6 @@ /*! * \brief Controller for the step that tries to establish a PACE - * connection using the card's Puk. + * connection using the card's PUK. * * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG */ @@ -9,13 +9,11 @@ #include "AbstractGenericState.h" -#include "context/ChangePinContext.h" - namespace governikus { class StateEstablishPacePuk - : public AbstractGenericState + : public AbstractGenericState { Q_OBJECT friend class StateBuilder; diff --git a/src/core/states/StateExtractCvcsFromEac1IntputType.cpp b/src/core/states/StateExtractCvcsFromEac1IntputType.cpp index 09ab89d..821b624 100644 --- a/src/core/states/StateExtractCvcsFromEac1IntputType.cpp +++ b/src/core/states/StateExtractCvcsFromEac1IntputType.cpp @@ -26,7 +26,7 @@ void StateExtractCvcsFromEac1IntputType::run() if (foundTerminalCvc) { qCritical() << "More than one terminal certificate found in EAC1InputType"; - setResult(Result::createCertChainInterruptedError(tr("No unique AT CVC"))); + setStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); Q_EMIT fireError(); return; } @@ -38,7 +38,7 @@ void StateExtractCvcsFromEac1IntputType::run() if (foundDvCvc) { qCritical() << "More than one DV certificate found in EAC1InputType"; - setResult(Result::createCertChainInterruptedError(tr("No unique DV CVC"))); + setStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); Q_EMIT fireError(); return; } @@ -50,14 +50,14 @@ void StateExtractCvcsFromEac1IntputType::run() if (!foundTerminalCvc) { qCritical() << "No terminal certificate found in EAC1InputType"; - setResult(Result::createCertChainInterruptedError(tr("No unique AT CVC"))); + setStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); Q_EMIT fireError(); return; } if (!foundDvCvc) { qCritical() << "No DV certificate found in EAC1InputType"; - setResult(Result::createCertChainInterruptedError(tr("No unique DV CVC"))); + setStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); Q_EMIT fireError(); return; } diff --git a/src/core/states/StateGenericSendReceive.cpp b/src/core/states/StateGenericSendReceive.cpp index 5bbbbb2..f148473 100644 --- a/src/core/states/StateGenericSendReceive.cpp +++ b/src/core/states/StateGenericSendReceive.cpp @@ -92,24 +92,19 @@ void StateGenericSendReceive::setRemoteMessageId(QSharedPointer pPa } -void StateGenericSendReceive::reportChannelEstablishmentError(const QString& pMessage) +void StateGenericSendReceive::reportChannelEstablishmentError(const GlobalStatus::Code pStatusCode) { - qCCritical(network) << pMessage; - setResult(Result::createTrustedChannelEstablishmentError(pMessage)); + qCCritical(network) << GlobalStatus(pStatusCode); + setStatus(pStatusCode); Q_EMIT fireError(); } void StateGenericSendReceive::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(pErrors)) + if (TlsConfiguration::containsFatalError(mReply, pErrors)) { - reportChannelEstablishmentError(tr("Failed to establish secure connection")); - } - else - { - qCDebug(network) << "Ignore SSL errors on QNetworkReply"; - mReply->ignoreSslErrors(); + reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error); } } @@ -144,14 +139,21 @@ void StateGenericSendReceive::onPreSharedKeyAuthenticationRequired(QSslPreShared bool StateGenericSendReceive::checkAndSaveCertificate(const QSslCertificate& pCertificate) { - QString errorMsg = CertificateChecker::checkAndSaveCertificate(pCertificate, getContext()->getTcToken()->getServerAddress(), getContext()); - if (!errorMsg.isNull()) + switch (CertificateChecker::checkAndSaveCertificate(pCertificate, getContext()->getTcToken()->getServerAddress(), getContext())) { - reportChannelEstablishmentError(errorMsg); - return false; + case CertificateChecker::CertificateStatus::Good: + return true; + + case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: + reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length); + return false; + + case CertificateChecker::CertificateStatus::Hash_Not_In_Description: + reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description); + return false; } - return true; + return false; } @@ -163,9 +165,9 @@ void StateGenericSendReceive::run() setMessageId(messageToSend.dynamicCast()); if (QSharedPointer paosResponse = messageToSend.dynamicCast()) { - if (!getContext()->isErrorReportedToServer() && !getContext()->getResult().isOk() && !getContext()->getResult().isOriginServer()) + if (!getContext()->isErrorReportedToServer() && getContext()->getStatus().isError() && !getContext()->getStatus().isOriginServer()) { - paosResponse->setResult(getContext()->getResult()); + paosResponse->setResult(getContext()->getStatus()); getContext()->setErrorReportedToServer(true); } else @@ -199,7 +201,7 @@ void StateGenericSendReceive::onReplyFinished() if (reply->error() != QNetworkReply::NoError) { - reportChannelEstablishmentError(NetworkManager::getLocalizedErrorString(reply)); + reportChannelEstablishmentError(NetworkManager::toTrustedChannelStatus(reply)); return; } @@ -210,7 +212,7 @@ void StateGenericSendReceive::onReplyFinished() const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statusCode >= 500) { - reportChannelEstablishmentError(tr("The program received an error from the server.")); + reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server); return; } @@ -232,13 +234,13 @@ void StateGenericSendReceive::onReplyFinished() if (paosHandler.getDetectedPaosType() == PaosType::UNKNOWN) { qCCritical(network) << "The program received an unknown message from the server."; - setResult(Result::createInternalError(tr("The program received an unknown message from the server."))); + setStatus(GlobalStatus::Code::Workflow_Unknown_Paos_Form_EidServer); Q_EMIT fireError(); } else { qCCritical(network) << "The program received an unexpected message from the server."; - setResult(Result::createInternalError(tr("The program received an unexpected message from the server."))); + setStatus(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer); Q_EMIT fireError(); } return; diff --git a/src/core/states/StateGenericSendReceive.h b/src/core/states/StateGenericSendReceive.h index 5d41fb3..21237c3 100644 --- a/src/core/states/StateGenericSendReceive.h +++ b/src/core/states/StateGenericSendReceive.h @@ -29,7 +29,7 @@ class StateGenericSendReceive void setMessageId(QSharedPointer pPaosMessage); void setRemoteMessageId(QSharedPointer pPaosMessage); void setReceivedMessage(QSharedPointer pMessage); - void reportChannelEstablishmentError(const QString& pMessage); + void reportChannelEstablishmentError(const GlobalStatus::Code pStatusCode); bool checkAndSaveCertificate(const QSslCertificate& pCertificate); void onSslErrors(const QList& pErrors); void onSslHandshakeDone(); diff --git a/src/core/states/StateGetSelfAuthenticationData.cpp b/src/core/states/StateGetSelfAuthenticationData.cpp index ca58c28..bd3fbe5 100644 --- a/src/core/states/StateGetSelfAuthenticationData.cpp +++ b/src/core/states/StateGetSelfAuthenticationData.cpp @@ -7,6 +7,7 @@ #include "StateGetSelfAuthenticationData.h" #include "CertificateChecker.h" +#include "HttpStatusCode.h" #include "SelfAuthenticationData.h" #include "TlsConfiguration.h" @@ -44,10 +45,10 @@ void StateGetSelfAuthenticationData::run() } -void StateGetSelfAuthenticationData::reportCommunicationError(const QString& pMessage) +void StateGetSelfAuthenticationData::reportCommunicationError(const GlobalStatus& pStatus) { - qCritical() << pMessage; - setResult(Result::createCommunicationError(pMessage)); + qCritical() << pStatus; + setStatus(pStatus); mReply->abort(); Q_EMIT fireError(); } @@ -55,36 +56,50 @@ void StateGetSelfAuthenticationData::reportCommunicationError(const QString& pMe void StateGetSelfAuthenticationData::onSslHandshakeDone() { - const QSslConfiguration sslConfiguration = mReply->sslConfiguration(); - qDebug() << "Used session cipher" << sslConfiguration.sessionCipher(); - qDebug() << "Used session protocol:" << sslConfiguration.sessionProtocol(); - qDebug() << "Used server certificate:" << sslConfiguration.peerCertificate(); - qDebug() << "Used ephemeral server key:" << sslConfiguration.ephemeralServerKey(); - - QString errorMsg = CertificateChecker::checkAndSaveCertificate(sslConfiguration.peerCertificate(), getContext()->getRefreshUrl(), getContext()); - if (!errorMsg.isNull()) + if (!checkSslConnectionAndSaveCertificate(mReply->sslConfiguration())) { - reportCommunicationError(errorMsg); + // checkAndSaveCertificate already set the error + mReply->abort(); + } +} + + +bool StateGetSelfAuthenticationData::checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration) +{ + qDebug() << "Used session cipher" << pSslConfiguration.sessionCipher(); + qDebug() << "Used session protocol:" << pSslConfiguration.sessionProtocol(); + qDebug() << "Used server certificate:" << pSslConfiguration.peerCertificate(); + qDebug() << "Used ephemeral server key:" << pSslConfiguration.ephemeralServerKey(); + + switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), getContext()->getRefreshUrl(), getContext())) + { + case CertificateChecker::CertificateStatus::Good: + break; + + case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length)); + return false; + + case CertificateChecker::CertificateStatus::Hash_Not_In_Description: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description)); + return false; } - if (!CertificateChecker::hasValidEphemeralKeyLength(sslConfiguration.ephemeralServerKey())) + if (!CertificateChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) { - errorMsg = tr("Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length."); - reportCommunicationError(errorMsg); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length)); + return false; } + + return true; } void StateGetSelfAuthenticationData::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(pErrors)) + if (TlsConfiguration::containsFatalError(mReply, pErrors)) { - reportCommunicationError(tr("Failed to establish secure connection")); - } - else - { - qDebug() << "Ignore SSL errors on QNetworkReply"; - mReply->ignoreSslErrors(); + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Ssl_Establishment_Error)); } } @@ -94,7 +109,7 @@ void StateGetSelfAuthenticationData::onNetworkReply() int statusCode = mReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); qDebug() << statusCode; - if (statusCode == 200) + if (statusCode == HttpStatusCode::OK) { QSharedPointer data(new SelfAuthenticationData(mReply->readAll())); if (data->isValid()) @@ -105,14 +120,14 @@ void StateGetSelfAuthenticationData::onNetworkReply() else { qDebug() << "Could not read data for self authentication."; - setResult(Result::createCommunicationError(tr("The server provided no or incomplete information. Your personal data could not be read out."))); + setStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); Q_EMIT fireError(); } } else { qDebug() << "Could not read data for self authentication. StatusCode:" << statusCode; - setResult(Result::createCommunicationError(tr("The server provided no or incomplete information. Your personal data could not be read out."))); + setStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); Q_EMIT fireError(); } } diff --git a/src/core/states/StateGetSelfAuthenticationData.h b/src/core/states/StateGetSelfAuthenticationData.h index df39322..958e0ee 100644 --- a/src/core/states/StateGetSelfAuthenticationData.h +++ b/src/core/states/StateGetSelfAuthenticationData.h @@ -26,7 +26,8 @@ class StateGetSelfAuthenticationData StateGetSelfAuthenticationData(const QSharedPointer& pContext); virtual void run() override; - void reportCommunicationError(const QString& pMessage); + void reportCommunicationError(const GlobalStatus& pStatus); + bool checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration); public: ~StateGetSelfAuthenticationData(); diff --git a/src/core/states/StateGetTcToken.cpp b/src/core/states/StateGetTcToken.cpp index c1b462b..f94aab6 100644 --- a/src/core/states/StateGetTcToken.cpp +++ b/src/core/states/StateGetTcToken.cpp @@ -4,10 +4,10 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "CertificateChecker.h" -#include "ErrorMessage.h" -#include "NetworkManager.h" #include "StateGetTcToken.h" + +#include "CertificateChecker.h" +#include "NetworkManager.h" #include "TlsConfiguration.h" #include @@ -41,10 +41,12 @@ void StateGetTcToken::run() auto url = getContext()->getTcTokenUrl(); qDebug() << "Got TC Token URL:" << url; - if (isValidRedirectUrl(url)) + if (!isValidRedirectUrl(url)) { - sendRequest(url); + Q_EMIT fireError(); + return; } + sendRequest(url); } @@ -53,8 +55,7 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) if (pUrl.isEmpty()) { qCritical() << "Error while connecting to the service provider. The server returns an invalid or empty redirect URL."; - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::FORMAT_ERROR))); - Q_EMIT fireError(); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); return false; } else if (pUrl.scheme() != QLatin1String("https")) @@ -70,8 +71,7 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) { qCritical() << httpsError; getContext()->setTcTokenNotFound(false); - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::FORMAT_ERROR))); - Q_EMIT fireError(); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); return false; } } @@ -96,11 +96,7 @@ void StateGetTcToken::sendRequest(const QUrl& pUrl) void StateGetTcToken::onSslErrors(const QList& pErrors) { - if (!TlsConfiguration::containsFatalError(pErrors)) - { - qDebug() << "Ignore SSL errors on QNetworkReply"; - mReply->ignoreSslErrors(); - } + TlsConfiguration::containsFatalError(mReply, pErrors); } @@ -117,7 +113,7 @@ void StateGetTcToken::onSslHandshakeDone() { mReply->abort(); qCritical() << "Error while connecting to the service provider. The server's SSL certificate uses an unsupported key algorithm or length."; - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::SSL_ERROR))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); Q_EMIT fireError(); return; } @@ -126,7 +122,7 @@ void StateGetTcToken::onSslHandshakeDone() { mReply->abort(); qCritical() << "Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length."; - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::SSL_ERROR))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); Q_EMIT fireError(); return; } @@ -143,8 +139,8 @@ void StateGetTcToken::onNetworkReply() if (mReply->error() != QNetworkReply::NoError) { - qCritical() << NetworkManager::getLocalizedErrorString(mReply.data()); - setResult(Result::createTrustedChannelEstablishmentError(NetworkManager::getLocalizedErrorString(mReply.data()))); + qCritical() << NetworkManager::toStatus(mReply.data()); + setStatus(NetworkManager::toTrustedChannelStatus(mReply.data())); Q_EMIT fireError(); return; } @@ -152,17 +148,24 @@ void StateGetTcToken::onNetworkReply() if (statusCode == HttpStatusCode::OK) { parseTcToken(); + return; } - else if (isValidRedirectUrl(redirectUrl) && (statusCode == HttpStatusCode::SEE_OTHER || statusCode == HttpStatusCode::FOUND || statusCode == HttpStatusCode::TEMPORARY_REDIRECT)) + + if (!isValidRedirectUrl(redirectUrl)) { - sendRequest(redirectUrl); + Q_EMIT fireError(); + return; } - else + + if (statusCode != HttpStatusCode::SEE_OTHER && statusCode != HttpStatusCode::FOUND && statusCode != HttpStatusCode::TEMPORARY_REDIRECT) { qCritical() << "Error while connecting to the service provider. The server returns an unexpected status code:" << statusCode; - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::FORMAT_ERROR))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); Q_EMIT fireError(); + return; } + + sendRequest(redirectUrl); } @@ -174,7 +177,7 @@ void StateGetTcToken::parseTcToken() if (data.isEmpty()) { qDebug() << "Received no data."; - setResult(Result::createTrustedChannelEstablishmentError(tr("Received no data."))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received); Q_EMIT fireError(); return; } @@ -189,6 +192,6 @@ void StateGetTcToken::parseTcToken() } qCritical() << "TCToken invalid"; - setResult(Result::createTrustedChannelEstablishmentError(ErrorMessage::toString(ErrorMessageId::FORMAT_ERROR))); + setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); Q_EMIT fireError(); } diff --git a/src/core/states/StateParseTcTokenUrl.cpp b/src/core/states/StateParseTcTokenUrl.cpp index de82dc8..7b3be00 100644 --- a/src/core/states/StateParseTcTokenUrl.cpp +++ b/src/core/states/StateParseTcTokenUrl.cpp @@ -6,10 +6,11 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "ErrorMessage.h" -#include "Result.h" #include "StateParseTcTokenUrl.h" +#include "Result.h" + + #include using namespace governikus; @@ -40,7 +41,7 @@ void StateParseTcTokenUrl::run() qCritical() << "No parameter tcTokenURL"; } - setResult(Result::createCommunicationError(ErrorMessage::toString(ErrorMessageId::WRONG_PARAMETER_INVOCATION))); + setStatus(GlobalStatus::Code::Workflow_Wrong_Parameter_Invocation); Q_EMIT fireError(); } } diff --git a/src/core/states/StatePreVerification.cpp b/src/core/states/StatePreVerification.cpp index 6f25c85..20a9686 100644 --- a/src/core/states/StatePreVerification.cpp +++ b/src/core/states/StatePreVerification.cpp @@ -49,7 +49,7 @@ void StatePreVerification::run() if (certificateChain.isProductive()) { qCritical() << "Using the developer mode is only allowed in a test environment"; - setResult(Result::createCertChainInterruptedError(tr("Using the developer mode is only allowed in a test environment."))); + setStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); Q_EMIT fireError(); return; } @@ -65,21 +65,21 @@ void StatePreVerification::run() if (!certificateChain.isValid()) { qCritical() << "Pre-verification failed: cannot build certificate chain"; - setResult(Result::createCertChainInterruptedError(tr("Pre-verification failed."))); + setStatus(GlobalStatus::Code::Workflow_Preverification_Error); Q_EMIT fireError(); return; } else if (!SignatureChecker(certificateChain).check()) { qCritical() << "Pre-verification failed: signature check failed"; - setResult(Result::createCertChainInterruptedError(tr("Pre-verification failed."))); + setStatus(GlobalStatus::Code::Workflow_Preverification_Error); Q_EMIT fireError(); return; } else if (!isValid(certificateChain)) { qCritical() << "Pre-verification failed: certificate not valid "; - setResult(Result::createCertChainInterruptedError(tr("Pre-verification failed."))); + setStatus(GlobalStatus::Code::Workflow_Preverification_Error); Q_EMIT fireError(); return; } diff --git a/src/core/states/StatePrepareChat.cpp b/src/core/states/StatePrepareChat.cpp deleted file mode 100644 index 6d13062..0000000 --- a/src/core/states/StatePrepareChat.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "states/StatePrepareChat.h" - -using namespace governikus; - - -/** - * Performs sanity operations on a chat: - *
    - *
  • all access rights not contained in the corresponding CVC are removed
  • - *
  • all access rights not displayed are removed
  • - *
- */ -static QSharedPointer sanitizeChat(QSharedPointer pChatToSanitize, QSharedPointer pAuthContext, bool pIsRequiredChat) -{ - auto terminalCvc = pAuthContext->getTerminalCvc(); - - const auto notAllowedAccessRight = pChatToSanitize->getAccessRights() - terminalCvc->getBody().getCHAT().getAccessRights(); - const auto notDisplayedAccessRight = pChatToSanitize->getAccessRights() - AccessRoleAndRightsUtil::allDisplayedOrderedRights().toSet(); - - if (!notAllowedAccessRight.isEmpty()) - { - for (AccessRight accessRight : notAllowedAccessRight) - { - qWarning() << "Access right" << accessRight << "in" << (pIsRequiredChat ? "required" : "optional") << "chat but not in CVC!"; - pChatToSanitize->removeAccessRight(accessRight); - } - } - if (!notDisplayedAccessRight.isEmpty()) - { - for (AccessRight accessRight : notDisplayedAccessRight) - { - qWarning() << "Access right" << accessRight << "in" << (pIsRequiredChat ? "required" : "optional") << "chat but not displayed!"; - pChatToSanitize->removeAccessRight(accessRight); - } - } - QSharedPointer auxiliaryData = pAuthContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData(); - if (pChatToSanitize->hasAccessRight(AccessRight::AGE_VERIFICATION) && (!auxiliaryData || !auxiliaryData->hasAgeVerificationDate())) - { - qWarning() << "AGE_VERIFICATION requested, but no age specified"; - pChatToSanitize->removeAccessRight(AccessRight::AGE_VERIFICATION); - } - if (pChatToSanitize->hasAccessRight(AccessRight::COMMUNITY_ID_VERIFICATION) && (!auxiliaryData || !auxiliaryData->hasCommunityID())) - { - qWarning() << "COMMUNITY_ID_VERIFICATION requested, but no community id specified"; - pChatToSanitize->removeAccessRight(AccessRight::COMMUNITY_ID_VERIFICATION); - } - - return pChatToSanitize; -} - - -StatePrepareChat::StatePrepareChat(const QSharedPointer& pContext) - : AbstractGenericState(pContext, false) -{ -} - - -void StatePrepareChat::run() -{ - Q_ASSERT(getContext()->getDidAuthenticateEac1()); - Q_ASSERT(getContext()->getTerminalCvc()); - if (auto auxData = getContext()->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()) - { - getContext()->setRequiredAge(auxData->getRequiredAge()); - } - if (getContext()->getDidAuthenticateEac1()->getRequiredChat()) - { - QSharedPointer requiredChat(new CHAT(*getContext()->getDidAuthenticateEac1()->getRequiredChat().data())); - getContext()->setRequiredChat(sanitizeChat(requiredChat, getContext(), true)); - } - - const CHAT& terminalChat = getContext()->getTerminalCvc()->getBody().getCHAT(); - - if (getContext()->getDidAuthenticateEac1()->getOptionalChat()) - { - QSharedPointer optionalChat(new CHAT(*getContext()->getDidAuthenticateEac1()->getOptionalChat().data())); - - if (getContext()->getRequiredChat()) - { - const auto accessRights = getContext()->getRequiredChat()->getAccessRights(); - for (AccessRight requiredRight : accessRights) - { - optionalChat->removeAccessRight(requiredRight); - } - } - getContext()->setOptionalChat(sanitizeChat(optionalChat, getContext(), false)); - } - else if (!getContext()->getDidAuthenticateEac1()->getOptionalChat() && !getContext()->getDidAuthenticateEac1()->getRequiredChat()) - { - QSharedPointer optionalChat(new CHAT(terminalChat)); - getContext()->setOptionalChat(sanitizeChat(optionalChat, getContext(), false)); - } - - QSharedPointer effectiveChat(new CHAT(terminalChat)); - effectiveChat->removeAllAccessRights(); - if (getContext()->getRequiredChat()) - { - effectiveChat->setAccessRights(getContext()->getRequiredChat()->getAccessRights()); - } - if (getContext()->getOptionalChat()) - { - effectiveChat->setAccessRights(getContext()->getOptionalChat()->getAccessRights()); - } - getContext()->setEffectiveChat(effectiveChat); - - qDebug() << "Initially set effective chat to:" << getContext()->getEffectiveChat()->encode().toHex(); - Q_EMIT fireSuccess(); -} diff --git a/src/core/states/StatePrepareChat.h b/src/core/states/StatePrepareChat.h deleted file mode 100644 index 6c9fb22..0000000 --- a/src/core/states/StatePrepareChat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * StatePrepareChat.h - * - * - * \brief Determines the optional and required chat either from elements OptionalCHAT and RequiredCHAT in EAC1InputType or from CVC. - * Initially sets the effective chat to the required chat. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "states/AbstractGenericState.h" - - -namespace governikus -{ - -class StatePrepareChat - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - - StatePrepareChat(const QSharedPointer& pContext); - virtual void run() override; -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateProcessCertificatesFromEac2.cpp b/src/core/states/StateProcessCertificatesFromEac2.cpp index 19ce2e3..fa5d790 100644 --- a/src/core/states/StateProcessCertificatesFromEac2.cpp +++ b/src/core/states/StateProcessCertificatesFromEac2.cpp @@ -37,14 +37,14 @@ void StateProcessCertificatesFromEac2::run() qWarning() << "Ignoring AT CVC from EAC2InputType" << *cvc; continue; } - cvcs.append(cvc); + cvcs += cvc; } getContext()->initCvcChainBuilder(cvcs); if (!getContext()->hasChainForCertificationAuthority(*getContext()->getPaceOutputData())) { qCritical() << "No cvc chain determined, abort authentication"; - setResult(Result::createInternalError(tr("The authenticity of your ID card could not be confirmed."))); + setStatus(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity); Q_EMIT fireError(); } else diff --git a/src/core/states/StateProcessing.cpp b/src/core/states/StateProcessing.cpp index b49c0b3..28e131a 100644 --- a/src/core/states/StateProcessing.cpp +++ b/src/core/states/StateProcessing.cpp @@ -24,7 +24,7 @@ void StateProcessing::run() else { qCritical() << "Cannot send \"Processing\" to caller: " << activationContext->getSendError(); - setResult(Result::createCommunicationError(activationContext->getSendError())); + setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Processing_Error, activationContext->getSendError())); Q_EMIT fireError(); } } diff --git a/src/core/states/StateRedirectBrowser.cpp b/src/core/states/StateRedirectBrowser.cpp index 7715bc5..a8bcec5 100644 --- a/src/core/states/StateRedirectBrowser.cpp +++ b/src/core/states/StateRedirectBrowser.cpp @@ -4,8 +4,8 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "Result.h" #include "StateRedirectBrowser.h" + #include "UrlUtil.h" #include @@ -32,7 +32,7 @@ void StateRedirectBrowser::run() { reportCommunicationError(); } - else if (sendRedirect(getContext()->getRefreshUrl(), getContext()->getResult())) + else if (sendRedirect(getContext()->getRefreshUrl(), getContext()->getStatus())) { Q_EMIT fireSuccess(); } @@ -42,14 +42,14 @@ void StateRedirectBrowser::run() void StateRedirectBrowser::sendErrorPage(HttpStatusCode pStatus) { auto activationContext = getContext()->getActivationContext(); - if (activationContext->sendErrorPage(pStatus, getContext()->getResult())) + if (activationContext->sendErrorPage(pStatus, getContext()->getStatus())) { Q_EMIT fireSuccess(); } else { qCritical() << "Cannot send error page to caller: " << activationContext->getSendError(); - setResult(Result::createCommunicationError(activationContext->getSendError())); + setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Error_Page_Transmission_Error, activationContext->getSendError())); Q_EMIT fireError(); } } @@ -60,7 +60,7 @@ void StateRedirectBrowser::reportCommunicationError() qDebug() << "Report communication error"; if (getContext()->getTcToken() != nullptr && getContext()->getTcToken()->getCommunicationErrorAddress().isValid()) { - if (sendRedirect(getContext()->getTcToken()->getCommunicationErrorAddress(), Result::createCommunicationError())) + if (sendRedirect(getContext()->getTcToken()->getCommunicationErrorAddress(), GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url)) { Q_EMIT fireSuccess(); } @@ -72,17 +72,17 @@ void StateRedirectBrowser::reportCommunicationError() } -bool StateRedirectBrowser::sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) +bool StateRedirectBrowser::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) { auto activationContext = getContext()->getActivationContext(); - if (activationContext->sendRedirect(pRedirectAddress, pResult)) + if (activationContext->sendRedirect(pRedirectAddress, pStatus)) { return true; } else { qCritical() << "Cannot send redirect to caller: " << activationContext->getSendError(); - setResult(Result::createCommunicationError(activationContext->getSendError())); + setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Redirect_Transmission_Error, activationContext->getSendError())); Q_EMIT fireError(); return false; } diff --git a/src/core/states/StateRedirectBrowser.h b/src/core/states/StateRedirectBrowser.h index 8e2ca79..bb69872 100644 --- a/src/core/states/StateRedirectBrowser.h +++ b/src/core/states/StateRedirectBrowser.h @@ -25,7 +25,7 @@ class StateRedirectBrowser void reportCommunicationError(); void sendErrorPage(HttpStatusCode pStatus); - bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult); + bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus); virtual void run() override; }; diff --git a/src/core/states/StateSelectBluetoothReader.cpp b/src/core/states/StateSelectBluetoothReader.cpp index 75f1826..20f98e3 100644 --- a/src/core/states/StateSelectBluetoothReader.cpp +++ b/src/core/states/StateSelectBluetoothReader.cpp @@ -18,12 +18,44 @@ StateSelectBluetoothReader::StateSelectBluetoothReader(const QSharedPointergetReaderName().isEmpty()) + { + qDebug() << "Skipping scan because there is already a paired device:" << getContext()->getReaderName(); + return; + } + + qDebug() << "Start bluetooth scan"; + ReaderManager::getInstance().startScan(); + + return; + } } @@ -57,7 +89,7 @@ void StateSelectBluetoothReader::onReaderConnected() ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); if (!readerInfo.isValid()) { - setResult(Result::createCommunicationError(tr("The selected card reader cannot be accessed anymore."))); + setStatus(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible); Q_EMIT fireError(); } else if (readerInfo.isConnected()) @@ -66,3 +98,42 @@ void StateSelectBluetoothReader::onReaderConnected() Q_EMIT fireSuccess(); } } + + +void StateSelectBluetoothReader::onAbort() +{ + const auto& readerName = getContext()->getReaderName(); + if (!readerName.isEmpty()) + { + ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(readerName); + if (readerInfo.isValid() && readerInfo.isConnected()) + { + ReaderManager::getInstance().disconnectReader(readerInfo.getName()); + } + } + Q_EMIT fireAbort(); +} + + +void StateSelectBluetoothReader::onReaderDeviceError(DeviceError pDeviceError) +{ + if (pDeviceError != DeviceError::DEVICE_POWERED_OFF) + { + setStatus(DeviceErrorUtil::toGlobalStatus(pDeviceError)); + Q_EMIT fireError(); + } +} + + +void StateSelectBluetoothReader::onExit(QEvent* pEvent) +{ + AbstractGenericState::onExit(pEvent); + ReaderManager::getInstance().stopScan(); +} + + +void StateSelectBluetoothReader::onEntry(QEvent* pEvent) +{ + AbstractGenericState::onEntry(pEvent); + mConnections += connect(getContext().data(), &WorkflowContext::fireAbortCardSelection, this, &StateSelectBluetoothReader::onAbort); +} diff --git a/src/core/states/StateSelectBluetoothReader.h b/src/core/states/StateSelectBluetoothReader.h index 1c5e888..afb4079 100644 --- a/src/core/states/StateSelectBluetoothReader.h +++ b/src/core/states/StateSelectBluetoothReader.h @@ -5,6 +5,7 @@ #pragma once #include "AbstractGenericState.h" +#include "DeviceError.h" namespace governikus { @@ -18,9 +19,19 @@ class StateSelectBluetoothReader StateSelectBluetoothReader(const QSharedPointer& pContext); virtual void run() override; + void startScan(); + private Q_SLOTS: void onReaderDetected(); void onReaderConnected(); + void onAbort(); + void onReaderDeviceError(DeviceError pDeviceError); + + protected: + void onExit(QEvent* pEvent) override; + + public: + void onEntry(QEvent* pEvent) override; Q_SIGNALS: void fireAbort(); diff --git a/src/core/states/StateSelectReaderType.cpp b/src/core/states/StateSelectReaderType.cpp index e4c74f6..407008e 100644 --- a/src/core/states/StateSelectReaderType.cpp +++ b/src/core/states/StateSelectReaderType.cpp @@ -31,6 +31,8 @@ void StateSelectReaderType::run() void StateSelectReaderType::onReaderTypeChanged() { + getContext()->setReaderName(QString()); + switch (getContext()->getReaderType()) { case ReaderManagerPlugInType::BLUETOOTH: diff --git a/src/core/states/StateStartPaosResponse.cpp b/src/core/states/StateStartPaosResponse.cpp index e2b3d57..c0bc257 100644 --- a/src/core/states/StateStartPaosResponse.cpp +++ b/src/core/states/StateStartPaosResponse.cpp @@ -14,17 +14,18 @@ StateStartPaosResponse::StateStartPaosResponse(const QSharedPointergetStartPaosResponse()); - if (getContext()->getStartPaosResponse()->getResult().isOk()) + const QSharedPointer& startPaosResponse = getContext()->getStartPaosResponse(); + Q_ASSERT(startPaosResponse); + + const Result& result = startPaosResponse->getResult(); + if (result.isOk()) { Q_EMIT fireSuccess(); + return; } - else - { - // we override our result with the one sent from server - Result result = getContext()->getStartPaosResponse()->getResult(); - qDebug() << "Set server result to model:" << result.getMajorString() << result.getMinorString() << result.getMessage(); - getContext()->setResult(result); - Q_EMIT fireError(); - } + + qDebug() << "Processing server result:" << result.getMajorString() << result.getMinorString() << result.getMessage(); + setStatus(result.toStatus()); + Q_EMIT fireError(); + } diff --git a/src/core/states/StateTransmit.cpp b/src/core/states/StateTransmit.cpp index 1e927be..8a73871 100644 --- a/src/core/states/StateTransmit.cpp +++ b/src/core/states/StateTransmit.cpp @@ -32,22 +32,22 @@ void StateTransmit::onCardCommandDone(QSharedPointer pCommand) { auto transmitCommand = pCommand.staticCast(); auto returnCode = transmitCommand->getReturnCode(); - if (returnCode == ReturnCode::OK) + if (returnCode == CardReturnCode::OK) { QSharedPointer response(getContext()->getTransmitResponses().last()); response->setOutputApdus(transmitCommand->getOutputApduAsHex()); Q_EMIT fireSuccess(); } - else if (returnCode == ReturnCode::UNEXPECTED_TRANSMIT_STATUS) + else if (returnCode == CardReturnCode::UNEXPECTED_TRANSMIT_STATUS) { QSharedPointer response(getContext()->getTransmitResponses().last()); response->setOutputApdus(transmitCommand->getOutputApduAsHex()); - setResult(Result::createError(returnCode)); // set the result to the model so it is written to the PAOS response + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); // set the result to the model so it is written to the PAOS response Q_EMIT fireSuccess(); } else { - setResult(Result::createError(returnCode)); + setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireError(); } } diff --git a/src/core/states/StateUpdateRetryCounter.cpp b/src/core/states/StateUpdateRetryCounter.cpp index e348da7..e289173 100644 --- a/src/core/states/StateUpdateRetryCounter.cpp +++ b/src/core/states/StateUpdateRetryCounter.cpp @@ -8,8 +8,6 @@ #include "Result.h" #include "StateUpdateRetryCounter.h" -#include "ReturnCodeUtil.h" - using namespace governikus; @@ -33,29 +31,29 @@ void StateUpdateRetryCounter::onUpdateRetryCounterDone(QSharedPointergetReturnCode() != ReturnCode::OK) + if (pCommand->getReturnCode() != CardReturnCode::OK) { qCritical() << "An error occurred while communicating with the card reader, cannot determine retry counter, abort state"; - setResult(Result::createInternalError(ReturnCodeUtil::toMessage(pCommand->getReturnCode()))); + setStatus(CardReturnCodeUtil::toGlobalStatus(pCommand->getReturnCode())); Q_EMIT fireError(); return; } auto cardConnection = getContext()->getCardConnection(); - const int retryCounter = cardConnection->getReaderInfo().getRetryCounter(); - if (retryCounter == 0) + switch (cardConnection->getReaderInfo().getRetryCounter()) { - qDebug() << "Puk required"; - Q_EMIT fireRetryCounterIsZero(); - } - else if (retryCounter == 1) - { - qDebug() << "Can required"; - Q_EMIT fireRetryCounterIsOne(); - } - else - { - qDebug() << "Pin allowed"; - Q_EMIT fireRetryCounterIsGTOne(); + case 0: + qDebug() << "PUK required"; + Q_EMIT fireRetryCounterIsZero(); + break; + + case 1: + qDebug() << "CAN required"; + Q_EMIT fireRetryCounterIsOne(); + break; + + default: + qDebug() << "PIN allowed"; + Q_EMIT fireRetryCounterIsGTOne(); } } diff --git a/src/core/states/StateWriteHistory.cpp b/src/core/states/StateWriteHistory.cpp index e7be5c6..05929c9 100644 --- a/src/core/states/StateWriteHistory.cpp +++ b/src/core/states/StateWriteHistory.cpp @@ -25,16 +25,14 @@ void StateWriteHistory::run() return; } - if (getContext()->getDidAuthenticateEac1() == nullptr || getContext()->getEffectiveChat() == nullptr) + if (getContext()->getDidAuthenticateEac1() == nullptr || getContext()->getEffectiveAccessRights().isEmpty()) { qWarning() << "No EAC1 structure or effective CHAT in model."; Q_EMIT fireError(); return; } - if (getContext()->getResult().isOk() && - getContext()->getDidAuthenticateEac1() != nullptr && - getContext()->getEffectiveChat() != nullptr) + if (getContext()->getStatus().isNoError()) { if (auto certDesc = getContext()->getDidAuthenticateEac1()->getCertificateDescription()) { @@ -48,7 +46,7 @@ void StateWriteHistory::run() QString validity = tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate); QStringList requestedData; - const auto& rights = getContext()->getEffectiveChat()->getAccessRights(); + const auto& rights = getContext()->getEffectiveAccessRights(); for (const auto& entry : rights) { requestedData += AccessRoleAndRightsUtil::toDisplayText(entry); @@ -56,7 +54,7 @@ void StateWriteHistory::run() if (!subjectName.isNull() && !termOfUsage.isNull()) { - HistoryEntry entry(subjectName, subjectUrl, certDesc->getPurpose(), QDateTime::currentDateTime(), termOfUsage.append("\n\n").append(validity), requestedData.join(QStringLiteral(", "))); + HistoryEntry entry(subjectName, subjectUrl, certDesc->getPurpose(), QDateTime::currentDateTime(), termOfUsage + QStringLiteral("\n\n") + validity, requestedData.join(QStringLiteral(", "))); AppSettings::getInstance().getHistorySettings().addHistoryEntry(entry); AppSettings::getInstance().getHistorySettings().save(); } diff --git a/src/core/view/UIPlugIn.cpp b/src/core/view/UIPlugIn.cpp index 7bb01d9..58e3b23 100644 --- a/src/core/view/UIPlugIn.cpp +++ b/src/core/view/UIPlugIn.cpp @@ -28,8 +28,12 @@ void UIPlugIn::onShowUi(UiModule pModule) } +#ifndef QT_NO_NETWORKPROXY void UIPlugIn::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) { Q_UNUSED(pProxy) Q_UNUSED(pAuthenticator) } + + +#endif diff --git a/src/core/view/UIPlugIn.h b/src/core/view/UIPlugIn.h index 250fe65..7c32a8b 100644 --- a/src/core/view/UIPlugIn.h +++ b/src/core/view/UIPlugIn.h @@ -30,7 +30,9 @@ class UIPlugIn virtual void onWorkflowFinished(QSharedPointer pContext) = 0; virtual void onApplicationStarted(); virtual void onShowUi(UiModule pModule); +#ifndef QT_NO_NETWORKPROXY virtual void onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); +#endif Q_SIGNALS: void fireChangePinRequest(); diff --git a/src/export/CMakeLists.txt b/src/export/CMakeLists.txt new file mode 100644 index 0000000..9643abb --- /dev/null +++ b/src/export/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppExport) + +TARGET_LINK_LIBRARIES(AusweisAppExport Qt5::Svg Qt5::PrintSupport AusweisAppSettings) diff --git a/src/export/PdfCreator.cpp b/src/export/PdfCreator.cpp new file mode 100644 index 0000000..530b922 --- /dev/null +++ b/src/export/PdfCreator.cpp @@ -0,0 +1,236 @@ +/* + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "PdfCreator.h" + +#include "AppSettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace governikus; + + +bool PdfExport::exportHistory(const QString& pFileName) +{ + if (pFileName.isEmpty()) + { + return false; + } + + + PdfCreator pdf(pFileName); + + QDateTime dateTime = QDateTime::currentDateTime(); + QString date = dateTime.toString(tr("MM/dd/yyyy")); + QString time = dateTime.toString(tr("hh:mm AP")); + pdf.setHeadline(tr("At %1 %2 the following data were saved:").arg(date, time)); + + pdf.initTable(3, {180, 80}, {tr("Date"), tr("Details")}); + auto history = AppSettings::getInstance().getHistorySettings().getHistoryEntries(); + for (int i = 0; i < history.size(); ++i) + { + pdf.addTableRow({history.at(i).getDateTime().toString(tr("MM/dd/yyyy hh:mm AP")), tr("Provider:"), history.at(i).getSubjectName()}); + pdf.addTableRow({QString(), tr("Purpose:"), history.at(i).getPurpose()}); + pdf.addTableRow({QString(), tr("Data:"), history.at(i).getRequestedData()}); + pdf.toggleRowColor(); + } + + pdf.save(); + return QDesktopServices::openUrl(pdf.getFileUrl()); +} + + +void PdfCreator::closeTable() +{ + mContent += QLatin1String(""); + mColumnCount = 0; +} + + +PdfCreator::PdfCreator(const QString& pFilename) + : mFilename(pFilename) + , mColoredRow(false) + , mColumnCount(0) + , mHeadline() + , mContent() +{ + if (!mFilename.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) + { + mFilename += QLatin1String(".pdf"); + } +} + + +PdfCreator::~PdfCreator() +{ + +} + + +QUrl PdfCreator::getFileUrl() +{ + return QUrl(mFilename); +} + + +void PdfCreator::setHeadline(const QString& pHeadline) +{ + mHeadline = pHeadline; +} + + +void PdfCreator::initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues) +{ + if (!mColumnCount) + { + mColumnCount = pColumnCount; + mContent += QLatin1String(""\ + ""); + for (int i = 0; i < mColumnCount; ++i) + { + const auto& width = i < pWidth.size() ? QStringLiteral(" width='%1'").arg(pWidth[i]) : QString(); + const auto& value = i < pValues.size() && !pValues[i].isEmpty() ? pValues[i] : QLatin1String(" "); + mContent += QStringLiteral("").arg(width, value); + } + mContent += QLatin1String(""); + } +} + + +void PdfCreator::addTableRow(const QStringList& pValues) +{ + mContent += mColoredRow ? QLatin1String("") : QLatin1String(""); + for (int i = 0; i < mColumnCount; ++i) + { + const auto& value = i < pValues.size() && pValues[i] != "" ? pValues[i] : QLatin1String(" "); + mContent += QStringLiteral("").arg(value); + } + mContent += QLatin1String(""); +} + + +void PdfCreator::toggleRowColor() +{ + mColoredRow = !mColoredRow; +} + + +void PdfCreator::save() +{ + closeTable(); + + QPrinter printer; + printer.setOutputFileName(mFilename); + QRect printer_rect(printer.pageRect()); + + QString company_header; + company_header += QStringLiteral("

" + "
" + "%2" + "
%2
" + "" + "" + "" + "" + "" + "" + "" + "" + "
" + "

" + "%1 - %2" + "

" + "

" + "%3" + "

" + "" + "
" + "
" + "

" + "%4" + "

" + "
").arg( + tr("History"), + QApplication::applicationName(), + tr("AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior)."), + mHeadline); + + QString company_footer; + company_footer += QLatin1String("

") + % tr("For further information, please see https://www.ausweisapp.bund.de/") + % QLatin1String("

"); + + //Setting up the header and calculating the header size + QTextDocument document_header; + + QSvgRenderer renderer(QStringLiteral(":/images/npa.svg")); + QImage image(768, 768, QImage::Format_ARGB32); + image.fill(0x00FFFFFF); + QPainter imagePainter(&image); + renderer.render(&imagePainter); + document_header.addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("pdflogo")), image); + + document_header.setPageSize(printer_rect.size()); + document_header.setHtml(company_header); + QSizeF header_size = document_header.size(); + + //Setting up the footer and calculating the footer size + QTextDocument document_footer; + document_footer.setPageSize(printer_rect.size()); + document_footer.setHtml(company_footer); + QSizeF footer_size = document_footer.size(); + + //Calculating the main document size for one page + QSizeF center_size(printer_rect.width(), + (printer.pageRect().height() - header_size.toSize().height() - footer_size.toSize().height())); + + //Insert HTML in main document + QTextDocument main_doc; + main_doc.setHtml(mContent); + main_doc.setPageSize(center_size); + + //Setting up the rectangles for each section. + QRect headerRect = QRect(QPoint(0, 0), document_header.size().toSize()); + QRect footerRect = QRect(QPoint(0, 0), document_footer.size().toSize()); + QRect contentRect = QRect(QPoint(0, 0), main_doc.size().toSize()); // Main content rectangle. + QRect currentRect = QRect(QPoint(0, 0), center_size.toSize()); // Current main content rectangle. + + QPainter painter(&printer); + + while (currentRect.intersects(contentRect)) + { //Loop if the current content rectangle intersects with the main content rectangle. + //Resetting the painter matrix co-ordinate system. + painter.resetMatrix(); + //Applying negative translation of painter co-ordinate system by current main content rectangle top y coordinate. + painter.translate(0, -currentRect.y()); + //Applying positive translation of painter co-ordinate system by header hight. + painter.translate(0, headerRect.height()); + //Drawing the center content for current page. + main_doc.drawContents(&painter, currentRect); + //Resetting the painter matrix co ordinate system. + painter.resetMatrix(); + //Drawing the header on the top of the page + document_header.drawContents(&painter, headerRect); + //Applying positive translation of painter co-ordinate system to draw the footer + painter.translate(0, headerRect.height()); + painter.translate(0, center_size.height()); + document_footer.drawContents(&painter, footerRect); + + //Translating the current rectangle to the area to be printed for the next page + currentRect.translate(0, currentRect.height()); + //Inserting a new page if there is still area left to be printed + if (currentRect.intersects(contentRect)) + { + printer.newPage(); + } + } +} diff --git a/src/export/PdfCreator.h b/src/export/PdfCreator.h new file mode 100644 index 0000000..84b2ea4 --- /dev/null +++ b/src/export/PdfCreator.h @@ -0,0 +1,53 @@ +/*! + * \brief Tool to create PDF-Documents for history or selfauthentication result. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include + +namespace governikus +{ + +class PdfExport +{ + Q_DECLARE_TR_FUNCTIONS(governikus::PdfExport) + + public: + static bool exportHistory(const QString& pFileName); +}; + + +class PdfCreator +{ + Q_DECLARE_TR_FUNCTIONS(governikus::PdfCreator) + + private: + QString mFilename; + bool mColoredRow; + int mColumnCount; + QString mHeadline; + QString mContent; + + void closeTable(); + + public: + PdfCreator(const QString& pFilename); + virtual ~PdfCreator(); + + QUrl getFileUrl(); + + void setHeadline(const QString& pHeadline); + void initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues); + void addTableRow(const QStringList& pValues); + void toggleRowColor(); + void save(); + +}; + + +} /* namespace governikus */ diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index b9e344b..f1b1f85 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -5,28 +5,14 @@ ADD_LIBRARY(AusweisAppExternalHttpParser ${EXTERNAL_HTTP_PARSER_FILES}) TARGET_INCLUDE_DIRECTORIES(AusweisAppExternalHttpParser INTERFACE "$") IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wcovered-switch-default") - SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-covered-switch-default") + SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-covered-switch-default") +ENDIF() + +IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wconversion") + SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-conversion") ENDIF() IF(NOT MSVC) SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-gnu-statement-expression") ENDIF() -################################## qhttpserver -######################################################################### -FILE(GLOB_RECURSE EXTERNAL_QHTTPSERVER_FILES qhttpserver/*.cpp) -ADD_LIBRARY(AusweisAppExternalQHttpServer ${EXTERNAL_QHTTPSERVER_FILES}) - -TARGET_INCLUDE_DIRECTORIES(AusweisAppExternalQHttpServer INTERFACE "$") -TARGET_LINK_LIBRARIES(AusweisAppExternalQHttpServer Qt5::Network AusweisAppGlobal AusweisAppExternalHttpParser) - - -################################## fervor -######################################################################### -IF(DESKTOP) - FILE(GLOB_RECURSE EXTERNAL_FERVOR_FILES fervor/*.cpp) - - ADD_LIBRARY(AusweisAppExternalFervor ${EXTERNAL_FERVOR_FILES}) - TARGET_INCLUDE_DIRECTORIES(AusweisAppExternalFervor INTERFACE "$") - TARGET_LINK_LIBRARIES(AusweisAppExternalFervor Qt5::Network Qt5::Xml Qt5::Widgets AusweisAppNetwork AusweisAppSettings) -ENDIF() diff --git a/src/external/fervor/LICENSE b/src/external/fervor/LICENSE deleted file mode 100644 index d9c310d..0000000 --- a/src/external/fervor/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2012 Linas Valiukas and others. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/external/fervor/ReleaseNotesDownloader.cpp b/src/external/fervor/ReleaseNotesDownloader.cpp deleted file mode 100644 index 393d8a9..0000000 --- a/src/external/fervor/ReleaseNotesDownloader.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AppSettings.h" -#include "NetworkManager.h" -#include "ReleaseNotesDownloader.h" - -#include -#include - -using namespace governikus; - -ReleaseNotesDownloader::ReleaseNotesDownloader() - : QObject(), mEventLoop(), mEncrypted(false), mReleaseNotes(tr("

Download of release notes failed

")), mReply() -{ -} - -ReleaseNotesDownloader::~ReleaseNotesDownloader() -{ -} - -void ReleaseNotesDownloader::checkCertificate(const QSslCertificate& pPeerCert) -{ - - QSslConfiguration sslConfiguration = mReply->sslConfiguration(); - qDebug() << "Used session cipher" << sslConfiguration.sessionCipher(); - qDebug() << "Used session protocol:" << sslConfiguration.sessionProtocol(); - - if (AppSettings::getInstance().getSecureStorage().getUpdateCertificates().contains(pPeerCert)) - { - qDebug() << "Found trusted certificate for release notes:" << pPeerCert; - mEncrypted = true; - } - else - { - qDebug() << "No trusted certificate found for release notes:" << pPeerCert; - mReply->abort(); - mEventLoop.quit(); - } -} - -void ReleaseNotesDownloader::encrypted() -{ - const QSslCertificate peerCert = mReply->sslConfiguration().peerCertificate(); - if (!peerCert.isNull()) - { - checkCertificate(peerCert); - } -} - -void ReleaseNotesDownloader::finished() -{ - if (!mEncrypted) - { - checkCertificate(mReply->sslConfiguration().peerCertificate()); - } - - if (mEncrypted) - { - QVariant possibleRedirectUrl = mReply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (possibleRedirectUrl.toUrl().isEmpty()) - { - mReleaseNotes = QString::fromUtf8(mReply->readAll()); - mEventLoop.quit(); - } - else - { - qDebug() << "redirect: " << possibleRedirectUrl.toUrl(); - QNetworkRequest request(possibleRedirectUrl.toUrl()); - mReply.reset(NetworkManager::getGlobalInstance().get(request)); - } - } -} - -void ReleaseNotesDownloader::sslErrors(const QList& pErrors) -{ - for (const QSslError& error : pErrors) - { - mReleaseNotes.append(error.errorString()); - mReleaseNotes.append("
"); - qCritical() << "Cannot check for release notes:" << error; - } -} - -QString ReleaseNotesDownloader::loadReleaseNotes(const QUrl& pUrl) -{ - qDebug() << "Download release notes:" << pUrl; - QNetworkRequest request(pUrl); - mReply.reset(NetworkManager::getGlobalInstance().get(request)); - - connect(mReply.data(), &QNetworkReply::finished, this, &ReleaseNotesDownloader::finished); - connect(mReply.data(), &QNetworkReply::sslErrors, this, &ReleaseNotesDownloader::sslErrors); - connect(mReply.data(), &QNetworkReply::encrypted, this, &ReleaseNotesDownloader::encrypted); - - mEventLoop.exec(); - return mReleaseNotes; -} diff --git a/src/external/fervor/ReleaseNotesDownloader.h b/src/external/fervor/ReleaseNotesDownloader.h deleted file mode 100644 index cf1b1c6..0000000 --- a/src/external/fervor/ReleaseNotesDownloader.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * \brief Helper to download release notes - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include -#include -#include - - -namespace governikus -{ - -class ReleaseNotesDownloader : public QObject -{ - Q_OBJECT - - private: - QEventLoop mEventLoop; - bool mEncrypted; - QString mReleaseNotes; - QScopedPointer mReply; - - void checkCertificate(const QSslCertificate& pPeerCert); - - private Q_SLOTS: - void encrypted(); - void finished(); - void sslErrors(const QList& pErrors); - - public: - ReleaseNotesDownloader(); - virtual ~ReleaseNotesDownloader(); - - QString loadReleaseNotes(const QUrl& pUrl); -}; - -} /* namespace governikus */ diff --git a/src/external/fervor/fvavailableupdate.cpp b/src/external/fervor/fvavailableupdate.cpp deleted file mode 100644 index 62c5e57..0000000 --- a/src/external/fervor/fvavailableupdate.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "fvavailableupdate.h" - -FvAvailableUpdate::FvAvailableUpdate(QObject *pParent) - : QObject(pParent) - , m_title() - , m_releaseNotesLink() - , m_releaseNotes() - , m_pubDate() - , m_enclosureUrl() - , m_enclosureVersion() - , m_enclosurePlatform() - , m_enclosureLength(0) - , m_enclosureType() -{ - // noop -} - -QString FvAvailableUpdate::GetTitle() -{ - return m_title; -} - -void FvAvailableUpdate::SetTitle(const QString& title) -{ - m_title = title; -} - -QUrl FvAvailableUpdate::GetReleaseNotesLink() -{ - return m_releaseNotesLink; -} - -void FvAvailableUpdate::SetReleaseNotesLink(const QUrl& releaseNotesLink) -{ - m_releaseNotesLink = releaseNotesLink; -} - -void FvAvailableUpdate::SetReleaseNotesLink(const QString& releaseNotesLink) -{ - SetReleaseNotesLink(QUrl(releaseNotesLink)); -} - -QString FvAvailableUpdate::GetReleaseNotes() -{ - return m_releaseNotes; -} - -void FvAvailableUpdate::SetReleaseNotes(const QString &releaseNotes) -{ - m_releaseNotes = releaseNotes; -} - -QString FvAvailableUpdate::GetPubDate() -{ - return m_pubDate; -} - -void FvAvailableUpdate::SetPubDate(const QString& pubDate) -{ - m_pubDate = pubDate; -} - -QUrl FvAvailableUpdate::GetEnclosureUrl() -{ - return m_enclosureUrl; -} - -void FvAvailableUpdate::SetEnclosureUrl(const QUrl& enclosureUrl) -{ - m_enclosureUrl = enclosureUrl; -} - -void FvAvailableUpdate::SetEnclosureUrl(const QString& enclosureUrl) -{ - SetEnclosureUrl(QUrl(enclosureUrl)); -} - -QString FvAvailableUpdate::GetEnclosureVersion() -{ - return m_enclosureVersion; -} - -void FvAvailableUpdate::SetEnclosureVersion(const QString& enclosureVersion) -{ - m_enclosureVersion = enclosureVersion; -} - -QString FvAvailableUpdate::GetEnclosurePlatform() -{ - return m_enclosurePlatform; -} - -void FvAvailableUpdate::SetEnclosurePlatform(const QString& enclosurePlatform) -{ - m_enclosurePlatform = enclosurePlatform; -} - -unsigned long FvAvailableUpdate::GetEnclosureLength() -{ - return m_enclosureLength; -} - -void FvAvailableUpdate::SetEnclosureLength(unsigned long enclosureLength) -{ - m_enclosureLength = enclosureLength; -} - -QString FvAvailableUpdate::GetEnclosureType() -{ - return m_enclosureType; -} - -void FvAvailableUpdate::SetEnclosureType(const QString& enclosureType) -{ - m_enclosureType = enclosureType; -} diff --git a/src/external/fervor/fvavailableupdate.h b/src/external/fervor/fvavailableupdate.h deleted file mode 100644 index a0f2e62..0000000 --- a/src/external/fervor/fvavailableupdate.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef FVAVAILABLEUPDATE_H -#define FVAVAILABLEUPDATE_H - -#include -#include - -class FvAvailableUpdate : public QObject -{ - Q_OBJECT -public: - explicit FvAvailableUpdate(QObject *pParent = nullptr); - - QString GetTitle(); - void SetTitle(const QString& title); - - QUrl GetReleaseNotesLink(); - void SetReleaseNotesLink(const QUrl& releaseNotesLink); - void SetReleaseNotesLink(const QString& releaseNotesLink); - - QString GetReleaseNotes(); - void SetReleaseNotes(const QString& releaseNotes); - - QString GetPubDate(); - void SetPubDate(const QString& pubDate); - - QUrl GetEnclosureUrl(); - void SetEnclosureUrl(const QUrl& enclosureUrl); - void SetEnclosureUrl(const QString& enclosureUrl); - - QString GetEnclosureVersion(); - void SetEnclosureVersion(const QString& enclosureVersion); - - QString GetEnclosurePlatform(); - void SetEnclosurePlatform(const QString& enclosurePlatform); - - unsigned long GetEnclosureLength(); - void SetEnclosureLength(unsigned long enclosureLength); - - QString GetEnclosureType(); - void SetEnclosureType(const QString& enclosureType); - -private: - QString m_title; - QUrl m_releaseNotesLink; - QString m_releaseNotes; - QString m_pubDate; - QUrl m_enclosureUrl; - QString m_enclosureVersion; - QString m_enclosurePlatform; - unsigned long m_enclosureLength; - QString m_enclosureType; - -}; - -#endif // FVAVAILABLEUPDATE_H diff --git a/src/external/fervor/fvignoredversions.cpp b/src/external/fervor/fvignoredversions.cpp deleted file mode 100644 index 23a2e07..0000000 --- a/src/external/fervor/fvignoredversions.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "fvignoredversions.h" -#include "fvversioncomparator.h" -#include -#include -#include - -// QSettings key for the latest skipped version -#define FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY "FVLatestSkippedVersion" - - -FVIgnoredVersions::FVIgnoredVersions(QObject *pParent) : - QObject(pParent) -{ - // noop -} - -bool FVIgnoredVersions::VersionIsIgnored(const QString& version) -{ - // We assume that variable 'version' contains either: - // 1) The current version of the application (ignore) - // 2) The version that was skipped before and thus stored in QSettings (ignore) - // 3) A newer version (don't ignore) - // 'version' is not likely to contain an older version in any case. - -// if (version == FV_APP_VERSION) { -// return true; -// } - - QSettings settings(QSettings::NativeFormat, - QSettings::UserScope, - QApplication::organizationName(), - QApplication::applicationName()); - - if (settings.contains(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY)) { - QString lastSkippedVersion = settings.value(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY).toString(); - if (version == lastSkippedVersion) { - // Implicitly skipped version - skip - return true; - } - } - - std::string currentAppVersion = QApplication::applicationVersion().toStdString(); - std::string suggestedVersion = version.toStdString(); - if (FvVersionComparator::CompareVersions(currentAppVersion, suggestedVersion) == FvVersionComparator::kAscending) { - // Newer version - do not skip - return false; - } - - // Fallback - skip - return true; -} - -void FVIgnoredVersions::IgnoreVersion(const QString& version) -{ - if (version == QApplication::applicationVersion()) { - // Don't ignore the current version - return; - } - - if (version.isEmpty()) { - return; - } - - QSettings settings(QSettings::NativeFormat, - QSettings::UserScope, - QApplication::organizationName(), - QApplication::applicationName()); - - settings.setValue(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY, version); - - return; -} diff --git a/src/external/fervor/fvignoredversions.h b/src/external/fervor/fvignoredversions.h deleted file mode 100644 index 60e7894..0000000 --- a/src/external/fervor/fvignoredversions.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FVIGNOREDVERSIONS_H -#define FVIGNOREDVERSIONS_H - -#include - -class FVIgnoredVersions : public QObject -{ - Q_OBJECT - -public: - static bool VersionIsIgnored(const QString& version); - static void IgnoreVersion(const QString& version); - -private: - explicit FVIgnoredVersions(QObject *pParent = nullptr); - -}; - -#endif // FVIGNOREDVERSIONS_H diff --git a/src/external/fervor/fvplatform.cpp b/src/external/fervor/fvplatform.cpp deleted file mode 100644 index 21dee5b..0000000 --- a/src/external/fervor/fvplatform.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "fvplatform.h" -#include -#include - -FvPlatform::FvPlatform(QObject *pParent) : - QObject(pParent) -{ - // noop -} - -bool FvPlatform::CurrentlyRunningOnPlatform(QString platform) -{ - platform = platform.toUpper().trimmed(); - if (platform.isEmpty()) { - return false; - } - - // Defined on AIX. -#ifdef Q_OS_AIX - if (platform == "Q_OS_AIX") { - return true; - } -#endif - - // Q_OS_BSD4 ("Defined on Any BSD 4.4 system") intentionally skipped. - - // Defined on BSD/OS. -#ifdef Q_OS_BSDI - if (platform == "Q_OS_BSDI") { - return true; - } -#endif - - // Defined on Cygwin. -#ifdef Q_OS_CYGWIN - if (platform == "Q_OS_CYGWIN") { - return true; - } -#endif - - // Q_OS_DARWIN ("Defined on Darwin OS (synonym for Q_OS_MAC)") intentionally skipped. - - // Defined on DG/UX. -#ifdef Q_OS_DGUX - if (platform == "Q_OS_DGUX") { - return true; - } -#endif - - // Defined on DYNIX/ptx. -#ifdef Q_OS_DYNIX - if (platform == "Q_OS_DYNIX") { - return true; - } -#endif - - // Defined on FreeBSD. -#ifdef Q_OS_FREEBSD - if (platform == "Q_OS_FREEBSD") { - return true; - } -#endif - - // Defined on HP-UX. -#ifdef Q_OS_HPUX - if (platform == "Q_OS_HPUX") { - return true; - } -#endif - - // Defined on GNU Hurd. -#ifdef Q_OS_HURD - if (platform == "Q_OS_HURD") { - return true; - } -#endif - - // Defined on SGI Irix. -#ifdef Q_OS_IRIX - if (platform == "Q_OS_IRIX") { - return true; - } -#endif - - // Defined on Linux. -#ifdef Q_OS_LINUX - if (platform == QLatin1String("Q_OS_LINUX")) { - return true; - } -#endif - - // Defined on LynxOS. -#ifdef Q_OS_LYNX - if (platform == "Q_OS_LYNX") { - return true; - } -#endif - - // Defined on MAC OS (synonym for Darwin). -#ifdef Q_OS_MAC - if (platform == "Q_OS_MAC") { - return true; - } -#endif - - // Q_OS_MSDOS ("Defined on MS-DOS and Windows") intentionally skipped. - - // Defined on NetBSD. -#ifdef Q_OS_NETBSD - if (platform == "Q_OS_NETBSD") { - return true; - } -#endif - - // Defined on OS/2. -#ifdef Q_OS_OS2 - if (platform == "Q_OS_OS2") { - return true; - } -#endif - - // Defined on OpenBSD. -#ifdef Q_OS_OPENBSD - if (platform == "Q_OS_OPENBSD") { - return true; - } -#endif - - // Defined on XFree86 on OS/2 (not PM). -#ifdef Q_OS_OS2EMX - if (platform == "Q_OS_OS2EMX") { - return true; - } -#endif - - // Defined on HP Tru64 UNIX. -#ifdef Q_OS_OSF - if (platform == "Q_OS_OSF") { - return true; - } -#endif - - // Defined on QNX Neutrino. -#ifdef Q_OS_QNX - if (platform == "Q_OS_QNX") { - return true; - } -#endif - - // Defined on Reliant UNIX. -#ifdef Q_OS_RELIANT - if (platform == "Q_OS_RELIANT") { - return true; - } -#endif - - // Defined on SCO OpenServer 5. -#ifdef Q_OS_SCO - if (platform == "Q_OS_SCO") { - return true; - } -#endif - - // Defined on Sun Solaris. -#ifdef Q_OS_SOLARIS - if (platform == "Q_OS_SOLARIS") { - return true; - } -#endif - - // Defined on Symbian. -#ifdef Q_OS_SYMBIAN - if (platform == "Q_OS_SYMBIAN") { - return true; - } -#endif - - // Defined on DEC Ultrix. -#ifdef Q_OS_ULTRIX - if (platform == "Q_OS_ULTRIX") { - return true; - } -#endif - - // Q_OS_UNIX ("Defined on Any UNIX BSD/SYSV system") intentionally skipped. - - // Defined on UnixWare 7, Open UNIX 8. -#ifdef Q_OS_UNIXWARE - if (platform == "Q_OS_UNIXWARE") { - return true; - } -#endif - - // Defined on Windows CE (note: goes before Q_OS_WIN32) -#ifdef Q_OS_WINCE - if (platform == "Q_OS_WINCE") { - return true; - } -#endif - - // Defined on all supported versions of Windows. -#ifdef Q_OS_WIN -#if defined(WIN64) - if (platform == "Q_OS_WIN64") { - return true; - } -#else - if (platform == "Q_OS_WIN32") { - return true; - } -#endif -#endif - - // Fallback - return false; -} diff --git a/src/external/fervor/fvplatform.h b/src/external/fervor/fvplatform.h deleted file mode 100644 index f71857f..0000000 --- a/src/external/fervor/fvplatform.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FVPLATFORM_H -#define FVPLATFORM_H - -#include - -class FvPlatform : public QObject -{ - Q_OBJECT - -public: - static bool CurrentlyRunningOnPlatform(QString platform); - -private: - explicit FvPlatform(QObject *parent = nullptr); - -}; - -#endif // FVPLATFORM_H diff --git a/src/external/fervor/fvupdater.cpp b/src/external/fervor/fvupdater.cpp deleted file mode 100644 index 31e9b31..0000000 --- a/src/external/fervor/fvupdater.cpp +++ /dev/null @@ -1,589 +0,0 @@ -#include "fvupdater.h" -#include "fvupdatewindow.h" -#include "fvplatform.h" -#include "fvignoredversions.h" -#include "fvavailableupdate.h" - -#include "AppSettings.h" -#include "NetworkManager.h" -#include "ReleaseNotesDownloader.h" - -#include -#include -#include -#include -#include -#include - - -#ifdef FV_DEBUG - // Unit tests -# include "fvversioncomparatortest.h" -#endif - -using governikus::NetworkManager; -using governikus::AppSettings; - -FvUpdater* FvUpdater::m_Instance = nullptr; -bool FvUpdater::DisableSilentCheck = false; - -FvUpdater* FvUpdater::sharedUpdater() -{ - static QMutex mutex; - if (! m_Instance) { - mutex.lock(); - - if (! m_Instance) { - m_Instance = new FvUpdater; - } - - mutex.unlock(); - } - - return m_Instance; -} - -void FvUpdater::drop() -{ - static QMutex mutex; - mutex.lock(); - delete m_Instance; - m_Instance = nullptr; - mutex.unlock(); -} - -FvUpdater::FvUpdater() - : QObject(nullptr) - , m_updaterWindow(nullptr) - , m_proposedUpdate(nullptr) - , m_silentAsMuchAsItCouldGet(false) - , m_feedURL() - , m_reply(nullptr) - , m_encrypted(false) - , m_httpRequestAborted(false) - , m_securityError(false) - , m_xml() -{ -#ifdef FV_DEBUG - // Unit tests - FvVersionComparatorTest* test = new FvVersionComparatorTest(); - test->runAll(); - delete test; -#endif - -} - -FvUpdater::~FvUpdater() -{ - if (m_proposedUpdate) { - delete m_proposedUpdate; - m_proposedUpdate = nullptr; - } - - hideUpdaterWindow(); -} - -void FvUpdater::showUpdaterWindowUpdatedWithCurrentUpdateProposal() -{ - // Destroy window if already exists - hideUpdaterWindow(); - - // Create a new window - m_updaterWindow = new FvUpdateWindow(); - m_updaterWindow->UpdateWindowWithCurrentProposedUpdate(); - m_updaterWindow->show(); -} - -void FvUpdater::hideUpdaterWindow() -{ - if (m_updaterWindow) { - if (! m_updaterWindow->close()) { - qWarning() << "Update window didn't close, leaking memory from now on"; - } - - // not deleting because of Qt::WA_DeleteOnClose - - m_updaterWindow = nullptr; - } -} - -void FvUpdater::updaterWindowWasClosed() -{ - // (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time. - m_updaterWindow = nullptr; -} - - -void FvUpdater::SetFeedURL(const QUrl& feedURL) -{ - m_feedURL = feedURL; -} - - -FvAvailableUpdate* FvUpdater::GetProposedUpdate() -{ - return m_proposedUpdate; -} - - -void FvUpdater::InstallUpdate() -{ - qDebug() << "Install update"; - - FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); - if (! proposedUpdate) { - qWarning() << "Proposed update is NULL (shouldn't be at this point)"; - return; - } - - // Open a link - if (! QDesktopServices::openUrl(proposedUpdate->GetEnclosureUrl())) { - showErrorDialog(tr("Unable to open this link in a browser. Please copy and paste the link into the address bar of your browser."), CRITICAL_MESSAGE); - return; - } - - hideUpdaterWindow(); -} - -void FvUpdater::SkipUpdate() -{ - qDebug() << "Skip update"; - - FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); - if (! proposedUpdate) { - qWarning() << "Proposed update is NULL (shouldn't be at this point)"; - return; - } - - // Start ignoring this particular version - FVIgnoredVersions::IgnoreVersion(proposedUpdate->GetEnclosureVersion()); - - hideUpdaterWindow(); -} - -void FvUpdater::RemindMeLater() -{ - qDebug() << "Remind me later"; - - hideUpdaterWindow(); -} - - -bool FvUpdater::CheckForUpdates(bool silentAsMuchAsItCouldGet) -{ - if (m_feedURL.isEmpty()) { - qCritical() << "Please set feed URL via setFeedURL() before calling CheckForUpdates()."; - return false; - } - - m_silentAsMuchAsItCouldGet = silentAsMuchAsItCouldGet; - - // Check if application's organization name and domain are set, fail otherwise - // (nowhere to store QSettings to) - if (QApplication::organizationName().isEmpty()) { - qCritical() << "QApplication::organizationName is not set. Please do that."; - return false; - } - if (QApplication::organizationDomain().isEmpty()) { - qCritical() << "QApplication::organizationDomain is not set. Please do that."; - return false; - } - - cancelDownloadFeed(); - m_httpRequestAborted = false; - startDownloadFeed(m_feedURL); - - return true; -} - -bool FvUpdater::CheckForUpdatesSilent() -{ - if (!DisableSilentCheck) - return CheckForUpdates(true); - - return false; -} - -bool FvUpdater::CheckForUpdatesNotSilent() -{ - return CheckForUpdates(false); -} - - -void FvUpdater::startDownloadFeed(const QUrl& url) -{ - m_xml.clear(); - - QNetworkRequest request(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml"); - - m_reply = governikus::NetworkManager::getGlobalInstance().get(request); - connect(m_reply, &QNetworkReply::readyRead, this, &FvUpdater::httpFeedReadyRead); - connect(m_reply, &QNetworkReply::downloadProgress, this, &FvUpdater::httpFeedUpdateDataReadProgress); - connect(m_reply, &QNetworkReply::finished, this, &FvUpdater::httpFeedDownloadFinished); - connect(m_reply, &QNetworkReply::sslErrors, this, &FvUpdater::httpFeedSslErrors); - connect(m_reply, &QNetworkReply::encrypted, this, &FvUpdater::httpFeedSslEncrypted); -} - -void FvUpdater::httpFeedSslErrors(const QList& pErrors) -{ - for (const QSslError& error : pErrors) - { - qWarning() << "(ignored)" << error.errorString(); - } - m_reply->ignoreSslErrors(); -} - -void FvUpdater::cancelDownloadFeed() -{ - if (m_reply) { - m_httpRequestAborted = true; - m_reply->abort(); - } -} - -void FvUpdater::httpFeedSslCheckPeerCert(const QSslCertificate& pPeerCert) -{ - if (AppSettings::getInstance().getSecureStorage().getUpdateCertificates().contains(pPeerCert)) - { - qDebug() << "Found trusted update certificate:" << pPeerCert; - m_encrypted = true; - } - else - { - qDebug() << "No trusted update certificate found:" << pPeerCert; - m_securityError = true; - m_reply->abort(); - } -} - -void FvUpdater::httpFeedSslEncrypted() -{ - QSslConfiguration sslConfiguration = m_reply->sslConfiguration(); - qDebug() << "Used session cipher" << sslConfiguration.sessionCipher(); - qDebug() << "Used session protocol:" << sslConfiguration.sessionProtocol(); - - const QSslCertificate peerCert = m_reply->sslConfiguration().peerCertificate(); - if (!peerCert.isNull()) - { - httpFeedSslCheckPeerCert(peerCert); - } -} - -void FvUpdater::httpFeedReadyRead() -{ - if (!m_encrypted) - { - const QSslCertificate peerCert = m_reply->sslConfiguration().peerCertificate(); - httpFeedSslCheckPeerCert(peerCert); - } - - // this slot gets called every time the QNetworkReply has new data. - // We read all of its new data and write it into the file. - // That way we use less RAM than when reading it at the finished() - // signal of the QNetworkReply - if (m_encrypted) - { - m_xml.addData(m_reply->readAll()); - } -} - -void FvUpdater::httpFeedUpdateDataReadProgress(qint64 bytesRead, - qint64 totalBytes) -{ - Q_UNUSED(bytesRead); - Q_UNUSED(totalBytes); - - if (m_httpRequestAborted) { - return; - } -} - -void FvUpdater::httpFeedDownloadFinished() -{ - if (m_httpRequestAborted) { - m_reply->deleteLater(); - return; - } - - QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (m_reply->error()) { - // Error. - showErrorDialog(tr("An error occurred. Please contact our support at AusweisApp2 Support."), CRITICAL_MESSAGE); - - } else if (! redirectionTarget.isNull()) { - QUrl newUrl = m_feedURL.resolved(redirectionTarget.toUrl()); - - m_feedURL = newUrl; - m_reply->deleteLater(); - - startDownloadFeed(m_feedURL); - return; - - } else { - - // Done. - xmlParseFeed(); - - } - - m_reply->deleteLater(); - m_reply = nullptr; -} - -bool FvUpdater::xmlParseFeed() -{ - QString currentTag, currentQualifiedTag; - - QString xmlTitle, xmlLink, xmlReleaseNotesLink, xmlPubDate, xmlEnclosureUrl, - xmlEnclosureVersion, xmlEnclosurePlatform, xmlEnclosureType; - unsigned long xmlEnclosureLength = 0; - - // Parse - while (! m_xml.atEnd()) { - - m_xml.readNext(); - - if (m_xml.isStartElement()) { - - currentTag = m_xml.name().toString(); - currentQualifiedTag = m_xml.qualifiedName().toString(); - - if (m_xml.name() == "item") { - - xmlTitle.clear(); - xmlLink.clear(); - xmlReleaseNotesLink.clear(); - xmlPubDate.clear(); - xmlEnclosureUrl.clear(); - xmlEnclosureVersion.clear(); - xmlEnclosurePlatform.clear(); - xmlEnclosureLength = 0; - xmlEnclosureType.clear(); - - } else if (m_xml.name() == "enclosure") { - - QXmlStreamAttributes attribs = m_xml.attributes(); - - if (attribs.hasAttribute(QStringLiteral("fervor:platform"))) { - - if (FvPlatform::CurrentlyRunningOnPlatform(attribs.value(QStringLiteral("fervor:platform")).toString().trimmed())) { - - xmlEnclosurePlatform = attribs.value(QStringLiteral("fervor:platform")).toString().trimmed(); - - if (attribs.hasAttribute(QStringLiteral("url"))) { - xmlEnclosureUrl = attribs.value(QStringLiteral("url")).toString().trimmed(); - } else { - xmlEnclosureUrl = QLatin1String(""); - } - - // First check for Sparkle's version, then overwrite with Fervor's version (if any) - if (attribs.hasAttribute(QStringLiteral("sparkle:version"))) { - QString candidateVersion = attribs.value(QStringLiteral("sparkle:version")).toString().trimmed(); - if (! candidateVersion.isEmpty()) { - xmlEnclosureVersion = candidateVersion; - } - } - if (attribs.hasAttribute(QStringLiteral("fervor:version"))) { - QString candidateVersion = attribs.value(QStringLiteral("fervor:version")).toString().trimmed(); - if (! candidateVersion.isEmpty()) { - xmlEnclosureVersion = candidateVersion; - } - } - - if (attribs.hasAttribute(QStringLiteral("length"))) { - xmlEnclosureLength = attribs.value(QStringLiteral("length")).toString().toLong(); - } else { - xmlEnclosureLength = 0; - } - if (attribs.hasAttribute(QStringLiteral("type"))) { - xmlEnclosureType = attribs.value(QStringLiteral("type")).toString().trimmed(); - } else { - xmlEnclosureType = QLatin1String(""); - } - - } - - } - - } - - } else if (m_xml.isEndElement()) { - - if (m_xml.name() == "item" && !xmlEnclosurePlatform.isEmpty()) { - - // That's it - we have analyzed a single and we'll stop - // here (because the topmost is the most recent one, and thus - // the newest version. - - return searchDownloadedFeedForUpdates(xmlTitle, - xmlLink, - xmlReleaseNotesLink, - xmlPubDate, - xmlEnclosureUrl, - xmlEnclosureVersion, - xmlEnclosurePlatform, - xmlEnclosureLength, - xmlEnclosureType); - - } - - } else if (m_xml.isCharacters() && ! m_xml.isWhitespace()) { - - if (currentTag == QLatin1String("title")) { - xmlTitle += m_xml.text().toString().trimmed(); - - } else if (currentTag == QLatin1String("link")) { - xmlLink += m_xml.text().toString().trimmed(); - - } else if (currentQualifiedTag == QLatin1String("sparkle:releaseNotesLink")) { - xmlReleaseNotesLink += m_xml.text().toString().trimmed(); - - } else if (currentTag == QLatin1String("pubDate")) { - xmlPubDate += m_xml.text().toString().trimmed(); - - } - - } - - if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { - - showErrorDialog(tr("Feed parsing failed: %1 %2.").arg(QString::number(m_xml.lineNumber()), m_xml.errorString()), NO_UPDATE_MESSAGE); - return false; - - } - } - - // No updates were found if we're at this point - // (not a single element found) - showInformationDialog(tr("Your software is up to date."), false); - - return false; -} - - -bool FvUpdater::searchDownloadedFeedForUpdates(const QString& xmlTitle, - QString xmlLink, - QString xmlReleaseNotesLink, - const QString& xmlPubDate, - const QString& xmlEnclosureUrl, - const QString& xmlEnclosureVersion, - const QString& xmlEnclosurePlatform, - unsigned long xmlEnclosureLength, - const QString& xmlEnclosureType) -{ - qDebug() << "Title:" << xmlTitle; - qDebug() << "Link:" << xmlLink; - qDebug() << "Release notes link:" << xmlReleaseNotesLink; - qDebug() << "Pub. date:" << xmlPubDate; - qDebug() << "Enclosure URL:" << xmlEnclosureUrl; - qDebug() << "Enclosure version:" << xmlEnclosureVersion; - qDebug() << "Enclosure platform:" << xmlEnclosurePlatform; - qDebug() << "Enclosure length:" << xmlEnclosureLength; - qDebug() << "Enclosure type:" << xmlEnclosureType; - - // Validate - if (xmlReleaseNotesLink.isEmpty()) { - if (xmlLink.isEmpty()) { - showErrorDialog(tr("Feed error: \"release notes\" link is empty"), NO_UPDATE_MESSAGE); - return false; - } else { - xmlReleaseNotesLink = xmlLink; - } - } else { - xmlLink = xmlReleaseNotesLink; - } - if (! (xmlLink.startsWith(QStringLiteral("http://")) || xmlLink.startsWith(QStringLiteral("https://")))) { - showErrorDialog(tr("Feed error: invalid \"release notes\" link"), NO_UPDATE_MESSAGE); - return false; - } - if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) { - showErrorDialog(tr("Feed error: invalid \"enclosure\" with the download link"), NO_UPDATE_MESSAGE); - return false; - } - - // Relevant version? - if (FVIgnoredVersions::VersionIsIgnored(xmlEnclosureVersion)) { - qDebug() << "Version '" << xmlEnclosureVersion << "' is ignored, too old or something like that."; - - showInformationDialog(tr("Your software is up to date."), false); - - return true; // Things have succeeded when you think of it. - } - - - // - // Success! At this point, we have found an update that can be proposed - // to the user. - // - - if (m_proposedUpdate) { - delete m_proposedUpdate; - m_proposedUpdate = nullptr; - } - - governikus::ReleaseNotesDownloader downloader; - - m_proposedUpdate = new FvAvailableUpdate(); - m_proposedUpdate->SetTitle(xmlTitle); - m_proposedUpdate->SetReleaseNotesLink(xmlReleaseNotesLink); - m_proposedUpdate->SetReleaseNotes(downloader.loadReleaseNotes(m_proposedUpdate->GetReleaseNotesLink())); - m_proposedUpdate->SetPubDate(xmlPubDate); - m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl); - m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion); - m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform); - m_proposedUpdate->SetEnclosureLength(xmlEnclosureLength); - m_proposedUpdate->SetEnclosureType(xmlEnclosureType); - - // Show "look, there's an update" window - showUpdaterWindowUpdatedWithCurrentUpdateProposal(); - - return true; -} - - -void FvUpdater::showErrorDialog(QString message, msgType type) -{ - if (m_silentAsMuchAsItCouldGet) { - if (type != CRITICAL_MESSAGE) { - // Don't show errors in the silent mode - return; - } - } - else - { - if(type == NO_UPDATE_MESSAGE) - { - message = tr("Your software is up to date."); - } - } - - QMessageBox dlFailedMsgBox(QApplication::activeWindow()); - dlFailedMsgBox.setIcon(QMessageBox::Critical); - dlFailedMsgBox.setWindowTitle(QApplication::applicationName() + " - "+ tr("Error")); - dlFailedMsgBox.setWindowIcon(QIcon(QStringLiteral(":/images/autentapp2.iconset/icon_16x16.png"))); - dlFailedMsgBox.setWindowModality(Qt::WindowModal); - dlFailedMsgBox.setWindowFlags(dlFailedMsgBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); - dlFailedMsgBox.setText(message); - dlFailedMsgBox.exec(); -} - -void FvUpdater::showInformationDialog(const QString& message, bool showEvenInSilentMode) -{ - if (m_silentAsMuchAsItCouldGet) { - if (! showEvenInSilentMode) { - // Don't show information dialogs in the silent mode - return; - } - } - - QMessageBox dlInformationMsgBox(QApplication::activeWindow()); - dlInformationMsgBox.setIcon(QMessageBox::Information); - dlInformationMsgBox.setWindowTitle(QApplication::applicationName() + " - "+tr("Information")); - dlInformationMsgBox.setWindowIcon(QIcon(QStringLiteral(":/images/autentapp2.iconset/icon_16x16.png"))); - dlInformationMsgBox.setWindowModality(Qt::WindowModal); - dlInformationMsgBox.setWindowFlags(dlInformationMsgBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); - dlInformationMsgBox.setText(message); - dlInformationMsgBox.exec(); -} - diff --git a/src/external/fervor/fvupdater.h b/src/external/fervor/fvupdater.h deleted file mode 100644 index d821414..0000000 --- a/src/external/fervor/fvupdater.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef FVUPDATER_H -#define FVUPDATER_H - -#include -#include -#include -#include -#include -class FvUpdateWindow; -class FvAvailableUpdate; - - -class FvUpdater : public QObject -{ - Q_OBJECT - -public: - static bool DisableSilentCheck; - - // Singleton - static FvUpdater* sharedUpdater(); - static void drop(); - - void SetFeedURL(const QUrl &feedURL); - -public Q_SLOTS: - - // Check for updates - bool CheckForUpdates(bool silentAsMuchAsItCouldGet = true); - - // Aliases - bool CheckForUpdatesSilent(); - bool CheckForUpdatesNotSilent(); - - - // - // --------------------------------------------------- - // --------------------------------------------------- - // --------------------------------------------------- - // --------------------------------------------------- - // - -protected: - - enum msgType { - INFO_MESSAGE, // shown always for users - NO_UPDATE_MESSAGE, // shown message only in not-silent mode, but modified - CRITICAL_MESSAGE // shown always - }; - - friend class FvUpdateWindow; // Uses GetProposedUpdate() and others - friend class FvUpdateConfirmDialog; // Uses GetProposedUpdate() and others - FvAvailableUpdate* GetProposedUpdate(); - - -protected Q_SLOTS: - - // Update window button Q_SLOTS - void InstallUpdate(); - void SkipUpdate(); - void RemindMeLater(); - -private: - - // - // Singleton business - // - // (we leave just the declarations, so the compiler will warn us if we try - // to use those two functions by accident) - FvUpdater(); // Hide main constructor - ~FvUpdater(); // Hide main destructor - Q_DISABLE_COPY(FvUpdater) - - - static FvUpdater* m_Instance; // Singleton instance - - - // - // Windows / dialogs - // - FvUpdateWindow* m_updaterWindow; // Updater window (NULL if not shown) - void showUpdaterWindowUpdatedWithCurrentUpdateProposal(); // Show updater window - void hideUpdaterWindow(); // Hide + destroy m_updaterWindow - void updaterWindowWasClosed(); // Sent by the updater window when it gets closed - - // Available update (NULL if not fetched) - FvAvailableUpdate* m_proposedUpdate; - - // If true, don't show the error dialogs and the "no updates." dialog - // (silentAsMuchAsItCouldGet from CheckForUpdates() goes here) - // Useful for automatic update checking upon application startup. - bool m_silentAsMuchAsItCouldGet; - - // Dialogs (notifications) - void showErrorDialog(QString message, msgType type = NO_UPDATE_MESSAGE); // Show an error message - void showInformationDialog(const QString& message, bool showEvenInSilentMode = false); // Show an informational message - - - // - // HTTP feed fetcher infrastructure - // - QUrl m_feedURL; // Feed URL that will be fetched - QNetworkReply* m_reply; - bool m_encrypted; - bool m_httpRequestAborted; - bool m_securityError; - - void startDownloadFeed(const QUrl& url); // Start downloading feed - void cancelDownloadFeed(); // Stop downloading the current feed - void httpFeedSslCheckPeerCert(const QSslCertificate& pPeerCert); - -private Q_SLOTS: - - void httpFeedReadyRead(); - void httpFeedUpdateDataReadProgress(qint64 bytesRead, - qint64 totalBytes); - void httpFeedDownloadFinished(); - void httpFeedSslErrors(const QList& pErrors); - void httpFeedSslEncrypted(); - - -private: - - // - // XML parser - // - QXmlStreamReader m_xml; // XML data collector and parser - bool xmlParseFeed(); // Parse feed in m_xml - bool searchDownloadedFeedForUpdates(const QString& xmlTitle, - QString xmlLink, - QString xmlReleaseNotesLink, - const QString& xmlPubDate, - const QString& xmlEnclosureUrl, - const QString& xmlEnclosureVersion, - const QString& xmlEnclosurePlatform, - unsigned long xmlEnclosureLength, - const QString& xmlEnclosureType); - - - // - // Helpers - // - void installTranslator(); // Initialize translation mechanism - -}; - -#endif // FVUPDATER_H diff --git a/src/external/fervor/fvupdatewindow.cpp b/src/external/fervor/fvupdatewindow.cpp deleted file mode 100644 index 53a82fd..0000000 --- a/src/external/fervor/fvupdatewindow.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "fvupdatewindow.h" -#include "ui_fvupdatewindow.h" -#include "fvupdater.h" -#include "fvavailableupdate.h" -#include -#include -#include - - -FvUpdateWindow::FvUpdateWindow(QWidget *pParent) - : QWidget(pParent) - , m_ui(new Ui::FvUpdateWindow) - , m_appIconScene() -{ - m_ui->setupUi(this); - - m_appIconScene = nullptr; - - // Delete on close - setAttribute(Qt::WA_DeleteOnClose, true); - - // Set the "close app, then reopen" string - QString closeReopenString = m_ui->downloadThisUpdateLabel->text().arg(QApplication::applicationName()); - m_ui->downloadThisUpdateLabel->setText(closeReopenString); - - // Set the "new version is available" string - QString newVersString = m_ui->newVersionIsAvailableLabel->text().arg(QApplication::applicationName()); - m_ui->newVersionIsAvailableLabel->setText(newVersString); - - // Connect buttons - connect(m_ui->installUpdateButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::InstallUpdate); - connect(m_ui->skipThisVersionButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::SkipUpdate); - connect(m_ui->remindMeLaterButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::RemindMeLater); -} - -FvUpdateWindow::~FvUpdateWindow() -{ - delete m_ui; -} - -bool FvUpdateWindow::UpdateWindowWithCurrentProposedUpdate() -{ - FvAvailableUpdate* proposedUpdate = FvUpdater::sharedUpdater()->GetProposedUpdate(); - if (! proposedUpdate) { - return false; - } - - QString downloadString = m_ui->wouldYouLikeToDownloadLabel->text() - .arg(QApplication::applicationName(), proposedUpdate->GetEnclosureVersion(), QApplication::applicationVersion()); - m_ui->wouldYouLikeToDownloadLabel->setText(downloadString); - - QString downloadLinkString = m_ui->updateFileLinkLabel->text().arg(proposedUpdate->GetEnclosureUrl().toString()); - m_ui->updateFileLinkLabel->setText(downloadLinkString); - - m_ui->releaseNotesWebView->setHtml(proposedUpdate->GetReleaseNotes()); - m_ui->releaseNotesWebView->setAccessibleName(m_ui->releaseNotesWebView->toPlainText()); - - return true; -} - -void FvUpdateWindow::closeEvent(QCloseEvent* pEvent) -{ - FvUpdater::sharedUpdater()->updaterWindowWasClosed(); - pEvent->accept(); -} diff --git a/src/external/fervor/fvupdatewindow.h b/src/external/fervor/fvupdatewindow.h deleted file mode 100644 index 6a5718b..0000000 --- a/src/external/fervor/fvupdatewindow.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FVUPDATEWINDOW_H -#define FVUPDATEWINDOW_H - -#include -class QGraphicsScene; - -namespace Ui { -class FvUpdateWindow; -} - -class FvUpdateWindow : public QWidget -{ - Q_OBJECT - - Q_DISABLE_COPY(FvUpdateWindow) - -public: - explicit FvUpdateWindow(QWidget *pParent = nullptr); - ~FvUpdateWindow(); - - // Update the current update proposal from FvUpdater - bool UpdateWindowWithCurrentProposedUpdate(); - - void closeEvent(QCloseEvent* pEvent); - -private: - Ui::FvUpdateWindow* m_ui; - QGraphicsScene* m_appIconScene; - -}; - -#endif // FVUPDATEWINDOW_H diff --git a/src/external/fervor/fvversioncomparator.cpp b/src/external/fervor/fvversioncomparator.cpp deleted file mode 100644 index 9204e6d..0000000 --- a/src/external/fervor/fvversioncomparator.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "fvversioncomparator.h" -#include -#include -#include -#include // for atoi() - -// -// Clone of Sparkle's SUStandardVersionComparator.m, so here's original author's -// copyright too: -// -// Copyright 2007 Andy Matuschak. All rights reserved. -// -// Everything's the same except for TypeOfCharacter() -// (because who knows how Foundation does isdigit() and such.) -// - - -FvVersionComparator::FvVersionComparator() -{ - // noop -} - -FvVersionComparator::CharacterType FvVersionComparator::TypeOfCharacter(const std::string& character) -{ - if (character == ".") { - return kSeparatorType; - } else if (isdigit(character[0])) { - return kNumberType; - } else if (isspace(character[0])) { - return kSeparatorType; - } else if (ispunct(character[0])) { - return kSeparatorType; - } else { - return kStringType; - } - -} - -std::vector FvVersionComparator::SplitVersionString(const std::string& version) -{ - std::string character; - std::string s; - unsigned long i = 0, n = 0; - CharacterType oldType, newType; - std::vector parts; - - if (version.length() == 0) { - // Nothing to do here - return parts; - } - - s = version.substr(0, 1); - oldType = TypeOfCharacter(s); - n = version.length() - 1; - for (i = 1; i <= n; ++i) { - character = version.substr(i, 1)[0]; - newType = TypeOfCharacter(character); - if (oldType != newType || oldType == kSeparatorType) { - // We've reached a new segment - std::string aPart = s; - parts.push_back(aPart); - s = character; - } else { - // Add character to string and continue - s.append(character); - } - oldType = newType; - } - - // Add the last part onto the array - parts.push_back(s); - return parts; -} - - -FvVersionComparator::ComparatorResult FvVersionComparator::CompareVersions(const std::string& versionA, - const std::string& versionB) -{ - std::vector partsA = SplitVersionString(versionA); - std::vector partsB = SplitVersionString(versionB); - - std::string partA = std::string(""), partB = std::string(""); - unsigned long i = 0, n = 0; - int intA, intB; - CharacterType typeA, typeB; - - n = std::min(partsA.size(), partsB.size()); - for (i = 0; i < n; ++i) { - partA = partsA.at(i); - partB = partsB.at(i); - - typeA = TypeOfCharacter(partA); - typeB = TypeOfCharacter(partB); - - // Compare types - if (typeA == typeB) { - // Same type; we can compare - if (typeA == kNumberType) { - intA = atoi(partA.c_str()); - intB = atoi(partB.c_str()); - - if (intA > intB) { - return kDescending; - } else if (intA < intB) { - return kAscending; - } - } else if (typeA == kStringType) { - short result = partA.compare(partB); - switch (result) { - case -1: return kAscending; break; - case 1: return kDescending; break; - case 0: /* do nothing */ break; - }; - } - } else { - // Not the same type? Now we have to do some validity checking - if (typeA != kStringType && typeB == kStringType) { - // typeA wins - return kDescending; - } else if (typeA == kStringType && typeB != kStringType) { - // typeB wins - return kAscending; - } else { - // One is a number and the other is a period. The period is invalid - if (typeA == kNumberType) { - return kDescending; - } else { - return kAscending; - } - } - } - } - // The versions are equal up to the point where they both still have parts - // Lets check to see if one is larger than the other - if (partsA.size() != partsB.size()) { - // Yep. Lets get the next part of the larger - // n holds the index of the part we want. - std::string missingPart = std::string(""); - CharacterType missingType; - ComparatorResult shorterResult, largerResult; - - if (partsA.size() > partsB.size()) { - missingPart = partsA.at(n); - shorterResult = kAscending; - largerResult = kDescending; - } else { - missingPart = partsB.at(n); - shorterResult = kDescending; - largerResult = kAscending; - } - - missingType = TypeOfCharacter(missingPart); - // Check the type - if (missingType == kStringType) { - // It's a string. Shorter version wins - return shorterResult; - } else { - // It's a number/period. Larger version wins - return largerResult; - } - } - - // check gentoo like versioning - partB = partsB.at(n-1); - if( TypeOfCharacter(partB) == kNumberType ) { - intB = atoi(partB.c_str()); - if (intB == 9999) { - return kAscending; - } - } - - // The 2 strings are identical - return kSame; -} diff --git a/src/external/fervor/fvversioncomparator.h b/src/external/fervor/fvversioncomparator.h deleted file mode 100644 index ede842e..0000000 --- a/src/external/fervor/fvversioncomparator.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef FVVERSIONCOMPARATOR_H -#define FVVERSIONCOMPARATOR_H - -#include -#include - - -class FvVersionComparator -{ -public: - - typedef enum { - kSame = 0, - kDescending = 1, - kAscending = -1 - } ComparatorResult; - - static ComparatorResult CompareVersions(const std::string& versionA, - const std::string& versionB); - -private: - - FvVersionComparator(); - - typedef enum { - kNumberType, - kStringType, - kSeparatorType - } CharacterType; - - static CharacterType TypeOfCharacter(const std::string& character); - static std::vector SplitVersionString(const std::string& version); - -}; - -#endif // FVVERSIONCOMPARATOR_H diff --git a/src/external/http_parser/http_parser.cpp b/src/external/http_parser/http_parser.cpp index 895bf0c..904c7c4 100644 --- a/src/external/http_parser/http_parser.cpp +++ b/src/external/http_parser/http_parser.cpp @@ -1816,6 +1816,7 @@ reexecute: case 2: parser->upgrade = 1; + /* FALLTHROUGH */ case 1: parser->flags |= F_SKIPBODY; break; @@ -2375,7 +2376,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, case s_req_server_with_at: found_at = 1; - /* FALLTROUGH */ + /* FALLTHROUGH */ case s_req_server: uf = UF_HOST; break; diff --git a/src/external/qhttpserver/LICENSE b/src/external/qhttpserver/LICENSE deleted file mode 100644 index 4cac42a..0000000 --- a/src/external/qhttpserver/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2011-2014 Nikhil Marathe - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/src/external/qhttpserver/qhttpconnection.cpp b/src/external/qhttpserver/qhttpconnection.cpp deleted file mode 100644 index aead4c4..0000000 --- a/src/external/qhttpserver/qhttpconnection.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "qhttpconnection.h" - -#include -#include - -#include "http_parser/http_parser.h" -#include "qhttprequest.h" -#include "qhttpresponse.h" - -/// @cond nodoc - -QHttpConnection::QHttpConnection(QTcpSocket* socket) - : QObject(nullptr) - , m_socket(socket) - , m_parser(nullptr) - , m_parserSettings(nullptr) - , m_request(nullptr, &QObject::deleteLater) - , m_response(nullptr, &QObject::deleteLater) - , m_currentUrl() - , m_currentHeaders() - , m_currentHeaderField() - , m_currentHeaderValue() - , m_transmitLen(0) - , m_transmitPos(0) -{ - m_parser = new http_parser(); - http_parser_init(m_parser, HTTP_REQUEST); - - m_parserSettings = new http_parser_settings(); - m_parserSettings->on_message_begin = MessageBegin; - m_parserSettings->on_url = Url; - m_parserSettings->on_header_field = HeaderField; - m_parserSettings->on_header_value = HeaderValue; - m_parserSettings->on_headers_complete = HeadersComplete; - m_parserSettings->on_body = Body; - m_parserSettings->on_message_complete = MessageComplete; - - m_parser->data = this; - - connect(socket, &QTcpSocket::readyRead, this, &QHttpConnection::parseRequest); - connect(socket, &QTcpSocket::disconnected, this, &QHttpConnection::socketDisconnected); - connect(socket, &QTcpSocket::bytesWritten, this, &QHttpConnection::updateWriteCount); -} - -QHttpConnection::~QHttpConnection() -{ - delete m_parser; - m_parser = nullptr; - - delete m_parserSettings; - m_parserSettings = nullptr; -} - - -QAbstractSocket::SocketState QHttpConnection::getState() const -{ - if (m_socket.isNull()) - { - return QAbstractSocket::UnconnectedState; - } - - return m_socket->state(); -} - - -void QHttpConnection::socketDisconnected() -{ - /* - * We distinguish two cases: - * 1. The socket is closed and nobody holds the response: - * In this case clearing the response, will destroy the response. - * Because the response also holds the connection in a QSharedPointer, this connection is destroyed afterwards. - * 2. The socket is closed and some other object still holds a reference to the response: - * In this case clearing the response only decrements the reference counter. - * After the other object destroys the QSharedPointer, the workflow is as in case 1. - * - * It is important that the QSharedPointer do not destroy the objects immediately, but after returning to the event loop! - * Thereby the currently active call stack can be finished. - */ - m_response.clear(); - - if (m_request) - { - if (m_request->successful()) - { - return; - } - - Q_EMIT m_request->end(); - } -} - - -void QHttpConnection::updateWriteCount(qint64 count) -{ - Q_ASSERT(m_transmitPos + count <= m_transmitLen); - - m_transmitPos += count; - - if (m_transmitPos == m_transmitLen) - { - m_transmitLen = 0; - m_transmitPos = 0; - Q_EMIT allBytesWritten(); - } -} - - -void QHttpConnection::parseRequest() -{ - Q_ASSERT(m_parser); - - while (m_socket->bytesAvailable()) - { - QByteArray arr = m_socket->readAll(); - http_parser_execute(m_parser, m_parserSettings, arr.constData(), arr.size()); - } -} - - -void QHttpConnection::write(const QByteArray& data) -{ - m_socket->write(data); - m_transmitLen += data.size(); -} - - -void QHttpConnection::flush() -{ - m_socket->flush(); -} - - -void QHttpConnection::responseDone() -{ - QHttpResponse* response = qobject_cast(QObject::sender()); - if (response->m_last) - { - m_socket->disconnectFromHost(); - } -} - - -/* URL Utilities */ -#define HAS_URL_FIELD(info, field) (info.field_set & (1 << (field))) - -#define GET_FIELD(data, info, field)\ - QString::fromLatin1(data + info.field_data[field].off, info.field_data[field].len) - -#define CHECK_AND_GET_FIELD(data, info, field)\ - (HAS_URL_FIELD(info, field) ? GET_FIELD(data, info, field) : QString()) - -namespace -{ - -QUrl createUrl(const char* urlData, const http_parser_url& urlInfo) -{ - QUrl url; - url.setScheme(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_SCHEMA)); - url.setHost(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_HOST)); - // Port is dealt with separately since it is available as an integer. - url.setPath(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_PATH)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - url.setQuery(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_QUERY)); -#else - if (HAS_URL_FIELD(urlInfo, UF_QUERY)) - { - url.setEncodedQuery(QByteArray(urlData + urlInfo.field_data[UF_QUERY].off, - urlInfo.field_data[UF_QUERY].len)); - } -#endif - url.setFragment(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_FRAGMENT)); - url.setUserInfo(CHECK_AND_GET_FIELD(urlData, urlInfo, UF_USERINFO)); - - if (HAS_URL_FIELD(urlInfo, UF_PORT)) - { - url.setPort(urlInfo.port); - } - - return url; -} - -} - -#undef CHECK_AND_SET_FIELD -#undef GET_FIELD -#undef HAS_URL_FIELD - -/******************** - * Static Callbacks * - *******************/ -int QHttpConnection::MessageBegin(http_parser* parser) -{ - QHttpConnection* theConnection = static_cast(parser->data); - theConnection->m_currentHeaders.clear(); - theConnection->m_currentUrl.clear(); - theConnection->m_currentUrl.reserve(128); - - // The QHttpRequest should not be parented to this, since it's memory - // management is the responsibility of the user of the library. - theConnection->m_request.reset(new QHttpRequest(), &QObject::deleteLater); - return 0; -} - - -int QHttpConnection::HeadersComplete(http_parser* parser) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - /** set method **/ - theConnection->m_request->setMethod(static_cast(parser->method)); - - /** set version **/ - theConnection->m_request->setVersion(QStringLiteral("%1.%2").arg(parser->http_major).arg(parser->http_minor)); - - /** get parsed url **/ - struct http_parser_url urlInfo; - int r = http_parser_parse_url(theConnection->m_currentUrl.constData(), - theConnection->m_currentUrl.size(), - parser->method == HTTP_CONNECT, - &urlInfo); - Q_ASSERT(r == 0); - Q_UNUSED(r); - - theConnection->m_request->setUrl(createUrl(theConnection->m_currentUrl.constData(), urlInfo)); - - // Insert last remaining header - theConnection->m_currentHeaders[theConnection->m_currentHeaderField.toLower()] = theConnection->m_currentHeaderValue; - theConnection->m_request->setHeaders(theConnection->m_currentHeaders); - - /** set client information **/ - theConnection->m_request->m_remoteAddress = theConnection->m_socket->peerAddress().toString(); - theConnection->m_request->m_remotePort = theConnection->m_socket->peerPort(); - - QSharedPointer sharedConnection; - if (theConnection->m_response.isNull()) - { - sharedConnection.reset(theConnection, &QObject::deleteLater); - } - else - { - sharedConnection = theConnection->m_response->m_connection; - } - - theConnection->m_response.reset(new QHttpResponse(sharedConnection), &QObject::deleteLater); - if (parser->http_major < 1 || parser->http_minor < 1) - { - theConnection->m_response->m_keepAlive = false; - } - - connect(theConnection->m_response.data(), &QHttpResponse::done, theConnection, &QHttpConnection::responseDone); - - // we are good to go! - Q_EMIT theConnection->newRequest(theConnection->m_request, theConnection->m_response); - return 0; -} - - -int QHttpConnection::MessageComplete(http_parser* parser) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - theConnection->m_request->setSuccessful(true); - Q_EMIT theConnection->m_request->end(); - return 0; -} - - -int QHttpConnection::Url(http_parser* parser, const char* at, size_t length) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - theConnection->m_currentUrl.append(at, length); - return 0; -} - - -int QHttpConnection::HeaderField(http_parser* parser, const char* at, size_t length) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - // insert the header we parsed previously - // into the header map - if (!theConnection->m_currentHeaderField.isEmpty() && !theConnection->m_currentHeaderValue.isEmpty()) - { - // header names are always lower-cased - theConnection->m_currentHeaders[theConnection->m_currentHeaderField.toLower()] = theConnection->m_currentHeaderValue; - // clear header value. this sets up a nice - // feedback loop where the next time - // HeaderValue is called, it can simply append - theConnection->m_currentHeaderField = QString(); - theConnection->m_currentHeaderValue = QString(); - } - - QString fieldSuffix = QString::fromLatin1(at, length); - theConnection->m_currentHeaderField += fieldSuffix; - return 0; -} - - -int QHttpConnection::HeaderValue(http_parser* parser, const char* at, size_t length) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - QString valueSuffix = QString::fromLatin1(at, length); - theConnection->m_currentHeaderValue += valueSuffix; - return 0; -} - - -int QHttpConnection::Body(http_parser* parser, const char* at, size_t length) -{ - QHttpConnection* theConnection = static_cast(parser->data); - Q_ASSERT(theConnection->m_request); - - Q_EMIT theConnection->m_request->data(QByteArray(at, length)); - return 0; -} - - -/// @endcond diff --git a/src/external/qhttpserver/qhttpconnection.h b/src/external/qhttpserver/qhttpconnection.h deleted file mode 100644 index 081bdff..0000000 --- a/src/external/qhttpserver/qhttpconnection.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_CONNECTION -#define Q_HTTP_CONNECTION - -#include "qhttpserverapi.h" -#include "qhttpserverfwd.h" - -#include -#include -#include - -/// @cond nodoc - -class QHTTPSERVER_API QHttpConnection - : public QObject -{ - Q_OBJECT - - Q_DISABLE_COPY(QHttpConnection) - - public: - QHttpConnection(QTcpSocket* socket); - - virtual void write(const QByteArray& data); - void flush(); - QAbstractSocket::SocketState getState() const; - - Q_SIGNALS: - void newRequest(QSharedPointer, QSharedPointer); - void allBytesWritten(); - - protected: - virtual ~QHttpConnection(); - - private Q_SLOTS: - void parseRequest(); - void responseDone(); - void socketDisconnected(); - void updateWriteCount(qint64); - - private: - static int MessageBegin(http_parser* parser); - static int Url(http_parser* parser, const char* at, size_t length); - static int HeaderField(http_parser* parser, const char* at, size_t length); - static int HeaderValue(http_parser* parser, const char* at, size_t length); - static int HeadersComplete(http_parser* parser); - static int Body(http_parser* parser, const char* at, size_t length); - static int MessageComplete(http_parser* parser); - - private: - QScopedPointer m_socket; - http_parser* m_parser; - http_parser_settings* m_parserSettings; - - // Since there can only be one request at any time even with pipelining. - QSharedPointer m_request; - QSharedPointer m_response; - - QByteArray m_currentUrl; - // The ones we are reading in from the parser - HeaderHash m_currentHeaders; - QString m_currentHeaderField; - QString m_currentHeaderValue; - - // Keep track of transmit buffer status - qint64 m_transmitLen; - qint64 m_transmitPos; -}; - -/// @endcond - -#endif diff --git a/src/external/qhttpserver/qhttprequest.cpp b/src/external/qhttpserver/qhttprequest.cpp deleted file mode 100644 index 6f8c422..0000000 --- a/src/external/qhttpserver/qhttprequest.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "qhttprequest.h" - -#include "qhttpconnection.h" - -QHttpRequest::QHttpRequest() - : QObject(nullptr) - , m_headers() - , m_method() - , m_url(QStringLiteral("http://localhost/")) - , m_version() - , m_remoteAddress() - , m_remotePort() - , m_body() - , m_success(false) -{ -} - - -QHttpRequest::~QHttpRequest() -{ -} - - -QString QHttpRequest::header(const QString& field) -{ - return m_headers.value(field.toLower(), QLatin1String("")); -} - - -const HeaderHash& QHttpRequest::headers() const -{ - return m_headers; -} - - -const QString& QHttpRequest::httpVersion() const -{ - return m_version; -} - - -const QUrl& QHttpRequest::url() const -{ - return m_url; -} - - -const QString QHttpRequest::path() const -{ - return m_url.path(); -} - - -const QString QHttpRequest::methodString() const -{ - return MethodToString(method()); -} - - -QHttpRequest::HttpMethod QHttpRequest::method() const -{ - return m_method; -} - - -const QString& QHttpRequest::remoteAddress() const -{ - return m_remoteAddress; -} - - -quint16 QHttpRequest::remotePort() const -{ - return m_remotePort; -} - - -void QHttpRequest::storeBody() -{ - connect(this, &QHttpRequest::data, this, &QHttpRequest::appendBody, Qt::UniqueConnection); -} - - -QString QHttpRequest::MethodToString(HttpMethod method) -{ - return QString::fromLatin1(QMetaEnum::fromType().valueToKey(method)); -} - - -void QHttpRequest::appendBody(const QByteArray& pBody) -{ - m_body.append(pBody); -} diff --git a/src/external/qhttpserver/qhttprequest.h b/src/external/qhttpserver/qhttprequest.h deleted file mode 100644 index 06f282f..0000000 --- a/src/external/qhttpserver/qhttprequest.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_REQUEST -#define Q_HTTP_REQUEST - -#include "qhttpserverapi.h" -#include "qhttpserverfwd.h" - -#include -#include -#include -#include - -class test_WebserviceActivationHandler; - -/// The QHttpRequest class represents the header and body data sent by the client. - -/** The requests header data is available immediately. Body data is streamed as - it comes in via the data() signal. As a consequence the application's request - callback should ensure that it connects to the data() signal before control - returns back to the event loop. Otherwise there is a risk of some data never - being received by the application. - - The class is read-only. */ -class QHTTPSERVER_API QHttpRequest - : public QObject -{ - Q_OBJECT - - Q_PROPERTY(HeaderHash headers READ headers) - Q_PROPERTY(QString remoteAddress READ remoteAddress) - Q_PROPERTY(quint16 remotePort READ remotePort) - Q_PROPERTY(QString method READ method) - Q_PROPERTY(QUrl url READ url) - Q_PROPERTY(QString path READ path) - Q_PROPERTY(QString httpVersion READ httpVersion) - - /// @cond nodoc - friend class QHttpConnection; - friend class::test_WebserviceActivationHandler; - /// @endcond - - public: - virtual ~QHttpRequest(); - - /// Request method enumeration. - /** @note Taken from http_parser.h -- make sure to keep synced */ - enum HttpMethod - { - HTTP_DELETE = 0, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, - // pathological - HTTP_CONNECT, - HTTP_OPTIONS, - HTTP_TRACE, - // webdav - HTTP_COPY, - HTTP_LOCK, - HTTP_MKCOL, - HTTP_MOVE, - HTTP_PROPFIND, - HTTP_PROPPATCH, - HTTP_SEARCH, - HTTP_UNLOCK, - // subversion - HTTP_REPORT, - HTTP_MKACTIVITY, - HTTP_CHECKOUT, - HTTP_MERGE, - // upnp - HTTP_MSEARCH, - HTTP_NOTIFY, - HTTP_SUBSCRIBE, - HTTP_UNSUBSCRIBE, - // RFC-5789 - HTTP_PATCH, - HTTP_PURGE - }; - - Q_ENUM(HttpMethod) - - /// The method used for the request. - HttpMethod method() const; - - /// Returns the method string for the request. - /** @note This will plainly transform the enum into a string HTTP_GET -> "HTTP_GET". */ - const QString methodString() const; - - /// The complete URL for the request. - - /** This includes the path and query string. - @sa path() */ - const QUrl& url() const; - - /// The path portion of the query URL. - /** @sa url() */ - const QString path() const; - - /// The HTTP version of the request. - /** @return A string in the form of "x.x" */ - const QString& httpVersion() const; - - /// Return all the headers sent by the client. - - /** This returns a reference. If you want to store headers - somewhere else, where the request may be deleted, - make sure you store them as a copy. - @note All header names are lowercase - so that Content-Length becomes content-length etc. */ - const HeaderHash& headers() const; - - /// Get the value of a header. - - /** Headers are stored as lowercase so the input @c field will be lowercased. - @param field Name of the header field - @return Value of the header or empty string if not found. */ - QString header(const QString& field); - - /// IP Address of the client in dotted decimal format. - const QString& remoteAddress() const; - - /// Outbound connection port for the client. - quint16 remotePort() const; - - /// Request body data, empty for non POST/PUT requests. - /** @sa storeBody() */ - const QByteArray& body() const - { - return m_body; - } - - - /// If this request was successfully received. - - /** Set before end() has been emitted, stating whether - the message was properly received. This is false - until the receiving the full request has completed. */ - bool successful() const - { - return m_success; - } - - - /// Utility function to make this request store all body data internally. - - /** If you call this when the request is received via QHttpServer::newRequest() - the request will take care of storing the body data for you. - Once the end() signal is emitted you can access the body data with - the body() function. - - If you wish to handle incoming data yourself don't call this function - and see the data() signal. - @sa data() body() */ - void storeBody(); - - Q_SIGNALS: - /// Emitted when new body data has been received. - - /** @note This may be emitted zero or more times - depending on the request type. - @param data Received data. */ - void data(const QByteArray& data); - - /// Emitted when the request has been fully received. - /** @note The no more data() Q_SIGNALS will be emitted after this. */ - void end(); - - private Q_SLOTS: - void appendBody(const QByteArray& body); - - private: - QHttpRequest(); - - static QString MethodToString(HttpMethod method); - - void setMethod(HttpMethod pMethod) - { - m_method = pMethod; - } - - - void setVersion(const QString& version) - { - m_version = version; - } - - - void setUrl(const QUrl& pUrl) - { - m_url = pUrl; - } - - - void setHeaders(const HeaderHash& pHeaders) - { - m_headers = pHeaders; - } - - - void setSuccessful(bool success) - { - m_success = success; - } - - - HeaderHash m_headers; - HttpMethod m_method; - QUrl m_url; - QString m_version; - QString m_remoteAddress; - quint16 m_remotePort; - QByteArray m_body; - bool m_success; -}; - -#endif diff --git a/src/external/qhttpserver/qhttpresponse.cpp b/src/external/qhttpserver/qhttpresponse.cpp deleted file mode 100644 index bf38403..0000000 --- a/src/external/qhttpserver/qhttpresponse.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "qhttpresponse.h" - -#include -#include - -#include "qhttpserver.h" -#include "qhttpconnection.h" - -QHttpResponse::QHttpResponse(QSharedPointer connection) - : QObject(nullptr) - , m_connection(connection) - , m_headers() - , m_headerWritten(false) - , m_sentConnectionHeader(false) - , m_sentContentLengthHeader(false) - , m_sentTransferEncodingHeader(false) - , m_sentDate(false) - , m_keepAlive(true) - , m_last(false) - , m_useChunkedEncoding(false) - , m_finished(false) -{ - connect(m_connection.data(), &QHttpConnection::allBytesWritten, this, &QHttpResponse::allBytesWritten); -} - - -QHttpResponse::~QHttpResponse() -{ -} - - -QAbstractSocket::SocketState QHttpResponse::getState() const -{ - if (m_connection.isNull()) - { - return QAbstractSocket::UnconnectedState; - } - - return m_connection->getState(); -} - - -void QHttpResponse::setHeader(const QString& field, const QString& value) -{ - if (!m_finished) - { - m_headers[field] = value; - } - else - { - qWarning() << "QHttpResponse::setHeader() Cannot set headers after response has finished."; - } -} - - -void QHttpResponse::writeHeader(const QByteArray& field, const QString& value) -{ - m_connection->write(field); - m_connection->write(": "); - m_connection->write(value.toUtf8()); - m_connection->write("\r\n"); -} - - -void QHttpResponse::writeHeaders() -{ - if (m_finished) - { - return; - } - - const auto headerKeys = m_headers.keys(); - for (const auto& name : headerKeys) - { - QString value = m_headers.value(name); - if (name.compare(QStringLiteral("connection"), Qt::CaseInsensitive) == 0) - { - m_sentConnectionHeader = true; - if (value.compare(QStringLiteral("close"), Qt::CaseInsensitive) == 0) - { - m_last = true; - } - else - { - m_keepAlive = true; - } - } - else if (name.compare(QStringLiteral("transfer-encoding"), Qt::CaseInsensitive) == 0) - { - m_sentTransferEncodingHeader = true; - if (value.compare(QStringLiteral("chunked"), Qt::CaseInsensitive) == 0) - { - m_useChunkedEncoding = true; - } - } - else if (name.compare(QStringLiteral("content-length"), Qt::CaseInsensitive) == 0) - { - m_sentContentLengthHeader = true; - } - else if (name.compare(QStringLiteral("date"), Qt::CaseInsensitive) == 0) - { - m_sentDate = true; - } - - writeHeader(name.toLatin1(), value); - } - - if (!m_sentConnectionHeader) - { - if (m_keepAlive && (m_sentContentLengthHeader || m_useChunkedEncoding)) - { - writeHeader("Connection", QStringLiteral("keep-alive")); - } - else - { - m_last = true; - writeHeader("Connection", QStringLiteral("close")); - } - } - - if (!m_sentContentLengthHeader && !m_sentTransferEncodingHeader) - { - if (m_useChunkedEncoding) - { - writeHeader("Transfer-Encoding", QStringLiteral("chunked")); - } - else - { - m_last = true; - } - } - - // Sun, 06 Nov 1994 08:49:37 GMT - RFC 822. Use QLocale::c() so english is used for month and - // day. - if (!m_sentDate) - { - writeHeader("Date", QLocale::c().toString(QDateTime::currentDateTimeUtc(), QStringLiteral("ddd, dd MMM yyyy hh:mm:ss")) + " GMT"); - } -} - - -void QHttpResponse::writeHead(int status) -{ - if (m_finished) - { - qWarning() << "QHttpResponse::writeHead() Cannot write headers after response has finished."; - return; - } - - if (m_headerWritten) - { - qWarning() << "QHttpResponse::writeHead() Already called once for this response."; - return; - } - - m_connection->write(QStringLiteral("HTTP/1.1 %1 %2\r\n").arg(status).arg(STATUS_CODES[status]).toLatin1()); - writeHeaders(); - m_connection->write("\r\n"); - - m_headerWritten = true; -} - - -void QHttpResponse::clearHeaders() -{ - m_headers.clear(); - m_headerWritten = false; -} - - -void QHttpResponse::write(const QByteArray& data) -{ - if (m_finished) - { - qWarning() << "QHttpResponse::write() Cannot write body after response has finished."; - return; - } - - if (!m_headerWritten) - { - qWarning() << "QHttpResponse::write() You must call writeHead() before writing body data."; - return; - } - - m_connection->write(data); -} - - -void QHttpResponse::end(const QByteArray& data) -{ - if (m_finished) - { - qWarning() << "QHttpResponse::end() Cannot write end after response has finished."; - return; - } - - if (data.size() > 0) - { - write(data); - } - m_finished = true; - - Q_EMIT done(); -} - - -void QHttpResponse::connectionClosed() -{ - m_finished = true; -} diff --git a/src/external/qhttpserver/qhttpresponse.h b/src/external/qhttpserver/qhttpresponse.h deleted file mode 100644 index c48e937..0000000 --- a/src/external/qhttpserver/qhttpresponse.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_RESPONSE -#define Q_HTTP_RESPONSE - -#include "qhttpserverapi.h" -#include "qhttpserverfwd.h" - -#include -#include - -class test_WebserviceActivationHandler; - -/// The QHttpResponse class handles sending data back to the client as a response to a request. - -/** The steps to respond correctly are -
    -
  1. Call setHeader() to set headers [optional]
  2. -
  3. Call writeHead() with the HTTP status code
  4. -
  5. Call write() zero or more times for body data.
  6. -
  7. Call end() when the resonse can be sent back
  8. -
*/ -class QHTTPSERVER_API QHttpResponse - : public QObject -{ - Q_OBJECT - friend struct QtSharedPointer::CustomDeleter; - friend class::test_WebserviceActivationHandler; - - public: - /// HTTP status code. - enum StatusCode - { - STATUS_CONTINUE = 100, - STATUS_SWITCH_PROTOCOLS = 101, - STATUS_PROCESSING = 102, - STATUS_OK = 200, - STATUS_CREATED = 201, - STATUS_ACCEPTED = 202, - STATUS_NON_AUTHORITATIVE_INFORMATION = 203, - STATUS_NO_CONTENT = 204, - STATUS_RESET_CONTENT = 205, - STATUS_PARTIAL_CONTENT = 206, - STATUS_MULTIPLE_CHOICES = 300, - STATUS_MOVED_PERMANENTLY = 301, - STATUS_FOUND = 302, - STATUS_SEE_OTHER = 303, - STATUS_NOT_MODIFIED = 304, - STATUS_USE_PROXY = 305, - STATUS_TEMPORARY_REDIRECT = 307, - STATUS_BAD_REQUEST = 400, - STATUS_UNAUTHORIZED = 401, - STATUS_PAYMENT_REQUIRED = 402, - STATUS_FORBIDDEN = 403, - STATUS_NOT_FOUND = 404, - STATUS_METHOD_NOT_ALLOWED = 405, - STATUS_NOT_ACCEPTABLE = 406, - STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, - STATUS_REQUEST_TIMEOUT = 408, - STATUS_CONFLICT = 409, - STATUS_GONE = 410, - STATUS_LENGTH_REQUIRED = 411, - STATUS_PRECONDITION_FAILED = 412, - STATUS_REQUEST_ENTITY_TOO_LARGE = 413, - STATUS_REQUEST_URI_TOO_LONG = 414, - STATUS_REQUEST_UNSUPPORTED_MEDIA_TYPE = 415, - STATUS_REQUESTED_RANGE_NOT_SATISFIABLE = 416, - STATUS_EXPECTATION_FAILED = 417, - STATUS_INTERNAL_SERVER_ERROR = 500, - STATUS_NOT_IMPLEMENTED = 501, - STATUS_BAD_GATEWAY = 502, - STATUS_SERVICE_UNAVAILABLE = 503, - STATUS_GATEWAY_TIMEOUT = 504, - STATUS_HTTP_VERSION_NOT_SUPPORTED = 505 - }; - - - /// @cond nodoc - friend class QHttpConnection; - /// @endcond - - QAbstractSocket::SocketState getState() const; - - public Q_SLOTS: - /// Sets a response header @c field to @c value. - - /** @note You must call this with all your custom headers - before calling writeHead(), write() or end(). - @param field Header field to be set. - @param value Header value to be set. */ - void setHeader(const QString& field, const QString& value); - - /// Writes the header section of the response - /// using @c status as the response status code. - - /** @param statusCode Status code for the response. - @note Any headers should be set before - invoking this function with setHeader(). */ - void writeHead(int statusCode); - - void clearHeaders(); - - /// Writes a block of @c data to the client. - /** @note writeHead() must be called before this function. */ - void write(const QByteArray& data); - - /// End/finish the response. - - /** Data will be flushed to the underlying socket - and the connection itself will be closed if - this is the last response. - - This will Q_EMIT done() and queue this object - for deletion. For details see \ref memorymanagement. - @param data Optional data to be written before finishing. */ - void end(const QByteArray& data = ""); - - Q_SIGNALS: - /// Emitted when all the data has been sent - - /** This signal indicates that the underlaying socket has transmitted all - of it's buffered data. It is possible to implement memory-efficient - file transfers by calling \ref write() for a block of data only after - receiving this signal. */ - void allBytesWritten(); - - /// Emitted when the response is finished. - - /** You should not interact with this object - after done() has been emitted as the object - has already been scheduled for deletion. */ - void done(); - - private: - QHttpResponse(QSharedPointer connection); - virtual ~QHttpResponse(); - - void writeHeaders(); - void writeHeader(const QByteArray& field, const QString& value); - - QSharedPointer m_connection; - - HeaderHash m_headers; - - bool m_headerWritten; - bool m_sentConnectionHeader; - bool m_sentContentLengthHeader; - bool m_sentTransferEncodingHeader; - bool m_sentDate; - bool m_keepAlive; - bool m_last; - bool m_useChunkedEncoding; - bool m_finished; - - private Q_SLOTS: - void connectionClosed(); -}; - -#endif diff --git a/src/external/qhttpserver/qhttpserver.cpp b/src/external/qhttpserver/qhttpserver.cpp deleted file mode 100644 index 7409ade..0000000 --- a/src/external/qhttpserver/qhttpserver.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "qhttpserver.h" - -#include -#include -#include -#include - -#include "qhttpconnection.h" -#include "qhttprequest.h" -#include "qhttpresponse.h" - -QHash STATUS_CODES; - -QHttpServer::QHttpServer(QObject* pParent) - : QObject(pParent) - , m_tcpServer(nullptr) -{ - STATUS_CODES.insert(100, QStringLiteral("Continue")); - STATUS_CODES.insert(101, QStringLiteral("Switching Protocols")); - STATUS_CODES.insert(102, QStringLiteral("Processing")); - // RFC 2518) obsoleted by RFC 4918 - STATUS_CODES.insert(200, QStringLiteral("OK")); - STATUS_CODES.insert(201, QStringLiteral("Created")); - STATUS_CODES.insert(202, QStringLiteral("Accepted")); - STATUS_CODES.insert(203, QStringLiteral("Non-Authoritative Information")); - STATUS_CODES.insert(204, QStringLiteral("No Content")); - STATUS_CODES.insert(205, QStringLiteral("Reset Content")); - STATUS_CODES.insert(206, QStringLiteral("Partial Content")); - STATUS_CODES.insert(207, QStringLiteral("Multi-Status")); - // RFC 4918 - STATUS_CODES.insert(300, QStringLiteral("Multiple Choices")); - STATUS_CODES.insert(301, QStringLiteral("Moved Permanently")); - STATUS_CODES.insert(302, QStringLiteral("Moved Temporarily")); - STATUS_CODES.insert(303, QStringLiteral("See Other")); - STATUS_CODES.insert(304, QStringLiteral("Not Modified")); - STATUS_CODES.insert(305, QStringLiteral("Use Proxy")); - STATUS_CODES.insert(307, QStringLiteral("Temporary Redirect")); - STATUS_CODES.insert(400, QStringLiteral("Bad Request")); - STATUS_CODES.insert(401, QStringLiteral("Unauthorized")); - STATUS_CODES.insert(402, QStringLiteral("Payment Required")); - STATUS_CODES.insert(403, QStringLiteral("Forbidden")); - STATUS_CODES.insert(404, QStringLiteral("Not Found")); - STATUS_CODES.insert(405, QStringLiteral("Method Not Allowed")); - STATUS_CODES.insert(406, QStringLiteral("Not Acceptable")); - STATUS_CODES.insert(407, QStringLiteral("Proxy Authentication Required")); - STATUS_CODES.insert(408, QStringLiteral("Request Time-out")); - STATUS_CODES.insert(409, QStringLiteral("Conflict")); - STATUS_CODES.insert(410, QStringLiteral("Gone")); - STATUS_CODES.insert(411, QStringLiteral("Length Required")); - STATUS_CODES.insert(412, QStringLiteral("Precondition Failed")); - STATUS_CODES.insert(413, QStringLiteral("Request Entity Too Large")); - STATUS_CODES.insert(414, QStringLiteral("Request-URI Too Large")); - STATUS_CODES.insert(415, QStringLiteral("Unsupported Media Type")); - STATUS_CODES.insert(416, QStringLiteral("Requested Range Not Satisfiable")); - STATUS_CODES.insert(417, QStringLiteral("Expectation Failed")); - STATUS_CODES.insert(418, QStringLiteral("I\"m a teapot")); - // RFC 2324 - STATUS_CODES.insert(422, QStringLiteral("Unprocessable Entity")); - // RFC 4918 - STATUS_CODES.insert(423, QStringLiteral("Locked")); - // RFC 4918 - STATUS_CODES.insert(424, QStringLiteral("Failed Dependency")); - // RFC 4918 - STATUS_CODES.insert(425, QStringLiteral("Unordered Collection")); - // RFC 4918 - STATUS_CODES.insert(426, QStringLiteral("Upgrade Required")); - // RFC 2817 - STATUS_CODES.insert(500, QStringLiteral("Internal Server Error")); - STATUS_CODES.insert(501, QStringLiteral("Not Implemented")); - STATUS_CODES.insert(502, QStringLiteral("Bad Gateway")); - STATUS_CODES.insert(503, QStringLiteral("Service Unavailable")); - STATUS_CODES.insert(504, QStringLiteral("Gateway Time-out")); - STATUS_CODES.insert(505, QStringLiteral("HTTP Version not supported")); - STATUS_CODES.insert(506, QStringLiteral("Variant Also Negotiates")); - // RFC 2295 - STATUS_CODES.insert(507, QStringLiteral("Insufficient Storage")); - // RFC 4918 - STATUS_CODES.insert(509, QStringLiteral("Bandwidth Limit Exceeded")); - STATUS_CODES.insert(510, QStringLiteral("Not Extended")); - // RFC 2774 -} - - -QHttpServer::~QHttpServer() -{ -} - - -void QHttpServer::newConnection() -{ - Q_ASSERT(m_tcpServer); - - while (m_tcpServer->hasPendingConnections()) - { - QHttpConnection* connection = new QHttpConnection(m_tcpServer->nextPendingConnection()); - connect(connection, &QHttpConnection::newRequest, this, &QHttpServer::newRequest); - } -} - - -bool QHttpServer::listen(const QHostAddress& address, quint16 port) -{ - Q_ASSERT(!m_tcpServer); - m_tcpServer = new QTcpServer(this); - - bool couldBindToPort = m_tcpServer->listen(address, port); - if (couldBindToPort) - { - connect(m_tcpServer, &QTcpServer::newConnection, this, &QHttpServer::newConnection); - } - else - { - delete m_tcpServer; - m_tcpServer = nullptr; - } - return couldBindToPort; -} - - -bool QHttpServer::listen(quint16 port) -{ - return listen(QHostAddress::Any, port); -} - - -quint16 QHttpServer::serverPort() -{ - Q_ASSERT(m_tcpServer); - - if (m_tcpServer) - { - return m_tcpServer->serverPort(); - } - - return 0; -} - - -void QHttpServer::close() -{ - if (m_tcpServer) - { - m_tcpServer->close(); - } -} diff --git a/src/external/qhttpserver/qhttpserver.h b/src/external/qhttpserver/qhttpserver.h deleted file mode 100644 index 9a90130..0000000 --- a/src/external/qhttpserver/qhttpserver.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_SERVER -#define Q_HTTP_SERVER - -#define QHTTPSERVER_VERSION_MAJOR 0 -#define QHTTPSERVER_VERSION_MINOR 1 -#define QHTTPSERVER_VERSION_PATCH 0 - -#include "qhttpserverapi.h" -#include "qhttpserverfwd.h" - -#include -#include - -/// Maps status codes to string reason phrases -extern QHash STATUS_CODES; - -/// The QHttpServer class forms the basis of the %QHttpServer -/// project. It is a fast, non-blocking HTTP server. - -/** These are the steps to create a server, handle and respond to requests: -
    -
  1. Create an instance of QHttpServer.
  2. -
  3. Connect a slot to the newRequest() signal.
  4. -
  5. Create a QCoreApplication to drive the server event loop.
  6. -
  7. Respond to clients by writing out to the QHttpResponse object.
  8. -
- - Here is a simple sample application on how to use this library - - helloworld.cpp - @include helloworld/helloworld.cpp - - helloworld.h - @include helloworld/helloworld.h */ -class QHTTPSERVER_API QHttpServer - : public QObject -{ - Q_OBJECT - - Q_DISABLE_COPY(QHttpServer) - - public: - /// Construct a new HTTP Server. - /** @param parent Parent QObject for the server. */ - QHttpServer(QObject* parent = nullptr); - virtual ~QHttpServer(); - - /// Start the server by bounding to the given @c address and @c port. - - /** @note This function returns immediately, it does not block. - @param address Address on which to listen to. Default is to listen on - all interfaces which means the server can be accessed from anywhere. - @param port Port number on which the server should run. - @return True if the server was started successfully, false otherwise. - @sa listen(quint16) */ - bool listen(const QHostAddress& address = QHostAddress::Any, quint16 port = 80); - - /// Starts the server on @c port listening on all interfaces. - - /** @param port Port number on which the server should run. - @return True if the server was started successfully, false otherwise. - @sa listen(const QHostAddress&, quint16) */ - bool listen(quint16 port); - - quint16 serverPort(); - - /// Stop the server and listening for new connections. - void close(); - - Q_SIGNALS: - /// Emitted when a client makes a new request to the server. - - /** The slot should use the given @c request and @c response - objects to communicate with the client. - @param request New incoming request. - @param response Response object to the request. */ - void newRequest(QSharedPointer request, QSharedPointer response); - - private Q_SLOTS: - void newConnection(); - - private: - QTcpServer* m_tcpServer; -}; - -#endif diff --git a/src/external/qhttpserver/qhttpserverapi.h b/src/external/qhttpserver/qhttpserverapi.h deleted file mode 100644 index 2ba7015..0000000 --- a/src/external/qhttpserver/qhttpserverapi.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_SERVER_API -#define Q_HTTP_SERVER_API - -#include - -//#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) -//#ifdef Q_OS_WIN -//// Define to export or import depending if we are building or using the library. -//// QHTTPSERVER_EXPORT should only be defined when building. -//#if defined(QHTTPSERVER_EXPORT) -//#define QHTTPSERVER_API __declspec(dllexport) -//#else -//#define QHTTPSERVER_API __declspec(dllimport) -//#endif -//#else -//// Define empty for other platforms -//#define QHTTPSERVER_API -//#endif -//#else -//#ifdef Q_WS_WIN -//// Define to export or import depending if we are building or using the library. -//// QHTTPSERVER_EXPORT should only be defined when building. -//#if defined(QHTTPSERVER_EXPORT) -//#define QHTTPSERVER_API __declspec(dllexport) -//#else -//#define QHTTPSERVER_API __declspec(dllimport) -//#endif -//#else -//// Define empty for other platforms -//#define QHTTPSERVER_API -//#endif -//#endif - -#define QHTTPSERVER_API -#endif diff --git a/src/external/qhttpserver/qhttpserverfwd.h b/src/external/qhttpserver/qhttpserverfwd.h deleted file mode 100644 index ca7c266..0000000 --- a/src/external/qhttpserver/qhttpserverfwd.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011-2014 Nikhil Marathe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef Q_HTTP_SERVER_FWD -#define Q_HTTP_SERVER_FWD - -#include -#include - -/*! - * A map of request or response headers - */ -typedef QHash HeaderHash; - -// QHttpServer -class QHttpServer; -class QHttpConnection; -class QHttpRequest; -class QHttpResponse; - -// Qt -class QTcpServer; -class QTcpSocket; - -// http_parser -struct http_parser_settings; -struct http_parser; - -#endif diff --git a/src/global/BuildHelper.cpp b/src/global/BuildHelper.cpp index d7b8d58..d494c21 100644 --- a/src/global/BuildHelper.cpp +++ b/src/global/BuildHelper.cpp @@ -4,6 +4,67 @@ #include "BuildHelper.h" +#ifdef Q_OS_ANDROID +#include "VersionNumber.h" + +#include +#include +#include +#endif + using namespace governikus; const char* BuildHelper::mDateTime = __DATE__ " / " __TIME__; + + +#ifdef Q_OS_ANDROID + +int BuildHelper::getVersionCode() +{ + if (VersionNumber::getApplicationVersion().isDeveloperVersion()) + { + return getVersionCode(QStringLiteral("com.governikus.ausweisapp2.dev")); + } + + return getVersionCode(QStringLiteral("com.governikus.ausweisapp2")); +} + + +int BuildHelper::getVersionCode(const QString& pPackageName) +{ + static int version_code = -1; + + if (version_code == -1) + { + QAndroidJniEnvironment env; + + auto context = QtAndroid::androidContext(); + auto manager = context.callObjectMethod("getPackageManager", + "()Landroid/content/pm/PackageManager;"); + + if (manager.isValid()) + { + const auto& str = QAndroidJniObject::fromString(pPackageName); + auto info = manager.callObjectMethod("getPackageInfo", + "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;", + str.object(), 0); + + if (info.isValid()) + { + version_code = info.getField("versionCode"); + } + } + + + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + + return version_code; +} + + +#endif diff --git a/src/global/BuildHelper.h b/src/global/BuildHelper.h index a664ba2..dea6694 100644 --- a/src/global/BuildHelper.h +++ b/src/global/BuildHelper.h @@ -6,6 +6,8 @@ #pragma once +#include + namespace governikus { @@ -23,6 +25,13 @@ class BuildHelper } +#ifdef Q_OS_ANDROID + static int getVersionCode(); + static int getVersionCode(const QString& pPackageName); + +#endif + + }; } /* namespace governikus */ diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index 6099d5c..7766c9d 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -2,3 +2,7 @@ ADD_PLATFORM_LIBRARY(AusweisAppGlobal) TARGET_INCLUDE_DIRECTORIES(AusweisAppGlobal SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR}) TARGET_LINK_LIBRARIES(AusweisAppGlobal Qt5::Core ${OPENSSL_LIBRARIES} ${OSX_SECURITY}) + +IF(ANDROID) + TARGET_LINK_LIBRARIES(AusweisAppGlobal Qt5::AndroidExtras) +ENDIF() diff --git a/src/global/CardReturnCode.cpp b/src/global/CardReturnCode.cpp new file mode 100644 index 0000000..8aa4e5c --- /dev/null +++ b/src/global/CardReturnCode.cpp @@ -0,0 +1,61 @@ +#include "CardReturnCode.h" +#include "moc_CardReturnCode.cpp" + +using namespace governikus; + + +GlobalStatus CardReturnCodeUtil::toGlobalStatus(CardReturnCode pCode) +{ + switch (pCode) + { + case CardReturnCode::OK: + return GlobalStatus::Code::No_Error; + + case CardReturnCode::UNDEFINED: + case CardReturnCode::UNKNOWN: + return GlobalStatus::Code::Unknown_Error; + + case CardReturnCode::CARD_NOT_FOUND: + return GlobalStatus::Code::Card_Not_Found; + + case CardReturnCode::COMMAND_FAILED: + case CardReturnCode::GET_CHALLENGE_FAILED: + return GlobalStatus::Code::Card_Communication_Error; + + case CardReturnCode::PROTOCOL_ERROR: + case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: + return GlobalStatus::Code::Card_Protocol_Error; + + case CardReturnCode::CANCELLATION_BY_USER: + return GlobalStatus::Code::Card_Cancellation_By_User; + + case CardReturnCode::INPUT_TIME_OUT: + return GlobalStatus::Code::Card_Input_TimeOut; + + case CardReturnCode::INVALID_PIN: + return GlobalStatus::Code::Card_Invalid_Pin; + + case CardReturnCode::INVALID_CAN: + return GlobalStatus::Code::Card_Invalid_Can; + + case CardReturnCode::INVALID_PUK: + return GlobalStatus::Code::Card_Invalid_Puk; + + case CardReturnCode::NEW_PIN_MISMATCH: + return GlobalStatus::Code::Card_NewPin_Mismatch; + + case CardReturnCode::NEW_PIN_INVALID_LENGTH: + return GlobalStatus::Code::Card_NewPin_Invalid_Length; + + case CardReturnCode::PIN_BLOCKED: + return GlobalStatus::Code::Card_Pin_Blocked; + + case CardReturnCode::PIN_NOT_BLOCKED: + return GlobalStatus::Code::Card_Pin_Not_Blocked; + + case CardReturnCode::PUK_INOPERATIVE: + return GlobalStatus::Code::Card_Puk_Blocked; + } + + return GlobalStatus::Code::Unknown_Error; +} diff --git a/src/global/ReturnCode.h b/src/global/CardReturnCode.h similarity index 50% rename from src/global/ReturnCode.h rename to src/global/CardReturnCode.h index e8a38b1..b28cd6c 100644 --- a/src/global/ReturnCode.h +++ b/src/global/CardReturnCode.h @@ -9,28 +9,42 @@ #pragma once #include "EnumHelper.h" +#include "GlobalStatus.h" namespace governikus { -defineEnumType(ReturnCode, +defineEnumType(CardReturnCode, UNDEFINED, OK, - NO_CARD, + CARD_NOT_FOUND, UNKNOWN, - TIME_OUT, - CAN_INVALID, - PIN_INVALID, - PUK_INVALID, + INPUT_TIME_OUT, + INVALID_CAN, + INVALID_PIN, + INVALID_PUK, COMMAND_FAILED, - GET_CHALLENGE_FAILED, + GET_CHALLENGE_FAILED, // TODO Check if still usefull CANCELLATION_BY_USER, - NEW_PINS_DONT_MATCH, - NEW_PIN_TOO_SHORT_OR_LONG, + NEW_PIN_MISMATCH, + NEW_PIN_INVALID_LENGTH, PIN_BLOCKED, PIN_NOT_BLOCKED, PUK_INOPERATIVE, PROTOCOL_ERROR, UNEXPECTED_TRANSMIT_STATUS) +class CardReturnCodeUtil +{ + private: + CardReturnCodeUtil() + { + + } + + + public: + static GlobalStatus toGlobalStatus(CardReturnCode pCode); +}; + } /* namespace governikus */ diff --git a/src/global/DeviceError.cpp b/src/global/DeviceError.cpp new file mode 100644 index 0000000..09c3803 --- /dev/null +++ b/src/global/DeviceError.cpp @@ -0,0 +1,41 @@ +/*! + * DeviceError.cpp + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "DeviceError.h" +#include "moc_DeviceError.cpp" + +namespace governikus +{ + +static int registerDeviceError = qRegisterMetaType("DeviceError"); + +namespace DeviceErrorUtil +{ +GlobalStatus toGlobalStatus(DeviceError pDeviceError) +{ + Q_UNUSED(registerDeviceError); + + switch (pDeviceError) + { + case DeviceError::DEVICE_CONNECTION_ERROR: + return GlobalStatus::Code::Workflow_Reader_Device_Connection_Error; + + case DeviceError::DEVICE_POWERED_OFF: + return GlobalStatus::Code::No_Error; + + case DeviceError::DEVICE_SCAN_ERROR: + return GlobalStatus::Code::Workflow_Reader_Device_Scan_Error; + + case DeviceError::UNKNOWN_ERROR: + return GlobalStatus::Code::Unknown_Error; + } + + return GlobalStatus::Code::Unknown_Error; +} + + +} +} diff --git a/src/global/DeviceError.h b/src/global/DeviceError.h new file mode 100644 index 0000000..436b8e7 --- /dev/null +++ b/src/global/DeviceError.h @@ -0,0 +1,28 @@ +/*! + * DeviceError.h + * + * \brief Global definitions for device error codes. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "EnumHelper.h" +#include "GlobalStatus.h" + +namespace governikus +{ + +defineEnumType(DeviceError, + UNKNOWN_ERROR, + DEVICE_CONNECTION_ERROR, + DEVICE_POWERED_OFF, + DEVICE_SCAN_ERROR) + +namespace DeviceErrorUtil +{ +GlobalStatus toGlobalStatus(DeviceError pDeviceError); +} /* namespace DeviceErrorUtil */ + +} /* namespace governikus */ diff --git a/src/global/EnumHelper.h b/src/global/EnumHelper.h index ba55305..d8948f0 100644 --- a/src/global/EnumHelper.h +++ b/src/global/EnumHelper.h @@ -10,11 +10,45 @@ #include #include +#include + namespace governikus { -template struct Enum {}; + +#define defineEnumOperators(enumName)\ + inline QDebug operator<<(QDebug pDbg, enumName pType)\ + {\ + QDebugStateSaver saver(pDbg);\ + return pDbg.noquote() << Enum::getName(pType);\ + }\ +\ + inline QString& operator+=(QString& pStr, enumName pType)\ + {\ + pStr += Enum::getName(pType);\ + return pStr;\ + }\ +\ + inline QString operator+(const QString& pStr, enumName pType)\ + {\ + return pStr + Enum::getName(pType);\ + }\ +\ + inline QString operator+(enumName pType, const QString& pStr)\ + {\ + return Enum::getName(pType) + pStr;\ + }\ +\ + inline bool operator==(std::underlying_type::type pType, enumName pName)\ + {\ + return static_cast::type>(pName) == pType;\ + }\ + inline bool operator!=(std::underlying_type::type pType, enumName pName)\ + {\ + return !(pType == pName);\ + } + #define defineTypedEnumType(enumName, enumType, ...)\ class Enum##enumName\ @@ -31,172 +65,122 @@ template struct Enum {}; };\ \ Q_ENUM(enumName)\ -\ - static inline QMetaEnum getMetaEnum()\ - {\ - return QMetaEnum::fromType();\ - }\ - static QString getName()\ - {\ - return QString::fromLatin1(getMetaEnum().name());\ - }\ - static QString getName(enumName pType)\ - {\ - const char* name = getMetaEnum().valueToKey(static_cast(pType));\ - if (name == nullptr)\ - {\ - return QStringLiteral("UNKNOWN(0x%1)").arg(static_cast(pType), 0, 16);\ - }\ - else\ - {\ - return QString::fromLatin1(name);\ - }\ - }\ -\ - static int getCount()\ - {\ - return getMetaEnum().keyCount();\ - }\ -\ - static const QVector& getList()\ - {\ - static QVector list;\ - if (list.isEmpty())\ - {\ - const QMetaEnum metaEnum = getMetaEnum();\ - list.reserve(metaEnum.keyCount());\ - for (int i = 0; i < metaEnum.keyCount(); ++i)\ - {\ - list.push_back(static_cast(metaEnum.value(i)));\ - }\ - }\ - return list;\ - }\ - static enumName fromString(const char* pValue, enumName pDefault)\ - {\ - bool ok = false;\ - int key = getMetaEnum().keyToValue(pValue, &ok);\ - if (ok)\ - {\ - return static_cast(key);\ - }\ - return pDefault;\ - }\ - static enumName fromString(const QString &pValue, enumName pDefault)\ - {\ - return fromString(pValue.toUtf8().constData(), pDefault);\ - }\ - static bool isValue(int pValue)\ - {\ - return getMetaEnum().valueToKey(pValue) != nullptr;\ - }\ - static bool isValue(uchar pValue)\ - {\ - return isValue(static_cast(pValue));\ - }\ - static bool isValue(char pValue)\ - {\ - return isValue(static_cast(pValue));\ - }\ - static enumType getValue(enumName pType)\ - {\ - return static_cast(pType);\ - }\ };\ \ - typedef Enum##enumName::enumName enumName;\ + using enumName = Enum##enumName::enumName;\ \ - template<> struct Enum {\ - static QString getName()\ - {\ - return Enum##enumName::getName();\ - }\ -\ - static QString getName(enumName pType)\ - {\ - return Enum##enumName::getName(pType);\ - }\ -\ - static int getCount()\ - {\ - return Enum##enumName::getCount();\ - }\ - static const QVector& getList()\ - {\ - return Enum##enumName::getList();\ - }\ - static enumName fromString(const char* pValue, enumName pDefault)\ - {\ - return Enum##enumName::fromString(pValue, pDefault);\ - }\ - static enumName fromString(const QString &pValue, enumName pDefault)\ - {\ - return Enum##enumName::fromString(pValue, pDefault);\ - }\ - static bool isValue(int pValue)\ - {\ - return Enum##enumName::isValue(pValue);\ - }\ - static bool isValue(uchar pValue)\ - {\ - return Enum##enumName::isValue(pValue);\ - }\ - static bool isValue(char pValue)\ - {\ - return Enum##enumName::isValue(pValue);\ - }\ - static enumType getValue(enumName pType)\ - {\ - return Enum##enumName::getValue(pType);\ - }\ - };\ -\ - inline QDebug operator<<(QDebug pDbg, enumName pType)\ - {\ - pDbg << Enum##enumName::getName(pType);\ - return pDbg;\ - }\ -\ - inline QString& operator+=(QString& pStr, enumName pType)\ - {\ - pStr += Enum##enumName::getName(pType);\ - return pStr;\ - }\ -\ - inline QString operator+(const QString& pStr, enumName pType)\ - {\ - return pStr + Enum##enumName::getName(pType);\ - }\ -\ - inline QString operator+(enumName pType, const QString& pStr)\ - {\ - return Enum##enumName::getName(pType) + pStr;\ - }\ -\ - inline bool operator==(enumType pType, enumName pName)\ - {\ - return static_cast(pName) == pType;\ - }\ - inline bool operator!=(enumType pType, enumName pName)\ - {\ - return !(pType == pName);\ - } + defineEnumOperators(enumName) #define defineEnumType(enumName, ...) defineTypedEnumType(enumName, int, __VA_ARGS__) -template inline QString getEnumName(T pType) + +template class Enum +{ + using EnumBaseTypeT = typename std::underlying_type::type; + + private: + Enum(); + Q_DISABLE_COPY(Enum) + + public: + static inline QMetaEnum getQtEnumMetaEnum() + { + return QMetaEnum::fromType(); + } + + + static QLatin1String getName() + { + return QLatin1String(getQtEnumMetaEnum().name()); + } + + + static QLatin1String getName(EnumTypeT pType) + { + const int value = static_cast(pType); + const char* name = getQtEnumMetaEnum().valueToKey(value); + if (Q_UNLIKELY(name == nullptr)) + { + qCritical().noquote().nospace() << "CRITICAL CONVERSION MISMATCH: UNKNOWN 0x" << QString::number(value, 16); + return QLatin1String(); + } + + return QLatin1String(name); + } + + + static int getCount() + { + return getQtEnumMetaEnum().keyCount(); + } + + + static const QVector& getList() + { + static QVector list; + if (list.isEmpty()) + { + const QMetaEnum metaEnum = getQtEnumMetaEnum(); + list.reserve(metaEnum.keyCount()); + for (int i = 0; i < metaEnum.keyCount(); ++i) + { + list.push_back(static_cast(metaEnum.value(i))); + } + } + return list; + } + + + static EnumTypeT fromString(const char* pValue, EnumTypeT pDefault) + { + bool ok = false; + int key = getQtEnumMetaEnum().keyToValue(pValue, &ok); + if (ok) + { + return static_cast(key); + } + return pDefault; + } + + + static EnumTypeT fromString(const QString& pValue, EnumTypeT pDefault) + { + return fromString(pValue.toUtf8().constData(), pDefault); + } + + + static bool isValue(int pValue) + { + return getQtEnumMetaEnum().valueToKey(pValue) != nullptr; + } + + + static bool isValue(uchar pValue) + { + return isValue(static_cast(pValue)); + } + + + static bool isValue(char pValue) + { + return isValue(static_cast(pValue)); + } + + + static EnumBaseTypeT getValue(EnumTypeT pType) + { + return static_cast(pType); + } + + +}; + + +template inline QLatin1String getEnumName(T pType) { return Enum::getName(pType); } -template inline QByteArray getEnumByteValue(T pType) -{ - QByteArray data; - data.append(Enum::getValue(pType)); - return data; -} - - } /* namespace governikus */ diff --git a/src/global/EnvHolder.cpp b/src/global/EnvHolder.cpp new file mode 100644 index 0000000..6f57757 --- /dev/null +++ b/src/global/EnvHolder.cpp @@ -0,0 +1,115 @@ +/* + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "EnvHolder.h" + +#include "SingletonHelper.h" + +#include + +using namespace governikus; + +defineSingleton(EnvHolder) + +EnvHolder::EnvHolder() +{ +} + + +EnvHolder::~EnvHolder() +{ +} + + +EnvHolder& EnvHolder::getInstance() +{ + return *Instance; +} + + +void* EnvHolder::getStoredSingleton(EnvHolder::Identifier pId) const +{ + switch (mTypeInfo.value(pId, Type::UNDEFINED)) + { + case Type::OWNERSHIP: + return mInstancesOwnership.value(pId).get(); + + case Type::UNMANAGED: + return mInstancesUnmanaged.value(pId); + + case Type::UNDEFINED: + return nullptr; + } + + return nullptr; +} + + +#ifndef QT_NO_DEBUG + +void EnvHolder::clear() +{ + auto& holder = getInstance(); + holder.mInstancesOwnership.clear(); + holder.mInstancesUnmanaged.clear(); + holder.mTypeInfo.clear(); + holder.mInstancesCreator.clear(); + holder.mSharedInstances.clear(); +} + + +void EnvHolder::set(const QMetaObject& pMetaObject, void* pObject, bool pOwnership) +{ + auto className = pMetaObject.className(); + auto& holder = getInstance(); + if (pObject) + { + qDebug() << "Add instance:" << className; + holder.mInstancesOwnership.remove(className); + holder.mInstancesUnmanaged.insert(className, pObject); + holder.mTypeInfo.insert(className, pOwnership ? Type::OWNERSHIP : Type::UNMANAGED); + } + else + { + qDebug() << "Remove instance:" << className; + holder.mInstancesOwnership.remove(className); + holder.mInstancesUnmanaged.remove(className); + holder.mTypeInfo.remove(className); + } +} + + +void governikus::EnvHolder::setCreator(const QMetaObject& pMetaObject, const std::function& pFunc) +{ + auto className = pMetaObject.className(); + auto& holder = getInstance(); + if (pFunc) + { + holder.mInstancesCreator.insert(className, pFunc); + } + else + { + holder.mInstancesCreator.remove(className); + } +} + + +void EnvHolder::setShared(const QMetaObject& pMetaObject, QSharedPointer pObject) +{ + auto className = pMetaObject.className(); + auto& holder = getInstance().mSharedInstances; + if (pObject) + { + qDebug() << "Add shared instance:" << className; + holder.insert(className, pObject.toWeakRef()); + } + else + { + qDebug() << "Remove shared instance:" << className; + holder.remove(className); + } +} + + +#endif diff --git a/src/global/EnvHolder.h b/src/global/EnvHolder.h new file mode 100644 index 0000000..373e268 --- /dev/null +++ b/src/global/EnvHolder.h @@ -0,0 +1,181 @@ +/* + * \brief Runtime environment holder for all Singletons. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace governikus +{ + +template bool singleton(T&); +template T* createNewObject(Args&& ... pArgs); + +class EnvHolder +{ + private: + Q_DISABLE_COPY(EnvHolder) + + enum class Type + { + UNDEFINED, + OWNERSHIP, + UNMANAGED + }; + + using Identifier = const char*; + QMap mTypeInfo; + QMap mInstancesUnmanaged; + QMap > mInstancesOwnership; + QMap > mSharedInstances; +#ifndef QT_NO_DEBUG + QMap > mInstancesCreator; +#endif + + static EnvHolder& getInstance(); + + template + typename std::enable_if::value&& std::is_destructible::value, T*>::type storeSingleton(Identifier pId) + { + static_assert(std::has_virtual_destructor::value, "Destructor must be virtual"); + + T* obj = nullptr; + bool ownership = singleton(obj); + Q_ASSERT(obj); + mTypeInfo.insert(pId, ownership ? Type::OWNERSHIP : Type::UNMANAGED); + if (ownership) + { + mInstancesOwnership.insert(pId, std::shared_ptr(obj)); + } + else + { + mInstancesUnmanaged.insert(pId, obj); + } + return obj; + } + + + template + typename std::enable_if::value, T*>::type storeSingleton(Identifier pId) + { + T* obj = &T::getInstance(); + mInstancesUnmanaged.insert(pId, obj); + mTypeInfo.insert(pId, Type::UNMANAGED); + return obj; + } + + + template + typename std::enable_if::value, T*>::type storeSingleton(Identifier pId) + { + T* obj = new T; + mInstancesOwnership.insert(pId, std::shared_ptr(obj)); + mTypeInfo.insert(pId, Type::OWNERSHIP); + return obj; + } + + + void* getStoredSingleton(Identifier pId) const; + + template + inline T* getSingleton() + { + Identifier id = T::staticMetaObject.className(); + void* obj = getStoredSingleton(id); + + if (!obj) + { + obj = storeSingleton(id); + } + + return static_cast(obj); + } + + + template + inline typename std::enable_if::value, T*>::type newObject(Args&& ... pArgs) const + { + auto obj = createNewObject(std::forward(pArgs) ...); + Q_ASSERT(obj); + return obj; + } + + + template + inline typename std::enable_if::value, T*>::type newObject(Args&& ... pArgs) const + { + return new T(std::forward(pArgs) ...); + } + + + template + inline T* createObject(Args&& ... pArgs) const + { +#ifndef QT_NO_DEBUG + Identifier id = T::staticMetaObject.className(); + auto creator = mInstancesCreator.value(id); + + if (creator) + { + return static_cast(creator()); + } +#endif + return newObject(std::forward(pArgs) ...); + } + + + protected: + EnvHolder(); + ~EnvHolder(); + + public: + template + static T* get() + { + return getInstance().getSingleton(); + } + + + template + static T* create(Args&& ... pArgs) + { + return getInstance().createObject(std::forward(pArgs) ...); + } + + + template + static QSharedPointer shared() + { + auto& holder = getInstance().mSharedInstances; + const auto* className = T::staticMetaObject.className(); + + QSharedPointer shared = qSharedPointerCast(holder.value(className)); + if (!shared) + { + shared = QSharedPointer::create(); + holder.insert(className, shared.toWeakRef()); + } + + return shared; + } + + +#ifndef QT_NO_DEBUG + static void clear(); + static void set(const QMetaObject& pMetaObject, void* pObject = nullptr, bool pOwnership = false); + static void setCreator(const QMetaObject& pMetaObject, const std::function& pFunc); + static void setShared(const QMetaObject& pMetaObject, QSharedPointer pObject = QSharedPointer()); +#endif + +}; + +} /* namespace governikus */ diff --git a/src/global/ErrorMessage.cpp b/src/global/ErrorMessage.cpp deleted file mode 100644 index 6641ace..0000000 --- a/src/global/ErrorMessage.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "ErrorMessage.h" - - -using namespace governikus; - -const char* const ErrorMessage::CONTACT_SUPPORT = QT_TR_NOOP("An error occurred. Please contact our support at AusweisApp2 Support."); - -const QMap ErrorMessage::mMessages = { - { - ErrorMessageId::WRONG_PARAMETER_INVOCATION, - QT_TR_NOOP("Application was invoked with wrong parameters.") - }, - { - ErrorMessageId::SSL_ERROR, - QT_TR_NOOP("It wasn't possible to connect to the server: a secure connection could not be established.") - }, - { - ErrorMessageId::FORMAT_ERROR, - QT_TR_NOOP("It wasn't possible to connect to the server: the server sent a non-standard response.") - }, - { - ErrorMessageId::TIME_OUT, - QT_TR_NOOP("Establishing a connection is taking too long.") - }, - { - ErrorMessageId::PROXY_ERROR, - QT_TR_NOOP("Establishing a connection via the proxy did not succeed.") - } -}; - -const QMap ErrorMessage::mAdvices = { - { - ErrorMessageId::WRONG_PARAMETER_INVOCATION, - CONTACT_SUPPORT - }, - { - ErrorMessageId::SSL_ERROR, - CONTACT_SUPPORT - }, - { - ErrorMessageId::FORMAT_ERROR, - CONTACT_SUPPORT - }, - { - ErrorMessageId::TIME_OUT, - CONTACT_SUPPORT - }, - { - ErrorMessageId::PROXY_ERROR, - CONTACT_SUPPORT - } -}; - -QString ErrorMessage::toString(ErrorMessageId pId) -{ - return tr(mAdvices.value(pId, nullptr)); -} diff --git a/src/global/ErrorMessage.h b/src/global/ErrorMessage.h deleted file mode 100644 index 6b06c44..0000000 --- a/src/global/ErrorMessage.h +++ /dev/null @@ -1,44 +0,0 @@ -/*! - * \brief Localized error messages to be used in different workflow steps. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "EnumHelper.h" - -#include -#include - -namespace governikus -{ - -defineEnumType(ErrorMessageId, - WRONG_PARAMETER_INVOCATION, - SSL_ERROR, - FORMAT_ERROR, - TIME_OUT, - PROXY_ERROR) - - -class ErrorMessage -{ - Q_DECLARE_TR_FUNCTIONS(governikus::ErrorMessage) - - public: - static QString toString(ErrorMessageId pId); - - static const char* const CONTACT_SUPPORT; - - private: - ErrorMessage() = delete; - - ~ErrorMessage() = delete; - - static const QMap mMessages; - static const QMap mAdvices; -}; - - -} /* namespace governikus */ diff --git a/src/global/GlobalStatus.cpp b/src/global/GlobalStatus.cpp new file mode 100644 index 0000000..29066f3 --- /dev/null +++ b/src/global/GlobalStatus.cpp @@ -0,0 +1,300 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "GlobalStatus.h" + +#include + +#define MESSAGE_SORRY "Sorry, that should not have happened! Please contact the support team." + +using namespace governikus; + + +const QString GlobalStatus::getExternalInfo(int pIndex) const +{ + return d->mExternalInformation.value(pIndex); +} + + +QString GlobalStatus::maskMessage(const QString& pMessage, const bool pMask) +{ + return pMask ? tr("An error occurred. Please contact our support at AusweisApp2 Support.") : pMessage; +} + + +bool GlobalStatus::operator ==(const GlobalStatus& pOther) const +{ + return *d == *pOther.d; +} + + +bool GlobalStatus::is(const GlobalStatus::Code pStatusCode) const +{ + return d->mStatusCode == pStatusCode; +} + + +GlobalStatus::Code GlobalStatus::getStatusCode() const +{ + return d->mStatusCode; +} + + +GlobalStatus::operator GlobalStatus::Code() const +{ + return getStatusCode(); +} + + +QString GlobalStatus::toErrorDescription(const bool pSimplifiedVersion) const +{ + switch (d->mStatusCode) + { + case Code::Workflow_Communication_Missing_Redirect_Url: + return QString(); + + case Code::No_Error: + return tr("No error occurred."); + + case Code::Unknown_Error: + return tr("An unexpected error has occurred during processing."); + + case Code::Workflow_Card_Removed: + return tr("The ID card has been removed. The process is aborted."); + + case Code::Workflow_Cannot_Confirm_IdCard_Authenticity: + return tr("The authenticity of your ID card could not be confirmed."); + + case Code::Workflow_Unknown_Paos_Form_EidServer: + return maskMessage(tr("The program received an unknown message from the server."), pSimplifiedVersion); + + case Code::Workflow_Unexpected_Message_From_EidServer: + return maskMessage(tr("The program received an unexpected message from the server."), pSimplifiedVersion); + + case Code::Workflow_Pin_Blocked_And_Puk_Objectionable: + return tr("After three wrong entries your PIN is blocked. Using the online identification function is no longer possible."); + + case Code::Workflow_Preverification_Developermode_Error: + return tr("Using the developer mode is only allowed in a test environment."); + + case Code::Workflow_Preverification_Error: + return maskMessage(tr("Pre-verification failed."), pSimplifiedVersion); + + case Code::Workflow_No_Unique_AtCvc: + return maskMessage(tr("No unique AT CVC"), pSimplifiedVersion); + + case Code::Workflow_No_Unique_DvCvc: + return maskMessage(tr("No unique DV CVC"), pSimplifiedVersion); + + case Code::Workflow_No_Permission_Error: + return tr("Authentication failed."); + + case Code::Workflow_Certificate_No_Description: + return maskMessage(tr("No certificate description available."), pSimplifiedVersion); + + case Code::Workflow_Certificate_No_Url_In_Description: + return maskMessage(tr("No subject url available in certificate description."), pSimplifiedVersion); + + case Code::Workflow_Certificate_Hash_Error: + return maskMessage(tr("The certificate description does not match the certificate."), pSimplifiedVersion); + + case Code::Workflow_Certificate_Sop_Error: + return maskMessage(tr("The subject URL in the certificate description and the TCToken URL don't satisfy the same origin policy."), pSimplifiedVersion); + + case Code::Workflow_Error_Page_Transmission_Error: + case Code::Workflow_Processing_Error: + case Code::Workflow_Redirect_Transmission_Error: + return maskMessage(getExternalInfo(), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_Establishment_Error: + return maskMessage(tr("Failed to establish secure connection"), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_Error_From_Server: + return maskMessage(tr("The program received an error from the server."), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_Hash_Not_In_Description: + case Code::Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description: + return maskMessage(tr("Hash of certificate not in certificate description"), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_No_Data_Received: + return maskMessage(tr("Received no data."), pSimplifiedVersion); + + case Code::Network_TimeOut: + case Code::Workflow_TrustedChannel_TimeOut: + return maskMessage(tr("Establishing a connection is taking too long."), pSimplifiedVersion); + + case Code::Network_Proxy_Error: + case Code::Workflow_TrustedChannel_Proxy_Error: + return maskMessage(tr("Establishing a connection via the proxy did not succeed."), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_Server_Format_Error: + return maskMessage(tr("It wasn't possible to connect to the server: the server sent a non-standard response."), pSimplifiedVersion); + + case Code::Network_Ssl_Establishment_Error: + case Code::Workflow_TrustedChannel_Ssl_Establishment_Error: + return maskMessage(tr("It wasn't possible to connect to the server: a secure connection could not be established."), pSimplifiedVersion); + + case Code::Workflow_Wrong_Parameter_Invocation: + return maskMessage(tr("Application was invoked with wrong parameters."), pSimplifiedVersion); + + case Code::Network_Other_Error: + case Code::Workflow_TrustedChannel_Other_Network_Error: + return maskMessage(tr("An unknown network error occurred."), pSimplifiedVersion); + + case Code::Workflow_Reader_Became_Inaccessible: + return tr("The selected card reader cannot be accessed anymore."); + + case Code::Workflow_Reader_Communication_Error: + return tr("An error occurred while communicating with the card reader."); + + case Code::Workflow_Server_Incomplete_Information_Provided: + return tr("The server provided no or incomplete information. Your personal data could not be read out."); + + case Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length: + return maskMessage(tr("Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length."), pSimplifiedVersion); + + case Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length: + case Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length: + return maskMessage(tr("Error while connecting to the server. The SSL certificate uses an unsupported key algorithm or length."), pSimplifiedVersion); + + case Code::Workflow_Network_Empty_Redirect_Url: + return maskMessage(tr("Empty redirect URL"), pSimplifiedVersion); + + case Code::Workflow_Network_Expected_Redirect: + return maskMessage(tr("Expected redirect, got %1").arg(getExternalInfo()), pSimplifiedVersion); + + case Code::Workflow_Network_Invalid_Scheme: + return maskMessage(tr("Invalid scheme: %1").arg(getExternalInfo()), pSimplifiedVersion); + + case Code::Workflow_Network_Malformed_Redirect_Url: + return maskMessage(tr("Malformed redirect URL: %1").arg(getExternalInfo()), pSimplifiedVersion); + + case Code::Workflow_Cancellation_By_User: + case Code::Card_Cancellation_By_User: + return tr("The process was cancelled by the user."); + + case Code::Paos_Unexpected_Warning: + case Code::Paos_Error_AL_Unknown_Error: + case Code::Paos_Error_AL_No_Permission: + case Code::Paos_Error_AL_Internal_Error: + case Code::Paos_Error_AL_Parameter_Error: + case Code::Paos_Error_AL_Unkown_API_Function: + case Code::Paos_Error_AL_Not_Initialized: + case Code::Paos_Error_AL_Warning_Connection_Disconnected: + case Code::Paos_Error_AL_Session_Terminated_Warning: + case Code::Paos_Error_AL_Communication_Error: + case Code::Paos_Error_DP_Timeout_Error: + case Code::Paos_Error_DP_Unknown_Channel_Handle: + case Code::Paos_Error_DP_Communication_Error: + case Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed: + case Code::Paos_Error_DP_Unknown_Protocol: + case Code::Paos_Error_DP_Unknown_Cipher_Suite: + case Code::Paos_Error_DP_Unknown_Webservice_Binding: + case Code::Paos_Error_DP_Node_Not_Reachable: + case Code::Paos_Error_IFDL_Timeout_Error: + case Code::Paos_Error_IFDL_InvalidSlotHandle: + case Code::Paos_Error_IFDL_CancellationByUser: + case Code::Paos_Error_KEY_KeyGenerationNotPossible: + case Code::Paos_Error_SAL_Cancellation_by_User: + case Code::Paos_Error_SAL_CertificateChainInterrupted: + case Code::Paos_Error_SAL_Invalid_Key: + case Code::Paos_Error_SAL_SecurityConditionNotSatisfied: + case Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning: + case Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning: + case Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed: + return getExternalInfo(); + + case Code::Card_Input_TimeOut: + return tr("The maximum time was exceeded during input process."); + + case Code::Card_Not_Found: + return tr("Card does not exist"); + + case Code::Card_Communication_Error: + return tr("An error occurred while communicating with the ID card."); + + case Code::Card_Protocol_Error: + return maskMessage(tr("A protocol error has occurred."), pSimplifiedVersion); + + case Code::Card_Invalid_Pin: + return tr("The given PIN is invalid."); + + case Code::Card_Invalid_Can: + return tr("The given card access number (CAN) is invalid."); + + case Code::Card_Invalid_Puk: + return tr("The given PUK is invalid."); + + case Code::Card_Pin_Blocked: + return tr("The PIN was blocked after too many unsuccessful attempts."); + + case Code::Card_Pin_Not_Blocked: + return tr("The PIN is not blocked."); + + case Code::Card_Puk_Blocked: + return tr("The PUK was used ten times and is set inoperative. Please contact the competent authority that issued your ID document to unlock the PIN."); + + case Code::Card_NewPin_Mismatch: + return tr("The new PIN and the confirmation do not match."); + + case Code::Card_NewPin_Invalid_Length: + return tr("The length of the new PIN is not valid."); + + case Code::Workflow_Reader_Device_Connection_Error: + return tr("An error occurred while connecting to a reader device."); + + case Code::Workflow_Reader_Device_Scan_Error: + return tr("An error occurred while scanning for reader devices."); + + case Code::RemoteReader_CloseCode_NormalClose: + return tr("The remote reader connection was closed properly."); + + case Code::RemoteReader_CloseCode_AbnormalClose: + return tr("The remote card reader connection was not closed properly."); + + case Code::RemoteReader_CloseCode_Undefined: + return tr("Undefined error code occured when the remote card reader connection was closed."); + } + + return QString(); +} + + +GlobalStatus::Origin GlobalStatus::getOrigin() const +{ + return d->mOrigin; +} + + +bool GlobalStatus::isOriginServer() const +{ + return d->mOrigin == Origin::Server; +} + + +bool GlobalStatus::isNoError() const +{ + return d->mStatusCode == Code::No_Error; +} + + +bool GlobalStatus::isError() const +{ + return !isNoError(); +} + + +bool GlobalStatus::isCancellationByUser() const +{ + return d->mStatusCode == Code::Workflow_Cancellation_By_User || + d->mStatusCode == Code::Card_Cancellation_By_User || + d->mStatusCode == Code::Paos_Error_SAL_Cancellation_by_User; +} + + +QDebug operator <<(QDebug pDbg, const GlobalStatus& pStatus) +{ + pDbg << pStatus.getStatusCode() << "|" << pStatus.toErrorDescription(); + return pDbg; +} diff --git a/src/global/GlobalStatus.h b/src/global/GlobalStatus.h new file mode 100644 index 0000000..49012d6 --- /dev/null +++ b/src/global/GlobalStatus.h @@ -0,0 +1,207 @@ +/*! + * \brief A global mapping for errors + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "EnumHelper.h" + +#include +#include + +namespace governikus +{ + + +class GlobalStatus +{ + Q_GADGET + Q_DECLARE_TR_FUNCTIONS(governikus::GlobalStatus) + + public: + enum class Code + { + Unknown_Error, + No_Error, + + Network_Ssl_Establishment_Error, + Network_TimeOut, + Network_Proxy_Error, + Network_Other_Error, + + Workflow_Communication_Missing_Redirect_Url, + Workflow_Cancellation_By_User, + Workflow_Card_Removed, + Workflow_Cannot_Confirm_IdCard_Authenticity, + Workflow_Unknown_Paos_Form_EidServer, + Workflow_Unexpected_Message_From_EidServer, + Workflow_Pin_Blocked_And_Puk_Objectionable, + Workflow_Preverification_Developermode_Error, + Workflow_Preverification_Error, + Workflow_No_Unique_AtCvc, + Workflow_No_Unique_DvCvc, + Workflow_No_Permission_Error, + Workflow_Certificate_No_Description, + Workflow_Certificate_No_Url_In_Description, + Workflow_Certificate_Hash_Error, + Workflow_Certificate_Sop_Error, + Workflow_Error_Page_Transmission_Error, + Workflow_Redirect_Transmission_Error, + Workflow_Processing_Error, + Workflow_TrustedChannel_Establishment_Error, + Workflow_TrustedChannel_Error_From_Server, + Workflow_TrustedChannel_Hash_Not_In_Description, + Workflow_TrustedChannel_No_Data_Received, + Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length, + Workflow_TrustedChannel_TimeOut, + Workflow_TrustedChannel_Proxy_Error, + Workflow_TrustedChannel_Ssl_Establishment_Error, + Workflow_TrustedChannel_Server_Format_Error, + Workflow_TrustedChannel_Other_Network_Error, + Workflow_Reader_Became_Inaccessible, + Workflow_Reader_Communication_Error, + Workflow_Server_Incomplete_Information_Provided, + Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length, + Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length, + Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description, + Workflow_Network_Empty_Redirect_Url, + Workflow_Network_Expected_Redirect, + Workflow_Network_Invalid_Scheme, + Workflow_Network_Malformed_Redirect_Url, + Workflow_Wrong_Parameter_Invocation, + + Paos_Unexpected_Warning, + + Paos_Error_AL_Unknown_Error, + Paos_Error_AL_No_Permission, + Paos_Error_AL_Internal_Error, + Paos_Error_AL_Parameter_Error, + Paos_Error_AL_Unkown_API_Function, + Paos_Error_AL_Not_Initialized, + Paos_Error_AL_Warning_Connection_Disconnected, + Paos_Error_AL_Session_Terminated_Warning, + Paos_Error_AL_Communication_Error, + Paos_Error_DP_Timeout_Error, + Paos_Error_DP_Unknown_Channel_Handle, + Paos_Error_DP_Communication_Error, + Paos_Error_DP_Trusted_Channel_Establishment_Failed, + Paos_Error_DP_Unknown_Protocol, + Paos_Error_DP_Unknown_Cipher_Suite, + Paos_Error_DP_Unknown_Webservice_Binding, + Paos_Error_DP_Node_Not_Reachable, + Paos_Error_IFDL_Timeout_Error, + Paos_Error_IFDL_InvalidSlotHandle, + Paos_Error_IFDL_CancellationByUser, + Paos_Error_KEY_KeyGenerationNotPossible, + Paos_Error_SAL_Cancellation_by_User, + Paos_Error_SAL_CertificateChainInterrupted, + Paos_Error_SAL_Invalid_Key, + Paos_Error_SAL_SecurityConditionNotSatisfied, + Paos_Error_SAL_MEAC_AgeVerificationFailedWarning, + Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning, + Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed, + + Workflow_Reader_Device_Connection_Error, + Workflow_Reader_Device_Scan_Error, + + Card_Not_Found, + Card_Communication_Error, + Card_Protocol_Error, + Card_Cancellation_By_User, + Card_Input_TimeOut, + Card_Invalid_Pin, + Card_Invalid_Can, + Card_Invalid_Puk, + Card_Pin_Blocked, + Card_Pin_Not_Blocked, + Card_Puk_Blocked, + Card_NewPin_Mismatch, + Card_NewPin_Invalid_Length, + + RemoteReader_CloseCode_NormalClose, + RemoteReader_CloseCode_AbnormalClose, + RemoteReader_CloseCode_Undefined + }; + + enum class Origin + { + Server, Client + }; + + Q_ENUM(Code) + Q_ENUM(Origin) + + private: + class InternalStatus + : public QSharedData + { + public: + const Code mStatusCode; + const QStringList mExternalInformation; + const Origin mOrigin; + + InternalStatus(Code pStatusCode, const QStringList& pExternalInformation, const Origin pOrigin) + : mStatusCode(pStatusCode) + , mExternalInformation(pExternalInformation) + , mOrigin(pOrigin) + { + + } + + + bool operator ==(const InternalStatus& pOther) const + { + return mStatusCode == pOther.mStatusCode && + mExternalInformation == pOther.mExternalInformation && + mOrigin == pOther.mOrigin; + } + + + }; + + QSharedDataPointer d; + const QString getExternalInfo(int pIndex = 0) const; + + static QString maskMessage(const QString& pMessage, const bool pMask); + + public: + GlobalStatus(Code pStatusCode, const QStringList& pExternalInformation = QStringList(), const Origin pOrigin = Origin::Client) + : d(new InternalStatus(pStatusCode, pExternalInformation, pOrigin)) + { + + } + + + GlobalStatus(Code pStatusCode, const QString& pExternalInformation, const Origin pOrigin = Origin::Client) + : GlobalStatus(pStatusCode, QStringList(pExternalInformation), pOrigin) + { + + } + + + bool operator ==(const GlobalStatus& pOther) const; + bool is(const Code pStatusCode) const; + + Code getStatusCode() const; + operator GlobalStatus::Code() const; + + QString toErrorDescription(const bool pSimplifiedVersion = false) const; + + Origin getOrigin() const; + bool isOriginServer() const; + + bool isNoError() const; + bool isError() const; + bool isCancellationByUser() const; +}; + +typedef GlobalStatus::Origin Origin; + +defineEnumOperators(GlobalStatus::Code) + +} /* namespace governikus */ + + +QDebug operator <<(QDebug pDbg, const governikus::GlobalStatus& pStatus); diff --git a/src/global/HashAlgorithmUtil.h b/src/global/HashAlgorithmUtil.h deleted file mode 100644 index 8a69322..0000000 --- a/src/global/HashAlgorithmUtil.h +++ /dev/null @@ -1,93 +0,0 @@ -/*! - * HashAlgorithmUtil.h - * - * \brief Simple utility class for QCryptographicHash::Algorithm. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -class test_HashAlgorithmUtil; - -namespace governikus -{ - -#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) - -class HashAlgorithmUtil -{ - HashAlgorithmUtil() = delete; - ~HashAlgorithmUtil() = delete; - - friend QDebug operator<<(QDebug, QCryptographicHash::Algorithm); - friend class::test_HashAlgorithmUtil; - - /*! - * Determines a readable name for the hash algorithm. - */ - static QString getName(QCryptographicHash::Algorithm pAlgorithm) - { - switch (pAlgorithm) - { - #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 - case QCryptographicHash::Md4: - return QStringLiteral("MD4"); - - case QCryptographicHash::Md5: - return QStringLiteral("MD5"); - - #endif - case QCryptographicHash::Sha1: - return QStringLiteral("SHA1"); - - #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 - case QCryptographicHash::Sha224: - return QStringLiteral("SHA224"); - - case QCryptographicHash::Sha256: - return QStringLiteral("SHA256"); - - case QCryptographicHash::Sha384: - return QStringLiteral("SHA384"); - - case QCryptographicHash::Sha512: - return QStringLiteral("SHA512"); - - case QCryptographicHash::Sha3_224: - return QStringLiteral("SHA3_224"); - - case QCryptographicHash::Sha3_256: - return QStringLiteral("SHA3_256"); - - case QCryptographicHash::Sha3_384: - return QStringLiteral("SHA3_384"); - - case QCryptographicHash::Sha3_512: - return QStringLiteral("SHA3_512"); - - #endif - } - - Q_UNREACHABLE(); - } - - -}; - - -inline QDebug operator<<(QDebug pDbg, QCryptographicHash::Algorithm pAlgo) -{ - QDebugStateSaver saver(pDbg); - pDbg.noquote() << HashAlgorithmUtil::getName(pAlgo); - return pDbg; -} - - -#endif - -} /* namespace governikus */ diff --git a/src/global/LanguageLoader.cpp b/src/global/LanguageLoader.cpp index c165d11..2e7e9e2 100644 --- a/src/global/LanguageLoader.cpp +++ b/src/global/LanguageLoader.cpp @@ -26,9 +26,9 @@ LanguageLoader::LanguageLoader() : mPath(FileDestination::getPath("translations")) , mTranslatorList() , mComponentList( -{ - QStringLiteral("ausweisapp2"), QStringLiteral("qt_help"), QStringLiteral("qt"), QStringLiteral("qtbase") -}) + { + QStringLiteral("ausweisapp2"), QStringLiteral("qtbase") + }) , mUsedLocale(mFallbackLanguage) { } @@ -202,7 +202,7 @@ bool LanguageLoader::loadTranslationFiles(const QLocale& pLocale) if (!translator.isNull()) { - mTranslatorList.append(translator); + mTranslatorList += translator; QCoreApplication::installTranslator(translator.data()); mUsedLocale = pLocale; loaded = true; diff --git a/src/global/LogCategories.cpp b/src/global/LogCategories.cpp index e2b6e44..15ce4b4 100644 --- a/src/global/LogCategories.cpp +++ b/src/global/LogCategories.cpp @@ -33,6 +33,11 @@ Q_LOGGING_CATEGORY(card_pcsc, "card_pcsc") */ Q_LOGGING_CATEGORY(card_nfc, "card_nfc") +/*! + * Logging category for all remote card relevant stuff + */ +Q_LOGGING_CATEGORY(card_remote, "card_remote") + /*! * Logging category for card drivers */ diff --git a/src/global/LogHandler.cpp b/src/global/LogHandler.cpp index 2c300ff..21389a7 100644 --- a/src/global/LogHandler.cpp +++ b/src/global/LogHandler.cpp @@ -24,24 +24,20 @@ LogHandler::LogHandler() , mEnvPattern(!qEnvironmentVariableIsEmpty("QT_MESSAGE_PATTERN")) , mFunctionFilenameSize(74) , mBacklogPosition(0) - , mDefaultMessagePattern(QStringLiteral("%{category} %{time yyyy.MM.dd hh:mm:ss.zzz} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif} %{function}(%{file}:%{line}) %{message}")) + , mMessagePattern(QStringLiteral("%{category} %{time yyyy.MM.dd hh:mm:ss.zzz} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif} %{function}(%{file}:%{line}) %{message}")) + , mDefaultMessagePattern(QStringLiteral("%{if-category}%{category}: %{endif}%{message}")) // as defined in qlogging.cpp , mLogFile(QDir::tempPath() + QStringLiteral("/AusweisApp2.XXXXXX.log")) // if you change value you need to adjust getOtherLogfiles() , mHandler(nullptr) , mFilePrefix("/src/") , mMutex() { - mLogFile.open(); - -#ifdef ENABLE_MESSAGE_PATTERN - qSetMessagePattern(mDefaultMessagePattern); -#endif } LogHandler::~LogHandler() { - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); if (mHandler) { qInstallMessageHandler(nullptr); @@ -58,15 +54,9 @@ LogHandler& LogHandler::getInstance() void LogHandler::init() { - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); if (!mHandler) { - static const char* envLoggingConf = "QT_LOGGING_CONF"; - if (!qEnvironmentVariableIsSet(envLoggingConf)) - { - qputenv(envLoggingConf, "./qtlogging.ini"); - } - mHandler = qInstallMessageHandler(&LogHandler::messageHandler); } } @@ -90,7 +80,7 @@ void LogHandler::logToFile(const QString& pOutput) QByteArray LogHandler::getBacklog() { - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); if (mLogFile.isOpen() && mLogFile.isReadable()) { @@ -107,7 +97,7 @@ QByteArray LogHandler::getBacklog() void LogHandler::resetBacklog() { - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); mBacklogPosition = mLogFile.pos(); } @@ -178,12 +168,12 @@ QByteArray LogHandler::formatFunction(const char* pFunction, const QByteArray& p QByteArray LogHandler::formatCategory(const char* pCategory) { static const char* PADDING = " "; - static const int MAX_LENGTH = qstrlen(PADDING); + static const int MAX_LENGTH = static_cast(qstrlen(PADDING)); QByteArray category(pCategory); if (category.length() > MAX_LENGTH) { - category = category.left(MAX_LENGTH - 3).append("..."); + category = category.left(MAX_LENGTH - 3) + QByteArrayLiteral("..."); } return category.append(PADDING, MAX_LENGTH - category.size()); } @@ -193,20 +183,20 @@ QString LogHandler::getPaddedLogMsg(const QMessageLogContext& pContext, const QS { const int paddingSize = (pContext.function == nullptr && pContext.file == nullptr && pContext.line == 0) ? mFunctionFilenameSize - 18 : // padding for nullptr == "unknown(unknown:0)" - mFunctionFilenameSize - 3 - qstrlen(pContext.function) - qstrlen(pContext.file) - QString::number(pContext.line).size(); + mFunctionFilenameSize - 3 - static_cast(qstrlen(pContext.function)) - static_cast(qstrlen(pContext.file)) - QString::number(pContext.line).size(); QString padding; padding.reserve(paddingSize + pMsg.size() + 3); padding.fill(QLatin1Char(' '), paddingSize); - padding.append(QStringLiteral(": ")); - padding.append(pMsg); + padding += QStringLiteral(": "); + padding += pMsg; return padding; } void LogHandler::handleMessage(QtMsgType pType, const QMessageLogContext& pContext, const QString& pMsg) { - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); QByteArray filename = formatFilename(pContext.file); QByteArray function = formatFunction(pContext.function, filename, pContext.line); @@ -215,16 +205,18 @@ void LogHandler::handleMessage(QtMsgType pType, const QMessageLogContext& pConte QMessageLogContext ctx; copyMessageLogContext(pContext, ctx, filename, function, category); -#ifdef ENABLE_MESSAGE_PATTERN - const QString msg = mEnvPattern ? pMsg : getPaddedLogMsg(ctx, pMsg); -#else - const QString& msg = pMsg; -#endif + const QString& message = mEnvPattern ? pMsg : getPaddedLogMsg(ctx, pMsg); - QString logMsg = qFormatLogMessage(pType, ctx, msg); - logMsg += QLatin1Char('\n'); + qSetMessagePattern(mMessagePattern); + QString logMsg = qFormatLogMessage(pType, ctx, message) + QLatin1Char('\n'); logToFile(logMsg); - mHandler(pType, ctx, msg); + +#ifdef ENABLE_MESSAGE_PATTERN + mHandler(pType, ctx, message); +#else + qSetMessagePattern(mDefaultMessagePattern); + mHandler(pType, ctx, pMsg); +#endif Q_EMIT fireRawLog(pMsg, QString::fromLatin1(pContext.category)); Q_EMIT fireLog(logMsg); @@ -238,7 +230,7 @@ bool LogHandler::copy(const QString& pDest) return false; } - QMutexLocker mutexLocker(&mMutex); + const QMutexLocker mutexLocker(&mMutex); return QFile::copy(mLogFile.fileName(), pDest); } diff --git a/src/global/LogHandler.h b/src/global/LogHandler.h index 439cd21..a61b910 100644 --- a/src/global/LogHandler.h +++ b/src/global/LogHandler.h @@ -28,7 +28,7 @@ class LogHandler const bool mEnvPattern; const int mFunctionFilenameSize; qint64 mBacklogPosition; - const QString mDefaultMessagePattern; + const QString mMessagePattern, mDefaultMessagePattern; QTemporaryFile mLogFile; QtMessageHandler mHandler; const QByteArray mFilePrefix; diff --git a/src/global/Randomizer.cpp b/src/global/Randomizer.cpp index 93f4971..45d22c6 100644 --- a/src/global/Randomizer.cpp +++ b/src/global/Randomizer.cpp @@ -39,9 +39,9 @@ template QList Randomizer::getEntropy() { QList entropy; - entropy += std::chrono::system_clock::now().time_since_epoch().count(); + entropy += static_cast(std::chrono::system_clock::now().time_since_epoch().count()); entropy += std::random_device()(); - entropy += qrand(); + entropy += static_cast(qrand()); UniversalBuffer buffer; if (RAND_bytes(buffer.data, sizeof(buffer.data))) @@ -61,7 +61,7 @@ template QList Randomizer::getEntropyWin() { QList entropy; -#ifdef Q_OS_WIN +#ifdef Q_OS_WIN32 UniversalBuffer buffer; HCRYPTPROV provider = 0; if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) diff --git a/src/global/ResourceLoader.cpp b/src/global/ResourceLoader.cpp index 7954e79..c9201b1 100644 --- a/src/global/ResourceLoader.cpp +++ b/src/global/ResourceLoader.cpp @@ -18,9 +18,9 @@ defineSingleton(ResourceLoader) ResourceLoader::ResourceLoader() : mFilenames( -{ - QStringLiteral("AusweisApp2.rcc") -}) + { + QStringLiteral("AusweisApp2.rcc") + }) , mLoadedResources() { } diff --git a/src/global/Result.cpp b/src/global/Result.cpp index c236f36..da420bd 100644 --- a/src/global/Result.cpp +++ b/src/global/Result.cpp @@ -7,7 +7,6 @@ #include "Result.h" #include "LanguageLoader.h" -#include "ReturnCodeUtil.h" #include #include @@ -23,131 +22,213 @@ const QMap Result::mMajorResults = { {Result::Major::Error, RESULTMAJOR "#error"} }; -const QMap Result::mMinorResults = { - {Result::Minor::AL_Unknown_Error, RESULTMINOR "/al/common#unknownError"}, - {Result::Minor::AL_No_Permission, RESULTMINOR "/al/common#noPermission"}, - {Result::Minor::AL_Internal_Error, RESULTMINOR "/al/common#internalError"}, - {Result::Minor::AL_Parameter_Error, RESULTMINOR "/al/common#parameterError"}, - {Result::Minor::AL_Unkown_API_Function, RESULTMINOR "/al/common#unkownAPIFunction"}, - {Result::Minor::AL_Not_Initialized, RESULTMINOR "/al/common#notInitialized"}, - {Result::Minor::AL_Warning_Connection_Disconnected, RESULTMINOR "/al/common#warningConnectionDisconnected"}, - {Result::Minor::AL_Session_Terminated_Warning, RESULTMINOR "/al/common#SessionTerminatedWarning"}, - {Result::Minor::AL_Communication_Error, RESULTMINOR "/al/common#communicationError"}, - {Result::Minor::DP_Timeout_Error, RESULTMINOR "/dp#timeout"}, - {Result::Minor::DP_Unknown_Channel_Handle, RESULTMINOR "/dp#unknownChannelHandle"}, - {Result::Minor::DP_Communication_Error, RESULTMINOR "/dp#communicationError"}, - {Result::Minor::DP_Trusted_Channel_Establishment_Failed, RESULTMINOR "/dp#trustedChannelEstablishmentFailed"}, - {Result::Minor::DP_Unknown_Protocol, RESULTMINOR "/dp#unknownProtocol"}, - {Result::Minor::DP_Unknown_Cipher_Suite, RESULTMINOR "/dp#unknownCipherSuite"}, - {Result::Minor::DP_Unknown_Webservice_Binding, RESULTMINOR "/dp#unknownWebserviceBinding"}, - {Result::Minor::DP_Node_Not_Reachable, RESULTMINOR "/dp#nodeNotReachable"}, - {Result::Minor::SAL_Cancellation_by_User, RESULTMINOR "/sal#cancellationByUser"}, - {Result::Minor::IFDL_Timeout_Error, RESULTMINOR "/ifdl/common#timeoutError"}, - {Result::Minor::IFDL_InvalidSlotHandle, RESULTMINOR "/ifdl/common#invalidSlotHandle"}, - {Result::Minor::IFDL_CancellationByUser, RESULTMINOR "/ifdl#cancellationByUser"}, - {Result::Minor::KEY_KeyGenerationNotPossible, RESULTMINOR "/il/key#keyGenerationNotPossible"}, - {Result::Minor::SAL_CertificateChainInterrupted, RESULTMINOR "/sal#certificateChainInterrupted"}, - {Result::Minor::SAL_Invalid_Key, RESULTMINOR "/sal#invalidKey"}, - {Result::Minor::SAL_SecurityConditionNotSatisfied, RESULTMINOR "/sal#securityConditionNotSatisfied"}, - {Result::Minor::SAL_MEAC_AgeVerificationFailedWarning, RESULTMINOR "/sal/mEAC#AgeVerificationFailedWarning"}, - {Result::Minor::SAL_MEAC_CommunityVerificationFailedWarning, RESULTMINOR "/sal/mEAC#CommunityVerificationFailedWarning"}, - {Result::Minor::SAL_MEAC_DocumentValidityVerificationFailed, RESULTMINOR "/sal/mEAC#DocumentValidityVerificationFailed"}, +// See TR-03112, section 4.2 for details about the codes +// AL -> Applicaction Layer +// DP -> Dispatcher +// IFDL -> Interface Device Layer +// KEY +// SAL -> Service Access Layer +const QMap Result::mMinorResults = { + {GlobalStatus::Code::Paos_Error_AL_Unknown_Error, RESULTMINOR "/al/common#unknownError"}, + {GlobalStatus::Code::Paos_Error_AL_No_Permission, RESULTMINOR "/al/common#noPermission"}, + {GlobalStatus::Code::Paos_Error_AL_Internal_Error, RESULTMINOR "/al/common#internalError"}, + {GlobalStatus::Code::Paos_Error_AL_Parameter_Error, RESULTMINOR "/al/common#parameterError"}, + {GlobalStatus::Code::Paos_Error_AL_Unkown_API_Function, RESULTMINOR "/al/common#unkownAPIFunction"}, + {GlobalStatus::Code::Paos_Error_AL_Not_Initialized, RESULTMINOR "/al/common#notInitialized"}, + {GlobalStatus::Code::Paos_Error_AL_Warning_Connection_Disconnected, RESULTMINOR "/al/common#warningConnectionDisconnected"}, + {GlobalStatus::Code::Paos_Error_AL_Session_Terminated_Warning, RESULTMINOR "/al/common#SessionTerminatedWarning"}, + {GlobalStatus::Code::Paos_Error_AL_Communication_Error, RESULTMINOR "/al/common#communicationError"}, + {GlobalStatus::Code::Paos_Error_DP_Timeout_Error, RESULTMINOR "/dp#timeout"}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Channel_Handle, RESULTMINOR "/dp#unknownChannelHandle"}, + {GlobalStatus::Code::Paos_Error_DP_Communication_Error, RESULTMINOR "/dp#communicationError"}, + {GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed, RESULTMINOR "/dp#trustedChannelEstablishmentFailed"}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Protocol, RESULTMINOR "/dp#unknownProtocol"}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Cipher_Suite, RESULTMINOR "/dp#unknownCipherSuite"}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Webservice_Binding, RESULTMINOR "/dp#unknownWebserviceBinding"}, + {GlobalStatus::Code::Paos_Error_DP_Node_Not_Reachable, RESULTMINOR "/dp#nodeNotReachable"}, + {GlobalStatus::Code::Paos_Error_IFDL_Timeout_Error, RESULTMINOR "/ifdl/common#timeoutError"}, + {GlobalStatus::Code::Paos_Error_IFDL_InvalidSlotHandle, RESULTMINOR "/ifdl/common#invalidSlotHandle"}, + {GlobalStatus::Code::Paos_Error_IFDL_CancellationByUser, RESULTMINOR "/ifdl#cancellationByUser"}, + {GlobalStatus::Code::Paos_Error_KEY_KeyGenerationNotPossible, RESULTMINOR "/il/key#keyGenerationNotPossible"}, + {GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User, RESULTMINOR "/sal#cancellationByUser"}, + {GlobalStatus::Code::Paos_Error_SAL_CertificateChainInterrupted, RESULTMINOR "/sal#certificateChainInterrupted"}, + {GlobalStatus::Code::Paos_Error_SAL_Invalid_Key, RESULTMINOR "/sal#invalidKey"}, + {GlobalStatus::Code::Paos_Error_SAL_SecurityConditionNotSatisfied, RESULTMINOR "/sal#securityConditionNotSatisfied"}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning, RESULTMINOR "/sal/mEAC#AgeVerificationFailedWarning"}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning, RESULTMINOR "/sal/mEAC#CommunityVerificationFailedWarning"}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed, RESULTMINOR "/sal/mEAC#DocumentValidityVerificationFailed"}, }; -const QMap Result::mMinorDescriptions = { - {Result::Minor::AL_Unknown_Error, QT_TR_NOOP("An unexpected error has occurred during processing.")}, - {Result::Minor::AL_No_Permission, QT_TR_NOOP("Use of the function by the client application is not permitted.")}, - {Result::Minor::AL_Internal_Error, QT_TR_NOOP("An internal error has occurred during processing.")}, - {Result::Minor::AL_Parameter_Error, QT_TR_NOOP("There was some problem with a provided or omitted parameter.")}, - {Result::Minor::AL_Unkown_API_Function, QT_TR_NOOP("The API function is unknown.")}, - {Result::Minor::AL_Not_Initialized, QT_TR_NOOP("The framework or layer has not been initialized.")}, - {Result::Minor::AL_Warning_Connection_Disconnected, QT_TR_NOOP("The active session has been terminated.")}, - {Result::Minor::AL_Session_Terminated_Warning, QT_TR_NOOP("The active session has been terminated.")}, - {Result::Minor::AL_Communication_Error, QT_TR_NOOP("A Communication error occurred during processing.")}, - {Result::Minor::DP_Timeout_Error, QT_TR_NOOP("The operation was terminated as the set time was exceeded.")}, - {Result::Minor::DP_Unknown_Channel_Handle, QT_TR_NOOP("The operation was aborted as an invalid channel handle was used.")}, - {Result::Minor::DP_Communication_Error, QT_TR_NOOP("A Communication error occurred during processing.")}, - {Result::Minor::DP_Trusted_Channel_Establishment_Failed, QT_TR_NOOP("A trusted channel could not be opened.")}, - {Result::Minor::DP_Unknown_Protocol, QT_TR_NOOP("The operation was aborted as an unknown protocol was used.")}, - {Result::Minor::DP_Unknown_Cipher_Suite, QT_TR_NOOP("The operation was aborted as an unknown cipher suite was used.")}, - {Result::Minor::DP_Unknown_Webservice_Binding, QT_TR_NOOP("The operation was aborted as an unknown web service binding was used.")}, - {Result::Minor::DP_Node_Not_Reachable, QT_TR_NOOP("A Communication error occurred during processing.")}, - {Result::Minor::SAL_Cancellation_by_User, QT_TR_NOOP("The operation was aborted due to cancellation by user.")}, - {Result::Minor::IFDL_Timeout_Error, QT_TR_NOOP("The operation was terminated as the set time was exceeded.")}, - {Result::Minor::KEY_KeyGenerationNotPossible, QT_TR_NOOP("Signature certificate key generation is not possible.")}, - {Result::Minor::SAL_CertificateChainInterrupted, QT_TR_NOOP("One or more certificate checks failed. The operation will be aborted due to security reasons.")}, - {Result::Minor::SAL_Invalid_Key, QT_TR_NOOP("This action cannot be performed. The online identification function of your ID card is deactivated. Please contact your citizen centre to activate the online identification function.")}, - {Result::Minor::SAL_SecurityConditionNotSatisfied, QT_TR_NOOP("The authenticity of your ID card could not be verified. Please make sure that you are using a genuine ID card. Please note that test applications require the use of a test ID card.")}, - {Result::Minor::SAL_MEAC_AgeVerificationFailedWarning, QT_TR_NOOP("The age verification failed.")}, - {Result::Minor::SAL_MEAC_CommunityVerificationFailedWarning, QT_TR_NOOP("The community verification failed.")}, - {Result::Minor::SAL_MEAC_DocumentValidityVerificationFailed, QT_TR_NOOP("The ID card is invalid or disabled.")}, -}; + +Result Result::fromStatus(const GlobalStatus& pStatus) +{ + switch (pStatus) + { + case GlobalStatus::Code::Unknown_Error: + case GlobalStatus::Code::Paos_Unexpected_Warning: + case GlobalStatus::Code::Paos_Error_AL_Unknown_Error: + break; + + case GlobalStatus::Code::No_Error: + return createOk(); + + case GlobalStatus::Code::Workflow_Card_Removed: + case GlobalStatus::Code::Paos_Error_IFDL_CancellationByUser: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_IFDL_CancellationByUser, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_Preverification_Developermode_Error: + case GlobalStatus::Code::Workflow_Preverification_Error: + case GlobalStatus::Code::Workflow_No_Unique_AtCvc: + case GlobalStatus::Code::Workflow_No_Unique_DvCvc: + case GlobalStatus::Code::Paos_Error_SAL_CertificateChainInterrupted: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_CertificateChainInterrupted, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_Certificate_No_Description: + case GlobalStatus::Code::Workflow_Certificate_No_Url_In_Description: + case GlobalStatus::Code::Workflow_Certificate_Hash_Error: + case GlobalStatus::Code::Workflow_Certificate_Sop_Error: + case GlobalStatus::Code::Paos_Error_AL_Parameter_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Parameter_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error: + case GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server: + case GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description: + case GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received: + case GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length: + case GlobalStatus::Code::Workflow_TrustedChannel_TimeOut: + case GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error: + case GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error: + case GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error: + case GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error: + case GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_Cancellation_By_User: + case GlobalStatus::Code::Card_Cancellation_By_User: + case GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_No_Permission_Error: + case GlobalStatus::Code::Paos_Error_AL_No_Permission: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_No_Permission, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url: + case GlobalStatus::Code::Workflow_Error_Page_Transmission_Error: + case GlobalStatus::Code::Workflow_Redirect_Transmission_Error: + case GlobalStatus::Code::Workflow_Processing_Error: + case GlobalStatus::Code::Workflow_Reader_Became_Inaccessible: + case GlobalStatus::Code::Workflow_Reader_Communication_Error: + case GlobalStatus::Code::Workflow_Reader_Device_Connection_Error: + case GlobalStatus::Code::Workflow_Reader_Device_Scan_Error: + case GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided: + case GlobalStatus::Code::Network_Ssl_Establishment_Error: + case GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length: + case GlobalStatus::Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length: + case GlobalStatus::Code::Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description: + case GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url: + case GlobalStatus::Code::Workflow_Network_Expected_Redirect: + case GlobalStatus::Code::Workflow_Network_Invalid_Scheme: + case GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url: + case GlobalStatus::Code::Network_TimeOut: + case GlobalStatus::Code::Network_Proxy_Error: + case GlobalStatus::Code::Network_Other_Error: + case GlobalStatus::Code::Workflow_Wrong_Parameter_Invocation: + case GlobalStatus::Code::Card_Invalid_Pin: + case GlobalStatus::Code::Card_Invalid_Can: + case GlobalStatus::Code::Card_Invalid_Puk: + case GlobalStatus::Code::Card_Puk_Blocked: + case GlobalStatus::Code::Paos_Error_AL_Communication_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Communication_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Card_Not_Found: + case GlobalStatus::Code::Card_Communication_Error: + case GlobalStatus::Code::Card_Input_TimeOut: + case GlobalStatus::Code::Card_Pin_Blocked: + case GlobalStatus::Code::Card_Pin_Not_Blocked: + case GlobalStatus::Code::Card_NewPin_Mismatch: + case GlobalStatus::Code::Card_NewPin_Invalid_Length: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Unknown_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity: + case GlobalStatus::Code::Workflow_Unknown_Paos_Form_EidServer: + case GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer: + case GlobalStatus::Code::Workflow_Pin_Blocked_And_Puk_Objectionable: + case GlobalStatus::Code::Card_Protocol_Error: + case GlobalStatus::Code::Paos_Error_AL_Internal_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Internal_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_AL_Unkown_API_Function: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Unkown_API_Function, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_AL_Not_Initialized: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Not_Initialized, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_AL_Warning_Connection_Disconnected: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Warning_Connection_Disconnected, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_AL_Session_Terminated_Warning: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Session_Terminated_Warning, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Timeout_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Timeout_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Channel_Handle: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Unknown_Channel_Handle, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Communication_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Communication_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Protocol: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Unknown_Protocol, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Cipher_Suite: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Unknown_Cipher_Suite, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Webservice_Binding: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Unknown_Webservice_Binding, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_DP_Node_Not_Reachable: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_DP_Node_Not_Reachable, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_IFDL_Timeout_Error: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_IFDL_Timeout_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_IFDL_InvalidSlotHandle: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_IFDL_InvalidSlotHandle, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_KEY_KeyGenerationNotPossible: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_KEY_KeyGenerationNotPossible, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_SAL_Invalid_Key: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_Invalid_Key, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_SAL_SecurityConditionNotSatisfied: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_SecurityConditionNotSatisfied, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed, pStatus.toErrorDescription(), pStatus.getOrigin()); + + case GlobalStatus::Code::RemoteReader_CloseCode_NormalClose: + return createOk(); + + case GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose: + case GlobalStatus::Code::RemoteReader_CloseCode_Undefined: + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Unknown_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); + } + + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Unknown_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); +} Result Result::createOk() { - return Result(Result::Major::Ok, Result::Minor::null); -} - - -Result Result::createError(ReturnCode pReturnCode) -{ - QPair errorPair = ReturnCodeUtil::toError(pReturnCode); - return Result(Result::Major::Error, errorPair.first, errorPair.second, QString(), pReturnCode); -} - - -Result Result::createInternalError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::AL_Internal_Error, pMessage, pLang); -} - - -Result Result::createParameterError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::AL_Parameter_Error, pMessage, pLang); -} - - -Result Result::createCommunicationError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::AL_Communication_Error, pMessage, pLang); -} - - -Result Result::createCertChainInterruptedError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::SAL_CertificateChainInterrupted, pMessage, pLang); -} - - -Result Result::createNoPermissionError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::AL_No_Permission, pMessage, pLang); -} - - -Result Result::createInvalidKeyError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::SAL_Invalid_Key, pMessage, pLang); -} - - -Result Result::createCardRemovedError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::IFDL_CancellationByUser, pMessage, pLang); -} - - -Result Result::createTrustedChannelEstablishmentError(const QString& pMessage, const QString& pLang) -{ - return Result(Result::Major::Error, Result::Minor::DP_Trusted_Channel_Establishment_Failed, pMessage, pLang); -} - - -Result Result::createCancelByUserError() -{ - return Result(Result::Major::Error, Result::Minor::SAL_Cancellation_by_User, ReturnCodeUtil::toMessage(ReturnCode::CANCELLATION_BY_USER)); + return Result(Result::Major::Ok, GlobalStatus::Code::Unknown_Error); } @@ -165,11 +246,11 @@ Result::Major Result::parseMajor(const QString& pMajor) { qWarning() << "Unknown ResultMajor:" << pMajor; } - return Major::null; + return Major::Unknown; } -Result::Minor Result::parseMinor(const QString& pMinor) +GlobalStatus::Code Result::parseMinor(const QString& pMinor) { for (auto iter = mMinorResults.cbegin(); iter != mMinorResults.cend(); ++iter) { @@ -183,59 +264,165 @@ Result::Minor Result::parseMinor(const QString& pMinor) { qWarning() << "Unknown ResultMinor:" << pMinor; } - return Minor::null; + return GlobalStatus::Code::Unknown_Error; } bool Result::isMajor(const QString& major) { - return Major::null != parseMajor(major); + return Major::Unknown != parseMajor(major); } bool Result::isMinor(const QString& minor) { - return Minor::null != parseMinor(minor); + return GlobalStatus::Code::Unknown_Error != parseMinor(minor); } -Result::ResultData::ResultData(Major pMajor, Minor pMinor, const QString& pMessage, const QString& pLang, ReturnCode pReturnCode, Origin pOrigin) +QString Result::getMessage(GlobalStatus::Code pMinor) +{ + switch (pMinor) + { + case GlobalStatus::Code::Paos_Error_AL_Unknown_Error: + return tr("An unexpected error has occurred during processing."); + + case GlobalStatus::Code::Paos_Error_AL_No_Permission: + return tr("Use of the function by the client application is not permitted."); + + case GlobalStatus::Code::Paos_Error_AL_Internal_Error: + return tr("An internal error has occurred during processing."); + + case GlobalStatus::Code::Paos_Error_AL_Parameter_Error: + return tr("There was some problem with a provided or omitted parameter."); + + case GlobalStatus::Code::Paos_Error_AL_Unkown_API_Function: + return tr("The API function is unknown."); + + case GlobalStatus::Code::Paos_Error_AL_Not_Initialized: + return tr("The framework or layer has not been initialized."); + + case GlobalStatus::Code::Paos_Error_AL_Warning_Connection_Disconnected: + return tr("The active session has been terminated."); + + case GlobalStatus::Code::Paos_Error_AL_Session_Terminated_Warning: + return tr("The active session has been terminated."); + + case GlobalStatus::Code::Paos_Error_AL_Communication_Error: + return tr("A Communication error occurred during processing."); + + case GlobalStatus::Code::Paos_Error_DP_Timeout_Error: + return tr("The operation was terminated as the set time was exceeded."); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Channel_Handle: + return tr("The operation was aborted as an invalid channel handle was used."); + + case GlobalStatus::Code::Paos_Error_DP_Communication_Error: + return tr("A Communication error occurred during processing."); + + case GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed: + return tr("A trusted channel could not be opened."); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Protocol: + return tr("The operation was aborted as an unknown protocol was used."); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Cipher_Suite: + return tr("The operation was aborted as an unknown cipher suite was used."); + + case GlobalStatus::Code::Paos_Error_DP_Unknown_Webservice_Binding: + return tr("The operation was aborted as an unknown web service binding was used."); + + case GlobalStatus::Code::Paos_Error_DP_Node_Not_Reachable: + return tr("A Communication error occurred during processing."); + + case GlobalStatus::Code::Paos_Error_IFDL_Timeout_Error: + return tr("The operation was terminated as the set time was exceeded."); + + case GlobalStatus::Code::Paos_Error_KEY_KeyGenerationNotPossible: + return tr("Signature certificate key generation is not possible."); + + case GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User: + return tr("The operation was aborted due to cancellation by user."); + + case GlobalStatus::Code::Paos_Error_SAL_CertificateChainInterrupted: + return tr("One or more certificate checks failed. The operation will be aborted due to security reasons."); + + case GlobalStatus::Code::Paos_Error_SAL_Invalid_Key: + return tr("This action cannot be performed. The online identification function of your ID card is deactivated. Please contact your competent authority to activate the online identification function."); + + case GlobalStatus::Code::Paos_Error_SAL_SecurityConditionNotSatisfied: + return tr("The authenticity of your ID card could not be verified. Please make sure that you are using a genuine ID card. Please note that test applications require the use of a test ID card."); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning: + return tr("The age verification failed."); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning: + return tr("The community verification failed."); + + case GlobalStatus::Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed: + return tr("The ID card is invalid or disabled."); + + case GlobalStatus::Code::Unknown_Error: + default: + return QString(); + } +} + + +Result::ResultData::ResultData(Major pMajor, GlobalStatus::Code pMinor, const QString& pMessage, Origin pOrigin) : QSharedData() , mMajor(pMajor) , mMinor(pMinor) , mMessage(pMessage) - , mMessageLang(pLang.isEmpty() ? LanguageLoader::getInstance().getUsedLocale().bcp47Name().left(2) : pLang) - , mReturnCode(pReturnCode) + , mMessageLang(LanguageLoader::getInstance().getUsedLocale().bcp47Name().left(2)) , mOrigin(pOrigin) { + if (pMinor != GlobalStatus::Code::No_Error && pMinor != GlobalStatus::Code::Unknown_Error && !mMinorResults.contains(pMinor)) + { + qCritical() << "Unknown status code in minor paos result:" << pMinor; + Q_ASSERT(false); + } } -Result::Result(Major pMajor, Minor pMinor, const QString& pMessage, const QString& pLang, ReturnCode pReturnCode, Origin pOrigin) - : d(new ResultData(pMajor, pMinor, pMessage, pLang, pReturnCode, pOrigin)) +Result::Result(Major pMajor, GlobalStatus::Code pMinor, const QString& pMessage, Origin pOrigin) + : d(new ResultData(pMajor, pMinor, pMessage, pOrigin)) { } -Result::Result(const QString& pMajor, const QString& pMinor, const QString& pMessage, const QString& pLang, ReturnCode pReturnCode, Origin pOrigin) - : Result(parseMajor(pMajor), parseMinor(pMinor), pMessage, pLang, pReturnCode, pOrigin) +Result::Result(const QString& pMajor, const QString& pMinor, const QString& pMessage, Origin pOrigin) + : Result(parseMajor(pMajor), parseMinor(pMinor), pMessage, pOrigin) { } +Result::Result(const GlobalStatus& pStatus) + : Result(fromStatus(pStatus)) +{ + +} + + +bool Result::operator ==(const Result& pResult) const +{ + return *d == *pResult.d; +} + + Result::Major Result::getMajor() const { return d->mMajor; } -Result::Minor Result::getMinor() const +GlobalStatus::Code Result::getMinor() const { return d->mMinor; } -const QString& Result::getMessage() const +QString Result::getMessage() const { return d->mMessage; } @@ -247,12 +434,6 @@ const QString& Result::getMessageLang() const } -ReturnCode Result::getReturnCode() const -{ - return d->mReturnCode; -} - - QString Result::getMajorString() const { return mMajorResults.value(d->mMajor); @@ -269,33 +450,66 @@ bool Result::isValid() const { switch (d->mMajor) { - case Major::null: + case Major::Unknown: return false; case Major::Ok: - return d->mMinor == Minor::null; + return d->mMinor == GlobalStatus::Code::Unknown_Error; default: - return d->mMinor != Minor::null; + return d->mMinor != GlobalStatus::Code::Unknown_Error; } } bool Result::isOk() const { - return d->mMajor == Major::Ok && d->mMinor == Minor::null; -} - - -QString Result::getMinorDescription() const -{ - return tr(mMinorDescriptions.value(d->mMinor)); + return d->mMajor == Major::Ok && d->mMinor == GlobalStatus::Code::Unknown_Error; } bool Result::isOriginServer() const { - return d->mOrigin == Origin::SERVER; + return d->mOrigin == Origin::Server; +} + + +GlobalStatus Result::toStatus() const +{ + QString message = getMessage(); + if (message.isEmpty() || isOriginServer()) + { + // if the message is not set, we clearly use the result minor + // if the server sent the message, it can be in any language, so we take the result minor + message = Result::getMessage(getMinor()); + } + + switch (getMajor()) + { + case Major::Unknown: + break; + + case Major::Ok: + if (isOk()) + { + return GlobalStatus::Code::No_Error; + } + // FALLTHROUGH + + case Major::Warning: + return GlobalStatus(GlobalStatus::Code::Paos_Unexpected_Warning, message); + + case Major::Error: + return GlobalStatus(getMinor(), message, d->mOrigin); + } + + return GlobalStatus(GlobalStatus::Code::Unknown_Error, message); +} + + +governikus::Result::operator GlobalStatus() const +{ + return toStatus(); } @@ -304,7 +518,7 @@ QJsonObject Result::toJson() const QJsonObject obj; obj["major"] = getMajorString(); - if (getMinor() != Minor::null) + if (getMinor() != GlobalStatus::Code::Unknown_Error) { obj["minor"] = getMinorString(); } @@ -315,7 +529,7 @@ QJsonObject Result::toJson() const obj["message"] = message; } - const auto& minorDesc = getMinorDescription(); + const auto& minorDesc = Result::getMessage(getMinor()); if (!minorDesc.isEmpty()) { obj["description"] = minorDesc; @@ -331,16 +545,11 @@ QJsonObject Result::toJson() const } -QString Result::toString() const -{ - return getMajorString() % " | " % getMinorString() % " | " % getMessage(); -} - - QDebug operator <<(QDebug pDbg, const governikus::Result& pResult) { + const QString string = pResult.getMajorString() % " | " % pResult.getMinorString() % " | " % pResult.getMessage(); QDebugStateSaver saver(pDbg); pDbg.space() << "Result:"; - pDbg.quote() << pResult.toString(); + pDbg.quote() << string; return pDbg; } diff --git a/src/global/Result.h b/src/global/Result.h index e419f40..342b167 100644 --- a/src/global/Result.h +++ b/src/global/Result.h @@ -6,7 +6,8 @@ #pragma once -#include "ReturnCode.h" +#include "CardReturnCode.h" +#include "GlobalStatus.h" #include #include @@ -15,6 +16,8 @@ #include #include +class test_result; + namespace governikus { @@ -24,58 +27,18 @@ class Result Q_DECLARE_TR_FUNCTIONS(governikus::Result) friend class StartPaosResponse; + friend class::test_result; public: enum class Major { - null, // Used as undefined state only! + Unknown, Ok, Warning, Error }; - enum class Minor - { - null, // Used by Major::Ok and undefined state only! - AL_Unknown_Error, - AL_No_Permission, - AL_Internal_Error, - AL_Parameter_Error, - AL_Unkown_API_Function, - AL_Not_Initialized, - AL_Warning_Connection_Disconnected, - AL_Session_Terminated_Warning, - AL_Communication_Error, - DP_Timeout_Error, - DP_Unknown_Channel_Handle, - DP_Communication_Error, - DP_Trusted_Channel_Establishment_Failed, - DP_Unknown_Protocol, - DP_Unknown_Cipher_Suite, - DP_Unknown_Webservice_Binding, - DP_Node_Not_Reachable, - IFDL_Timeout_Error, - IFDL_InvalidSlotHandle, - IFDL_CancellationByUser, - KEY_KeyGenerationNotPossible, - SAL_Cancellation_by_User, - SAL_CertificateChainInterrupted, - SAL_Invalid_Key, - SAL_SecurityConditionNotSatisfied, - SAL_DocumentValidityVerificationFailed, - SAL_MEAC_AgeVerificationFailedWarning, - SAL_MEAC_CommunityVerificationFailedWarning, - SAL_MEAC_DocumentValidityVerificationFailed, - }; - - enum class Origin - { - SERVER, CLIENT - }; - Q_ENUM(Major) - Q_ENUM(Minor) - Q_ENUM(Origin) private: class ResultData @@ -83,58 +46,64 @@ class Result { public: const Major mMajor; - const Minor mMinor; + const GlobalStatus::Code mMinor; const QString mMessage; const QString mMessageLang; - const ReturnCode mReturnCode; const Origin mOrigin; - ResultData(Major pMajor, Minor pMinor, const QString& pMessage, const QString& pLang, ReturnCode pReturnCode, Origin pOrigin); + ResultData(Major pMajor, GlobalStatus::Code pMinor, const QString& pMessage, Origin pOrigin); + + bool operator ==(const ResultData& pOther) const + { + return mMajor == pOther.mMajor && + mMinor == pOther.mMinor && + mMessage == pOther.mMessage && + mMessageLang == pOther.mMessageLang && + mOrigin == pOther.mOrigin; + } + + }; static const QMap mMajorResults; - static const QMap mMinorResults; - static const QMap mMinorDescriptions; + static const QMap mMinorResults; QSharedDataPointer d; - Result(Major pMajor, Minor pMinor, const QString& pMessage = QString(), const QString& pLang = QString(), ReturnCode pReturnCode = ReturnCode::UNDEFINED, Origin pOrigin = Origin::CLIENT); - Result(const QString& pMajor, const QString& pMinor = QString(), const QString& pMessage = QString(), const QString& pLang = QString(), ReturnCode pReturnCode = ReturnCode::UNDEFINED, Origin pOrigin = Origin::CLIENT); + static Result fromStatus(const GlobalStatus& pStatus); + + Result(Major pMajor, GlobalStatus::Code pMinor, const QString& pMessage = QString(), Origin pOrigin = Origin::Client); + Result(const QString& pMajor, const QString& pMinor = QString(), const QString& pMessage = QString(), Origin pOrigin = Origin::Client); public: + Result(const GlobalStatus& pStatus); + + bool operator ==(const Result& pResult) const; + static Result createOk(); - static Result createError(ReturnCode pReturnCode); - static Result createCertChainInterruptedError(const QString& pMessage, const QString& pLang = QString()); - static Result createNoPermissionError(const QString& pMessage, const QString& pLang = QString()); - static Result createInvalidKeyError(const QString& pMessage, const QString& pLang = QString()); - static Result createInternalError(const QString& pMessage = QString(), const QString& pLang = QString()); - static Result createParameterError(const QString& pMessage = QString(), const QString& pLang = QString()); - static Result createCommunicationError(const QString& pMessage = QString(), const QString& pLang = QString()); - static Result createCardRemovedError(const QString& pMessage, const QString& pLang = QString()); - static Result createTrustedChannelEstablishmentError(const QString& pMessage, const QString& pLang = QString()); - static Result createCancelByUserError(); static Major parseMajor(const QString& pMajor); - static Minor parseMinor(const QString& pMinor); + static GlobalStatus::Code parseMinor(const QString& pMinor); static bool isMajor(const QString& pMajor); static bool isMinor(const QString& pMinor); + static QString getMessage(GlobalStatus::Code pMinor); Major getMajor() const; - Minor getMinor() const; - const QString& getMessage() const; + GlobalStatus::Code getMinor() const; + QString getMessage() const; const QString& getMessageLang() const; - ReturnCode getReturnCode() const; QString getMajorString() const; QString getMinorString() const; - QString getMinorDescription() const; - QString toString() const; bool isValid() const; bool isOk() const; bool isOriginServer() const; QJsonObject toJson() const; + + GlobalStatus toStatus() const; + operator GlobalStatus() const; }; } diff --git a/src/global/ReturnCode.cpp b/src/global/ReturnCode.cpp deleted file mode 100644 index 527443a..0000000 --- a/src/global/ReturnCode.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "ReturnCode.h" -#include "moc_ReturnCode.cpp" diff --git a/src/global/ReturnCodeUtil.cpp b/src/global/ReturnCodeUtil.cpp deleted file mode 100644 index 60f75bb..0000000 --- a/src/global/ReturnCodeUtil.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/*! - * ReturnCodeUtil.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ReturnCodeUtil.h" - -#include - -using namespace governikus; - -const ReturnCodeUtil::MapType ReturnCodeUtil::mCodeTable -{ - { - ReturnCode::OK, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("No error occurred."), - QT_TR_NOOP("no error") - } - }, - { - ReturnCode::NO_CARD, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("Card does not exist"), - QT_TR_NOOP("Card does not exist") - } - }, - { - ReturnCode::TIME_OUT, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The maximum time was exceeded during input process."), - QT_TR_NOOP("A timeout occurred during input process") - } - }, - { - ReturnCode::UNKNOWN, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The input is invalid."), - QT_TR_NOOP("invalid input") - } - }, - { - ReturnCode::COMMAND_FAILED, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("An error occurred while communicating with the card reader."), - QT_TR_NOOP("An error occurred while communicating with the card reader.") - } - }, - { - ReturnCode::GET_CHALLENGE_FAILED, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("An error occurred while communicating with the card reader."), - QT_TR_NOOP("An error occurred while communicating with the card reader.") - } - }, - { - ReturnCode::CANCELLATION_BY_USER, - { - Result::Minor::SAL_Cancellation_by_User, - QT_TR_NOOP("The process was cancelled by the user."), - QT_TR_NOOP("The process was cancelled by the user.") - } - }, - { - ReturnCode::NEW_PINS_DONT_MATCH, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The new PIN and the confirmation do not match."), - QT_TR_NOOP("The new PIN and the confirmation do not match.") - } - }, - { - ReturnCode::NEW_PIN_TOO_SHORT_OR_LONG, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The length of the new PIN is not valid."), - QT_TR_NOOP("The length of the new PIN is not valid.") - } - }, - { - ReturnCode::PIN_BLOCKED, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The PIN was blocked after too many unsuccessful attempts."), - QT_TR_NOOP("PIN is blocked") - } - }, - { - ReturnCode::PROTOCOL_ERROR, - { - Result::Minor::AL_Internal_Error, - QT_TR_NOOP("A protocol error has occurred."), - QT_TR_NOOP("A protocol error has occurred.") - } - }, - { - ReturnCode::PIN_NOT_BLOCKED, - { - Result::Minor::AL_Unknown_Error, - QT_TR_NOOP("The PIN is not blocked."), - QT_TR_NOOP("The PIN is not blocked.") - } - }, - { - ReturnCode::UNEXPECTED_TRANSMIT_STATUS, - { - Result::Minor::AL_Internal_Error, - QT_TR_NOOP("Unexpected transmit status"), - QT_TR_NOOP("Unexpected transmit status") - } - }, - { - ReturnCode::CAN_INVALID, - { - Result::Minor::AL_Communication_Error, - QT_TR_NOOP("The given card access number (CAN) is invalid."), - QT_TR_NOOP("given card access number (CAN) is invalid") - } - }, - { - ReturnCode::PIN_INVALID, - { - Result::Minor::AL_Communication_Error, - QT_TR_NOOP("The given PIN is invalid."), - QT_TR_NOOP("given PIN is invalid") - } - }, - { - ReturnCode::PUK_INVALID, - { - Result::Minor::AL_Communication_Error, - QT_TR_NOOP("The given PUK is invalid."), - QT_TR_NOOP("given PUK is invalid") - } - }, - { - ReturnCode::PUK_INOPERATIVE, - { - Result::Minor::AL_Communication_Error, - QT_TR_NOOP("The PUK was used ten times and is set inoperative."), - QT_TR_NOOP("PUK is inoperative") - } - }, -}; - - -QString ReturnCodeUtil::toString(ReturnCode pCode) -{ - auto i = mCodeTable.find(pCode); - if (i == mCodeTable.end()) - { - return tr("Unknown error"); - } - return tr(i->shortText); -} - - -QString ReturnCodeUtil::toMessage(ReturnCode pCode) -{ - auto i = mCodeTable.find(pCode); - if (i == mCodeTable.end()) - { - return tr("An unknown error occurred: ") + pCode; - } - - return tr(i->longText); -} - - -Result::Minor ReturnCodeUtil::toResult(ReturnCode pCode) -{ - auto i = mCodeTable.find(pCode); - if (i == mCodeTable.end()) - { - return Result::Minor::AL_Unknown_Error; - } - return i->trCode; -} - - -QPair ReturnCodeUtil::toError(ReturnCode pCode) -{ - auto i = mCodeTable.find(pCode); - if (i == mCodeTable.end()) - { - return QPair(Result::Minor::AL_Unknown_Error, - tr("An unknown error occurred: ") + pCode); - } - return QPair(i->trCode, tr(i->longText)); -} diff --git a/src/global/ReturnCodeUtil.h b/src/global/ReturnCodeUtil.h deleted file mode 100644 index cc7b9d0..0000000 --- a/src/global/ReturnCodeUtil.h +++ /dev/null @@ -1,71 +0,0 @@ -/*! - * ReturnCodeUtil.h - * - * \brief Global ReturnCode utility functions. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -#include "Result.h" -#include "ReturnCode.h" - -namespace governikus -{ - - -class ReturnCodeUtil -{ - Q_DECLARE_TR_FUNCTIONS(governikus::ReturnCodeUtil) - - struct Data - { - Result::Minor trCode; - const char* longText; - const char* shortText; - }; - - typedef QMap MapType; - static const MapType mCodeTable; - - ReturnCodeUtil() = delete; - ~ReturnCodeUtil() = delete; - - public: - /*! - * \brief Returns a short internationalized string for a given error code. - * \param pCode The error code. - * \return The internationalized string. - */ - static QString toString(ReturnCode pCode); - - /*! - * \brief Returns an internationalized error message string (a sentence) for a given error code. - * \param pCode The error code. - * \return The internationalized message string. - */ - static QString toMessage(ReturnCode pCode); - - /*! - * \brief Translate an error code to a type "Result::Minor" error code. - * \param pCode The error code. - * \return The type "Result::Minor" error code. - */ - static Result::Minor toResult(ReturnCode pCode); - - /*! - * \brief Translate an error code to a type "Result::Minor" error code and - * an internationalized error message string. - * \param pCode The error code. - * \return A QPair containinf the type "Result::Minor" error code and the - * error message string. - */ - static QPair toError(ReturnCode pCode); -}; - -} /* namespace governikus */ diff --git a/src/global/VersionInfo.cpp b/src/global/VersionInfo.cpp index b9c0239..032505e 100644 --- a/src/global/VersionInfo.cpp +++ b/src/global/VersionInfo.cpp @@ -33,14 +33,14 @@ VersionInfo::VersionInfo() VersionInfo VersionInfo::getInstance() { return VersionInfo({ - {NAME, QCoreApplication::applicationName()}, - {IMPL_TITLE, QCoreApplication::applicationName()}, - {IMPL_VENDOR, QCoreApplication::organizationName()}, - {IMPL_VERSION, QCoreApplication::applicationVersion()}, - {SPEC_TITLE, QStringLiteral("TR-03124")}, - {SPEC_VENDOR, QStringLiteral("Federal Office for Information Security")}, - {SPEC_VERSION, QStringLiteral("1.2")} - }); + {NAME, QCoreApplication::applicationName()}, + {IMPL_TITLE, QCoreApplication::applicationName()}, + {IMPL_VENDOR, QCoreApplication::organizationName()}, + {IMPL_VERSION, QCoreApplication::applicationVersion()}, + {SPEC_TITLE, QStringLiteral("TR-03124")}, + {SPEC_VENDOR, QStringLiteral("Federal Office for Information Security")}, + {SPEC_VERSION, QStringLiteral("1.2")} + }); } diff --git a/src/gui/AppQtGui.cpp b/src/gui/AppQtGui.cpp index 595d81d..8a49524 100644 --- a/src/gui/AppQtGui.cpp +++ b/src/gui/AppQtGui.cpp @@ -12,6 +12,7 @@ #include "NetworkManager.h" #include "ReaderDriverGui.h" #include "SetupAssistantGui.h" +#include "UpdateWindow.h" #include "Updater.h" #include "generic/HelpAction.h" #include "generic/Page.h" @@ -48,6 +49,7 @@ Q_DECLARE_LOGGING_CATEGORY(gui) AppQtGui::AppQtGui() : QObject() , mMainWidget(nullptr) + , mIcon(QStringLiteral(":/images/npa.svg")) , mTrayIcon(nullptr) , mActiveWorkflowUi() , mSetupAssistantGui(nullptr) @@ -58,7 +60,7 @@ AppQtGui::AppQtGui() initGuiProfile(); mMainWidget = new AppQtMainWidget(); - mMainWidget->setWindowIcon(QIcon(QStringLiteral(":/images/autentapp2.iconset/icon_512x512.png"))); + mMainWidget->setWindowIcon(mIcon); } @@ -161,9 +163,11 @@ void AppQtGui::activateWorkflowUi(QSharedPointer pWorkflowUi, bool mMainWidget->activateMenuBarItems(false); closeDialogs(); - mAggressiveToForeground = mActiveWorkflowUi.dynamicCast(); +#ifdef Q_OS_WIN + mAggressiveToForeground = mActiveWorkflowUi.objectCast(); +#endif bool hideAfterWorkflow = pAllowHideAfterWorkflow - && mActiveWorkflowUi.dynamicCast() + && mActiveWorkflowUi.objectCast() && AppSettings::getInstance().getGeneralSettings().isAutoCloseWindowAfterAuthentication(); mMainWidget->setHideWindowAfterWorkflow(hideAfterWorkflow); show(); @@ -264,6 +268,7 @@ bool AppQtGui::askChangeTransportPinNow() QMessageBox messageBox(mMainWidget); messageBox.setWindowTitle(QCoreApplication::applicationName() + " - Information"); messageBox.setWindowModality(Qt::WindowModal); + messageBox.setWindowFlags(messageBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); messageBox.setText(tr("Did you change the initial transport PIN already?

Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. Online identification with transport PIN is not possible.")); messageBox.setStandardButtons(QMessageBox::Yes); auto changePinButton = messageBox.addButton(tr("No, change transport PIN now"), QMessageBox::NoRole); @@ -386,17 +391,17 @@ QString AppQtGui::readStyleSheet(const QString& pFileName) QRegularExpressionMatch match = it.next(); if (lastOffset < match.capturedStart()) { - result.append(styleSheet.midRef(lastOffset, match.capturedStart() - lastOffset)); + result += styleSheet.midRef(lastOffset, match.capturedStart() - lastOffset); } - result.append(readStyleSheet(match.captured(1))); + result += readStyleSheet(match.captured(1)); lastOffset = match.capturedEnd(); } if (lastOffset < styleSheet.length()) { - result.append(styleSheet.midRef(lastOffset)); + result += styleSheet.midRef(lastOffset); } return result; @@ -436,7 +441,7 @@ void AppQtGui::createTrayIcon() #endif trayIconMenu->addAction(quitAction); - mTrayIcon = new QSystemTrayIcon(QIcon(QStringLiteral(":images/autentapp2.iconset/icon_16x16.png")), mMainWidget); + mTrayIcon = new QSystemTrayIcon(mIcon, mMainWidget); connect(mTrayIcon, &QSystemTrayIcon::activated, this, &AppQtGui::onActivated); connect(mTrayIcon, &QSystemTrayIcon::messageClicked, this, [this] {show(UiModule::CURRENT); }); @@ -508,7 +513,7 @@ void AppQtGui::onCloseWindowRequested(bool* pDoClose) messageBox.setWindowTitle(QApplication::applicationName() + " - Information"); messageBox.setWindowModality(Qt::WindowModal); messageBox.setIcon(QMessageBox::Information); - + messageBox.setWindowFlags(messageBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); messageBox.setText(tr("The user interface of the %1 is closed.").arg(QApplication::applicationName())); messageBox.setInformativeText(tr("The program remains available via the icon in the system tray. Click on the %1 icon to reopen the user interface.").arg(QApplication::applicationName())); messageBox.setCheckBox(new QCheckBox(tr("Don't show this dialog again."))); @@ -535,7 +540,7 @@ void AppQtGui::onCloseWindowRequested(bool* pDoClose) void AppQtGui::onDebugStyleSheetChanged(const QString& pPath) { - if (QFileSystemWatcher* watcher = dynamic_cast(sender())) + if (QFileSystemWatcher* watcher = qobject_cast(sender())) { // work-around for QFileSystemWatcher no longer knowing the file after receiving the first notification watcher->removePath(pPath); @@ -546,6 +551,7 @@ void AppQtGui::onDebugStyleSheetChanged(const QString& pPath) } +#ifndef QT_NO_NETWORKPROXY void AppQtGui::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) { CredentialDialog dialog(mMainWidget); @@ -559,6 +565,9 @@ void AppQtGui::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthe } +#endif + + void AppQtGui::show(UiModule pModule) { if (!mActiveWorkflowUi.isNull()) @@ -600,18 +609,19 @@ void AppQtGui::show(UiModule pModule) mMainWidget->resize(size); } +#ifdef Q_OS_WIN if (mAggressiveToForeground) { // Changing the window flags seems to be the only way to // bring the window to the foreground if it is not minimized. - Qt::WindowFlags flags = mMainWidget->windowFlags(); - flags |= Qt::WindowStaysOnTopHint; - mMainWidget->setWindowFlags(flags); + const Qt::WindowFlags flags = mMainWidget->windowFlags(); + mMainWidget->setWindowFlags(flags | Qt::WindowStaysOnTopHint); mMainWidget->show(); - flags &= ~Qt::WindowStaysOnTopHint; mMainWidget->setWindowFlags(flags); + mAggressiveToForeground = false; } +#endif mMainWidget->show(); mMainWidget->activateWindow(); @@ -630,7 +640,7 @@ void AppQtGui::show(UiModule pModule) Updater::getInstance().update(); if (AppSettings::getInstance().getGeneralSettings().isAutoUpdateCheck()) { - Updater::getInstance().checkAppUpdate(true); + new UpdateWindow(true, mMainWidget); } } } diff --git a/src/gui/AppQtGui.h b/src/gui/AppQtGui.h index b090312..22b5b78 100644 --- a/src/gui/AppQtGui.h +++ b/src/gui/AppQtGui.h @@ -64,7 +64,9 @@ class AppQtGui virtual void show(UiModule pModule = UiModule::CURRENT); virtual void onApplicationStarted(); virtual void onShowUserInformation(const QString& pAppName); +#ifndef QT_NO_NETWORKPROXY void onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); +#endif private Q_SLOTS: void onActivated(QSystemTrayIcon::ActivationReason reason); @@ -78,6 +80,7 @@ class AppQtGui private: AppQtMainWidget* mMainWidget; + QIcon mIcon; QSystemTrayIcon* mTrayIcon; QSharedPointer mActiveWorkflowUi; SetupAssistantGui* mSetupAssistantGui; diff --git a/src/gui/AppQtMainWidget.cpp b/src/gui/AppQtMainWidget.cpp index 9b280c1..2bc047a 100644 --- a/src/gui/AppQtMainWidget.cpp +++ b/src/gui/AppQtMainWidget.cpp @@ -51,7 +51,7 @@ AppQtMainWidget::AppQtMainWidget() mUi->appLogoWidget->setAttribute(Qt::WA_TransparentForMouseEvents); - QStackedLayout* centralStackLayout = dynamic_cast(mUi->centralWidget->layout()); + QStackedLayout* centralStackLayout = qobject_cast(mUi->centralWidget->layout()); centralStackLayout->setStackingMode(QStackedLayout::StackAll); centralStackLayout->setCurrentIndex(1); @@ -69,7 +69,7 @@ AppQtMainWidget::AppQtMainWidget() connect(mUi->actionBeenden, &QAction::triggered, this, &AppQtMainWidget::fireQuitApplicationRequested); connect(mUi->actionSettings, &QAction::triggered, this, &AppQtMainWidget::onSettingsButtonClicked); - //menu pin management + //menu PIN management connect(mUi->actionChangePin, &QAction::triggered, this, &AppQtMainWidget::onChangePinButtonClicked); //help @@ -221,9 +221,9 @@ void AppQtMainWidget::workflowActivated(WorkflowWidgetParent pParent, const QStr while (containingWidget != nullptr) { QWidget* containerParent = containingWidget->parentWidget(); - if (QStackedWidget* stackedWidget = dynamic_cast(containerParent)) + if (QStackedWidget* stackedWidget = qobject_cast(containerParent)) { - mSelectedPagesBeforeWorkflow.append(stackedWidget->currentWidget()); + mSelectedPagesBeforeWorkflow += stackedWidget->currentWidget(); stackedWidget->setCurrentWidget(containingWidget); } @@ -246,7 +246,7 @@ void AppQtMainWidget::workflowDeactivated() for (auto widget : qAsConst(mSelectedPagesBeforeWorkflow)) { - if (QStackedWidget* stackedWidget = dynamic_cast(widget->parentWidget())) + if (QStackedWidget* stackedWidget = qobject_cast(widget->parentWidget())) { stackedWidget->setCurrentWidget(widget); } @@ -296,7 +296,7 @@ void AppQtMainWidget::switchToPinSettingsAfterWorkflow() while (containingWidget != nullptr) { QWidget* containerParent = containingWidget->parentWidget(); - if (dynamic_cast(containerParent) != nullptr) + if (qobject_cast(containerParent) != nullptr) { mSelectedPagesBeforeWorkflow += containingWidget; } @@ -403,7 +403,7 @@ void AppQtMainWidget::updateGeometryRecursively(QWidget* pWidget, QSet for (QObject* child : pWidget->children()) { - if (QWidget* widget = dynamic_cast(child)) + if (QWidget* widget = qobject_cast(child)) { updateGeometryRecursively(widget, pVisitedObjects); } @@ -458,12 +458,12 @@ void AppQtMainWidget::onOpenLoggingFileButtonClicked() void AppQtMainWidget::onSaveLoggingFileButtonClicked() { - QString filename = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save file"), QDir::homePath().append("/AusweisApp2.log"), QStringLiteral("*.log")); + QString filename = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save file"), QDir::homePath() + QStringLiteral("/AusweisApp2.log"), QStringLiteral("*.log")); if (!filename.isNull()) { if (!filename.endsWith(QStringLiteral(".log"), Qt::CaseSensitivity::CaseInsensitive)) { - filename.append(".log"); + filename += QStringLiteral(".log"); } qCDebug(gui) << "File location:" << filename; @@ -494,7 +494,7 @@ void AppQtMainWidget::onTabButtonToggled(QAbstractButton* pButton, bool pChecked void AppQtMainWidget::onTabActionTriggered() { - if (QAction* action = dynamic_cast(sender())) + if (QAction* action = qobject_cast(sender())) { if (QAbstractButton* button = mTabAction2Button.value(action)) { diff --git a/src/gui/AppQtMainWidget.ui b/src/gui/AppQtMainWidget.ui index faac87d..ee8691f 100644 --- a/src/gui/AppQtMainWidget.ui +++ b/src/gui/AppQtMainWidget.ui @@ -18,7 +18,7 @@ - :/images/npa.ico:/images/npa.ico + :/images/npa.svg:/images/npa.svg diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index f52ec56..2b679d2 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,4 +1,8 @@ ADD_PLATFORM_LIBRARY(AusweisAppWidget) -TARGET_LINK_LIBRARIES(AusweisAppWidget Qt5::Widgets Qt5::Svg Qt5::PrintSupport AusweisAppCore AusweisAppGlobal) +TARGET_LINK_LIBRARIES(AusweisAppWidget Qt5::Widgets Qt5::Svg Qt5::PrintSupport Qt5::QuickWidgets AusweisAppCore AusweisAppGlobal AusweisAppQml AusweisAppExport) TARGET_COMPILE_DEFINITIONS(AusweisAppWidget PRIVATE QT_STATICPLUGIN) + +IF(WIN32) + TARGET_LINK_LIBRARIES(AusweisAppWidget Qt5::WinExtras) +ENDIF() diff --git a/src/gui/DetailDialog.cpp b/src/gui/DetailDialog.cpp index c852875..899d81e 100644 --- a/src/gui/DetailDialog.cpp +++ b/src/gui/DetailDialog.cpp @@ -39,7 +39,7 @@ void DetailDialog::setDetails(const QString& pDetails) } -bool DetailDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool DetailDialog::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -50,5 +50,5 @@ bool DetailDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QDialog::eventFilter(pObject, pEvent); } diff --git a/src/gui/DetailWidget.cpp b/src/gui/DetailWidget.cpp index 68485eb..2dd9d75 100644 --- a/src/gui/DetailWidget.cpp +++ b/src/gui/DetailWidget.cpp @@ -46,7 +46,11 @@ void DetailWidget::paintEvent(QPaintEvent*) static const int SCROLLAREA_PREFERRED_WIDTH = 504; // See comment to accepted answer at // http://stackoverflow.com/questions/16515646/how-to-get-scroll-bar-real-width-in-qt +#ifdef Q_OS_WIN + static const int SCROLLBAR_EXTRA_SPACE = 40; +#else static const int SCROLLBAR_EXTRA_SPACE = 3; +#endif const int scrollbarWidth = qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent) + SCROLLBAR_EXTRA_SPACE; const int contentMaxWidth = SCROLLAREA_PREFERRED_WIDTH - scrollbarWidth; diff --git a/src/gui/DiagnosisDialog.cpp b/src/gui/DiagnosisDialog.cpp index fe2681c..90f6b11 100644 --- a/src/gui/DiagnosisDialog.cpp +++ b/src/gui/DiagnosisDialog.cpp @@ -44,7 +44,7 @@ DiagnosisDialog::~DiagnosisDialog() void DiagnosisDialog::onSaveButtonClicked() { - QString fileName = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save diagnosis result"), QDir::homePath().append(tr("/AusweisApp2-diagnosis.txt")), + QString fileName = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save diagnosis result"), QDir::homePath() + tr("/AusweisApp2-diagnosis.txt"), tr("Text files (*.txt)")); @@ -54,7 +54,7 @@ void DiagnosisDialog::onSaveButtonClicked() } if (!fileName.endsWith(QStringLiteral(".txt"), Qt::CaseSensitivity::CaseInsensitive)) { - fileName.append(".txt"); + fileName += QStringLiteral(".txt"); } QString text = mDiagnosisWidget->getInfoTextEdit(); @@ -70,7 +70,7 @@ void DiagnosisDialog::onSaveButtonClicked() } -bool DiagnosisDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool DiagnosisDialog::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -81,5 +81,5 @@ bool DiagnosisDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QDialog::eventFilter(pObject, pEvent); } diff --git a/src/gui/DiagnosisDialog.ui b/src/gui/DiagnosisDialog.ui index 9b68586..1706a7f 100644 --- a/src/gui/DiagnosisDialog.ui +++ b/src/gui/DiagnosisDialog.ui @@ -52,7 +52,7 @@ - Save… + Save as... diff --git a/src/gui/DiagnosisWidget.cpp b/src/gui/DiagnosisWidget.cpp index 5a32de4..dc8a219 100644 --- a/src/gui/DiagnosisWidget.cpp +++ b/src/gui/DiagnosisWidget.cpp @@ -157,10 +157,10 @@ DiagnosisWidget::DiagnosisWidget(DiagnosisContext* pContext, QWidget* pParent) mTimestampItem->setText(0, tr("Time of diagnosis")); const QStringList appVersion({ - QStringLiteral("%1 (%2)").arg(QCoreApplication::applicationVersion(), QString::fromLatin1(BuildHelper::getDateTime())), - QStringLiteral("Qt ") + QString::fromLatin1(qVersion()), - QString::fromLatin1(SSLeay_version(0)) - }); + QStringLiteral("%1 (%2)").arg(QCoreApplication::applicationVersion(), QString::fromLatin1(BuildHelper::getDateTime())), + QStringLiteral("Qt ") + QString::fromLatin1(qVersion()), + QString::fromLatin1(SSLeay_version(0)) + }); for (const auto& str : appVersion) { (new QTreeWidgetItem(mAppVersionTreeItem))->setText(0, str); @@ -180,7 +180,7 @@ DiagnosisWidget::~DiagnosisWidget() } -bool DiagnosisWidget::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool DiagnosisWidget::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -191,7 +191,7 @@ bool DiagnosisWidget::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QWidget::eventFilter(pObject, pEvent); } diff --git a/src/gui/GeneralSettingsWidget.cpp b/src/gui/GeneralSettingsWidget.cpp index 4fbe329..1893ee0 100644 --- a/src/gui/GeneralSettingsWidget.cpp +++ b/src/gui/GeneralSettingsWidget.cpp @@ -5,7 +5,7 @@ #include "GeneralSettingsWidget.h" #include "AppSettings.h" -#include "Updater.h" +#include "UpdateWindow.h" #include "ui_GeneralSettingsWidget.h" using namespace governikus; @@ -76,5 +76,5 @@ void GeneralSettingsWidget::onCheckBoxStateChanged(int) void GeneralSettingsWidget::onUpdateCheckButtonClicked() { - Updater::getInstance().checkAppUpdate(); + new UpdateWindow(false, this); } diff --git a/src/gui/HistoryWidget.cpp b/src/gui/HistoryWidget.cpp index 027a3dd..52e3ae0 100644 --- a/src/gui/HistoryWidget.cpp +++ b/src/gui/HistoryWidget.cpp @@ -5,6 +5,7 @@ #include "HistoryWidget.h" #include "DeleteHistoryDialog.h" +#include "PdfCreator.h" #include "generic/ListCheckItemWidget.h" #include "generic/ListItem.h" #include "generic/ListItemIconLeft.h" @@ -17,6 +18,7 @@ #include #include + using namespace governikus; @@ -45,8 +47,8 @@ HistoryWidget::~HistoryWidget() void HistoryWidget::init() { QStringList header; - header.append(tr("Date")); - header.append(tr("Details")); + header += tr("Date"); + header += tr("Details"); mUi->historyTableWidget->setColumnCount(header.count()); mUi->historyTableWidget->setHorizontalHeaderLabels(header); @@ -105,14 +107,14 @@ void HistoryWidget::updateTable(const QVector& pItems) mUi->historyTableWidget->insertRow(rowIndex); //date column with needed properties - QLabel* dateLabel = new QLabel(entry.getDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm"))); + QLabel* dateLabel = new QLabel(entry.getDateTime().toString(tr("MM/dd/yyyy hh:mm AP"))); dateLabel->setContentsMargins(11, 11, 11, 11); dateLabel->setAlignment(Qt::AlignTop); dateLabel->setProperty("termsOfUsage", entry.getTermOfUsage()); - dateLabel->setProperty("date", entry.getDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm"))); + dateLabel->setProperty("date", entry.getDateTime().toString(tr("MM/dd/yyyy hh:mm AP"))); dateLabel->setFocusPolicy(Qt::TabFocus); - dateLabel->setAccessibleName(tr("Date:") + entry.getDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm"))); + dateLabel->setAccessibleName(tr("Date:") + entry.getDateTime().toString(tr("MM/dd/yyyy hh:mm AP"))); mUi->historyTableWidget->setCellWidget(rowIndex, 0, dateLabel); @@ -163,33 +165,26 @@ void HistoryWidget::updateTable(const QVector& pItems) } -bool HistoryWidget::eventFilter(QObject*, QEvent* pEvent) +bool HistoryWidget::eventFilter(QObject* pObject, QEvent* pEvent) { - switch (pEvent->type()) + if (pEvent->type() == QEvent::KeyPress) { - case QEvent::KeyPress: + QKeyEvent* pressed = static_cast(pEvent); + if ((pressed->key() == Qt::Key_Enter) || (pressed->key() == Qt::Key_Return) || (pressed->key() == Qt::Key_Space)) { - QKeyEvent* pressed = static_cast(pEvent); - if ((pressed->key() == Qt::Key_Enter) || (pressed->key() == Qt::Key_Return) || (pressed->key() == Qt::Key_Space)) + const auto selectedIndexes = mUi->historyTableWidget->selectionModel()->selectedIndexes(); + for (auto index : selectedIndexes) { - const auto selectedIndexes = mUi->historyTableWidget->selectionModel()->selectedIndexes(); - for (auto index : selectedIndexes) - { - QWidget* tmpWidget = qobject_cast(mUi->historyTableWidget->cellWidget(index.row(), dateColumn)); - DetailDialog d(this); - d.setDetails(tmpWidget->property("termsOfUsage").toString()); - d.exec(); - } - return true; + QWidget* tmpWidget = qobject_cast(mUi->historyTableWidget->cellWidget(index.row(), dateColumn)); + DetailDialog d(this); + d.setDetails(tmpWidget->property("termsOfUsage").toString()); + d.exec(); } + return true; } - break; - - default: - return false; } - return false; + return QWidget::eventFilter(pObject, pEvent); } @@ -234,134 +229,12 @@ void HistoryWidget::deleteHistory() void HistoryWidget::exportHistory() { - QString htmlContent, company_header, company_footer; - QPrinter printer; - QRect printer_rect(printer.pageRect()); - QString pdfName = QFileDialog::getSaveFileName(this, QApplication::applicationName() + " - " + tr("Save history"), QDir::currentPath(), tr("PDF Documents (*.pdf)")); - if (pdfName.size() > 0) - { - printer.setOutputFileName(pdfName); - - //Header - - //Header - QDateTime dateTime = QDateTime::currentDateTime(); - QString date = dateTime.toString(QStringLiteral("dd.MM.yyyy")); - QString time = dateTime.toString(QStringLiteral("hh:mm")); - - company_header.append("

"); - company_header.append(""); - company_header.append(tr("")); - company_header.append(""); - company_header.append(""); - company_header.append(""); - - company_header.append(tr(""); - company_header.append(""); - company_header.append("

History - ") + QApplication::applicationName() + tr("

AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior).


At %1 %2 the following data were saved:").arg(date, time) + "

"); - - company_footer.append(tr("

For further information, please see https://www.ausweisapp.bund.de/

")); - - //Setting up the header and calculating the header size - QTextDocument* document_header = new QTextDocument(this); - document_header->setPageSize(printer_rect.size()); - document_header->setHtml(company_header); - QSizeF header_size = document_header->size(); - - - //Setting up the footer and calculating the footer size - QTextDocument* document_footer = new QTextDocument(this); - document_footer->setPageSize(printer_rect.size()); - document_footer->setHtml(company_footer); - QSizeF footer_size = document_footer->size(); - - //Calculating the main document size for one page - QSizeF center_size(printer_rect.width(), - (printer.pageRect().height() - header_size.toSize().height() - footer_size.toSize().height())); - - htmlContent.append(""); - htmlContent.append(tr("")); - - auto history = AppSettings::getInstance().getHistorySettings().getHistoryEntries(); - - for (int i = 0; i < history.size(); ++i) - { - if (i % 2 == 0) - { - htmlContent.append(""); - } - else - { - htmlContent.append(""); - } - htmlContent.append(""); - htmlContent.append(""); - } - - htmlContent.append("
DateDetails
"); - htmlContent.append(history.at(i).getDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm"))); - htmlContent.append(""); - - htmlContent.append(""); - htmlContent.append(tr("")); - htmlContent.append(""); - htmlContent.append(""); - htmlContent.append(tr("")); - htmlContent.append(""); - htmlContent.append(""); - htmlContent.append(tr("")); - htmlContent.append(""); - htmlContent.append("
Provider:" + history.at(i).getSubjectName() + "
Purpose:" + history.at(i).getPurpose() + "
Data:" + history.at(i).getRequestedData() + "
"); - - htmlContent.append("
"); - - //Insert HTML in main document - QTextDocument* main_doc = new QTextDocument(this); - main_doc->setHtml(htmlContent); - main_doc->setPageSize(center_size); - - //Setting up the rectangles for each section. - QRect headerRect = QRect(QPoint(0, 0), document_header->size().toSize()); - QRect footerRect = QRect(QPoint(0, 0), document_footer->size().toSize()); - QRect contentRect = QRect(QPoint(0, 0), main_doc->size().toSize()); // Main content rectangle. - QRect currentRect = QRect(QPoint(0, 0), center_size.toSize()); // Current main content rectangle. - - QPainter painter(&printer); - - while (currentRect.intersects(contentRect)) - { //Loop if the current content rectangle intersects with the main content rectangle. - //Resetting the painter matrix co-ordinate system. - painter.resetMatrix(); - //Applying negative translation of painter co-ordinate system by current main content rectangle top y coordinate. - painter.translate(0, -currentRect.y()); - //Applying positive translation of painter co-ordinate system by header hight. - painter.translate(0, headerRect.height()); - //Drawing the center content for current page. - main_doc->drawContents(&painter, currentRect); - //Resetting the painter matrix co ordinate system. - painter.resetMatrix(); - //Drawing the header on the top of the page - document_header->drawContents(&painter, headerRect); - //Applying positive translation of painter co-ordinate system to draw the footer - painter.translate(0, headerRect.height()); - painter.translate(0, center_size.height()); - document_footer->drawContents(&painter, footerRect); - - //Translating the current rectangle to the area to be printed for the next page - currentRect.translate(0, currentRect.height()); - //Inserting a new page if there is till area left to be printed - if (currentRect.intersects(contentRect)) - { - printer.newPage(); - } - } - QDesktopServices::openUrl(QUrl(pdfName)); - } + PdfExport::exportHistory(pdfName); } diff --git a/src/gui/HistoryWidget.h b/src/gui/HistoryWidget.h index 732b9b1..5d71e9a 100644 --- a/src/gui/HistoryWidget.h +++ b/src/gui/HistoryWidget.h @@ -10,8 +10,6 @@ #include "generic/ListCheckItemWidget.h" #include "generic/Page.h" -#include -#include #include #include #include diff --git a/src/gui/HistoryWidget.ui b/src/gui/HistoryWidget.ui index f335719..9cbcc8f 100644 --- a/src/gui/HistoryWidget.ui +++ b/src/gui/HistoryWidget.ui @@ -178,7 +178,7 @@ - Delete history… + Delete history... @@ -188,7 +188,7 @@ save history as PDF
- Save as PDF… + Save as PDF...
diff --git a/src/gui/HistoryWidgetQml.cpp b/src/gui/HistoryWidgetQml.cpp new file mode 100644 index 0000000..17efad2 --- /dev/null +++ b/src/gui/HistoryWidgetQml.cpp @@ -0,0 +1,66 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HistoryWidgetQml.h" +#include "ui_HistoryWidgetQml.h" + +#include "DpiCalculator.h" +#include "UIPlugInQml.h" + +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + +using namespace governikus; + + +HistoryWidgetQml::HistoryWidgetQml(QWidget* pParent) + : Page(pParent) + , mUi(new Ui::HistoryWidgetQml()) + , mDpi(DpiCalculator::getDpi()) + , mHistoryModel(&AppSettings::getInstance().getHistorySettings(), &AppSettings::getInstance().getProviderSettings()) + , mQmlExtension() +{ + mUi->setupUi(this); + + connect(mUi->quickWidget, &QQuickWidget::statusChanged, this, &HistoryWidgetQml::onQQuickWidgetStatusChanged); + + QQmlContext* context = mUi->quickWidget->rootContext(); + context->setContextProperty("widgetPlugin", this); + context->setContextProperty("screenDpi", mDpi); + context->setContextProperty("qmlExtension", &mQmlExtension); + context->setContextProperty("historyModel", &mHistoryModel); + + mUi->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + mUi->quickWidget->engine()->addImportPath(UIPlugInQml::getFile("qml_stationary/").toString()); + mUi->quickWidget->setSource(UIPlugInQml::getFile("qml_stationary/HistoryWidgetQmlPlugin.qml")); +} + + +HistoryWidgetQml::~HistoryWidgetQml() +{ +} + + +void HistoryWidgetQml::onQQuickWidgetStatusChanged(QQuickWidget::Status pStatus) +{ + qDebug(qml) << "HistoryWidget status:" << pStatus; + + const QList& errors = mUi->quickWidget->errors(); + for (const QQmlError& error : errors) + { + qWarning(qml) << "HistoryWidget QML error:" << error.toString(); + } +} + + +void HistoryWidgetQml::showDetailDialog(const QString& pDetails) +{ + DetailDialog d(this); + d.setDetails(pDetails); + d.exec(); +} diff --git a/src/gui/HistoryWidgetQml.h b/src/gui/HistoryWidgetQml.h new file mode 100644 index 0000000..3e67466 --- /dev/null +++ b/src/gui/HistoryWidgetQml.h @@ -0,0 +1,51 @@ +/*! + * \brief A history widget which embeds QML + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AppSettings.h" +#include "DetailDialog.h" +#include "HistoryModel.h" +#include "QmlExtension.h" +#include "generic/Page.h" + +#include +#include +#include + +namespace Ui +{ +class HistoryWidgetQml; +} + +namespace governikus +{ + +class ProviderDetailWidget; + +class HistoryWidgetQml + : public Page +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + qreal mDpi; + HistoryModel mHistoryModel; + QmlExtension mQmlExtension; + + private Q_SLOTS: + void onQQuickWidgetStatusChanged(QQuickWidget::Status pStatus); + + public: + HistoryWidgetQml(QWidget* pParent = nullptr); + virtual ~HistoryWidgetQml(); + + Q_INVOKABLE void showDetailDialog(const QString& pDetails); +}; + +} /* namespace governikus */ diff --git a/src/gui/HistoryWidgetQml.ui b/src/gui/HistoryWidgetQml.ui new file mode 100644 index 0000000..7ea7b99 --- /dev/null +++ b/src/gui/HistoryWidgetQml.ui @@ -0,0 +1,48 @@ + + + HistoryWidgetQml + + + + 0 + 0 + 599 + 666 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + QQuickWidget::SizeViewToRootObject + + + + + + + + + + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
+
+ + +
diff --git a/src/gui/LogFilesDialog.cpp b/src/gui/LogFilesDialog.cpp index fea111d..e537d69 100644 --- a/src/gui/LogFilesDialog.cpp +++ b/src/gui/LogFilesDialog.cpp @@ -167,7 +167,7 @@ void LogFilesDialog::onSaveButtonClicked() } -bool LogFilesDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool LogFilesDialog::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -178,5 +178,5 @@ bool LogFilesDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QDialog::eventFilter(pObject, pEvent); } diff --git a/src/gui/LogFilesDialog.ui b/src/gui/LogFilesDialog.ui index 8b84bc1..b62f844 100644 --- a/src/gui/LogFilesDialog.ui +++ b/src/gui/LogFilesDialog.ui @@ -80,14 +80,14 @@ - Save… + Save... - Delete old files… + Delete old files... diff --git a/src/gui/PinSettingsInfoWidget.h b/src/gui/PinSettingsInfoWidget.h index 8cda52f..a4c635b 100644 --- a/src/gui/PinSettingsInfoWidget.h +++ b/src/gui/PinSettingsInfoWidget.h @@ -1,5 +1,5 @@ /*! - * \brief Widget for pin settings information. + * \brief Widget for PIN settings information. * * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ diff --git a/src/gui/PinSettingsWidget.cpp b/src/gui/PinSettingsWidget.cpp index 9789d4a..94fb4b4 100644 --- a/src/gui/PinSettingsWidget.cpp +++ b/src/gui/PinSettingsWidget.cpp @@ -153,7 +153,7 @@ QVector PinSettingsWidget::getReaderWithNPA(const QVector& pRead { if (!knownReaderTypes.contains(readerInfo.getReaderType())) { - knownReaderInfos.append(readerInfo); - knownReaderTypes.append(readerInfo.getReaderType()); + knownReaderInfos += readerInfo; + knownReaderTypes += readerInfo.getReaderType(); } } @@ -333,7 +333,7 @@ void PinSettingsWidget::hideEvent(QHideEvent* pEvent) if (mRandomPinDialog && mRandomPinDialog->isVisible()) { // close the PinPad in case the tab is hidden, - // e.g. an authentication was started, so the pin change is aborted. + // e.g. an authentication was started, so the PIN change is aborted. mRandomPinDialog->reject(); } } @@ -665,7 +665,7 @@ void PinSettingsWidget::onRandomPinButtonClicked() mRandomPinDialog = new RandomPinDialog(6, selectedReaderName, this); if (mRandomPinDialog->exec() == QDialog::Accepted && !mRandomPinDialog->getPin().isEmpty()) { - QToolButton* pinButton = dynamic_cast(sender()); + QToolButton* pinButton = qobject_cast(sender()); if (pinButton == nullptr) { qCCritical(gui) << "sender == nullptr"; diff --git a/src/gui/PinSettingsWidget.ui b/src/gui/PinSettingsWidget.ui index a3db1c9..b519461 100644 --- a/src/gui/PinSettingsWidget.ui +++ b/src/gui/PinSettingsWidget.ui @@ -44,7 +44,7 @@ Select a secure PIN that consists of six digits. Do not select a number that can be guessed easily, such as "123456", your date of birth or any other number that is printed on your ID card. -When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by Bundesdruckerei GmbH onhebalf of your citizen centre. +When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by your competent authority. Please note that the PIN may only consist of digits (0-9). @@ -80,7 +80,7 @@ Please note that the PIN may only consist of digits (0-9).
Select a secure PIN that consists of six digits. Do not select a number that can be guessed easily, such as "123456", your date of birth or any other number that is printed on your ID card. -When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by Bundesdruckerei GmbH onhebalf of your citizen centre. +When you change your PIN for the first time, please enter your five-digit transport PIN in the field "Current PIN / Transport PIN". You received your transport PIN with the letter sent to you by your competent authority. Please note that the PIN may only consist of digits (0-9). @@ -114,9 +114,9 @@ Please note that the PIN may only consist of digits (0-9). Qt::TabFocus - You have entered the wrong PIN three times. The online identification function is now blocked. Please use your personal unblocking key (PUK) to unblock your ID card. You received the PUK with the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre. + You have entered the wrong PIN three times. The online identification function is now blocked. Please use your personal unblocking key (PUK) to unblock your ID card. You received the PUK with the letter sent to you by your competent authority. -Please note that you can only use the PUK to unblock the eID function. If you have forgotten your PIN, you can have a new PIN set at the citizen centre. +Please note that you can only use the PUK to unblock the eID function. If you have forgotten your PIN, you can have a new PIN set at your competent authority. Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -430,7 +430,7 @@ Please note that you can only use the PUK to unblock the eID function. If you ha <html> <h4>eID feature deactivated</h4> -<p>The eID function of your ID card is deactivated. Please contact your citizen centre to activate the eID function.</p> +<p>The eID function of your ID card is deactivated. Please contact your competent authority to activate the eID function.</p> </html> @@ -1133,7 +1133,7 @@ If not, you can now remove your ID card form the card reader. Qt::TabFocus - successful pin change icon + successful PIN change icon Qt::AlignCenter diff --git a/src/gui/ProviderWidget.cpp b/src/gui/ProviderWidget.cpp index 4247601..9dd8082 100644 --- a/src/gui/ProviderWidget.cpp +++ b/src/gui/ProviderWidget.cpp @@ -33,7 +33,7 @@ ProviderWidget::ProviderWidget(QWidget* pParent) mUi->setupUi(this); connect(mUi->providerSearch, &QLineEdit::textChanged, this, &ProviderWidget::searchProvider); - connect(ProviderService::getSharedInstance(), &ProviderService::fireUpdateFinished, this, &ProviderWidget::onProviderChanged); + connect(&ProviderService::getInstance(), &ProviderService::fireUpdateFinished, this, &ProviderWidget::onProviderChanged); fill(); } @@ -55,8 +55,8 @@ void ProviderWidget::fill() { qDebug() << "add provider for desktop widgets."; QStringList header; - header.append(tr("Name")); - header.append(tr("Address")); + header += tr("Name"); + header += tr("Address"); ProviderSettings& providerSettings = AppSettings::getInstance().getProviderSettings(); providerSettings.load(); @@ -68,7 +68,8 @@ void ProviderWidget::fill() int row = 0; for (const Provider& provider : providerSettings.getProviders()) { - QLabel* providerName = new QLabel(provider.getShortName()); + + QLabel* providerName = new QLabel(provider.getLongName().isEmpty() ? provider.getShortName() : provider.getLongName()); providerName->setFocusPolicy(Qt::TabFocus); providerName->setToolTip(providerName->text()); providerName->setTextFormat(Qt::RichText); diff --git a/src/gui/ProviderWidgetQml.cpp b/src/gui/ProviderWidgetQml.cpp new file mode 100644 index 0000000..187856f --- /dev/null +++ b/src/gui/ProviderWidgetQml.cpp @@ -0,0 +1,63 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "ProviderWidgetQml.h" +#include "ui_ProviderWidgetQml.h" + +#include "ApplicationModel.h" +#include "DpiCalculator.h" +#include "UIPlugInQml.h" + +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + +using namespace governikus; + + +ProviderWidgetQml::ProviderWidgetQml(QWidget* pParent) + : Page(pParent) + , mUi(new Ui::ProviderWidgetQml()) + , mDpi(DpiCalculator::getDpi()) + , mHistoryModel(&AppSettings::getInstance().getHistorySettings(), &AppSettings::getInstance().getProviderSettings()) + , mProviderModel(&AppSettings::getInstance().getProviderSettings()) + , mQmlExtension() +{ + mUi->setupUi(this); + + connect(mUi->quickWidget, &QQuickWidget::statusChanged, this, &ProviderWidgetQml::onQQuickWidgetStatusChanged); + + QQmlContext* context = mUi->quickWidget->rootContext(); + context->setContextProperty("widgetPlugin", this); + context->setContextProperty("screenDpi", mDpi); + context->setContextProperty("qmlExtension", &mQmlExtension); + context->setContextProperty("historyModel", &mHistoryModel); + context->setContextProperty("providerModel", &mProviderModel); + context->setContextProperty("applicationModel", &ApplicationModel::getWidgetInstance()); + + mUi->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + mUi->quickWidget->engine()->addImportPath(UIPlugInQml::getFile("qml_stationary/").toString()); + mUi->quickWidget->setSource(UIPlugInQml::getFile("qml_stationary/ProviderWidgetQmlPlugin.qml")); +} + + +ProviderWidgetQml::~ProviderWidgetQml() +{ +} + + +void ProviderWidgetQml::onQQuickWidgetStatusChanged(QQuickWidget::Status pStatus) +{ + qDebug(qml) << "ProviderWidget status:" << pStatus; + + const QList& errors = mUi->quickWidget->errors(); + for (const QQmlError& error : errors) + { + qWarning(qml) << "ProviderWidget QML error:" << error.toString(); + } +} diff --git a/src/gui/ProviderWidgetQml.h b/src/gui/ProviderWidgetQml.h new file mode 100644 index 0000000..b56c97b --- /dev/null +++ b/src/gui/ProviderWidgetQml.h @@ -0,0 +1,50 @@ +/*! + * \brief TODO + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AppSettings.h" +#include "HistoryModel.h" +#include "ProviderCategoryFilterModel.h" +#include "QmlExtension.h" +#include "generic/Page.h" + +#include +#include +#include + +namespace Ui +{ +class ProviderWidgetQml; +} + +namespace governikus +{ + +class ProviderDetailWidget; + +class ProviderWidgetQml + : public Page +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + qreal mDpi; + HistoryModel mHistoryModel; + ProviderCategoryFilterModel mProviderModel; + QmlExtension mQmlExtension; + + private Q_SLOTS: + void onQQuickWidgetStatusChanged(QQuickWidget::Status pStatus); + + public: + ProviderWidgetQml(QWidget* pParent = nullptr); + virtual ~ProviderWidgetQml(); +}; + +} /* namespace governikus */ diff --git a/src/gui/ProviderWidgetQml.ui b/src/gui/ProviderWidgetQml.ui new file mode 100644 index 0000000..bb149a1 --- /dev/null +++ b/src/gui/ProviderWidgetQml.ui @@ -0,0 +1,48 @@ + + + ProviderWidgetQml + + + + 0 + 0 + 599 + 666 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + QQuickWidget::SizeViewToRootObject + + + + + + + + + + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
+
+ + +
diff --git a/src/gui/ProxySettingsWidget.cpp b/src/gui/ProxySettingsWidget.cpp deleted file mode 100644 index 5d3e42e..0000000 --- a/src/gui/ProxySettingsWidget.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*! - * ProxySettingsWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProxySettingsWidget.h" - -#include "ui_ProxySettingsWidget.h" - -#include -#include - -using namespace governikus; - -ProxySettingsWidget::ProxySettingsWidget(QWidget* pParent) - : Page(tr("Extended"), pParent) - , mUi(new Ui::ProxySettingsWidget()) -{ - mUi->setupUi(this); - - setContentsMargins(9, 9, 9, 9); - connect(mUi->noProxyRadioButton, &QRadioButton::toggled, this, &ProxySettingsWidget::onProxyTypeChanged); - connect(mUi->systemProxyRadioButton, &QRadioButton::toggled, this, &ProxySettingsWidget::onProxyTypeChanged); -} - - -ProxySettingsWidget::~ProxySettingsWidget() -{ -} - - -/* - ProxyType ProxySettingsWidget::getProxyType() const - { - if (mUi->systemProxyRadioButton->isChecked()) - { - return ProxyType::SYSTEM; - } - return ProxyType::NONE; - } - - - void ProxySettingsWidget::setProxyType(ProxyType pType) - { - switch (pType) - { - case ProxyType::NONE: - mUi->noProxyRadioButton->setChecked(true); - break; - - case ProxyType::SYSTEM: - mUi->systemProxyRadioButton->setChecked(true); - break; - } - } - */ -void ProxySettingsWidget::onProxyTypeChanged(bool pChecked) -{ - if (pChecked) - { - return; - } - onProxySettingsChanged(); -} - - -void ProxySettingsWidget::onProxySettingsChanged() -{ - Q_EMIT settingsChanged(); -} - - -void ProxySettingsWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/ProxySettingsWidget.h b/src/gui/ProxySettingsWidget.h deleted file mode 100644 index 2d590de..0000000 --- a/src/gui/ProxySettingsWidget.h +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * \brief Widget for the proxy settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "ProxySettings.h" -#include "generic/Page.h" - -#include -#include - -namespace Ui -{ -class ProxySettingsWidget; -} - -namespace governikus -{ - -class ProxySettingsWidget - : public Page -{ - Q_OBJECT - - public: - ProxySettingsWidget(QWidget* pParent = nullptr); - virtual ~ProxySettingsWidget(); - - //QNetworkProxy::ProxyType getProxyType() const; - //void setProxyType(QNetworkProxy::ProxyType pType); - - Q_SIGNALS: - void settingsChanged(); - - private Q_SLOTS: - void onProxyTypeChanged(bool pChecked); - void onProxySettingsChanged(); - - private: - QScopedPointer mUi; - - virtual void paintEvent(QPaintEvent*) override; -}; - -} /* namespace governikus */ diff --git a/src/gui/ProxySettingsWidget.ui b/src/gui/ProxySettingsWidget.ui deleted file mode 100644 index c8441c2..0000000 --- a/src/gui/ProxySettingsWidget.ui +++ /dev/null @@ -1,127 +0,0 @@ - - - ProxySettingsWidget - - - - 0 - 0 - 467 - 430 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - <h4>Is your network connected by proxy to the Internet?</h4> -<p>In most cases no proxy is used. If you cannot answer the question or if you are insecure please ask your system administrator.</p> - - - true - - - 15 - - - - - - - Qt::Horizontal - - - - - - - - 15 - - - 15 - - - 15 - - - 15 - - - - - - - no proxy - - - networkbuttongroup - - - - - - - use system settings - - - true - - - networkbuttongroup - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - proxySettingsDescriptionLabel - noProxyRadioButton - systemProxyRadioButton - - - - - - -
diff --git a/src/gui/RandomPinDialog.cpp b/src/gui/RandomPinDialog.cpp index 585089c..faa16d1 100644 --- a/src/gui/RandomPinDialog.cpp +++ b/src/gui/RandomPinDialog.cpp @@ -100,7 +100,7 @@ QString RandomPinDialog::getPin() void RandomPinDialog::onPosButtonClicked() { - QToolButton* posButton = dynamic_cast(sender()); + QToolButton* posButton = qobject_cast(sender()); if (posButton) { mUi->pin->setText(mUi->pin->text() + "" + posButton->property(PIN).toString()); @@ -126,7 +126,7 @@ void RandomPinDialog::onCardInserted() } -bool RandomPinDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool RandomPinDialog::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -137,5 +137,5 @@ bool RandomPinDialog::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QDialog::eventFilter(pObject, pEvent); } diff --git a/src/gui/RandomPinDialog.h b/src/gui/RandomPinDialog.h index b60de2e..12c1149 100644 --- a/src/gui/RandomPinDialog.h +++ b/src/gui/RandomPinDialog.h @@ -1,7 +1,7 @@ /*! * RandomPinDialog.h * - * \brief Dialog for display the random pin. + * \brief Dialog for display the random PIN. * * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ diff --git a/src/gui/RandomPinDialog.ui b/src/gui/RandomPinDialog.ui index c8899f7..9dc2df3 100644 --- a/src/gui/RandomPinDialog.ui +++ b/src/gui/RandomPinDialog.ui @@ -255,7 +255,7 @@ - pin field + PIN field 6 diff --git a/src/gui/ReaderDriverDialog.cpp b/src/gui/ReaderDriverDialog.cpp index 42d1f3a..5d6004c 100644 --- a/src/gui/ReaderDriverDialog.cpp +++ b/src/gui/ReaderDriverDialog.cpp @@ -39,7 +39,7 @@ ReaderDriverDialog::~ReaderDriverDialog() } -bool ReaderDriverDialog::eventFilter(QObject* /* pObject */, QEvent* pEvent) +bool ReaderDriverDialog::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -50,5 +50,5 @@ bool ReaderDriverDialog::eventFilter(QObject* /* pObject */, QEvent* pEvent) return true; } } - return false; + return QDialog::eventFilter(pObject, pEvent); } diff --git a/src/gui/SelfInformationWidget.ui b/src/gui/SelfInformationWidget.ui index 2c7a6c2..b492d31 100644 --- a/src/gui/SelfInformationWidget.ui +++ b/src/gui/SelfInformationWidget.ui @@ -112,7 +112,7 @@ Qt::TabFocus - Use the button 'See my personal data now…' to display the data stored on your ID card. An Internet connection is required to display the data. Your personal data is neither saved nor processed in any way. + Use the button 'See my personal data now...' to display the data stored on your ID card. An Internet connection is required to display the data. Your personal data is neither saved nor processed in any way. true @@ -164,7 +164,7 @@ - See my personal data now… + See my personal data now... diff --git a/src/gui/SettingsWidget.ui b/src/gui/SettingsWidget.ui index 974fdfa..8ec56d2 100644 --- a/src/gui/SettingsWidget.ui +++ b/src/gui/SettingsWidget.ui @@ -71,7 +71,7 @@ - Diagnosis… + Diagnosis... diff --git a/src/gui/SetupAssistantWizard.cpp b/src/gui/SetupAssistantWizard.cpp index 09a4bed..c03faf7 100644 --- a/src/gui/SetupAssistantWizard.cpp +++ b/src/gui/SetupAssistantWizard.cpp @@ -74,9 +74,9 @@ SetupAssistantWizard::SetupAssistantWizard(QWidget* pParent) setMinimumSize(700, 450); setWizardStyle(QWizard::ClassicStyle); setWindowModality(Qt::WindowModal); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setOption(QWizard::NoCancelButton, false); setAttribute(Qt::WA_DeleteOnClose); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); mPageCount = 3; if (mNoScriptFinder.isExtensionFound()) @@ -380,10 +380,10 @@ QWizardPage* SetupAssistantWizard::createConclusionPage() QLabel* transportPinLabel = new QLabel(tr("Personal 6-digit PIN" "

" - "Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre.")); + "Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by your competent authority.")); transportPinLabel->setWordWrap(true); transportPinLabel->setFocusPolicy(Qt::TabFocus); - transportPinLabel->setAccessibleName(tr("Personal 6-digit PIN. Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by Bundesdruckerei GmbH on behalf of your citizen centre.")); + transportPinLabel->setAccessibleName(tr("Personal 6-digit PIN. Prior to the first use of the online identification function you have to replace the transport PIN by an individual 6-digit PIN. The AusweisApp's PIN management offers this function. For replacing the transport PIN you need the letter sent to you by your competent authority.")); GuiUtils::updateFontSize(transportPinLabel); @@ -433,7 +433,7 @@ void SetupAssistantWizard::accept() } -bool SetupAssistantWizard::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +bool SetupAssistantWizard::eventFilter(QObject* pObject, QEvent* pEvent) { if (pEvent->type() == QEvent::KeyPress) { @@ -444,5 +444,5 @@ bool SetupAssistantWizard::eventFilter(QObject* /*pObject*/, QEvent* pEvent) return true; } } - return false; + return QWizard::eventFilter(pObject, pEvent); } diff --git a/src/gui/UIPlugInWidgets.cpp b/src/gui/UIPlugInWidgets.cpp index f51471f..406e3ff 100644 --- a/src/gui/UIPlugInWidgets.cpp +++ b/src/gui/UIPlugInWidgets.cpp @@ -4,6 +4,7 @@ #include "UIPlugInWidgets.h" +#include "ApplicationModel.h" #include "workflow/WorkflowAuthenticateQtGui.h" #include "workflow/WorkflowChangePinQtGui.h" #include "workflow/WorkflowSelfInfoQtGui.h" @@ -37,9 +38,10 @@ void UIPlugInWidgets::doShutdown() void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext) { pContext->setReaderType(ReaderManagerPlugInType::PCSC); + ApplicationModel::getWidgetInstance().resetContext(pContext); QSharedPointer currentWorkflowGui; - if (auto changePinContext = pContext.dynamicCast()) + if (auto changePinContext = pContext.objectCast()) { currentWorkflowGui = mGui.createWorkflowChangePinUi(changePinContext); mGui.activateWorkflowUi(currentWorkflowGui); @@ -47,7 +49,7 @@ void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext } bool allowHideAfterWorklow = true; - if (auto selfAuthContext = pContext.dynamicCast()) + if (auto selfAuthContext = pContext.objectCast()) { if (mGui.askChangeTransportPinNow()) { @@ -56,7 +58,7 @@ void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext } currentWorkflowGui = mGui.createWorkflowSelfInfoUi(selfAuthContext); } - else if (auto authContext = pContext.dynamicCast()) + else if (auto authContext = pContext.objectCast()) { if (mGui.askChangeTransportPinNow()) { @@ -75,6 +77,7 @@ void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext void UIPlugInWidgets::onWorkflowFinished(QSharedPointer pContext) { Q_UNUSED(pContext) + ApplicationModel::getWidgetInstance().resetContext(); mGui.deactivateCurrentWorkflowUi(); } @@ -91,7 +94,11 @@ void UIPlugInWidgets::onShowUi(UiModule pModule) } +#ifndef QT_NO_NETWORKPROXY void UIPlugInWidgets::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) { mGui.onProxyAuthenticationRequired(pProxy, pAuthenticator); } + + +#endif diff --git a/src/gui/UIPlugInWidgets.h b/src/gui/UIPlugInWidgets.h index 2a22799..77ffd41 100644 --- a/src/gui/UIPlugInWidgets.h +++ b/src/gui/UIPlugInWidgets.h @@ -34,7 +34,9 @@ class UIPlugInWidgets virtual void onWorkflowFinished(QSharedPointer pContext) override; virtual void onApplicationStarted() override; virtual void onShowUi(UiModule pModule) override; +#ifndef QT_NO_NETWORKPROXY virtual void onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) override; +#endif }; } /* namespace governikus */ diff --git a/src/gui/UpdateWindow.cpp b/src/gui/UpdateWindow.cpp new file mode 100644 index 0000000..10e787a --- /dev/null +++ b/src/gui/UpdateWindow.cpp @@ -0,0 +1,102 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "UpdateWindow.h" + +#include "Updater.h" +#include "ui_UpdateWindow.h" + +#include +#include + +using namespace governikus; + +UpdateWindow::UpdateWindow(bool pSilent, QWidget* pParent) + : QDialog(pParent) + , mUi() + , mSilent(pSilent) + , mUpdateData() +{ + setAttribute(Qt::WA_DeleteOnClose, true); + auto& updater = Updater::getInstance(); + connect(&updater, &Updater::fireAppUpdateCheckFinished, this, &UpdateWindow::onAppUpdateCheckFinished); + updater.checkAppUpdate(); +} + + +UpdateWindow::~UpdateWindow() +{ +} + + +void UpdateWindow::onAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError) +{ + if (pError.isError()) + { + showBox(QMessageBox::Critical, pError.toErrorDescription()); + } + else if (pUpdateAvailable) + { + mUpdateData = Updater::getInstance().getUpdateData(); + fillData(); + show(); + return; + } + else if (!mSilent) + { + showBox(QMessageBox::Information, tr("Your software is up to date.")); + } + + close(); +} + + +void UpdateWindow::onUpdateClicked() +{ + const auto& url = mUpdateData.getUrl(); + qDebug() << "Download application update:" << url; + if (!QDesktopServices::openUrl(url)) + { + showBox(QMessageBox::Warning, tr("Unable to open this link in a browser. Please copy and paste the link into the address bar of your browser.")); + } + close(); +} + + +void UpdateWindow::onSkipVersionClicked() +{ + Updater::getInstance().skipVersion(mUpdateData.getVersion()); + close(); +} + + +void UpdateWindow::showBox(QMessageBox::Icon pIcon, const QString& pMsg) +{ + QMessageBox box(QApplication::activeWindow()); + box.setIcon(pIcon); + box.setWindowTitle(QApplication::applicationName() + QStringLiteral(" - ") + tr("Updates")); + box.setWindowIcon(QIcon(QStringLiteral(":/images/npa.svg"))); + box.setWindowModality(Qt::WindowModal); + box.setText(pMsg); + box.exec(); +} + + +void UpdateWindow::fillData() +{ + if (!mUi) + { + mUi.reset(new Ui::UpdateWindow()); + mUi->setupUi(this); + + connect(mUi->skipButton, &QAbstractButton::clicked, this, &UpdateWindow::onSkipVersionClicked); + connect(mUi->reminderButton, &QAbstractButton::clicked, this, &QWidget::close); + connect(mUi->downloadButton, &QAbstractButton::clicked, this, &UpdateWindow::onUpdateClicked); + } + + mUi->downloadLabel->setText(mUi->downloadLabel->text().arg(mUpdateData.getVersion(), QApplication::applicationVersion())); + mUi->linkLabel->setText(mUi->linkLabel->text().arg(mUpdateData.getUrl().toString())); + mUi->releaseNotes->setHtml(mUpdateData.getNotes().isEmpty() ? tr("

Download of release notes failed

") : mUpdateData.getNotes()); + mUi->releaseNotes->setAccessibleName(mUi->releaseNotes->toPlainText()); +} diff --git a/src/gui/UpdateWindow.h b/src/gui/UpdateWindow.h new file mode 100644 index 0000000..b29f1bf --- /dev/null +++ b/src/gui/UpdateWindow.h @@ -0,0 +1,47 @@ +/*! + * \brief Window for application updates + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AppUpdateData.h" + +#include "GlobalStatus.h" + +#include +#include + +namespace Ui +{ +class UpdateWindow; +} + +namespace governikus +{ + +class UpdateWindow + : public QDialog +{ + Q_OBJECT + + private: + QScopedPointer mUi; + bool mSilent; + AppUpdateData mUpdateData; + + void showBox(QMessageBox::Icon pIcon, const QString& pMsg); + void fillData(); + + public: + UpdateWindow(bool pSilent = false, QWidget* pParent = nullptr); + virtual ~UpdateWindow(); + + private Q_SLOTS: + void onAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError); + void onUpdateClicked(); + void onSkipVersionClicked(); +}; + +} /* namespace governikus */ diff --git a/src/external/fervor/fvupdatewindow.ui b/src/gui/UpdateWindow.ui similarity index 71% rename from src/external/fervor/fvupdatewindow.ui rename to src/gui/UpdateWindow.ui index 61b0b34..e564ba6 100644 --- a/src/external/fervor/fvupdatewindow.ui +++ b/src/gui/UpdateWindow.ui @@ -1,7 +1,7 @@ - FvUpdateWindow - + UpdateWindow + Qt::ApplicationModal @@ -9,22 +9,22 @@ 0 0 - 640 - 480 + 600 + 450
Software Update - - :/images/autentapp2.iconset/icon_16x16.png:/images/autentapp2.iconset/icon_16x16.png + + :/images/npa.svg:/images/npa.svg - + - + 75 @@ -35,22 +35,22 @@ Qt::TabFocus - A new version of %1 is available! + A new version of AusweisApp2 is available! - + Qt::TabFocus - %1 %2 is now available - you have %3. Would you like to download it now? + AusweisApp2 %1 is now available - you have %2. Would you like to download it now? - + Qt::TabFocus @@ -60,7 +60,7 @@ - + Qt::TabFocus @@ -91,7 +91,7 @@
- + 160 @@ -115,12 +115,12 @@ Qt::TabFocus - Download this update and close "%1". Install the update and start "%1" again. + Download this update and close current "AusweisApp2". Install the update and start "AusweisApp2" again. - + Qt::TabFocus @@ -130,19 +130,16 @@ - + - - - skip update of current version - + Skip update - + Qt::Horizontal @@ -155,20 +152,14 @@ - - - remind me later for this available version - + Remind me later - - - download available version - + Download update diff --git a/src/gui/generic/BusyOverlay.ui b/src/gui/generic/BusyOverlay.ui index d4a7537..f72492e 100644 --- a/src/gui/generic/BusyOverlay.ui +++ b/src/gui/generic/BusyOverlay.ui @@ -36,7 +36,7 @@ Qt::StrongFocus - The process is started … + The process is started... Qt::AlignCenter diff --git a/src/gui/generic/BusyOverlayContainer.cpp b/src/gui/generic/BusyOverlayContainer.cpp index a0c9356..1cf67a7 100644 --- a/src/gui/generic/BusyOverlayContainer.cpp +++ b/src/gui/generic/BusyOverlayContainer.cpp @@ -21,7 +21,7 @@ BusyOverlayContainer::BusyOverlayContainer(QWidget* pWidgetToOverlay, bool pStar QBoxLayout* overlayContainerLayout = new QVBoxLayout(busyOverlayContainer); overlayContainerLayout->addWidget(mOverlay, 0, Qt::AlignHCenter | Qt::AlignVCenter); - QStackedLayout* stackLayout = dynamic_cast(layout()); + QStackedLayout* stackLayout = qobject_cast(layout()); stackLayout->setStackingMode(QStackedLayout::StackAll); stackLayout->addWidget(pWidgetToOverlay); diff --git a/src/gui/generic/ExclusiveButtonGroup.cpp b/src/gui/generic/ExclusiveButtonGroup.cpp index 35e8580..f703f8c 100644 --- a/src/gui/generic/ExclusiveButtonGroup.cpp +++ b/src/gui/generic/ExclusiveButtonGroup.cpp @@ -25,7 +25,7 @@ ExclusiveButtonGroup::~ExclusiveButtonGroup() void ExclusiveButtonGroup::addButton(QAbstractButton* pButton) { - mButtons.append(pButton); + mButtons += pButton; pButton->installEventFilter(this); @@ -54,7 +54,7 @@ void ExclusiveButtonGroup::removeButton(QAbstractButton* pButton) bool ExclusiveButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) { - if (QAbstractButton* button = dynamic_cast(pWatched)) + if (QAbstractButton* button = qobject_cast(pWatched)) { if (pEvent->type() == QEvent::MouseButtonPress && button->isChecked()) { @@ -77,7 +77,7 @@ bool ExclusiveButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) void ExclusiveButtonGroup::onButtonClicked(bool /*pChecked*/) { - if (QAbstractButton* button = dynamic_cast(sender())) + if (QAbstractButton* button = qobject_cast(sender())) { Q_EMIT buttonClicked(button); } @@ -86,7 +86,7 @@ void ExclusiveButtonGroup::onButtonClicked(bool /*pChecked*/) void ExclusiveButtonGroup::onButtonPressed() { - if (QAbstractButton* button = dynamic_cast(sender())) + if (QAbstractButton* button = qobject_cast(sender())) { Q_EMIT buttonPressed(button); } @@ -95,7 +95,7 @@ void ExclusiveButtonGroup::onButtonPressed() void ExclusiveButtonGroup::onButtonReleased() { - if (QAbstractButton* button = dynamic_cast(sender())) + if (QAbstractButton* button = qobject_cast(sender())) { Q_EMIT buttonReleased(button); } @@ -104,7 +104,7 @@ void ExclusiveButtonGroup::onButtonReleased() void ExclusiveButtonGroup::onButtonToggled(bool pChecked) { - if (QAbstractButton* button = dynamic_cast(sender())) + if (QAbstractButton* button = qobject_cast(sender())) { if (pChecked) { diff --git a/src/gui/generic/GuiUtils.cpp b/src/gui/generic/GuiUtils.cpp index efa0975..ab066e3 100644 --- a/src/gui/generic/GuiUtils.cpp +++ b/src/gui/generic/GuiUtils.cpp @@ -8,6 +8,7 @@ #include #include +#include #include using namespace governikus; @@ -31,33 +32,33 @@ QFrame* GuiUtils::createLine(bool pHorizontal) } -void GuiUtils::showPinCanPukErrorDialog(ReturnCode pReturnCode, int pRetryCounter, QWidget* pParent) +void GuiUtils::showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent) { QMessageBox messageBox(pParent); QString title; QString text; switch (pReturnCode) { - case ReturnCode::CAN_INVALID: + case CardReturnCode::INVALID_CAN: title = tr("Wrong card access number (CAN)"); text = tr("The given card access number (CAN) is not correct. You have one more try to enter the correct PIN." " Please mind that you have to acknowledge this last try with your card access" " number (CAN)."); break; - case ReturnCode::PUK_INVALID: + case CardReturnCode::INVALID_PUK: title = tr("Wrong PUK"); text = tr("Please enter your PUK again."); break; - case ReturnCode::PUK_INOPERATIVE: + case CardReturnCode::PUK_INOPERATIVE: title = tr("PUK is inoperative"); text = tr("You have correctly entered the PUK ten times and have thus reached the maximum count." - " The PUK is now inoperative and can no longer be used for unblocking the PIN. Please address the" - " citizen centre that has issued your ID card for unblocking your PIN."); + " The PUK is now inoperative and can no longer be used for unblocking the PIN. Please address your" + " competent authority that has issued your ID card for unblocking your PIN."); break; - case ReturnCode::PIN_INVALID: + case CardReturnCode::INVALID_PIN: default: title = tr("Wrong PIN"); break; @@ -88,7 +89,7 @@ void GuiUtils::showPinCanPukErrorDialog(ReturnCode pReturnCode, int pRetryCounte messageBox.setWindowTitle(QCoreApplication::applicationName() + " - " + title); messageBox.setWindowModality(Qt::WindowModal); messageBox.setText(QStringLiteral("

%1

%2

").arg(title, text)); - messageBox.setIconPixmap(QPixmap(QStringLiteral(":images/autentapp2.iconset/icon_32x32.png"))); + messageBox.setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); messageBox.setStandardButtons(QMessageBox::StandardButton::Ok); messageBox.exec(); @@ -146,5 +147,5 @@ void GuiUtils::updateFontSize(QWidget* pWidget) newFont.setPointSizeF(newFont.pointSizeF() * factor); } - return pWidget->setFont(newFont); + pWidget->setFont(newFont); } diff --git a/src/gui/generic/GuiUtils.h b/src/gui/generic/GuiUtils.h index 841e476..6e27b77 100644 --- a/src/gui/generic/GuiUtils.h +++ b/src/gui/generic/GuiUtils.h @@ -10,7 +10,7 @@ #include -#include "ReturnCode.h" +#include "CardReturnCode.h" class QFrame; @@ -28,7 +28,7 @@ class GuiUtils static QFrame* createLine(bool pHorizontal); - static void showPinCanPukErrorDialog(ReturnCode pReturnCode, int pRetryCounter, QWidget* pParent); + static void showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent); static bool showWrongPinBlockedDialog(QWidget* pParent); static void updateFontSize(QWidget* pWidget); }; diff --git a/src/gui/generic/KeylessPasswordEdit.cpp b/src/gui/generic/KeylessPasswordEdit.cpp index 3f8e2a8..718828d 100644 --- a/src/gui/generic/KeylessPasswordEdit.cpp +++ b/src/gui/generic/KeylessPasswordEdit.cpp @@ -414,7 +414,7 @@ class KeylessPasswordEdit::DigitField break; case State::ACTIVE: - textToDraw = QString(QLatin1Char('0' + char(mValue))); + textToDraw = QString(QLatin1Char(static_cast('0' + char(mValue)))); break; } @@ -595,7 +595,7 @@ void KeylessPasswordEdit::setMaxLength(int pLength) { DigitField* field = new DigitField(mRenderingHelper.data(), this); mLayout->addWidget(field, 0, mDigitFields.size()); - mDigitFields.append(field); + mDigitFields += field; connect(field, &DigitField::activationRequested, this, &KeylessPasswordEdit::onFieldActivationRequested); connect(field, &DigitField::deactivationRequested, this, &KeylessPasswordEdit::onFieldDeactivationRequested); @@ -743,7 +743,7 @@ void KeylessPasswordEdit::keyPressEvent(QKeyEvent* pEvent) void KeylessPasswordEdit::onFieldActivationRequested() { - DigitField* field = dynamic_cast(sender()); + DigitField* field = qobject_cast(sender()); int fieldIndex = field != nullptr ? mDigitFields.indexOf(field) : -1; if (fieldIndex >= 0) { @@ -755,7 +755,7 @@ void KeylessPasswordEdit::onFieldActivationRequested() void KeylessPasswordEdit::onFieldDeactivationRequested() { - DigitField* field = dynamic_cast(sender()); + DigitField* field = qobject_cast(sender()); int fieldIndex = field != nullptr ? mDigitFields.indexOf(field) : -1; if (fieldIndex >= 0 && fieldIndex == mActiveFieldIndex) { diff --git a/src/gui/generic/TabButtonGroup.cpp b/src/gui/generic/TabButtonGroup.cpp index a8f4640..f28fa90 100644 --- a/src/gui/generic/TabButtonGroup.cpp +++ b/src/gui/generic/TabButtonGroup.cpp @@ -107,7 +107,7 @@ bool TabButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) return false; } - QAbstractButton* button = dynamic_cast(pWatched); + QAbstractButton* button = qobject_cast(pWatched); if (button == nullptr) { return false; diff --git a/src/gui/step/AuthenticateStepsWidget.cpp b/src/gui/step/AuthenticateStepsWidget.cpp index 269491c..03998e6 100644 --- a/src/gui/step/AuthenticateStepsWidget.cpp +++ b/src/gui/step/AuthenticateStepsWidget.cpp @@ -36,12 +36,6 @@ StepAuthenticationEac1Widget* AuthenticateStepsWidget::getEac1Page() const } -StepChooseDeviceWidget* AuthenticateStepsWidget::getChooseDevicePage() const -{ - return mUi->chooseDevicePage; -} - - SelfInfoWidget* AuthenticateStepsWidget::getSelfInfoPage() const { return mUi->selfInfoPage; diff --git a/src/gui/step/AuthenticateStepsWidget.h b/src/gui/step/AuthenticateStepsWidget.h index 6c586d1..09c1b88 100644 --- a/src/gui/step/AuthenticateStepsWidget.h +++ b/src/gui/step/AuthenticateStepsWidget.h @@ -23,7 +23,6 @@ namespace governikus class BusyOverlayContainer; class SelfInfoWidget; -class StepChooseDeviceWidget; class StepAuthenticationEac1Widget; class AuthenticateStepsWidget @@ -41,8 +40,6 @@ class AuthenticateStepsWidget } - StepChooseDeviceWidget* getChooseDevicePage() const; - StepAuthenticationEac1Widget* getEac1Page() const; SelfInfoWidget* getSelfInfoPage() const; diff --git a/src/gui/step/AuthenticateStepsWidget.ui b/src/gui/step/AuthenticateStepsWidget.ui index bce1645..48d0c01 100644 --- a/src/gui/step/AuthenticateStepsWidget.ui +++ b/src/gui/step/AuthenticateStepsWidget.ui @@ -12,7 +12,6 @@
- @@ -27,12 +26,6 @@
step/SelfInfoWidget.h
1
- - governikus::StepChooseDeviceWidget - QWidget -
step/StepChooseDeviceWidget.h
- 1 -
diff --git a/src/gui/step/SelfInfoWidget.cpp b/src/gui/step/SelfInfoWidget.cpp index f331841..3148574 100644 --- a/src/gui/step/SelfInfoWidget.cpp +++ b/src/gui/step/SelfInfoWidget.cpp @@ -4,14 +4,14 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "SelfAuthenticationData.h" - #include "SelfInfoWidget.h" -#include "ui_SelfInfoWidget.h" +#include "PdfCreator.h" +#include "SelfAuthenticationData.h" #include "generic/ListItem.h" #include "generic/ListItemSubTitle.h" #include "generic/ListItemTitle.h" +#include "ui_SelfInfoWidget.h" #include #include @@ -19,8 +19,6 @@ #include #include #include -#include -#include using namespace governikus; @@ -192,10 +190,6 @@ void SelfInfoWidget::onPrintButtonClicked() { if (mData != nullptr && mData->isValid()) { - QString htmlContent, company_header, company_footer; - QPrinter printer; - QRect printer_rect(printer.pageRect()); - QString pdfName = QFileDialog::getSaveFileName(this, QApplication::applicationName() + " - " + tr("Save"), QDir::currentPath(), @@ -203,114 +197,35 @@ void SelfInfoWidget::onPrintButtonClicked() if (pdfName.size() > 0) { - printer.setOutputFileName(pdfName); + PdfCreator pdf(pdfName); + QString text; - //Header - QString date = mData->getDateTime().toString(QStringLiteral("dd.MM.yyyy")); - QString time = mData->getDateTime().toString(QStringLiteral("hh:mm")); - - company_header.append("

"); - company_header.append(""); - company_header.append(tr("")); - company_header.append(""); - company_header.append(""); - company_header.append(""); - - company_header.append(tr(""); - company_header.append(""); - company_header.append("

ID card info - ") + QApplication::applicationName() + tr("

AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Bundesministerium des Innern (Federal Ministry of the Interior).


At %1 %2 the following data has been read out of your ID card:").arg(date, time) + "

"); - - company_footer.append(tr("

For further information, please see https://www.ausweisapp.bund.de/

")); - - //Setting up the header and calculating the header size - QTextDocument* document_header = new QTextDocument(this); - document_header->setPageSize(printer_rect.size()); - document_header->setHtml(company_header); - QSizeF header_size = document_header->size(); - - //Setting up the footer and calculating the footer size - QTextDocument* document_footer = new QTextDocument(this); - document_footer->setPageSize(printer_rect.size()); - document_footer->setHtml(company_footer); - QSizeF footer_size = document_footer->size(); - - //Calculating the main document size for one page - QSizeF center_size(printer_rect.width(), - (printer.pageRect().height() - header_size.toSize().height() - footer_size.toSize().height())); - - htmlContent.append(""); + QString date = mData->getDateTime().toString(tr("MM/dd/yyyy")); + QString time = mData->getDateTime().toString(tr("hh:mm AP")); + pdf.setHeadline(tr("At %1 %2 the following data has been read out of your ID card:").arg(date, time)); + pdf.initTable(2, {180}, {tr("Entry"), tr("Content")}); for (int i = 0; i < mUi->dataLayout->count(); ++i) { QLayoutItem* item = mUi->dataLayout->itemAt(i); if (!item->isEmpty()) { - if (i % 2 == 0) - { - htmlContent.append(""); + text = label->text(); } else { - htmlContent.append(""); + pdf.addTableRow({text, label->text()}); + pdf.toggleRowColor(); } } } - htmlContent.append("
"); - } - else - { - htmlContent.append(""); - } - - QLabel* test = qobject_cast(item->widget()); - htmlContent.append("" + test->text()); + QLabel* label = qobject_cast(item->widget()); if (i % 2 == 0) { - htmlContent.append("
"); - - //Insert HTML in main document - QTextDocument* main_doc = new QTextDocument(this); - main_doc->setHtml(htmlContent); - main_doc->setPageSize(center_size); - - //Setting up the rectangles for each section. - QRect headerRect = QRect(QPoint(0, 0), document_header->size().toSize()); - QRect footerRect = QRect(QPoint(0, 0), document_footer->size().toSize()); - QRect contentRect = QRect(QPoint(0, 0), main_doc->size().toSize()); // Main content rectangle. - QRect currentRect = QRect(QPoint(0, 0), center_size.toSize()); // Current main content rectangle. - - QPainter painter(&printer); - - while (currentRect.intersects(contentRect)) - { //Loop if the current content rectangle intersects with the main content rectangle. - //Resetting the painter matrix co-ordinate system. - painter.resetMatrix(); - //Applying negative translation of painter co-ordinate system by current main content rectangle top y coordinate. - painter.translate(0, -currentRect.y()); - //Applying positive translation of painter co-ordinate system by header hight. - painter.translate(0, headerRect.height()); - //Drawing the center content for current page. - main_doc->drawContents(&painter, currentRect); - //Resetting the painter matrix co ordinate system. - painter.resetMatrix(); - //Drawing the header on the top of the page - document_header->drawContents(&painter, headerRect); - //Applying positive translation of painter co-ordinate system to draw the footer - painter.translate(0, headerRect.height()); - painter.translate(0, center_size.height()); - document_footer->drawContents(&painter, footerRect); - - //Translating the current rectangle to the area to be printed for the next page - currentRect.translate(0, currentRect.height()); - //Inserting a new page if there is till area left to be printed - if (currentRect.intersects(contentRect)) - { - printer.newPage(); - } - } - QDesktopServices::openUrl(QUrl(pdfName)); + pdf.save(); + QDesktopServices::openUrl(pdf.getFileUrl()); } } } diff --git a/src/gui/step/StepAdviseUserToRemoveCardGui.cpp b/src/gui/step/StepAdviseUserToRemoveCardGui.cpp index ef48d54..759fcbc 100644 --- a/src/gui/step/StepAdviseUserToRemoveCardGui.cpp +++ b/src/gui/step/StepAdviseUserToRemoveCardGui.cpp @@ -45,7 +45,7 @@ StepAdviseUserToRemoveCardGui::~StepAdviseUserToRemoveCardGui() void StepAdviseUserToRemoveCardGui::activate() { - Q_EMIT setCancelButtonState(ButtonState::HIDDEN); + setCancelButtonState(ButtonState::HIDDEN); if (ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).getCardType() == CardType::NONE) { @@ -62,9 +62,9 @@ void StepAdviseUserToRemoveCardGui::activate() mMessageBox = new QMessageBox(mMainWidget); mMessageBox->setWindowTitle(QCoreApplication::applicationName() + " - Information"); mMessageBox->setWindowModality(Qt::WindowModal); - mMessageBox->setText(tr("You may now remove your ID card from the card reader.")); - mMessageBox->setIconPixmap(QPixmap(QStringLiteral(":images/autentapp2.iconset/icon_32x32.png"))); mMessageBox->setWindowFlags(mMessageBox->windowFlags() & ~Qt::WindowContextHelpButtonHint); + mMessageBox->setText(tr("You may now remove your ID card from the card reader.")); + mMessageBox->setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); } mMessageBox->exec(); diff --git a/src/gui/step/StepAuthenticationEac1Gui.cpp b/src/gui/step/StepAuthenticationEac1Gui.cpp index 6969d4f..2377967 100644 --- a/src/gui/step/StepAuthenticationEac1Gui.cpp +++ b/src/gui/step/StepAuthenticationEac1Gui.cpp @@ -45,6 +45,7 @@ void StepAuthenticationEac1Gui::activate() connect(this, &StepAuthenticationEac1Gui::fireUiFinished, this, &StepAuthenticationEac1Gui::onUiFinished); mWidget->setContext(mContext); + mWidget->setState(StepDidAuthenticateEac1Ui::State::INITIAL); mStepsWidget->setCurrentWidget(mWidget); } diff --git a/src/gui/step/StepAuthenticationEac1Widget.cpp b/src/gui/step/StepAuthenticationEac1Widget.cpp index ae3f62a..bec01f7 100644 --- a/src/gui/step/StepAuthenticationEac1Widget.cpp +++ b/src/gui/step/StepAuthenticationEac1Widget.cpp @@ -7,6 +7,14 @@ #include "StepAuthenticationEac1Widget.h" #include "ui_StepAuthenticationEac1Widget.h" +#include "AppSettings.h" +#include "CardConnection.h" +#include "DetailDialog.h" +#include "RandomPinDialog.h" +#include "generic/GuiUtils.h" +#include "generic/PasswordEdit.h" + +#include #include #include #include @@ -14,14 +22,12 @@ #include #include #include +#include #include -#include "AppSettings.h" -#include "CardConnection.h" -#include "DetailDialog.h" -#include "RandomPinDialog.h" -#include "generic/GuiUtils.h" -#include "generic/PasswordEdit.h" +#ifdef Q_OS_WIN32 +#include +#endif using namespace governikus; @@ -33,10 +39,13 @@ StepAuthenticationEac1Widget::StepAuthenticationEac1Widget(QWidget* pParent) , mContext() , mCANField(nullptr) , mPINField(nullptr) - , mState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT) + , mState(StepDidAuthenticateEac1Ui::State::INITIAL) , mProgressBar(nullptr) , mProgressBarLabel(nullptr) , mCloseWindowWhenFinished() +#ifdef Q_OS_WIN32 + , mTaskbarButton(new QWinTaskbarButton(this)) +#endif { mUi->setupUi(this); @@ -52,51 +61,12 @@ StepAuthenticationEac1Widget::~StepAuthenticationEac1Widget() } -void StepAuthenticationEac1Widget::setContext(QSharedPointer pContext) +void StepAuthenticationEac1Widget::setContext(const QSharedPointer& pContext) { mContext = pContext; - if (mContext == nullptr) - { - return; - } - - mState = StepDidAuthenticateEac1Ui::State::EDIT_CHAT; - - auto eac1 = mContext->getDidAuthenticateEac1(); - - mUi->subjectName->setText(eac1->getCertificateDescription()->getSubjectName()); - mUi->usage->setText(eac1->getCertificateDescription()->getPurpose()); - - if (eac1->getTransactionInfo().isNull() || eac1->getTransactionInfo().isEmpty()) - { - mUi->transactionInfoGroupBox->setVisible(false); - } - else - { - mUi->transactionInfo->setText(eac1->getTransactionInfo()); - mUi->transactionInfoGroupBox->setVisible(true); - } - - //clear lists - mUi->listWidgetWest->clear(); - mUi->listWidgetEast->clear(); - - prepareChatsForGui(); - - updateButtonsAndPinWidget(); - - mUi->detailsPushButton->setEnabled(true); - mUi->listWidgetWest->setEnabled(true); - mUi->listWidgetEast->setEnabled(true); - - if (mContext->getCardConnection()->getReaderInfo().isBasicReader()) - { - Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); - } - else - { - Q_EMIT setForwardButtonState(ButtonState::ENABLED, tr("Identify now")); - } + #ifdef Q_OS_WIN32 + connect(mContext.data(), &AuthContext::fireResultChanged, this, &StepAuthenticationEac1Widget::onResultChanged); + #endif } @@ -106,127 +76,79 @@ void StepAuthenticationEac1Widget::setState(StepDidAuthenticateEac1Ui::State pSt { return; } - mState = pState; - QString progressText; - int progressValue = 0; - switch (pState) { + case StepDidAuthenticateEac1Ui::State::INITIAL: + break; + case StepDidAuthenticateEac1Ui::State::EDIT_CHAT: + setupChatView(); + return; + + case StepDidAuthenticateEac1Ui::State::ENTER_PIN: + updateButtonsAndPinWidget(); return; case StepDidAuthenticateEac1Ui::State::AUTHENTICATING_ESERVICE: Q_EMIT setCancelButtonState(ButtonState::ENABLED); - progressValue = 1; - progressText = tr("Service provider is verified"); + updateProgressPanel(1, tr("Service provider is verified")); break; case StepDidAuthenticateEac1Ui::State::AUTHENTICATING_CARD: - progressValue = 2; - progressText = tr("Card is being verified"); + updateProgressPanel(2, tr("Card is being verified")); break; case StepDidAuthenticateEac1Ui::State::READING_CARD_DATA: - progressValue = 3; - progressText = tr("Reading data"); + updateProgressPanel(3, tr("Reading data")); break; case StepDidAuthenticateEac1Ui::State::REDIRECTING_BROWSER: - progressValue = 4; - progressText = tr("Service provider is being verified"); + updateProgressPanel(4, tr("Service provider is being verified")); break; case StepDidAuthenticateEac1Ui::State::FINISHED: + updateProgressPanel(); Q_EMIT setCancelButtonState(ButtonState::HIDDEN); Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("OK")); break; } - - if (progressValue > 0) - { - if (mProgressBar == nullptr) - { - clearPinWidgetLayout(); - QWidget* progressWidget = new QWidget(); - QVBoxLayout* progressWidgetLayout = new QVBoxLayout(progressWidget); - progressWidgetLayout->setMargin(0); - mUi->pinWidgetLayout->addWidget(progressWidget); - - mProgressBar = new QProgressBar(); - mProgressBar->setTextVisible(false); - mProgressBar->setRange(0, 4); - progressWidgetLayout->addWidget(mProgressBar); - - mProgressBarLabel = new QLabel(); - progressWidgetLayout->addWidget(mProgressBarLabel); - - mUi->pinGroupBox->setTitle(tr("Identify")); - mUi->pinGroupBox->setVisible(true); - } - - mProgressBar->setValue(progressValue); - mProgressBarLabel->setText(progressText); - } - else - { - const bool cancelled = mContext->getLastPaceResult() == ReturnCode::CANCELLATION_BY_USER; - clearPinWidgetLayout(); - QWidget* doneWidget = new QWidget(); - QHBoxLayout* doneWidgetLayout = new QHBoxLayout(doneWidget); - doneWidgetLayout->setMargin(0); - mUi->pinWidgetLayout->addWidget(doneWidget); - - doneWidgetLayout->addStretch(); - QLabel* doneIcon = new QLabel; - QLabel* doneText = new QLabel(cancelled ? tr("The process was cancelled by the user") : tr("Identification successful")); - doneIcon->setPixmap(QPixmap(cancelled ? QStringLiteral(":/images/icon_cancelled.png") : QStringLiteral(":/images/icon_ok.png"))); - doneWidgetLayout->addWidget(doneIcon); - doneWidgetLayout->addWidget(doneText); - doneWidgetLayout->addStretch(); - - mUi->pinGroupBox->setTitle(tr("Result")); - } } void StepAuthenticationEac1Widget::forwardStep() { - mUi->detailsPushButton->setEnabled(false); - mUi->listWidgetWest->setEnabled(false); - mUi->listWidgetEast->setEnabled(false); - setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); + Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); - if (mContext->getCardConnection() != nullptr && mContext->getCardConnection()->getReaderInfo().isBasicReader()) + if (mState == StepDidAuthenticateEac1Ui::State::EDIT_CHAT) { - mUi->pinGroupBox->setVisible(false); - - int childCount = mUi->pinWidgetLayout->count(); - for (int i = 0; i < childCount; ++i) + mUi->detailsPushButton->setEnabled(false); + mUi->listWidgetWest->setEnabled(false); + mUi->listWidgetEast->setEnabled(false); + } + else if (mState == StepDidAuthenticateEac1Ui::State::ENTER_PIN) + { + if (mContext->getCardConnection() != nullptr && mContext->getCardConnection()->getReaderInfo().isBasicReader()) { - QLayoutItem* child = mUi->pinWidgetLayout->itemAt(i); - if (child->widget() != nullptr) + mUi->pinGroupBox->setVisible(false); + + int childCount = mUi->pinWidgetLayout->count(); + for (int i = 0; i < childCount; ++i) { - child->widget()->setEnabled(false); + QLayoutItem* child = mUi->pinWidgetLayout->itemAt(i); + if (child->widget() != nullptr) + { + child->widget()->setEnabled(false); + } } } + else + { + Q_EMIT setCancelButtonState(ButtonState::DISABLED); + } } - else - { - mUi->pinGroupBox->setVisible(true); - QLabel* label = new QLabel(tr("Please pay attention to the display of your card reader.")); - label->setFocusPolicy(Qt::TabFocus); - label->setObjectName(QStringLiteral("eac1PinInformationLabel")); - - clearPinWidgetLayout(); - - mUi->pinWidgetLayout->invalidate(); - mUi->pinWidgetLayout->addWidget(label); - - setCancelButtonState(ButtonState::DISABLED); - } } @@ -245,19 +167,22 @@ void StepAuthenticationEac1Widget::updateButtonsAndPinWidget() if (mContext->getCardConnection()->getReaderInfo().isBasicReader()) { - Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); - clearPinWidgetLayout(); createBasicReaderWidget(); focusWidget(); - - mUi->pinGroupBox->setVisible(true); } else { - Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); - mUi->pinGroupBox->setVisible(false); + clearPinWidgetLayout(); + QLabel* label = new QLabel(tr("Please pay attention to the display of your card reader.")); + label->setFocusPolicy(Qt::TabFocus); + label->setObjectName(QStringLiteral("eac1PinInformationLabel")); + mUi->pinWidgetLayout->invalidate(); + mUi->pinWidgetLayout->addWidget(label); + Q_EMIT setCancelButtonState(ButtonState::DISABLED); } + mUi->pinGroupBox->setVisible(true); + Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); } @@ -316,19 +241,56 @@ void StepAuthenticationEac1Widget::onDetailsButtonClicked() } +void StepAuthenticationEac1Widget::setupChatView() +{ + auto eac1 = mContext->getDidAuthenticateEac1(); + mUi->subjectName->setText(eac1->getCertificateDescription()->getSubjectName()); + QString purpose = eac1->getCertificateDescription()->getPurpose(); + if (purpose.isEmpty()) + { + purpose = tr("See details under more..."); + } + mUi->usage->setText(purpose); + + if (eac1->getTransactionInfo().isNull() || eac1->getTransactionInfo().isEmpty()) + { + mUi->transactionInfoGroupBox->setVisible(false); + } + else + { + mUi->transactionInfo->setText(eac1->getTransactionInfo()); + mUi->transactionInfoGroupBox->setVisible(true); + } + + + mUi->listWidgetWest->clear(); + mUi->listWidgetEast->clear(); + + prepareChatsForGui(); + + mUi->detailsPushButton->setEnabled(true); + mUi->listWidgetWest->setEnabled(true); + mUi->listWidgetEast->setEnabled(true); + mUi->pinGroupBox->setVisible(false); + + Q_EMIT setCancelButtonState(ButtonState::ENABLED); + Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); +} + + void StepAuthenticationEac1Widget::prepareChatsForGui() { - double optionalRightsCount = mContext->getOptionalChat() ? mContext->getOptionalChat()->getAccessRights().size() : 0; - double requiredRightsCount = mContext->getRequiredChat() ? mContext->getRequiredChat()->getAccessRights().size() : 0; + const double optionalRightsCount = mContext->getOptionalAccessRights().size(); + const double requiredRightsCount = mContext->getRequiredAccessRights().size(); int listSize = qCeil((optionalRightsCount + requiredRightsCount) / 2.0); for (AccessRight orderedRight : AccessRoleAndRightsUtil::allDisplayedOrderedRights()) { - if (mContext->getOptionalChat() && mContext->getOptionalChat()->getAccessRights().contains(orderedRight)) + if (mContext->getOptionalAccessRights().contains(orderedRight)) { addChatRightToGui(orderedRight, true, listSize); } - else if (mContext->getRequiredChat() && mContext->getRequiredChat()->getAccessRights().contains(orderedRight)) + else if (mContext->getRequiredAccessRights().contains(orderedRight)) { addChatRightToGui(orderedRight, false, listSize); } @@ -341,11 +303,11 @@ void StepAuthenticationEac1Widget::addChatRightToGui(AccessRight pRight, bool pO QString displayText = AccessRoleAndRightsUtil::toDisplayText(pRight); if (pRight == AccessRight::AGE_VERIFICATION) { - displayText = displayText.append(" (%1)").arg(mContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + displayText += QStringLiteral(" (%1)").arg(mContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); } QCheckBox* cb = new QCheckBox(displayText); cb->setEnabled(pOptional); - cb->setChecked(mContext->getEffectiveChat()->getAccessRights().contains(pRight)); + cb->setChecked(mContext->getEffectiveAccessRights().contains(pRight)); mMap.insert(cb, pRight); @@ -443,6 +405,63 @@ void StepAuthenticationEac1Widget::createBasicReaderWidget() } +void StepAuthenticationEac1Widget::updateProgressPanel(int pProgressValue, const QString& pProgressText) +{ + if (pProgressValue > 0) + { + if (mProgressBar == nullptr) + { + clearPinWidgetLayout(); + QWidget* progressWidget = new QWidget(); + QVBoxLayout* progressWidgetLayout = new QVBoxLayout(progressWidget); + progressWidgetLayout->setMargin(0); + mUi->pinWidgetLayout->addWidget(progressWidget); + + mProgressBar = new QProgressBar(); + mProgressBar->setTextVisible(false); + mProgressBar->setRange(0, 4); + progressWidgetLayout->addWidget(mProgressBar); + + mProgressBarLabel = new QLabel(); + progressWidgetLayout->addWidget(mProgressBarLabel); + + mUi->pinGroupBox->setTitle(tr("Identify")); + mUi->pinGroupBox->setVisible(true); + } + + mProgressBar->setValue(pProgressValue); + mProgressBarLabel->setText(pProgressText); + } + else + { + const bool cancelled = mContext->getStatus().isCancellationByUser(); + clearPinWidgetLayout(); + QWidget* doneWidget = new QWidget(); + QHBoxLayout* doneWidgetLayout = new QHBoxLayout(doneWidget); + doneWidgetLayout->setMargin(0); + mUi->pinWidgetLayout->addWidget(doneWidget); + + doneWidgetLayout->addStretch(); + QLabel* doneIcon = new QLabel; + QLabel* doneText = new QLabel(cancelled ? tr("The process was cancelled by the user") : tr("Identification successful")); + doneIcon->setPixmap(QPixmap(cancelled ? QStringLiteral(":/images/icon_cancelled.png") : QStringLiteral(":/images/icon_ok.png"))); + doneWidgetLayout->addWidget(doneIcon); + doneWidgetLayout->addWidget(doneText); + doneWidgetLayout->addStretch(); + + mUi->pinGroupBox->setTitle(tr("Result")); + } + +#ifdef Q_OS_WIN32 + if (mTaskbarButton) + { + auto progress = mTaskbarButton->progress(); + progress->setValue(pProgressValue == 0 ? progress->maximum() : pProgressValue); + } +#endif +} + + void StepAuthenticationEac1Widget::checkBoxChanged(int pCheckState) { QCheckBox* cb = qobject_cast(sender()); @@ -450,13 +469,13 @@ void StepAuthenticationEac1Widget::checkBoxChanged(int pCheckState) { if (pCheckState == Qt::Unchecked) { - QMap::iterator i = mMap.find(cb); + QMap::ConstIterator i = qAsConst(mMap).find(cb); qCDebug(gui) << "remove from effective chat: " << i.value(); mContext->removeEffectiveAccessRight(i.value()); } else { - QMap::iterator i = mMap.find(cb); + QMap::ConstIterator i = qAsConst(mMap).find(cb); qCDebug(gui) << "set to effective chat: " << i.value(); mContext->addEffectiveAccessRight(i.value()); } @@ -469,7 +488,7 @@ void StepAuthenticationEac1Widget::onRandomButtonClicked() RandomPinDialog randomPinDialog(6, mContext->getReaderName(), this); if (randomPinDialog.exec() == QDialog::Accepted && !randomPinDialog.getPin().isEmpty()) { - QToolButton* pinButton = dynamic_cast(sender()); + QToolButton* pinButton = qobject_cast(sender()); if (pinButton == nullptr) { qCCritical(gui) << "sender == nullptr"; @@ -486,17 +505,44 @@ void StepAuthenticationEac1Widget::onRandomButtonClicked() } -void StepAuthenticationEac1Widget::validateAndSetText(const QString& pPassword, QLineEdit* pLineEdit) +void StepAuthenticationEac1Widget::onResultChanged() { - static QRegularExpression expression(QStringLiteral("[0-9]*")); - QString match = expression.match(pPassword).captured(0); - if (match != pPassword) +#ifdef Q_OS_WIN32 + if (mTaskbarButton && (mContext.isNull() || mContext->getStatus().isError())) { - QPoint tooltipPos = pLineEdit->mapToGlobal(QPoint(pLineEdit->sizeHint().width(), 0)); - QToolTip::showText(tooltipPos, tr("Only digits (0-9) are permitted."), nullptr, QRect(), 3000); - qCDebug(gui) << "match: " << match << ", password: " << pPassword; + mTaskbarButton->progress()->stop(); } - pLineEdit->setText(match); +#endif +} + + +void StepAuthenticationEac1Widget::hideEvent(QHideEvent* pEvent) +{ +#ifdef Q_OS_WIN32 + if (mTaskbarButton) + { + mTaskbarButton->progress()->setVisible(false); + } +#endif + QWidget::hideEvent(pEvent); +} + + +void StepAuthenticationEac1Widget::showEvent(QShowEvent* pEvent) +{ +#ifdef Q_OS_WIN32 + auto window = QApplication::activeWindow(); + if (window) + { + mTaskbarButton->setWindow(window->windowHandle()); + auto progress = mTaskbarButton->progress(); + progress->setVisible(true); + progress->setRange(0, 5); // 5 == count of states in setState + progress->reset(); + progress->resume(); // reset stop() + } +#endif + QWidget::showEvent(pEvent); } @@ -537,17 +583,17 @@ void StepAuthenticationEac1Widget::pinTextEdited(const QString& pText) { if (mPINField->isLineEditActive()) { - setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); + Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); } else { - setForwardButtonState(ButtonState::ENABLED, tr("Identify now")); + Q_EMIT setForwardButtonState(ButtonState::ENABLED, tr("Identify now")); } Q_EMIT firePinUpdated(mPINField->text()); } else { - setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); + Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); } } diff --git a/src/gui/step/StepAuthenticationEac1Widget.h b/src/gui/step/StepAuthenticationEac1Widget.h index 0e5255c..a274ad5 100644 --- a/src/gui/step/StepAuthenticationEac1Widget.h +++ b/src/gui/step/StepAuthenticationEac1Widget.h @@ -11,7 +11,12 @@ #include "StepGui.h" #include "context/AuthContext.h" -class QCheckBox; +#include + +#ifdef Q_OS_WIN32 +#include +#endif + class QLabel; class QLineEdit; class QProgressBar; @@ -37,7 +42,7 @@ class StepAuthenticationEac1Widget StepAuthenticationEac1Widget(QWidget* pParent = nullptr); virtual ~StepAuthenticationEac1Widget(); - void setContext(QSharedPointer pContext); + void setContext(const QSharedPointer& pContext); void setState(StepDidAuthenticateEac1Ui::State pState); void forwardStep(); @@ -58,18 +63,25 @@ class StepAuthenticationEac1Widget void canTextEdited(const QString& pText); void pinTextEdited(const QString& pText); void onRandomButtonClicked(); + void onResultChanged(); + + protected: + void hideEvent(QHideEvent* pEvent); + void showEvent(QShowEvent* pEvent); private: + void setupChatView(); + void prepareChatsForGui(); + void updateProgressPanel(int pProgressValue = 0, const QString& pProgressText = QString()); + void addChatRightToGui(AccessRight pRight, bool pOptional, int pListSize); void clearPinWidgetLayout(); void createBasicReaderWidget(); - void validateAndSetText(const QString& pPassword, QLineEdit* pLineEdit); - private: QScopedPointer mUi; QSharedPointer mContext; @@ -83,6 +95,10 @@ class StepAuthenticationEac1Widget QLabel* mProgressBarLabel; bool mCloseWindowWhenFinished; + + #ifdef Q_OS_WIN32 + QWinTaskbarButton* mTaskbarButton; + #endif }; } /* namespace governikus */ diff --git a/src/gui/step/StepAuthenticationEac1Widget.ui b/src/gui/step/StepAuthenticationEac1Widget.ui index 48c700a..711b20b 100644 --- a/src/gui/step/StepAuthenticationEac1Widget.ui +++ b/src/gui/step/StepAuthenticationEac1Widget.ui @@ -26,7 +26,7 @@ Qt::TabFocus - <html><head/><body><p align="justify">Information on the service provider who wants to read out data from your ID card is given here. For further information press the button &quot;more…&quot;.</p></body></html> + <html><head/><body><p align="justify">Information on the service provider who wants to read out data from your ID card is given here. For further information press the button &quot;more...&quot;.</p></body></html> diff --git a/src/gui/step/StepChooseCardGui.cpp b/src/gui/step/StepChooseCardGui.cpp index a7e597d..e04b010 100644 --- a/src/gui/step/StepChooseCardGui.cpp +++ b/src/gui/step/StepChooseCardGui.cpp @@ -29,7 +29,6 @@ StepChooseCardGui::StepChooseCardGui(const QSharedPointer& pCon , mCancelButton(nullptr) , mReaderDriverButton(nullptr) , mDiagnosisButton(nullptr) - , mStepsWidget(pStepsWidget) , mContext(pContext) { mInformationMessageBox->setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - Information")); @@ -51,10 +50,7 @@ StepChooseCardGui::~StepChooseCardGui() void StepChooseCardGui::activate() { - Q_EMIT setCancelButtonState(ButtonState::ENABLED); - - mStepsWidget->setCurrentWidget(mStepsWidget->getProcessingPage()); - mStepsWidget->getProcessingPage()->startAnimation(); + setCancelButtonState(ButtonState::ENABLED); connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); onReaderManagerSignal(); @@ -64,8 +60,6 @@ void StepChooseCardGui::activate() void StepChooseCardGui::deactivate() { disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); - - mStepsWidget->getProcessingPage()->stopAnimation(); } @@ -76,7 +70,7 @@ QString StepChooseCardGui::getCurrentReaderImage(const QVector& pRea { if (!knownReaderTypes.contains(readerInfo.getReaderType())) { - knownReaderTypes.append(readerInfo.getReaderType()); + knownReaderTypes += readerInfo.getReaderType(); } } @@ -95,7 +89,7 @@ QString StepChooseCardGui::getCurrentReaderImage(const QVector& pRea void StepChooseCardGui::updateErrorMessage(const QString& pTitle, const QString& pMessage, bool closeErrorMessage) { - if (closeErrorMessage) + if (closeErrorMessage || mContext->getStatus().isError()) { mDiagnosisGui->deactivate(); mReaderDriverGui->deactivate(); @@ -125,7 +119,7 @@ void StepChooseCardGui::updateErrorMessage(const QString& pTitle, const QString& { if (mInformationMessageBox->clickedButton() == mCancelButton) { - fireCancelled(); + Q_EMIT fireCancelled(); } else if (mInformationMessageBox->clickedButton() == mDiagnosisButton) { @@ -178,6 +172,16 @@ void StepChooseCardGui::onReaderManagerSignal() } else { - updateErrorMessage(QString(), QString(), true); + if (readersWithNpa[0].isPinDeactivated()) + { + updateErrorMessage(tr("Online identification function is disabled."), + tr("This action cannot be performed. The online identification function of your ID card is deactivated." + " Please contact your competent authority to activate the online identification function."), + false); + } + else + { + updateErrorMessage(QString(), QString(), true); + } } } diff --git a/src/gui/step/StepChooseCardGui.h b/src/gui/step/StepChooseCardGui.h index a8fceda..90870af 100644 --- a/src/gui/step/StepChooseCardGui.h +++ b/src/gui/step/StepChooseCardGui.h @@ -31,7 +31,6 @@ class StepChooseCardGui QPointer mDiagnosisGui; QPointer mReaderDriverGui; QPushButton* mCancelButton, * mReaderDriverButton, * mDiagnosisButton; - AuthenticateStepsWidget* mStepsWidget; QSharedPointer mContext; diff --git a/src/gui/step/StepChooseDeviceWidget.cpp b/src/gui/step/StepChooseDeviceWidget.cpp deleted file mode 100644 index 89be4cf..0000000 --- a/src/gui/step/StepChooseDeviceWidget.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/*! - * StepChooseDeviceWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepChooseDeviceWidget.h" -#include "ui_StepChooseDeviceWidget.h" - -#include "ReaderManager.h" -#include "generic/ListItem.h" -#include "generic/ListItemIconLeft.h" -#include "generic/ListItemIconRight.h" -#include "generic/ListItemSubTitle.h" -#include "generic/ListItemTitle.h" - -#include -#include - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(gui) - -StepChooseDeviceWidget::StepChooseDeviceWidget(QWidget* pParent) - : Page(QStringLiteral("Choose Device"), pParent) - , mUi(new Ui::StepChooseDeviceWidget()) - , mMovieLabel(new QLabel()) - , mInitialized(false) -{ - mMovieLabel->setMovie(new QMovie(QStringLiteral(":/images/busy_animation.gif"))); - mMovieLabel->setAlignment(Qt::AlignCenter); - mMovieLabel->setMargin(8); - mUi->setupUi(this); - mUi->verticalLayout_3->addWidget(mMovieLabel.data()); - - connect(mUi->scanButton, &QPushButton::clicked, this, &StepChooseDeviceWidget::onScanButtonClicked); - - mUi->scanDescriptionLabel->setText(tr("Please connect your tablet/smartphone with the Reiner SCT cyberJack wave now. You can find a detailled description in the online help.")); -} - - -StepChooseDeviceWidget::~StepChooseDeviceWidget() -{ - if (!mMovieLabel.isNull() && mMovieLabel->movie() != nullptr) - { - delete mMovieLabel->movie(); - mMovieLabel->setMovie(nullptr); - } - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepChooseDeviceWidget::onReaderAdded); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepChooseDeviceWidget::onReaderRemoved); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepChooseDeviceWidget::onCardInserted); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepChooseDeviceWidget::onCardRemoved); -} - - -void StepChooseDeviceWidget::setState(StepChooseDeviceUi::State pState) -{ - switch (pState) - { - case StepChooseDeviceUi::State::INITIAL: - { - Q_EMIT setForwardButtonState(ButtonState::DISABLED); - // clear the device list - while (mUi->devicesList->count()) - { - QWidget* readerWidget = mUi->devicesList->itemAt(0)->widget(); - mUi->devicesList->removeWidget(readerWidget); - delete readerWidget; - } - // add currently known readers - const auto allReaders = ReaderManager::getInstance().getReaderInfos(); - for (const auto& info : allReaders) - { - onReaderAdded(info.getName()); - } - if (!mInitialized) - { - mInitialized = true; - // lazy initialization because the ReaderManager does not exist yet on construction time - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepChooseDeviceWidget::onReaderAdded); - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepChooseDeviceWidget::onReaderRemoved); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepChooseDeviceWidget::onCardInserted); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepChooseDeviceWidget::onCardRemoved); - } - return; - } - - case StepChooseDeviceUi::State::SCAN_STARTED: - - mUi->scanButton->setEnabled(false); - mMovieLabel->setVisible(true); - mMovieLabel->movie()->start(); - return; - - case StepChooseDeviceUi::State::FINISHED: - /* no break - fall through*/ - - case StepChooseDeviceUi::State::SCAN_STOPPED: - mUi->scanButton->setEnabled(true); - mMovieLabel->setVisible(false); - mMovieLabel->movie()->stop(); - return; - } -} - - -void StepChooseDeviceWidget::onReaderAdded(const QString& pReaderName) -{ - ListItem* listItemWidget = new ListItem(this); - listItemWidget->installEventFilter(this); - listItemWidget->setObjectName(QStringLiteral("listItemWidget")); - - QHBoxLayout* listItemWidgetLayout = new QHBoxLayout(listItemWidget); - listItemWidgetLayout->setSpacing(0); - listItemWidgetLayout->setObjectName(QStringLiteral("listItemWidgetLayout")); - listItemWidgetLayout->setContentsMargins(0, 0, 0, 0); - - QFrame* verticalFrame = new QFrame(listItemWidget); - verticalFrame->setObjectName(QStringLiteral("verticalFrame")); - - QVBoxLayout* titleSubtitelLayout = new QVBoxLayout(verticalFrame); - titleSubtitelLayout->setSpacing(0); - titleSubtitelLayout->setObjectName(QStringLiteral("titleSubtitelLayout")); - titleSubtitelLayout->setContentsMargins(0, 0, 0, 0); - - ListItemTitle* titleLabel = new ListItemTitle(verticalFrame); - titleLabel->setObjectName(QStringLiteral("titleLabel")); - titleLabel->setText(pReaderName); - - listItemWidget->setProperty("ReaderName", pReaderName); - - titleSubtitelLayout->addWidget(titleLabel); - - ListItemSubTitle* subTitleLabel = new ListItemSubTitle(verticalFrame); - subTitleLabel->setObjectName(QStringLiteral("subTitleLabel")); - subTitleLabel->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - - titleSubtitelLayout->addWidget(subTitleLabel); - - listItemWidgetLayout->addWidget(verticalFrame); - - ListItemIconRight* listItemIconRight = new ListItemIconRight(listItemWidget); - listItemIconRight->setObjectName(QStringLiteral("listItemIconRight")); - - QSizePolicy listItemSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - listItemSizePolicy.setHorizontalStretch(0); - listItemSizePolicy.setVerticalStretch(0); - listItemSizePolicy.setHeightForWidth(listItemIconRight->sizePolicy().hasHeightForWidth()); - listItemIconRight->setSizePolicy(listItemSizePolicy); - listItemIconRight->setVisible(false); - listItemWidgetLayout->addWidget(listItemIconRight); - - mUi->devicesList->addWidget(listItemWidget); - - ReaderInfo info = ReaderManager::getInstance().getReaderInfo(pReaderName); - if (!info.isConnected()) - { - setSubtitleOfReader(pReaderName, tr("Not connected")); - setIconVisible(pReaderName, true); - } - else if (info.getCardType() == CardType::EID_CARD) - { - onCardInserted(pReaderName); - } - else - { - onCardRemoved(pReaderName); - } -} - - -void StepChooseDeviceWidget::onReaderRemoved(const QString& pReaderName) -{ - if (QWidget* readerItem = getWidgetWithProperty("ReaderName", pReaderName)) - { - mUi->devicesList->removeWidget(readerItem); - delete readerItem; - } -} - - -void StepChooseDeviceWidget::onCardInserted(const QString& pReaderName) -{ - if (ReaderManager::getInstance().getReaderInfo(pReaderName).getCardType() == CardType::EID_CARD) - { - setSubtitleOfReader(pReaderName, tr("ID card found")); - setIconVisible(pReaderName, true); - qDebug() << "choose reader" << pReaderName; - Q_EMIT fireUiFinished(pReaderName); - } -} - - -void StepChooseDeviceWidget::onCardRemoved(const QString& pReaderName) -{ - if (ReaderManager::getInstance().getReaderInfo(pReaderName).isConnected()) - { - setSubtitleOfReader(pReaderName, tr("No ID card found")); - setIconVisible(pReaderName, false); - } - else - { - setSubtitleOfReader(pReaderName, tr("Not connected")); - setIconVisible(pReaderName, true); - } -} - - -void StepChooseDeviceWidget::setSubtitleOfReader(const QString& pReaderName, const QString& pSubTitle) -{ - if (QWidget* readerItem = getWidgetWithProperty("ReaderName", pReaderName)) - { - ListItemSubTitle* subTitle = readerItem->findChild(QStringLiteral("subTitleLabel")); - - for (int i = 0; i < mUi->devicesList->count(); ++i) - { - if (QObject* deviceWidget = mUi->devicesList->itemAt(i)->widget()) - { - if (deviceWidget->property("ReaderName") == pReaderName) - { - if (subTitle != nullptr) - { - subTitle->setText(pSubTitle); - return; - } - } - } - } - } - qWarning() << "No reader found to adjust subtitle" << pReaderName; -} - - -void StepChooseDeviceWidget::setIconVisible(const QString& pReaderName, bool pVisible) -{ - - for (int i = 0; i < mUi->devicesList->count(); ++i) - { - if (QObject* deviceWidget = mUi->devicesList->itemAt(i)->widget()) - { - if (deviceWidget->property("ReaderName") == pReaderName) - { - ListItemIconRight* listIcon = deviceWidget->findChild(QStringLiteral("listItemIconRight")); - if (listIcon != nullptr) - { - listIcon->setVisible(pVisible); - return; - } - } - } - } - qWarning() << "No reader found to adjust icon visibility" << pReaderName; -} - - -void StepChooseDeviceWidget::onScanButtonClicked() -{ - mUi->devicesList->setEnabled(false); - - Q_EMIT fireScanButtonClicked(); -} - - -QWidget* StepChooseDeviceWidget::getWidgetWithProperty(const char* pName, const QString& pValue) const -{ - for (int i = 0; i < mUi->devicesList->count(); ++i) - { - if (QWidget* widget = mUi->devicesList->itemAt(i)->widget()) - { - if (widget->property(pName).toString() == pValue) - { - return widget; - } - } - } - qCritical() << "No widget found with property " << pName << "=" << pValue; - return nullptr; -} - - -bool StepChooseDeviceWidget::eventFilter(QObject* pWatched, QEvent* pEvent) -{ - switch (pEvent->type()) - { - case QEvent::MouseButtonPress: - if (pWatched->inherits("governikus::ListItem")) - { - if (!qobject_cast(pWatched)->property("ReaderName").isNull() && qobject_cast(pWatched)->property("ReaderName").isValid()) - { - QString readerName = qobject_cast(pWatched)->property("ReaderName").toString(); - ReaderInfo info = ReaderManager::getInstance().getReaderInfo(readerName); - if (!info.isConnected()) - { - qDebug() << "Connect reader" << readerName; - ReaderManager::getInstance().connectReader(readerName); - } - } - } - return true; - - default: - return false; - } -} diff --git a/src/gui/step/StepChooseDeviceWidget.h b/src/gui/step/StepChooseDeviceWidget.h deleted file mode 100644 index 7777c16..0000000 --- a/src/gui/step/StepChooseDeviceWidget.h +++ /dev/null @@ -1,62 +0,0 @@ -/*! - * StepChooseDeviceWidget.h - * - * \brief Widget for the step StepChooseDeviceGui. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "StepGui.h" -#include "context/AuthContext.h" -#include "generic/Page.h" - -#include - -namespace Ui -{ -class StepChooseDeviceWidget; -} - -class QLabel; - -namespace governikus -{ - -class StepChooseDeviceWidget - : public Page -{ - Q_OBJECT - - public: - StepChooseDeviceWidget(QWidget* pParent = nullptr); - virtual ~StepChooseDeviceWidget(); - - void setState(StepChooseDeviceUi::State pState); - - Q_SIGNALS: - void setForwardButtonState(ButtonState pState, const QString& pText = QString()); - void setCancelButtonState(ButtonState pState); - void fireScanButtonClicked(); - void fireUiFinished(const QString& pReaderName); - - private Q_SLOTS: - void onScanButtonClicked(); - void onReaderAdded(const QString& pReaderName); - void onReaderRemoved(const QString& pReaderName); - void onCardInserted(const QString& pReaderName); - void onCardRemoved(const QString& pReaderName); - - private: - QScopedPointer mUi; - QScopedPointer mMovieLabel; - bool mInitialized; - - QWidget* getWidgetWithProperty(const char* pName, const QString& pValue) const; - void setSubtitleOfReader(const QString& pReaderName, const QString& pSubTitle); - void setIconVisible(const QString& pReaderName, bool pVisible); - bool eventFilter(QObject* pWatched, QEvent* pEvent); -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepChooseDeviceWidget.ui b/src/gui/step/StepChooseDeviceWidget.ui deleted file mode 100644 index 5e2dbaa..0000000 --- a/src/gui/step/StepChooseDeviceWidget.ui +++ /dev/null @@ -1,214 +0,0 @@ - - - StepChooseDeviceWidget - - - - 0 - 0 - 612 - 436 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 0 - 20 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 20 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Qt::AlignJustify|Qt::AlignVCenter - - - true - - - - - - - - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - - 0 - 0 - - - - Scan - - - - - - - - - - QLayout::SetFixedSize - - - 0 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 0 - 20 - - - - - - - - - - - governikus::HeaderBox - QWidget -
generic/HeaderBox.h
- 1 -
-
- - -
diff --git a/src/gui/step/StepErrorGui.cpp b/src/gui/step/StepErrorGui.cpp index 204871a..d39730f 100644 --- a/src/gui/step/StepErrorGui.cpp +++ b/src/gui/step/StepErrorGui.cpp @@ -2,8 +2,9 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "AppQtMainWidget.h" #include "StepErrorGui.h" + +#include "AppQtMainWidget.h" #include "generic/GuiUtils.h" #include @@ -33,12 +34,10 @@ StepErrorGui::~StepErrorGui() void StepErrorGui::reportError() { - // On error don't automatically close the window after the workflow is done. + // Do not close the window automatically in case of errors when the workflow is done. mMainWidget->setHideWindowAfterWorkflow(false); - - auto result = mContext->getResult(); - if (result.getMinor() == Result::Minor::SAL_Invalid_Key && !mContext->getCardConnection()->getReaderInfo().getCardInfo().isPinDeactivated()) + if (mContext->getStatus().is(GlobalStatus::Code::Paos_Error_SAL_Invalid_Key) && !mContext->getCardConnection()->getReaderInfo().getCardInfo().isPinDeactivated()) { if (GuiUtils::showWrongPinBlockedDialog(mMainWidget)) { @@ -52,22 +51,14 @@ void StepErrorGui::reportError() return; } - - QString message = result.getMessage(); - if (message.isEmpty() || result.isOriginServer()) - { - // if the message is not set, we clearly use the result minor - // if the server sent the message, it can be in any language, so we take the result minor - message = result.getMinorDescription(); - } + QString message = mContext->getStatus().toErrorDescription(true); if (message.isEmpty()) { - qCCritical(gui) << "No error message determined:" << result.getMajorString() << result.getMinorString() << result.getMessage(); + qCCritical(gui) << "No error message determined:" << mContext->getStatus(); message = tr("Sorry, that should not have happened! Please contact the support team."); Q_ASSERT(!message.isEmpty()); } - QMessageBox::warning(mMainWidget, QCoreApplication::applicationName() + " - " + tr("Error"), message); Q_EMIT fireUiFinished(); } diff --git a/src/gui/step/StepGui.h b/src/gui/step/StepGui.h index c443352..109816f 100644 --- a/src/gui/step/StepGui.h +++ b/src/gui/step/StepGui.h @@ -18,7 +18,9 @@ struct StepDidAuthenticateEac1Ui { enum class State { + INITIAL, EDIT_CHAT, + ENTER_PIN, AUTHENTICATING_ESERVICE, AUTHENTICATING_CARD, READING_CARD_DATA, @@ -27,17 +29,6 @@ struct StepDidAuthenticateEac1Ui }; }; -struct StepChooseDeviceUi -{ - enum class State - { - INITIAL, - SCAN_STARTED, - SCAN_STOPPED, - FINISHED, - }; -}; - class Page; class StepGuiDelegate diff --git a/src/gui/step/StepProcessingGui.cpp b/src/gui/step/StepProcessingGui.cpp index 83c658d..4610cb4 100644 --- a/src/gui/step/StepProcessingGui.cpp +++ b/src/gui/step/StepProcessingGui.cpp @@ -22,8 +22,8 @@ StepProcessingGui::~StepProcessingGui() void StepProcessingGui::activate() { - Q_EMIT setCancelButtonState(ButtonState::ENABLED); - Q_EMIT setForwardButtonState(ButtonState::HIDDEN); + setCancelButtonState(ButtonState::ENABLED); + setForwardButtonState(ButtonState::HIDDEN); mStepsWidget->setCurrentWidget(mStepsWidget->getProcessingPage()); mStepsWidget->getProcessingPage()->startAnimation(); diff --git a/src/gui/workflow/GenericWorkflowGui.h b/src/gui/workflow/GenericWorkflowGui.h index 2ac6a88..90f32f6 100644 --- a/src/gui/workflow/GenericWorkflowGui.h +++ b/src/gui/workflow/GenericWorkflowGui.h @@ -43,7 +43,7 @@ class GenericWorkflowGui , mParentWidget(pParentWidget) , mWidget(pWidget) , mStepGui(nullptr) - , mContext(pContext.dynamicCast()) + , mContext(pContext.objectCast()) { Q_ASSERT(mContext != nullptr); connect(this, &WorkflowGui::fireUserCancelled, mContext.data(), &WorkflowContext::fireCancelWorkflow); diff --git a/src/gui/workflow/WorkflowAuthenticateQtGui.cpp b/src/gui/workflow/WorkflowAuthenticateQtGui.cpp index 26d258e..4f56131 100644 --- a/src/gui/workflow/WorkflowAuthenticateQtGui.cpp +++ b/src/gui/workflow/WorkflowAuthenticateQtGui.cpp @@ -8,6 +8,18 @@ #include "AppSettings.h" #include "generic/GuiUtils.h" +#include "states/FinalState.h" +#include "states/StateDidAuthenticateEac1.h" +#include "states/StateDidAuthenticateEac2.h" +#include "states/StateEditAccessRights.h" +#include "states/StateEstablishPaceCan.h" +#include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" +#include "states/StateProcessing.h" +#include "states/StateProcessing.h" +#include "states/StateSelectPcscReader.h" +#include "states/StateTransmit.h" +#include "states/StateWriteHistory.h" #include "step/AuthenticateStepsWidget.h" #include "step/StepAdviseUserToRemoveCardGui.h" #include "step/StepAuthenticationDoneGui.h" @@ -15,6 +27,7 @@ #include "step/StepChooseCardGui.h" #include "step/StepErrorGui.h" #include "step/StepProcessingGui.h" +#include "workflow/WorkflowQtWidget.h" using namespace governikus; @@ -22,21 +35,18 @@ using namespace governikus; WorkflowAuthenticateQtGui::WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) - , mRetryCounterUpdated(false) + , mCanEntered(false) , mAuthenticateStepsWidget(mParentWidget->findChild()) , mAdviseUserToRemoveCardGui(new StepAdviseUserToRemoveCardGui(mContext, mParentWidget)) - , mAuthenticationDoneGui(new StepAuthenticationDoneGui(mContext)) , mDidAuthenticateGui(new StepAuthenticationEac1Gui(mContext, mAuthenticateStepsWidget)) , mChooseCardGui(new StepChooseCardGui(mContext, mAuthenticateStepsWidget)) , mErrorGui(new StepErrorGui(mContext, mParentWidget)) , mProcessingGui(new StepProcessingGui(mContext, mAuthenticateStepsWidget)) + , mAuthenticationDoneGui(new StepAuthenticationDoneGui(mContext)) { Q_ASSERT(mAuthenticateStepsWidget != nullptr); - - GenericWorkflowGui::activateStepUi(mProcessingGui); - connect(mWidget, &WorkflowQtWidget::fireUserCancelled, this, &WorkflowGui::fireUserCancelled); - connect(mWidget, &WorkflowQtWidget::forwardStep, this, &WorkflowAuthenticateQtGui::nextStep); + connect(mWidget, &WorkflowQtWidget::forwardStep, this, &WorkflowAuthenticateQtGui::onForwardStep); } @@ -47,8 +57,9 @@ WorkflowAuthenticateQtGui::~WorkflowAuthenticateQtGui() void WorkflowAuthenticateQtGui::activate() { + activateStepUi(mProcessingGui); mParentWidget->workflowActivated(WorkflowWidgetParent::Authentication, tr("Identify")); - connect(mContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &WorkflowAuthenticateQtGui::onStateChanged); + connect(mContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &WorkflowAuthenticateQtGui::onCurrentStateChanged); } @@ -66,26 +77,14 @@ bool WorkflowAuthenticateQtGui::verifyAbortWorkflow() msgBox.setText(tr("Do you really want to cancel?")); msgBox.setInformativeText(tr("You can as well identity later by calling the service provider's Internet page" " again.")); - QPixmap pixmap(QStringLiteral(":images/autentapp2.iconset/icon_32x32.png")); - msgBox.setIconPixmap(pixmap); + msgBox.setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setWindowFlags(msgBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); return msgBox.exec() == QMessageBox::Yes; } -void WorkflowAuthenticateQtGui::handleBlockedPin() -{ - mContext->fireCancelWorkflow(); - if (GuiUtils::showWrongPinBlockedDialog(mWidget)) - { - mParentWidget->switchToPinSettingsAfterWorkflow(); - mContext->setReaderName(QString()); - } -} - - -void WorkflowAuthenticateQtGui::nextStep() +void WorkflowAuthenticateQtGui::onForwardStep() { if (mStepGui != nullptr) { @@ -94,11 +93,11 @@ void WorkflowAuthenticateQtGui::nextStep() } -void WorkflowAuthenticateQtGui::onStateChanged(const QString& pNewState) +void WorkflowAuthenticateQtGui::onCurrentStateChanged(const QString& pNewState) { - if (!mContext->getResult().isOk() && !mContext->isErrorReportedToUser()) + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) { - if (mContext->getResult().getMinor() != Result::Minor::SAL_Cancellation_by_User) + if (!mContext->getStatus().isCancellationByUser()) { activateStepUi(mErrorGui); mErrorGui->reportError(); @@ -106,64 +105,74 @@ void WorkflowAuthenticateQtGui::onStateChanged(const QString& pNewState) mContext->setErrorReportedToUser(); } - bool approveNewState = true; - if (pNewState == QLatin1String("StateProcessing")) + bool approveNewState = true; + if (AbstractState::isState(pNewState)) { activateStepUi(mProcessingGui); GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); approveNewState = !settings.isTransportPinReminder(); } - else if (pNewState == QLatin1String("StateSelectPcscReader")) + else if (AbstractState::isState(pNewState)) + { + approveNewState = false; + activateStepUi(mDidAuthenticateGui); + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT); + } + else if (AbstractState::isState(pNewState)) { activateStepUi(mChooseCardGui); } - else if (pNewState == QLatin1String("StateUpdateRetryCounter")) + else if (AbstractState::isState(pNewState) || AbstractState::isState(pNewState)) { - mRetryCounterUpdated = true; - } - else if (mRetryCounterUpdated) - { - mRetryCounterUpdated = false; - approveNewState = false; - if (mContext->isPinBlocked()) + if (AbstractState::isState(pNewState)) { - activateStepUi(mProcessingGui); - handleBlockedPin(); + approveNewState = !mContext->getCardConnection()->getReaderInfo().isBasicReader(); + mCanEntered = true; } - else if (mContext->getLastPaceResult() != ReturnCode::OK) + else if (AbstractState::isState(pNewState)) + { + // PIN entry after CAN entry is done without user interaction + approveNewState = mCanEntered || !mContext->getCardConnection()->getReaderInfo().isBasicReader(); + } + activateStepUi(mDidAuthenticateGui); + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::ENTER_PIN); + if (mContext->getLastPaceResult() != CardReturnCode::OK) { mDidAuthenticateGui->incorrectPinError(); } - else + } + else if (AbstractState::isState(pNewState)) + { + approveNewState = false; + Q_EMIT mContext->fireCancelWorkflow(); + if (GuiUtils::showWrongPinBlockedDialog(mWidget)) { - activateStepUi(mDidAuthenticateGui); - mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT); + mContext->setReaderName(QString()); + mParentWidget->switchToPinSettingsAfterWorkflow(); } } - else if (pNewState == QLatin1String("StateDidAuthenticateEac1")) + else if (AbstractState::isState(pNewState)) { mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_ESERVICE); } - else if (pNewState == QLatin1String("StateDidAuthenticateEac2")) + else if (AbstractState::isState(pNewState)) { mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_CARD); } - else if (pNewState == QLatin1String("StateTransmit")) + else if (AbstractState::isState(pNewState)) { mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::READING_CARD_DATA); } - else if (pNewState == QLatin1String("StateWriteHistory") && isActive(mDidAuthenticateGui)) + else if (AbstractState::isState(pNewState) && isActive(mDidAuthenticateGui)) { mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::FINISHED); } - else if (pNewState == QLatin1String("FinalState")) + else if (AbstractState::isState(pNewState)) { activateStepUi(mAdviseUserToRemoveCardGui); activateStepUi(mAuthenticationDoneGui); } - - mContext->setStateApproved(approveNewState); } diff --git a/src/gui/workflow/WorkflowAuthenticateQtGui.h b/src/gui/workflow/WorkflowAuthenticateQtGui.h index 60e6730..79eed4e 100644 --- a/src/gui/workflow/WorkflowAuthenticateQtGui.h +++ b/src/gui/workflow/WorkflowAuthenticateQtGui.h @@ -30,20 +30,18 @@ class WorkflowAuthenticateQtGui Q_OBJECT private: - bool mRetryCounterUpdated; + bool mCanEntered; AuthenticateStepsWidget* mAuthenticateStepsWidget; QSharedPointer mAdviseUserToRemoveCardGui; - QSharedPointer mAuthenticationDoneGui; QSharedPointer mDidAuthenticateGui; QSharedPointer mChooseCardGui; QSharedPointer mErrorGui; QSharedPointer mProcessingGui; - - void handleBlockedPin(); + QSharedPointer mAuthenticationDoneGui; private Q_SLOTS: - void nextStep(); - void onStateChanged(const QString& pNewState); + void onForwardStep(); + void onCurrentStateChanged(const QString& pNewState); public: WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget); diff --git a/src/gui/workflow/WorkflowChangePinQtGui.cpp b/src/gui/workflow/WorkflowChangePinQtGui.cpp index 0470c2e..69c06de 100644 --- a/src/gui/workflow/WorkflowChangePinQtGui.cpp +++ b/src/gui/workflow/WorkflowChangePinQtGui.cpp @@ -9,6 +9,13 @@ #include "AppQtMainWidget.h" #include "PinSettingsWidget.h" #include "generic/GuiUtils.h" +#include "states/StateChangePin.h" +#include "states/StateCleanUpReaderManager.h" +#include "states/StateEstablishPaceCan.h" +#include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" +#include "states/StateSelectReaderType.h" +#include "states/StateUpdateRetryCounter.h" #include "step/StepChooseCardGui.h" #include "step/StepErrorGui.h" @@ -53,9 +60,9 @@ bool WorkflowChangePinQtGui::verifyAbortWorkflow() void WorkflowChangePinQtGui::onStateChanged(const QString& pNextState) { - if (!mContext->getResult().isOk() && !mContext->isErrorReportedToUser()) + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) { - if (mContext->getResult().getMinor() != Result::Minor::SAL_Cancellation_by_User) + if (!mContext->getStatus().isCancellationByUser()) { activateStepUi(mErrorGui); mErrorGui->reportError(); @@ -66,7 +73,7 @@ void WorkflowChangePinQtGui::onStateChanged(const QString& pNextState) if (mRetryCounterUpdated) { mRetryCounterUpdated = false; - if (mContext->getLastPaceResult() != ReturnCode::OK) + if (mContext->getLastPaceResult() != CardReturnCode::OK) { auto newRetryCounter = mContext->getCardConnection()->getReaderInfo().getRetryCounter(); GuiUtils::showPinCanPukErrorDialog(mContext->getLastPaceResult(), newRetryCounter, mPinSettingsWidget); @@ -80,31 +87,31 @@ void WorkflowChangePinQtGui::onStateChanged(const QString& pNextState) } } - if (pNextState == QLatin1String("StateSelectReaderType")) + if (AbstractState::isState(pNextState)) { mContext->setReaderType(ReaderManagerPlugInType::PCSC); } - else if (pNextState == QLatin1String("StateUpdateRetryCounter")) + else if (AbstractState::isState(pNextState)) { mRetryCounterUpdated = true; } - else if (pNextState == QLatin1String("StateEstablishPacePin")) + else if (AbstractState::isState(pNextState)) { mContext->setPin(mPinSettingsWidget->getPin()); } - else if (pNextState == QLatin1String("StateEstablishPaceCan")) + else if (AbstractState::isState(pNextState)) { mContext->setCan(mPinSettingsWidget->getCan()); } - else if (pNextState == QLatin1String("StateEstablishPacePuk")) + else if (AbstractState::isState(pNextState)) { mContext->setPuk(mPinSettingsWidget->getPuk()); } - else if (pNextState == QLatin1String("StateChangePin")) + else if (AbstractState::isState(pNextState)) { mContext->setNewPin(mPinSettingsWidget->getNewPin()); } - else if (pNextState == QLatin1String("StateCleanUpReaderManager") && mContext->getResult().isOk()) + else if (AbstractState::isState(pNextState) && mContext->getStatus().isNoError()) { bool pinBlocked = (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 0); mPinSettingsWidget->setMode(pinBlocked ? PinSettingsWidget::Mode::AfterPinUnblock : PinSettingsWidget::Mode::AfterPinChange); diff --git a/src/gui/workflow/WorkflowSelfInfoQtGui.cpp b/src/gui/workflow/WorkflowSelfInfoQtGui.cpp index 6e9974e..11156c8 100644 --- a/src/gui/workflow/WorkflowSelfInfoQtGui.cpp +++ b/src/gui/workflow/WorkflowSelfInfoQtGui.cpp @@ -6,9 +6,19 @@ #include "WorkflowSelfInfoQtGui.h" -#include "AppQtMainWidget.h" #include "AppSettings.h" #include "generic/GuiUtils.h" +#include "states/FinalState.h" +#include "states/StateDidAuthenticateEac1.h" +#include "states/StateDidAuthenticateEac2.h" +#include "states/StateEditAccessRights.h" +#include "states/StateEstablishPaceCan.h" +#include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" +#include "states/StateLoadTcTokenUrl.h" +#include "states/StateSelectPcscReader.h" +#include "states/StateTransmit.h" +#include "states/StateWriteHistory.h" #include "step/AuthenticateStepsWidget.h" #include "step/StepAdviseUserToRemoveCardGui.h" #include "step/StepAuthenticationEac1Gui.h" @@ -18,25 +28,24 @@ #include "step/StepShowSelfAuthenticationDataGui.h" #include "workflow/WorkflowQtWidget.h" + using namespace governikus; + WorkflowSelfInfoQtGui::WorkflowSelfInfoQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) - , mRetryCounterUpdated(false) + , mCanEntered(false) , mAuthenticateStepsWidget(pParentWidget->findChild()) - , mStepAdviseUserToRemoveCardGui(new StepAdviseUserToRemoveCardGui(mContext, mParentWidget)) - , mStepChooseCardGui(new StepChooseCardGui(mContext, mAuthenticateStepsWidget)) - , mStepAuthenticationEac1Gui(new StepAuthenticationEac1Gui(mContext, mAuthenticateStepsWidget)) - , mStepErrorGui(new StepErrorGui(mContext, mParentWidget)) - , mStepProcessingGui(new StepProcessingGui(mContext, mAuthenticateStepsWidget)) - , mStepShowSelfAuthenticationDataGui(new StepShowSelfAuthenticationDataGui(mContext, mAuthenticateStepsWidget)) + , mAdviseUserToRemoveCardGui(new StepAdviseUserToRemoveCardGui(mContext, mParentWidget)) + , mDidAuthenticateGui(new StepAuthenticationEac1Gui(mContext, mAuthenticateStepsWidget)) + , mChooseCardGui(new StepChooseCardGui(mContext, mAuthenticateStepsWidget)) + , mErrorGui(new StepErrorGui(mContext, mParentWidget)) + , mProcessingGui(new StepProcessingGui(mContext, mAuthenticateStepsWidget)) + , mShowSelfAuthenticationDataGui(new StepShowSelfAuthenticationDataGui(mContext, mAuthenticateStepsWidget)) { Q_ASSERT(mAuthenticateStepsWidget != nullptr); - connect(mWidget, &WorkflowQtWidget::fireUserCancelled, this, &WorkflowGui::fireUserCancelled); connect(mWidget, &WorkflowQtWidget::forwardStep, this, &WorkflowSelfInfoQtGui::onForwardStep); - - connect(mContext.data(), &SelfAuthenticationContext::fireCurrentStateChanged, this, &WorkflowSelfInfoQtGui::onCurrentStateChanged); } @@ -47,14 +56,14 @@ WorkflowSelfInfoQtGui::~WorkflowSelfInfoQtGui() void WorkflowSelfInfoQtGui::activate() { + activateStepUi(mProcessingGui); mParentWidget->workflowActivated(WorkflowWidgetParent::SelfAuthentication, tr("Identify")); - activateStepUi(mStepProcessingGui); + connect(mContext.data(), &SelfAuthenticationContext::fireCurrentStateChanged, this, &WorkflowSelfInfoQtGui::onCurrentStateChanged); } void WorkflowSelfInfoQtGui::deactivate() { - WorkflowGui::deactivate(); mParentWidget->workflowDeactivated(); } @@ -66,80 +75,6 @@ bool WorkflowSelfInfoQtGui::verifyAbortWorkflow() } -void WorkflowSelfInfoQtGui::onCurrentStateChanged(const QString& pNewState) -{ - if (!mContext->getResult().isOk() && !mContext->isErrorReportedToUser()) - { - if (mContext->getResult().getMinor() != Result::Minor::SAL_Cancellation_by_User) - { - activateStepUi(mStepErrorGui); - mStepErrorGui->reportError(); - } - mContext->setErrorReportedToUser(); - } - - bool approveNewState = true; - - if (pNewState == QLatin1String("StateLoadTcTokenUrl")) - { - GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); - approveNewState = !settings.isTransportPinReminder(); - } - else if (pNewState == QLatin1String("StateSelectPcscReader")) - { - activateStepUi(mStepChooseCardGui); - } - else if (pNewState == QLatin1String("StateUpdateRetryCounter")) - { - mRetryCounterUpdated = true; - } - else if (mRetryCounterUpdated) - { - mRetryCounterUpdated = false; - approveNewState = false; - if (!showPinBlockageDialog()) - { - if (mContext->getLastPaceResult() != ReturnCode::OK) - { - mStepAuthenticationEac1Gui->incorrectPinError(); - } - else - { - activateStepUi(mStepAuthenticationEac1Gui); - mStepAuthenticationEac1Gui->setState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT); - } - } - } - else if (pNewState == QLatin1String("StateDidAuthenticateEac1")) - { - mStepAuthenticationEac1Gui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_ESERVICE); - } - else if (pNewState == QLatin1String("StateDidAuthenticateEac2")) - { - mStepAuthenticationEac1Gui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_CARD); - } - else if (pNewState == QLatin1String("StateTransmit")) - { - mStepAuthenticationEac1Gui->setState(StepDidAuthenticateEac1Ui::State::READING_CARD_DATA); - } - else if (pNewState == QLatin1String("StateWriteHistory") && isActive(mStepAuthenticationEac1Gui)) - { - mStepAuthenticationEac1Gui->setState(StepDidAuthenticateEac1Ui::State::FINISHED); - } - else if (pNewState == QLatin1String("FinalState")) - { - activateStepUi(mStepAdviseUserToRemoveCardGui); - if (mContext->getResult().isOk()) - { - approveNewState = false; - activateStepUi(mStepShowSelfAuthenticationDataGui); - } - } - - mContext->setStateApproved(approveNewState); -} - - void WorkflowSelfInfoQtGui::onForwardStep() { if (mStepGui) @@ -149,21 +84,88 @@ void WorkflowSelfInfoQtGui::onForwardStep() } -bool WorkflowSelfInfoQtGui::showPinBlockageDialog() +void WorkflowSelfInfoQtGui::onCurrentStateChanged(const QString& pNewState) { - if (mContext->isPinBlocked()) + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) { - activateStepUi(mStepProcessingGui); - mContext->fireCancelWorkflow(); + if (!mContext->getStatus().isCancellationByUser()) + { + activateStepUi(mErrorGui); + mErrorGui->reportError(); + } + mContext->setErrorReportedToUser(); + } + + bool approveNewState = true; + if (AbstractState::isState(pNewState)) + { + GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); + approveNewState = !settings.isTransportPinReminder(); + } + else if (AbstractState::isState(pNewState)) + { + approveNewState = false; + activateStepUi(mDidAuthenticateGui); + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT); + } + else if (AbstractState::isState(pNewState)) + { + activateStepUi(mChooseCardGui); + } + else if (AbstractState::isState(pNewState) || AbstractState::isState(pNewState)) + { + if (AbstractState::isState(pNewState)) + { + approveNewState = !mContext->getCardConnection()->getReaderInfo().isBasicReader(); + mCanEntered = true; + } + else if (AbstractState::isState(pNewState)) + { + // PIN entry after CAN entry is done without user interaction + approveNewState = mCanEntered || !mContext->getCardConnection()->getReaderInfo().isBasicReader(); + } + activateStepUi(mDidAuthenticateGui); + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::ENTER_PIN); + if (mContext->getLastPaceResult() != CardReturnCode::OK) + { + mDidAuthenticateGui->incorrectPinError(); + } + } + else if (AbstractState::isState(pNewState)) + { + approveNewState = false; + Q_EMIT mContext->fireCancelWorkflow(); if (GuiUtils::showWrongPinBlockedDialog(mWidget)) { mContext->setReaderName(QString()); mParentWidget->switchToPinSettingsAfterWorkflow(); } - - return true; } - - return false; + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_ESERVICE); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::AUTHENTICATING_CARD); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::READING_CARD_DATA); + } + else if (AbstractState::isState(pNewState) && isActive(mDidAuthenticateGui)) + { + mDidAuthenticateGui->setState(StepDidAuthenticateEac1Ui::State::FINISHED); + } + else if (AbstractState::isState(pNewState)) + { + activateStepUi(mAdviseUserToRemoveCardGui); + if (mContext->getStatus().isNoError()) + { + approveNewState = false; + activateStepUi(mShowSelfAuthenticationDataGui); + } + } + mContext->setStateApproved(approveNewState); } diff --git a/src/gui/workflow/WorkflowSelfInfoQtGui.h b/src/gui/workflow/WorkflowSelfInfoQtGui.h index 9f0e479..76d74e9 100644 --- a/src/gui/workflow/WorkflowSelfInfoQtGui.h +++ b/src/gui/workflow/WorkflowSelfInfoQtGui.h @@ -14,18 +14,13 @@ namespace governikus { -class AppQtMainWidget; class AuthenticateStepsWidget; -class StepGui; -class WorkflowQtWidget; class StepAdviseUserToRemoveCardGui; -class StepChooseCardGui; -class StepChooseDeviceGui; +class StepShowSelfAuthenticationDataGui; class StepAuthenticationEac1Gui; +class StepChooseCardGui; class StepErrorGui; class StepProcessingGui; -class StepShowSelfAuthenticationDataGui; -class StepTransportPinReminderGui; class WorkflowSelfInfoQtGui : public GenericWorkflowGui @@ -33,19 +28,18 @@ class WorkflowSelfInfoQtGui Q_OBJECT private: - bool mRetryCounterUpdated; + bool mCanEntered; AuthenticateStepsWidget* mAuthenticateStepsWidget; - QSharedPointer mStepAdviseUserToRemoveCardGui; - QSharedPointer mStepChooseCardGui; - QSharedPointer mStepAuthenticationEac1Gui; - QSharedPointer mStepErrorGui; - QSharedPointer mStepProcessingGui; - QSharedPointer mStepShowSelfAuthenticationDataGui; - - bool showPinBlockageDialog(); + QSharedPointer mAdviseUserToRemoveCardGui; + QSharedPointer mDidAuthenticateGui; + QSharedPointer mChooseCardGui; + QSharedPointer mErrorGui; + QSharedPointer mProcessingGui; + QSharedPointer mShowSelfAuthenticationDataGui; private Q_SLOTS: void onForwardStep(); + void onCurrentStateChanged(const QString& pNewState); public: WorkflowSelfInfoQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget); @@ -53,13 +47,7 @@ class WorkflowSelfInfoQtGui virtual void activate() override; virtual void deactivate() override; - virtual bool verifyAbortWorkflow() override; - - const QSharedPointer& getContext(); - - public Q_SLOTS: - void onCurrentStateChanged(const QString& pNewState); }; } /* namespace governikus */ diff --git a/src/jsonapi/MessageDispatcher.cpp b/src/jsonapi/MessageDispatcher.cpp index a412b3f..c9ce2e1 100644 --- a/src/jsonapi/MessageDispatcher.cpp +++ b/src/jsonapi/MessageDispatcher.cpp @@ -11,6 +11,7 @@ #include "messages/MsgHandlerCertificate.h" #include "messages/MsgHandlerEnterCan.h" #include "messages/MsgHandlerEnterPin.h" +#include "messages/MsgHandlerEnterPuk.h" #include "messages/MsgHandlerInfo.h" #include "messages/MsgHandlerInsertCard.h" #include "messages/MsgHandlerInternalError.h" @@ -94,6 +95,9 @@ MsgHandler MessageDispatcher::createForStateChange(MsgType pStateType) case MsgType::ENTER_CAN: return MsgHandlerEnterCan(mContext); + case MsgType::ENTER_PUK: + return MsgHandlerEnterPuk(mContext); + case MsgType::ACCESS_RIGHTS: return MsgHandlerAccessRights(mContext); @@ -102,7 +106,7 @@ MsgHandler MessageDispatcher::createForStateChange(MsgType pStateType) default: mContext.getWorkflowContext()->setStateApproved(); - return MsgHandler::MsgVoid; + return MsgHandler::Void; } } @@ -197,7 +201,7 @@ MsgHandler MessageDispatcher::cancel() if (mContext.isActiveWorkflow()) { Q_EMIT mContext.getWorkflowContext()->fireCancelWorkflow(); - return MsgHandler::MsgVoid; + return MsgHandler::Void; } return MsgHandlerBadState(MsgCmdType::CANCEL); @@ -209,7 +213,7 @@ MsgHandler MessageDispatcher::accept() if (mContext.getLastStateMsg() == MsgType::ACCESS_RIGHTS) { mContext.getWorkflowContext()->setStateApproved(); - return MsgHandler::MsgVoid; + return MsgHandler::Void; } return MsgHandlerBadState(MsgCmdType::ACCEPT); diff --git a/src/jsonapi/UIPlugInJsonApi.cpp b/src/jsonapi/UIPlugInJsonApi.cpp index a381957..469c7b3 100644 --- a/src/jsonapi/UIPlugInJsonApi.cpp +++ b/src/jsonapi/UIPlugInJsonApi.cpp @@ -29,9 +29,19 @@ UIPlugInJsonApi::~UIPlugInJsonApi() } +void UIPlugInJsonApi::callFireMessage(const QByteArray& pMsg) const +{ + if (!pMsg.isEmpty()) + { + qCDebug(jsonapi) << "Fire message:" << pMsg; + Q_EMIT fireMessage(pMsg); + } +} + + void UIPlugInJsonApi::onWorkflowStarted(QSharedPointer pContext) { - if (pContext.dynamicCast()) + if (pContext.objectCast()) { #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) pContext->setReaderType(ReaderManagerPlugInType::NFC); @@ -42,49 +52,31 @@ void UIPlugInJsonApi::onWorkflowStarted(QSharedPointer pContext connect(pContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &UIPlugInJsonApi::onCurrentStateChanged); } - const auto& msg = mMessageDispatcher.init(pContext); - if (!msg.isEmpty()) - { - Q_EMIT fireMessage(msg); - } + callFireMessage(mMessageDispatcher.init(pContext)); } void UIPlugInJsonApi::onWorkflowFinished(QSharedPointer ) { - const auto& response = mMessageDispatcher.finish(); - if (!response.isEmpty()) - { - Q_EMIT fireMessage(response); - } + callFireMessage(mMessageDispatcher.finish()); } void UIPlugInJsonApi::onReaderEvent(const QString& pName) { - Q_EMIT fireMessage(mMessageDispatcher.createMsgReader(pName)); + callFireMessage(mMessageDispatcher.createMsgReader(pName)); } void UIPlugInJsonApi::onCurrentStateChanged(const QString& pNewState) { - const auto& response = mMessageDispatcher.processStateChange(pNewState); - if (!response.isEmpty()) - { - qDebug(jsonapi) << "Fire message:" << response; - Q_EMIT fireMessage(response); - } + callFireMessage(mMessageDispatcher.processStateChange(pNewState)); } void UIPlugInJsonApi::doMessageProcessing(const QByteArray& pMsg) { - const auto& response = mMessageDispatcher.processCommand(pMsg); - if (!response.isEmpty()) - { - qDebug(jsonapi) << "Fire message:" << response; - Q_EMIT fireMessage(response); - } + callFireMessage(mMessageDispatcher.processCommand(pMsg)); } diff --git a/src/jsonapi/UIPlugInJsonApi.h b/src/jsonapi/UIPlugInJsonApi.h index 7835c03..22922c0 100644 --- a/src/jsonapi/UIPlugInJsonApi.h +++ b/src/jsonapi/UIPlugInJsonApi.h @@ -23,6 +23,8 @@ class UIPlugInJsonApi private: MessageDispatcher mMessageDispatcher; + inline void callFireMessage(const QByteArray& pMsg) const; + public: UIPlugInJsonApi(); virtual ~UIPlugInJsonApi(); @@ -38,7 +40,7 @@ class UIPlugInJsonApi void doMessageProcessing(const QByteArray& pMsg); Q_SIGNALS: - void fireMessage(const QByteArray& pMsg); + void fireMessage(const QByteArray& pMsg) const; }; } /* namespace governikus */ diff --git a/src/jsonapi/messages/MsgContext.cpp b/src/jsonapi/messages/MsgContext.cpp index 9c3f655..b1232f2 100644 --- a/src/jsonapi/messages/MsgContext.cpp +++ b/src/jsonapi/messages/MsgContext.cpp @@ -31,7 +31,7 @@ QSharedPointer MsgContext::getAuthContext() { if (mContext) { - return mContext.dynamicCast(); + return mContext.objectCast(); } return QSharedPointer(); @@ -42,7 +42,7 @@ QSharedPointer MsgContext::getAuthContext() const { if (mContext) { - return mContext.dynamicCast(); + return mContext.objectCast(); } return QSharedPointer(); diff --git a/src/jsonapi/messages/MsgHandler.cpp b/src/jsonapi/messages/MsgHandler.cpp index 2c5d22d..9ee42cf 100644 --- a/src/jsonapi/messages/MsgHandler.cpp +++ b/src/jsonapi/messages/MsgHandler.cpp @@ -7,6 +7,7 @@ #include "states/StateEditAccessRights.h" #include "states/StateEstablishPaceCan.h" #include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" #include "states/StateSelectNfcReader.h" #include "states/StateSelectPcscReader.h" @@ -16,7 +17,7 @@ using namespace governikus; const MsgLevel MsgHandler::DEFAULT_MSG_LEVEL = MsgLevel::v1; -const MsgHandler MsgHandler::MsgVoid = MsgHandler(); +const MsgHandler MsgHandler::Void = MsgHandler(); MsgType MsgHandler::getStateMsgType(const QString& pState) @@ -29,6 +30,10 @@ MsgType MsgHandler::getStateMsgType(const QString& pState) { return MsgType::ENTER_CAN; } + else if (AbstractState::isState(pState)) + { + return MsgType::ENTER_PUK; + } else if (AbstractState::isState(pState)) { return MsgType::ACCESS_RIGHTS; diff --git a/src/jsonapi/messages/MsgHandler.h b/src/jsonapi/messages/MsgHandler.h index 2c0be5d..7586868 100644 --- a/src/jsonapi/messages/MsgHandler.h +++ b/src/jsonapi/messages/MsgHandler.h @@ -35,7 +35,7 @@ class MsgHandler void setVoid(bool pVoid = true); public: - static const MsgHandler MsgVoid; + static const MsgHandler Void; static const MsgLevel DEFAULT_MSG_LEVEL; static MsgType getStateMsgType(const QString& pState); diff --git a/src/jsonapi/messages/MsgHandlerAccessRights.cpp b/src/jsonapi/messages/MsgHandlerAccessRights.cpp index ca513f2..1d3f32a 100644 --- a/src/jsonapi/messages/MsgHandlerAccessRights.cpp +++ b/src/jsonapi/messages/MsgHandlerAccessRights.cpp @@ -43,18 +43,17 @@ MsgHandlerAccessRights::MsgHandlerAccessRights(const QJsonObject& pObj, MsgConte void MsgHandlerAccessRights::handleSetRawData(const QJsonArray& pRaw, const QSharedPointer& pContext) { Q_ASSERT(pContext); - Q_ASSERT(pContext->getEffectiveChat()); QSet effectiveChat; - if (pContext->getOptionalChat()) + if (!pContext->getOptionalAccessRights().isEmpty()) { for (const auto& entry : pRaw) { if (entry.isDouble()) { const auto value = static_cast(entry.toInt()); - if (pContext->getOptionalChat()->hasAccessRight(value)) + if (pContext->getOptionalAccessRights().contains(value)) { effectiveChat += value; } @@ -82,18 +81,17 @@ void MsgHandlerAccessRights::handleSetRawData(const QJsonArray& pRaw, const QSha } -QJsonArray MsgHandlerAccessRights::getAccessRights(const QSharedPointer& pChat) const +QJsonArray MsgHandlerAccessRights::getAccessRights(const QSet& pRights) const { QJsonArray array; - if (pChat) + + QList accessRights = pRights.toList(); + std::sort(accessRights.rbegin(), accessRights.rend()); + for (auto entry : qAsConst(accessRights)) { - QList accessRights = pChat->getAccessRights().toList(); - std::sort(accessRights.rbegin(), accessRights.rend()); - for (auto entry : qAsConst(accessRights)) - { - array += static_cast(entry); - } + array += static_cast(entry); } + return array; } @@ -103,9 +101,9 @@ void MsgHandlerAccessRights::fillAccessRights(const QSharedPointergetRequiredChat()); - raw["optional"] = getAccessRights(pContext->getOptionalChat()); - raw["effective"] = getAccessRights(pContext->getEffectiveChat()); + raw["required"] = getAccessRights(pContext->getRequiredAccessRights()); + raw["optional"] = getAccessRights(pContext->getOptionalAccessRights()); + raw["effective"] = getAccessRights(pContext->getEffectiveAccessRights()); mJsonObject["raw"] = raw; } diff --git a/src/jsonapi/messages/MsgHandlerAccessRights.h b/src/jsonapi/messages/MsgHandlerAccessRights.h index b7d4aeb..ebd2fb2 100644 --- a/src/jsonapi/messages/MsgHandlerAccessRights.h +++ b/src/jsonapi/messages/MsgHandlerAccessRights.h @@ -20,7 +20,7 @@ class MsgHandlerAccessRights void setError(const QLatin1String& pError); void handleSetRawData(const QJsonArray& pRaw, const QSharedPointer& pContext); - QJsonArray getAccessRights(const QSharedPointer& pChat) const; + QJsonArray getAccessRights(const QSet& pRights) const; void fillAccessRights(const QSharedPointer& pContext); public: diff --git a/src/jsonapi/messages/MsgHandlerAuth.cpp b/src/jsonapi/messages/MsgHandlerAuth.cpp index 6da5c66..72e5628 100644 --- a/src/jsonapi/messages/MsgHandlerAuth.cpp +++ b/src/jsonapi/messages/MsgHandlerAuth.cpp @@ -48,7 +48,7 @@ MsgHandlerAuth::MsgHandlerAuth(const QSharedPointer& pContext) { Q_ASSERT(pContext); - mJsonObject["result"] = pContext->getResult().toJson(); + mJsonObject["result"] = Result(pContext->getStatus()).toJson(); QString url; if (pContext->getRefreshUrl().isEmpty()) @@ -71,7 +71,7 @@ MsgHandlerAuth::MsgHandlerAuth(const QSharedPointer& pContext) QUrl MsgHandlerAuth::createUrl(const QString& pUrl) { const QUrl parsedUrl(pUrl); - if (parsedUrl.isValid() && parsedUrl.scheme() == QLatin1String("https") && !parsedUrl.host().isEmpty()) + if (parsedUrl.isValid() && !parsedUrl.host().isEmpty()) { QUrlQuery query; query.addQueryItem(QStringLiteral("tcTokenURL"), QString::fromLatin1(QUrl::toPercentEncoding(pUrl))); diff --git a/src/jsonapi/messages/MsgHandlerEnterCan.cpp b/src/jsonapi/messages/MsgHandlerEnterCan.cpp index c11ae54..b44b0ea 100644 --- a/src/jsonapi/messages/MsgHandlerEnterCan.cpp +++ b/src/jsonapi/messages/MsgHandlerEnterCan.cpp @@ -17,11 +17,11 @@ MsgHandlerEnterCan::MsgHandlerEnterCan(const MsgContext& pContext) MsgHandlerEnterCan::MsgHandlerEnterCan(const QJsonObject& pObj, MsgContext& pContext) : MsgHandlerEnterCan(pContext) { - parseValue(pObj["can"], [&](const QString& pNumber) - { - auto ctx = pContext.getWorkflowContext(); - ctx->setCan(pNumber); - ctx->setStateApproved(); - setVoid(); - }); + parseValue(pObj, [&](const QString& pNumber) + { + auto ctx = pContext.getWorkflowContext(); + ctx->setCan(pNumber); + ctx->setStateApproved(); + setVoid(); + }); } diff --git a/src/jsonapi/messages/MsgHandlerEnterNumber.cpp b/src/jsonapi/messages/MsgHandlerEnterNumber.cpp index 1720978..4658abb 100644 --- a/src/jsonapi/messages/MsgHandlerEnterNumber.cpp +++ b/src/jsonapi/messages/MsgHandlerEnterNumber.cpp @@ -39,20 +39,21 @@ void MsgHandlerEnterNumber::setReader(const QSharedPointer& pFunc, ushort pCount) +void MsgHandlerEnterNumber::parseValue(const QJsonObject& pObj, const std::function& pFunc, ushort pCount) { - if (pValue.isUndefined()) + const auto& value = pObj[QLatin1String("value")]; + if (value.isUndefined()) { setError(QStringLiteral("Value cannot be undefined")); } - else if (!pValue.isString()) + else if (!value.isString()) { setError(QStringLiteral("Invalid value")); } else { const auto& regex = QStringLiteral("^[0-9]{%1}$").arg(pCount); - const auto& number = pValue.toString(); + const auto& number = value.toString(); if (QRegularExpression(regex).match(number).hasMatch()) { pFunc(number); diff --git a/src/jsonapi/messages/MsgHandlerEnterNumber.h b/src/jsonapi/messages/MsgHandlerEnterNumber.h index 4d6d667..2f151f0 100644 --- a/src/jsonapi/messages/MsgHandlerEnterNumber.h +++ b/src/jsonapi/messages/MsgHandlerEnterNumber.h @@ -25,7 +25,7 @@ class MsgHandlerEnterNumber protected: MsgHandlerEnterNumber(MsgType pType, const MsgContext& pContext); - void parseValue(const QJsonValue& pObj, + void parseValue(const QJsonObject& pObj, const std::function& pFunc, ushort pCount = 6); }; diff --git a/src/jsonapi/messages/MsgHandlerEnterPin.cpp b/src/jsonapi/messages/MsgHandlerEnterPin.cpp index d19a101..fa84877 100644 --- a/src/jsonapi/messages/MsgHandlerEnterPin.cpp +++ b/src/jsonapi/messages/MsgHandlerEnterPin.cpp @@ -17,11 +17,11 @@ MsgHandlerEnterPin::MsgHandlerEnterPin(const MsgContext& pContext) MsgHandlerEnterPin::MsgHandlerEnterPin(const QJsonObject& pObj, MsgContext& pContext) : MsgHandlerEnterPin(pContext) { - parseValue(pObj["pin"], [&](const QString& pNumber) - { - auto ctx = pContext.getWorkflowContext(); - ctx->setPin(pNumber); - ctx->setStateApproved(); - setVoid(); - }); + parseValue(pObj, [&](const QString& pNumber) + { + auto ctx = pContext.getWorkflowContext(); + ctx->setPin(pNumber); + ctx->setStateApproved(); + setVoid(); + }); } diff --git a/src/jsonapi/messages/MsgHandlerEnterPuk.cpp b/src/jsonapi/messages/MsgHandlerEnterPuk.cpp new file mode 100644 index 0000000..fd0438f --- /dev/null +++ b/src/jsonapi/messages/MsgHandlerEnterPuk.cpp @@ -0,0 +1,14 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "MsgHandlerEnterPuk.h" + +#include "context/WorkflowContext.h" + +using namespace governikus; + +MsgHandlerEnterPuk::MsgHandlerEnterPuk(const MsgContext& pContext) + : MsgHandlerEnterNumber(MsgType::ENTER_PUK, pContext) +{ +} diff --git a/src/jsonapi/messages/MsgHandlerEnterPuk.h b/src/jsonapi/messages/MsgHandlerEnterPuk.h new file mode 100644 index 0000000..36eabb2 --- /dev/null +++ b/src/jsonapi/messages/MsgHandlerEnterPuk.h @@ -0,0 +1,23 @@ +/*! + * \brief Message EnterPuk of JSON API. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "MsgContext.h" +#include "MsgHandlerEnterNumber.h" + +namespace governikus +{ + +class MsgHandlerEnterPuk + : public MsgHandlerEnterNumber +{ + public: + MsgHandlerEnterPuk(const MsgContext& pContext); +}; + + +} /* namespace governikus */ diff --git a/src/jsonapi/messages/MsgHandlerReader.cpp b/src/jsonapi/messages/MsgHandlerReader.cpp index 8be4cfd..0597a1d 100644 --- a/src/jsonapi/messages/MsgHandlerReader.cpp +++ b/src/jsonapi/messages/MsgHandlerReader.cpp @@ -62,14 +62,16 @@ void MsgHandlerReader::setReaderInfo(QJsonObject& pObj, const ReaderInfo& pInfo, pObj["attached"] = pInfo.isValid(); if (pInfo.isValid()) { - QJsonObject card; - const bool npa = pInfo.getCardType() == CardType::EID_CARD; - card["inserted"] = npa; - if (npa) + if (pInfo.getCardType() == CardType::EID_CARD) { + QJsonObject card; card["deactivated"] = pInfo.isPinDeactivated(); card["retryCounter"] = pInfo.getRetryCounter(); + pObj["card"] = card; + } + else + { + pObj["card"] = QJsonValue::Null; } - pObj["card"] = card; } } diff --git a/src/jsonapi/messages/MsgTypes.h b/src/jsonapi/messages/MsgTypes.h index 6743965..d45a55a 100644 --- a/src/jsonapi/messages/MsgTypes.h +++ b/src/jsonapi/messages/MsgTypes.h @@ -26,7 +26,8 @@ defineEnumType(MsgType, ACCESS_RIGHTS, INSERT_CARD, ENTER_PIN, - ENTER_CAN) + ENTER_CAN, + ENTER_PUK) defineEnumType(MsgCmdType, UNDEFINED, diff --git a/src/main.cpp b/src/main.cpp index d4e64ea..86b53d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "CommandLineParser.h" +#include "MetaTypeRegister.h" #include "SignalHandler.h" #include "controller/AppController.h" #include "core/DeviceInfo.h" @@ -11,7 +12,7 @@ #include #include -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_WINRT) #include #define QAPP QGuiApplication #else @@ -23,7 +24,7 @@ // Includes for version API #include -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) Q_IMPORT_PLUGIN(PcscReaderManagerPlugIn) Q_IMPORT_PLUGIN(WebserviceActivationHandler) #endif @@ -44,7 +45,7 @@ Q_IMPORT_PLUGIN(BluetoothReaderManagerPlugIn) #endif -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) Q_IMPORT_PLUGIN(UIPlugInCli) Q_IMPORT_PLUGIN(UIPlugInWidgets) #endif @@ -80,6 +81,7 @@ static inline void printInfo() qCInfo(init) << "### Architecture:" << QSysInfo::currentCpuArchitecture(); #ifdef Q_OS_ANDROID qCInfo(init) << "### Device:" << DeviceInfo::getPrettyInfo(); + qCInfo(init) << "### VersionCode:" << BuildHelper::getVersionCode(); #endif qCInfo(init) << "### Qt Version:" << qVersion(); qCInfo(init) << "### OpenSSL Version:" << QSslSocket::sslLibraryVersionString(); @@ -98,7 +100,7 @@ static inline void printInfo() } -int main(int argc, char** argv) +Q_DECL_EXPORT int main(int argc, char** argv) { QCoreApplication::setOrganizationName(QStringLiteral(VENDOR)); #ifdef VENDOR_DOMAIN @@ -116,6 +118,8 @@ int main(int argc, char** argv) CommandLineParser::getInstance().parse(); printInfo(); + MetaTypes::registerMetaTypes(); + AppController controller; if (!controller.start()) { diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index eac127a..90117c4 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -1,3 +1,3 @@ ADD_PLATFORM_LIBRARY(AusweisAppNetwork) -TARGET_LINK_LIBRARIES(AusweisAppNetwork Qt5::Network Qt5::Core AusweisAppGlobal AusweisAppSettings) +TARGET_LINK_LIBRARIES(AusweisAppNetwork Qt5::Network Qt5::Core AusweisAppGlobal AusweisAppSettings AusweisAppExternalHttpParser) diff --git a/src/network/DatagramHandler.cpp b/src/network/DatagramHandler.cpp new file mode 100644 index 0000000..628c3af --- /dev/null +++ b/src/network/DatagramHandler.cpp @@ -0,0 +1,24 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "DatagramHandler.h" + + +using namespace governikus; + + +void DatagramHandler::registerMetaTypes() +{ + static bool registered = false; + if (!registered) + { + qRegisterMetaType("QHostAddress"); + registered = true; + } +} + + +DatagramHandler::~DatagramHandler() +{ +} diff --git a/src/network/DatagramHandler.h b/src/network/DatagramHandler.h new file mode 100644 index 0000000..ebfdd0a --- /dev/null +++ b/src/network/DatagramHandler.h @@ -0,0 +1,36 @@ +/*! + * \brief Provides an interface to send and receive datagrams over UDP. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include + + +namespace governikus +{ + + +class DatagramHandler + : public QObject +{ + Q_OBJECT + + public: + static void registerMetaTypes(); + + DatagramHandler() = default; + virtual ~DatagramHandler(); + virtual bool isBound() const = 0; + virtual bool send(const QJsonDocument& pData, const QHostAddress& pAddress = QHostAddress::Broadcast) = 0; + + Q_SIGNALS: + void fireNewMessage(const QJsonDocument& pData, const QHostAddress& pAddress); +}; + + +} /* namespace governikus */ diff --git a/src/network/DatagramHandlerImpl.cpp b/src/network/DatagramHandlerImpl.cpp new file mode 100644 index 0000000..b0819b9 --- /dev/null +++ b/src/network/DatagramHandlerImpl.cpp @@ -0,0 +1,106 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "DatagramHandlerImpl.h" + +#include "EnvHolder.h" + +#include +#include +#include +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(network) + + +namespace governikus +{ + +template<> DatagramHandler* createNewObject() +{ + return new DatagramHandlerImpl; +} + + +} /* namespace governikus */ + + +quint16 DatagramHandlerImpl::cPort = 24727; + + +DatagramHandlerImpl::DatagramHandlerImpl() + : DatagramHandler() + , mSocket(new QUdpSocket) +{ +#ifndef QT_NO_NETWORKPROXY + mSocket->setProxy(QNetworkProxy::NoProxy); +#endif + + connect(mSocket.data(), &QUdpSocket::readyRead, this, &DatagramHandlerImpl::onReadyRead); + + if (mSocket->bind(cPort)) + { + qCDebug(network) << "Bound on port:" << mSocket->localPort(); + } + else + { + qCDebug(network) << "Cannot bind socket:" << mSocket->errorString(); + } +} + + +DatagramHandlerImpl::~DatagramHandlerImpl() +{ + if (isBound()) + { + qCDebug(network) << "Shutdown socket"; + mSocket->close(); + } +} + + +bool DatagramHandlerImpl::isBound() const +{ + return mSocket->state() == QAbstractSocket::BoundState; +} + + +bool DatagramHandlerImpl::send(const QJsonDocument& pData, const QHostAddress& pAddress) +{ + const auto& data = pData.toJson(QJsonDocument::Compact); + const quint16 remotePort = cPort == 0 ? mSocket->localPort() : cPort; + if (mSocket->writeDatagram(data.constData(), pAddress, remotePort) != data.size()) + { + qCCritical(network) << "Cannot write datagram:" << mSocket->error() << '|' << mSocket->errorString(); + return false; + } + return true; +} + + +void DatagramHandlerImpl::onReadyRead() +{ + while (mSocket->hasPendingDatagrams()) + { + QByteArray datagram; + QHostAddress addr; + + datagram.resize(static_cast(mSocket->pendingDatagramSize())); + mSocket->readDatagram(datagram.data(), datagram.size(), &addr); + + QJsonParseError jsonError; + const auto& json = QJsonDocument::fromJson(datagram, &jsonError); + if (jsonError.error == QJsonParseError::NoError) + { + qCDebug(network) << "Fire new message"; + Q_EMIT fireNewMessage(json, addr); + } + else + { + qCInfo(network) << "Datagram does not contain valid JSON:" << datagram; + } + } +} diff --git a/src/network/DatagramHandlerImpl.h b/src/network/DatagramHandlerImpl.h new file mode 100644 index 0000000..6c2dd8f --- /dev/null +++ b/src/network/DatagramHandlerImpl.h @@ -0,0 +1,44 @@ +/*! + * \brief Provides an UDP socket to send and receive datagrams. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "DatagramHandler.h" + +#include +#include +#include + +class test_DatagramHandlerImpl; + +namespace governikus +{ + +class DatagramHandlerImpl + : public DatagramHandler +{ + Q_OBJECT + + private: + friend class::test_DatagramHandlerImpl; + friend struct QtSharedPointer::CustomDeleter; + + static quint16 cPort; + QScopedPointer mSocket; + + public: + DatagramHandlerImpl(); + virtual ~DatagramHandlerImpl(); + + virtual bool isBound() const override; + virtual bool send(const QJsonDocument& pData, const QHostAddress& pAddress = QHostAddress::Broadcast) override; + + private Q_SLOTS: + void onReadyRead(); +}; + + +} /* namespace governikus */ diff --git a/src/network/HttpRequest.cpp b/src/network/HttpRequest.cpp new file mode 100644 index 0000000..b411eba --- /dev/null +++ b/src/network/HttpRequest.cpp @@ -0,0 +1,200 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpRequest.h" + +#include + +using namespace governikus; + +#define CAST_OBJ(parser) HttpRequest * obj = static_cast(parser->data); + +Q_DECLARE_LOGGING_CATEGORY(network) + + +HttpRequest::HttpRequest(QAbstractSocket* pSocket, QObject* pParent) + : QObject(pParent) + , mUrl() + , mHeader() + , mBody() + , mSocket(pSocket, [](QAbstractSocket* s){ + s->flush(); + s->deleteLater(); + }) + , mParser() + , mParserSettings() + , mFinished(false) + , mCurrentHeaderField() + , mCurrentHeaderValue() +{ + Q_ASSERT(mSocket); + + http_parser_init(&mParser, HTTP_REQUEST); + mParser.data = this; + + mParserSettings.on_message_begin = &HttpRequest::onMessageBegin; + mParserSettings.on_message_complete = &HttpRequest::onMessageComplete; + mParserSettings.on_headers_complete = &HttpRequest::onHeadersComplete; + mParserSettings.on_header_field = &HttpRequest::onHeaderField; + mParserSettings.on_header_value = &HttpRequest::onHeaderValue; + mParserSettings.on_body = &HttpRequest::onBody; + mParserSettings.on_url = &HttpRequest::onUrl; + + connect(mSocket.data(), &QAbstractSocket::readyRead, this, &HttpRequest::onReadyRead); + connect(mSocket.data(), &QAbstractSocket::disconnected, this, &HttpRequest::deleteLater); + onReadyRead(); +} + + +HttpRequest::~HttpRequest() +{ +} + + +bool HttpRequest::isConnected() const +{ + return mSocket->state() == QAbstractSocket::ConnectedState; +} + + +QByteArray HttpRequest::getMethod() const +{ + return QByteArray(http_method_str(static_cast(mParser.method))); +} + + +bool HttpRequest::isUpgrade() const +{ + return mParser.upgrade; +} + + +QByteArray HttpRequest::getHeader(const QByteArray& pKey) const +{ + return mHeader.value(pKey); +} + + +const QMap& HttpRequest::getHeader() const +{ + return mHeader; +} + + +QUrl HttpRequest::getUrl() const +{ + return QUrl::fromEncoded(mUrl); +} + + +const QByteArray& HttpRequest::getBody() const +{ + return mBody; +} + + +bool HttpRequest::send(const HttpResponse& pResponse) +{ + const auto& msg = pResponse.getMessage(); + if (mSocket->write(msg) != msg.size()) + { + qCCritical(network) << "Cannot write response:" << mSocket->error() << '|' << mSocket->errorString(); + return false; + } + return true; +} + + +void HttpRequest::onReadyRead() +{ + while (mSocket->bytesAvailable()) + { + const auto& buffer = mSocket->readAll(); + http_parser_execute(&mParser, &mParserSettings, buffer.constData(), static_cast(buffer.size())); + + const auto errorCode = HTTP_PARSER_ERRNO(&mParser); + if (errorCode != HPE_OK) + { + qCWarning(network) << "Http request not well-formed:" << http_errno_name(errorCode) << "|" << http_errno_description(errorCode); + } + } + + if (mFinished) + { + disconnect(mSocket.data(), &QAbstractSocket::readyRead, this, &HttpRequest::onReadyRead); + disconnect(mSocket.data(), &QAbstractSocket::disconnected, this, &HttpRequest::deleteLater); + Q_EMIT fireMessageComplete(this, mSocket); + } +} + + +int HttpRequest::onMessageBegin(http_parser* pParser) +{ + Q_UNUSED(pParser) + return 0; +} + + +int HttpRequest::onMessageComplete(http_parser* pParser) +{ + CAST_OBJ(pParser) + obj->mFinished = true; + qCDebug(network) << "Message completed"; + return 0; +} + + +int HttpRequest::onHeadersComplete(http_parser* pParser) +{ + CAST_OBJ(pParser) + obj->insertHeader(); + qCDebug(network) << obj->getMethod() << " |" << obj->getUrl(); + qCDebug(network) << "Header completed"; + return 0; +} + + +int HttpRequest::onHeaderField(http_parser* pParser, const char* pPos, size_t pLength) +{ + CAST_OBJ(pParser) + obj->insertHeader(); + add(obj->mCurrentHeaderField, pPos, pLength); + return 0; +} + + +int HttpRequest::onHeaderValue(http_parser* pParser, const char* pPos, size_t pLength) +{ + CAST_OBJ(pParser) + add(obj->mCurrentHeaderValue, pPos, pLength); + return 0; +} + + +int HttpRequest::onBody(http_parser* pParser, const char* pPos, size_t pLength) +{ + CAST_OBJ(pParser) + add(obj->mBody, pPos, pLength); + return 0; +} + + +int HttpRequest::onUrl(http_parser* pParser, const char* pPos, size_t pLength) +{ + CAST_OBJ(pParser) + add(obj->mUrl, pPos, pLength); + return 0; +} + + +void HttpRequest::insertHeader() +{ + if (!mCurrentHeaderField.isEmpty() && !mCurrentHeaderValue.isEmpty()) + { + qCDebug(network).nospace() << "Header | " << mCurrentHeaderField << ": " << mCurrentHeaderValue; + mHeader.insert(mCurrentHeaderField.toLower(), mCurrentHeaderValue); + mCurrentHeaderField.clear(); + mCurrentHeaderValue.clear(); + } +} diff --git a/src/network/HttpRequest.h b/src/network/HttpRequest.h new file mode 100644 index 0000000..3965c69 --- /dev/null +++ b/src/network/HttpRequest.h @@ -0,0 +1,81 @@ +/*! + * \brief Class to parse http request. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "HttpResponse.h" +#include "http_parser/http_parser.h" + +#include +#include +#include +#include +#include +#include + +class test_WebserviceActivationHandler; + +namespace governikus +{ + +class HttpRequest + : public QObject +{ + Q_OBJECT + + private: + friend class::test_WebserviceActivationHandler; + + static int onMessageBegin(http_parser* pParser); + static int onMessageComplete(http_parser* pParser); + static int onHeadersComplete(http_parser* pParser); + static int onHeaderField(http_parser* pParser, const char* pPos, size_t pLength); + static int onHeaderValue(http_parser* pParser, const char* pPos, size_t pLength); + static int onBody(http_parser* pParser, const char* pPos, size_t pLength); + static int onUrl(http_parser* pParser, const char* pPos, size_t pLength); + + static inline void add(QByteArray& pDest, const char* pPos, size_t pLength) + { + pDest += QByteArray(pPos, static_cast(pLength)); + } + + + QByteArray mUrl; + QMap mHeader; + QByteArray mBody; + QSharedPointer mSocket; + http_parser mParser; + http_parser_settings mParserSettings; + + bool mFinished; + QByteArray mCurrentHeaderField; + QByteArray mCurrentHeaderValue; + + void insertHeader(); + + public: + HttpRequest(QAbstractSocket* pSocket, QObject* pParent = nullptr); + virtual ~HttpRequest(); + + bool isConnected() const; + + QByteArray getMethod() const; + bool isUpgrade() const; + QByteArray getHeader(const QByteArray& pKey) const; + const QMap& getHeader() const; + QUrl getUrl() const; + const QByteArray& getBody() const; + + bool send(const HttpResponse& pResponse); + + private Q_SLOTS: + void onReadyRead(); + + Q_SIGNALS: + void fireMessageComplete(HttpRequest* pSelf, QSharedPointer pSocket); +}; + +} /* namespace governikus */ diff --git a/src/network/HttpResponse.cpp b/src/network/HttpResponse.cpp new file mode 100644 index 0000000..b5eadd1 --- /dev/null +++ b/src/network/HttpResponse.cpp @@ -0,0 +1,124 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpResponse.h" + +#include +#include +#include +#include + +using namespace governikus; + +namespace +{ +static const auto HEADER_CONTENT_LENGTH = QByteArrayLiteral("Content-Length"); +static const auto HEADER_CONTENT_TYPE = QByteArrayLiteral("Content-Type"); +static const auto HEADER_SERVER = QByteArrayLiteral("Server"); +static const auto HEADER_DATE = QByteArrayLiteral("Date"); +} + +Q_DECLARE_LOGGING_CATEGORY(network) + +HttpResponse::HttpResponse(HttpStatusCode pStatus, const QByteArray& pBody, const QByteArray& pContentType) + : mStatus(pStatus) + , mHeader() + , mBody() +{ + setBody(pBody, pContentType); + + // According to TR-03124-1, chapter 2.2.2.1, the Server-header shall have the following form: + auto version = QCoreApplication::applicationVersion().toUtf8(); + if (!version.isEmpty()) + { + version.prepend('/'); + } + setHeader(HEADER_SERVER, QCoreApplication::applicationName().toUtf8() % version % QByteArrayLiteral(" (TR-03124-1/1.2)")); + setHeader(HEADER_DATE, QLocale::c().toString(QDateTime::currentDateTimeUtc(), QStringLiteral("ddd, dd MMM yyyy hh:mm:ss")).toUtf8() + QByteArrayLiteral(" GMT")); + setHeader(HEADER_CONTENT_LENGTH, QByteArray::number(mBody.size())); +} + + +HttpResponse::~HttpResponse() +{ +} + + +bool HttpResponse::isValid() const +{ + return mStatus != HttpStatusCode::UNDEFINED; +} + + +QByteArray HttpResponse::getHeader(const QByteArray& pKey) const +{ + return mHeader.value(pKey); +} + + +const QMap& HttpResponse::getHeaders() const +{ + return mHeader; +} + + +void HttpResponse::setHeader(const QByteArray& pKey, const QByteArray& pValue) +{ + mHeader.insert(pKey, pValue); +} + + +HttpStatusCode HttpResponse::getStatus() const +{ + return mStatus; +} + + +void HttpResponse::setStatus(HttpStatusCode pStatus) +{ + mStatus = pStatus; +} + + +const QByteArray& HttpResponse::getBody() const +{ + return mBody; +} + + +void HttpResponse::setBody(const QByteArray& pBody, const QByteArray& pContentType) +{ + mBody = pBody; + setHeader(HEADER_CONTENT_LENGTH, QByteArray::number(mBody.size())); + if (mBody.isEmpty() || pContentType.isEmpty()) + { + Q_ASSERT(pContentType.isEmpty()); + mHeader.remove(HEADER_CONTENT_TYPE); + } + else if (!pContentType.isEmpty()) + { + setHeader(HEADER_CONTENT_TYPE, pContentType); + } +} + + +QByteArray HttpResponse::getMessage() const +{ + Q_ASSERT(mStatus != HttpStatusCode::UNDEFINED); + + static const QByteArray CR_LF = QByteArrayLiteral("\r\n"); + QByteArrayList list; + + const auto& statusCode = QByteArray::number(static_cast(mStatus)); + QByteArray statusMsg(getEnumName(mStatus).data()); + list += QByteArrayLiteral("HTTP/1.0 ") % statusCode % ' ' % statusMsg.replace('_', ' '); + + const auto& end = mHeader.constEnd(); + for (auto iter = mHeader.constBegin(); iter != end; ++iter) + { + list += iter.key() % QByteArrayLiteral(": ") % iter.value(); + } + + return list.join(CR_LF) % CR_LF % CR_LF % mBody; +} diff --git a/src/network/HttpResponse.h b/src/network/HttpResponse.h new file mode 100644 index 0000000..875f62d --- /dev/null +++ b/src/network/HttpResponse.h @@ -0,0 +1,42 @@ +/*! + * \brief Class to create http response. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "HttpStatusCode.h" + +#include +#include + +namespace governikus +{ + +class HttpResponse +{ + private: + HttpStatusCode mStatus; + QMap mHeader; + QByteArray mBody; + + public: + HttpResponse(HttpStatusCode pStatus = HttpStatusCode::UNDEFINED, const QByteArray& pBody = QByteArray(), const QByteArray& pContentType = QByteArray()); + virtual ~HttpResponse(); + bool isValid() const; + + QByteArray getHeader(const QByteArray& pKey) const; + const QMap& getHeaders() const; + void setHeader(const QByteArray& pKey, const QByteArray& pValue); + + HttpStatusCode getStatus() const; + void setStatus(HttpStatusCode pStatus); + + const QByteArray& getBody() const; + void setBody(const QByteArray& pBody, const QByteArray& pContentType = QByteArray()); + + QByteArray getMessage() const; +}; + +} /* namespace governikus */ diff --git a/src/network/HttpServer.cpp b/src/network/HttpServer.cpp new file mode 100644 index 0000000..605c2a0 --- /dev/null +++ b/src/network/HttpServer.cpp @@ -0,0 +1,91 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpServer.h" + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(network) + +quint16 HttpServer::cPort = 24727; + +HttpServer::HttpServer(quint16 pPort) + : QObject() + , mServer(new QTcpServer) +{ + connect(mServer.data(), &QTcpServer::newConnection, this, &HttpServer::onNewConnection); + + if (mServer->listen(QHostAddress::LocalHost, pPort)) + { + qCDebug(network) << "Listening on port:" << mServer->serverPort(); + } + else + { + qCDebug(network) << "Cannot start server:" << mServer->errorString(); + } +} + + +HttpServer::~HttpServer() +{ + if (isListening()) + { + qCDebug(network) << "Shutdown server"; + mServer->close(); + } +} + + +bool HttpServer::isListening() const +{ + return mServer->isListening(); +} + + +quint16 HttpServer::getServerPort() const +{ + return mServer->serverPort(); +} + + +void HttpServer::onNewConnection() +{ + while (mServer->hasPendingConnections()) + { + auto socket = mServer->nextPendingConnection(); + socket->startTransaction(); + auto request = new HttpRequest(socket, this); + connect(request, &HttpRequest::fireMessageComplete, this, &HttpServer::onMessageComplete); + } +} + + +void HttpServer::onMessageComplete(HttpRequest* pRequest, QSharedPointer pSocket) +{ + pRequest->setParent(nullptr); + + if (pRequest->isUpgrade()) + { + pRequest->deleteLater(); + pSocket->rollbackTransaction(); + + if (pRequest->getHeader(QByteArrayLiteral("upgrade")).toLower() == QByteArrayLiteral("websocket")) + { + qCDebug(network) << "Upgrade to websocket requested"; + Q_EMIT fireNewWebSocketRequest(pSocket); + } + else + { + qCWarning(network) << "Unknown upgrade requested"; + pRequest->send(HttpStatusCode::NOT_FOUND); + } + } + else + { + pSocket->commitTransaction(); + Q_EMIT fireNewHttpRequest(QSharedPointer(pRequest, &QObject::deleteLater)); + } +} diff --git a/src/network/HttpServer.h b/src/network/HttpServer.h new file mode 100644 index 0000000..835e3b4 --- /dev/null +++ b/src/network/HttpServer.h @@ -0,0 +1,45 @@ +/*! + * \brief Provide a HTTP server. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "HttpRequest.h" + +#include +#include +#include +#include + +namespace governikus +{ + +class HttpServer + : public QObject +{ + Q_OBJECT + + private: + QScopedPointer mServer; + + public: + static quint16 cPort; + + HttpServer(quint16 pPort = HttpServer::cPort); + virtual ~HttpServer(); + + bool isListening() const; + quint16 getServerPort() const; + + private Q_SLOTS: + void onNewConnection(); + void onMessageComplete(HttpRequest* pRequest, QSharedPointer pSocket); + + Q_SIGNALS: + void fireNewHttpRequest(const QSharedPointer& pRequest); + void fireNewWebSocketRequest(const QSharedPointer& pSocket); +}; + +} /* namespace governikus */ diff --git a/src/network/HttpStatusCode.h b/src/network/HttpStatusCode.h index 8cd59f8..d6595ca 100644 --- a/src/network/HttpStatusCode.h +++ b/src/network/HttpStatusCode.h @@ -11,7 +11,9 @@ namespace governikus { +// see https://www.ietf.org/rfc/rfc2616.txt defineEnumType(HttpStatusCode, + UNDEFINED = 0, CONTINUE = 100, SWITCH_PROTOCOLS = 101, PROCESSING = 102, diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp index 57f2a5e..aa4a38d 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -4,10 +4,9 @@ #include "NetworkManager.h" -#include "ErrorMessage.h" +#include "AppSettings.h" #include "NetworkReplyError.h" #include "NetworkReplyTimeout.h" -#include "TlsConfiguration.h" #include "VersionInfo.h" #include @@ -104,8 +103,10 @@ NetworkManager::NetworkManager() mNetAccessManagerPsk->useAuthenticationManagerFrom(*mNetAccessManager); } +#ifndef QT_NO_NETWORKPROXY connect(mNetAccessManager.data(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &NetworkManager::fireProxyAuthenticationRequired); connect(mNetAccessManagerPsk.data(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &NetworkManager::fireProxyAuthenticationRequired); +#endif } @@ -137,12 +138,12 @@ QNetworkReply* NetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& QNetworkReply* response; if (pUsePsk) { - pRequest.setSslConfiguration(TlsConfiguration::createPskSslConfiguration()); + pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettingsPsk().getConfiguration()); response = mNetAccessManagerPsk->post(pRequest, pData); } else { - pRequest.setSslConfiguration(TlsConfiguration::createSslConfiguration()); + pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); response = mNetAccessManager->post(pRequest, pData); } @@ -159,7 +160,7 @@ QNetworkReply* NetworkManager::get(QNetworkRequest& pRequest, int pTimeoutInMill } pRequest.setHeader(QNetworkRequest::UserAgentHeader, getUserAgentHeader()); - pRequest.setSslConfiguration(TlsConfiguration::createSslConfiguration()); + pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); QNetworkReply* response = mNetAccessManager->get(pRequest); trackConnection(response, pTimeoutInMilliSeconds); return response; @@ -169,7 +170,7 @@ QNetworkReply* NetworkManager::get(QNetworkRequest& pRequest, int pTimeoutInMill QSslSocket* NetworkManager::createSslSocket(const QUrl& pUrl) { QSslSocket* socket = new QSslSocket(); - socket->setSslConfiguration(TlsConfiguration::createSslConfiguration()); + socket->setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); configureProxy(socket, pUrl); return socket; } @@ -177,12 +178,17 @@ QSslSocket* NetworkManager::createSslSocket(const QUrl& pUrl) void NetworkManager::configureProxy(QTcpSocket* pSocket, const QUrl& pUrl) { +#ifndef QT_NO_NETWORKPROXY // set the proxy explicitly, otherwise the proxy exception don't count QNetworkProxyQuery query(pUrl, QNetworkProxyQuery::QueryType::TcpSocket); - QNetworkProxy proxy = QNetworkProxyFactory::proxyForQuery(query).last(); + const QNetworkProxy& proxy = QNetworkProxyFactory::proxyForQuery(query).constLast(); pSocket->setProxy(proxy); connect(pSocket, &QTcpSocket::proxyAuthenticationRequired, this, &NetworkManager::fireProxyAuthenticationRequired); +#else + Q_UNUSED(pSocket) + Q_UNUSED(pUrl) +#endif } @@ -201,36 +207,72 @@ void NetworkManager::onShutdown() } -QString NetworkManager::getLocalizedErrorString(QNetworkReply* pNetworkReply) +NetworkManager::NetworkError NetworkManager::toNetworkError(const QNetworkReply* const pNetworkReply) { qCDebug(network) << "Select error message for:" << pNetworkReply->error(); - const QString requestUrl = pNetworkReply->request().url().toString(); switch (pNetworkReply->error()) { case QNetworkReply::TimeoutError: - return ErrorMessage::toString(ErrorMessageId::TIME_OUT); + return NetworkError::TimeOut; - // Fall through case QNetworkReply::ProxyAuthenticationRequiredError: case QNetworkReply::ProxyConnectionClosedError: case QNetworkReply::ProxyConnectionRefusedError: case QNetworkReply::ProxyNotFoundError: case QNetworkReply::ProxyTimeoutError: case QNetworkReply::UnknownProxyError: - return ErrorMessage::toString(ErrorMessageId::PROXY_ERROR); + return NetworkError::ProxyError; case QNetworkReply::SslHandshakeFailedError: - return ErrorMessage::toString(ErrorMessageId::SSL_ERROR); + return NetworkError::SslError; default: - return getLocalizedErrorString(pNetworkReply->errorString(), requestUrl); + qCCritical(network) << "Network error opening URL" << pNetworkReply->request().url().toString(); + qCCritical(network) << "Network error description" << pNetworkReply->errorString(); + return NetworkError::OtherError; } } -QString NetworkManager::getLocalizedErrorString(QTcpSocket* pTcpSocket, const QString& pPeerAddress) +GlobalStatus NetworkManager::toTrustedChannelStatus(const QNetworkReply* const pNetworkReply) { - return getLocalizedErrorString(pTcpSocket->errorString(), pPeerAddress); + switch (toNetworkError(pNetworkReply)) + { + case NetworkManager::NetworkError::TimeOut: + return GlobalStatus::Code::Workflow_TrustedChannel_TimeOut; + + case NetworkManager::NetworkError::ProxyError: + return GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error; + + case NetworkManager::NetworkError::SslError: + return GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error; + + case NetworkManager::NetworkError::OtherError: + return GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error; + } + + return GlobalStatus::Code::Unknown_Error; +} + + +GlobalStatus NetworkManager::toStatus(const QNetworkReply* const pNetworkReply) +{ + switch (toNetworkError(pNetworkReply)) + { + case NetworkManager::NetworkError::TimeOut: + return GlobalStatus::Code::Network_TimeOut; + + case NetworkManager::NetworkError::ProxyError: + return GlobalStatus::Code::Network_Proxy_Error; + + case NetworkManager::NetworkError::SslError: + return GlobalStatus::Code::Network_Ssl_Establishment_Error; + + case NetworkManager::NetworkError::OtherError: + return GlobalStatus::Code::Network_Other_Error; + } + + return GlobalStatus::Code::Unknown_Error; } @@ -240,29 +282,14 @@ void NetworkManager::trackConnection(QNetworkReply* pResponse, const int pTimeou mOpenConnectionCount++; connect(pResponse, &QNetworkReply::finished, [&] { - --mOpenConnectionCount; - }); + --mOpenConnectionCount; + }); NetworkReplyTimeout::setTimeout(pResponse, pTimeoutInMilliSeconds); } -QString NetworkManager::getLocalizedErrorString(const QString& pErrorString, const QString& pRequestUrl) -{ - qCCritical(network) << "Network error opening URL" << pRequestUrl; - qCCritical(network) << "Network error description" << pErrorString; - return ErrorMessage::tr(ErrorMessage::CONTACT_SUPPORT); -} - - -QDebug operator <<(QDebug pDbg, const QNetworkProxyQuery& pQuery) -{ - QDebugStateSaver saver(pDbg); - pDbg.nospace() << "ProxyQuery(type:" << (int) pQuery.queryType() << ", protocol:" << pQuery.protocolTag() << ", peerPort:" << pQuery.peerPort() << ", peerHostName:" << pQuery.peerHostName() << ", localPort:" << pQuery.localPort() << ", url:" << pQuery.url() << ")"; - return pDbg; -} - - +#ifndef QT_NO_NETWORKPROXY namespace { class NoProxyFactory @@ -314,25 +341,20 @@ class SystemProxyFactory } -void NetworkManager::setProxy(QNetworkProxy::ProxyType pProxyType) +void NetworkManager::setApplicationProxyFactory() { if (Q_UNLIKELY(mLockProxy)) { - qCWarning(network) << "Won't use proxy settings because they are locked!"; - pProxyType = QNetworkProxy::NoProxy; + qCWarning(network) << "Won't use system proxy because user locked it!"; + qCDebug(network) << "proxy -> none"; + QNetworkProxyFactory::setApplicationProxyFactory(new NoProxyFactory()); } - - switch (pProxyType) + else { - case QNetworkProxy::NoProxy: - qCDebug(network) << "proxy -> none"; - QNetworkProxyFactory::setApplicationProxyFactory(new NoProxyFactory()); - break; - - default: - case QNetworkProxy::DefaultProxy: - qCDebug(network) << "proxy -> system"; - QNetworkProxyFactory::setApplicationProxyFactory(new SystemProxyFactory()); - break; + qCDebug(network) << "proxy -> system"; + QNetworkProxyFactory::setApplicationProxyFactory(new SystemProxyFactory()); } } + + +#endif diff --git a/src/network/NetworkManager.h b/src/network/NetworkManager.h index e5cccb9..c17ae9e 100644 --- a/src/network/NetworkManager.h +++ b/src/network/NetworkManager.h @@ -6,6 +6,8 @@ #pragma once +#include "GlobalStatus.h" + #include #include #include @@ -31,7 +33,6 @@ class NetworkManager QScopedPointer mNetAccessManager; QScopedPointer mNetAccessManagerPsk; - static QString getLocalizedErrorString(const QString& pErrorString, const QString& pRequestUrl); void configureProxy(QTcpSocket* pSocket, const QUrl& pUrl); QString getUserAgentHeader() const; @@ -39,7 +40,16 @@ class NetworkManager void onShutdown(); public: - static void setProxy(QNetworkProxy::ProxyType pProxyType); + enum class NetworkError + { + TimeOut, + ProxyError, + SslError, + OtherError, + }; + Q_ENUM(NetworkError) + + static void setApplicationProxyFactory(); static void lockProxy(bool pLocked) { mLockProxy = pLocked; @@ -47,8 +57,9 @@ class NetworkManager static NetworkManager& getGlobalInstance(); - static QString getLocalizedErrorString(QTcpSocket* pTcpSocket, const QString& pPeerAddress); - static QString getLocalizedErrorString(QNetworkReply* pNetworkReply); + static NetworkError toNetworkError(const QNetworkReply* const pNetworkReply); + static GlobalStatus toTrustedChannelStatus(const QNetworkReply* const pNetworkReply); + static GlobalStatus toStatus(const QNetworkReply* const pNetworkReply); static QString getTlsVersionString(QSsl::SslProtocol pProtocol); NetworkManager(); @@ -72,4 +83,3 @@ class NetworkManager } /* namespace governikus */ QDebug operator <<(QDebug pDbg, QSsl::SslProtocol pProtocol); -QDebug operator <<(QDebug pDbg, const QNetworkProxyQuery& pQuery); diff --git a/src/network/TlsConfiguration.cpp b/src/network/TlsConfiguration.cpp index db49fa8..38c9151 100644 --- a/src/network/TlsConfiguration.cpp +++ b/src/network/TlsConfiguration.cpp @@ -15,148 +15,6 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(developermode) Q_DECLARE_LOGGING_CATEGORY(network) -QSslConfiguration TlsConfiguration::mConfig; -QSslConfiguration TlsConfiguration::mPskConfig; - -SslEllipticCurveVector TlsConfiguration::mEllipticCurves; -SslCipherList TlsConfiguration::mPskCiphers; -SslCipherList TlsConfiguration::mCiphersWithForwardSecrecy; -SslCipherList TlsConfiguration::mCiphersWithSha1ForBackwardCompatibility; - - -SslCipherList& SslCipherList::operator +=(const QString& pCipherName) -{ - QSslCipher cipher(pCipherName); - if (cipher.isNull()) - { - qCWarning(network) << "Cipher is not supported by OpenSSL and will be ignored:" << pCipherName; - } - else - { - append(cipher); - } - - return *this; -} - - -SslEllipticCurveVector& SslEllipticCurveVector::operator +=(const QString& pEllipticCurveName) -{ - QSslEllipticCurve curve = QSslEllipticCurve::fromLongName(pEllipticCurveName); - if (curve.isValid() && curve.isTlsNamedCurve()) - { - append(curve); - } - else - { - qCWarning(network) << "EllipticCurve is not supported by OpenSSL and will be ignored:" << pEllipticCurveName; - } - - return *this; -} - - -const QVector& TlsConfiguration::getAllowedSslEllipticCurves() -{ - if (mEllipticCurves.isEmpty()) - { - for (const QString& cipherName : AppSettings::getInstance().getSecureStorage().getAllowedSslEllipticCurves()) - { - mEllipticCurves += cipherName; - } - } - return mEllipticCurves; -} - - -const QList& TlsConfiguration::getCiphersWithPsk() -{ - if (mPskCiphers.isEmpty()) - { - for (const QString& cipherName : AppSettings::getInstance().getSecureStorage().getCiphersWithPsk()) - { - mPskCiphers += cipherName; - } - } - return mPskCiphers; -} - - -/*! - * This is the intersection of all ciphers with forward secrecy needed by TR-03116 Part 4 - * and all ciphers supported by openSSL according to https://www.openssl.org/docs/apps/ciphers.html. - */ -const QList& TlsConfiguration::getCiphersWithForwardSecrecy() -{ - if (mCiphersWithForwardSecrecy.isEmpty()) - { - for (const QString& cipherName : AppSettings::getInstance().getSecureStorage().getCiphersWithForwardSecrecy()) - { - mCiphersWithForwardSecrecy += cipherName; - } - } - return mCiphersWithForwardSecrecy; -} - - -/*! - * Enable SHA1 for message authentication as a "compatibility exception", see TR-02102-2, section 3.3.2 - */ -const QList& TlsConfiguration::getCiphersWithSha1ForBackwardCompatibility() -{ - if (mCiphersWithSha1ForBackwardCompatibility.isEmpty()) - { - for (const QString& cipherName : AppSettings::getInstance().getSecureStorage().getCiphersWithSha1ForBackwardCompatibility()) - { - mCiphersWithSha1ForBackwardCompatibility += cipherName; - } - } - return mCiphersWithSha1ForBackwardCompatibility; -} - - -QSslConfiguration TlsConfiguration::createSslConfiguration() -{ - if (!mConfig.isNull()) - { - return mConfig; - } - - QSslConfiguration config(QSslConfiguration::defaultConfiguration()); - - QList allowedCiphers = getCiphersWithForwardSecrecy(); - allowedCiphers.append(getCiphersWithSha1ForBackwardCompatibility()); - - // disable system CA certificates. Set allowRootCertOnDemandLoading = false - config.setCaCertificates(QSslConfiguration::systemCaCertificates()); - config.setCiphers(allowedCiphers); - config.setProtocol(AppSettings::getInstance().getSecureStorage().getSslProtocolVersion()); - config.setEllipticCurves(getAllowedSslEllipticCurves()); - config.setSignatureAndHashAlgorithms(AppSettings::getInstance().getSecureStorage().getSignatureAlgorithms()); - mConfig = config; - return mConfig; -} - - -QSslConfiguration TlsConfiguration::createPskSslConfiguration() -{ - if (!mPskConfig.isNull()) - { - return mPskConfig; - } - - QSslConfiguration config(QSslConfiguration::defaultConfiguration()); - - // disable system CA certificates. Set allowRootCertOnDemandLoading = false - config.setCaCertificates(QSslConfiguration::systemCaCertificates()); - config.setCiphers(getCiphersWithPsk()); - config.setProtocol(AppSettings::getInstance().getSecureStorage().getSslProtocolVersionPsk()); - config.setSignatureAndHashAlgorithms(AppSettings::getInstance().getSecureStorage().getSignatureAlgorithmsPsk()); - mPskConfig = config; - return mPskConfig; -} - - QStringList TlsConfiguration::getFatalErrors(const QList& pErrors) { static const QSet fatalErrors( @@ -191,7 +49,16 @@ QStringList TlsConfiguration::getFatalErrors(const QList& pErrors) } -bool TlsConfiguration::containsFatalError(const QList& pErrors) +bool TlsConfiguration::containsFatalError(QNetworkReply* pReply, const QList& pErrors) { - return !getFatalErrors(pErrors).isEmpty(); + Q_ASSERT(pReply); + + if (getFatalErrors(pErrors).isEmpty()) + { + qCDebug(network) << "Ignore SSL errors"; + pReply->ignoreSslErrors(); + return false; + } + + return true; } diff --git a/src/network/TlsConfiguration.h b/src/network/TlsConfiguration.h index b13e0ff..01fd14e 100644 --- a/src/network/TlsConfiguration.h +++ b/src/network/TlsConfiguration.h @@ -9,6 +9,7 @@ #include "SecureStorage.h" #include +#include #include #include #include @@ -17,55 +18,17 @@ namespace governikus { -class SslCipherList - : public QList -{ - public: - SslCipherList& operator +=(const QString& pCipherName); -}; - -class SslEllipticCurveVector - : public QVector -{ - public: - SslEllipticCurveVector& operator +=(const QString& pEllipticCurveName); -}; - class TlsConfiguration { private: - static QSslConfiguration mConfig; - static QSslConfiguration mPskConfig; - - static SslEllipticCurveVector mEllipticCurves; - static SslCipherList mPskCiphers; - static SslCipherList mCiphersWithForwardSecrecy; - static SslCipherList mCiphersWithSha1ForBackwardCompatibility; - TlsConfiguration(); ~TlsConfiguration(); Q_DISABLE_COPY(TlsConfiguration) public: - static const QList& getCiphersWithPsk(); - static const QList& getCiphersWithForwardSecrecy(); - static const QList& getCiphersWithSha1ForBackwardCompatibility(); - static const QVector& getAllowedSslEllipticCurves(); - - /*! - * Create SSL/TLS configuration for TLS-1-2 and every other connection - * like ProviderService and Updates. - */ - static QSslConfiguration createSslConfiguration(); - - /*! - * Create SSL/TLS configuration for TLS-2 with RSA-PSK cipher suites. - */ - static QSslConfiguration createPskSslConfiguration(); - static QStringList getFatalErrors(const QList& pErrors); - static bool containsFatalError(const QList& pErrors); + static bool containsFatalError(QNetworkReply* pReply, const QList& pErrors); }; } /* namespace governikus */ diff --git a/src/network/UrlUtil.cpp b/src/network/UrlUtil.cpp index 89fa4bb..3cf4176 100644 --- a/src/network/UrlUtil.cpp +++ b/src/network/UrlUtil.cpp @@ -54,27 +54,28 @@ QString UrlUtil::removePrefix(QString pStr) } -QUrl UrlUtil::addMajorMinor(const QUrl& pOriginUrl, const Result& pResult) +QUrl UrlUtil::addMajorMinor(const QUrl& pOriginUrl, const GlobalStatus& pStatus) { - QString major = removePrefix(pResult.getMajorString()); + const Result result(pStatus); + const QString& major = removePrefix(result.getMajorString()); QUrlQuery q; q.setQuery(pOriginUrl.query()); q.addQueryItem(QStringLiteral("ResultMajor"), major); - if (pResult.getMinor() != Result::Minor::null) + if (result.getMinor() != GlobalStatus::Code::Unknown_Error) { QString minor; - if (pResult.isOriginServer()) + if (result.isOriginServer()) { minor = QStringLiteral("serverError"); } - else if (pResult.getMinor() == Result::Minor::AL_Communication_Error || - pResult.getMinor() == Result::Minor::DP_Trusted_Channel_Establishment_Failed || - pResult.getMinor() == Result::Minor::SAL_Cancellation_by_User) + else if (result.getMinor() == GlobalStatus::Code::Paos_Error_AL_Communication_Error || + result.getMinor() == GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed || + result.getMinor() == GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User) { - minor = removePrefix(pResult.getMinorString()); + minor = removePrefix(result.getMinorString()); } else { diff --git a/src/network/UrlUtil.h b/src/network/UrlUtil.h index f001be4..6217eba 100644 --- a/src/network/UrlUtil.h +++ b/src/network/UrlUtil.h @@ -40,7 +40,7 @@ class UrlUtil /*! * Append result to URL. */ - static QUrl addMajorMinor(const QUrl& pUrl, const Result& pResult); + static QUrl addMajorMinor(const QUrl& pUrl, const GlobalStatus& pStatus); }; diff --git a/src/qml/ApplicationModel.cpp b/src/qml/ApplicationModel.cpp index d6c2ca0..e388aea 100644 --- a/src/qml/ApplicationModel.cpp +++ b/src/qml/ApplicationModel.cpp @@ -6,12 +6,25 @@ #include "ReaderInfo.h" #include "ReaderManager.h" +#include "SingletonHelper.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" #include "context/SelfAuthenticationContext.h" +#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#include +#endif + +#ifdef Q_OS_ANDROID +#include +#include +#include +#endif + using namespace governikus; +defineSingleton(ApplicationModel) + void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) { @@ -19,7 +32,7 @@ void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) { Q_EMIT fireBluetoothEnabledChanged(); } - if (pInfo.getPlugInType() == ReaderManagerPlugInType::NFC) + else if (pInfo.getPlugInType() == ReaderManagerPlugInType::NFC) { Q_EMIT fireNfcEnabledChanged(); } @@ -31,7 +44,10 @@ ApplicationModel::ApplicationModel(QObject* pParent) , mContext() { connect(&ReaderManager::getInstance(), &ReaderManager::fireStatusChanged, this, &ApplicationModel::onStatusChanged); - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderPropertiesUpdated, this, &ApplicationModel::fireReaderPropertiesUpdated); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &ApplicationModel::fireBluetoothReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderConnected, this, &ApplicationModel::fireBluetoothReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &ApplicationModel::fireBluetoothReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireStatusChanged, this, &ApplicationModel::fireBluetoothReaderChanged); } @@ -40,66 +56,119 @@ ApplicationModel::~ApplicationModel() } -void ApplicationModel::resetContext(QSharedPointer pContext) +ApplicationModel& ApplicationModel::getWidgetInstance() +{ + return *Instance; +} + + +void ApplicationModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; Q_EMIT fireCurrentWorkflowChanged(); } -bool ApplicationModel::isEnabled(ReaderManagerPlugInType pType) const +ReaderManagerPlugInInfo ApplicationModel::getFirstPlugInInfo(ReaderManagerPlugInType pType) const { const auto pluginInfos = ReaderManager::getInstance().getPlugInInfos(); for (const auto& info : pluginInfos) { if (info.getPlugInType() == pType) { - return info.isEnabled(); + return info; } } - return false; + return ReaderManagerPlugInInfo(); +} + + +bool ApplicationModel::isNfcAvailable() const +{ + return getFirstPlugInInfo(ReaderManagerPlugInType::NFC).isAvailable(); } bool ApplicationModel::isNfcEnabled() const { - return isEnabled(ReaderManagerPlugInType::NFC); + return getFirstPlugInInfo(ReaderManagerPlugInType::NFC).isEnabled(); } -bool ApplicationModel::isExtendedLengthApdusUnsupported() const +bool ApplicationModel::isBluetoothAvailable() const { - for (const ReaderInfo& readerInfo : ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::NFC)) - { - if (readerInfo.getExtendedLengthApduSupportCode() == ExtendedLengthApduSupportCode::NOT_SUPPORTED) - { - return true; - } - } - - return false; + return getFirstPlugInInfo(ReaderManagerPlugInType::BLUETOOTH).isAvailable(); } bool ApplicationModel::isBluetoothEnabled() const { - return isEnabled(ReaderManagerPlugInType::BLUETOOTH); + return getFirstPlugInInfo(ReaderManagerPlugInType::BLUETOOTH).isEnabled(); } QString ApplicationModel::getCurrentWorkflow() const { - if (mContext.dynamicCast()) + if (mContext.objectCast()) { return QStringLiteral("changepin"); } - if (mContext.dynamicCast()) + if (mContext.objectCast()) { return QStringLiteral("selfauthentication"); } - if (mContext.dynamicCast()) + if (mContext.objectCast()) { return QStringLiteral("authentication"); } return QString(); } + + +void ApplicationModel::setBluetoothEnabled(bool pEnabled) +{ +#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + if (pEnabled) + { + QBluetoothLocalDevice localDevice; + localDevice.powerOn(); + qDebug() << "Bluetooth" << (pEnabled ? "Enabled" : "Disabled"); + } +#else + qWarning() << (pEnabled ? "Enabling" : "Disabling") << "Bluetooth not supported on this platform"; +#endif +} + + +bool ApplicationModel::locationPermissionRequired() const +{ +#ifdef Q_OS_ANDROID + if (QtAndroid::androidSdkVersion() < 23) + { + return false; + } + + QAndroidJniEnvironment env; + const int PERMISSION_GRANTED = 0; + const auto& permission = QAndroidJniObject::fromString(QStringLiteral("android.permission.ACCESS_COARSE_LOCATION")); + + const auto result = QAndroidJniObject::callStaticMethod( + "org/qtproject/qt5/android/QtNative", + "checkSelfPermission", + "(Ljava/lang/String;)I", + permission.object()); + + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + qWarning() << "Exception occurred while checking location permission"; + return false; + } + + return (result != PERMISSION_GRANTED) && ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::BLUETOOTH).isEmpty(); + +#else + return false; + +#endif +} diff --git a/src/qml/ApplicationModel.h b/src/qml/ApplicationModel.h index d537b0a..efde4d0 100644 --- a/src/qml/ApplicationModel.h +++ b/src/qml/ApplicationModel.h @@ -24,32 +24,40 @@ class ApplicationModel { Q_OBJECT Q_PROPERTY(bool nfcEnabled READ isNfcEnabled NOTIFY fireNfcEnabledChanged) - Q_PROPERTY(bool extendedLengthApdusUnsupported READ isExtendedLengthApdusUnsupported NOTIFY fireReaderPropertiesUpdated) - Q_PROPERTY(bool bluetoothEnabled READ isBluetoothEnabled NOTIFY fireBluetoothEnabledChanged) + Q_PROPERTY(bool nfcAvailable READ isNfcAvailable CONSTANT) + Q_PROPERTY(bool bluetoothEnabled READ isBluetoothEnabled WRITE setBluetoothEnabled NOTIFY fireBluetoothEnabledChanged) + Q_PROPERTY(bool bluetoothAvailable READ isBluetoothAvailable CONSTANT) + Q_PROPERTY(bool locationPermissionRequired READ locationPermissionRequired NOTIFY fireBluetoothReaderChanged) Q_PROPERTY(QString currentWorkflow READ getCurrentWorkflow NOTIFY fireCurrentWorkflowChanged) QSharedPointer mContext; void onStatusChanged(const ReaderManagerPlugInInfo& pInfo); - bool isEnabled(ReaderManagerPlugInType pType) const; + ReaderManagerPlugInInfo getFirstPlugInInfo(ReaderManagerPlugInType pType) const; public: ApplicationModel(QObject* pParent = nullptr); virtual ~ApplicationModel(); - void resetContext(QSharedPointer pContext = QSharedPointer()); + // TODO: remove the singleton when the stationary qml ui used the UIPlugInQml + static ApplicationModel& getWidgetInstance(); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); + + bool isNfcAvailable() const; bool isNfcEnabled() const; - bool isExtendedLengthApdusUnsupported() const; + bool isBluetoothAvailable() const; bool isBluetoothEnabled() const; + void setBluetoothEnabled(bool pEnabled); + bool locationPermissionRequired() const; QString getCurrentWorkflow() const; Q_SIGNALS: void fireNfcEnabledChanged(); void fireBluetoothEnabledChanged(); - void fireReaderPropertiesUpdated(); void fireCurrentWorkflowChanged(); + void fireBluetoothReaderChanged(); }; diff --git a/src/qml/AuthModel.cpp b/src/qml/AuthModel.cpp index 70d3ca3..cbdd9a8 100644 --- a/src/qml/AuthModel.cpp +++ b/src/qml/AuthModel.cpp @@ -3,6 +3,7 @@ */ #include "AuthModel.h" + #include "ReaderManagerPlugInInfo.h" #include "context/AuthContext.h" @@ -12,6 +13,7 @@ using namespace governikus; AuthModel::AuthModel(QObject* pParent) : QObject(pParent) , mContext() + , mTransactionInfo() { } @@ -21,18 +23,21 @@ AuthModel::~AuthModel() } -void AuthModel::resetContext(QSharedPointer pContext) +void AuthModel::resetContext(const QSharedPointer& pContext) { + if (!mTransactionInfo.isEmpty()) + { + mTransactionInfo.clear(); + + Q_EMIT fireTransactionInfoChanged(); + } + mContext = pContext; if (mContext) { -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - mContext->setReaderType(ReaderManagerPlugInType::NFC); -#else - mContext->setReaderType(ReaderManagerPlugInType::PCSC); -#endif connect(mContext.data(), &AuthContext::fireCurrentStateChanged, this, &AuthModel::fireCurrentStateChanged); connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &AuthModel::fireResultChanged); + connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &AuthModel::onDidAuthenticateEac1Changed); } /* @@ -50,13 +55,19 @@ QString AuthModel::getCurrentState() const QString AuthModel::getResultString() const { - return mContext ? mContext->getResult().getMessage() : QString(); + return mContext ? mContext->getStatus().toErrorDescription(true) : QString(); } bool AuthModel::isError() const { - return mContext && !mContext->getResult().isOk(); + return mContext && mContext->getStatus().isError(); +} + + +const QString& AuthModel::getTransactionInfo() const +{ + return mTransactionInfo; } @@ -78,11 +89,21 @@ void AuthModel::cancelWorkflow() } +void AuthModel::cancelWorkflowOnPinBlocked() +{ + if (mContext) + { + mContext->setStatus(GlobalStatus::Code::Workflow_Pin_Blocked_And_Puk_Objectionable); + Q_EMIT mContext->fireCancelWorkflow(); + } +} + + void AuthModel::setReaderType(const QString& pReaderType) { if (mContext) { - mContext->setReaderType(EnumReaderManagerPlugInType::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); + mContext->setReaderType(Enum::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); } } @@ -105,3 +126,19 @@ void AuthModel::abortCardSelection() Q_EMIT mContext->fireAbortCardSelection(); } } + + +void AuthModel::onDidAuthenticateEac1Changed() +{ + if (mContext) + { + const QSharedPointer& didAuthenticateEAC1 = mContext->getDidAuthenticateEac1(); + const QString newTransactionInfo = didAuthenticateEAC1.isNull() ? QString() : didAuthenticateEAC1->getTransactionInfo(); + if (newTransactionInfo != mTransactionInfo) + { + mTransactionInfo = newTransactionInfo; + + Q_EMIT fireTransactionInfoChanged(); + } + } +} diff --git a/src/qml/AuthModel.h b/src/qml/AuthModel.h index 01a1ca2..a12da89 100644 --- a/src/qml/AuthModel.h +++ b/src/qml/AuthModel.h @@ -22,28 +22,36 @@ class AuthModel Q_PROPERTY(QString currentState READ getCurrentState NOTIFY fireCurrentStateChanged) Q_PROPERTY(QString resultString READ getResultString NOTIFY fireResultChanged) Q_PROPERTY(bool error READ isError NOTIFY fireResultChanged) + Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged) QSharedPointer mContext; + QString mTransactionInfo; public: AuthModel(QObject* pParent = nullptr); virtual ~AuthModel(); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); QString getCurrentState() const; QString getResultString() const; bool isError() const; + const QString& getTransactionInfo() const; - Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void cancelWorkflow(); + Q_INVOKABLE void cancelWorkflowOnPinBlocked(); + Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void setReaderType(const QString& pReaderType); Q_INVOKABLE bool isBasicReader(); Q_INVOKABLE void abortCardSelection(); + public Q_SLOTS: + void onDidAuthenticateEac1Changed(); + Q_SIGNALS: void fireCurrentStateChanged(const QString& pState); void fireResultChanged(); + void fireTransactionInfoChanged(); }; diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt index c405b14..8e57fa1 100644 --- a/src/qml/CMakeLists.txt +++ b/src/qml/CMakeLists.txt @@ -1,6 +1,14 @@ ADD_PLATFORM_LIBRARY(AusweisAppQml) TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Svg Qt5::Qml Qt5::Quick Qt5::QuickControls2 AusweisAppCore AusweisAppGlobal) +IF(DESKTOP) + TARGET_LINK_LIBRARIES(AusweisAppQml AusweisAppExport) +ENDIF() + +IF(TARGET Qt5::Bluetooth) + TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Bluetooth) +ENDIF() + TARGET_COMPILE_DEFINITIONS(AusweisAppQml PRIVATE QT_STATICPLUGIN) IF(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") diff --git a/src/qml/CertificateDescriptionModel.cpp b/src/qml/CertificateDescriptionModel.cpp index e4b8076..f5ec66e 100644 --- a/src/qml/CertificateDescriptionModel.cpp +++ b/src/qml/CertificateDescriptionModel.cpp @@ -32,38 +32,44 @@ void CertificateDescriptionModel::onDidAuthenticateEac1Changed() { beginResetModel(); mData.clear(); - - auto certDescr = getCertificateDescription(); - const QString serviceProviderAddress = certDescr->getServiceProviderAddress(); - const QString purpose = getPurpose(); - const QString dataSecurityOfficer = certDescr->getDataSecurityOfficer(); - const QString termsOfUsage = certDescr->getTermsOfUsage(); - const bool showDetailedProviderInfo = !(serviceProviderAddress.isEmpty() || purpose.isEmpty() || dataSecurityOfficer.isEmpty()); - - mData.append(QPair(tr("Service provider"), getSubjectName() + '\n' + getSubjectUrl())); - mData.append(QPair(tr("Certificate issuer"), certDescr->getIssuerName() + '\n' + certDescr->getIssuerUrl())); - if (showDetailedProviderInfo) + if (const auto& certDescr = getCertificateDescription()) { - mData.append(QPair(tr("Name, address and mail address of the service provider"), serviceProviderAddress)); - mData.append(QPair(tr("Purpose"), purpose)); - mData.append(QPair(tr("Indication of the bodies responsible for the service provider, " - "that verify the compliance with data security regulations"), dataSecurityOfficer)); + initModelData(certDescr); } - else if (!termsOfUsage.isEmpty()) - { - mData.append(QPair(tr("Service provider information"), termsOfUsage)); - } - if (!getValidity().isEmpty()) - { - mData.append(QPair(tr("Validity"), getValidity())); - } - endResetModel(); Q_EMIT fireChanged(); } +void CertificateDescriptionModel::initModelData(const QSharedPointer& pCertDescription) +{ + const QString& serviceProviderAddress = pCertDescription->getServiceProviderAddress(); + const QString& purpose = getPurpose(); + const QString& dataSecurityOfficer = pCertDescription->getDataSecurityOfficer(); + const QString& termsOfUsage = pCertDescription->getTermsOfUsage(); + const bool showDetailedProviderInfo = !(serviceProviderAddress.isEmpty() || purpose.isEmpty() || dataSecurityOfficer.isEmpty()); + + mData += QPair(tr("Service provider"), getSubjectName() + '\n' + getSubjectUrl()); + mData += QPair(tr("Certificate issuer"), pCertDescription->getIssuerName() + '\n' + pCertDescription->getIssuerUrl()); + if (showDetailedProviderInfo) + { + mData += QPair(tr("Name, address and mail address of the service provider"), serviceProviderAddress); + mData += QPair(tr("Purpose"), purpose); + mData += QPair(tr("Indication of the bodies responsible for the service provider, " + "that verify the compliance with data security regulations"), dataSecurityOfficer); + } + else if (!termsOfUsage.isEmpty()) + { + mData += QPair(tr("Service provider information"), termsOfUsage); + } + if (!getValidity().isEmpty()) + { + mData += QPair(tr("Validity"), getValidity()); + } +} + + CertificateDescriptionModel::CertificateDescriptionModel(QObject* pParent) : QAbstractListModel(pParent) , mData() @@ -74,7 +80,7 @@ CertificateDescriptionModel::CertificateDescriptionModel(QObject* pParent) } -void CertificateDescriptionModel::resetContext(QSharedPointer pContext) +void CertificateDescriptionModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; if (mContext) @@ -88,19 +94,22 @@ void CertificateDescriptionModel::resetContext(QSharedPointer pCont QString CertificateDescriptionModel::getSubjectName() const { - return getCertificateDescription()->getSubjectName(); + const auto& certificateDescription = getCertificateDescription(); + return certificateDescription ? getCertificateDescription()->getSubjectName() : QString(); } QString CertificateDescriptionModel::getSubjectUrl() const { - return getCertificateDescription()->getSubjectUrl(); + const auto& certificateDescription = getCertificateDescription(); + return certificateDescription ? getCertificateDescription()->getSubjectUrl() : QString(); } QString CertificateDescriptionModel::getPurpose() const { - return getCertificateDescription()->getPurpose(); + const auto& certificateDescription = getCertificateDescription(); + return certificateDescription ? getCertificateDescription()->getPurpose() : QString(); } diff --git a/src/qml/CertificateDescriptionModel.h b/src/qml/CertificateDescriptionModel.h index 888ae68..265ece5 100644 --- a/src/qml/CertificateDescriptionModel.h +++ b/src/qml/CertificateDescriptionModel.h @@ -39,6 +39,7 @@ class CertificateDescriptionModel inline QSharedPointer getCertificateDescription() const; inline QString getValidity() const; + void initModelData(const QSharedPointer& pCertDescription); private Q_SLOTS: void onDidAuthenticateEac1Changed(); @@ -46,7 +47,7 @@ class CertificateDescriptionModel public: CertificateDescriptionModel(QObject* pParent = nullptr); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); QString getSubjectName() const; QString getSubjectUrl() const; diff --git a/src/qml/ChangePinModel.cpp b/src/qml/ChangePinModel.cpp index 4e16ac9..60d12e5 100644 --- a/src/qml/ChangePinModel.cpp +++ b/src/qml/ChangePinModel.cpp @@ -3,8 +3,8 @@ */ #include "ChangePinModel.h" + #include "ReaderManager.h" -#include "ReturnCodeUtil.h" #include "context/ChangePinContext.h" #include @@ -23,16 +23,11 @@ ChangePinModel::~ChangePinModel() } -void ChangePinModel::resetContext(QSharedPointer pContext) +void ChangePinModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; if (mContext) { -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - mContext->setReaderType(ReaderManagerPlugInType::NFC); -#else - mContext->setReaderType(ReaderManagerPlugInType::PCSC); -#endif connect(mContext.data(), &ChangePinContext::fireCurrentStateChanged, this, &ChangePinModel::fireCurrentStateChanged); connect(mContext.data(), &ChangePinContext::fireResultChanged, this, &ChangePinModel::fireResultChanged); connect(mContext.data(), &ChangePinContext::fireSuccessMessageChanged, this, &ChangePinModel::fireResultChanged); @@ -55,20 +50,18 @@ QString ChangePinModel::getCurrentState() const QString ChangePinModel::getResultString() const { - if (mContext) - { - return mContext->getResult().isOk() ? mContext->getSuccessMessage() : mContext->getResult().getMessage(); - } - else + if (!mContext) { return QString(); } + + return mContext->getStatus().isNoError() ? mContext->getSuccessMessage() : mContext->getStatus().toErrorDescription(true); } bool ChangePinModel::isResultOk() const { - return mContext && mContext->getResult().isOk(); + return mContext && mContext->getStatus().isNoError(); } @@ -78,15 +71,6 @@ void ChangePinModel::startWorkflow() } -void ChangePinModel::continueWorkflow() -{ - if (mContext) - { - mContext->setStateApproved(); - } -} - - void ChangePinModel::cancelWorkflow() { if (mContext) @@ -101,7 +85,7 @@ void ChangePinModel::setReaderType(const QString& pReaderType) { if (mContext) { - mContext->setReaderType(EnumReaderManagerPlugInType::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); + mContext->setReaderType(Enum::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); } } diff --git a/src/qml/ChangePinModel.h b/src/qml/ChangePinModel.h index 2630fe0..e0a2b23 100644 --- a/src/qml/ChangePinModel.h +++ b/src/qml/ChangePinModel.h @@ -1,5 +1,5 @@ /*! - * \brief Model implementation for the pin action. + * \brief Model implementation for the PIN action. * * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG */ @@ -29,14 +29,13 @@ class ChangePinModel ChangePinModel(QObject* pParent = nullptr); virtual ~ChangePinModel(); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); QString getCurrentState() const; QString getResultString() const; bool isResultOk() const; Q_INVOKABLE void startWorkflow(); - Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void cancelWorkflow(); Q_INVOKABLE void setReaderType(const QString& pReaderType); Q_INVOKABLE bool isBasicReader(); diff --git a/src/qml/ChatModel.cpp b/src/qml/ChatModel.cpp index b3c3ffd..17c18e4 100644 --- a/src/qml/ChatModel.cpp +++ b/src/qml/ChatModel.cpp @@ -21,7 +21,6 @@ ChatModel::ChatModel(QObject* pParent) , mSelectedRights() , mFilterOptionalModel() , mFilterRequiredModel() - , mRequiredAge() { resetContext(QSharedPointer()); @@ -33,16 +32,16 @@ ChatModel::ChatModel(QObject* pParent) void ChatModel::initFilterModel(QSortFilterProxyModel& pModel, const QString& pFilter) { pModel.setSourceModel(this); - pModel.setFilterRole(ChatRoles::OPTIONAL); + pModel.setFilterRole(ChatRoles::OPTIONAL_ROLE); pModel.setFilterRegExp(pFilter); } -void ChatModel::resetContext(QSharedPointer pContext) +void ChatModel::resetContext(const QSharedPointer& pContext) { mAuthContext = pContext; - if (pContext.dynamicCast()) + if (pContext.objectCast()) { /* nothing to do, access rights are static */ } @@ -53,13 +52,10 @@ void ChatModel::resetContext(QSharedPointer pContext) mAllRights.clear(); mOptionalRights.clear(); mSelectedRights.clear(); - mRequiredAge.clear(); endResetModel(); - connect(mAuthContext.data(), &AuthContext::fireOptionalChatChanged, this, &ChatModel::onOptionalChatChanged); - connect(mAuthContext.data(), &AuthContext::fireRequiredChatChanged, this, &ChatModel::onRequiredChatChanged); - connect(mAuthContext.data(), &AuthContext::fireRequiredAgeChanged, this, &ChatModel::onRequiredAgeChanged); + connect(mAuthContext.data(), &AuthContext::fireAuthenticationDataChanged, this, &ChatModel::onAuthenticationDataChanged); } else { @@ -84,42 +80,33 @@ void ChatModel::resetContext(QSharedPointer pContext) mOptionalRights.clear(); mSelectedRights = mAllRights.toSet(); - mRequiredAge.clear(); endResetModel(); } } -void ChatModel::onOptionalChatChanged() +void ChatModel::onAuthenticationDataChanged() { beginResetModel(); - Q_ASSERT(mAuthContext->getOptionalChat()); - mOptionalRights += mAuthContext->getOptionalChat()->getAccessRights(); - setOrderedAllRights(mAuthContext->getOptionalChat()->getAccessRights()); - mSelectedRights += mAuthContext->getOptionalChat()->getAccessRights(); + mAllRights.clear(); + mOptionalRights.clear(); + mSelectedRights.clear(); - endResetModel(); -} + if (!mAuthContext->getRequiredAccessRights().isEmpty()) + { + setOrderedAllRights(mAuthContext->getRequiredAccessRights()); + mSelectedRights += mAuthContext->getRequiredAccessRights(); + } + if (!mAuthContext->getOptionalAccessRights().isEmpty()) + { + mOptionalRights += mAuthContext->getOptionalAccessRights(); + setOrderedAllRights(mAuthContext->getOptionalAccessRights()); + mSelectedRights += mAuthContext->getOptionalAccessRights(); + } -void ChatModel::onRequiredChatChanged() -{ - beginResetModel(); - - Q_ASSERT(mAuthContext->getRequiredChat()); - setOrderedAllRights(mAuthContext->getRequiredChat()->getAccessRights()); - mSelectedRights += mAuthContext->getRequiredChat()->getAccessRights(); - - endResetModel(); -} - - -void ChatModel::onRequiredAgeChanged() -{ - beginResetModel(); - mRequiredAge = mAuthContext->getRequiredAge(); endResetModel(); } @@ -147,20 +134,20 @@ QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const if (pIndex.isValid() && pIndex.row() < rowCount()) { auto right = mAllRights.at(pIndex.row()); - if (pRole == Qt::DisplayRole || pRole == NAME) + if (pRole == Qt::DisplayRole || pRole == NAME_ROLE) { QString displayText = AccessRoleAndRightsUtil::toDisplayText(right); - if (right == AccessRight::AGE_VERIFICATION && !mRequiredAge.isEmpty()) + if (right == AccessRight::AGE_VERIFICATION) { - displayText = displayText.append(" (%1)").arg(mRequiredAge); + displayText += QStringLiteral(" (%1)").arg(mAuthContext->getRequiredAge()); } return displayText; } - if (pRole == OPTIONAL) + if (pRole == OPTIONAL_ROLE) { return mOptionalRights.contains(right); } - if (pRole == SELECTED) + if (pRole == SELECTED_ROLE) { return mSelectedRights.contains(right); } @@ -172,16 +159,16 @@ QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const QHash ChatModel::roleNames() const { QHash roles = QAbstractListModel::roleNames(); - roles.insert(NAME, "name"); - roles.insert(OPTIONAL, "optional"); - roles.insert(SELECTED, "selected"); + roles.insert(NAME_ROLE, "name"); + roles.insert(OPTIONAL_ROLE, "optional"); + roles.insert(SELECTED_ROLE, "selected"); return roles; } bool ChatModel::setData(const QModelIndex& pIndex, const QVariant& pValue, int pRole) { - if (pRole == SELECTED) + if (pRole == SELECTED_ROLE) { auto right = mAllRights.at(pIndex.row()); @@ -201,7 +188,7 @@ bool ChatModel::setData(const QModelIndex& pIndex, const QVariant& pValue, int p return false; } - dataChanged(pIndex, pIndex, QVector({SELECTED})); + Q_EMIT dataChanged(pIndex, pIndex, QVector({SELECTED_ROLE})); return true; } diff --git a/src/qml/ChatModel.h b/src/qml/ChatModel.h index 94da61b..bb80647 100644 --- a/src/qml/ChatModel.h +++ b/src/qml/ChatModel.h @@ -31,13 +31,12 @@ class ChatModel QSet mOptionalRights, mSelectedRights; QSortFilterProxyModel mFilterOptionalModel; QSortFilterProxyModel mFilterRequiredModel; - QString mRequiredAge; enum ChatRoles { - NAME = Qt::UserRole + 1, - OPTIONAL, - SELECTED + NAME_ROLE = Qt::UserRole + 1, + OPTIONAL_ROLE, + SELECTED_ROLE }; private: @@ -45,14 +44,12 @@ class ChatModel void setOrderedAllRights(const QSet& pAllRights); private Q_SLOTS: - void onOptionalChatChanged(); - void onRequiredChatChanged(); - void onRequiredAgeChanged(); + void onAuthenticationDataChanged(); public: ChatModel(QObject* pParent = nullptr); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); int rowCount(const QModelIndex& = QModelIndex()) const override; QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; diff --git a/src/qml/ConnectivityManager.cpp b/src/qml/ConnectivityManager.cpp new file mode 100644 index 0000000..69756de --- /dev/null +++ b/src/qml/ConnectivityManager.cpp @@ -0,0 +1,107 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "ConnectivityManager.h" + +#include +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(network) + + +ConnectivityManager::ConnectivityManager(QObject* pParent) + : QObject(pParent) + , mTimerId(0) + , mActive(false) +{ +} + + +ConnectivityManager::~ConnectivityManager() +{ + if (mTimerId) + { + killTimer(mTimerId); + } +} + + +void ConnectivityManager::setActive(bool pActive, const QString& pInterfaceName) +{ + if (mActive != pActive) + { + if (pActive) + { + qCDebug(network) << "Found active network interface" << pInterfaceName; + } + else + { + qCDebug(network) << "Found no active network interface"; + } + mActive = pActive; + Q_EMIT fireNetworkInterfaceActiveChanged(mActive); + } +} + + +void ConnectivityManager::updateConnectivity() +{ + const auto& allInterfaces = QNetworkInterface::allInterfaces(); + for (const auto& iface : allInterfaces) + { + if (iface.flags().testFlag(QNetworkInterface::IsUp) + && iface.flags().testFlag(QNetworkInterface::IsRunning) + && !iface.flags().testFlag(QNetworkInterface::IsLoopBack) + && !iface.addressEntries().isEmpty()) + { + setActive(true, iface.name()); + return; + } + } + setActive(false); +} + + +void ConnectivityManager::timerEvent(QTimerEvent* pTimerEvent) +{ + if (pTimerEvent->timerId() == mTimerId) + { + updateConnectivity(); + } +} + + +bool ConnectivityManager::isNetworkInterfaceActive() const +{ + return mActive; +} + + +void ConnectivityManager::startWatching() +{ + if (mTimerId) + { + qCWarning(network) << "Already started, skip"; + return; + } + mTimerId = startTimer(1000); + updateConnectivity(); +} + + +void ConnectivityManager::stopWatching() +{ + if (!mTimerId) + { + qCWarning(network) << "Already stopped, skip"; + return; + } + killTimer(mTimerId); + mTimerId = 0; +} diff --git a/src/qml/ConnectivityManager.h b/src/qml/ConnectivityManager.h new file mode 100644 index 0000000..44ed45a --- /dev/null +++ b/src/qml/ConnectivityManager.h @@ -0,0 +1,44 @@ +/*! + * \brief Utility class providing information about network connectivity status. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + + +#include + + +namespace governikus +{ + +class ConnectivityManager + : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool networkInterfaceActive READ isNetworkInterfaceActive NOTIFY fireNetworkInterfaceActiveChanged) + + private: + int mTimerId; + bool mActive; + void setActive(bool pActive, const QString& pInterfaceName = QString()); + void updateConnectivity(); + + protected: + void timerEvent(QTimerEvent* pEvent) override; + + public: + ConnectivityManager(QObject* pParent = nullptr); + virtual ~ConnectivityManager(); + + bool isNetworkInterfaceActive() const; + void startWatching(); + void stopWatching(); + + Q_SIGNALS: + void fireNetworkInterfaceActiveChanged(bool pActive); +}; + + +} /* namespace governikus */ diff --git a/src/qml/DpiCalculator_generic.cpp b/src/qml/DpiCalculator_generic.cpp index 4c1c51d..df24eb6 100644 --- a/src/qml/DpiCalculator_generic.cpp +++ b/src/qml/DpiCalculator_generic.cpp @@ -13,12 +13,8 @@ Q_DECLARE_LOGGING_CATEGORY(qml) qreal DpiCalculator::getDpi() { qreal dpi = 0.0; -#ifdef Q_OS_WIN - auto app = static_cast(QCoreApplication::instance()); - auto screen = app->primaryScreen(); - dpi = screen->logicalDotsPerInch() * app->devicePixelRatio(); -#elif defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) auto qtDpi = qgetenv("QT_ANDROID_THEME_DISPLAY_DPI"); bool ok; dpi = qtDpi.toFloat(&ok); @@ -35,7 +31,7 @@ qreal DpiCalculator::getDpi() #else auto app = static_cast(QCoreApplication::instance()); auto screen = app->primaryScreen(); - dpi = screen->physicalDotsPerInch() * app->devicePixelRatio(); + dpi = screen->logicalDotsPerInch(); #endif qCInfo(qml) << "Determined dpi" << dpi; diff --git a/src/qml/HistoryModel.cpp b/src/qml/HistoryModel.cpp index 67da9c1..9378ac3 100644 --- a/src/qml/HistoryModel.cpp +++ b/src/qml/HistoryModel.cpp @@ -5,12 +5,42 @@ */ #include "HistoryModel.h" +#include "ProviderModel.h" +#include #include using namespace governikus; +namespace +{ +bool matchProviderWithSubjectUrl(const Provider& pProvider, const QString& pSubjectUrl) +{ + const QString subjectUrlHost = QUrl(pSubjectUrl).host(); + + // Check provider address host. + if (QUrl(pProvider.getAddress()).host() == subjectUrlHost) + { + return true; + } + + // Check subject urls. + for (const auto& subjectUrl : pProvider.getSubjectUrls()) + { + if (QUrl(subjectUrl).host() == subjectUrlHost) + { + return true; + } + } + + return false; +} + + +} + + HistoryProxyModel::HistoryProxyModel() { } @@ -29,7 +59,7 @@ bool HistoryProxyModel::removeRows(int pRow, int pCount, const QModelIndex& pPar bool ProviderNameFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& /* pSourceParent */) const { - HistoryModel* const dataSourceModel = dynamic_cast(sourceModel()); + HistoryModel* const dataSourceModel = qobject_cast(sourceModel()); if (dataSourceModel == nullptr) { return false; @@ -37,12 +67,13 @@ bool ProviderNameFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex auto entry = mHistorySettings->getHistoryEntries()[pSourceRow]; - return mProviderAddressHost == QUrl(entry.getSubjectUrl()).host(); + return matchProviderWithSubjectUrl(mProvider, entry.getSubjectUrl()); } -ProviderNameFilterModel::ProviderNameFilterModel(HistorySettings* pHistorySettings) +ProviderNameFilterModel::ProviderNameFilterModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings) : mHistorySettings(pHistorySettings) + , mProviderSettings(pProviderSettings) { } @@ -54,12 +85,22 @@ ProviderNameFilterModel::~ProviderNameFilterModel() void ProviderNameFilterModel::setProviderAddress(const QString& pProviderAddress) { - const QString providerAddressHost = QUrl(pProviderAddress).host(); - if (providerAddressHost != mProviderAddressHost) + if (mProvider.getAddress() != pProviderAddress) { - mProviderAddressHost = providerAddressHost; + for (const auto& provider : mProviderSettings->getProviders()) + { + if (provider.getAddress() == pProviderAddress) + { + mProvider = provider; - invalidateFilter(); + invalidateFilter(); + + return; + } + } + + // If we get here, no provider for pProviderAddress was found in the settings. + qWarning() << "Cannot select provider with address" << pProviderAddress; } } @@ -69,12 +110,14 @@ HistoryModel::HistoryModel(HistorySettings* pHistorySettings, ProviderSettings* , mHistorySettings(pHistorySettings) , mProviderSettings(pProviderSettings) , mFilterModel() - , mNameFilterModel(pHistorySettings) + , mNameFilterModel(pHistorySettings, pProviderSettings) { mFilterModel.setSourceModel(this); mFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive); mNameFilterModel.setSourceModel(this); + mHistoryModelSearchFilter.setSourceModel(this); connect(mHistorySettings, &HistorySettings::fireHistoryEntriesChanged, this, &HistoryModel::onHistoryEntriesChanged); + connect(mHistorySettings, &HistorySettings::fireEnabledChanged, this, &HistoryModel::fireEnabledChanged); connect(mProviderSettings, &ProviderSettings::fireProvidersChanged, this, &HistoryModel::onProvidersChanged); } @@ -103,11 +146,12 @@ void HistoryModel::onProvidersChanged() PROVIDER_HOMEPAGE, PROVIDER_HOMEPAGE_BASE, PROVIDER_PHONE, + PROVIDER_PHONE_COST, PROVIDER_EMAIL, PROVIDER_POSTALADDRESS, PROVIDER_ICON, PROVIDER_IMAGE}); - dataChanged(index(0), index(rowCount() - 1), PROVIDER_ROLES); + Q_EMIT dataChanged(index(0), index(rowCount() - 1), PROVIDER_ROLES); } @@ -150,22 +194,22 @@ QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const if (pRole == PROVIDER_SHORTNAME) { auto provider = determineProviderFor(entry); - return QVariant(provider.getShortName()); + return provider.getShortName().toString(); } if (pRole == PROVIDER_LONGNAME) { auto provider = determineProviderFor(entry); - return QVariant(provider.getLongName()); + return provider.getLongName().toString(); } if (pRole == PROVIDER_SHORTDESCRIPTION) { auto provider = determineProviderFor(entry); - return QVariant(provider.getShortDescription()); + return provider.getShortDescription().toString(); } if (pRole == PROVIDER_LONGDESCRIPTION) { auto provider = determineProviderFor(entry); - return QVariant(provider.getLongDescription()); + return provider.getLongDescription().toString(); } if (pRole == PROVIDER_ADDRESS) { @@ -192,6 +236,12 @@ QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const auto provider = determineProviderFor(entry); return provider.getPhone(); } + if (pRole == PROVIDER_PHONE_COST) + { + const auto& provider = determineProviderFor(entry); + const auto& cost = mProviderSettings->getCallCost(provider); + return ProviderModel::createCostString(cost); + } if (pRole == PROVIDER_EMAIL) { auto provider = determineProviderFor(entry); @@ -222,9 +272,9 @@ Provider HistoryModel::determineProviderFor(const HistoryEntry& pHistoryEntry) c QVector matchingProviders; for (const auto& provider : mProviderSettings->getProviders()) { - if (QUrl(provider.getAddress()).host() == QUrl(pHistoryEntry.getSubjectUrl()).host()) + if (matchProviderWithSubjectUrl(provider, pHistoryEntry.getSubjectUrl())) { - matchingProviders.append(provider); + matchingProviders += provider; } } if (matchingProviders.size() == 1) @@ -235,6 +285,22 @@ Provider HistoryModel::determineProviderFor(const HistoryEntry& pHistoryEntry) c } +bool HistoryModel::isEnabled() const +{ + return mHistorySettings->isEnabled(); +} + + +void HistoryModel::setEnabled(bool pEnabled) +{ + if (pEnabled != isEnabled()) + { + mHistorySettings->setEnabled(pEnabled); + mHistorySettings->save(); + } +} + + QHash HistoryModel::roleNames() const { QHash roles = QAbstractListModel::roleNames(); @@ -243,20 +309,21 @@ QHash HistoryModel::roleNames() const roles.insert(DATETIME, "dateTime"); roles.insert(TERMSOFUSAGE, "termsOfUsage"); roles.insert(REQUESTEDDATA, "requestedData"); - roles.insert(PROVIDER_CATEGORY, "provider_category"); - roles.insert(PROVIDER_SHORTNAME, "provider_shortname"); - roles.insert(PROVIDER_LONGNAME, "provider_longname"); - roles.insert(PROVIDER_SHORTDESCRIPTION, "provider_shortdescription"); - roles.insert(PROVIDER_LONGDESCRIPTION, "provider_longdescription"); - roles.insert(PROVIDER_ADDRESS, "provider_address"); - roles.insert(PROVIDER_ADDRESS_DOMAIN, "provider_address_domain"); - roles.insert(PROVIDER_HOMEPAGE, "provider_homepage"); - roles.insert(PROVIDER_HOMEPAGE_BASE, "provider_homepage_base"); - roles.insert(PROVIDER_PHONE, "provider_phone"); - roles.insert(PROVIDER_EMAIL, "provider_email"); - roles.insert(PROVIDER_POSTALADDRESS, "provider_postaladdress"); - roles.insert(PROVIDER_ICON, "provider_icon"); - roles.insert(PROVIDER_IMAGE, "provider_image"); + roles.insert(PROVIDER_CATEGORY, "providerCategory"); + roles.insert(PROVIDER_SHORTNAME, "providerShortName"); + roles.insert(PROVIDER_LONGNAME, "providerLongName"); + roles.insert(PROVIDER_SHORTDESCRIPTION, "providerShortDescription"); + roles.insert(PROVIDER_LONGDESCRIPTION, "providerLongDescription"); + roles.insert(PROVIDER_ADDRESS, "providerAddress"); + roles.insert(PROVIDER_ADDRESS_DOMAIN, "providerAddressDomain"); + roles.insert(PROVIDER_HOMEPAGE, "providerHomepage"); + roles.insert(PROVIDER_HOMEPAGE_BASE, "providerHomepageBase"); + roles.insert(PROVIDER_PHONE, "providerPhone"); + roles.insert(PROVIDER_PHONE_COST, "providerPhoneCost"); + roles.insert(PROVIDER_EMAIL, "providerEmail"); + roles.insert(PROVIDER_POSTALADDRESS, "providerPostalAddress"); + roles.insert(PROVIDER_ICON, "providerIcon"); + roles.insert(PROVIDER_IMAGE, "providerImage"); return roles; } @@ -290,3 +357,9 @@ ProviderNameFilterModel* HistoryModel::getNameFilterModel() { return &mNameFilterModel; } + + +HistoryModelSearchFilter* HistoryModel::getHistoryModelSearchFilter() +{ + return &mHistoryModelSearchFilter; +} diff --git a/src/qml/HistoryModel.h b/src/qml/HistoryModel.h index 27a6863..58eb0d1 100644 --- a/src/qml/HistoryModel.h +++ b/src/qml/HistoryModel.h @@ -6,6 +6,7 @@ #pragma once +#include "HistoryModelSearchFilter.h" #include "HistorySettings.h" #include "ProviderSettings.h" @@ -38,13 +39,15 @@ class ProviderNameFilterModel private: QPointer mHistorySettings; - QString mProviderAddressHost; + QPointer mProviderSettings; + + Provider mProvider; protected: bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; public: - ProviderNameFilterModel(HistorySettings* pHistorySettings); + ProviderNameFilterModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings); virtual ~ProviderNameFilterModel(); @@ -59,46 +62,56 @@ class HistoryModel Q_OBJECT Q_PROPERTY(HistoryProxyModel * filter READ getFilterModel CONSTANT) Q_PROPERTY(ProviderNameFilterModel * nameFilter READ getNameFilterModel CONSTANT) + Q_PROPERTY(HistoryModelSearchFilter * searchFilter READ getHistoryModelSearchFilter CONSTANT) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY fireEnabledChanged) QPointer mHistorySettings; QPointer mProviderSettings; HistoryProxyModel mFilterModel; ProviderNameFilterModel mNameFilterModel; - - enum HistoryRoles - { - SUBJECT = Qt::UserRole + 1, - PURPOSE, - DATETIME, - TERMSOFUSAGE, - REQUESTEDDATA, - PROVIDER_CATEGORY, - PROVIDER_SHORTNAME, - PROVIDER_LONGNAME, - PROVIDER_SHORTDESCRIPTION, - PROVIDER_LONGDESCRIPTION, - PROVIDER_ADDRESS, - PROVIDER_ADDRESS_DOMAIN, - PROVIDER_HOMEPAGE, - PROVIDER_HOMEPAGE_BASE, - PROVIDER_PHONE, - PROVIDER_EMAIL, - PROVIDER_POSTALADDRESS, - PROVIDER_ICON, - PROVIDER_IMAGE - }; + HistoryModelSearchFilter mHistoryModelSearchFilter; private: Provider determineProviderFor(const HistoryEntry& pHistoryEntry) const; + bool isEnabled() const; + void setEnabled(bool pEnabled); + private Q_SLOTS: void onHistoryEntriesChanged(); void onProvidersChanged(); + Q_SIGNALS: + void fireEnabledChanged(); + public: HistoryModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings, QObject* pParent = nullptr); virtual ~HistoryModel(); + enum HistoryRoles + { + SUBJECT = Qt::UserRole + 1, + PURPOSE, + DATETIME, + TERMSOFUSAGE, + REQUESTEDDATA, + PROVIDER_CATEGORY, + PROVIDER_SHORTNAME, + PROVIDER_LONGNAME, + PROVIDER_SHORTDESCRIPTION, + PROVIDER_LONGDESCRIPTION, + PROVIDER_ADDRESS, + PROVIDER_ADDRESS_DOMAIN, + PROVIDER_HOMEPAGE, + PROVIDER_HOMEPAGE_BASE, + PROVIDER_PHONE, + PROVIDER_PHONE_COST, + PROVIDER_EMAIL, + PROVIDER_POSTALADDRESS, + PROVIDER_ICON, + PROVIDER_IMAGE + }; + int rowCount(const QModelIndex& = QModelIndex()) const override; QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; QHash roleNames() const override; @@ -106,6 +119,7 @@ class HistoryModel Q_INVOKABLE HistoryProxyModel* getFilterModel(); Q_INVOKABLE ProviderNameFilterModel* getNameFilterModel(); + HistoryModelSearchFilter* getHistoryModelSearchFilter(); }; } /* namespace governikus */ diff --git a/src/qml/HistoryModelSearchFilter.cpp b/src/qml/HistoryModelSearchFilter.cpp new file mode 100644 index 0000000..f0915a2 --- /dev/null +++ b/src/qml/HistoryModelSearchFilter.cpp @@ -0,0 +1,44 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HistoryModelSearchFilter.h" + +#include "HistoryModel.h" + +#include + +using namespace governikus; + + +bool HistoryModelSearchFilter::filterAcceptsRow(int pSourceRow, const QModelIndex&) const +{ + if (mFilterString.isEmpty()) + { + return true; + } + + const HistoryModel* const dataSourceModel = qobject_cast(sourceModel()); + if (dataSourceModel == nullptr) + { + return false; + } + + const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0); + if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("MM/dd/yyyy")).contains(mFilterString, Qt::CaseInsensitive) + || dataSourceModel->data(modelIndex, HistoryModel::SUBJECT).toString().contains(mFilterString, Qt::CaseInsensitive) + || dataSourceModel->data(modelIndex, HistoryModel::PURPOSE).toString().contains(mFilterString, Qt::CaseInsensitive) + || dataSourceModel->data(modelIndex, HistoryModel::REQUESTEDDATA).toString().contains(mFilterString, Qt::CaseInsensitive)) + { + return true; + } + + return false; +} + + +void governikus::HistoryModelSearchFilter::setFilterString(const QString& pFilterString) +{ + mFilterString = pFilterString; + invalidateFilter(); +} diff --git a/src/qml/HistoryModelSearchFilter.h b/src/qml/HistoryModelSearchFilter.h new file mode 100644 index 0000000..5e7807a --- /dev/null +++ b/src/qml/HistoryModelSearchFilter.h @@ -0,0 +1,31 @@ +/*! + * \brief A filter to search the history model + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include + +namespace governikus +{ + +class HistoryModelSearchFilter + : public QSortFilterProxyModel +{ + Q_OBJECT + + private: + QString mFilterString; + + protected: + bool filterAcceptsRow(int pSourceRow, const QModelIndex&) const override; + + public: + Q_INVOKABLE void setFilterString(const QString& pFilterString); +}; + +} diff --git a/src/qml/NumberModel.cpp b/src/qml/NumberModel.cpp index 962b9dd..8ec1402 100644 --- a/src/qml/NumberModel.cpp +++ b/src/qml/NumberModel.cpp @@ -3,7 +3,8 @@ */ #include "NumberModel.h" -#include "ReturnCodeUtil.h" + +#include "ReaderManager.h" #include "context/ChangePinContext.h" #include "context/WorkflowContext.h" @@ -14,6 +15,10 @@ using namespace governikus; NumberModel::NumberModel(QObject* pParent) : QObject(pParent) { + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderPropertiesUpdated, this, &NumberModel::onReaderInfoChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &NumberModel::onReaderInfoChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &NumberModel::onReaderInfoChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &NumberModel::onReaderInfoChanged); } @@ -22,7 +27,7 @@ NumberModel::~NumberModel() } -void NumberModel::resetContext(QSharedPointer pContext) +void NumberModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; if (mContext) @@ -30,16 +35,16 @@ void NumberModel::resetContext(QSharedPointer pContext) connect(mContext.data(), &WorkflowContext::fireCanChanged, this, &NumberModel::fireCanChanged); connect(mContext.data(), &WorkflowContext::firePinChanged, this, &NumberModel::firePinChanged); - const auto changePinContext = mContext.dynamicCast(); + const auto changePinContext = mContext.objectCast(); if (changePinContext) { connect(changePinContext.data(), &ChangePinContext::fireNewPinChanged, this, &NumberModel::fireNewPinChanged); connect(changePinContext.data(), &ChangePinContext::firePukChanged, this, &NumberModel::firePukChanged); } - connect(mContext.data(), &ChangePinContext::fireCardConnectionChanged, this, &NumberModel::onCardConnectionChanged); - connect(mContext.data(), &ChangePinContext::fireReaderNameChanged, this, &NumberModel::fireRetryCounterChanged); - connect(mContext.data(), &ChangePinContext::fireLastPaceResultChanged, this, &NumberModel::fireInputErrorChanged); + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &NumberModel::onCardConnectionChanged); + connect(mContext.data(), &WorkflowContext::fireReaderNameChanged, this, &NumberModel::fireReaderInfoChanged); + connect(mContext.data(), &WorkflowContext::fireLastPaceResultChanged, this, &NumberModel::fireInputErrorChanged); } Q_EMIT fireCanChanged(); @@ -47,7 +52,16 @@ void NumberModel::resetContext(QSharedPointer pContext) Q_EMIT fireNewPinChanged(); Q_EMIT firePukChanged(); Q_EMIT fireInputErrorChanged(); - Q_EMIT fireRetryCounterChanged(); + Q_EMIT fireReaderInfoChanged(); +} + + +void NumberModel::continueWorkflow() +{ + if (mContext) + { + mContext->setStateApproved(); + } } @@ -83,7 +97,7 @@ void NumberModel::setPin(const QString& pPin) QString NumberModel::getNewPin() const { - const auto changePinContext = mContext.dynamicCast(); + const auto changePinContext = mContext.objectCast(); return changePinContext ? changePinContext->getNewPin() : QString(); } @@ -91,7 +105,7 @@ QString NumberModel::getNewPin() const void NumberModel::setNewPin(const QString& pNewPin) { - const auto changePinContext = mContext.dynamicCast(); + const auto changePinContext = mContext.objectCast(); if (changePinContext) { changePinContext->setNewPin(pNewPin); @@ -101,15 +115,14 @@ void NumberModel::setNewPin(const QString& pNewPin) QString NumberModel::getPuk() const { - const auto changePinContext = mContext.dynamicCast(); - + const auto changePinContext = mContext.objectCast(); return changePinContext ? changePinContext->getPuk() : QString(); } void NumberModel::setPuk(const QString& pPuk) { - const auto changePinContext = mContext.dynamicCast(); + const auto changePinContext = mContext.objectCast(); if (changePinContext) { changePinContext->setPuk(pPuk); @@ -119,13 +132,16 @@ void NumberModel::setPuk(const QString& pPuk) QString NumberModel::getInputError() const { - if (mContext.isNull() || mContext->getLastPaceResult() == ReturnCode::OK || mContext->getCardConnection().isNull()) + if (mContext.isNull() + || mContext->getLastPaceResult() == CardReturnCode::OK + || mContext->getLastPaceResult() == CardReturnCode::CANCELLATION_BY_USER + || mContext->getCardConnection().isNull()) { return QString(); } - ReturnCode paceResult = mContext->getLastPaceResult(); - if (paceResult == ReturnCode::PIN_INVALID) + CardReturnCode paceResult = mContext->getLastPaceResult(); + if (paceResult == CardReturnCode::INVALID_PIN) { int oldRetryCounter = mContext->getOldRetryCounter(); if (oldRetryCounter > 2) @@ -134,27 +150,27 @@ QString NumberModel::getInputError() const } if (oldRetryCounter == 2) { - return tr("You have entered a wrong PIN two times. " - "You have one try left before the PIN is blocked. " - "You have to enter your CAN first."); + return tr("You have entered the wrong PIN twice. " + "For a third attempt, you have to enter your six-digit card access number first. " + "You can find your card access number on the front of your ID card."); } if (oldRetryCounter == 1) { return tr("You have entered a wrong PIN three times. " "Your PIN is now blocked. " - "You have to enter your PUK now for unblocking."); + "You have to enter the PUK now for unblocking."); } } - if (paceResult == ReturnCode::CAN_INVALID) + if (paceResult == CardReturnCode::INVALID_CAN) { return tr("You have entered a wrong CAN, please try again."); } - if (paceResult == ReturnCode::PUK_INVALID) + if (paceResult == CardReturnCode::INVALID_PUK) { return tr("You have entered a wrong PUK. " "Please try again."); } - return ReturnCodeUtil::toMessage(paceResult); + return CardReturnCodeUtil::toGlobalStatus(paceResult).toErrorDescription(true); } @@ -163,9 +179,9 @@ void NumberModel::onCardConnectionChanged() Q_ASSERT(mContext); if (auto cardConnection = mContext->getCardConnection()) { - connect(cardConnection.data(), &CardConnection::fireReaderInfoChanged, this, &NumberModel::fireRetryCounterChanged); + connect(cardConnection.data(), &CardConnection::fireReaderInfoChanged, this, &NumberModel::fireReaderInfoChanged); } - Q_EMIT fireRetryCounterChanged(); + Q_EMIT fireReaderInfoChanged(); } @@ -180,3 +196,43 @@ int NumberModel::getRetryCounter() const return mContext->getCardConnection()->getReaderInfo().getRetryCounter(); } } + + +bool NumberModel::isExtendedLengthApdusUnsupported() const +{ + if (mContext && !mContext->getReaderName().isEmpty()) + { + ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()); + return readerInfo.getExtendedLengthApduSupportCode() == ExtendedLengthApduSupportCode::NOT_SUPPORTED; + } + return false; +} + + +bool NumberModel::isPinDeactivated() const +{ + if (mContext && !mContext->getReaderName().isEmpty()) + { + return ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).isPinDeactivated(); + } + return false; +} + + +bool NumberModel::isCardConnected() const +{ + if (mContext && !mContext->getReaderName().isEmpty()) + { + return ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).getCardType() != CardType::NONE; + } + return false; +} + + +void NumberModel::onReaderInfoChanged(const QString& pReaderName) +{ + if (mContext && pReaderName == mContext->getReaderName()) + { + Q_EMIT fireReaderInfoChanged(); + } +} diff --git a/src/qml/NumberModel.h b/src/qml/NumberModel.h index b2ebf52..502c040 100644 --- a/src/qml/NumberModel.h +++ b/src/qml/NumberModel.h @@ -24,7 +24,10 @@ class NumberModel Q_PROPERTY(QString newPin READ getNewPin WRITE setNewPin NOTIFY fireNewPinChanged) Q_PROPERTY(QString puk READ getPuk WRITE setPuk NOTIFY firePukChanged) Q_PROPERTY(QString inputError READ getInputError NOTIFY fireInputErrorChanged) - Q_PROPERTY(int retryCounter READ getRetryCounter NOTIFY fireRetryCounterChanged) + Q_PROPERTY(int retryCounter READ getRetryCounter NOTIFY fireReaderInfoChanged) + Q_PROPERTY(bool extendedLengthApdusUnsupported READ isExtendedLengthApdusUnsupported NOTIFY fireReaderInfoChanged) + Q_PROPERTY(bool pinDeactivated READ isPinDeactivated NOTIFY fireReaderInfoChanged) + Q_PROPERTY(bool cardConnected READ isCardConnected NOTIFY fireReaderInfoChanged) QSharedPointer mContext; @@ -35,7 +38,8 @@ class NumberModel NumberModel(QObject* pParent = nullptr); virtual ~NumberModel(); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); + Q_INVOKABLE void continueWorkflow(); QString getCan() const; void setCan(const QString& pCan); @@ -53,13 +57,22 @@ class NumberModel int getRetryCounter() const; + bool isExtendedLengthApdusUnsupported() const; + + bool isPinDeactivated() const; + + bool isCardConnected() const; + + private Q_SLOTS: + void onReaderInfoChanged(const QString& pReaderName); + Q_SIGNALS: void fireCanChanged(); void firePinChanged(); void fireNewPinChanged(); void firePukChanged(); void fireInputErrorChanged(); - void fireRetryCounterChanged(); + void fireReaderInfoChanged(); }; diff --git a/src/qml/ProviderCategoryFilterModel.cpp b/src/qml/ProviderCategoryFilterModel.cpp new file mode 100644 index 0000000..4e38552 --- /dev/null +++ b/src/qml/ProviderCategoryFilterModel.cpp @@ -0,0 +1,165 @@ +#include "ProviderCategoryFilterModel.h" + + +using namespace governikus; + + +static const QStringList CATEGORIES({"citizen", "insurance", "finance", "other"}); + + +QString ProviderCategoryFilterModel::getSearchString() const +{ + return mSearchString; +} + + +void ProviderCategoryFilterModel::updateSearchString(const QString& pSearchString) +{ + const QString& newSearchString = pSearchString.trimmed(); + if (mSearchString != newSearchString) + { + mSearchString = newSearchString; + invalidateFilter(); + Q_EMIT fireCriteriaChanged(); + } +} + + +QStringList ProviderCategoryFilterModel::getSelectedCategories() const +{ + return mSelectedCategories.toList(); +} + + +int ProviderCategoryFilterModel::getAdditionalResultCount() const +{ + int results = 0; + for (const QString& p : CATEGORIES) + { + results += matchesForExcludedCategory(p); + } + return results; +} + + +int ProviderCategoryFilterModel::matchesForExcludedCategory(const QString& pCategory) const +{ + if (mSearchString.isEmpty() || mSelectedCategories.isEmpty() || mSelectedCategories.contains(pCategory)) + { + return 0; + } + + QAbstractItemModel* const model = sourceModel(); + const int count = model->rowCount(); + int matchCount = 0; + for (int sourceRow = 0; sourceRow < count; ++sourceRow) + { + const QModelIndex idx = model->index(sourceRow, 0, QModelIndex()); + const QString dt = model->data(idx, Qt::DisplayRole).toString(); + if (!dt.contains(mSearchString, Qt::CaseInsensitive)) + { + continue; + } + + if (pCategory.toLower() == model->data(idx, ProviderModel::CATEGORY).toString().toLower()) + { + matchCount++; + } + } + + return matchCount; +} + + +bool ProviderCategoryFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const +{ + QAbstractItemModel* const model = sourceModel(); + Q_ASSERT(model != nullptr); + const QModelIndex idx = model->index(pSourceRow, 0, pSourceParent); + + if (!mSearchString.isEmpty()) + { + const QString dt = model->data(idx, Qt::DisplayRole).toString(); + if (!dt.contains(mSearchString, Qt::CaseInsensitive)) + { + return false; + } + } + + return mSelectedCategories.isEmpty() || mSelectedCategories.contains(QStringLiteral("all")) || + mSelectedCategories.contains(model->data(idx, ProviderModel::CATEGORY).toString().toLower()); +} + + +ProviderCategoryFilterModel::ProviderCategoryFilterModel(ProviderSettings* pSettings) : + mProviderModel(pSettings) +{ + setSourceModel(&mProviderModel); + + sort(0); + sortByCategoryFirst(false); + setSortCaseSensitivity(Qt::CaseInsensitive); +} + + +ProviderCategoryFilterModel::~ProviderCategoryFilterModel() +{ +} + + +void ProviderCategoryFilterModel::sortByCategoryFirst(bool pEnabled) +{ + setSortRole(pEnabled ? ProviderModel::SORT_ROLE : ProviderModel::SHORTNAME); +} + + +void ProviderCategoryFilterModel::setCategorySelection(const QString& pCategory) +{ + mSelectedCategories.clear(); + + if (!pCategory.isEmpty()) + { + mSelectedCategories.insert(pCategory.toLower()); + } + invalidateFilter(); + Q_EMIT fireCriteriaChanged(); +} + + +void ProviderCategoryFilterModel::updateCategorySelection(const QString& pCategory, bool pSelected) +{ + const int categoryCount = mSelectedCategories.count(); + if (pSelected) + { + mSelectedCategories.insert(pCategory.toLower()); + } + else + { + mSelectedCategories.remove(pCategory.toLower()); + } + + if (mSelectedCategories.count() != categoryCount) + { + invalidateFilter(); + Q_EMIT fireCriteriaChanged(); + } +} + + +void ProviderCategoryFilterModel::addAdditionalResultCategories() +{ + bool needUpdate = false; + for (const QString& p : CATEGORIES) + { + if (matchesForExcludedCategory(p) > 0) + { + needUpdate = true; + mSelectedCategories += p; + } + } + if (needUpdate) + { + invalidateFilter(); + Q_EMIT fireCriteriaChanged(); + } +} diff --git a/src/qml/ProviderCategoryFilterModel.h b/src/qml/ProviderCategoryFilterModel.h new file mode 100644 index 0000000..19255de --- /dev/null +++ b/src/qml/ProviderCategoryFilterModel.h @@ -0,0 +1,59 @@ +/*! + * \brief Model implementation for the providers. + * + * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "ProviderModel.h" +#include "ProviderSettings.h" + +#include +#include +#include + + +namespace governikus +{ + +class ProviderCategoryFilterModel + : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(QString searchString READ getSearchString WRITE updateSearchString NOTIFY fireCriteriaChanged) + Q_PROPERTY(QStringList categories READ getSelectedCategories NOTIFY fireCriteriaChanged) + Q_PROPERTY(int rowCount READ rowCount NOTIFY fireCriteriaChanged) + Q_PROPERTY(int additionalResultCount READ getAdditionalResultCount NOTIFY fireCriteriaChanged) + + private: + QString mSearchString; + QSet mSelectedCategories; + + ProviderModel mProviderModel; + + QString getSearchString() const; + void updateSearchString(const QString& pSearchString); + QStringList getSelectedCategories() const; + int getAdditionalResultCount() const; + int matchesForExcludedCategory(const QString& pCategory) const; + + protected: + bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; + + public: + ProviderCategoryFilterModel(ProviderSettings* pSettings); + virtual ~ProviderCategoryFilterModel(); + + Q_INVOKABLE void sortByCategoryFirst(bool pEnabled); + Q_INVOKABLE void setCategorySelection(const QString& pCategory); + Q_INVOKABLE void updateCategorySelection(const QString& pCategory, bool pSelected); + Q_INVOKABLE void addAdditionalResultCategories(); + + Q_SIGNALS: + void fireCriteriaChanged(); + +}; + + +} /* namespace governikus */ diff --git a/src/qml/ProviderModel.cpp b/src/qml/ProviderModel.cpp index 054688d..f9a8d4b 100644 --- a/src/qml/ProviderModel.cpp +++ b/src/qml/ProviderModel.cpp @@ -1,134 +1,29 @@ #include "ProviderModel.h" + using namespace governikus; -bool ProviderCategoryFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const -{ - QAbstractItemModel* const model = sourceModel(); - Q_ASSERT(model != nullptr); - const QModelIndex idx = model->index(pSourceRow, 0, pSourceParent); +static const QStringList CATEGORIES({"citizen", "insurance", "finance", "other"}); - if (!mSearchString.isEmpty()) + +QString ProviderModel::createCostString(double pCostsPerMinute, double pCostsPerCall) +{ + if (pCostsPerMinute > 0.0) { - const QString dt = model->data(idx, Qt::DisplayRole).toString().toLower(); - if (!dt.contains(mSearchString)) - { - return false; - } + return tr("%1/min").arg(createAmountString(pCostsPerMinute)); } - - return mSelectedCategories.isEmpty() || - mSelectedCategories.contains(model->data(idx, ProviderModel::CATEGORY).toString().toLower()); -} - - -ProviderCategoryFilterModel::ProviderCategoryFilterModel() -{ -} - - -ProviderCategoryFilterModel::~ProviderCategoryFilterModel() -{ -} - - -void ProviderCategoryFilterModel::updateSearchString(const QString& pSearchString) -{ - const QString lowerSearchString = pSearchString.toLower(); - if (mSearchString != lowerSearchString) + if (pCostsPerCall > 0.0) { - mSearchString = lowerSearchString; - - invalidateFilter(); - Q_EMIT fireCriteriaChanged(); + return tr("%1/call").arg(createAmountString(pCostsPerCall)); } + return QString(); } -void ProviderCategoryFilterModel::updateCategorySelection(const QString& pCategory, bool pSelected) -{ - const int categoryCount = mSelectedCategories.count(); - if (pSelected) - { - mSelectedCategories.insert(pCategory.toLower()); - } - else - { - mSelectedCategories.remove(pCategory.toLower()); - } - - if (mSelectedCategories.count() != categoryCount) - { - invalidateFilter(); - - fireCriteriaChanged(); - } -} - - -int ProviderCategoryFilterModel::matchesForExcludedCategory(const QString& pCategory) const -{ - if (mSearchString.isEmpty() || mSelectedCategories.isEmpty() || mSelectedCategories.contains(pCategory)) - { - return 0; - } - - QAbstractItemModel* const model = sourceModel(); - Q_ASSERT(model != nullptr); - const int count = model->rowCount(); - int matchCount = 0; - for (int sourceRow = 0; sourceRow < count; ++sourceRow) - { - const QModelIndex idx = model->index(sourceRow, 0, QModelIndex()); - if (!mSearchString.isEmpty()) - { - const QString dt = model->data(idx, Qt::DisplayRole).toString().toLower(); - if (!dt.contains(mSearchString)) - { - continue; - } - } - - if (pCategory.toLower() == model->data(idx, ProviderModel::CATEGORY).toString().toLower()) - { - matchCount++; - } - } - - return matchCount; -} - - -bool ProviderCategoryFilterModel::isSelected(const QString& pCategory) const -{ - return mSelectedCategories.contains(pCategory); -} - - -ProviderModel::ProviderModel(ProviderSettings* pSettings, QObject* pParent) - : QAbstractListModel(pParent) - , mSettings(pSettings) - , mFilterModel() - , mSortModel() - , mCategoryFilterModel() -{ - mFilterModel.setSourceModel(this); - mFilterModel.sort(0); - mFilterModel.setFilterRole(CATEGORY); - - mSortModel.setSourceModel(this); - mSortModel.sort(0); - mSortModel.setSortRole(SORT_ROLE); - - mCategoryFilterModel.setSourceModel(this); - - connect(mSettings, &ProviderSettings::fireProvidersChanged, this, &ProviderModel::onProvidersChanged); -} - - -ProviderModel::~ProviderModel() +QString ProviderModel::createAmountString(double pCents) { + return pCents > 100 ? tr("%1 EUR").arg(pCents / 100.0) : tr("%1 ct").arg(pCents); } @@ -139,6 +34,19 @@ void ProviderModel::onProvidersChanged() } +ProviderModel::ProviderModel(ProviderSettings* pSettings, QObject* pParent) + : QAbstractListModel(pParent) + , mSettings(pSettings) +{ + connect(mSettings, &ProviderSettings::fireSettingsChanged, this, &ProviderModel::onProvidersChanged); +} + + +ProviderModel::~ProviderModel() +{ +} + + int ProviderModel::rowCount(const QModelIndex&) const { return mSettings->getProviders().size(); @@ -153,8 +61,8 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const if (pRole == Qt::DisplayRole) { - auto value = provider.getLongName(); - return QVariant(value.isEmpty() ? provider.getShortName() : value); + auto longName = provider.getLongName(); + return longName.isEmpty() ? provider.getShortName().toString() : longName.toString(); } if (pRole == CATEGORY) @@ -163,19 +71,19 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const } if (pRole == SHORTNAME) { - return QVariant(provider.getShortName()); + return provider.getShortName().toString(); } if (pRole == LONGNAME) { - return QVariant(provider.getLongName()); + return provider.getLongName().toString(); } if (pRole == SHORTDESCRIPTION) { - return QVariant(provider.getShortDescription()); + return provider.getShortDescription().toString(); } if (pRole == LONGDESCRIPTION) { - return QVariant(provider.getLongDescription()); + return provider.getLongDescription().toString(); } if (pRole == ADDRESS) { @@ -197,6 +105,11 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const { return provider.getPhone(); } + if (pRole == PHONE_COST) + { + const auto& cost = mSettings->getCallCost(provider); + return createCostString(cost); + } if (pRole == EMAIL) { return provider.getEMail(); @@ -228,38 +141,40 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const QHash ProviderModel::roleNames() const { QHash roles = QAbstractListModel::roleNames(); - roles.insert(CATEGORY, "category"); - roles.insert(SHORTNAME, "shortName"); - roles.insert(LONGNAME, "longName"); - roles.insert(SHORTDESCRIPTION, "shortDescription"); - roles.insert(LONGDESCRIPTION, "longDescription"); - roles.insert(ADDRESS, "address"); - roles.insert(ADDRESS_DOMAIN, "addressDomain"); - roles.insert(HOMEPAGE, "homepage"); - roles.insert(HOMEPAGE_BASE, "homepagebase"); - roles.insert(PHONE, "phone"); - roles.insert(EMAIL, "email"); - roles.insert(POSTALADDRESS, "postalAddress"); - roles.insert(ICON, "icon"); - roles.insert(IMAGE, "image"); + roles.insert(CATEGORY, "providerCategory"); + roles.insert(SHORTNAME, "providerShortName"); + roles.insert(LONGNAME, "providerLongName"); + roles.insert(SHORTDESCRIPTION, "providerShortDescription"); + roles.insert(LONGDESCRIPTION, "providerLongDescription"); + roles.insert(ADDRESS, "providerAddress"); + roles.insert(ADDRESS_DOMAIN, "providerAddressDomain"); + roles.insert(HOMEPAGE, "providerHomepage"); + roles.insert(HOMEPAGE_BASE, "providerHomepageBase"); + roles.insert(PHONE, "providerPhone"); + roles.insert(PHONE_COST, "providerPhoneCost"); + roles.insert(EMAIL, "providerEmail"); + roles.insert(POSTALADDRESS, "providerPostalAddress"); + roles.insert(ICON, "providerIcon"); + roles.insert(IMAGE, "providerImage"); return roles; } -QSortFilterProxyModel* ProviderModel::getFilterModel() +QString ProviderModel::createCostString(const CallCost& pCosts) { - return &mFilterModel; -} - - -QSortFilterProxyModel* ProviderModel::getSortModel() -{ - return &mSortModel; -} - - -ProviderCategoryFilterModel* ProviderModel::getCategoryFilterModel() -{ - return &mCategoryFilterModel; + if (pCosts.isNull()) + { + return QString(); + } + + QString msg; + if (pCosts.getFreeSeconds() > 0) + { + msg += tr("%1 seconds free, afterwards ").arg(pCosts.getFreeSeconds()); + } + msg += tr("landline costs %1; ").arg(createCostString(pCosts.getLandlineCentsPerMinute(), pCosts.getLandlineCentsPerCall())); + const auto mobileCosts = createCostString(pCosts.getMobileCentsPerMinute(), pCosts.getMobileCentsPerCall()); + msg += mobileCosts.isEmpty() ? tr("mobile costs may vary.") : tr("mobile costs %1").arg(mobileCosts); + return msg; } diff --git a/src/qml/ProviderModel.h b/src/qml/ProviderModel.h index 63c0f66..566ccca 100644 --- a/src/qml/ProviderModel.h +++ b/src/qml/ProviderModel.h @@ -10,57 +10,25 @@ #include #include -#include -#include -#include + + +class test_ProviderModel; namespace governikus { -class ProviderCategoryFilterModel - : public QSortFilterProxyModel -{ - Q_OBJECT - - private: - QString mSearchString; - - QSet mSelectedCategories; - - protected: - bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; - - public: - ProviderCategoryFilterModel(); - - virtual ~ProviderCategoryFilterModel(); - - Q_INVOKABLE void updateSearchString(const QString& pSearchString); - - Q_INVOKABLE void updateCategorySelection(const QString& pCategory, bool pSelected); - - Q_INVOKABLE int matchesForExcludedCategory(const QString& pCategory) const; - - Q_INVOKABLE bool isSelected(const QString& pCategory) const; - - Q_SIGNALS: - void fireCriteriaChanged(); - -}; - class ProviderModel : public QAbstractListModel { + friend class::test_ProviderModel; + Q_OBJECT - Q_PROPERTY(QSortFilterProxyModel * filter READ getFilterModel CONSTANT) - Q_PROPERTY(QSortFilterProxyModel * sortModel READ getSortModel CONSTANT) - Q_PROPERTY(ProviderCategoryFilterModel * categoryFilter READ getCategoryFilterModel CONSTANT) QPointer mSettings; - QSortFilterProxyModel mFilterModel; - QSortFilterProxyModel mSortModel; - ProviderCategoryFilterModel mCategoryFilterModel; + + static QString createCostString(double pCostsPerMinute, double pCostsPerCall); + static QString createAmountString(double pCents); private Q_SLOTS: void onProvidersChanged(); @@ -78,6 +46,7 @@ class ProviderModel HOMEPAGE, HOMEPAGE_BASE, PHONE, + PHONE_COST, EMAIL, POSTALADDRESS, ICON, @@ -92,9 +61,7 @@ class ProviderModel QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; QHash roleNames() const override; - Q_INVOKABLE QSortFilterProxyModel* getFilterModel(); - Q_INVOKABLE QSortFilterProxyModel* getSortModel(); - Q_INVOKABLE ProviderCategoryFilterModel* getCategoryFilterModel(); + static QString createCostString(const CallCost& pCosts); }; diff --git a/src/qml/ShareUtil.h b/src/qml/QmlExtension.h similarity index 51% rename from src/qml/ShareUtil.h rename to src/qml/QmlExtension.h index d88c998..61129f9 100644 --- a/src/qml/ShareUtil.h +++ b/src/qml/QmlExtension.h @@ -12,13 +12,17 @@ namespace governikus { -class ShareUtil +class QmlExtension : public QObject { Q_OBJECT public: + Q_INVOKABLE void showSettings(const QString& pAction); Q_INVOKABLE void shareText(const QString& pText, const QString& pChooserTitle); + Q_INVOKABLE void showFeedback(const QString& pMessage); + Q_INVOKABLE bool exportHistory(const QString& pPdfUrl) const; + Q_INVOKABLE void mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg); }; } diff --git a/src/qml/QmlExtension_android.cpp b/src/qml/QmlExtension_android.cpp new file mode 100644 index 0000000..9680bba --- /dev/null +++ b/src/qml/QmlExtension_android.cpp @@ -0,0 +1,189 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "QmlExtension.h" + +#include "LogHandler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + + +using namespace governikus; + +void QmlExtension::showSettings(const QString& pAction) +{ + QAndroidJniEnvironment env; + + QAndroidJniObject jAction = QAndroidJniObject::fromString(pAction); + QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", jAction.object()); + jint flag = QAndroidJniObject::getStaticField( + "android/content/Intent", + "FLAG_ACTIVITY_NEW_TASK"); + intent.callObjectMethod("setFlags", "(I)V", flag); + + if (intent.isValid()) + { + qCCritical(qml) << "Call action:" << pAction; + QtAndroid::startActivity(intent, 0); + } + + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Cannot call an action as activity:" << pAction; + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + + +void QmlExtension::shareText(const QString& pText, const QString& pChooserTitle) +{ + QAndroidJniEnvironment env; + QAndroidJniObject javaActivity(QtAndroid::androidActivity()); + if (javaActivity == nullptr) + { + qCCritical(qml) << "Cannot determine android activity"; + return; + } + + QAndroidJniObject jText = QAndroidJniObject::fromString(pText); + QAndroidJniObject jTitle = QAndroidJniObject::fromString(pChooserTitle); + QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/ShareUtil", + "shareText", + "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V", + javaActivity.object(), + jText.object(), + jTitle.object()); + + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Cannot call ShareUtil.shareText()"; + env->ExceptionDescribe(); + env->ExceptionClear(); + return; + } +} + + +void QmlExtension::showFeedback(const QString& pMessage) +{ + QtAndroid::runOnAndroidThread([pMessage] { + const QAndroidJniObject javaString = QAndroidJniObject::fromString(pMessage); + // Using the appcontext is essential since it holds the default application colours + const QAndroidJniObject androidAppContext = QtAndroid::androidActivity().callObjectMethod( + "getApplicationContext", + "()Landroid/content/Context;"); + QAndroidJniObject toast = QAndroidJniObject::callStaticObjectMethod( + "android/widget/Toast", + "makeText", + "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", + androidAppContext.object(), + javaString.object(), + jint(1)); + toast.callMethod("show"); + }); +} + + +/* + * Calling + * QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).last() + * does the same but we don't want to rely on Qt internals, so we do it on our own. + */ +QString getPublicLogFileName(QAndroidJniEnvironment& env, const QAndroidJniObject& javaActivity) +{ + const auto jEmptyString = QAndroidJniObject::fromString(QLatin1String("")); + const auto& jExternalFilesDir = javaActivity.callObjectMethod("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;", jEmptyString.object()); + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Exception determining externalFilesDir"; + env->ExceptionDescribe(); + env->ExceptionClear(); + return QString(); + } + if (jExternalFilesDir == nullptr) + { + qCCritical(qml) << "Cannot determine externalFilesDir"; + return QString(); + } + + const auto& jExternalFilesDirPath = jExternalFilesDir.callObjectMethod("getAbsolutePath", "()Ljava/lang/String;"); + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Exception determining externalFilesDir absolute path"; + env->ExceptionDescribe(); + env->ExceptionClear(); + return QString(); + } + if (jExternalFilesDirPath == nullptr) + { + qCCritical(qml) << "Cannot determine externalFilesDir absolute path"; + return QString(); + } + + const auto nowAsISO = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd'T'HH:mm:ss-t")); + return QStringLiteral("%1/AusweisApp2-%2.log").arg(jExternalFilesDirPath.toString(), nowAsISO); +} + + +void QmlExtension::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) +{ + QAndroidJniEnvironment env; + QAndroidJniObject javaActivity(QtAndroid::androidActivity()); + if (javaActivity == nullptr) + { + qCCritical(qml) << "Cannot determine android activity"; + return; + } + + const auto& jEmail = QAndroidJniObject::fromString(pEmail); + const auto& jSubject = QAndroidJniObject::fromString(pSubject); + const auto& jMsg = QAndroidJniObject::fromString(pMsg); + const auto& jChooserTitle = QAndroidJniObject::fromString(tr("Send application log per email...")); + const auto& publicLogFile = getPublicLogFileName(env, javaActivity); + const auto& jPublicLogFile = QAndroidJniObject::fromString(publicLogFile); + + qCDebug(qml) << "Copy log file to" << publicLogFile; + if (!LogHandler::getInstance().copy(publicLogFile)) + { + qCCritical(qml) << "Cannot copy log file to" << publicLogFile; + return; + } + + QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/ShareUtil", + "shareLog", + "(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + javaActivity.object(), + jEmail.object(), + jSubject.object(), + jMsg.object(), + jPublicLogFile.object(), + jChooserTitle.object()); + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Exception calling ShareUtil.shareLog()"; + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + + +bool QmlExtension::exportHistory(const QString&) const +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; + return false; +} + + +#include "moc_QmlExtension.cpp" diff --git a/src/qml/QmlExtension_generic.cpp b/src/qml/QmlExtension_generic.cpp new file mode 100644 index 0000000..c859138 --- /dev/null +++ b/src/qml/QmlExtension_generic.cpp @@ -0,0 +1,55 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "QmlExtension.h" + +#ifndef Q_OS_WINRT +#include "PdfCreator.h" +#endif + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(qml) + +using namespace governikus; + + +void QmlExtension::showSettings(const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +void QmlExtension::shareText(const QString&, const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +void QmlExtension::showFeedback(const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +void QmlExtension::mailLog(const QString&, const QString&, const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +bool QmlExtension::exportHistory(const QString& pPdfUrl) const +{ +#ifdef Q_OS_WINRT + return false; + +#else + return PdfExport::exportHistory(QUrl(pPdfUrl).toLocalFile()); + +#endif +} + + +#include "moc_QmlExtension.cpp" diff --git a/src/qml/ShareUtil_ios.mm b/src/qml/QmlExtension_ios.mm similarity index 55% rename from src/qml/ShareUtil_ios.mm rename to src/qml/QmlExtension_ios.mm index 4eb78bf..2426d55 100644 --- a/src/qml/ShareUtil_ios.mm +++ b/src/qml/QmlExtension_ios.mm @@ -2,15 +2,23 @@ * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG */ -#include "ShareUtil.h" +#include "QmlExtension.h" +#include #import +Q_DECLARE_LOGGING_CATEGORY(qml) using namespace governikus; -void ShareUtil::shareText(const QString& pText, const QString& pChooserTitle) +void QmlExtension::showSettings(const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +void QmlExtension::shareText(const QString& pText, const QString& pChooserTitle) { Q_UNUSED(pChooserTitle); NSMutableArray* shareItemArray = [NSMutableArray new]; @@ -25,4 +33,23 @@ void ShareUtil::shareText(const QString& pText, const QString& pChooserTitle) } -#include "moc_ShareUtil.cpp" +void QmlExtension::mailLog(const QString&, const QString&, const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +void QmlExtension::showFeedback(const QString&) +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; +} + + +bool QmlExtension::exportHistory(const QString&) const +{ + qCWarning(qml) << "NOT IMPLEMENTED YET"; + return false; +} + + +#include "moc_QmlExtension.cpp" diff --git a/src/qml/SelfAuthenticationModel.cpp b/src/qml/SelfAuthenticationModel.cpp index cedb186..eceb8d6 100644 --- a/src/qml/SelfAuthenticationModel.cpp +++ b/src/qml/SelfAuthenticationModel.cpp @@ -20,29 +20,29 @@ void SelfAuthenticationModel::onSelfAuthenticationDataChanged() auto selfAuthenticationData = mContext->getSelfAuthenticationData(); if (!selfAuthenticationData->getValue(SelfAuthData::FamilyNames).isNull()) { - mData.append(QPair(tr("Family name"), selfAuthenticationData->getValue(SelfAuthData::FamilyNames))); + mData += QPair(tr("Family name"), selfAuthenticationData->getValue(SelfAuthData::FamilyNames)); } if (!selfAuthenticationData->getValue(SelfAuthData::BirthName).isNull()) { - mData.append(QPair(tr("Birth name"), selfAuthenticationData->getValue(SelfAuthData::BirthName))); + mData += QPair(tr("Birth name"), selfAuthenticationData->getValue(SelfAuthData::BirthName)); } if (!selfAuthenticationData->getValue(SelfAuthData::GivenNames).isNull()) { - mData.append(QPair(tr("Given name(s)"), selfAuthenticationData->getValue(SelfAuthData::GivenNames))); + mData += QPair(tr("Given name(s)"), selfAuthenticationData->getValue(SelfAuthData::GivenNames)); } if (!selfAuthenticationData->getValue(SelfAuthData::AcademicTitle).isNull()) { - mData.append(QPair(tr("Doctoral degree"), selfAuthenticationData->getValue(SelfAuthData::AcademicTitle))); + mData += QPair(tr("Doctoral degree"), selfAuthenticationData->getValue(SelfAuthData::AcademicTitle)); } if (!selfAuthenticationData->getValue(SelfAuthData::DateOfBirth).isNull()) { QDateTime dateTime = QDateTime::fromString(selfAuthenticationData->getValue(SelfAuthData::DateOfBirth), QStringLiteral("yyyy-MM-dd+hh:mm")); - auto dateString = dateTime.toString(tr("dd.MM.yyyy")); - mData.append(QPair(tr("Date of birth"), dateString)); + auto dateString = dateTime.toString(tr("MM/dd/yyyy")); + mData += QPair(tr("Date of birth"), dateString); } if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfBirth).isNull()) { - mData.append(QPair(tr("Place of birth"), selfAuthenticationData->getValue(SelfAuthData::PlaceOfBirth))); + mData += QPair(tr("Place of birth"), selfAuthenticationData->getValue(SelfAuthData::PlaceOfBirth)); } QString address; @@ -67,25 +67,25 @@ void SelfAuthenticationModel::onSelfAuthenticationDataChanged() } if (!address.isNull()) { - mData.append(QPair(tr("Address"), address)); + mData += QPair(tr("Address"), address); } auto documentType = selfAuthenticationData->getValue(SelfAuthData::DocumentType); if (!documentType.isNull()) { - mData.append(QPair(tr("Document type"), documentType)); + mData += QPair(tr("Document type"), documentType); } if (!selfAuthenticationData->getValue(SelfAuthData::Nationality).isNull()) { - mData.append(QPair(tr("Nationality"), selfAuthenticationData->getValue(SelfAuthData::Nationality))); + mData += QPair(tr("Nationality"), selfAuthenticationData->getValue(SelfAuthData::Nationality)); } if (!selfAuthenticationData->getValue(SelfAuthData::ArtisticName).isNull()) { - mData.append(QPair(tr("Religious / artistic name"), selfAuthenticationData->getValue(SelfAuthData::ArtisticName))); + mData += QPair(tr("Religious / artistic name"), selfAuthenticationData->getValue(SelfAuthData::ArtisticName)); } if (!selfAuthenticationData->getValue(SelfAuthData::IssuingState).isNull()) { - mData.append(QPair(tr("Issuing country"), selfAuthenticationData->getValue(SelfAuthData::IssuingState))); + mData += QPair(tr("Issuing country"), selfAuthenticationData->getValue(SelfAuthData::IssuingState)); } // Show "Residence Permit" for eAT- and Test-Cards only @@ -97,7 +97,7 @@ void SelfAuthenticationModel::onSelfAuthenticationDataChanged() documentType == QLatin1String("AF") || documentType == QLatin1String("TA"))) { - mData.append(QPair(tr("Residence permit I"), selfAuthenticationData->getValue(SelfAuthData::ResidencePermitI))); + mData += QPair(tr("Residence permit I"), selfAuthenticationData->getValue(SelfAuthData::ResidencePermitI)); } } @@ -113,7 +113,7 @@ SelfAuthenticationModel::SelfAuthenticationModel(QObject* pParent) } -void SelfAuthenticationModel::resetContext(QSharedPointer pContext) +void SelfAuthenticationModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; if (mContext) @@ -130,15 +130,6 @@ void SelfAuthenticationModel::startWorkflow() } -void SelfAuthenticationModel::continueWorkflow() -{ - if (mContext) - { - mContext->setStateApproved(); - } -} - - void SelfAuthenticationModel::cancelWorkflow() { if (mContext) diff --git a/src/qml/SelfAuthenticationModel.h b/src/qml/SelfAuthenticationModel.h index ba27313..929a61d 100644 --- a/src/qml/SelfAuthenticationModel.h +++ b/src/qml/SelfAuthenticationModel.h @@ -36,10 +36,9 @@ class SelfAuthenticationModel public: SelfAuthenticationModel(QObject* pParent = nullptr); - void resetContext(QSharedPointer pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); Q_INVOKABLE void startWorkflow(); - Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void cancelWorkflow(); Q_INVOKABLE bool isBasicReader(); diff --git a/src/qml/SettingsModel.cpp b/src/qml/SettingsModel.cpp index 4223047..6a9718c 100644 --- a/src/qml/SettingsModel.cpp +++ b/src/qml/SettingsModel.cpp @@ -19,8 +19,14 @@ bool SettingsModel::isDeveloperMode() const void SettingsModel::setDeveloperMode(bool pEnable) { + if (isDeveloperMode() == pEnable) + { + return; + } + AppSettings::getInstance().getGeneralSettings().setDeveloperMode(pEnable); AppSettings::getInstance().getGeneralSettings().save(); + Q_EMIT fireDeveloperModeChanged(); } @@ -32,6 +38,12 @@ bool SettingsModel::useSelfauthenticationTestUri() const void SettingsModel::setUseSelfauthenticationTestUri(bool pUse) { + if (useSelfauthenticationTestUri() == pUse) + { + return; + } + AppSettings::getInstance().getGeneralSettings().setUseSelfauthenticationTestUri(pUse); AppSettings::getInstance().getGeneralSettings().save(); + Q_EMIT fireUseSelfauthenticationTestUriChanged(); } diff --git a/src/qml/SettingsModel.h b/src/qml/SettingsModel.h index 1b36b25..c626d45 100644 --- a/src/qml/SettingsModel.h +++ b/src/qml/SettingsModel.h @@ -16,8 +16,8 @@ class SettingsModel : public QObject { Q_OBJECT - Q_PROPERTY(bool developerMode READ isDeveloperMode WRITE setDeveloperMode) - Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri) + Q_PROPERTY(bool developerMode READ isDeveloperMode WRITE setDeveloperMode NOTIFY fireDeveloperModeChanged) + Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireUseSelfauthenticationTestUriChanged) public: bool isDeveloperMode() const; @@ -25,6 +25,10 @@ class SettingsModel bool useSelfauthenticationTestUri() const; void setUseSelfauthenticationTestUri(bool pUse); + + Q_SIGNALS: + void fireDeveloperModeChanged(); + void fireUseSelfauthenticationTestUriChanged(); }; } /* namespace governikus */ diff --git a/src/qml/ShareUtil.java b/src/qml/ShareUtil.java index 48601b2..3e426d3 100644 --- a/src/qml/ShareUtil.java +++ b/src/qml/ShareUtil.java @@ -1,12 +1,24 @@ package com.governikus.ausweisapp2; -import android.content.Context; -import android.content.Intent; +import android.Manifest; +import android.app.Activity; +import android.content.*; +import android.net.Uri; +import android.os.Environment; +import android.util.Log; + +import java.io.*; +import java.nio.channels.FileChannel; +import java.text.*; +import java.util.*; public class ShareUtil { - public static void shareText(Context ctx, String text, String chooserTitle) + private static final String TAG = "AusweisApp2"; + + + public static void shareText(Context ctx, final String text, final String chooserTitle) { Intent shareData = new Intent(); shareData.setType("text/plain"); @@ -16,4 +28,26 @@ public class ShareUtil } + public static void shareLog(Activity activity, final String email, final String subject, final String msg, final String logFilePath, final String chooserTitle) + { + try + { + File logFile = new File(logFilePath); + + Intent shareData = new Intent(); + shareData.setType("message/rfc822"); + shareData.setAction(Intent.ACTION_SEND); + shareData.putExtra(Intent.EXTRA_EMAIL, new String[] {email}); + shareData.putExtra(Intent.EXTRA_SUBJECT, subject); + shareData.putExtra(Intent.EXTRA_TEXT, msg); + shareData.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(logFilePath))); + activity.startActivity(Intent.createChooser(shareData, chooserTitle)); + } + catch (Exception e) + { + Log.e(TAG, "Error sharing log file", e); + } + } + + } diff --git a/src/qml/ShareUtil_android.cpp b/src/qml/ShareUtil_android.cpp deleted file mode 100644 index 73d6f13..0000000 --- a/src/qml/ShareUtil_android.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "ShareUtil.h" - -#include -#include -#include -#include -#include - - -using namespace governikus; - - -void ShareUtil::shareText(const QString& pText, const QString& pChooserTitle) -{ - QAndroidJniEnvironment env; - QAndroidJniObject javaActivity(QtAndroid::androidActivity()); - if (env->ExceptionCheck()) - { - env->ExceptionClear(); - return; - } - - if (javaActivity == nullptr) - { - return; - } - - QAndroidJniObject jText = QAndroidJniObject::fromString(pText); - QAndroidJniObject jTitle = QAndroidJniObject::fromString(pChooserTitle); - QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/ShareUtil", - "shareText", - "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V", - javaActivity.object(), - jText.object(), - jTitle.object()); - if (env->ExceptionCheck()) - { - env->ExceptionClear(); - return; - } -} - - -#include "moc_ShareUtil.cpp" diff --git a/src/qml/ShareUtil_generic.cpp b/src/qml/ShareUtil_generic.cpp deleted file mode 100644 index 29601c6..0000000 --- a/src/qml/ShareUtil_generic.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "ShareUtil.h" - -#include - - -using namespace governikus; - - -void ShareUtil::shareText(const QString&, const QString&) -{ - qWarning() << "NOT IMPLEMENTED YET"; -} - - -#include "moc_ShareUtil.cpp" diff --git a/src/qml/StatusBarUtil.cpp b/src/qml/StatusBarUtil.cpp index 4bdb9d1..8058bff 100644 --- a/src/qml/StatusBarUtil.cpp +++ b/src/qml/StatusBarUtil.cpp @@ -5,44 +5,63 @@ */ #include "StatusBarUtil.h" +#include #include #include #ifdef Q_OS_ANDROID -#include -#include -#include + #include + #include + #include + #define FLAG_TRANSLUCENT_STATUS 0x04000000 + #define FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 0x80000000 + #define HSV_VALUE_REDUCTION (255 * 20 / 100) #endif + + using namespace governikus; + +bool StatusBarUtil::catchJavaExceptions() const +{ +#ifdef Q_OS_ANDROID + QAndroidJniEnvironment env; + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + qWarning() << "Exception occurred while setting status bar color"; + return true; + } +#endif + return false; +} + + void StatusBarUtil::setStatusBarColor(const QString& pColor) { #ifdef Q_OS_ANDROID - QAndroidJniEnvironment env; - QAndroidJniObject javaActivity(QtAndroid::androidActivity()); - if (env->ExceptionCheck()) + if (QtAndroid::androidSdkVersion() < 21) { - env->ExceptionClear(); - qWarning() << "Exception occurred while acquiring activity"; return; } - if (javaActivity == nullptr) - { - qWarning() << "Failed to acquire activity"; - return; - } - QAndroidJniObject jColorName = QAndroidJniObject::fromString(pColor); - QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/StatusBarUtil", - "setStatusBarColor", - "(Landroid/app/Activity;Ljava/lang/String;)V", - javaActivity.object(), - jColorName.object()); - if (env->ExceptionCheck()) - { - env->ExceptionClear(); - qWarning() << "Exception occurred while setting color"; - return; - } + QColor color(pColor); + int newValue = color.value() >= HSV_VALUE_REDUCTION ? color.value() - HSV_VALUE_REDUCTION : 0; + color.setHsv(color.hue(), color.saturation(), newValue); + + QtAndroid::runOnAndroidThread([ = ](){ + QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;"); + if (catchJavaExceptions()) + { + return; + } + + window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS); + window.callMethod("setStatusBarColor", "(I)V", color.rgba()); + catchJavaExceptions(); + }); + #else Q_UNUSED(pColor) #endif diff --git a/src/qml/StatusBarUtil.h b/src/qml/StatusBarUtil.h index 6253384..16524ff 100644 --- a/src/qml/StatusBarUtil.h +++ b/src/qml/StatusBarUtil.h @@ -17,6 +17,9 @@ class StatusBarUtil { Q_OBJECT + private: + bool catchJavaExceptions() const; + public: Q_INVOKABLE void setStatusBarColor(const QString& pColor); }; diff --git a/src/qml/StatusBarUtil.java b/src/qml/StatusBarUtil.java deleted file mode 100644 index 478fd75..0000000 --- a/src/qml/StatusBarUtil.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.governikus.ausweisapp2; - -import android.app.Activity; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; -import android.util.Log; -import android.view.Window; -import android.view.WindowManager.LayoutParams; -import com.governikus.ausweisapp2.R; - -public class StatusBarUtil -{ - public static void setStatusBarColor(final Activity activity, final String color) - { - activity.runOnUiThread(new Runnable(){ - @Override - public void run(){ - if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) - { - Window window = activity.getWindow(); - window.clearFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS); - window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - int colorValue; - if (color.equals("CITIZEN")) - { - colorValue = R.color.statusbar_citizen; - } - else if (color.equals("INSURANCE")) - { - colorValue = R.color.statusbar_insurance; - } - else if (color.equals("FINANCE")) - { - colorValue = R.color.statusbar_finance; - } - else if (color.equals("OTHER")) - { - colorValue = R.color.statusbar_other; - } - else - { - colorValue = R.color.statusbar_default; - } - window.setStatusBarColor(activity.getResources().getColor(colorValue)); - } - } - }); - } - - -} diff --git a/src/qml/UIPlugInQml.cpp b/src/qml/UIPlugInQml.cpp index d9f56c8..25fdf54 100644 --- a/src/qml/UIPlugInQml.cpp +++ b/src/qml/UIPlugInQml.cpp @@ -2,11 +2,6 @@ * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG */ -#ifndef QT_NO_DEBUG -#define QT_QML_DEBUG -#include -#endif - #include "AppSettings.h" #include "DpiCalculator.h" #include "FileDestination.h" @@ -41,21 +36,10 @@ Q_IMPORT_PLUGIN(QtQuick2WindowPlugin) Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin) Q_IMPORT_PLUGIN(QtQmlModelsPlugin) Q_IMPORT_PLUGIN(QtQmlStateMachinePlugin) - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) Q_IMPORT_PLUGIN(QtGraphicalEffectsPlugin) -#if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0)) -Q_IMPORT_PLUGIN(QtQuickControlsPlugin) -Q_IMPORT_PLUGIN(QtLabsControlsPlugin) -Q_IMPORT_PLUGIN(QtLabsTemplatesPlugin) -#endif -#endif - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) //Q_IMPORT_PLUGIN(QtQuickControls2Plugin) //Q_IMPORT_PLUGIN(QtQuickExtrasFlatPlugin) //Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin) -#endif #endif @@ -71,7 +55,7 @@ UIPlugInQml::UIPlugInQml() , mChangePinModel() , mAuthModel() , mVersionInformationModel() - , mShareUtil() + , mQmlExtension() , mSelfAuthenticationModel() , mSettingsModel() , mCertificateDescriptionModel() @@ -80,6 +64,7 @@ UIPlugInQml::UIPlugInQml() , mApplicationModel() , mExplicitPlatformStyle(getPlatformSelectors()) , mStatusBarUtil() + , mConnectivityManager() { #if defined(Q_OS_ANDROID) QGuiApplication::setFont(QFont("Roboto")); @@ -123,7 +108,7 @@ void UIPlugInQml::init() mEngine->rootContext()->setContextProperty("changePinModel", &mChangePinModel); mEngine->rootContext()->setContextProperty("authModel", &mAuthModel); mEngine->rootContext()->setContextProperty("versionInformationModel", &mVersionInformationModel); - mEngine->rootContext()->setContextProperty("shareUtil", &mShareUtil); + mEngine->rootContext()->setContextProperty("qmlExtension", &mQmlExtension); mEngine->rootContext()->setContextProperty("selfAuthenticationModel", &mSelfAuthenticationModel); mEngine->rootContext()->setContextProperty("settingsModel", &mSettingsModel); mEngine->rootContext()->setContextProperty("certificateDescriptionModel", &mCertificateDescriptionModel); @@ -131,6 +116,7 @@ void UIPlugInQml::init() mEngine->rootContext()->setContextProperty("numberModel", &mNumberModel); mEngine->rootContext()->setContextProperty("applicationModel", &mApplicationModel); mEngine->rootContext()->setContextProperty("statusBarUtil", &mStatusBarUtil); + mEngine->rootContext()->setContextProperty("connectivityManager", &mConnectivityManager); mEngine->load(getFile(QStringLiteral("qml/main.qml"))); @@ -172,57 +158,50 @@ QString UIPlugInQml::getPlatformSelectors() const void UIPlugInQml::onWorkflowStarted(QSharedPointer pContext) { mApplicationModel.resetContext(pContext); + mNumberModel.resetContext(pContext); - if (auto changePinContext = pContext.dynamicCast()) + if (auto changePinContext = pContext.objectCast()) { mChangePinModel.resetContext(changePinContext); } - if (auto authContext = pContext.dynamicCast()) + if (auto authContext = pContext.objectCast()) { + mConnectivityManager.startWatching(); mAuthModel.resetContext(authContext); mCertificateDescriptionModel.resetContext(authContext); mChatModel.resetContext(authContext); } - if (auto authContext = pContext.dynamicCast()) + if (auto authContext = pContext.objectCast()) { mSelfAuthenticationModel.resetContext(authContext); } - - if (auto workflowContext = pContext.dynamicCast()) - { - mNumberModel.resetContext(workflowContext); - } } void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) { mApplicationModel.resetContext(); + mNumberModel.resetContext(); - if (pContext.dynamicCast()) + if (pContext.objectCast()) { mChangePinModel.resetContext(); } - if (pContext.dynamicCast()) + if (pContext.objectCast()) { + mConnectivityManager.stopWatching(); mAuthModel.resetContext(); mCertificateDescriptionModel.resetContext(); mChatModel.resetContext(); } - if (pContext.dynamicCast()) + if (pContext.objectCast()) { mSelfAuthenticationModel.resetContext(); } - - if (pContext.dynamicCast()) - { - mNumberModel.resetContext(); - } - } @@ -232,18 +211,24 @@ void UIPlugInQml::doShutdown() } -QUrl UIPlugInQml::getFile(const QString& pFile) const +QUrl UIPlugInQml::getFile(const QString& pFile) { const QString path = FileDestination::getPath(pFile); -#if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) +#if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) if (!QFile::exists(path)) { return QUrl::fromLocalFile(QStringLiteral(RES_DIR) + QLatin1Char('/') + pFile); } #endif +#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) return path; + +#else + return QUrl::fromLocalFile(path); + +#endif } diff --git a/src/qml/UIPlugInQml.h b/src/qml/UIPlugInQml.h index 2d669b3..76d8321 100644 --- a/src/qml/UIPlugInQml.h +++ b/src/qml/UIPlugInQml.h @@ -13,12 +13,13 @@ #include "CertificateDescriptionModel.h" #include "ChangePinModel.h" #include "ChatModel.h" +#include "ConnectivityManager.h" #include "HistoryModel.h" #include "NumberModel.h" -#include "ProviderModel.h" +#include "ProviderCategoryFilterModel.h" +#include "QmlExtension.h" #include "SelfAuthenticationModel.h" #include "SettingsModel.h" -#include "ShareUtil.h" #include "StatusBarUtil.h" #include "VersionInformationModel.h" #include @@ -39,12 +40,12 @@ class UIPlugInQml private: QScopedPointer mEngine; qreal mDpi; - ProviderModel mProviderModel; + ProviderCategoryFilterModel mProviderModel; HistoryModel mHistoryModel; ChangePinModel mChangePinModel; AuthModel mAuthModel; VersionInformationModel mVersionInformationModel; - ShareUtil mShareUtil; + QmlExtension mQmlExtension; SelfAuthenticationModel mSelfAuthenticationModel; SettingsModel mSettingsModel; CertificateDescriptionModel mCertificateDescriptionModel; @@ -53,8 +54,7 @@ class UIPlugInQml ApplicationModel mApplicationModel; QString mExplicitPlatformStyle; StatusBarUtil mStatusBarUtil; - - QUrl getFile(const QString& pFile) const; + ConnectivityManager mConnectivityManager; QString getPlatformSelectors() const; @@ -66,6 +66,8 @@ class UIPlugInQml Q_INVOKABLE bool isDeveloperBuild() const; Q_INVOKABLE void init(); + static QUrl getFile(const QString& pFile); + private Q_SLOTS: virtual void doShutdown() override; virtual void onWorkflowStarted(QSharedPointer pContext) override; diff --git a/src/qml/VersionInformationModel.cpp b/src/qml/VersionInformationModel.cpp index 0940985..b14e1d4 100644 --- a/src/qml/VersionInformationModel.cpp +++ b/src/qml/VersionInformationModel.cpp @@ -23,20 +23,23 @@ VersionInformationModel::VersionInformationModel(QObject* pParent) : QAbstractListModel(pParent) , mData() { - mData.append(QPair(tr("Application Name"), QCoreApplication::applicationName())); - mData.append(QPair(tr("Application Version"), QCoreApplication::applicationVersion())); - mData.append(QPair(tr("Organization"), QCoreApplication::organizationName())); - mData.append(QPair(tr("Organization domain"), QCoreApplication::organizationDomain())); - mData.append(QPair(tr("Build date"), QString::fromLatin1(BuildHelper::getDateTime()))); - mData.append(QPair(tr("System version"), QSysInfo::prettyProductName())); - mData.append(QPair(tr("Kernel"), QSysInfo::kernelVersion())); - mData.append(QPair(tr("Architecture"), QSysInfo::currentCpuArchitecture())); + mData += QPair(tr("Application Name"), QCoreApplication::applicationName()); + mData += QPair(tr("Application Version"), QCoreApplication::applicationVersion()); + mData += QPair(tr("Organization"), QCoreApplication::organizationName()); + mData += QPair(tr("Organization domain"), QCoreApplication::organizationDomain()); + mData += QPair(tr("Build date"), QString::fromLatin1(BuildHelper::getDateTime())); #ifdef Q_OS_ANDROID - mData.append(QPair(tr("Compiled architecture"), QSysInfo::buildCpuArchitecture())); - mData.append(QPair(tr("Device"), DeviceInfo::getPrettyInfo())); + mData += QPair(tr("VersionCode"), QString::number(BuildHelper::getVersionCode())); #endif - mData.append(QPair(tr("Qt Version"), QString::fromLatin1(qVersion()))); - mData.append(QPair(tr("OpenSSL Version"), QSslSocket::sslLibraryVersionString())); + mData += QPair(tr("System version"), QSysInfo::prettyProductName()); + mData += QPair(tr("Kernel"), QSysInfo::kernelVersion()); + mData += QPair(tr("Architecture"), QSysInfo::currentCpuArchitecture()); +#ifdef Q_OS_ANDROID + mData += QPair(tr("Compiled architecture"), QSysInfo::buildCpuArchitecture()); + mData += QPair(tr("Device"), DeviceInfo::getPrettyInfo()); +#endif + mData += QPair(tr("Qt Version"), QString::fromLatin1(qVersion())); + mData += QPair(tr("OpenSSL Version"), QSslSocket::sslLibraryVersionString()); } diff --git a/src/services/AppUpdateBackend.cpp b/src/services/AppUpdateBackend.cpp new file mode 100644 index 0000000..abd698c --- /dev/null +++ b/src/services/AppUpdateBackend.cpp @@ -0,0 +1,186 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "AppUpdateBackend.h" + +#include "GeneralSettings.h" +#include "VersionNumber.h" + +#include +#include +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(update) + + +AppUpdateBackend::AppUpdateBackend() + : UpdateBackend() + , mNotesService() + , mUpdateData() +{ + connect(&mNotesService, &UpdateService::fireUpdateFinished, this, &AppUpdateBackend::onReleaseNotesFinished); +} + + +void AppUpdateBackend::setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates) +{ + mNotesService.setTrustedUpdateCertificates(pTrustedUpdateCertificates); +} + + +QDateTime AppUpdateBackend::getIssueDate() const +{ + return QDateTime(); // do not abort if Last-Modified is older +} + + +void AppUpdateBackend::processSuccess(const QByteArray& pData) +{ + QJsonParseError jsonError; + const auto& json = QJsonDocument::fromJson(pData, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + qCWarning(update) << "Cannot parse json data:" << jsonError.errorString(); + return; + } + + const auto& obj = json.object(); + const QJsonValue& items = obj["items"]; + if (items.isArray()) + { + const auto& itemArray = items.toArray(); + const auto& end = itemArray.constEnd(); + for (auto iter = itemArray.constBegin(); iter != end; ++iter) + { + if (iter->isObject()) + { + if (checkPlatformObject(iter->toObject())) + { + mNotesService.runUpdate(); + return; + } + } + else + { + qCWarning(update) << "Object of field 'items' cannot be parsed"; + } + } + } + else + { + qCWarning(update) << "Field 'items' cannot be parsed"; + } + + Q_EMIT fireAppUpdateCheckFinished(false); +} + + +void AppUpdateBackend::processError(const GlobalStatus& pError) +{ + qCDebug(update) << "Cannot process app update check:" << pError; + Q_EMIT fireAppUpdateCheckFinished(false, pError); +} + + +void AppUpdateBackend::onReleaseNotesFinished() +{ + mUpdateData.setNotes(QString::fromUtf8(mNotesService.getContent())); + Q_EMIT fireAppUpdateCheckFinished(true, mNotesService.getError()); +} + + +void AppUpdateBackend::skipVersion(const QString& pVersion) +{ + qCInfo(update) << "Skip application update:" << pVersion; + GeneralSettings::skipVersion(pVersion); +} + + +bool AppUpdateBackend::checkPlatformObject(const QJsonObject& pJson) +{ + const auto& platform = pJson[QLatin1String("platform")].toString(); + + if (!isPlatform(platform)) + { + qCDebug(update) << "Unused platform:" << platform; + return false; + } + + qCDebug(update) << "Found platform:" << platform; + const auto& version = pJson[QLatin1String("version")].toString(); + + if (version == GeneralSettings::getSkipVersion()) + { + qCInfo(update) << "Version will be skipped:" << version; + return false; + } + + AppUpdateData data; + data.setDate(QDateTime::fromString(pJson[QLatin1String("date")].toString(), Qt::ISODate)); + data.setVersion(version); + data.setUrl(QUrl(pJson[QLatin1String("url")].toString())); + data.setChecksumUrl(QUrl(pJson[QLatin1String("checksum")].toString())); + data.setNotesUrl(QUrl(pJson[QLatin1String("notes")].toString())); + data.setSize(pJson[QLatin1String("size")].toInt(-1)); + + if (!data.isValid()) + { + qCWarning(update) << "Invalid item:" << pJson; + return false; + } + + const auto& itemVersion = VersionNumber(version); + if (itemVersion > VersionNumber::getApplicationVersion()) + { + qCInfo(update) << "Found new version:" << version; + mNotesService.setUpdateUrl(data.getNotesUrl()); + mUpdateData = data; + return true; + } + + qCDebug(update) << "No new version:" << version; + return false; +} + + +const AppUpdateData& AppUpdateBackend::getUpdateData() const +{ + return mUpdateData; +} + + +bool AppUpdateBackend::isPlatform(const QString& pPlatform) const +{ +#ifdef Q_OS_WIN64 + if (pPlatform == QLatin1String("Q_OS_WIN64")) + { + return true; + } +#endif + +#ifdef Q_OS_WIN32 + if (pPlatform == QLatin1String("Q_OS_WIN32")) + { + return true; + } +#endif + +#ifdef Q_OS_OSX + if (pPlatform == QLatin1String("Q_OS_MAC")) + { + return true; + } +#endif + +#if !defined(Q_OS_OSX) && !defined(Q_OS_WIN) + if (pPlatform == QLatin1String("SOURCES")) + { + return true; + } +#endif + + return false; +} diff --git a/src/services/AppUpdateBackend.h b/src/services/AppUpdateBackend.h new file mode 100644 index 0000000..dec5382 --- /dev/null +++ b/src/services/AppUpdateBackend.h @@ -0,0 +1,53 @@ +/*! + * \brief UpdateBackend implementation for AppService. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AbstractSettings.h" +#include "AppUpdateData.h" +#include "DownloadService.h" +#include "UpdateService.h" + +#include +#include + +namespace governikus +{ + +class AppUpdateBackend + : public QObject + , public UpdateBackend +{ + Q_OBJECT + + private: + DownloadService mNotesService; + AppUpdateData mUpdateData; + QSharedPointer mStore; + + bool isPlatform(const QString& pPlatform) const; + bool checkPlatformObject(const QJsonObject& pJson); + + public: + AppUpdateBackend(); + + void skipVersion(const QString& pVersion); + const AppUpdateData& getUpdateData() const; + void setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates); + + virtual QDateTime getIssueDate() const override; + virtual void processSuccess(const QByteArray& pData) override; + virtual void processError(const GlobalStatus& pError) override; + + private Q_SLOTS: + void onReleaseNotesFinished(); + + Q_SIGNALS: + void fireAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError = GlobalStatus::Code::No_Error); +}; + + +} /* namespace governikus */ diff --git a/src/services/AppUpdateData.cpp b/src/services/AppUpdateData.cpp new file mode 100644 index 0000000..2192ed7 --- /dev/null +++ b/src/services/AppUpdateData.cpp @@ -0,0 +1,118 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "AppUpdateData.h" + +using namespace governikus; + +AppUpdateData::AppUpdateData() + : mDate() + , mVersion() + , mUrl() + , mSize(-1) + , mChecksumUrl() + , mNotesUrl() + , mNotes() +{ +} + + +bool AppUpdateData::isValid() const +{ + // Valid means = required data! + return !mVersion.isEmpty() && + mUrl.isValid() && + mNotesUrl.isValid(); +} + + +const QDateTime AppUpdateData::getDate() const +{ + return mDate; +} + + +void AppUpdateData::setDate(const QDateTime& pDate) +{ + mDate = pDate; +} + + +const QString& AppUpdateData::getVersion() const +{ + return mVersion; +} + + +void AppUpdateData::setVersion(const QString& pVersion) +{ + mVersion = pVersion; +} + + +const QUrl& AppUpdateData::getUrl() const +{ + return mUrl; +} + + +void AppUpdateData::setUrl(const QUrl& pUrl) +{ + mUrl = pUrl; +} + + +int AppUpdateData::getSize() const +{ + return mSize; +} + + +void AppUpdateData::setSize(int pSize) +{ + if (pSize < 0) + { + mSize = -1; + } + else + { + mSize = pSize; + } +} + + +const QUrl& AppUpdateData::getChecksumUrl() const +{ + return mChecksumUrl; +} + + +void AppUpdateData::setChecksumUrl(const QUrl& pUrl) +{ + mChecksumUrl = pUrl; +} + + +const QUrl& AppUpdateData::getNotesUrl() const +{ + return mNotesUrl; +} + + +void AppUpdateData::setNotesUrl(const QUrl& pUrl) +{ + mNotesUrl = pUrl; +} + + +void AppUpdateData::setNotes(const QString& pNotes) +{ + mNotes = pNotes; +} + + +const QString& AppUpdateData::getNotes() const +{ + return mNotes; +} diff --git a/src/services/AppUpdateData.h b/src/services/AppUpdateData.h new file mode 100644 index 0000000..976a1da --- /dev/null +++ b/src/services/AppUpdateData.h @@ -0,0 +1,55 @@ +/*! + * \brief Update data implementation for application version. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include + +namespace governikus +{ + +class AppUpdateData +{ + private: + QDateTime mDate; + QString mVersion; + QUrl mUrl; + int mSize; + QUrl mChecksumUrl; + QUrl mNotesUrl; + QString mNotes; + + public: + AppUpdateData(); + + bool isValid() const; + + const QDateTime getDate() const; + void setDate(const QDateTime& pDate); + + const QString& getVersion() const; + void setVersion(const QString& pVersion); + + const QUrl& getUrl() const; + void setUrl(const QUrl& pUrl); + + int getSize() const; + void setSize(int pSize); + + const QUrl& getChecksumUrl() const; + void setChecksumUrl(const QUrl& pUrl); + + const QUrl& getNotesUrl() const; + void setNotesUrl(const QUrl& pUrl); + + const QString& getNotes() const; + void setNotes(const QString& pNotes); +}; + + +} /* namespace governikus */ diff --git a/src/services/AppUpdateService.cpp b/src/services/AppUpdateService.cpp new file mode 100644 index 0000000..7665ae2 --- /dev/null +++ b/src/services/AppUpdateService.cpp @@ -0,0 +1,53 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "AppUpdateService.h" + +#include "AppUpdateBackend.h" +#include "SingletonHelper.h" + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(update) + +defineSingleton(AppUpdateService) + + +AppUpdateService::AppUpdateService() + : UpdateService(QSharedPointer(new AppUpdateBackend), QStringLiteral("app")) +{ + connect(getUpdateBackend().data(), &AppUpdateBackend::fireAppUpdateCheckFinished, this, &AppUpdateService::fireAppUpdateCheckFinished); +} + + +AppUpdateService::~AppUpdateService() +{ +} + + +AppUpdateService& AppUpdateService::getInstance() +{ + return *Instance; +} + + +void AppUpdateService::setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates) +{ + UpdateService::setTrustedUpdateCertificates(pTrustedUpdateCertificates); + getUpdateBackend()->setTrustedUpdateCertificates(pTrustedUpdateCertificates); +} + + +void AppUpdateService::skipVersion(const QString& pVersion) +{ + getUpdateBackend()->skipVersion(pVersion); +} + + +const AppUpdateData& AppUpdateService::getUpdateData() const +{ + return getUpdateBackend()->getUpdateData(); +} diff --git a/src/services/AppUpdateService.h b/src/services/AppUpdateService.h new file mode 100644 index 0000000..cb1a67a --- /dev/null +++ b/src/services/AppUpdateService.h @@ -0,0 +1,36 @@ +/*! + * \brief Update checker for the application. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AppUpdateData.h" +#include "UpdateService.h" + +namespace governikus +{ + +class AppUpdateService + : public UpdateService +{ + Q_OBJECT + + protected: + AppUpdateService(); + virtual ~AppUpdateService(); + + public: + static AppUpdateService& getInstance(); + + void skipVersion(const QString& pVersion); + const AppUpdateData& getUpdateData() const; + virtual void setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates) override; + + Q_SIGNALS: + void fireAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError); +}; + + +} /* namespace governikus */ diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 362e3dd..2fbc981 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -1,7 +1,3 @@ ADD_PLATFORM_LIBRARY(AusweisAppServices) TARGET_LINK_LIBRARIES(AusweisAppServices Qt5::Core AusweisAppCard AusweisAppNetwork AusweisAppSettings) - -IF(NOT ANDROID AND NOT IOS) - TARGET_LINK_LIBRARIES(AusweisAppServices AusweisAppExternalFervor) -ENDIF() diff --git a/src/services/DownloadBackend.cpp b/src/services/DownloadBackend.cpp new file mode 100644 index 0000000..cffd57e --- /dev/null +++ b/src/services/DownloadBackend.cpp @@ -0,0 +1,39 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "DownloadBackend.h" + +using namespace governikus; + + +QDateTime DownloadBackend::getIssueDate() const +{ + return QDateTime(); +} + + +void DownloadBackend::processSuccess(const QByteArray& pData) +{ + mContent = pData; + mError = GlobalStatus::Code::No_Error; +} + + +void DownloadBackend::processError(const GlobalStatus& pError) +{ + mError = pError; + mContent.clear(); +} + + +const QByteArray& DownloadBackend::getContent() const +{ + return mContent; +} + + +const GlobalStatus& DownloadBackend::getError() const +{ + return mError; +} diff --git a/src/services/DownloadBackend.h b/src/services/DownloadBackend.h new file mode 100644 index 0000000..80c822d --- /dev/null +++ b/src/services/DownloadBackend.h @@ -0,0 +1,37 @@ +/*! + * \brief DownloadBackend implementation for \ref DownloadService. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "UpdateBackend.h" + +namespace governikus +{ + +class DownloadBackend + : public UpdateBackend +{ + private: + QByteArray mContent; + GlobalStatus mError; + + public: + DownloadBackend() + : mError(GlobalStatus::Code::No_Error) + { + + } + + + const QByteArray& getContent() const; + const GlobalStatus& getError() const; + + virtual QDateTime getIssueDate() const override; + virtual void processSuccess(const QByteArray& pData) override; + virtual void processError(const GlobalStatus& pError) override; +}; + +} /* namespace governikus */ diff --git a/src/services/DownloadService.cpp b/src/services/DownloadService.cpp new file mode 100644 index 0000000..ab331fc --- /dev/null +++ b/src/services/DownloadService.cpp @@ -0,0 +1,32 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "DownloadService.h" + +#include "DownloadBackend.h" + +using namespace governikus; + + +DownloadService::DownloadService() + : UpdateService(QSharedPointer(new DownloadBackend), QStringLiteral("download")) +{ +} + + +DownloadService::~DownloadService() +{ +} + + +const QByteArray& DownloadService::getContent() const +{ + return getUpdateBackend()->getContent(); +} + + +const GlobalStatus& DownloadService::getError() const +{ + return getUpdateBackend()->getError(); +} diff --git a/src/services/DownloadService.h b/src/services/DownloadService.h new file mode 100644 index 0000000..16b9a3b --- /dev/null +++ b/src/services/DownloadService.h @@ -0,0 +1,28 @@ +/*! + * \brief General downloader as service. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "UpdateService.h" + +namespace governikus +{ + +class DownloadService + : public UpdateService +{ + Q_OBJECT + + public: + DownloadService(); + virtual ~DownloadService(); + + const QByteArray& getContent() const; + const GlobalStatus& getError() const; +}; + + +} /* namespace governikus */ diff --git a/src/services/DriverParser.cpp b/src/services/DriverParser.cpp index 0e52a4b..1cafc98 100644 --- a/src/services/DriverParser.cpp +++ b/src/services/DriverParser.cpp @@ -65,20 +65,20 @@ class EntryParser EntryParser::EntryParser(const QJsonValue& pJsonValue) : mJsonValue(pJsonValue) , mWinVersion( -{ - {"WV_WINDOWS7", QSysInfo::WV_WINDOWS7}, - {"WV_WINDOWS8", QSysInfo::WV_WINDOWS8}, - {"WV_WINDOWS8_1", QSysInfo::WV_WINDOWS8_1}, - {"WV_WINDOWS10", QSysInfo::WV_WINDOWS10} -} + { + {"WV_WINDOWS7", QSysInfo::WV_WINDOWS7}, + {"WV_WINDOWS8", QSysInfo::WV_WINDOWS8}, + {"WV_WINDOWS8_1", QSysInfo::WV_WINDOWS8_1}, + {"WV_WINDOWS10", QSysInfo::WV_WINDOWS10} + } ) , mMacVersion({ - {"MV_10_9", QSysInfo::MV_10_9}, - {"MV_10_10", QSysInfo::MV_10_10}, - {"MV_10_11", QSysInfo::MV_10_11} -} + {"MV_10_9", QSysInfo::MV_10_9}, + {"MV_10_10", QSysInfo::MV_10_10}, + {"MV_10_11", QSysInfo::MV_10_11} + } ) { } diff --git a/src/services/DriverService.cpp b/src/services/DriverService.cpp index add3ac5..53fd008 100644 --- a/src/services/DriverService.cpp +++ b/src/services/DriverService.cpp @@ -1,21 +1,19 @@ /*! - * DriverService.cpp - * * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG */ - #include "DriverService.h" +#include "AppSettings.h" #include "DriverParser.h" +#include "DriverSettings.h" +#include "SingletonHelper.h" #include "UpdateSettingsBackend.h" -#include "AppSettings.h" - -#include - using namespace governikus; +defineSingleton(DriverService) + namespace { class UpdateDriverSettingsBackend @@ -41,11 +39,8 @@ class UpdateDriverSettingsBackend } -DriverService* DriverService::mSharedInstance = nullptr; - - -DriverService::DriverService(DriverSettings& pSettings) - : UpdateService(QSharedPointer(new UpdateDriverSettingsBackend(pSettings)), +DriverService::DriverService() + : UpdateService(QSharedPointer(new UpdateDriverSettingsBackend(AppSettings::getInstance().getDriverSettings())), QStringLiteral("driver configuration")) { } @@ -56,17 +51,7 @@ DriverService::~DriverService() } -DriverService* DriverService::getSharedInstance() +DriverService& DriverService::getInstance() { - static QMutex mutex; - if (!mSharedInstance) - { - QMutexLocker locker(&mutex); - if (!mSharedInstance) - { - mSharedInstance = new DriverService(AppSettings::getInstance().getDriverSettings()); - } - } - - return mSharedInstance; + return *Instance; } diff --git a/src/services/DriverService.h b/src/services/DriverService.h index 49706ab..ff7a265 100644 --- a/src/services/DriverService.h +++ b/src/services/DriverService.h @@ -1,19 +1,13 @@ /*! - * DriverService.h - * * \brief Service providing an update mechanism for the reader driver settings * * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG */ - #pragma once - -#include "DriverSettings.h" #include "UpdateService.h" - namespace governikus { class DriverService @@ -21,20 +15,12 @@ class DriverService { Q_OBJECT - private: - static DriverService* mSharedInstance; - - public: - DriverService(DriverSettings& pSettings); - + protected: + DriverService(); virtual ~DriverService(); - /*! - * Get the singleton - */ - static DriverService* getSharedInstance(); - - + public: + static DriverService& getInstance(); }; } /* namespace governikus */ diff --git a/src/services/IconCache.cpp b/src/services/IconCache.cpp index 1ae72a0..45c9fe2 100644 --- a/src/services/IconCache.cpp +++ b/src/services/IconCache.cpp @@ -70,7 +70,7 @@ void IconCache::processNextIcon() } else { - const QString icon = mPendingIcons.first(); + const QString& icon = mPendingIcons.constFirst(); mIconService.reset(new IconService(mIconCacheFolderPath, icon)); @@ -160,7 +160,7 @@ void IconCache::setIconUpdateUrlBase(const QString& pIconUpdateUrlBase) QString IconCache::getLocalIconUrl(const QString& pIcon) const { - return pIcon.startsWith(QRC_PREFIX) ? pIcon : QStringLiteral("file://") + getIconPathInCache(pIcon); + return pIcon.startsWith(QRC_PREFIX) ? pIcon : QUrl::fromLocalFile(getIconPathInCache(pIcon)).toString(); } diff --git a/src/services/IconUpdateBackend.cpp b/src/services/IconUpdateBackend.cpp index d49d8b2..7f19449 100644 --- a/src/services/IconUpdateBackend.cpp +++ b/src/services/IconUpdateBackend.cpp @@ -49,7 +49,7 @@ void IconUpdateBackend::processSuccess(const QByteArray& pData) } -void IconUpdateBackend::processError() +void IconUpdateBackend::processError(const GlobalStatus& pError) { - // Nothing to do. + Q_UNUSED(pError) } diff --git a/src/services/IconUpdateBackend.h b/src/services/IconUpdateBackend.h index 1ce74fc..726cfd2 100644 --- a/src/services/IconUpdateBackend.h +++ b/src/services/IconUpdateBackend.h @@ -10,17 +10,12 @@ #include "UpdateBackend.h" #include -#include - namespace governikus { class IconUpdateBackend - : public QObject - , public UpdateBackend + : public UpdateBackend { - Q_OBJECT - private: const QString mIcon; @@ -35,7 +30,7 @@ class IconUpdateBackend virtual void processSuccess(const QByteArray& pData) override; - virtual void processError() override; + virtual void processError(const GlobalStatus& pError) override; }; diff --git a/src/services/ProviderParser.cpp b/src/services/ProviderParser.cpp index 1f338c9..d7ac400 100644 --- a/src/services/ProviderParser.cpp +++ b/src/services/ProviderParser.cpp @@ -9,6 +9,11 @@ #include #include +#include + + +Q_DECLARE_LOGGING_CATEGORY(update) + using namespace governikus; @@ -30,6 +35,7 @@ QSharedPointer ProviderParser::parse(const QByteArray& pData) const auto& json = QJsonDocument::fromJson(pData, &jsonError); if (jsonError.error != QJsonParseError::NoError) { + qCCritical(update) << "Cannot parse provider settings:" << jsonError.errorString(); return QSharedPointer(); } QJsonObject doc = json.object(); @@ -37,6 +43,20 @@ QSharedPointer ProviderParser::parse(const QByteArray& pData) QSharedPointer providerSettings(new ProviderSettings()); providerSettings->setIssueDate(doc["issueDate"].toVariant().toDateTime()); + QMap callCosts; + const auto& callCostArray = doc["callcosts"].toArray(); + for (const auto& callCostElem : callCostArray) + { + const auto cost = CallCost(callCostElem); + const auto& prefixArray = callCostElem.toObject()["prefixes"].toArray(); + for (const auto& prefixElem : prefixArray) + { + const auto& prefix = prefixElem.toString(); + callCosts.insert(prefix, cost); + } + } + providerSettings->setCallCosts(callCosts); + QJsonArray array = doc["provider"].toArray(); QVector providers(array.size()); for (int i = 0; i < array.size(); ++i) @@ -58,7 +78,8 @@ QSharedPointer ProviderParser::parse(const QByteArray& pData) prov["icon"].toString(), prov["image"].toString(), prov["tcTokenUrl"].toString(), - prov["clientUrl"].toString()); + prov["clientUrl"].toString(), + prov["subjectUrls"].toVariant().toStringList()); } providerSettings->setProviders(providers); diff --git a/src/services/ProviderService.cpp b/src/services/ProviderService.cpp index ed64d8d..429406a 100644 --- a/src/services/ProviderService.cpp +++ b/src/services/ProviderService.cpp @@ -6,12 +6,14 @@ #include "AppSettings.h" #include "ProviderParser.h" +#include "ProviderSettings.h" +#include "SingletonHelper.h" #include "UpdateSettingsBackend.h" -#include - using namespace governikus; +defineSingleton(ProviderService) + namespace { class UpdateProviderSettingsBackend @@ -36,11 +38,8 @@ class UpdateProviderSettingsBackend } - -ProviderService* ProviderService::mSharedInstance = nullptr; - -ProviderService::ProviderService(ProviderSettings& pSettings) - : UpdateService(QSharedPointer(new UpdateProviderSettingsBackend(pSettings)), +ProviderService::ProviderService() + : UpdateService(QSharedPointer(new UpdateProviderSettingsBackend(AppSettings::getInstance().getProviderSettings())), QStringLiteral("provider configuration")) { } @@ -51,16 +50,7 @@ ProviderService::~ProviderService() } -ProviderService* ProviderService::getSharedInstance() +ProviderService& ProviderService::getInstance() { - static QMutex mutex; - if (!mSharedInstance) - { - QMutexLocker locker(&mutex); - if (!mSharedInstance) - { - mSharedInstance = new ProviderService(AppSettings::getInstance().getProviderSettings()); - } - } - return mSharedInstance; + return *Instance; } diff --git a/src/services/ProviderService.h b/src/services/ProviderService.h index 2cef658..7e4c36c 100644 --- a/src/services/ProviderService.h +++ b/src/services/ProviderService.h @@ -1,19 +1,13 @@ /*! - * ProviderService.h - * * \brief Service providing an update mechanism for the provider settings * * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ - #pragma once - -#include "ProviderSettings.h" #include "UpdateService.h" - namespace governikus { class ProviderService @@ -21,20 +15,12 @@ class ProviderService { Q_OBJECT - private: - static ProviderService* mSharedInstance; - - public: - ProviderService(ProviderSettings& pSettings); - + protected: + ProviderService(); virtual ~ProviderService(); - /*! - * Get the singleton - */ - static ProviderService* getSharedInstance(); - - + public: + static ProviderService& getInstance(); }; } /* namespace governikus */ diff --git a/src/services/UpdateBackend.h b/src/services/UpdateBackend.h index 9c32260..88ef01c 100644 --- a/src/services/UpdateBackend.h +++ b/src/services/UpdateBackend.h @@ -10,6 +10,7 @@ #pragma once +#include "GlobalStatus.h" #include #include @@ -28,7 +29,7 @@ class UpdateBackend virtual void processSuccess(const QByteArray& pData) = 0; - virtual void processError() = 0; + virtual void processError(const GlobalStatus& pError) = 0; }; } diff --git a/src/services/UpdateService.cpp b/src/services/UpdateService.cpp index 7188d8a..a14473d 100644 --- a/src/services/UpdateService.cpp +++ b/src/services/UpdateService.cpp @@ -7,10 +7,12 @@ * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG */ - -#include "NetworkManager.h" #include "UpdateService.h" +#include "HttpStatusCode.h" +#include "NetworkManager.h" +#include "TlsConfiguration.h" + #include @@ -21,24 +23,21 @@ Q_DECLARE_LOGGING_CATEGORY(update) void UpdateService::onSslErrors(const QList& pErrors) { - for (const auto& error : pErrors) - { - qCWarning(update) << "(ignored)" << error.errorString(); - } - mReply->ignoreSslErrors(); + TlsConfiguration::containsFatalError(mReply, pErrors); } void UpdateService::onSslHandshakeDone() { - QSslConfiguration sslConfiguration = mReply->sslConfiguration(); - qCDebug(update) << "Used session cipher:" << sslConfiguration.sessionCipher(); - qCDebug(update) << "Used session protocol:" << sslConfiguration.sessionProtocol(); + const auto& cfg = mReply->sslConfiguration(); + const auto& cert = cfg.peerCertificate(); + qDebug(update) << "Used session cipher:" << cfg.sessionCipher(); + qDebug(update) << "Used session protocol:" << cfg.sessionProtocol(); + qDebug(update) << "Used server certificate:" << cert; - QSslCertificate sslCert = sslConfiguration.peerCertificate(); - if (!mTrustedUpdateCertificates.contains(sslCert)) + if (!mTrustedUpdateCertificates.contains(cert)) { - qCCritical(update).nospace() << "Untrusted certificate found [" << mNameForLog << "]: " << sslCert; + qCritical(update).nospace() << "Untrusted certificate found [" << mNameForLog << "]: " << cert; mReply->abort(); } } @@ -52,7 +51,7 @@ void UpdateService::onMetadataChanged() if (!status.isNull()) { qCDebug(update) << "Found header status" << status.toString(); - if (status.toInt() != 200) + if (status.toInt() != HttpStatusCode::OK) { qCCritical(update) << "Abort request, status " << status.toInt(); mReply->abort(); @@ -68,6 +67,7 @@ void UpdateService::onMetadataChanged() if (localIssueDate.isValid() && lastModified.toDateTime() <= localIssueDate) { qCDebug(update) << "Abort request, Last-Modified is older than issue date of current data"; + mCancel = true; mReply->abort(); return; @@ -79,35 +79,35 @@ void UpdateService::onMetadataChanged() void UpdateService::onNetworkReplyFinished() { mReply->deleteLater(); + + if (mCancel) + { + Q_EMIT fireUpdateFinished(); + return; + } + + const auto& cert = mReply->sslConfiguration().peerCertificate(); + if (cert.isNull() || !mTrustedUpdateCertificates.contains(cert)) + { + qCCritical(update).nospace() << "Connection not secure [" << mNameForLog << "]"; + mUpdateBackend->processError(GlobalStatus::Code::Network_Ssl_Establishment_Error); + Q_EMIT fireUpdateFinished(); + return; + } + if (mReply->error() != QNetworkReply::NoError) { qCCritical(update).nospace() << mReply->errorString() << " [" << mNameForLog << "]"; - mUpdateBackend->processError(); + mUpdateBackend->processError(NetworkManager::toStatus(mReply)); Q_EMIT fireUpdateFinished(); - - return; - } - else if (mReply->sslConfiguration().peerCertificate().isNull()) - { - qCCritical(update).nospace() << "Connection not encrypted [" << mNameForLog << "]"; - mUpdateBackend->processError(); - Q_EMIT fireUpdateFinished(); - return; } mUpdateBackend->processSuccess(mReply->readAll()); - Q_EMIT fireUpdateFinished(); } -QSharedPointer UpdateService::getUpdateBackend() -{ - return mUpdateBackend; -} - - UpdateService::UpdateService(const QSharedPointer& pUpdateBackend, const QString& pNameForLog) : mUpdateBackend(pUpdateBackend) @@ -115,6 +115,7 @@ UpdateService::UpdateService(const QSharedPointer& pUpdateBackend , mUpdateUrl() , mTrustedUpdateCertificates() , mReply() + , mCancel(false) { Q_ASSERT_X(pUpdateBackend, "UpdateService", "invalid update backend"); } @@ -147,9 +148,10 @@ void UpdateService::setUpdateUrl(const QUrl& pUpdateUrl) void UpdateService::runUpdate() { - qCDebug(update) << QStringLiteral("Get %1 from update site %2").arg(mNameForLog, mUpdateUrl.toString()); + qDebug(update) << QStringLiteral("Get %1 from update site:").arg(mNameForLog) << mUpdateUrl; QNetworkRequest request(mUpdateUrl); + mCancel = false; mReply = NetworkManager::getGlobalInstance().get(request); connect(mReply.data(), &QNetworkReply::sslErrors, this, &UpdateService::onSslErrors); diff --git a/src/services/UpdateService.h b/src/services/UpdateService.h index 89919f3..827da5b 100644 --- a/src/services/UpdateService.h +++ b/src/services/UpdateService.h @@ -38,6 +38,7 @@ class UpdateService QVector mTrustedUpdateCertificates; QPointer mReply; + bool mCancel; private Q_SLOTS: void onSslErrors(const QList& pErrors); @@ -49,7 +50,19 @@ class UpdateService void onNetworkReplyFinished(); protected: - QSharedPointer getUpdateBackend(); + template + QSharedPointer getUpdateBackend() + { + return mUpdateBackend.staticCast(); + } + + + template + QSharedPointer getUpdateBackend() const + { + return mUpdateBackend.staticCast(); + } + public: UpdateService(const QSharedPointer& pUpdateBackend, @@ -58,9 +71,7 @@ class UpdateService virtual ~UpdateService(); void setUpdateUrl(const QUrl& pUpdateUrl); - - void setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates); - + virtual void setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates); void runUpdate(); Q_SIGNALS: diff --git a/src/services/UpdateSettingsBackend.h b/src/services/UpdateSettingsBackend.h index baee471..94e42f6 100644 --- a/src/services/UpdateSettingsBackend.h +++ b/src/services/UpdateSettingsBackend.h @@ -67,25 +67,10 @@ class UpdateSettingsBackend void saveLatestSettings(QSharedPointer pUpdatedSettings) { - bool needsSaving = false; - - QSharedPointer defaultSettings = loadDefaultSettings(); - if (defaultSettings != nullptr && defaultSettings->getIssueDate() > mCurrentSettings.getIssueDate()) - { - qCDebug(update) << QStringLiteral("Replacing current %1 with default %1 issued on %2").arg(mNameForLog, defaultSettings->getIssueDate().toString(Qt::DateFormat::ISODate)); - mCurrentSettings.update(*defaultSettings); - needsSaving = true; - } - if (pUpdatedSettings != nullptr && pUpdatedSettings->getIssueDate() > mCurrentSettings.getIssueDate()) { qCDebug(update) << QStringLiteral("Replacing current %1 with updated %1 issued on %2").arg(mNameForLog, pUpdatedSettings->getIssueDate().toString(Qt::DateFormat::ISODate)); mCurrentSettings.update(*pUpdatedSettings); - needsSaving = true; - } - - if (needsSaving) - { mCurrentSettings.save(); } else @@ -109,6 +94,15 @@ class UpdateSettingsBackend // (re-)load current settings to have the up-to-date issue date. mCurrentSettings.load(); qCDebug(update) << QStringLiteral("Loaded current %1 issued on %2").arg(mNameForLog, mCurrentSettings.getIssueDate().toString(Qt::DateFormat::ISODate)); + + // Check if more recent default settings have been installed. + QSharedPointer defaultSettings = loadDefaultSettings(); + if (defaultSettings != nullptr && defaultSettings->getIssueDate() > mCurrentSettings.getIssueDate()) + { + qCDebug(update) << QStringLiteral("Replacing current %1 with default %1 issued on %2").arg(mNameForLog, defaultSettings->getIssueDate().toString(Qt::DateFormat::ISODate)); + mCurrentSettings.update(*defaultSettings); + mCurrentSettings.save(); + } } @@ -139,8 +133,9 @@ class UpdateSettingsBackend } - virtual void processError() override + virtual void processError(const GlobalStatus& pError) override { + Q_UNUSED(pError) saveLatestSettings(QSharedPointer()); } diff --git a/src/services/Updater.cpp b/src/services/Updater.cpp index 5bd6c70..5cd1406 100644 --- a/src/services/Updater.cpp +++ b/src/services/Updater.cpp @@ -5,16 +5,13 @@ #include "Updater.h" #include "AppSettings.h" +#include "AppUpdateService.h" #include "DriverService.h" #include "ProviderService.h" #include "SecureStorage.h" #include "SingletonHelper.h" #include "VersionNumber.h" -#if defined(Q_OS_WIN) || defined(Q_OS_OSX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) -#include "fervor/fvupdater.h" -#endif - #include using namespace governikus; @@ -28,19 +25,21 @@ Updater::Updater() SecureStorage& secureStorage = AppSettings::getInstance().getSecureStorage(); secureStorage.load(); -#if defined(Q_OS_WIN) || defined(Q_OS_OSX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) auto url = VersionNumber::getApplicationVersion().isDeveloperVersion() ? secureStorage.getAppcastBetaUpdateUrl() : secureStorage.getAppcastUpdateUrl(); - FvUpdater::sharedUpdater()->SetFeedURL(url); + AppUpdateService::getInstance().setUpdateUrl(url); + AppUpdateService::getInstance().setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); + connect(&AppUpdateService::getInstance(), &AppUpdateService::fireAppUpdateCheckFinished, this, &Updater::fireAppUpdateCheckFinished); +#if defined(Q_OS_WIN) || defined(Q_OS_OSX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) // qDebug() << "Driver update url =" << secureStorage.getDriverUpdateUrl(); - // DriverService::getSharedInstance()->setUpdateUrl(secureStorage.getDriverUpdateUrl()); - // DriverService::getSharedInstance()->setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); + // DriverService::getInstance().setUpdateUrl(secureStorage.getDriverUpdateUrl()); + // DriverService::getInstance().setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); #endif qDebug() << "Provider update url =" << secureStorage.getProviderUpdateUrl(); - ProviderService::getSharedInstance()->setUpdateUrl(secureStorage.getProviderUpdateUrl()); - ProviderService::getSharedInstance()->setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); - connect(ProviderService::getSharedInstance(), &UpdateService::fireUpdateFinished, this, &Updater::onUpdateProviderSettingsFinished); + ProviderService::getInstance().setUpdateUrl(secureStorage.getProviderUpdateUrl()); + ProviderService::getInstance().setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); + connect(&ProviderService::getInstance(), &UpdateService::fireUpdateFinished, this, &Updater::onUpdateProviderSettingsFinished); mIconCache.init(); mIconCache.setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); @@ -65,20 +64,9 @@ void Updater::update() } -void Updater::checkAppUpdate(bool pSilent) +void Updater::checkAppUpdate() { -#if defined(Q_OS_WIN) || defined(Q_OS_OSX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - if (pSilent) - { - FvUpdater::sharedUpdater()->CheckForUpdatesSilent(); - } - else - { - FvUpdater::sharedUpdater()->CheckForUpdatesNotSilent(); - } -#else - Q_UNUSED(pSilent) -#endif + AppUpdateService::getInstance().runUpdate(); } @@ -88,13 +76,25 @@ const IconCache& Updater::getIconCache() const } +const AppUpdateData& Updater::getUpdateData() const +{ + return AppUpdateService::getInstance().getUpdateData(); +} + + +void Updater::skipVersion(const QString& pVersion) +{ + AppUpdateService::getInstance().skipVersion(pVersion); +} + + void Updater::doUpdateRemoteSettings() { #if defined(Q_OS_WIN) || defined(Q_OS_OSX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - // DriverService::getSharedInstance()->runUpdate(); + // DriverService::getInstance().runUpdate(); #endif - ProviderService::getSharedInstance()->runUpdate(); + ProviderService::getInstance().runUpdate(); } diff --git a/src/services/Updater.h b/src/services/Updater.h index 9131e3a..a4c3941 100644 --- a/src/services/Updater.h +++ b/src/services/Updater.h @@ -4,6 +4,7 @@ #pragma once +#include "AppUpdateData.h" #include "IconCache.h" namespace governikus @@ -23,12 +24,17 @@ class Updater static Updater& getInstance(); void update(); - void checkAppUpdate(bool pSilent = false); + void checkAppUpdate(); const IconCache& getIconCache() const; + const AppUpdateData& getUpdateData() const; + void skipVersion(const QString& pVersion); private Q_SLOTS: void onUpdateProviderSettingsFinished(); void doUpdateRemoteSettings(); + + Q_SIGNALS: + void fireAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError); }; } /* namespace governikus */ diff --git a/src/settings/AppSettings.cpp b/src/settings/AppSettings.cpp index cf42b21..ced3ee8 100644 --- a/src/settings/AppSettings.cpp +++ b/src/settings/AppSettings.cpp @@ -19,16 +19,17 @@ AppSettings::AppSettings() , mGeneralSettings() , mPreVerificationSettings() , mProviderSettings() - , mProxySettings() , mSecureStorage() , mHistorySettings() + , mRemoteReaderSettings() { connect(&mDriverSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); connect(&mGeneralSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); connect(&mPreVerificationSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); connect(&mProviderSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); - connect(&mProxySettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); connect(&mHistorySettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); + connect(&mRemoteReaderSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); + } @@ -49,9 +50,9 @@ void AppSettings::load() mGeneralSettings.load(); mPreVerificationSettings.load(); mProviderSettings.load(); - mProxySettings.load(); mSecureStorage.load(); mHistorySettings.load(); + mRemoteReaderSettings.load(); } @@ -69,8 +70,8 @@ void AppSettings::save() mGeneralSettings.save(); mPreVerificationSettings.save(); mProviderSettings.save(); - mProxySettings.save(); mHistorySettings.save(); + mRemoteReaderSettings.save(); } @@ -98,12 +99,6 @@ ProviderSettings& AppSettings::getProviderSettings() } -ProxySettings& AppSettings::getProxySettings() -{ - return mProxySettings; -} - - SecureStorage& AppSettings::getSecureStorage() { return mSecureStorage; @@ -114,3 +109,9 @@ HistorySettings& AppSettings::getHistorySettings() { return mHistorySettings; } + + +RemoteReaderSettings& AppSettings::getRemoteReaderSettings() +{ + return mRemoteReaderSettings; +} diff --git a/src/settings/AppSettings.h b/src/settings/AppSettings.h index 212fa21..1bd5cbb 100644 --- a/src/settings/AppSettings.h +++ b/src/settings/AppSettings.h @@ -8,17 +8,17 @@ #pragma once -#include - #include "AbstractSettings.h" #include "DriverSettings.h" #include "GeneralSettings.h" #include "HistorySettings.h" #include "PreVerificationSettings.h" #include "ProviderSettings.h" -#include "ProxySettings.h" +#include "RemoteReaderSettings.h" #include "SecureStorage.h" +#include + class test_AppSettings; namespace governikus @@ -39,9 +39,9 @@ class AppSettings GeneralSettings mGeneralSettings; PreVerificationSettings mPreVerificationSettings; ProviderSettings mProviderSettings; - ProxySettings mProxySettings; SecureStorage mSecureStorage; HistorySettings mHistorySettings; + RemoteReaderSettings mRemoteReaderSettings; protected: AppSettings(); @@ -58,9 +58,9 @@ class AppSettings GeneralSettings& getGeneralSettings(); PreVerificationSettings& getPreVerificationSettings(); ProviderSettings& getProviderSettings(); - ProxySettings& getProxySettings(); SecureStorage& getSecureStorage(); HistorySettings& getHistorySettings(); + RemoteReaderSettings& getRemoteReaderSettings(); }; inline bool operator==(const AppSettings& pLeft, const AppSettings& pRight) @@ -70,9 +70,9 @@ inline bool operator==(const AppSettings& pLeft, const AppSettings& pRight) pLeft.mGeneralSettings == pRight.mGeneralSettings && pLeft.mPreVerificationSettings == pRight.mPreVerificationSettings && pLeft.mProviderSettings == pRight.mProviderSettings && - pLeft.mProxySettings == pRight.mProxySettings && pLeft.mSecureStorage == pRight.mSecureStorage && - pLeft.mHistorySettings == pRight.mHistorySettings); + pLeft.mHistorySettings == pRight.mHistorySettings && + pLeft.mRemoteReaderSettings == pRight.mRemoteReaderSettings); } diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt index b61e0a4..b7d3b93 100644 --- a/src/settings/CMakeLists.txt +++ b/src/settings/CMakeLists.txt @@ -5,3 +5,7 @@ TARGET_LINK_LIBRARIES(AusweisAppSettings Qt5::Network Qt5::Core AusweisAppGlobal IF(MAC) TARGET_LINK_LIBRARIES(AusweisAppSettings ${OSX_APPKIT}) ENDIF() + +IF(ANDROID) + TARGET_LINK_LIBRARIES(AusweisAppSettings Qt5::AndroidExtras) +ENDIF() diff --git a/src/settings/CallCost.cpp b/src/settings/CallCost.cpp new file mode 100644 index 0000000..31f656e --- /dev/null +++ b/src/settings/CallCost.cpp @@ -0,0 +1,85 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ +#include "CallCost.h" + +#include +#include + + +using namespace governikus; + + +CallCost::CallCost(int pFreeSeconds, double pLandlineCentsPerMinute, double pLandlineCentsPerCall, double pMobileCentsPerMinute, double pMobileCentsPerCall) + : mFreeSeconds(pFreeSeconds) + , mLandlineCentsPerMinute(pLandlineCentsPerMinute) + , mLandlineCentsPerCall(pLandlineCentsPerCall) + , mMobileCentsPerMinute(pMobileCentsPerMinute) + , mMobileCentsPerCall(pMobileCentsPerCall) +{ +} + + +CallCost::CallCost(const QJsonValue& pJson) + : mFreeSeconds(pJson.toObject()["free-seconds"].toInt()) + , mLandlineCentsPerMinute(pJson.toObject()["landline"].toObject()["per-minute"].toDouble()) + , mLandlineCentsPerCall(pJson.toObject()["landline"].toObject()["per-call"].toDouble()) + , mMobileCentsPerMinute(pJson.toObject()["mobile"].toObject()["per-minute"].toDouble()) + , mMobileCentsPerCall(pJson.toObject()["mobile"].toObject()["per-call"].toDouble()) +{ +} + + +bool CallCost::isNull() const +{ + return mFreeSeconds == 0 && mLandlineCentsPerMinute == 0.0 && mLandlineCentsPerCall == 0.0 && mMobileCentsPerMinute == 0.0 && mMobileCentsPerCall == 0.0; +} + + +int CallCost::getFreeSeconds() const +{ + return mFreeSeconds; +} + + +double CallCost::getLandlineCentsPerMinute() const +{ + return mLandlineCentsPerMinute; +} + + +double CallCost::getLandlineCentsPerCall() const +{ + return mLandlineCentsPerCall; +} + + +double CallCost::getMobileCentsPerMinute() const +{ + return mMobileCentsPerMinute; +} + + +double CallCost::getMobileCentsPerCall() const +{ + return mMobileCentsPerCall; +} + + +QDebug operator<<(QDebug pDbg, const CallCost& pCallCost) +{ + QDebugStateSaver saver(pDbg); + if (pCallCost.isNull()) + { + pDbg.nospace() << "CallCost(null)"; + } + else + { + pDbg.nospace() << "CallCost(free=" << pCallCost.getFreeSeconds() + << ", ll-call=" << pCallCost.getLandlineCentsPerCall() + << ", ll-min=" << pCallCost.getLandlineCentsPerMinute() + << ", mob-call=" << pCallCost.getMobileCentsPerCall() + << ", mob-min=" << pCallCost.getMobileCentsPerMinute() << ")"; + } + return pDbg; +} diff --git a/src/settings/CallCost.h b/src/settings/CallCost.h new file mode 100644 index 0000000..6c2e97e --- /dev/null +++ b/src/settings/CallCost.h @@ -0,0 +1,54 @@ +/*! + * \brief Phone call cost representation + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include + + +namespace governikus +{ + + +class CallCost +{ + friend bool operator==(const CallCost& pLeft, const CallCost& pRight); + + int mFreeSeconds; + double mLandlineCentsPerMinute, mLandlineCentsPerCall; + double mMobileCentsPerMinute, mMobileCentsPerCall; + + public: + CallCost(int pFreeSeconds = 0, double pLandlineCentsPerMinute = 0.0, double pLandlineCentsPerCall = 0.0, double pMobileCentsPerMinute = 0.0, double pMobileCentsPerCall = 0.0); + CallCost(const QJsonValue& pJson); + + void load(); + void save(); + + bool isNull() const; + int getFreeSeconds() const; + double getLandlineCentsPerMinute() const; + double getLandlineCentsPerCall() const; + double getMobileCentsPerMinute() const; + double getMobileCentsPerCall() const; +}; + + +inline bool operator==(const CallCost& pLeft, const CallCost& pRight) +{ + return &pLeft == &pRight || ( + pLeft.mFreeSeconds == pRight.mFreeSeconds && + pLeft.mLandlineCentsPerMinute == pRight.mLandlineCentsPerMinute && + pLeft.mLandlineCentsPerCall == pRight.mLandlineCentsPerCall && + pLeft.mMobileCentsPerMinute == pRight.mMobileCentsPerMinute && + pLeft.mMobileCentsPerCall == pRight.mMobileCentsPerCall); +} + + +} /* namespace governikus */ + +QDebug operator<<(QDebug pDbg, const governikus::CallCost& pCallCost); diff --git a/src/settings/DriverSettings.cpp b/src/settings/DriverSettings.cpp index 9ddbcdc..ad2ced6 100644 --- a/src/settings/DriverSettings.cpp +++ b/src/settings/DriverSettings.cpp @@ -181,7 +181,7 @@ void DriverSettings::save() void DriverSettings::update(const AbstractSettings& pOther) { - const DriverSettings* const other = dynamic_cast(&pOther); + const DriverSettings* const other = qobject_cast(&pOther); if (other != nullptr) { mIssueDate = other->getIssueDate(); diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index f941210..6701f04 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -18,12 +18,18 @@ #include #endif +#ifdef Q_OS_ANDROID +#include +#endif + #ifndef QT_NO_DEBUG static bool Test_AutoStart = GENERAL_SETTINGS_DEFAULT_AUTOSTART; #endif using namespace governikus; +const QLatin1String SETTINGS_SKIP_VERSION("skipVersion"); + const QLatin1String SETTINGS_NAME_AUTO_CLOSE_WINDOW("autoCloseWindow"); const QLatin1String SETTINGS_NAME_SHOW_SETUP_ASSISTANT("showSetupAssistant"); const QLatin1String SETTINGS_NAME_REMIND_USER_TO_CLOSE("remindToClose"); @@ -51,8 +57,8 @@ GeneralSettings::GeneralSettings() { // QFuture.result() crashes under linux and win if uninitalized mAutoStart = QtConcurrent::run([] { - return GENERAL_SETTINGS_DEFAULT_AUTOSTART; - }); + return GENERAL_SETTINGS_DEFAULT_AUTOSTART; + }); } @@ -319,8 +325,8 @@ void GeneralSettings::setAutoStart(bool pAutoStart) { mAutoStart.waitForFinished(); mAutoStart = QtConcurrent::run([pAutoStart] { - return pAutoStart; - }); + return pAutoStart; + }); Q_EMIT fireSettingsChanged(); } @@ -399,6 +405,16 @@ void GeneralSettings::setTransportPinReminder(bool pTransportPinReminder) bool GeneralSettings::isDeveloperMode() const { + // TODO Replace the following hack with a clean solution. + // Also remove "AndroidExtras" from module linkage. +#ifdef Q_OS_ANDROID + if (QtAndroid::androidService().isValid()) + { + qDebug() << "Running as android service. Developer mode is disallowed."; + return false; + } +#endif + return mDeveloperMode; } @@ -427,3 +443,17 @@ void GeneralSettings::setUseSelfauthenticationTestUri(bool pUse) Q_EMIT fireSettingsChanged(); } } + + +void GeneralSettings::skipVersion(const QString& pVersion) +{ + auto store = getStore(); + store->setValue(SETTINGS_SKIP_VERSION, pVersion); + store->sync(); +} + + +QString GeneralSettings::getSkipVersion() +{ + return getStore()->value(SETTINGS_SKIP_VERSION).toString(); +} diff --git a/src/settings/GeneralSettings.h b/src/settings/GeneralSettings.h index 76be1db..9a4af08 100644 --- a/src/settings/GeneralSettings.h +++ b/src/settings/GeneralSettings.h @@ -76,7 +76,7 @@ class GeneralSettings QString mPersistentSettingsVersion; /*! - * remind the user to change the transport pin before first authentication. + * remind the user to change the transport PIN before first authentication. */ bool mTransportPinReminder; @@ -95,6 +95,9 @@ class GeneralSettings GeneralSettings(); public: + static void skipVersion(const QString& pVersion); + static QString getSkipVersion(); + virtual ~GeneralSettings(); virtual void load() override; diff --git a/src/settings/HistorySettings.cpp b/src/settings/HistorySettings.cpp index ab77689..7080aa2 100644 --- a/src/settings/HistorySettings.cpp +++ b/src/settings/HistorySettings.cpp @@ -8,6 +8,11 @@ #include +#ifdef Q_OS_ANDROID +#include +#include +#endif + // names for settings groups/keys const QLatin1String SETTINGS_GROUP_NAME_CHRONIC("history"); @@ -113,7 +118,7 @@ void HistorySettings::load() QDateTime dateTime = QDateTime::fromString(settings->value(SETTINGS_NAME_CHRONIC_DATETIME, "").toString(), Qt::ISODate); QString termsOfUsage = settings->value(SETTINGS_NAME_CHRONIC_TOU, "").toString(); QString requestData = settings->value(SETTINGS_NAME_CHRONIC_REQUESTED_DATA, "").toString(); - items.append(HistoryEntry(subjectName, subjectUrl, usage, dateTime, termsOfUsage, requestData)); + items += HistoryEntry(subjectName, subjectUrl, usage, dateTime, termsOfUsage, requestData); } settings->endArray(); setHistoryEntries(items); @@ -165,7 +170,7 @@ void HistorySettings::deleteSettings(const QDateTime& pLatestToKeep) { if (!pLatestToKeep.isNull() && item.getDateTime() <= pLatestToKeep) { - remainingItems.append(item); + remainingItems += item; } } setHistoryEntries(remainingItems); @@ -206,6 +211,16 @@ void HistorySettings::setHistoryEntries(const QVector& pHistoryEnt void HistorySettings::addHistoryEntry(const HistoryEntry& pHistoryEntry) { + // TODO Replace the following hack with a clean solution. + // Also remove "AndroidExtras" from module linkage. +#ifdef Q_OS_ANDROID + if (QtAndroid::androidService().isValid()) + { + qDebug() << "Running as android service. Ignoring save request for history."; + return; + } +#endif + mHistoryEntries.prepend(pHistoryEntry); Q_EMIT fireHistoryEntriesChanged(); } diff --git a/src/settings/PreVerificationSettings.cpp b/src/settings/PreVerificationSettings.cpp index c100ab7..46cc939 100644 --- a/src/settings/PreVerificationSettings.cpp +++ b/src/settings/PreVerificationSettings.cpp @@ -38,7 +38,7 @@ void PreVerificationSettings::load() for (int i = 0; i < itemCount; ++i) { settings->setArrayIndex(i); - linkCertificates.append(settings->value(SETTINGS_NAME_LINKCERTIFICATE).toByteArray()); + linkCertificates += settings->value(SETTINGS_NAME_LINKCERTIFICATE).toByteArray(); } mLinkCertificates = linkCertificates; @@ -111,7 +111,7 @@ bool PreVerificationSettings::addLinkCertificate(const QByteArray& pCert) { return false; } - mLinkCertificates.append(pCert); + mLinkCertificates += pCert; Q_EMIT fireSettingsChanged(); return true; } diff --git a/src/settings/ProviderSettings.cpp b/src/settings/ProviderSettings.cpp index 22fa407..2feec89 100644 --- a/src/settings/ProviderSettings.cpp +++ b/src/settings/ProviderSettings.cpp @@ -8,6 +8,7 @@ #include "AppSettings.h" #include "VersionNumber.h" +#include #include using namespace governikus; @@ -29,6 +30,16 @@ const QLatin1String SETTINGS_NAME_EMAIL("email"); const QLatin1String SETTINGS_NAME_POSTALADDRESS("postalAddress"); const QLatin1String SETTINGS_NAME_ICON("icon"); const QLatin1String SETTINGS_NAME_IMAGE("image"); +const QLatin1String SETTINGS_NAME_TCTOKENURL("tcTokenUrl"); +const QLatin1String SETTINGS_NAME_CLIENTURL("clientUrl"); +const QLatin1String SETTINGS_NAME_SUBJECTURLS("subjectUrls"); +const QLatin1String SETTINGS_NAME_CALLCOSTS("callcosts"); +const QLatin1String SETTINGS_NAME_CALLCOST_PREFIX("prefix"); +const QLatin1String SETTINGS_NAME_CALLCOST_FREESECS("free-seconds"); +const QLatin1String SETTINGS_NAME_CALLCOST_LANDLINE_PER_MIN("landline-per-minute"); +const QLatin1String SETTINGS_NAME_CALLCOST_LANDLINE_PER_CALL("landline-per-call"); +const QLatin1String SETTINGS_NAME_CALLCOST_MOB_PER_MIN("mobile-per-minute"); +const QLatin1String SETTINGS_NAME_CALLCOST_MOB_PER_CALL("mobile-per-call"); Provider::Provider(const LanguageString& pShortName, @@ -44,7 +55,8 @@ Provider::Provider(const LanguageString& pShortName, const QString& pIcon, const QString& pImage, const QString& pTcTokenUrl, - const QString& pClientUrl) + const QString& pClientUrl, + const QStringList& pSubjectUrls) : mShortName(pShortName) , mLongName(pLongName) , mShortDescription(pShortDescription) @@ -61,6 +73,7 @@ Provider::Provider(const LanguageString& pShortName, , mLocalImageUrl() , mTcTokenUrl(pTcTokenUrl) , mClientUrl(pClientUrl) + , mSubjectUrls(pSubjectUrls) { } @@ -97,15 +110,7 @@ const QString& Provider::getAddress() const QString Provider::getAddressDomain() const { - if (mAddress.isNull()) - { - return QString(); - } - else - { - auto domain = mAddress.split('/'); - return domain[0] + QLatin1String("//") + domain[2]; - } + return QUrl::fromUserInput(mAddress).host(); } @@ -117,17 +122,7 @@ const QString& Provider::getHomepage() const QString Provider::getHomepageBase() const { - const auto chunks = mHomepage.split('/'); - if (chunks[0] == QLatin1String("https:") || chunks[0] == QLatin1String("http:")) - { - Q_ASSERT(chunks.size() >= 3); - - return chunks[2]; - } - else - { - return chunks[0]; - } + return QUrl::fromUserInput(mHomepage).host(); } @@ -191,6 +186,12 @@ const QString& Provider::getClientUrl() const } +const QStringList& Provider::getSubjectUrls() const +{ + return mSubjectUrls; +} + + void Provider::setTcTokenUrl(const QString& pTcTokenUrl) { mTcTokenUrl = pTcTokenUrl; @@ -225,9 +226,11 @@ ProviderSettings::ProviderSettings() , mIssueDate() , mProviders() , mIconMap() + , mCallCosts() { connect(this, &ProviderSettings::fireIssueDateChanged, this, &ProviderSettings::fireSettingsChanged); connect(this, &ProviderSettings::fireProvidersChanged, this, &ProviderSettings::fireSettingsChanged); + connect(this, &ProviderSettings::fireCallCostsChanged, this, &ProviderSettings::fireSettingsChanged); } @@ -255,16 +258,22 @@ QStringList ProviderSettings::getRequiredIcons() const } +#ifndef QT_NO_DEBUG + + ProviderSettings::ProviderSettings(const QDateTime& pIssueDate, const QVector& pProviders) : AbstractSettings() , mIssueDate(pIssueDate) , mProviders(pProviders) , mIconMap() + , mCallCosts() { - Q_EMIT fireRequiredIcons(getRequiredIcons()); } +#endif + + ProviderSettings::~ProviderSettings() { } @@ -304,6 +313,10 @@ void ProviderSettings::load() const QString postalAddress = getSettingsValue(settings, SETTINGS_NAME_POSTALADDRESS).toString(); const QString icon = getSettingsValue(settings, SETTINGS_NAME_ICON).toString(); const QString image = getSettingsValue(settings, SETTINGS_NAME_IMAGE).toString(); + const QString tcTokenUrl = getSettingsValue(settings, SETTINGS_NAME_TCTOKENURL).toString(); + const QString clientUrl = getSettingsValue(settings, SETTINGS_NAME_CLIENTURL).toString(); + const QStringList subjectUrls = getSettingsValue(settings, SETTINGS_NAME_SUBJECTURLS).toStringList(); + providers += Provider(shortName, longName, shortDescription, @@ -315,13 +328,33 @@ void ProviderSettings::load() email, postalAddress, icon, - image); + image, + tcTokenUrl, + clientUrl, + subjectUrls); } settings->endArray(); setProviders(providers); setIssueDate(settings->value(SETTINGS_NAME_ISSUEDATE).toDateTime()); + const int callCostListSize = settings->beginReadArray(SETTINGS_NAME_CALLCOSTS); + QMap callCosts; + providers.reserve(listSize); + for (int i = 0; i < callCostListSize; ++i) + { + settings->setArrayIndex(i); + const int freeSeconds = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_FREESECS).toInt(); + const double landlinePerMin = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_LANDLINE_PER_MIN).toDouble(); + const double landlinePerCall = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_LANDLINE_PER_CALL).toDouble(); + const double mobilePerMin = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_MOB_PER_MIN).toDouble(); + const double mobilePerCall = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_MOB_PER_CALL).toDouble(); + const QString prefix = getSettingsValue(settings, SETTINGS_NAME_CALLCOST_PREFIX).toString(); + callCosts.insert(prefix, CallCost(freeSeconds, landlinePerMin, landlinePerCall, mobilePerMin, mobilePerCall)); + } + settings->endArray(); + setCallCosts(callCosts); + settings->endGroup(); } @@ -395,9 +428,30 @@ void ProviderSettings::save() settings->setValue(SETTINGS_NAME_POSTALADDRESS, provider.getPostalAddress()); settings->setValue(SETTINGS_NAME_ICON, provider.getIcon()); settings->setValue(SETTINGS_NAME_IMAGE, provider.getImage()); + settings->setValue(SETTINGS_NAME_TCTOKENURL, provider.getTcTokenUrl()); + settings->setValue(SETTINGS_NAME_CLIENTURL, provider.getClientUrl()); + settings->setValue(SETTINGS_NAME_SUBJECTURLS, provider.getSubjectUrls()); } settings->endArray(); + settings->beginWriteArray(SETTINGS_NAME_CALLCOSTS); + const auto& prefixes = mCallCosts.keys(); + for (int i = 0; i < prefixes.size(); ++i) + { + settings->setArrayIndex(i); + const auto& prefix = prefixes.at(i); + const auto callCost = mCallCosts.value(prefix); + + settings->setValue(SETTINGS_NAME_CALLCOST_FREESECS, callCost.getFreeSeconds()); + settings->setValue(SETTINGS_NAME_CALLCOST_LANDLINE_PER_MIN, callCost.getLandlineCentsPerMinute()); + settings->setValue(SETTINGS_NAME_CALLCOST_LANDLINE_PER_CALL, callCost.getLandlineCentsPerCall()); + settings->setValue(SETTINGS_NAME_CALLCOST_MOB_PER_MIN, callCost.getMobileCentsPerMinute()); + settings->setValue(SETTINGS_NAME_CALLCOST_MOB_PER_CALL, callCost.getMobileCentsPerCall()); + settings->setValue(SETTINGS_NAME_CALLCOST_PREFIX, prefix); + } + settings->endArray(); + + settings->setValue(SETTINGS_NAME_ISSUEDATE, mIssueDate); settings->endGroup(); @@ -407,11 +461,12 @@ void ProviderSettings::save() void ProviderSettings::update(const AbstractSettings& pOther) { - const ProviderSettings* const other = dynamic_cast(&pOther); + const ProviderSettings* const other = qobject_cast(&pOther); if (other != nullptr) { mIssueDate = other->getIssueDate(); setProviders(other->getProviders()); + setCallCosts(other->getCallCosts()); } } @@ -451,6 +506,49 @@ void ProviderSettings::setProviders(const QVector& pProviders) } +void ProviderSettings::setCallCosts(const QMap& pCallCosts) +{ + if (mCallCosts != pCallCosts) + { + mCallCosts = pCallCosts; + Q_EMIT fireCallCostsChanged(); + } +} + + +const QMap& ProviderSettings::getCallCosts() const +{ + return mCallCosts; +} + + +CallCost ProviderSettings::getCallCost(const Provider& pProvider) const +{ + return getCallCost(pProvider.getPhone()); +} + + +CallCost ProviderSettings::getCallCost(const QString& pProviderPhone) const +{ + QString standardisedPhoneNumber = pProviderPhone; + standardisedPhoneNumber = standardisedPhoneNumber.remove(QLatin1String("+49")); + standardisedPhoneNumber = standardisedPhoneNumber.remove(QRegularExpression("[^\\d]")); + + if (!standardisedPhoneNumber.isEmpty()) + { + const auto& prefixes = mCallCosts.keys(); + for (const auto& prefix : prefixes) + { + if (standardisedPhoneNumber.startsWith(prefix)) + { + return mCallCosts[prefix]; + } + } + } + return CallCost(); +} + + void ProviderSettings::requestIconMap() { Q_EMIT fireRequiredIcons(getRequiredIcons()); diff --git a/src/settings/ProviderSettings.h b/src/settings/ProviderSettings.h index 14d4f12..9ab1a3f 100644 --- a/src/settings/ProviderSettings.h +++ b/src/settings/ProviderSettings.h @@ -5,6 +5,7 @@ #pragma once #include "AbstractSettings.h" +#include "CallCost.h" #include "LanguageString.h" #include @@ -40,6 +41,7 @@ class Provider QString mLocalImageUrl; QString mTcTokenUrl; QString mClientUrl; + QStringList mSubjectUrls; public: Provider(const LanguageString& pShortName = QString(), @@ -55,7 +57,9 @@ class Provider const QString& pIcon = QString(), const QString& pImage = QString(), const QString& pTcTokenUrl = QString(), - const QString& pClientUrl = QString()); + const QString& pClientUrl = QString(), + const QStringList& pSubjectUrls = QStringList() + ); const LanguageString& getShortName() const; const LanguageString& getLongName() const; @@ -75,6 +79,7 @@ class Provider const QString& getImageUrl() const; const QString& getTcTokenUrl() const; const QString& getClientUrl() const; + const QStringList& getSubjectUrls() const; void setTcTokenUrl(const QString& pTcTokenUrl); @@ -114,12 +119,14 @@ class ProviderSettings friend class AppSettings; friend class ProviderParser; friend class::test_ProviderSettings; + friend class::test_ProviderParser; friend bool operator==(const ProviderSettings& pLeft, const ProviderSettings& pRight); private: QDateTime mIssueDate; QVector mProviders; QMap mIconMap; + QMap mCallCosts; // Use mIconMap to update icon and image urls in all providers. void applyMap(); @@ -127,11 +134,16 @@ class ProviderSettings QStringList getRequiredIcons() const; ProviderSettings(); + #ifndef QT_NO_DEBUG + // This constructor is only for use in testcases ProviderSettings(const QDateTime& pIssueDate, const QVector& pProviders); + #endif static void save(QSharedPointer& pSettings, const QString& pGroupName, LanguageString const& pLanguageString); static LanguageString load(const QSharedPointer& pSettings, const QString& pGroupName); + CallCost getCallCost(const QString& pProviderPhone) const; + public: virtual ~ProviderSettings(); @@ -149,6 +161,11 @@ class ProviderSettings const QVector& getProviders() const; void setProviders(const QVector& pProviders); + void setCallCosts(const QMap& pCallCosts); + const QMap& getCallCosts() const; + + CallCost getCallCost(const Provider& pProvider) const; + void requestIconMap(); public Q_SLOTS: @@ -156,10 +173,9 @@ class ProviderSettings Q_SIGNALS: void fireIssueDateChanged(); - void fireProvidersChanged(); - void fireRequiredIcons(const QStringList& pIcons); + void fireCallCostsChanged(); }; inline bool operator==(const ProviderSettings& pLeft, const ProviderSettings& pRight) @@ -167,7 +183,8 @@ inline bool operator==(const ProviderSettings& pLeft, const ProviderSettings& pR return &pLeft == &pRight || ( pLeft.mIssueDate == pRight.mIssueDate && pLeft.mProviders == pRight.mProviders && - pLeft.mIconMap == pRight.mIconMap); + pLeft.mIconMap == pRight.mIconMap && + pLeft.mCallCosts == pRight.mCallCosts); } diff --git a/src/settings/ProxySettings.cpp b/src/settings/ProxySettings.cpp deleted file mode 100644 index 8c5a978..0000000 --- a/src/settings/ProxySettings.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/*! - * ProxySettings.cpp - * - * \brief Contains the method definitions of the ProxySettings class. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProxySettings.h" - -using namespace governikus; - - -const QLatin1String SETTINGS_GROUP_NAME_PROXY("proxy"); -const QLatin1String SETTINGS_NAME_PROXY_TYPE("type"); - -const QLatin1String SETTINGS_PROXY_TYPE_NAME_NONE("none"); -const QLatin1String SETTINGS_PROXY_TYPE_NAME_SYSTEM("system"); - - -ProxySettings::ProxySettings() - : AbstractSettings() - , mProxyType(QNetworkProxy::DefaultProxy) -{ -} - - -ProxySettings::~ProxySettings() -{ -} - - -QNetworkProxy::ProxyType ProxySettings::getProxyType() const -{ - return mProxyType; -} - - -void ProxySettings::setProxyType(QNetworkProxy::ProxyType pProxyType) -{ - if (pProxyType != mProxyType) - { - mProxyType = pProxyType; - Q_EMIT fireSettingsChanged(); - } -} - - -void ProxySettings::load() -{ - //use system proxy only - return; - - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_PROXY); - - QString proxyTypeName = settings->value(SETTINGS_NAME_PROXY_TYPE, QString()).toString(); - if (proxyTypeName == SETTINGS_PROXY_TYPE_NAME_NONE) - { - mProxyType = QNetworkProxy::NoProxy; - } - else if (proxyTypeName == SETTINGS_PROXY_TYPE_NAME_SYSTEM) - { - mProxyType = QNetworkProxy::DefaultProxy; - } - settings->endGroup(); -} - - -bool ProxySettings::isUnsaved() const -{ - ProxySettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - -void ProxySettings::save() -{ - //use system proxy only - return; - - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_PROXY); - settings->remove(QString()); // remove the whole group first - - auto proxyTypeName = mProxyType == QNetworkProxy::NoProxy ? SETTINGS_PROXY_TYPE_NAME_NONE : SETTINGS_PROXY_TYPE_NAME_SYSTEM; - settings->setValue(SETTINGS_NAME_PROXY_TYPE, proxyTypeName); - - settings->endGroup(); - settings->sync(); -} diff --git a/src/settings/ProxySettings.h b/src/settings/ProxySettings.h deleted file mode 100644 index 926265e..0000000 --- a/src/settings/ProxySettings.h +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * ProxySettings.h - * - * \brief Contains the definition of the ProxySettings class. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractSettings.h" - -#include -#include -#include - - -class test_ProxySettings; - - -namespace governikus -{ - -/*! - * \brief Represents proxy server settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ -class ProxySettings - : public AbstractSettings -{ - Q_OBJECT - - friend class AppSettings; - friend class::test_ProxySettings; - - private: - QNetworkProxy::ProxyType mProxyType; - ProxySettings(); - - public: - virtual ~ProxySettings(); - - QNetworkProxy::ProxyType getProxyType() const; - void setProxyType(QNetworkProxy::ProxyType pProxyType); - - virtual void load() override; - virtual bool isUnsaved() const override; - virtual void save() override; -}; - -inline bool operator==(const ProxySettings& pLeft, const ProxySettings& pRight) -{ - return &pLeft == &pRight || pLeft.getProxyType() == pRight.getProxyType(); -} - - -inline bool operator!=(const ProxySettings& pLeft, const ProxySettings& pRight) -{ - return !(pLeft == pRight); -} - - -} /* namespace governikus */ diff --git a/src/settings/RemoteReaderSettings.cpp b/src/settings/RemoteReaderSettings.cpp new file mode 100644 index 0000000..96f18ec --- /dev/null +++ b/src/settings/RemoteReaderSettings.cpp @@ -0,0 +1,98 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "RemoteReaderSettings.h" + +using namespace governikus; + +// names for settings groups/keys +const QLatin1String SETTINGS_GROUP_NAME_REMOTEREADER("remotereader"); +const QLatin1String SETTINGS_NAME_DEVICE_NAME("serverName"); +const QLatin1String SETTINGS_NAME_USE_ENCRYPTION("useEncryption"); +const QLatin1String SETTINGS_NAME_PASSWORD("password"); + + +RemoteReaderSettings::RemoteReaderSettings() + : AbstractSettings() + , mServerName(QLatin1String("RemoteReader")) + , mUseEncryption(false) + , mPassword("") +{ +} + + +RemoteReaderSettings::~RemoteReaderSettings() +{ +} + + +void RemoteReaderSettings::load() +{ + auto settings = getStore(); + + settings->beginGroup(SETTINGS_GROUP_NAME_REMOTEREADER); + mServerName = settings->value(SETTINGS_NAME_DEVICE_NAME, mServerName).toString(); + mUseEncryption = settings->value(SETTINGS_NAME_USE_ENCRYPTION, mUseEncryption).toBool(); + mPassword = settings->value(SETTINGS_NAME_PASSWORD, mPassword).toString(); + settings->endGroup(); +} + + +bool RemoteReaderSettings::isUnsaved() const +{ + RemoteReaderSettings oldSettings; + oldSettings.load(); + return oldSettings != *this; +} + + +void RemoteReaderSettings::save() +{ + auto settings = getStore(); + + settings->beginGroup(SETTINGS_GROUP_NAME_REMOTEREADER); + settings->remove(QString()); // remove the whole group first + settings->setValue(SETTINGS_NAME_DEVICE_NAME, mServerName); + settings->setValue(SETTINGS_NAME_USE_ENCRYPTION, mUseEncryption); + settings->setValue(SETTINGS_NAME_PASSWORD, mPassword); + settings->endGroup(); + + settings->sync(); +} + + +QString RemoteReaderSettings::getServerName() const +{ + return mServerName; +} + + +void RemoteReaderSettings::setServerName(const QString& pName) +{ + mServerName = pName; +} + + +bool RemoteReaderSettings::useEncryption() const +{ + return mUseEncryption; +} + + +void RemoteReaderSettings::setEncryption(bool pEnabled) +{ + mUseEncryption = pEnabled; +} + + +QString RemoteReaderSettings::getPassword() const +{ + return mPassword; +} + + +void RemoteReaderSettings::setPassword(const QString& pPassword) +{ + mPassword = pPassword; +} diff --git a/src/settings/RemoteReaderSettings.h b/src/settings/RemoteReaderSettings.h new file mode 100644 index 0000000..08a51ba --- /dev/null +++ b/src/settings/RemoteReaderSettings.h @@ -0,0 +1,64 @@ +/*! + * \brief Remotereader settings + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AbstractSettings.h" + +#include + +class test_RemoteReaderSettings; + +namespace governikus +{ + +class RemoteReaderSettings + : public AbstractSettings +{ + Q_OBJECT + + friend class AppSettings; + friend class::test_RemoteReaderSettings; + + private: + QString mServerName; + bool mUseEncryption; + QString mPassword; + + RemoteReaderSettings(); + + public: + virtual ~RemoteReaderSettings(); + + virtual void load() override; + virtual bool isUnsaved() const override; + virtual void save() override; + + QString getServerName() const; + void setServerName(const QString& pName); + bool useEncryption() const; + void setEncryption(bool pEnabled); + QString getPassword() const; + void setPassword(const QString& pPassword); + +}; + +inline bool operator==(const RemoteReaderSettings& pLeft, const RemoteReaderSettings& pRight) +{ + return &pLeft == &pRight || ( + pLeft.getServerName() == pRight.getServerName() && + pLeft.useEncryption() == pRight.useEncryption() && + pLeft.getPassword() == pRight.getPassword()); +} + + +inline bool operator!=(const RemoteReaderSettings& pLeft, const RemoteReaderSettings& pRight) +{ + return !(pLeft == pRight); +} + + +} /* namespace governikus */ diff --git a/src/settings/SecureStorage.cpp b/src/settings/SecureStorage.cpp index b711307..46967a9 100644 --- a/src/settings/SecureStorage.cpp +++ b/src/settings/SecureStorage.cpp @@ -23,15 +23,10 @@ const QLatin1String SETTINGS_GROUP_NAME_CV_ROOT_CERTIFICATE_TEST("cvRootCertific const QLatin1String SETTINGS_GROUP_NAME_UPDATE_CERTIFICATES("updateCertificates"); -const QLatin1String SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS("signatureAlgorithms"); -const QLatin1String SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS_PSK("signatureAlgorithmsPsk"); - -const QLatin1String SETTINGS_GROUP_NAME_ALLOWED_ECS("ecCiphers"); -const QLatin1String SETTINGS_GROUP_NAME_PSK_CIPHERS("pskCiphers"); -const QLatin1String SETTINGS_GROUP_NAME_FS_CIPHERS("fsCiphers"); -const QLatin1String SETTINGS_GROUP_NAME_FS_CIPHERS_WITH_BACKWARD_COMPATIBILITY("fsCiphersWithBc"); -const QLatin1String SETTINGS_NAME_SSL_PROTOCOL_VERSION("sslProtocolVersion"); -const QLatin1String SETTINGS_NAME_SSL_PROTOCOL_VERSION_PSK("sslProtocolVersionPsk"); +const QLatin1String SETTINGS_GROUP_NAME_TLS_SETTINGS("tlsSettings"); +const QLatin1String SETTINGS_GROUP_NAME_TLS_SETTINGS_PSK("tlsSettingsPsk"); +const QLatin1String SETTINGS_GROUP_NAME_MIN_STATIC_KEY_SIZES("minStaticKeySizes"); +const QLatin1String SETTINGS_GROUP_NAME_MIN_EPHEMERAL_KEY_SIZES("minEphemeralKeySizes"); const QLatin1String SETTINGS_GROUP_NAME_SELF_AUTHENTICATION("selfAuthentication"); const QLatin1String SETTINGS_NAME_SELF_AUTHENTICATION_URL("url"); @@ -64,14 +59,8 @@ SecureStorage::SecureStorage() , mSelfAuthenticationTestCertDescr() , mAppcastUpdateUrl() , mAppcastBetaUpdateUrl() - , mAllowedSslEllipticCurves() - , mPskCiphers() - , mCiphersWithForwardSecrecy() - , mCiphersWithSha1ForBackwardCompatibility() - , mProtocolVersion(QSsl::SslProtocol::SecureProtocols) - , mProtocolVersionPsk(QSsl::SslProtocol::SecureProtocols) - , mSignatureAlgorithms() - , mSignatureAlgorithmsPsk() + , mTlsSettings() + , mTlsSettingsPsk() { } @@ -133,58 +122,20 @@ void SecureStorage::load() mUpdateCertificates += certificate; } - mAllowedSslEllipticCurves.clear(); - QJsonArray allowedEcs; - if (readJsonArray(allowedEcs, config, SETTINGS_GROUP_NAME_ALLOWED_ECS)) + QJsonValue tlsValue = config.value(SETTINGS_GROUP_NAME_TLS_SETTINGS); + if (!tlsValue.isUndefined()) { - for (const QJsonValue& line : qAsConst(allowedEcs)) - { - mAllowedSslEllipticCurves += line.toString(); - } + mTlsSettings.load(tlsValue.toObject()); } - mPskCiphers.clear(); - QJsonArray pskCiphers; - if (readJsonArray(pskCiphers, config, SETTINGS_GROUP_NAME_PSK_CIPHERS)) + QJsonValue tlsPskValue = config.value(SETTINGS_GROUP_NAME_TLS_SETTINGS_PSK); + if (!tlsPskValue.isUndefined()) { - for (const QJsonValue& line : qAsConst(pskCiphers)) - { - mPskCiphers += line.toString(); - } + mTlsSettingsPsk.load(tlsPskValue.toObject()); } + mMinStaticKeySizes = readKeySizes(config, SETTINGS_GROUP_NAME_MIN_STATIC_KEY_SIZES); + mMinEphemeralKeySizes = readKeySizes(config, SETTINGS_GROUP_NAME_MIN_EPHEMERAL_KEY_SIZES); - mCiphersWithForwardSecrecy.clear(); - QJsonArray fsCiphers; - if (readJsonArray(fsCiphers, config, SETTINGS_GROUP_NAME_FS_CIPHERS)) - { - for (const QJsonValue& line : qAsConst(fsCiphers)) - { - mCiphersWithForwardSecrecy += line.toString(); - } - } - - mCiphersWithSha1ForBackwardCompatibility.clear(); - QJsonArray fsCiphersWithBc; - if (readJsonArray(fsCiphersWithBc, config, SETTINGS_GROUP_NAME_FS_CIPHERS_WITH_BACKWARD_COMPATIBILITY)) - { - for (const QJsonValue& line : qAsConst(fsCiphersWithBc)) - { - mCiphersWithSha1ForBackwardCompatibility += line.toString(); - } - } - mProtocolVersion = readSslProtocol(config, SETTINGS_NAME_SSL_PROTOCOL_VERSION); - mProtocolVersionPsk = readSslProtocol(config, SETTINGS_NAME_SSL_PROTOCOL_VERSION_PSK); - - mSignatureAlgorithms = readSignatureAlgorithms(config, SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS); - if (mSignatureAlgorithms.isEmpty()) - { - qWarning() << "Using default for" << SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS; - } - mSignatureAlgorithmsPsk = readSignatureAlgorithms(config, SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS_PSK); - if (mSignatureAlgorithmsPsk.isEmpty()) - { - qWarning() << "Using default for" << SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS_PSK; - } mSelfAuthenticationUrl = readGroup(config, SETTINGS_GROUP_NAME_SELF_AUTHENTICATION, SETTINGS_NAME_SELF_AUTHENTICATION_URL); mSelfAuthenticationTestUrl = readGroup(config, SETTINGS_GROUP_NAME_SELF_AUTHENTICATION, SETTINGS_NAME_SELF_AUTHENTICATION_TEST_URL); @@ -258,51 +209,35 @@ const QUrl& SecureStorage::getAppcastBetaUpdateUrl() const } -const QVector& SecureStorage::getAllowedSslEllipticCurves() const +const TlsSettings& SecureStorage::getTlsSettings() const { - return mAllowedSslEllipticCurves; + return mTlsSettings; } -const QVector& SecureStorage::getCiphersWithPsk() const +const TlsSettings& SecureStorage::getTlsSettingsPsk() const { - return mPskCiphers; + return mTlsSettingsPsk; } -const QVector& SecureStorage::getCiphersWithForwardSecrecy() const +int SecureStorage::getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const { - return mCiphersWithForwardSecrecy; + if (!mMinStaticKeySizes.contains(pKeyAlgorithm)) + { + qWarning() << "No minimum ephemeral key size specified, returning default"; + } + return mMinStaticKeySizes.value(pKeyAlgorithm, 0); } -const QVector& SecureStorage::getCiphersWithSha1ForBackwardCompatibility() const +int SecureStorage::getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const { - return mCiphersWithSha1ForBackwardCompatibility; -} - - -QSsl::SslProtocol SecureStorage::getSslProtocolVersion() const -{ - return mProtocolVersion; -} - - -QSsl::SslProtocol SecureStorage::getSslProtocolVersionPsk() const -{ - return mProtocolVersionPsk; -} - - -const QVector& SecureStorage::getSignatureAlgorithms() const -{ - return mSignatureAlgorithms; -} - - -const QVector& SecureStorage::getSignatureAlgorithmsPsk() const -{ - return mSignatureAlgorithmsPsk; + if (!mMinEphemeralKeySizes.contains(pKeyAlgorithm)) + { + qWarning() << "No minimum ephemeral key size specified, returning default"; + } + return mMinEphemeralKeySizes.value(pKeyAlgorithm, 0); } @@ -340,76 +275,35 @@ QString SecureStorage::readGroup(const QJsonObject& pConfig, const QLatin1String } -QSsl::SslProtocol SecureStorage::readSslProtocol(const QJsonObject& pConfig, const QLatin1String& pName) +QMap SecureStorage::readKeySizes(const QJsonObject& pConfig, const QLatin1String& pKey) { - const auto& value = pConfig.value(pName).toString(); - if (value == QLatin1String("TlsV1_0OrLater")) + QMap keySizes; + const auto& object = pConfig.value(pKey).toObject(); + if (!object.isEmpty()) { - return QSsl::SslProtocol::TlsV1_0OrLater; - } - if (value == QLatin1String("TlsV1_1OrLater")) - { - return QSsl::SslProtocol::TlsV1_1OrLater; - } - if (value == QLatin1String("TlsV1_2OrLater")) - { - return QSsl::SslProtocol::TlsV1_2OrLater; - } - qCritical() << pName << ": Unsupported TLS protocol version detected" << value; - qCritical() << "Returning default \"SecureProtocols\""; - return QSsl::SslProtocol::SecureProtocols; -} - - -QVector SecureStorage::readSignatureAlgorithms(const QJsonObject& pConfig, const QLatin1String& pKey) -{ - const QJsonValue& tmp = pConfig[pKey]; - if (tmp.isUndefined() || !tmp.isArray()) - { - qCritical() << pKey << "is malformed"; - return QVector(); - } - const QJsonArray& array = tmp.toArray(); - - QVector algorithms; - for (const QJsonValue& line : array) - { - const auto& parts = line.toString().split(QLatin1Char('+')); - if (parts.size() != 2) + const auto& keys = object.keys(); + for (const QString& key : keys) { - qCritical() << pKey << "has malformed item" << line; - return QVector(); - } - - static const auto& hashMetaEnum = QMetaEnum::fromType(); - bool hashConversionSuccessfull; - const int hashInt = hashMetaEnum.keyToValue(parts[1].toLatin1().constData(), &hashConversionSuccessfull); - if (!hashConversionSuccessfull) - { - qCritical() << "Not a hash algorithm" << parts[1]; - return QVector(); - } - auto hash = static_cast(hashInt); - - if (parts[0] == QLatin1String("Rsa")) - { - algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Rsa, hash); - } - else if (parts[0] == QLatin1String("Dsa")) - { - algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Dsa, hash); - } - else if (parts[0] == QLatin1String("Ec")) - { - algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Ec, hash); - } - else - { - qCritical() << "Not a signature algorithm" << parts[0]; - return QVector(); + const auto value = object.value(key).toInt(0); + if (key == QLatin1String("Rsa")) + { + keySizes.insert(QSsl::KeyAlgorithm::Rsa, value); + } + else if (key == QLatin1String("Dsa")) + { + keySizes.insert(QSsl::KeyAlgorithm::Dsa, value); + } + else if (key == QLatin1String("Ec")) + { + keySizes.insert(QSsl::KeyAlgorithm::Ec, value); + } + else + { + qCritical() << "Ignore unknown key type" << key; + } } } - return algorithms; + return keySizes; } diff --git a/src/settings/SecureStorage.h b/src/settings/SecureStorage.h index c05f627..9a77cd8 100644 --- a/src/settings/SecureStorage.h +++ b/src/settings/SecureStorage.h @@ -10,6 +10,7 @@ #pragma once #include "AbstractSettings.h" +#include "TlsSettings.h" #include #include @@ -51,21 +52,16 @@ class SecureStorage final QUrl mAppcastUpdateUrl; QUrl mAppcastBetaUpdateUrl; - QVector mAllowedSslEllipticCurves; - QVector mPskCiphers; - QVector mCiphersWithForwardSecrecy; - QVector mCiphersWithSha1ForBackwardCompatibility; - QSsl::SslProtocol mProtocolVersion; - QSsl::SslProtocol mProtocolVersionPsk; - QVector mSignatureAlgorithms, mSignatureAlgorithmsPsk; + TlsSettings mTlsSettings, mTlsSettingsPsk; + QMap mMinStaticKeySizes; + QMap mMinEphemeralKeySizes; SecureStorage(); ~SecureStorage(); bool readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String& pName); QString readGroup(const QJsonObject& pConfig, const QLatin1String& pGroup, const QLatin1String& pName); - QSsl::SslProtocol readSslProtocol(const QJsonObject& pConfig, const QLatin1String& pName); - QVector readSignatureAlgorithms(const QJsonObject& pConfig, const QLatin1String& pKey); + QMap readKeySizes(const QJsonObject& pConfig, const QLatin1String& pKey); void readByteArrayList(QByteArrayList& pArray, const QJsonObject& pConfig, const QLatin1String& pName); public: @@ -80,14 +76,10 @@ class SecureStorage final const QString& getProviderIconUpdateUrlBase() const; const QUrl& getAppcastUpdateUrl() const; const QUrl& getAppcastBetaUpdateUrl() const; - const QVector& getAllowedSslEllipticCurves() const; - const QVector& getCiphersWithPsk() const; - const QVector& getCiphersWithForwardSecrecy() const; - const QVector& getCiphersWithSha1ForBackwardCompatibility() const; - QSsl::SslProtocol getSslProtocolVersion() const; - QSsl::SslProtocol getSslProtocolVersionPsk() const; - const QVector& getSignatureAlgorithms() const; - const QVector& getSignatureAlgorithmsPsk() const; + const TlsSettings& getTlsSettings() const; + const TlsSettings& getTlsSettingsPsk() const; + int getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; + int getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; }; inline bool operator==(const SecureStorage& pLeft, const SecureStorage& pRight) @@ -104,7 +96,11 @@ inline bool operator==(const SecureStorage& pLeft, const SecureStorage& pRight) pLeft.mSelfAuthenticationCertDescr == pRight.mSelfAuthenticationCertDescr && pLeft.mSelfAuthenticationTestCertDescr == pRight.mSelfAuthenticationTestCertDescr && pLeft.mAppcastUpdateUrl == pRight.mAppcastUpdateUrl && - pLeft.mAppcastBetaUpdateUrl == pRight.mAppcastBetaUpdateUrl); + pLeft.mAppcastBetaUpdateUrl == pRight.mAppcastBetaUpdateUrl && + pLeft.mTlsSettings == pRight.mTlsSettings && + pLeft.mTlsSettingsPsk == pRight.mTlsSettingsPsk && + pLeft.mMinStaticKeySizes == pRight.mMinStaticKeySizes && + pLeft.mMinEphemeralKeySizes == pRight.mMinEphemeralKeySizes); } diff --git a/src/settings/TlsSettings.cpp b/src/settings/TlsSettings.cpp new file mode 100644 index 0000000..f5f5561 --- /dev/null +++ b/src/settings/TlsSettings.cpp @@ -0,0 +1,230 @@ +/*! + * TlsSettings.cpp + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "TlsSettings.h" + +#include +#include +#include +#include + + +using namespace governikus; + +const QLatin1String SETTINGS_NAME_SSL_PROTOCOL_VERSION("protocolVersion"); +const QLatin1String SETTINGS_GROUP_NAME_CIPHERS("ciphers"); +const QLatin1String SETTINGS_GROUP_NAME_ELLIPTIC_CURVES("ellipticCurves"); +const QLatin1String SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS("signatureAlgorithms"); + + +SslCipherList& SslCipherList::operator +=(const QString& pCipherName) +{ + QSslCipher cipher(pCipherName); + if (cipher.isNull()) + { + qWarning() << "Cipher is not supported by OpenSSL and will be ignored:" << pCipherName; + } + else + { + append(cipher); + } + + return *this; +} + + +SslEllipticCurveVector& SslEllipticCurveVector::operator +=(const QString& pEllipticCurveName) +{ + QSslEllipticCurve curve = QSslEllipticCurve::fromLongName(pEllipticCurveName); + if (curve.isValid() && curve.isTlsNamedCurve()) + { + append(curve); + } + else + { + qWarning() << "EllipticCurve is not supported by OpenSSL and will be ignored:" << pEllipticCurveName; + } + + return *this; +} + + +TlsSettings::TlsSettings() + : mConfiguration() +{ +} + + +TlsSettings::~TlsSettings() +{ +} + + +void TlsSettings::load(const QJsonObject& pConfig) +{ + const auto protocolVersion = readSslProtocol(pConfig, SETTINGS_NAME_SSL_PROTOCOL_VERSION); + + SslCipherList ciphers; + QJsonArray pskCiphers; + if (readJsonArray(pskCiphers, pConfig, SETTINGS_GROUP_NAME_CIPHERS)) + { + for (const QJsonValue& line : qAsConst(pskCiphers)) + { + ciphers += line.toString(); + } + } + + SslEllipticCurveVector ellipticCurves; + QJsonArray allowedEcs; + if (pConfig.contains(SETTINGS_GROUP_NAME_ELLIPTIC_CURVES) && readJsonArray(allowedEcs, pConfig, SETTINGS_GROUP_NAME_ELLIPTIC_CURVES)) + { + for (const QJsonValue& line : qAsConst(allowedEcs)) + { + ellipticCurves += line.toString(); + } + } + + const auto& signatureAlgorithms = readSignatureAlgorithms(pConfig, SETTINGS_GROUP_NAME_SIGNATURE_ALGORITHMS); + + mConfiguration = QSslConfiguration::defaultConfiguration(); + mConfiguration.setCaCertificates(QList()); // disable fetching of system CA certificates. Set allowRootCertOnDemandLoading to false in Qt + mConfiguration.setProtocol(protocolVersion); + mConfiguration.setCiphers(ciphers); + mConfiguration.setEllipticCurves(ellipticCurves); + mConfiguration.setSignatureAndHashAlgorithms(signatureAlgorithms); +} + + +QSsl::SslProtocol TlsSettings::getProtocolVersion() const +{ + return mConfiguration.protocol(); +} + + +QList TlsSettings::getCiphers() const +{ + return mConfiguration.ciphers(); +} + + +QVector TlsSettings::getEllipticCurves() const +{ + return mConfiguration.ellipticCurves(); +} + + +QVector TlsSettings::getSignatureAlgorithms() const +{ + return mConfiguration.signatureAndHashAlgorithms(); +} + + +const QSslConfiguration& TlsSettings::getConfiguration() const +{ + return mConfiguration; +} + + +bool TlsSettings::readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String& pName) +{ + QJsonValue value = pConfig.value(pName); + if (value.isUndefined()) + { + qDebug() << pName << "undefined, using default"; + return false; + } + if (!value.isArray()) + { + qCritical() << "Expecting array for" << pName << "in SecureStorage"; + return false; + } + pArray = value.toArray(); + return true; +} + + +QSsl::SslProtocol TlsSettings::readSslProtocol(const QJsonObject& pConfig, const QLatin1String& pName) +{ + if (!pConfig.contains(pName)) + { + qDebug() << pName << "undefined, using default"; + } + else + { + const auto& value = pConfig.value(pName).toString(); + if (value == QLatin1String("TlsV1_0OrLater")) + { + return QSsl::SslProtocol::TlsV1_0OrLater; + } + if (value == QLatin1String("TlsV1_1OrLater")) + { + return QSsl::SslProtocol::TlsV1_1OrLater; + } + if (value == QLatin1String("TlsV1_2OrLater")) + { + return QSsl::SslProtocol::TlsV1_2OrLater; + } + qCritical() << pName << ": Unsupported TLS protocol version detected" << value; + } + return QSsl::SslProtocol::SecureProtocols; +} + + +QVector TlsSettings::readSignatureAlgorithms(const QJsonObject& pConfig, const QLatin1String& pKey) +{ + const QJsonValue& tmp = pConfig[pKey]; + if (tmp.isUndefined()) + { + qDebug() << pKey << "undefined, using default"; + return QVector(); + } + if (!tmp.isArray()) + { + qCritical() << pKey << "is malformed"; + return QVector(); + } + const QJsonArray& array = tmp.toArray(); + + QVector algorithms; + for (const QJsonValue& line : array) + { + const auto& parts = line.toString().split(QLatin1Char('+')); + if (parts.size() != 2) + { + qCritical() << pKey << "has malformed item" << line; + return QVector(); + } + + static const auto& hashMetaEnum = QMetaEnum::fromType(); + bool hashConversionSuccessfull; + const int hashInt = hashMetaEnum.keyToValue(parts[1].toLatin1().constData(), &hashConversionSuccessfull); + if (!hashConversionSuccessfull) + { + qCritical() << "Not a hash algorithm" << parts[1]; + return QVector(); + } + auto hash = static_cast(hashInt); + + if (parts[0] == QLatin1String("Rsa")) + { + algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Rsa, hash); + } + else if (parts[0] == QLatin1String("Dsa")) + { + algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Dsa, hash); + } + else if (parts[0] == QLatin1String("Ec")) + { + algorithms += SignatureAlgorithmPair(QSsl::KeyAlgorithm::Ec, hash); + } + else + { + qCritical() << "Not a signature algorithm" << parts[0]; + return QVector(); + } + } + return algorithms; +} diff --git a/src/settings/TlsSettings.h b/src/settings/TlsSettings.h new file mode 100644 index 0000000..af1e96e --- /dev/null +++ b/src/settings/TlsSettings.h @@ -0,0 +1,91 @@ +/*! + * TlsSettings.h + * + * \brief Configuration options for TLS channels + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "AbstractSettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +class test_TlsSettings; + + +namespace governikus +{ + + +class SecureStorage; +using SignatureAlgorithmPair = QPair; + + +class SslCipherList + : public QList +{ + public: + SslCipherList& operator +=(const QString& pCipherName); +}; + + +class SslEllipticCurveVector + : public QVector +{ + public: + SslEllipticCurveVector& operator +=(const QString& pEllipticCurveName); +}; + + +class TlsSettings final +{ + friend class SecureStorage; + friend class::test_TlsSettings; + friend bool operator==(const TlsSettings& pLeft, const TlsSettings& pRight); + + private: + QSslConfiguration mConfiguration; + + TlsSettings(); + ~TlsSettings(); + + bool readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String& pName); + QString readGroup(const QJsonObject& pConfig, const QLatin1String& pGroup, const QLatin1String& pName); + QSsl::SslProtocol readSslProtocol(const QJsonObject& pConfig, const QLatin1String& pName); + QVector readSignatureAlgorithms(const QJsonObject& pConfig, const QLatin1String& pKey); + + public: + void load(const QJsonObject& pConfig); + + QSsl::SslProtocol getProtocolVersion() const; + QList getCiphers() const; + QVector getEllipticCurves() const; + QVector getSignatureAlgorithms() const; + const QSslConfiguration& getConfiguration() const; +}; + + +inline bool operator==(const TlsSettings& pLeft, const TlsSettings& pRight) +{ + return &pLeft == &pRight || ( + pLeft.mConfiguration == pRight.mConfiguration); +} + + +inline bool operator!=(const TlsSettings& pLeft, const TlsSettings& pRight) +{ + return !(pLeft == pRight); +} + + +} // namespace governikus diff --git a/src/websocket/UIPlugInWebSocket.cpp b/src/websocket/UIPlugInWebSocket.cpp index aeaddc0..0fe396e 100644 --- a/src/websocket/UIPlugInWebSocket.cpp +++ b/src/websocket/UIPlugInWebSocket.cpp @@ -7,6 +7,7 @@ #include "view/UILoader.h" #include +#include #include #include @@ -16,7 +17,7 @@ Q_DECLARE_LOGGING_CATEGORY(websocket) using namespace governikus; -int UIPlugInWebSocket::WEBSOCKET_PORT = UIPlugInWebSocket::WEBSOCKET_DEFAULT_PORT; +quint16 UIPlugInWebSocket::cWebSocketPort = UIPlugInWebSocket::WEBSOCKET_DEFAULT_PORT; UIPlugInWebSocket::UIPlugInWebSocket() @@ -24,22 +25,44 @@ UIPlugInWebSocket::UIPlugInWebSocket() , mServer(QCoreApplication::applicationName() + QLatin1Char('/') + QCoreApplication::applicationVersion(), QWebSocketServer::NonSecureMode) , mConnection(nullptr) , mJsonApi(nullptr) + , mContext() { - if (UILoader::getInstance().load(UIPlugInName::UIPlugInJsonApi)) - { - mJsonApi = qobject_cast(UILoader::getInstance().getLoaded(UIPlugInName::UIPlugInJsonApi)); - Q_ASSERT(mJsonApi); - connect(&mServer, &QWebSocketServer::newConnection, this, &UIPlugInWebSocket::onNewConnection); - qDebug(websocket) << "Starting WebSocket..." << mServer.listen(QHostAddress::LocalHost, WEBSOCKET_PORT); - if (!mServer.isListening()) - { - qCritical(websocket) << mServer.errorString(); - } - } - else + if (!UILoader::getInstance().load(UIPlugInName::UIPlugInJsonApi)) { qWarning(websocket) << "Cannot start WebSocket because JSON-API is missing"; + return; } + + mJsonApi = qobject_cast(UILoader::getInstance().getLoaded(UIPlugInName::UIPlugInJsonApi)); + Q_ASSERT(mJsonApi); + connect(&mServer, &QWebSocketServer::newConnection, this, &UIPlugInWebSocket::onNewConnection); + qDebug(websocket) << "Starting WebSocket..." << mServer.listen(QHostAddress::LocalHost, cWebSocketPort); + if (!mServer.isListening()) + { + qCritical(websocket) << mServer.errorString(); + return; + } + + const quint16 port = mServer.serverPort(); + qDebug(websocket) << "Listening on port" << port; + +#ifndef QT_NO_DEBUG + if (cWebSocketPort == 0) + { + const QString path = WEBSOCKET_PORT_FILENAME(QCoreApplication::applicationPid()); + QFile file(path); + if (file.open(QIODevice::WriteOnly)) + { + QTextStream(&file) << port; + qDebug(websocket) << "Stored port number to info file" << path; + } + else + { + qCritical(websocket) << "Failed to store port number to info file" << path; + } + } +#endif + } @@ -48,27 +71,29 @@ UIPlugInWebSocket::~UIPlugInWebSocket() } -void UIPlugInWebSocket::setPort(int pPort) +void UIPlugInWebSocket::setPort(quint16 pPort) { - WEBSOCKET_PORT = pPort; + cWebSocketPort = pPort; } -int UIPlugInWebSocket::getPort() +quint16 UIPlugInWebSocket::getPort() { - return WEBSOCKET_PORT; + return cWebSocketPort; } void UIPlugInWebSocket::onWorkflowStarted(QSharedPointer pContext) { - Q_UNUSED(pContext) + mContext = pContext; } void UIPlugInWebSocket::onWorkflowFinished(QSharedPointer pContext) { - Q_UNUSED(pContext) + Q_UNUSED(pContext); + + mContext.clear(); } @@ -95,6 +120,13 @@ void UIPlugInWebSocket::onNewConnection() void UIPlugInWebSocket::onClientDisconnected() { qDebug(websocket) << "Client disconnected..."; + + if (mContext) + { + const QSignalBlocker blocker(mJsonApi); + Q_EMIT mContext->fireCancelWorkflow(); + } + mConnection.reset(); disconnect(mJsonApi, &UIPlugInJsonApi::fireMessage, this, &UIPlugInWebSocket::onJsonApiMessage); } diff --git a/src/websocket/UIPlugInWebSocket.h b/src/websocket/UIPlugInWebSocket.h index 9f0152b..084f48c 100644 --- a/src/websocket/UIPlugInWebSocket.h +++ b/src/websocket/UIPlugInWebSocket.h @@ -9,6 +9,7 @@ #include "UIPlugInJsonApi.h" #include "view/UIPlugIn.h" +#include #include #include #include @@ -16,6 +17,8 @@ namespace governikus { +#define WEBSOCKET_PORT_FILENAME(PID) (QDir::tempPath() + QDir::separator() + QStringLiteral("web_socket_port-") + QString::number(PID)) + class UIPlugInWebSocket : public UIPlugIn { @@ -27,8 +30,9 @@ class UIPlugInWebSocket QWebSocketServer mServer; QScopedPointer mConnection; UIPlugInJsonApi* mJsonApi; + QSharedPointer mContext; - static int WEBSOCKET_PORT; + static quint16 cWebSocketPort; private Q_SLOTS: virtual void doShutdown() override; @@ -44,10 +48,10 @@ class UIPlugInWebSocket UIPlugInWebSocket(); virtual ~UIPlugInWebSocket(); - static void setPort(int pPort); - static int getPort(); + static void setPort(quint16 pPort); + static quint16 getPort(); - static const int WEBSOCKET_DEFAULT_PORT = 14727; + static const quint16 WEBSOCKET_DEFAULT_PORT = 14727; }; } /* namespace governikus */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 191f57e..1a0935f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,5 +2,36 @@ qt5_add_resources(QRC_FIXTURE "fixture/fixture.qrc") ADD_OBJECT_LIBRARY(QRC_FIXTURE_OBJ ${QRC_FIXTURE} Qt5::Core) +FUNCTION(EXTRACT_TESTNAME result filepath) + STRING(REPLACE ".cpp" "" testname ${filepath}) + STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" testname ${testname}) + STRING(REPLACE "/" "_" testname ${testname}) + STRING(REPLACE "_test_" "_" testname ${testname}) + SET(${result} "Test_${testname}" PARENT_SCOPE) +ENDFUNCTION() + + +FUNCTION(GET_TEST_CMDLINE cmdline testname) + IF(NOT WIN32 AND "${testname}" MATCHES "gui" OR "${testname}" MATCHES "\\.qml") + SET(PLATFORM -platform offscreen) + ENDIF() + + SET(${cmdline} ${PLATFORM} -v2 -o ${CMAKE_CURRENT_BINARY_DIR}/results.${testname}.log.xml,xml PARENT_SCOPE) +ENDFUNCTION() + + +FUNCTION(ADD_QML_TEST_FILES _import_path) + FILE(GLOB_RECURSE TEST_SUBFILES "${CMAKE_CURRENT_SOURCE_DIR}/test_*.qml") + FOREACH(sourcefile ${TEST_SUBFILES}) + EXTRACT_TESTNAME(TESTNAME ${sourcefile}) + GET_TEST_CMDLINE(CMD_PARAMS ${TESTNAME}) + ADD_TEST(NAME ${TESTNAME} COMMAND $ ${CMD_PARAMS} -input ${sourcefile} -import "${_import_path}") + SET_TESTS_PROPERTIES(${TESTNAME} PROPERTIES LABELS "qml") + ENDFOREACH() +ENDFUNCTION() + + ADD_SUBDIRECTORY(helper) +ADD_SUBDIRECTORY(qml) +ADD_SUBDIRECTORY(qml_stationary) ADD_SUBDIRECTORY(qt) diff --git a/test/helper/CMakeLists.txt b/test/helper/CMakeLists.txt index 1a6a286..c6f70a0 100644 --- a/test/helper/CMakeLists.txt +++ b/test/helper/CMakeLists.txt @@ -1,5 +1,13 @@ ADD_PLATFORM_LIBRARY(AusweisAppTestHelper) TARGET_INCLUDE_DIRECTORIES(AusweisAppTestHelper SYSTEM PUBLIC ${PCSC_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(AusweisAppTestHelper Qt5::Network Qt5::Xml Qt5::Widgets Qt5::Test AusweisAppActivation AusweisAppExternalQHttpServer AusweisAppCard AusweisAppNetwork) +# TODO: Remove the QmlTestRunner from the lib AusweisAppTestHelper, currently it's included and therefore Qt5::QuickTest is needed as linked lib +TARGET_LINK_LIBRARIES(AusweisAppTestHelper Qt5::Network Qt5::Xml Qt5::Test AusweisAppActivation AusweisAppCard AusweisAppCardRemote AusweisAppNetwork AusweisAppCore AusweisAppWebSocket Qt5::QuickTest) TARGET_COMPILE_DEFINITIONS(AusweisAppTestHelper PRIVATE QT_STATICPLUGIN) + +IF(DESKTOP) + TARGET_LINK_LIBRARIES(AusweisAppTestHelper Qt5::Widgets) +ENDIF() + +ADD_EXECUTABLE(QmlTestRunner QmlTestRunner.cpp) +TARGET_LINK_LIBRARIES(QmlTestRunner Qt5::QuickTest Qt5::Gui) diff --git a/test/helper/CliHelper.cpp b/test/helper/CliHelper.cpp index 7e4d8e7..c87f081 100644 --- a/test/helper/CliHelper.cpp +++ b/test/helper/CliHelper.cpp @@ -6,6 +6,8 @@ #include +#include + using namespace governikus; CliHelper::CliHelper(QObject* pParent) @@ -140,10 +142,10 @@ quint16 CliHelper::getServerPort() if (matcher.hasMatch() && !matcher.captured(1).isNull()) { bool converted = false; - quint16 port = matcher.captured(1).toUInt(&converted); - if (converted) + auto port = matcher.captured(1).toUInt(&converted); + if (converted && port <= USHRT_MAX) { - mServerPort = port; + mServerPort = static_cast(port); } } } diff --git a/test/helper/MockActivationContext.h b/test/helper/MockActivationContext.h index ef1f49d..f1c03f9 100644 --- a/test/helper/MockActivationContext.h +++ b/test/helper/MockActivationContext.h @@ -26,7 +26,7 @@ class MockActivationContext virtual ~MockActivationContext(); - virtual QUrl getActivationURL() override + virtual QUrl getActivationURL() const override { return QUrl(); } @@ -48,20 +48,20 @@ class MockActivationContext } - virtual bool sendErrorPage(HttpStatusCode pStatusCode, const Result& pResult) override + virtual bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override { Q_UNUSED(pStatusCode); - Q_UNUSED(pResult); + Q_UNUSED(pStatus); mSendErroPageCalled = true; mSendError = mErrorMessageOnSend; return mErroPageValue; } - virtual bool sendRedirect(const QUrl& pRedirectAddress, const Result& pResult) override + virtual bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) override { Q_UNUSED(pRedirectAddress); - Q_UNUSED(pResult); + Q_UNUSED(pStatus); mSendRedirectCalled = true; mSendError = mErrorMessageOnSend; return mRedirectValue; diff --git a/test/helper/MockCard.cpp b/test/helper/MockCard.cpp index 1027f7e..83e2986 100644 --- a/test/helper/MockCard.cpp +++ b/test/helper/MockCard.cpp @@ -18,28 +18,28 @@ MockCard::~MockCard() } -ReturnCode MockCard::connect() +CardReturnCode MockCard::connect() { - mConnected = mCardConfig.mConnect == ReturnCode::OK; + mConnected = mCardConfig.mConnect == CardReturnCode::OK; return mCardConfig.mConnect; } -ReturnCode MockCard::disconnect() +CardReturnCode MockCard::disconnect() { - mConnected = mCardConfig.mDisconnect == ReturnCode::OK; + mConnected = mCardConfig.mDisconnect == CardReturnCode::OK; return mCardConfig.mDisconnect; } -ReturnCode MockCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) +CardReturnCode MockCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { Q_UNUSED(pCmd); if (mCardConfig.mTransmits.isEmpty()) { qFatal("No (more) response APDU configured, but a(nother) command transmitted"); } - QPair config = mCardConfig.mTransmits.takeFirst(); + QPair config = mCardConfig.mTransmits.takeFirst(); pRes.setBuffer(config.second); return config.first; } diff --git a/test/helper/MockCard.h b/test/helper/MockCard.h index d75bbd6..377ab0f 100644 --- a/test/helper/MockCard.h +++ b/test/helper/MockCard.h @@ -18,15 +18,15 @@ namespace governikus { -typedef QPair TransmitConfig; +typedef QPair TransmitConfig; class MockCardConfig { public: QVector mTransmits; - ReturnCode mConnect = ReturnCode::OK; - ReturnCode mDisconnect = ReturnCode::OK; + CardReturnCode mConnect = CardReturnCode::OK; + CardReturnCode mDisconnect = CardReturnCode::OK; MockCardConfig(const QVector& pTransmits = QVector()) : mTransmits(pTransmits) @@ -49,8 +49,8 @@ class MockCard MockCard(const MockCardConfig& pCardConfig); virtual ~MockCard(); - ReturnCode connect() override; - ReturnCode disconnect() override; + CardReturnCode connect() override; + CardReturnCode disconnect() override; bool isConnected() override { @@ -58,33 +58,7 @@ class MockCard } - ReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - - - /*! - * Not supported, returns ReturnCode::COMMAND_FAILED - */ - ReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, int pTimeoutSeconds) override - { - Q_UNUSED(pPinId); - Q_UNUSED(pChat); - Q_UNUSED(pCertificateDescription); - Q_UNUSED(pChannelOutput); - Q_UNUSED(pTimeoutSeconds); - return ReturnCode::COMMAND_FAILED; - } - - - /*! - * Not supported, returns ReturnCode::COMMAND_FAILED - */ - ReturnCode setEidPin(unsigned int pTimeoutSeconds) override - { - Q_UNUSED(pTimeoutSeconds); - return ReturnCode::COMMAND_FAILED; - } - - + CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; }; diff --git a/test/helper/MockDataChannel.cpp b/test/helper/MockDataChannel.cpp new file mode 100644 index 0000000..29e05d4 --- /dev/null +++ b/test/helper/MockDataChannel.cpp @@ -0,0 +1,41 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "MockDataChannel.h" + +using namespace governikus; + + +MockDataChannel::MockDataChannel() +{ +} + + +MockDataChannel::~MockDataChannel() +{ +} + + +void MockDataChannel::close() +{ + Q_EMIT fireClosed(GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); +} + + +void MockDataChannel::closeAbnormal() +{ + Q_EMIT fireClosed(GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); +} + + +void MockDataChannel::send(const QByteArray& pDataBlock) +{ + Q_EMIT fireSend(pDataBlock); +} + + +void MockDataChannel::onReceived(const QByteArray& pDataBlock) +{ + Q_EMIT fireReceived(pDataBlock); +} diff --git a/test/helper/MockDataChannel.h b/test/helper/MockDataChannel.h new file mode 100644 index 0000000..d2b0ea1 --- /dev/null +++ b/test/helper/MockDataChannel.h @@ -0,0 +1,35 @@ +/*! + * \brief Data channel mock for tests. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "DataChannel.h" + +namespace governikus +{ + +class MockDataChannel + : public DataChannel +{ + Q_OBJECT + + public: + MockDataChannel(); + virtual ~MockDataChannel(); + + virtual void send(const QByteArray& pDataBlock) override; + virtual void close() override; + void closeAbnormal(); + + public Q_SLOTS: + void onReceived(const QByteArray& pDataBlock); + + Q_SIGNALS: + void fireSend(const QByteArray& pDataBlock); +}; + + +} /* namespace governikus */ diff --git a/test/helper/MockHttpServer.cpp b/test/helper/MockHttpServer.cpp new file mode 100644 index 0000000..3d24478 --- /dev/null +++ b/test/helper/MockHttpServer.cpp @@ -0,0 +1,54 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "MockHttpServer.h" + +#include "EnvHolder.h" + +using namespace governikus; + +MockHttpServer::MockHttpServer() + : QObject() + , mServer() +{ + HttpServer::cPort = 0; + mServer = EnvHolder::shared(); + QVERIFY(mServer); + QVERIFY(mServer->isListening()); + connect(mServer.data(), &HttpServer::fireNewHttpRequest, this, &MockHttpServer::onNewHttpRequest); +} + + +void MockHttpServer::reset() +{ + mMock.clear(); +} + + +void MockHttpServer::addMock(const QByteArray& pUrl, const HttpResponse& pResponse) +{ + mMock.insert(pUrl, pResponse); +} + + +QUrl MockHttpServer::getAddress(const QString& pPath) const +{ + const auto& port = QString::number(mServer->getServerPort()); + return QUrl(QStringLiteral("http://localhost:") + port + pPath); +} + + +void MockHttpServer::onNewHttpRequest(const QSharedPointer& pRequest) +{ + QVERIFY(pRequest); + const auto& response = mMock.value(pRequest->getUrl().toEncoded()); + if (response.isValid()) + { + pRequest->send(response); + } + else + { + pRequest->send(HttpStatusCode::INTERNAL_SERVER_ERROR); + } +} diff --git a/test/helper/MockHttpServer.h b/test/helper/MockHttpServer.h new file mode 100644 index 0000000..81757c8 --- /dev/null +++ b/test/helper/MockHttpServer.h @@ -0,0 +1,38 @@ +/*! + * \brief Provide a HTTP-Server for tests + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "HttpServer.h" + +#include "HttpResponse.h" + +#include + +namespace governikus +{ + +class MockHttpServer + : public QObject +{ + Q_OBJECT + + private: + QSharedPointer mServer; + QMap mMock; + + public: + MockHttpServer(); + + void reset(); + void addMock(const QByteArray& pUrl, const HttpResponse& pResponse); + QUrl getAddress(const QString& pPath = QString()) const; + + private Q_SLOTS: + void onNewHttpRequest(const QSharedPointer& pRequest); +}; + +} /* namespace governikus */ diff --git a/test/helper/MockNetworkManager.cpp b/test/helper/MockNetworkManager.cpp index ae047ce..8c31e13 100644 --- a/test/helper/MockNetworkManager.cpp +++ b/test/helper/MockNetworkManager.cpp @@ -21,13 +21,8 @@ MockNetworkManager::~MockNetworkManager() } -QNetworkReply* MockNetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) +MockNetworkReply* MockNetworkManager::getReply(const QNetworkRequest& pRequest) { - Q_UNUSED(pRequest); - Q_UNUSED(pData); - Q_UNUSED(pUsePsk); - Q_UNUSED(pTimeoutInMilliSeconds); - if (mNextReply) { mLastReply = mNextReply; @@ -47,5 +42,26 @@ QNetworkReply* MockNetworkManager::paos(QNetworkRequest& pRequest, const QByteAr mLastReply = new MockNetworkReply(content); } + mLastReply->setRequest(pRequest); return mLastReply; } + + +QNetworkReply* MockNetworkManager::get(QNetworkRequest& pRequest, int pTimeoutInMilliSeconds) +{ + Q_UNUSED(pRequest); + Q_UNUSED(pTimeoutInMilliSeconds); + + return getReply(pRequest); +} + + +QNetworkReply* MockNetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) +{ + Q_UNUSED(pRequest); + Q_UNUSED(pData); + Q_UNUSED(pUsePsk); + Q_UNUSED(pTimeoutInMilliSeconds); + + return getReply(pRequest); +} diff --git a/test/helper/MockNetworkManager.h b/test/helper/MockNetworkManager.h index 57f13d5..55fd4fb 100644 --- a/test/helper/MockNetworkManager.h +++ b/test/helper/MockNetworkManager.h @@ -22,9 +22,12 @@ class MockNetworkManager MockNetworkReply* mNextReply; MockNetworkReply* mLastReply; + MockNetworkReply* getReply(const QNetworkRequest& pRequest); + public: MockNetworkManager(); virtual ~MockNetworkManager(); + virtual QNetworkReply* get(QNetworkRequest& pRequest, int pTimeoutInMilliSeconds = 30000) override; virtual QNetworkReply* paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk = true, int pTimeoutInMilliSeconds = 30000) override; void setFilename(const QString& pFilename) diff --git a/test/helper/MockNetworkReply.cpp b/test/helper/MockNetworkReply.cpp index a343ce5..00bbe16 100644 --- a/test/helper/MockNetworkReply.cpp +++ b/test/helper/MockNetworkReply.cpp @@ -9,9 +9,9 @@ using namespace governikus; MockNetworkReply::MockNetworkReply(const QByteArray& pData, QObject* pParent) : QNetworkReply(pParent) - , mData(pData) - , mDataPosition(0) + , mSocket() { + mSocket.mReadBuffer = pData; setOpenMode(QIODevice::ReadOnly); } @@ -23,12 +23,5 @@ MockNetworkReply::~MockNetworkReply() qint64 MockNetworkReply::readData(char* pDst, qint64 pMaxSize) { - QByteArray data = mData.mid(mDataPosition, pMaxSize); - int length = data.length(); - if (length) - { - qstrncpy(pDst, data.constData(), length); - mDataPosition += length; - } - return length; + return mSocket.readData(pDst, pMaxSize); } diff --git a/test/helper/MockNetworkReply.h b/test/helper/MockNetworkReply.h index b36b4ce..2b49996 100644 --- a/test/helper/MockNetworkReply.h +++ b/test/helper/MockNetworkReply.h @@ -6,6 +6,8 @@ #pragma once +#include "MockSocket.h" + #include namespace governikus @@ -17,8 +19,7 @@ class MockNetworkReply Q_OBJECT private: - const QByteArray mData; - int mDataPosition; + MockSocket mSocket; public: MockNetworkReply(const QByteArray& pData = QByteArray(), QObject* pParent = nullptr); @@ -29,6 +30,12 @@ class MockNetworkReply } + void setRequest(const QNetworkRequest& pRequest) + { + QNetworkReply::setRequest(pRequest); + } + + virtual qint64 readData(char* pDst, qint64 pMaxSize) override; void fireFinished() diff --git a/test/helper/MockQHttpConnection.cpp b/test/helper/MockQHttpConnection.cpp deleted file mode 100644 index fbe6891..0000000 --- a/test/helper/MockQHttpConnection.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "MockQHttpConnection.h" - -using namespace governikus; - -MockQHttpConnection::MockQHttpConnection() - : QHttpConnection(nullptr) -{ -} - - -MockQHttpConnection::~MockQHttpConnection() -{ -} - - -void MockQHttpConnection::write(const QByteArray& data) -{ - mContent.append(data); -} diff --git a/test/helper/MockQHttpConnection.h b/test/helper/MockQHttpConnection.h deleted file mode 100644 index fa4595c..0000000 --- a/test/helper/MockQHttpConnection.h +++ /dev/null @@ -1,31 +0,0 @@ -/*! - * MockQtthpConnection.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "qhttpserver/qhttpconnection.h" - - -namespace governikus -{ - -class MockQHttpConnection - : public QHttpConnection -{ - Q_OBJECT - - public: - QByteArray mContent; - - MockQHttpConnection(); - virtual ~MockQHttpConnection(); - - void write(const QByteArray& data) override; - - -}; - -} /* namespace governikus */ diff --git a/test/helper/MockSocket.cpp b/test/helper/MockSocket.cpp new file mode 100644 index 0000000..8e7bea8 --- /dev/null +++ b/test/helper/MockSocket.cpp @@ -0,0 +1,57 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "MockSocket.h" + +using namespace governikus; + +MockSocket::MockSocket() + : QTcpSocket() + , mReadBuffer() + , mReaderBufferPosition(0) + , mReaderBufferChunk(-1) + , mWriteBuffer() +{ + open(QIODevice::ReadWrite); +} + + +MockSocket::~MockSocket() +{ +} + + +qint64 MockSocket::bytesAvailable() const +{ + return mReadBuffer.size() - mReaderBufferPosition; +} + + +qint64 MockSocket::readData(char* pDestination, qint64 pMaxSize) +{ + Q_ASSERT(pMaxSize <= INT_MAX); + + int chunk = static_cast(pMaxSize); + if (mReaderBufferChunk > -1 && mReaderBufferChunk < chunk) + { + chunk = mReaderBufferChunk; + } + + QByteArray data = mReadBuffer.mid(mReaderBufferPosition, chunk); + int length = data.length(); + if (length >= 0) + { + qstrncpy(pDestination, data.constData(), static_cast(length)); + mReaderBufferPosition += length; + } + return length; +} + + +qint64 MockSocket::writeData(const char* pData, qint64 pMaxSize) +{ + const auto& data = QByteArray(pData, static_cast(pMaxSize)); + mWriteBuffer += data; + return data.size(); +} diff --git a/test/helper/MockSocket.h b/test/helper/MockSocket.h new file mode 100644 index 0000000..a0a39b0 --- /dev/null +++ b/test/helper/MockSocket.h @@ -0,0 +1,34 @@ +/*! + * \brief Mock a QAbstractSocket for tests. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include + +namespace governikus +{ + +class MockSocket + : public QTcpSocket +{ + Q_OBJECT + + public: + QByteArray mReadBuffer; + int mReaderBufferPosition; + int mReaderBufferChunk; + QByteArray mWriteBuffer; + + MockSocket(); + virtual ~MockSocket(); + + qint64 bytesAvailable() const override; + qint64 readData(char* pDestination, qint64 pMaxSize) override; + qint64 writeData(const char* pData, qint64 pMaxSize) override; +}; + +} /* namespace governikus */ diff --git a/test/helper/PersoSimController.cpp b/test/helper/PersoSimController.cpp index ac7df49..2adc218 100644 --- a/test/helper/PersoSimController.cpp +++ b/test/helper/PersoSimController.cpp @@ -102,17 +102,10 @@ bool PersoSimController::startProcess() // wait for PersoSim command line prompt QEventLoop eventLoop; mEventLoop = &eventLoop; - try - { - int result = eventLoop.exec(); - mEventLoop = nullptr; - XCOMPARE(result, 0, false); - } - catch (...) - { - mEventLoop = nullptr; - throw; - } + + int result = eventLoop.exec(); + mEventLoop = nullptr; + XCOMPARE(result, 0, false); return true; } diff --git a/test/helper/QmlTestRunner.cpp b/test/helper/QmlTestRunner.cpp new file mode 100644 index 0000000..c4d9546 --- /dev/null +++ b/test/helper/QmlTestRunner.cpp @@ -0,0 +1,3 @@ +#include +#include +QUICK_TEST_MAIN(qml) diff --git a/test/helper/RemoteCardNotificationChecker.cpp b/test/helper/RemoteCardNotificationChecker.cpp new file mode 100644 index 0000000..76d6727 --- /dev/null +++ b/test/helper/RemoteCardNotificationChecker.cpp @@ -0,0 +1,139 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + + +#include "RemoteCardNotificationChecker.h" + +#include + +#include + +using namespace governikus; + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::REMOTE_READER_DISCOVER); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::REMOTE_READER_OFFER); + QCOMPARE(pNotification->getDeviceName(), QStringLiteral("Sony Xperia Z5 compact")); + QVERIFY(pNotification->isEncrypted()); + QVERIFY(pNotification->getPort() == static_cast(24728)); + QCOMPARE(pNotification->getAvailableApiLevels(), QVector({1, 2, 3, 4})); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::GET_API_LEVEL); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::SET_API_LEVEL); + QCOMPARE(pNotification->getLevel(), 1); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::API_LEVEL); + QCOMPARE(pNotification->getError(), QStringLiteral("No error")); + QCOMPARE(pNotification->getAvailable(), QVector({1, 2, 3, 4})); + QVERIFY(pNotification->getCurrent() == 2); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::GET_READER_LIST); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::READER_LIST); + + // Readers. + const QVector& readers = pNotification->getReaders(); + QCOMPARE(readers.size(), 1); + const ReaderDescription& reader = readers.first(); + QCOMPARE(reader.getName(), QStringLiteral("NFC Reader")); + QVERIFY(reader.isAttached()); + QCOMPARE(reader.getExtendedLength(), ExtendedLengthApduSupportCode::SUPPORTED); + + // Cards. + QVERIFY(reader.hasCard()); + + const CardDescription& card = reader.getCard(); + QCOMPARE(card.getEFCardAccess(), QByteArray::fromHex("3181c10000")); + QCOMPARE(card.getRetryCounter(), 3); + QVERIFY(!card.isPinDeactivated()); + QVERIFY(!card.isConnected()); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::READER); + QCOMPARE(pNotification->getError(), QStringLiteral("Optional error message")); + + // Readers. + const ReaderDescription& reader = pNotification->getReader(); + QCOMPARE(reader.getName(), QStringLiteral("NFC Reader")); + QVERIFY(!reader.isAttached()); + QCOMPARE(reader.getExtendedLength(), ExtendedLengthApduSupportCode::SUPPORTED); + + // Cards. + QVERIFY(!reader.hasCard()); + + const CardDescription& card = reader.getCard(); + QCOMPARE(card.getEFCardAccess(), QByteArray()); + QCOMPARE(card.getRetryCounter(), -1); + QVERIFY(card.isPinDeactivated()); + QVERIFY(!card.isConnected()); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::CONNECT); + QCOMPARE(pNotification->getReaderName(), QStringLiteral("NFC Reader")); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::DISCONNECT); + QCOMPARE(pNotification->getReaderName(), QStringLiteral("NFC Reader")); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::TRANSMIT); + QCOMPARE(pNotification->getReaderName(), QStringLiteral("NFC Reader")); + QCOMPARE(pNotification->getCommandApdu(), QByteArray::fromHex("00A402022F00")); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::TRANSMIT_RESPONSE); + QCOMPARE(pNotification->getReaderName(), QStringLiteral("NFC Reader")); + QCOMPARE(pNotification->getError(), QStringLiteral("Optional error message")); + QCOMPARE(pNotification->getResponseApdu(), QByteArray::fromHex("9000")); +} + + +void RemoteCardNotificationChecker::process(const QSharedPointer& pNotification) +{ + QCOMPARE(pNotification->getType(), CardNotificationType::UNSUPPORTED); + QCOMPARE(pNotification->getError(), QStringLiteral("Invalid command")); +} diff --git a/test/helper/RemoteCardNotificationChecker.h b/test/helper/RemoteCardNotificationChecker.h new file mode 100644 index 0000000..c8155e9 --- /dev/null +++ b/test/helper/RemoteCardNotificationChecker.h @@ -0,0 +1,51 @@ +/*! + * \brief Helper class to verify the content of remote card notification. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "RemoteCardNotifications.h" + + +namespace governikus +{ + +class RemoteCardNotificationChecker + : public NotificationVisitor +{ + public: + RemoteCardNotificationChecker() = default; + + virtual ~RemoteCardNotificationChecker() = default; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + + virtual void process(const QSharedPointer& pNotification) override; + +}; + +} /* namespace governikus */ diff --git a/test/helper/TestAuthContext.cpp b/test/helper/TestAuthContext.cpp new file mode 100644 index 0000000..1ddba75 --- /dev/null +++ b/test/helper/TestAuthContext.cpp @@ -0,0 +1,66 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "TestAuthContext.h" +#include "TestFileHelper.h" +#include "paos/retrieve/DidAuthenticateEac1Parser.h" + + +using namespace governikus; + + +TestAuthContext::TestAuthContext(ActivationContext* pActivationContext, const QString& pFileName) + : AuthContext(pActivationContext) + , mDidAuthenticateEac1() +{ + mDidAuthenticateEac1.reset(static_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(pFileName)))); + setDidAuthenticateEac1(mDidAuthenticateEac1); + setTerminalCvc(mDidAuthenticateEac1->getCvCertificates().at(0)); + setDvCvc(mDidAuthenticateEac1->getCvCertificates().at(1)); +} + + +TestAuthContext::~TestAuthContext() +{ +} + + +void TestAuthContext::setRequiredAccessRights(const QSet& pAccessRights) +{ + if (pAccessRights.isEmpty()) + { + mDidAuthenticateEac1->mEac1InputType.mRequiredChat.reset(); + } + else + { + if (!mDidAuthenticateEac1->getRequiredChat()) + { + mDidAuthenticateEac1->mEac1InputType.mRequiredChat.reset(new CHAT(getTerminalCvc()->getBody().getCHAT())); + } + mDidAuthenticateEac1->getRequiredChat()->removeAllAccessRights(); + mDidAuthenticateEac1->getRequiredChat()->setAccessRights(pAccessRights); + } + setDidAuthenticateEac1(mDidAuthenticateEac1); + setTerminalCvc(mDidAuthenticateEac1->getCvCertificates().at(0)); +} + + +void TestAuthContext::setOptionalAccessRights(const QSet& pAccessRights) +{ + if (pAccessRights.isEmpty()) + { + mDidAuthenticateEac1->mEac1InputType.mOptionalChat.reset(); + } + else + { + if (!mDidAuthenticateEac1->getOptionalChat()) + { + mDidAuthenticateEac1->mEac1InputType.mOptionalChat.reset(new CHAT(getTerminalCvc()->getBody().getCHAT())); + } + mDidAuthenticateEac1->getOptionalChat()->removeAllAccessRights(); + mDidAuthenticateEac1->getOptionalChat()->setAccessRights(pAccessRights); + } + setDidAuthenticateEac1(mDidAuthenticateEac1); + setTerminalCvc(mDidAuthenticateEac1->getCvCertificates().at(0)); +} diff --git a/test/helper/TestAuthContext.h b/test/helper/TestAuthContext.h new file mode 100644 index 0000000..9e18dac --- /dev/null +++ b/test/helper/TestAuthContext.h @@ -0,0 +1,33 @@ +/*! + * \brief Helper to use AuthContext in an easy way. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include "context/AuthContext.h" +#include "paos/retrieve/DidAuthenticateEac1.h" + +#include + +namespace governikus +{ + +class TestAuthContext + : public AuthContext +{ + Q_OBJECT + + private: + QSharedPointer mDidAuthenticateEac1; + + public: + TestAuthContext(ActivationContext* pActivationContext, const QString& pFileName); + virtual ~TestAuthContext(); + + void setRequiredAccessRights(const QSet& pAccessRights); + void setOptionalAccessRights(const QSet& pAccessRights); +}; + +} /* namespace governikus */ diff --git a/test/helper/TestFileHelper.cpp b/test/helper/TestFileHelper.cpp index 3e9d4a2..10ad3e1 100644 --- a/test/helper/TestFileHelper.cpp +++ b/test/helper/TestFileHelper.cpp @@ -7,7 +7,7 @@ #include "FileDestination.h" #include -#include +#include using namespace governikus; @@ -40,8 +40,8 @@ QByteArray TestFileHelper::readFile(const QString& pFileName) void TestFileHelper::createTranslations(const QString& pTranslationDir) { const QStringList testFiles({ - "de_AT", "de_DE", "en", "fr_FR", "es", "defect", "de_fe", "en_gb", "it" - }); + "de_AT", "de_DE", "en", "fr_FR", "es", "defect", "de_fe", "en_gb", "it" + }); QDir dir(pTranslationDir); if (dir.exists()) @@ -59,3 +59,16 @@ void TestFileHelper::createTranslations(const QString& pTranslationDir) QVERIFY(file.exists()); } } + + +bool TestFileHelper::containsLog(const QSignalSpy& pSpy, const QLatin1String& pStr) +{ + for (const auto& entry : pSpy) + { + if (entry.at(0).toString().contains(pStr)) + { + return true; + } + } + return false; +} diff --git a/test/helper/TestFileHelper.h b/test/helper/TestFileHelper.h index 0bf5923..05239cc 100644 --- a/test/helper/TestFileHelper.h +++ b/test/helper/TestFileHelper.h @@ -8,6 +8,7 @@ #include #include +#include namespace governikus { @@ -17,6 +18,7 @@ class TestFileHelper public: static QByteArray readFile(const QString& pFileName); static void createTranslations(const QString& pTranslationDir); + static bool containsLog(const QSignalSpy& pSpy, const QLatin1String& pStr); }; } /* namespace governikus */ diff --git a/test/helper/WebSocketHelper.cpp b/test/helper/WebSocketHelper.cpp new file mode 100644 index 0000000..6e015c1 --- /dev/null +++ b/test/helper/WebSocketHelper.cpp @@ -0,0 +1,98 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "WebSocketHelper.h" + +#include "UIPlugInWebSocket.h" + +#include +#include + +using namespace governikus; + +void WebSocketHelper::connectWebsocket(int pPort) +{ + QEventLoop eventLoop; + + connect(&mWebSocket, &QWebSocket::connected, &eventLoop, &QEventLoop::quit); + connect(&mWebSocket, &QWebSocket::disconnected, &eventLoop, &QEventLoop::quit); + connect(&mWebSocket, QOverload::of(&QWebSocket::error), &eventLoop, &QEventLoop::quit); + + const QString address = QString("ws://localhost:%1").arg(pPort); + mWebSocket.open(QUrl(address)); + + QTimer timer; + timer.setSingleShot(true); + timer.setInterval(mConnectionTiemout); + connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit); + + eventLoop.exec(); +} + + +void WebSocketHelper::onTextMessageReceived(const QString& pMessage) +{ + mInput += pMessage; +} + + +WebSocketHelper::WebSocketHelper(int pPort, int pConnectionTimeout) + : mConnectionTiemout(pConnectionTimeout) +{ + connect(&mWebSocket, &QWebSocket::textMessageReceived, this, &WebSocketHelper::onTextMessageReceived); + + const qint64 start = QDateTime::currentMSecsSinceEpoch(); + do + { + connectWebsocket(pPort); + } + while (mWebSocket.state() != QAbstractSocket::SocketState::ConnectedState + && mWebSocket.error() == QAbstractSocket::SocketError::ConnectionRefusedError + && QDateTime::currentMSecsSinceEpoch() - start < mConnectionTiemout); +} + + +QAbstractSocket::SocketState WebSocketHelper::getState() const +{ + return mWebSocket.state(); +} + + +bool WebSocketHelper::waitForMessage(const std::function& pMessageMatcher) +{ + const qint64 start = QDateTime::currentMSecsSinceEpoch(); + + do + { + while (!mInput.isEmpty()) + { + const QString& message = mInput.takeFirst(); + const QJsonDocument& document = QJsonDocument::fromJson(message.toUtf8()); + + if (pMessageMatcher(document.object())) + { + return true; + } + } + + QEventLoop eventLoop; + connect(&mWebSocket, &QWebSocket::textMessageReceived, &eventLoop, &QEventLoop::quit); + + QTimer timer; + timer.setSingleShot(true); + timer.setInterval(mConnectionTiemout); + connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit); + + eventLoop.exec(); + } + while (QDateTime::currentMSecsSinceEpoch() - start < mConnectionTiemout); + + return false; +} + + +void WebSocketHelper::sendMessage(const QString& pMessage) +{ + mWebSocket.sendTextMessage(pMessage); +} diff --git a/test/helper/WebSocketHelper.h b/test/helper/WebSocketHelper.h new file mode 100644 index 0000000..3f4a7fa --- /dev/null +++ b/test/helper/WebSocketHelper.h @@ -0,0 +1,37 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#pragma once + +#include +#include +#include + +namespace governikus +{ + +class WebSocketHelper + : public QObject +{ + Q_OBJECT + + private: + const int mConnectionTiemout; + QWebSocket mWebSocket; + QVector mInput; + + void connectWebsocket(int pPort); + + private Q_SLOTS: + void onTextMessageReceived(const QString& pMessage); + + public: + WebSocketHelper(int pPort, int pConnectionTimeout = 15000); + + QAbstractSocket::SocketState getState() const; + bool waitForMessage(const std::function& pMessageMatcher); + void sendMessage(const QString& pMessage); +}; + +} /* namespace governikus */ diff --git a/test/qml/CMakeLists.txt b/test/qml/CMakeLists.txt new file mode 100644 index 0000000..8fe3b13 --- /dev/null +++ b/test/qml/CMakeLists.txt @@ -0,0 +1 @@ +ADD_QML_TEST_FILES(${RESOURCES_DIR}/qml) diff --git a/test/qml/test_Utils.qml b/test/qml/test_Utils.qml new file mode 100644 index 0000000..0d171bd --- /dev/null +++ b/test/qml/test_Utils.qml @@ -0,0 +1,16 @@ +import QtQuick 2.3 +import QtTest 1.0 + +import global 1.0 + +TestCase { + name: "MathTests" + + + function test_escapeHtml() { + compare(Utils.escapeHtml("a&b"), "a&b", "escape &") + compare(Utils.escapeHtml("
"), "<br/>", "escape < and >") + compare(Utils.escapeHtml("\"Hello\""), ""Hello"", "escape \"") + } + +} diff --git a/test/qml_stationary/AusweisApp2/Global/test_Utils.qml b/test/qml_stationary/AusweisApp2/Global/test_Utils.qml new file mode 100644 index 0000000..46ba91d --- /dev/null +++ b/test/qml_stationary/AusweisApp2/Global/test_Utils.qml @@ -0,0 +1,16 @@ +import QtQuick 2.3 +import QtTest 1.0 + +import AusweisApp2.Global 1.0 + +TestCase { + name: "MathTests" + + + function test_escapeHtml() { + compare(Utils.escapeHtml("a&b"), "a&b", "escape &") + compare(Utils.escapeHtml("
"), "<br/>", "escape < and >") + compare(Utils.escapeHtml("\"Hello\""), ""Hello"", "escape \"") + } + +} diff --git a/test/qml_stationary/CMakeLists.txt b/test/qml_stationary/CMakeLists.txt new file mode 100644 index 0000000..5242c49 --- /dev/null +++ b/test/qml_stationary/CMakeLists.txt @@ -0,0 +1 @@ +ADD_QML_TEST_FILES(${RESOURCES_DIR}/qml_stationary) diff --git a/test/qt/CMakeLists.txt b/test/qt/CMakeLists.txt index 39b99f3..4bbfef4 100644 --- a/test/qt/CMakeLists.txt +++ b/test/qt/CMakeLists.txt @@ -5,11 +5,12 @@ FUNCTION(ADD_TEST_EXECUTABLE testname) TARGET_INCLUDE_DIRECTORIES(${testname} SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR}) TARGET_LINK_LIBRARIES(${testname} Qt5::Network Qt5::Xml Qt5::Test ${OPENSSL_LIBRARIES}) - TARGET_LINK_LIBRARIES(${testname} AusweisAppTestHelper AusweisAppCore AusweisAppCard AusweisAppCardDrivers AusweisAppGlobal AusweisAppServices AusweisAppSettings AusweisAppNetwork) - TARGET_LINK_LIBRARIES(${testname} AusweisAppActivationWebservice AusweisAppActivationInternal AusweisAppJsonApi) + TARGET_LINK_LIBRARIES(${testname} AusweisAppTestHelper AusweisAppCore AusweisAppCard AusweisAppGlobal AusweisAppServices AusweisAppSettings AusweisAppNetwork) + TARGET_LINK_LIBRARIES(${testname} AusweisAppActivationInternal AusweisAppJsonApi AusweisAppAidl AusweisAppQml) + TARGET_LINK_LIBRARIES(${testname} AusweisAppCardRemote) - IF(LINUX OR WIN32 OR MAC OR BSD) - TARGET_LINK_LIBRARIES(${testname} Qt5::Widgets AusweisAppWidget AusweisAppCardPcsc) + IF(DESKTOP) + TARGET_LINK_LIBRARIES(${testname} Qt5::Widgets AusweisAppWidget AusweisAppCardPcsc AusweisAppCardDrivers AusweisAppActivationWebservice) ENDIF() IF(LINUX OR ANDROID OR IOS) @@ -26,24 +27,6 @@ FUNCTION(ADD_TEST_EXECUTABLE testname) ENDFUNCTION() -FUNCTION(GET_TEST_CMDLINE cmdline testname) - IF(NOT WIN32 AND "${testname}" MATCHES "gui") - SET(PLATFORM -platform offscreen) - ENDIF() - - SET(${cmdline} ${PLATFORM} -v2 -o ${CMAKE_CURRENT_BINARY_DIR}/results.${testname}.log.xml,xml PARENT_SCOPE) -ENDFUNCTION() - - -FUNCTION(EXTRACT_TESTNAME result filepath) - STRING(REPLACE ".cpp" "" testname ${filepath}) - STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" testname ${testname}) - STRING(REPLACE "/" "_" testname ${testname}) - STRING(REPLACE "_test_" "_" testname ${testname}) - SET(${result} "Test_${testname}" PARENT_SCOPE) -ENDFUNCTION() - - FUNCTION(ADD_TEST_EXECUTABLE_SUBDIR) SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) IF(APPLE OR WIN32 OR BSD) @@ -51,10 +34,10 @@ FUNCTION(ADD_TEST_EXECUTABLE_SUBDIR) ENDIF() IF(IOS OR ANDROID) LIST(REMOVE_ITEM SUBDIRS gui) + LIST(REMOVE_ITEM SUBDIRS cli) LIST(REMOVE_ITEM SUBDIRS pcsc) - ENDIF() - IF(BSD) # remove me if platform is fixed - LIST(REMOVE_ITEM SUBDIRS gui) + LIST(REMOVE_ITEM SUBDIRS drivers) + LIST(REMOVE_ITEM SUBDIRS activation_webservice) ENDIF() FOREACH(SUBDIR ${SUBDIRS}) diff --git a/test/qt/activation/test_Template.cpp b/test/qt/activation_webservice/test_Template.cpp similarity index 69% rename from test/qt/activation/test_Template.cpp rename to test/qt/activation_webservice/test_Template.cpp index f48d630..75163e5 100644 --- a/test/qt/activation/test_Template.cpp +++ b/test/qt/activation_webservice/test_Template.cpp @@ -29,7 +29,7 @@ class test_Template void emptyTemplate() { - Template tplt(QString::null); + Template tplt(""); QCOMPARE(tplt.getContextKeys().size(), 0); } @@ -83,22 +83,22 @@ class test_Template void renderErrorPage() { - QLatin1String title("test titel"); - QLatin1String msg_header("nachrichten header"); - QLatin1String msg_header_expl("nachricht"); - QLatin1String error_msg("fehler"); - QLatin1String error_msg_label("fehler label"); - QLatin1String report_header("report_header"); - QLatin1String report_link("report_link"); - QLatin1String report_button("report_button"); + QString title("test titel"); + QString msg_header("nachrichten header"); + QString msg_header_expl("nachricht"); + QString error_msg("fehler"); + QString error_msg_label("fehler label"); + QString report_header("report_header"); + QString report_link("report_link"); + QString report_button("report_button"); Template tplt = Template::fromFile(QStringLiteral(":/html_templates/error.html")); - tplt.setContextParameter(QLatin1String("TITLE"), title); - tplt.setContextParameter(QLatin1String("MESSAGE_HEADER"), msg_header); - tplt.setContextParameter(QLatin1String("MESSAGE_HEADER_EXPLANATION"), msg_header_expl); - tplt.setContextParameter(QLatin1String("ERROR_MESSAGE_LABEL"), error_msg_label); - tplt.setContextParameter(QLatin1String("ERROR_MESSAGE"), error_msg); + tplt.setContextParameter(QStringLiteral("TITLE"), title); + tplt.setContextParameter(QStringLiteral("MESSAGE_HEADER"), msg_header); + tplt.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), msg_header_expl); + tplt.setContextParameter(QStringLiteral("ERROR_MESSAGE_LABEL"), error_msg_label); + tplt.setContextParameter(QStringLiteral("ERROR_MESSAGE"), error_msg); tplt.setContextParameter(QStringLiteral("REPORT_HEADER"), report_header); tplt.setContextParameter(QStringLiteral("REPORT_LINK"), report_link); tplt.setContextParameter(QStringLiteral("REPORT_BUTTON"), report_button); @@ -119,21 +119,21 @@ class test_Template void renderAlreadyActivePage() { - QLatin1String title("test titel"); - QLatin1String msg_header("nachrichten header"); - QLatin1String msg_header_expl("nachricht"); - QLatin1String content_header("inhalt header"); - QLatin1String content_link("inhalt link"); - QLatin1String content_button("inhalt button"); + QString title("test titel"); + QString msg_header("nachrichten header"); + QString msg_header_expl("nachricht"); + QString content_header("inhalt header"); + QString content_link("inhalt link"); + QString content_button("inhalt button"); Template tplt = Template::fromFile(QStringLiteral(":/html_templates/alreadyactive.html")); - tplt.setContextParameter(QLatin1String("TITLE"), title); - tplt.setContextParameter(QLatin1String("MESSAGE_HEADER"), msg_header); - tplt.setContextParameter(QLatin1String("MESSAGE_HEADER_EXPLANATION"), msg_header_expl); - tplt.setContextParameter(QLatin1String("CONTENT_HEADER"), content_header); - tplt.setContextParameter(QLatin1String("CONTENT_LINK"), content_link); - tplt.setContextParameter(QLatin1String("CONTENT_BUTTON"), content_button); + tplt.setContextParameter(QStringLiteral("TITLE"), title); + tplt.setContextParameter(QStringLiteral("MESSAGE_HEADER"), msg_header); + tplt.setContextParameter(QStringLiteral("MESSAGE_HEADER_EXPLANATION"), msg_header_expl); + tplt.setContextParameter(QStringLiteral("CONTENT_HEADER"), content_header); + tplt.setContextParameter(QStringLiteral("CONTENT_LINK"), content_link); + tplt.setContextParameter(QStringLiteral("CONTENT_BUTTON"), content_button); const auto& errorPage = tplt.render(); QCOMPARE(tplt.getContextKeys().size(), 6); diff --git a/test/qt/activation/test_WebserviceActivationHandler.cpp b/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp similarity index 61% rename from test/qt/activation/test_WebserviceActivationHandler.cpp rename to test/qt/activation_webservice/test_WebserviceActivationHandler.cpp index 0129dff..befc80f 100644 --- a/test/qt/activation/test_WebserviceActivationHandler.cpp +++ b/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp @@ -8,10 +8,8 @@ #include "WebserviceActivationHandler.h" #include "LogHandler.h" -#include "MockQHttpConnection.h" +#include "MockSocket.h" #include "ResourceLoader.h" -#include "qhttpserver/qhttprequest.h" -#include "qhttpserver/qhttpresponse.h" #include #include @@ -23,10 +21,9 @@ class test_WebserviceActivationHandler : public QObject { Q_OBJECT - QSharedPointer mConnection; WebserviceActivationHandler mHandler; - QSharedPointer mRequest; - QSharedPointer mResponse; + QPointer mSocket; + QSharedPointer mRequest; QScopedPointer mShowUiSpy, mShowUserInfoSpy, mAuthenticationSpy; private Q_SLOTS: @@ -39,9 +36,8 @@ class test_WebserviceActivationHandler void init() { - mConnection.reset(new MockQHttpConnection()); - mRequest.reset(new QHttpRequest()); - mResponse.reset(new QHttpResponse(mConnection)); + mSocket = new MockSocket(); + mRequest.reset(new HttpRequest(mSocket)); mShowUiSpy.reset(new QSignalSpy(&mHandler, &WebserviceActivationHandler::fireShowUiRequest)); mShowUserInfoSpy.reset(new QSignalSpy(&mHandler, &WebserviceActivationHandler::fireShowUserInformation)); mAuthenticationSpy.reset(new QSignalSpy(&mHandler, &WebserviceActivationHandler::fireAuthenticationRequest)); @@ -56,9 +52,9 @@ class test_WebserviceActivationHandler void showUI_noModule() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -69,9 +65,9 @@ class test_WebserviceActivationHandler void showUI_moduleCurrent() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI=current")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI=current"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -82,9 +78,9 @@ class test_WebserviceActivationHandler void showUI_modulePINManagement() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI=PINManagement")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI=PINManagement"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -95,9 +91,9 @@ class test_WebserviceActivationHandler void showUI_modulePINManagement_caseInsensitive() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?showui=pinManagement")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?showui=pinManagement"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -108,9 +104,9 @@ class test_WebserviceActivationHandler void showUI_moduleSettings() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI=Settings")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI=Settings"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -121,61 +117,61 @@ class test_WebserviceActivationHandler void status_noFormat() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?status")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?status"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mShowUiSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); QCOMPARE(mAuthenticationSpy->count(), 0); - QCOMPARE(mResponse->m_headers.value("Content-Type"), QString("text/plain; charset=utf-8")); + QVERIFY(mSocket->mWriteBuffer.contains("Content-Type: text/plain; charset=utf-8")); } void status_formatPlain() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?status=plain")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?status=plain"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mShowUiSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); QCOMPARE(mAuthenticationSpy->count(), 0); - QCOMPARE(mResponse->m_headers.value("Content-Type"), QString("text/plain; charset=utf-8")); + QVERIFY(mSocket->mWriteBuffer.contains("Content-Type: text/plain; charset=utf-8")); } void status_formatJson() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?status=json")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?status=json"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mShowUiSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); QCOMPARE(mAuthenticationSpy->count(), 0); - QCOMPARE(mResponse->m_headers.value("Content-Type"), QString("application/json")); + QVERIFY(mSocket->mWriteBuffer.contains("Content-Type: application/json")); } void status_formatJson_caseInsensitive() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?status=JsoN")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?status=JsoN"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mShowUiSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); QCOMPARE(mAuthenticationSpy->count(), 0); - QCOMPARE(mResponse->m_headers.value("Content-Type"), QString("application/json")); + QVERIFY(mSocket->mWriteBuffer.contains("Content-Type: application/json")); } void authentication() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?tctokenURL=bla")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?tctokenURL=bla"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mShowUiSpy->count(), 0); QCOMPARE(mShowUserInfoSpy->count(), 0); @@ -185,21 +181,20 @@ class test_WebserviceActivationHandler void unknownRequest() { - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?unknownRequest")); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?unknownRequest"); - mHandler.onNewRequest(mRequest, mResponse); - - QVERIFY(mConnection->mContent.contains("HTTP/1.1 404 Not Found")); + mHandler.onNewRequest(mRequest); + QVERIFY(mSocket->mWriteBuffer.contains("HTTP/1.0 404 NOT FOUND")); } void sameUserAgentVersion() { QCoreApplication::setApplicationVersion("1.0.0"); - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI")); - mRequest->m_headers.insert("user-agent", QCoreApplication::applicationName() + "/" + QCoreApplication::applicationVersion() + " (TR-03124-1/1.2)"); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI"); + mRequest->mHeader.insert("user-agent", QCoreApplication::applicationName().toUtf8() + '/' + QCoreApplication::applicationVersion().toUtf8() + " (TR-03124-1/1.2)"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUiSpy->count(), 1); @@ -211,10 +206,10 @@ class test_WebserviceActivationHandler { QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); QCoreApplication::setApplicationVersion("1.0.0"); - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI")); - mRequest->m_headers.insert("user-agent", QCoreApplication::applicationName() + "/0.0.0 (TR-03124-1/1.2)"); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI"); + mRequest->mHeader.insert("user-agent", QCoreApplication::applicationName().toUtf8() + "/0.0.0 (TR-03124-1/1.2)"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUiSpy->count(), 0); @@ -231,10 +226,10 @@ class test_WebserviceActivationHandler { QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); QCoreApplication::setApplicationVersion("1.0.0"); - mRequest->setUrl(QUrl("http://localhost:24727/eID-Client?ShowUI")); - mRequest->m_headers.insert("user-agent", QCoreApplication::applicationName() + "/2.0.0 (TR-03124-1/1.2)"); + mRequest->mUrl = QByteArray("http://localhost:24727/eID-Client?ShowUI"); + mRequest->mHeader.insert("user-agent", QCoreApplication::applicationName().toUtf8() + "/2.0.0 (TR-03124-1/1.2)"); - mHandler.onNewRequest(mRequest, mResponse); + mHandler.onNewRequest(mRequest); QCOMPARE(mAuthenticationSpy->count(), 0); QCOMPARE(mShowUiSpy->count(), 0); diff --git a/test/qt/aidl/test_PskManager.cpp b/test/qt/aidl/test_PskManager.cpp new file mode 100644 index 0000000..d3de053 --- /dev/null +++ b/test/qt/aidl/test_PskManager.cpp @@ -0,0 +1,58 @@ +/*! + * \brief Unit tests for PskManager. + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "PskManager.h" + +#include + +using namespace governikus; + +class test_PskManager + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void isSecure() + { + QVERIFY(!PskManager::getInstance().isSecureRandomPsk()); + QVERIFY(!PskManager::getInstance().generatePsk().isEmpty()); + QVERIFY(PskManager::getInstance().isSecureRandomPsk()); + } + + + void generatePskWithoutClientPartial() + { + QByteArray prev; + for (int i = 0; i < 100; ++i) + { + const auto& tmp = PskManager::getInstance().generatePsk(); + QVERIFY(prev != tmp); + QCOMPARE(tmp, PskManager::getInstance().getPsk()); + QVERIFY(PskManager::getInstance().isSecureRandomPsk()); + prev = tmp; + } + } + + + void generatePskWithClientPartial() + { + QByteArray prev("0xABCDEF"); + for (int i = 0; i < 100; ++i) + { + const auto& tmp = PskManager::getInstance().generatePsk(prev); + QVERIFY(prev != tmp); + QCOMPARE(tmp, PskManager::getInstance().getPsk()); + QVERIFY(PskManager::getInstance().isSecureRandomPsk()); + prev = tmp; + } + } + + +}; + +QTEST_GUILESS_MAIN(test_PskManager) +#include "test_PskManager.moc" diff --git a/test/qt/bluetooth/test_BluetoothMessage.cpp b/test/qt/bluetooth/test_BluetoothMessage.cpp index a5dc354..0ed852e 100644 --- a/test/qt/bluetooth/test_BluetoothMessage.cpp +++ b/test/qt/bluetooth/test_BluetoothMessage.cpp @@ -17,14 +17,6 @@ class test_BluetoothMessage Q_OBJECT private Q_SLOTS: - void get() - { - BluetoothMessage msg(BluetoothMsgId::StatusInd); - const BluetoothMessageStatusInd* obj = msg.get(); - QVERIFY(obj != nullptr); - } - - void statusIndCtor() { BluetoothMessageStatusInd msg; @@ -34,11 +26,10 @@ class test_BluetoothMessage void statusIndStatusChange() { - BluetoothMessageParameterStatusChange param(getEnumByteValue(BluetoothStatusChange::CardRecovered)); + BluetoothMessageParameterStatusChange param(QByteArray(1, Enum::getValue(BluetoothStatusChange::CardRecovered))); BluetoothMessageStatusInd msg; msg.copyParameter(param); - QVERIFY(msg.getParamStatusChange()->get() != nullptr); QCOMPARE(msg.getStatusChange(), BluetoothStatusChange::CardRecovered); } diff --git a/test/qt/bluetooth/test_BluetoothMessageParser.cpp b/test/qt/bluetooth/test_BluetoothMessageParser.cpp index 57b0f50..f1ae910 100644 --- a/test/qt/bluetooth/test_BluetoothMessageParser.cpp +++ b/test/qt/bluetooth/test_BluetoothMessageParser.cpp @@ -35,13 +35,15 @@ class test_BluetoothMessageParser BluetoothMessage::Ptr message = parser1.getMessages().at(0); QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::TransferApduResponse); - QCOMPARE(message->getParameterList().size(), 2); + QCOMPARE(message->mMessageParameter.size(), 2); - QCOMPARE(message->getParameterList().at(0)->getParameterId(), BluetoothParamId::ResultCode); - QCOMPARE(message->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothResultCode::Ok)); + const auto& params = message->mMessageParameter; + QCOMPARE(params.first()->getParameterId(), BluetoothParamId::ResultCode); + QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothResultCode::Ok))); - auto paramApdu = message->getParameterList().at(1)->get(); - QCOMPARE(paramApdu->getParameterId(), BluetoothParamId::ResponseAPDU); + const auto param = params.last(); + QCOMPARE(param->getParameterId(), BluetoothParamId::ResponseAPDU); + const auto paramApdu = param.staticCast(); QCOMPARE(paramApdu->getResponseApdu(), QByteArray::fromHex("3081f9a106040400000000a20404029000a381c43181c1300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020141302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145a42204209ee959c9f063c6e144b463e04fa19ef44da0f5059d817a7db2240bbee8b218a29000")); } @@ -56,7 +58,7 @@ class test_BluetoothMessageParser BluetoothMessage::Ptr message = parser1.getMessages().at(0); QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - auto msgInd = message->get(); + auto msgInd = message.staticCast(); QCOMPARE(msgInd->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardNotAccessible")); QCOMPARE(msgInd->getStatusChange(), BluetoothStatusChange::CardNotAccessible); } @@ -83,12 +85,14 @@ class test_BluetoothMessageParser QCOMPARE(parser1.getRemainingBytes().size(), 0); QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::TransferAtrResponse); - QCOMPARE(parser1.getMessages()[0]->getParameterList().size(), 2); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getParameterId(), BluetoothParamId::ResultCode); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothResultCode::Ok)); + QCOMPARE(parser1.getMessages()[0]->mMessageParameter.size(), 2); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(1)->getParameterId(), BluetoothParamId::ATR); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(1)->getValue(), QByteArray::fromHex("4b8a80018031f873f741e082900075")); + const auto& params = parser1.getMessages()[0]->mMessageParameter; + QCOMPARE(params.first()->getParameterId(), BluetoothParamId::ResultCode); + QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothResultCode::Ok))); + + QCOMPARE(params.last()->getParameterId(), BluetoothParamId::ATR); + QCOMPARE(params.last()->getValue(), QByteArray::fromHex("4b8a80018031f873f741e082900075")); QCOMPARE(parser1.getMessages()[0]->toString(), QString("TransferAtrResponse | Parameter: ResultCode | Value: Ok | Parameter: ATR | Value: 4b8a80018031f873f741e082900075")); @@ -105,14 +109,18 @@ class test_BluetoothMessageParser QCOMPARE(parser1.getRemainingBytes().size(), 0); QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - QCOMPARE(parser1.getMessages()[0]->getParameterList().size(), 1); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getParameterId(), BluetoothParamId::StatusChange); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothStatusChange::CardInserted)); + QCOMPARE(parser1.getMessages()[0]->mMessageParameter.size(), 1); + + const auto& params = parser1.getMessages()[0]->mMessageParameter; + QCOMPARE(params.first()->getParameterId(), BluetoothParamId::StatusChange); + QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothStatusChange::CardInserted))); QCOMPARE(parser1.getMessages()[1]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - QCOMPARE(parser1.getMessages()[1]->getParameterList().size(), 1); - QCOMPARE(parser1.getMessages()[1]->getParameterList().at(0)->getParameterId(), BluetoothParamId::StatusChange); - QCOMPARE(parser1.getMessages()[1]->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothStatusChange::CardRemoved)); + QCOMPARE(parser1.getMessages()[1]->mMessageParameter.size(), 1); + + const auto& paramsInd = parser1.getMessages()[1]->mMessageParameter; + QCOMPARE(paramsInd.first()->getParameterId(), BluetoothParamId::StatusChange); + QCOMPARE(paramsInd.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothStatusChange::CardRemoved))); } @@ -125,18 +133,22 @@ class test_BluetoothMessageParser QCOMPARE(parser1.getMessages().size(), 1); QCOMPARE(parser1.getRemainingBytes().size(), 0); QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - QCOMPARE(parser1.getMessages()[0]->getParameterList().size(), 1); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getParameterId(), BluetoothParamId::StatusChange); - QCOMPARE(parser1.getMessages()[0]->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothStatusChange::CardInserted)); + QCOMPARE(parser1.getMessages()[0]->mMessageParameter.size(), 1); + + const auto& params = parser1.getMessages()[0]->mMessageParameter; + QCOMPARE(params.first()->getParameterId(), BluetoothParamId::StatusChange); + QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothStatusChange::CardInserted))); response = QByteArray::fromHex("110100000800000103000000"); BluetoothMessageParser parser2(response); QCOMPARE(parser2.getMessages().size(), 1); QCOMPARE(parser2.getRemainingBytes().size(), 0); QCOMPARE(parser2.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - QCOMPARE(parser2.getMessages()[0]->getParameterList().size(), 1); - QCOMPARE(parser2.getMessages()[0]->getParameterList().at(0)->getParameterId(), BluetoothParamId::StatusChange); - QCOMPARE(parser2.getMessages()[0]->getParameterList().at(0)->getValue(), getEnumByteValue(BluetoothStatusChange::CardRemoved)); + QCOMPARE(parser2.getMessages()[0]->mMessageParameter.size(), 1); + + const auto& paramsStatus = parser2.getMessages()[0]->mMessageParameter; + QCOMPARE(paramsStatus.first()->getParameterId(), BluetoothParamId::StatusChange); + QCOMPARE(paramsStatus.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothStatusChange::CardRemoved))); } diff --git a/test/qt/card/asn1/test_Asn1Util.cpp b/test/qt/card/asn1/test_Asn1Util.cpp new file mode 100644 index 0000000..cef8097 --- /dev/null +++ b/test/qt/card/asn1/test_Asn1Util.cpp @@ -0,0 +1,63 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "asn1/ASN1Util.h" + +#include +#include + + +using namespace governikus; + + +class test_Asn1Util + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void encodeEmptyData() + { + auto data = QByteArray(); + + auto encoded = Asn1Util::encode(0x20, data); + + QCOMPARE(encoded, QByteArray::fromHex("2000")); + } + + + void encodeShortLengthData() + { + auto data = QByteArray::fromHex("01").repeated(0x10); + + auto encoded = Asn1Util::encode(0x20, data); + + QCOMPARE(encoded, QByteArray::fromHex("2010").append(data)); + } + + + void encodeShortLengthMaxData() + { + auto data = QByteArray::fromHex("01").repeated(0x7F); + + auto encoded = Asn1Util::encode(0x20, data); + + QCOMPARE(encoded, QByteArray::fromHex("207F").append(data)); + } + + + void encodeExtendedLengthData() + { + auto data = QByteArray::fromHex("01").repeated(0xFF); + + auto encoded = Asn1Util::encode(0x20, data); + + QCOMPARE(encoded, QByteArray::fromHex("2081FF").append(data)); + } + + +}; + +QTEST_GUILESS_MAIN(test_Asn1Util) +#include "test_Asn1Util.moc" diff --git a/test/qt/card/asn1/test_CVCertificate.cpp b/test/qt/card/asn1/test_CVCertificate.cpp index 6130624..a10a440 100644 --- a/test/qt/card/asn1/test_CVCertificate.cpp +++ b/test/qt/card/asn1/test_CVCertificate.cpp @@ -4,14 +4,15 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include -#include +#include "asn1/CVCertificate.h" + +#include "LogHandler.h" #include "TestFileHelper.h" #include "asn1/ASN1Util.h" -#include "asn1/CVCertificate.h" #include "asn1/KnownOIDs.h" +#include using namespace governikus; @@ -34,6 +35,18 @@ class test_CVCertificate private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + void getRawBody() { QByteArray body("7f4e82016e5f290100420e44454356434165494430303130337f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641048925419fc7f194922cfc6b8dd25ae6a19c1b59216e6cf06270e5d75cfd64205f55cf867bbfefeefd6e680e1fd197f18ab684484901362568efc9adb5c6018d728701015f200e44454356434165494430303130337f4c12060904007f0007030102025305fc0f13ffff5f25060102010200035f2406010501020003"); @@ -124,6 +137,55 @@ class test_CVCertificate } + void debugStream() + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + + QLatin1String output(R"(CVC(type=CVCA, car="DETESTeID00001", chr="DETESTeID00001", valid=["2010-08-13","2013-08-13"])"); + QSharedPointer cvca = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + + qDebug() << cvca; + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains(output)); + + QSharedPointer cvcsConst(cvca); + qDebug() << cvcsConst; + QCOMPARE(spy.count(), 1); + param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains(output)); + + QVector > cvcsVector({cvca}); + qDebug() << cvcsVector; + QCOMPARE(spy.count(), 1); + param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains(output)); + + QVector > cvcsVectorConst({cvca}); + qDebug() << cvcsVectorConst; + QCOMPARE(spy.count(), 1); + param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains(output)); + } + + + void equals() + { + QSharedPointer cvca1 = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + QSharedPointer cvca2 = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + QVERIFY(cvca1 == cvca2); + + QSharedPointer cvca1_const = cvca1; + QSharedPointer cvca2_const = cvca2; + QVERIFY(cvca1_const == cvca2_const); + + QVERIFY(cvca1 == cvca2_const); + QVERIFY(cvca2_const == cvca1); + QVERIFY(cvca1_const == cvca2); + QVERIFY(cvca2 == cvca1_const); + } + + }; QTEST_GUILESS_MAIN(test_CVCertificate) diff --git a/test/qt/card/asn1/test_EcdsaPublicKey.cpp b/test/qt/card/asn1/test_EcdsaPublicKey.cpp index c94ab1b..9163457 100644 --- a/test/qt/card/asn1/test_EcdsaPublicKey.cpp +++ b/test/qt/card/asn1/test_EcdsaPublicKey.cpp @@ -219,10 +219,11 @@ class test_EcdsaPublicKey const EC_POINT* generator = EC_GROUP_get0_generator(ecGroup); - int bufLen = EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); + auto bufLen = EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); - QVector buf(bufLen); - EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast(buf.data()), buf.size(), nullptr); + Q_ASSERT(bufLen <= INT_MAX); + QVector buf(static_cast(bufLen)); + EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast(buf.data()), static_cast(buf.size()), nullptr); QCOMPARE(QByteArray(buf.data(), buf.size()).toHex().toUpper(), QByteArray("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")); QCOMPARE(ecdsaPublicKey->getPublicKeyOid(), QByteArray("0.4.0.127.0.7.2.2.2.2.3")); @@ -273,10 +274,11 @@ class test_EcdsaPublicKey const EC_POINT* generator = EC_GROUP_get0_generator(ecGroup); - int bufLen = EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); + auto bufLen = EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); + Q_ASSERT(bufLen <= INT_MAX); - QVector buf(bufLen); - EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast(buf.data()), buf.size(), nullptr); + QVector buf(static_cast(bufLen)); + EC_POINT_point2oct(ecGroup, generator, point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast(buf.data()), static_cast(buf.size()), nullptr); QCOMPARE(QByteArray(buf.data(), buf.size()).toHex().toUpper(), QByteArray("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")); QCOMPARE(ecdsaPublicKey->getPublicKeyOid(), QByteArray("0.4.0.127.0.7.2.2.2.2.3")); diff --git a/test/qt/card/asn1/test_SecurityInfos.cpp b/test/qt/card/asn1/test_SecurityInfos.cpp index e8e4ed9..7336292 100644 --- a/test/qt/card/asn1/test_SecurityInfos.cpp +++ b/test/qt/card/asn1/test_SecurityInfos.cpp @@ -33,7 +33,7 @@ class test_SecurityInfos auto securityInfos = SecurityInfos::fromHex(hexString); QVERIFY(securityInfos != nullptr); - QCOMPARE(securityInfos->getSecurityInfos().size(), 0); + QCOMPARE(securityInfos->getSecurityInfos().size(), 0); } @@ -59,9 +59,9 @@ class test_SecurityInfos auto securityInfos = SecurityInfos::fromHex(hexString); QVERIFY(securityInfos != nullptr); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); - QCOMPARE(securityInfos->getSecurityInfos().size(), 0); + QCOMPARE(securityInfos->getSecurityInfos().size(), 1); + QCOMPARE(securityInfos->getPACEInfos().size(), 1); + QCOMPARE(securityInfos->getChipAuthenticationInfos().size(), 0); } @@ -76,9 +76,9 @@ class test_SecurityInfos auto securityInfos = SecurityInfos::fromHex(hexString); QVERIFY(securityInfos != nullptr); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); - QCOMPARE(securityInfos->getSecurityInfos().size(), 0); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); + QCOMPARE(securityInfos->getSecurityInfos().size(), 1); + QCOMPARE(securityInfos->getPACEInfos().size(), 0); + QCOMPARE(securityInfos->getChipAuthenticationInfos().size(), 1); } @@ -101,9 +101,9 @@ class test_SecurityInfos auto securityInfos = SecurityInfos::fromHex(hexString); QVERIFY(securityInfos != nullptr); - QCOMPARE(securityInfos->getSecurityInfos().size(), 3); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); - QCOMPARE(securityInfos->getSecurityInfos().size(), 1); + QCOMPARE(securityInfos->getSecurityInfos().size(), 3); + QCOMPARE(securityInfos->getPACEInfos().size(), 1); + QCOMPARE(securityInfos->getChipAuthenticationInfos().size(), 1); } diff --git a/test/qt/card/asn1/test_efCardAccess.cpp b/test/qt/card/asn1/test_efCardAccess.cpp index 7759013..7d10659 100644 --- a/test/qt/card/asn1/test_efCardAccess.cpp +++ b/test/qt/card/asn1/test_efCardAccess.cpp @@ -2,16 +2,13 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include -#include -#include -#include - #include "TestFileHelper.h" #include "asn1/ChipAuthenticationInfo.h" #include "asn1/PACEInfo.h" #include "asn1/SecurityInfos.h" +#include + using namespace governikus; class test_efCardAccess @@ -32,8 +29,8 @@ class test_efCardAccess auto efCardAccess = EFCardAccess::decode(bytes); QVERIFY(efCardAccess != nullptr); - QCOMPARE(efCardAccess->getSecurityInfos().size(), 1); - QCOMPARE(efCardAccess->getSecurityInfos().size(), 1); + QCOMPARE(efCardAccess->getChipAuthenticationInfos().size(), 1); + QCOMPARE(efCardAccess->getPACEInfos().size(), 1); QCOMPARE(efCardAccess->getContentBytes(), bytes); } diff --git a/test/qt/card/asn1/test_efCardSecurity.cpp b/test/qt/card/asn1/test_efCardSecurity.cpp index 884532b..1281d9e 100644 --- a/test/qt/card/asn1/test_efCardSecurity.cpp +++ b/test/qt/card/asn1/test_efCardSecurity.cpp @@ -4,14 +4,12 @@ * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG */ -#include -#include -#include -#include - #include "TestFileHelper.h" #include "asn1/EFCardSecurity.h" +#include +#include + using namespace governikus; class test_efCardSecurity @@ -143,7 +141,7 @@ class test_efCardSecurity auto efCardSecurity = EFCardSecurity::decode(bytes); QVERIFY(efCardSecurity != nullptr); - QCOMPARE(efCardSecurity->getSecurityInfos().size(), 9); + QCOMPARE(efCardSecurity->getSecurityInfos()->getSecurityInfos().size(), 9); } diff --git a/test/qt/card/base/command/test_BaseCardCommand.cpp b/test/qt/card/base/command/test_BaseCardCommand.cpp index d1ab50b..61b64fd 100644 --- a/test/qt/card/base/command/test_BaseCardCommand.cpp +++ b/test/qt/card/base/command/test_BaseCardCommand.cpp @@ -28,7 +28,7 @@ class BaseCardCommandDummy virtual void internalExecute() { - mReturnCode = ReturnCode::OK; + mReturnCode = CardReturnCode::OK; } @@ -44,7 +44,7 @@ class test_BaseCardCommand { MockReader reader("dummy reader"); BaseCardCommandDummy command(&reader); - QCOMPARE(command.getReturnCode(), ReturnCode::UNKNOWN); + QCOMPARE(command.getReturnCode(), CardReturnCode::UNKNOWN); QSignalSpy spy(&command, &BaseCardCommand::commandDone); QMetaObject::invokeMethod(&command, "execute"); @@ -53,7 +53,7 @@ class test_BaseCardCommand auto param = spy.takeFirst(); QSharedPointer sharedCommand = param.at(0).value >(); QCOMPARE(sharedCommand.data(), &command); - QCOMPARE(command.getReturnCode(), ReturnCode::OK); + QCOMPARE(command.getReturnCode(), CardReturnCode::OK); } @@ -61,7 +61,7 @@ class test_BaseCardCommand { MockReader reader("dummy reader"); BaseCardCommandDummy command(&reader); - QCOMPARE(command.checkRetryCounterAndPrepareForPace("test"), ReturnCode::NO_CARD); + QCOMPARE(command.checkRetryCounterAndPrepareForPace("test"), CardReturnCode::CARD_NOT_FOUND); } diff --git a/test/qt/card/pace/test_CipherMAC.cpp b/test/qt/card/pace/test_CipherMAC.cpp index fb29f6e..6b848dd 100644 --- a/test/qt/card/pace/test_CipherMAC.cpp +++ b/test/qt/card/pace/test_CipherMAC.cpp @@ -2,15 +2,11 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ - -#include -#include -#include - #include "asn1/KnownOIDs.h" #include "pace/CipherMac.h" #include "pace/KeyDerivationFunction.h" +#include using namespace governikus; diff --git a/test/qt/card/pace/test_EcUtil.cpp b/test/qt/card/pace/test_EcUtil.cpp index 1ce4cc5..3c8afd1 100644 --- a/test/qt/card/pace/test_EcUtil.cpp +++ b/test/qt/card/pace/test_EcUtil.cpp @@ -2,15 +2,12 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include -#include -#include -#include -#include - #include "pace/ec/EcUtil.h" #include "pace/ec/EllipticCurveFactory.h" +#include +#include +#include using namespace governikus; diff --git a/test/qt/card/pace/test_EcdhKeyAgreement.cpp b/test/qt/card/pace/test_EcdhKeyAgreement.cpp index 9324fee..b24c2e5 100644 --- a/test/qt/card/pace/test_EcdhKeyAgreement.cpp +++ b/test/qt/card/pace/test_EcdhKeyAgreement.cpp @@ -38,9 +38,9 @@ class test_EcdhKeyAgreement void perform_failureOnGetNonce() { QVector transmitConfigs; - transmitConfigs.append(TransmitConfig(ReturnCode::OK, QByteArray::fromHex("6982"))); + transmitConfigs.append(TransmitConfig(CardReturnCode::OK, QByteArray::fromHex("6982"))); QScopedPointer reader(MockReader::createMockReader(transmitConfigs, mEfCardAccess)); - QSharedPointer paceInfo = mEfCardAccess->getSecurityInfos().at(0); + QSharedPointer paceInfo = mEfCardAccess->getPACEInfos().at(0); QScopedPointer keyAgreement(new EcdhKeyAgreement(paceInfo, reader->createCardConnectionWorker())); KeyAgreementStatus result = keyAgreement->perform("123456"); diff --git a/test/qt/card/pace/test_EllipticCurveFactory.cpp b/test/qt/card/pace/test_EllipticCurveFactory.cpp index 31ff076..1349b0d 100644 --- a/test/qt/card/pace/test_EllipticCurveFactory.cpp +++ b/test/qt/card/pace/test_EllipticCurveFactory.cpp @@ -2,15 +2,11 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ - -#include -#include -#include -#include -#include - #include "pace/ec/EllipticCurveFactory.h" +#include +#include +#include using namespace governikus; diff --git a/test/qt/card/pace/test_KeyDerivationFunction.cpp b/test/qt/card/pace/test_KeyDerivationFunction.cpp index 21e007e..7645cb4 100644 --- a/test/qt/card/pace/test_KeyDerivationFunction.cpp +++ b/test/qt/card/pace/test_KeyDerivationFunction.cpp @@ -2,13 +2,11 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include -#include -#include - #include "asn1/KnownOIDs.h" #include "pace/KeyDerivationFunction.h" +#include + using namespace governikus; /** diff --git a/test/qt/card/pace/test_PaceHandler.cpp b/test/qt/card/pace/test_PaceHandler.cpp index f588101..890da90 100644 --- a/test/qt/card/pace/test_PaceHandler.cpp +++ b/test/qt/card/pace/test_PaceHandler.cpp @@ -52,9 +52,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader()); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -64,9 +64,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -76,9 +76,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -88,9 +88,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -100,9 +100,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -112,9 +112,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -124,9 +124,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -136,9 +136,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -148,9 +148,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -160,9 +160,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -172,9 +172,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -184,9 +184,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -196,9 +196,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -208,9 +208,9 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -218,14 +218,14 @@ class test_PaceHandler void failureOnMseSetAt() { QVector transmitConfigs; - transmitConfigs.append(TransmitConfig(ReturnCode::OK, QByteArray::fromHex("9000"))); // Select file - transmitConfigs.append(TransmitConfig(ReturnCode::OK, QByteArray::fromHex("6A80"))); // MSE:Set AT + transmitConfigs.append(TransmitConfig(CardReturnCode::OK, QByteArray::fromHex("9000"))); // Select file + transmitConfigs.append(TransmitConfig(CardReturnCode::OK, QByteArray::fromHex("6A80"))); // MSE:Set AT QScopedPointer reader(MockReader::createMockReader(transmitConfigs, mEfCardAccessBytes)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - ReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); - QCOMPARE(status, ReturnCode::PROTOCOL_ERROR); + QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } diff --git a/test/qt/card/pace/test_SymmetricCipher.cpp b/test/qt/card/pace/test_SymmetricCipher.cpp index c470461..7ea8bbf 100644 --- a/test/qt/card/pace/test_SymmetricCipher.cpp +++ b/test/qt/card/pace/test_SymmetricCipher.cpp @@ -2,15 +2,12 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include -#include -#include -#include - #include "asn1/KnownOIDs.h" #include "pace/KeyDerivationFunction.h" #include "pace/SymmetricCipher.h" +#include +#include using namespace governikus; diff --git a/test/qt/card/test_Command.cpp b/test/qt/card/test_Command.cpp index 8a19547..647ed34 100644 --- a/test/qt/card/test_Command.cpp +++ b/test/qt/card/test_Command.cpp @@ -66,8 +66,9 @@ class test_Command void testPinModifyBuilder_createChangeEidPinCommandData() { PinModifyBuilder builder; - unsigned int timeout = 77; - QCOMPARE(builder.createChangeEidPinCommandData(timeout), QByteArray::fromHex("82000000000606010202070400010200000004000000002C0203").prepend(timeout).prepend(timeout)); + quint8 timeout = 77; + auto timeoutBytes = QByteArray::fromHex(QByteArray::number(timeout, 16)); + QCOMPARE(builder.createChangeEidPinCommandData(timeout), QByteArray::fromHex("82000000000606010202070400010200000004000000002C0203").prepend(timeoutBytes).prepend(timeoutBytes)); } diff --git a/test/qt/card/test_EstablishPACEChannelOutput.cpp b/test/qt/card/test_EstablishPACEChannelOutput.cpp index bd53e49..6e6bb02 100644 --- a/test/qt/card/test_EstablishPACEChannelOutput.cpp +++ b/test/qt/card/test_EstablishPACEChannelOutput.cpp @@ -52,7 +52,7 @@ class test_EstablishPACEChannelOutput EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(bytes, PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::OK, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::OK, channelOutput.getPaceReturnCode()); QCOMPARE(channelOutput.getCARcurr(), QByteArray("DECVCAeID00103")); QCOMPARE(channelOutput.getCARprev(), QByteArray("DECVCAeID00102")); QVERIFY(!channelOutput.getEfCardAccess().isEmpty()); @@ -66,7 +66,7 @@ class test_EstablishPACEChannelOutput EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(bytes, PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::OK, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::OK, channelOutput.getPaceReturnCode()); QVERIFY(channelOutput.getCARcurr().isEmpty()); QVERIFY(channelOutput.getCARprev().isEmpty()); QVERIFY(!channelOutput.getEfCardAccess().isEmpty()); @@ -88,7 +88,7 @@ class test_EstablishPACEChannelOutput EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::UNKNOWN, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::UNKNOWN, channelOutput.getPaceReturnCode()); QCOMPARE(channelOutput.getCARcurr(), QByteArray()); QCOMPARE(channelOutput.getCARprev(), QByteArray()); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray()); @@ -110,7 +110,7 @@ class test_EstablishPACEChannelOutput EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); QCOMPARE(channelOutput.getCARcurr(), QByteArray()); QCOMPARE(channelOutput.getCARprev(), QByteArray()); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray::fromHex("3100")); @@ -132,7 +132,7 @@ class test_EstablishPACEChannelOutput EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); QCOMPARE(channelOutput.getCARcurr(), QByteArray("DECVCAeID00103")); QCOMPARE(channelOutput.getCARprev(), QByteArray("DECVCAeID00102")); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray::fromHex("3100")); @@ -158,7 +158,7 @@ class test_EstablishPACEChannelOutput ); EstablishPACEChannelOutput channelOutput; channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); - QCOMPARE(ReturnCode::PIN_INVALID, channelOutput.getPaceReturnCode()); + QCOMPARE(CardReturnCode::INVALID_PIN, channelOutput.getPaceReturnCode()); } diff --git a/test/qt/card/test_MSEBuilder.cpp b/test/qt/card/test_MSEBuilder.cpp new file mode 100644 index 0000000..e24b17d --- /dev/null +++ b/test/qt/card/test_MSEBuilder.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "Commands.h" +#include "TestFileHelper.h" + +#include +#include + +using namespace governikus; + +class test_MSEBuilder + : public QObject +{ + Q_OBJECT + + QSharedPointer mMseBuilder; + + void assertCommandContent(const QByteArray& pExpectedContent) + { + QCOMPARE(mMseBuilder->build().getData(), pExpectedContent); + } + + + private Q_SLOTS: + void init() + { + mMseBuilder.reset(new MSEBuilder(MSEBuilder::P1::PERFORM_SECURITY_OPERATION, MSEBuilder::P2::SET_AT)); + } + + + void setAuxiliaryData() + { + QByteArray data = QByteArray::fromHex("0102030405060708090A0B0C0D0E0F"); + mMseBuilder->setAuxiliaryData(data); + assertCommandContent(data); + } + + + void setOid() + { + QByteArray data = QByteArray::fromHex("1929394959697989796959493929"); + mMseBuilder->setOid(data); + assertCommandContent(QByteArray::fromHex("800E").append(data)); + } + + + void setPublicKey() + { + QByteArray data = QByteArray::fromHex("a9d9e9f9493954939495"); + mMseBuilder->setPublicKey(data); + assertCommandContent(QByteArray::fromHex("830A").append(data)); + } + + + void setPublicKeyId() + { + PACE_PIN_ID pinId = PACE_PIN_ID::PACE_PIN; + mMseBuilder->setPublicKey(pinId); + assertCommandContent(QByteArray::fromHex("8301").append(static_cast(pinId))); + } + + + void setPrivateKey() + { + QByteArray data = QByteArray::fromHex("a9d9e9f94939549394"); + mMseBuilder->setPrivateKey(data); + assertCommandContent(QByteArray::fromHex("8409").append(data)); + } + + + void setEphemeralPublicKey() + { + QByteArray data = QByteArray::fromHex("a9d9e9f949395493999994"); + mMseBuilder->setEphemeralPublicKey(data); + assertCommandContent(QByteArray::fromHex("910B").append(data)); + } + + + void setChat() + { + QByteArray data = QByteArray::fromHex("a9d9e9f949"); + mMseBuilder->setChat(data); + assertCommandContent(data); + } + + +}; + +QTEST_GUILESS_MAIN(test_MSEBuilder) +#include "test_MSEBuilder.moc" diff --git a/test/qt/card/test_ReaderManager.cpp b/test/qt/card/test_ReaderManager.cpp index 2bd621a..61feb41 100644 --- a/test/qt/card/test_ReaderManager.cpp +++ b/test/qt/card/test_ReaderManager.cpp @@ -5,12 +5,12 @@ #include "MockReaderManagerPlugIn.h" #include "ReaderManager.h" +#include "ReaderManagerWorker.h" -#include +#include #include #include -#include -#include +#include Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) @@ -58,6 +58,7 @@ class test_ReaderManager private Q_SLOTS: void initTestCase() { + ReaderManagerWorker::registerMetaTypes(); ReaderManager::getInstance().init(); ReaderManager::getInstance().getPlugInInfos(); // just to wait until initialization finished } @@ -124,7 +125,7 @@ class test_ReaderManager CreateCardConnectionCommandSlot commandSlot; MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("MockReader 4711"); MockCardConfig cardConfig; - cardConfig.mConnect = ReturnCode::COMMAND_FAILED; + cardConfig.mConnect = CardReturnCode::COMMAND_FAILED; reader->setCard(cardConfig); ReaderManager::getInstance().callCreateCardConnectionCommand("MockReader 4711", &commandSlot, &CreateCardConnectionCommandSlot::onCardCommandDone); @@ -140,7 +141,7 @@ class test_ReaderManager CreateCardConnectionCommandSlot commandSlot; MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("MockReader 4711"); MockCardConfig cardConfig; - cardConfig.mConnect = ReturnCode::OK; + cardConfig.mConnect = CardReturnCode::OK; reader->setCard(cardConfig); ReaderManager::getInstance().callCreateCardConnectionCommand("MockReader 4711", &commandSlot, &CreateCardConnectionCommandSlot::onCardCommandDone); diff --git a/test/qt/card/test_SecureMessaging.cpp b/test/qt/card/test_SecureMessaging.cpp index bc23e1f..c65b68d 100644 --- a/test/qt/card/test_SecureMessaging.cpp +++ b/test/qt/card/test_SecureMessaging.cpp @@ -13,6 +13,17 @@ using namespace governikus; /* * Test data generated with ocard */ +class ByteArrayUtil +{ + public: + template static QByteArray fromValue(T pValue) + { + return QByteArray::fromHex(QByteArray::number(pValue, 16)); + } + + +}; + class test_SecureMessaging : public QObject { @@ -23,6 +34,7 @@ class test_SecureMessaging QScopedPointer mCipherMac; QScopedPointer mCipher; + QByteArray concat(std::initializer_list pList) const { QByteArray result; @@ -39,7 +51,7 @@ class test_SecureMessaging QVector result(4); ++pSsc; - QByteArray ssc = QByteArray(mCipher->getBlockSize() - QByteArray::number(pSsc).size(), 0x00).append(pSsc); + QByteArray ssc = QByteArray(mCipher->getBlockSize() - QByteArray::number(pSsc, 16).size(), 0x00).append(ByteArrayUtil::fromValue(pSsc)); if (pBuffer.length() > 2) { @@ -51,16 +63,16 @@ class test_SecureMessaging int padLen = mCipher->getBlockSize() - (pData.size() % mCipher->getBlockSize()); pData = concat({pData, QByteArray::fromHex("80"), QByteArray(padLen - 1, 0x00)}); QByteArray encryptedData = mCipher->encrypt(pData).prepend(0x01); - result[0] = QByteArray().append(char(0x87)).append(encryptedData.size()).append(encryptedData); + result[0] = QByteArray().append(char(0x87)).append(ByteArrayUtil::fromValue(encryptedData.size())).append(encryptedData); } QByteArray pSw = pBuffer.right(2); - result[1] = QByteArray().append(char(0x99)).append(pSw.size()).append(pSw); + result[1] = QByteArray().append(char(0x99)).append(ByteArrayUtil::fromValue(pSw.size())).append(pSw); { QByteArray dataToMac = concat({ssc, result[0], result[1]}); int padLen = mCipher->getBlockSize() - (dataToMac.size() % mCipher->getBlockSize()); dataToMac.append(char(0x80)).append(QByteArray(padLen - 1, 0x00)); QByteArray mac = mCipherMac->generate(dataToMac); - result[2] = QByteArray().append(char(0x8E)).append(mac.size()).append(mac); + result[2] = QByteArray().append(char(0x8E)).append(ByteArrayUtil::fromValue(mac.size())).append(mac); } result[3] = pSw; diff --git a/test/qt/cli/test_UIPlugInCli.cpp b/test/qt/cli/test_UIPlugInCli.cpp index adc71fa..4d8f4ab 100644 --- a/test/qt/cli/test_UIPlugInCli.cpp +++ b/test/qt/cli/test_UIPlugInCli.cpp @@ -25,11 +25,13 @@ class test_UIPlugInCli QSKIP("Console is not supported at the moment"); #endif - #ifdef Q_OS_BSD4 - QSKIP("Platform plugin seems broken"); + #ifdef Q_OS_OSX + QSKIP("QProcess/CliHelper is flaky on OSX"); #endif - QSKIP("QProcess/CliHelper is flaky"); + #if defined(Q_OS_BSD4) || defined (Q_OS_LINUX) + QSKIP("Platform plugin seems broken"); + #endif } @@ -42,13 +44,13 @@ class test_UIPlugInCli void cleanup() { cli->tearDown(); - } void quit() { CLI_VERIFY(cli->run()); + CLI_VERIFY(cli->waitForOutput("ready")); CLI_VERIFY(cli->waitForPong()); cli->send("help"); CLI_VERIFY(cli->waitForOutput("Available commands:")); @@ -67,6 +69,7 @@ class test_UIPlugInCli void term() { CLI_VERIFY(cli->run()); + CLI_VERIFY(cli->waitForOutput("ready")); CLI_VERIFY(cli->waitForPong()); cli->stop(); QCOMPARE(cli->state(), QProcess::NotRunning); @@ -77,6 +80,7 @@ class test_UIPlugInCli void termDuringOldPin() { CLI_VERIFY(cli->run()); + CLI_VERIFY(cli->waitForOutput("ready")); cli->send("changepin"); CLI_VERIFY(cli->waitForOutput("Please enter old PIN")); cli->stop(); @@ -87,9 +91,8 @@ class test_UIPlugInCli void changePin() { - QSKIP("unfinished"); - CLI_VERIFY(cli->run()); + CLI_VERIFY(cli->waitForOutput("ready")); cli->send("changepin"); CLI_VERIFY(cli->waitForOutput("Please enter old PIN")); cli->send("123456"); @@ -104,6 +107,7 @@ class test_UIPlugInCli void getServerPort() { CLI_VERIFY(cli->run()); + CLI_VERIFY(cli->waitForOutput("ready")); QVERIFY(cli->getServerPort() > 0); } diff --git a/test/qt/core/context/test_AuthContext.cpp b/test/qt/core/context/test_AuthContext.cpp index 7f2f340..85d2cc0 100644 --- a/test/qt/core/context/test_AuthContext.cpp +++ b/test/qt/core/context/test_AuthContext.cpp @@ -6,7 +6,8 @@ * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG */ -#include "context/AuthContext.h" +#include "TestAuthContext.h" +#include "TestFileHelper.h" #include "testMacros.h" #include @@ -23,10 +24,10 @@ class test_AuthContext Q_OBJECT private: + QScopedPointer mEac1Changed; + QScopedPointer mDataChanged; QScopedPointer mEffectiveSignal; - QScopedPointer mRequiredSignal; - QScopedPointer mOptionalSignal; - QScopedPointer mAuthContext; + QScopedPointer mAuthContext; QSharedPointer getChat(const std::initializer_list& pList) { @@ -36,206 +37,168 @@ class test_AuthContext } - void checkAndResetSignals(int pRequired, int pOptional, int pEffective) + void clearSignals() { - QCOMPARE(mRequiredSignal->count(), pRequired); - QCOMPARE(mOptionalSignal->count(), pOptional); + mEac1Changed->clear(); + mDataChanged->clear(); + mEffectiveSignal->clear(); + } + + + void checkChatSizes(const QString& pTestNum, int pRequired, int pOptional, int pEffective) + { + qDebug() << "Checking test" << pTestNum; + QCOMPARE(mAuthContext->getRequiredAccessRights().size(), pRequired); + QCOMPARE(mAuthContext->getOptionalAccessRights().size(), pOptional); + QCOMPARE(mAuthContext->getEffectiveAccessRights().size(), pEffective); + } + + + void checkAndClearSignals(const QString& pTestNum, int pEac1Data, int pEffective) + { + qDebug() << "Checking test" << pTestNum; + QCOMPARE(mEac1Changed->count(), pEac1Data); + QCOMPARE(mDataChanged->count(), pEac1Data); QCOMPARE(mEffectiveSignal->count(), pEffective); - mRequiredSignal->clear(); - mOptionalSignal->clear(); - mEffectiveSignal->clear(); + clearSignals(); } private Q_SLOTS: void init() { - mAuthContext.reset(new AuthContext(nullptr)); + // Creates a context with 17 access rights in cvc + // Because required and optional are empty, all 17 rights are optional by default + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + mAuthContext->setRequiredAccessRights({}); + mAuthContext->setOptionalAccessRights({}); + + mEac1Changed.reset(new QSignalSpy(mAuthContext.data(), &AuthContext::fireDidAuthenticateEac1Changed)); + mDataChanged.reset(new QSignalSpy(mAuthContext.data(), &AuthContext::fireAuthenticationDataChanged)); mEffectiveSignal.reset(new QSignalSpy(mAuthContext.data(), &AuthContext::fireEffectiveChatChanged)); - mRequiredSignal.reset(new QSignalSpy(mAuthContext.data(), &AuthContext::fireRequiredChatChanged)); - mOptionalSignal.reset(new QSignalSpy(mAuthContext.data(), &AuthContext::fireOptionalChatChanged)); } void cleanup() { + mEac1Changed.reset(); mEffectiveSignal.reset(); - mRequiredSignal.reset(); - mOptionalSignal.reset(); mAuthContext.reset(); } - void emptyOnCreation() + void test_AuthContext_01() { - QVERIFY(!mAuthContext->getEffectiveChat()); - QVERIFY(!mAuthContext->getRequiredChat()); - QVERIFY(!mAuthContext->getOptionalChat()); + // Exists after creation - All cvc rights are optional and selected + checkChatSizes("01-01", 0, 17, 17); } - void setEffectiveWithoutRequiredAndOptional() + void test_AuthContext_02() { - QVERIFY(mAuthContext->setEffectiveChat(getChat({}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 0); - checkAndResetSignals(0, 0, 1); + // Try to set required right that is not in cvc + mAuthContext->setRequiredAccessRights({AccessRight::READ_DG21}); + checkChatSizes("02-01", 0, 17, 17); + checkAndClearSignals("02-02", 1, 1); - QVERIFY(!mAuthContext->setEffectiveChat(getChat({AccessRight::AGE_VERIFICATION}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 0); - checkAndResetSignals(0, 0, 1); + // Try to set optional right that is not in cvc + mAuthContext->setOptionalAccessRights({AccessRight::READ_DG21}); + checkChatSizes("02-03", 0, 17, 17); + checkAndClearSignals("02-04", 1, 1); + + // Try to set a right in required and optional + mAuthContext->setOptionalAccessRights({AccessRight::READ_DG05}); + checkChatSizes("02-05", 0, 1, 1); + checkAndClearSignals("02-06", 1, 1); + mAuthContext->setRequiredAccessRights({AccessRight::READ_DG05}); + checkChatSizes("02-07", 1, 0, 1); + checkAndClearSignals("02-08", 1, 1); } - void requiredChat() + void test_AuthContext_03() { - mAuthContext->setRequiredChat(getChat({AccessRight::AGE_VERIFICATION})); - QVERIFY(mAuthContext->getRequiredChat()); - QVERIFY(!mAuthContext->getEffectiveChat()); - checkAndResetSignals(1, 0, 0); - - QVERIFY(!mAuthContext->setEffectiveChat(getChat({}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - QVERIFY(mAuthContext->setEffectiveChat(getChat({AccessRight::AGE_VERIFICATION}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - mAuthContext->setRequiredChat(getChat({})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 0); - checkAndResetSignals(1, 0, 1); - - mAuthContext->setRequiredChat(getChat({AccessRight::AGE_VERIFICATION})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(1, 0, 1); - - mAuthContext->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 1, 0); - - QVERIFY(mAuthContext->setEffectiveChat(getChat({AccessRight::AGE_VERIFICATION}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - mAuthContext->setRequiredChat(getChat({})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(1, 0, 0); + // Clear effective access rights + mAuthContext->setEffectiveAccessRights({}); + checkChatSizes("03-01", 0, 17, 0); + checkAndClearSignals("03-02", 0, 1); } - void optionalChat() + void test_AuthContext_04() { - mAuthContext->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION})); - QVERIFY(mAuthContext->getOptionalChat()); - QVERIFY(!mAuthContext->getEffectiveChat()); - checkAndResetSignals(0, 1, 0); + // Set only one access right as optional, required access rights remain empty + mAuthContext->setOptionalAccessRights({AccessRight::READ_DG05}); + checkChatSizes("04-01", 0, 1, 1); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-02", 1, 1); - QVERIFY(mAuthContext->setEffectiveChat(getChat({}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 0); - checkAndResetSignals(0, 0, 1); + // Try to set an optional access right that is already set + QVERIFY(mAuthContext->addEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("04-03", 0, 1, 1); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-04", 0, 0); - QVERIFY(mAuthContext->setEffectiveChat(getChat({AccessRight::AGE_VERIFICATION}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); + // Try to remove an optional access right + QVERIFY(mAuthContext->removeEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("04-05", 0, 1, 0); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-06", 0, 1); - mAuthContext->setOptionalChat(getChat({})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 0); - checkAndResetSignals(0, 1, 1); + // Try to remove an optional access right that is not set + QVERIFY(mAuthContext->removeEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("04-07", 0, 1, 0); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-08", 0, 0); - mAuthContext->setRequiredChat(getChat({AccessRight::AGE_VERIFICATION})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(1, 0, 1); + // Try to set an optional access right + QVERIFY(mAuthContext->addEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("04-09", 0, 1, 1); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-10", 0, 1); - mAuthContext->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 1, 0); - - QVERIFY(mAuthContext->setEffectiveChat(getChat({AccessRight::AGE_VERIFICATION}))); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - mAuthContext->setOptionalChat(getChat({})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 1, 0); + // Try to set an access right that is not included in optional or required access rights + QVERIFY(!mAuthContext->addEffectiveAccessRight(AccessRight::AGE_VERIFICATION)); + checkChatSizes("04-11", 0, 1, 1); + QVERIFY(mAuthContext->getOptionalAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("04-12", 0, 0); } - void effectiveChat() + void test_AuthContext_05() { - mAuthContext->setRequiredChat(getChat({AccessRight::AGE_VERIFICATION})); - checkAndResetSignals(1, 0, 0); + // Set only one access right as required, optional access rights remain empty + mAuthContext->setRequiredAccessRights({AccessRight::READ_DG05}); + checkChatSizes("05-01", 1, 0, 1); + QVERIFY(mAuthContext->getRequiredAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("05-02", 1, 1); - mAuthContext->setOptionalChat(getChat({AccessRight::INSTALL_QUAL_CERT})); - checkAndResetSignals(0, 1, 0); + // Try to set an required access right that is already set + QVERIFY(mAuthContext->addEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("05-03", 1, 0, 1); + QVERIFY(mAuthContext->getRequiredAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("05-04", 0, 0); - QVERIFY(!mAuthContext->setEffectiveChat(getChat({}))); - checkAndResetSignals(0, 0, 1); + // Try to remove an required access right + QVERIFY(!mAuthContext->removeEffectiveAccessRight(AccessRight::READ_DG05)); + checkChatSizes("05-05", 1, 0, 1); + QVERIFY(mAuthContext->getRequiredAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("05-06", 0, 0); - QVERIFY(!mAuthContext->addEffectiveAccessRight(AccessRight::PRIVILEGED_TERMINAL)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 0); - - QVERIFY(mAuthContext->removeEffectiveAccessRight(AccessRight::PRIVILEGED_TERMINAL)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 0); - - QVERIFY(!mAuthContext->removeEffectiveAccessRight(AccessRight::AGE_VERIFICATION)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 0); - - QVERIFY(mAuthContext->addEffectiveAccessRight(AccessRight::INSTALL_QUAL_CERT)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 2); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::INSTALL_QUAL_CERT)); - checkAndResetSignals(0, 0, 1); - - QVERIFY(mAuthContext->addEffectiveAccessRight(AccessRight::INSTALL_QUAL_CERT)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 2); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::INSTALL_QUAL_CERT)); - checkAndResetSignals(0, 0, 0); - - QVERIFY(mAuthContext->removeEffectiveAccessRight(AccessRight::INSTALL_QUAL_CERT)); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - QVERIFY(!mAuthContext->setEffectiveAccessRights({})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 0); - - QVERIFY(mAuthContext->setEffectiveAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::INSTALL_QUAL_CERT})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 2); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::INSTALL_QUAL_CERT)); - checkAndResetSignals(0, 0, 1); - - QVERIFY(!mAuthContext->setEffectiveAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::PRIVILEGED_TERMINAL})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 1); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - checkAndResetSignals(0, 0, 1); - - QVERIFY(!mAuthContext->setEffectiveAccessRights({AccessRight::INSTALL_QUAL_CERT, AccessRight::PRIVILEGED_TERMINAL})); - QCOMPARE(mAuthContext->getEffectiveChat()->getAccessRights().size(), 2); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::AGE_VERIFICATION)); - QVERIFY(mAuthContext->getEffectiveChat()->getAccessRights().contains(AccessRight::INSTALL_QUAL_CERT)); - checkAndResetSignals(0, 0, 1); + // Try to remove an access right that is not included in optional or required access rights + QVERIFY(mAuthContext->removeEffectiveAccessRight(AccessRight::AGE_VERIFICATION)); + checkChatSizes("05-07", 1, 0, 1); + QVERIFY(mAuthContext->getRequiredAccessRights().contains(AccessRight::READ_DG05)); + QVERIFY(mAuthContext->getEffectiveAccessRights().contains(AccessRight::READ_DG05)); + checkAndClearSignals("05-08", 0, 0); } diff --git a/test/qt/core/paos/invoke/test_DisconnectResponse.cpp b/test/qt/core/paos/invoke/test_DisconnectResponse.cpp index b4fef8b..b080962 100644 --- a/test/qt/core/paos/invoke/test_DisconnectResponse.cpp +++ b/test/qt/core/paos/invoke/test_DisconnectResponse.cpp @@ -48,7 +48,7 @@ class test_DisconnectResponse DisconnectResponse responseWithSlot; responseWithSlot.setMessageId("dummy"); - responseWithSlot.setResult(Result::createError(ReturnCode::NO_CARD)); + responseWithSlot.setResult(Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CARD_NOT_FOUND))); responseWithSlot.setSlotHandle("huhu"); elem = responseWithSlot.marshall(); diff --git a/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp b/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp index 0bcbc87..026e819 100644 --- a/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp +++ b/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp @@ -24,7 +24,7 @@ class test_DidAuthenticateEac1 void parseXml() { QByteArray content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml"); - QScopedPointer eac1(dynamic_cast(DidAuthenticateEac1Parser().parse(content))); + QScopedPointer eac1(static_cast(DidAuthenticateEac1Parser().parse(content))); QVERIFY(!eac1.isNull()); QCOMPARE(eac1->getConnectionHandle().getCardApplication(), QString("4549445F49534F5F32343732375F42415345")); @@ -50,7 +50,7 @@ class test_DidAuthenticateEac1 void test_TS_TA_2_1_1() { QByteArray content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1_TS_TA_2.1.1.xml"); - QScopedPointer eac1(dynamic_cast(DidAuthenticateEac1Parser().parse(content))); + QScopedPointer eac1(static_cast(DidAuthenticateEac1Parser().parse(content))); QVERIFY(eac1 == nullptr); } diff --git a/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp b/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp index 1279574..5263e2b 100644 --- a/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp +++ b/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp @@ -29,7 +29,7 @@ class test_DidAuthenticateEac2 void parseXml() { QByteArray content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC2.xml"); - QScopedPointer eac2(dynamic_cast(DidAuthenticateEac2Parser().parse(content))); + QScopedPointer eac2(static_cast(DidAuthenticateEac2Parser().parse(content))); QVERIFY(!eac2.isNull()); QCOMPARE(eac2->getConnectionHandle().getCardApplication(), QString("4549445F49534F5F32343732375F42415345")); diff --git a/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp b/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp index eb4f64c..16c23ab 100644 --- a/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp +++ b/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp @@ -33,7 +33,7 @@ class test_StartPAOSResponse StartPaosResponse message(content); QCOMPARE(message.getResult().getMajor(), Result::Major::Ok); - QCOMPARE(message.getResult().getMinor(), Result::Minor::null); + QCOMPARE(message.getResult().getMinor(), GlobalStatus::Code::Unknown_Error); QVERIFY(message.getResult().getMessage().isNull()); } @@ -45,7 +45,7 @@ class test_StartPAOSResponse StartPaosResponse message(content); QCOMPARE(message.getResult().getMajor(), Result::Major::Error); - QCOMPARE(message.getResult().getMinor(), Result::Minor::DP_Timeout_Error); + QCOMPARE(message.getResult().getMinor(), GlobalStatus::Code::Paos_Error_DP_Timeout_Error); QVERIFY(message.getResult().getMessage().isNull()); } @@ -57,7 +57,7 @@ class test_StartPAOSResponse StartPaosResponse message(content); QCOMPARE(message.getResult().getMajor(), Result::Major::Error); - QCOMPARE(message.getResult().getMinor(), Result::Minor::DP_Timeout_Error); + QCOMPARE(message.getResult().getMinor(), GlobalStatus::Code::Paos_Error_DP_Timeout_Error); QCOMPARE(message.getResult().getMessage(), QString("Detail message")); } diff --git a/test/qt/core/paos/retrieve/test_transmit.cpp b/test/qt/core/paos/retrieve/test_transmit.cpp index 549d2c5..7e1d026 100644 --- a/test/qt/core/paos/retrieve/test_transmit.cpp +++ b/test/qt/core/paos/retrieve/test_transmit.cpp @@ -29,7 +29,7 @@ class test_transmit void parseXml() { QByteArray content = TestFileHelper::readFile(":/paos/Transmit.xml"); - QScopedPointer transmit(dynamic_cast(TransmitParser().parse(content))); + QScopedPointer transmit(static_cast(TransmitParser().parse(content))); QVERIFY(!transmit.isNull()); auto inputApdusInfos = transmit->getInputApduInfos(); @@ -65,7 +65,7 @@ class test_transmit void parseXmlWithAddressing() { QByteArray content = TestFileHelper::readFile(":/paos/Transmit3.xml"); - QScopedPointer transmit(dynamic_cast(TransmitParser().parse(content))); + QScopedPointer transmit(static_cast(TransmitParser().parse(content))); QVERIFY(!transmit.isNull()); auto inputApdusInfos = transmit->getInputApduInfos(); @@ -103,7 +103,7 @@ class test_transmit void parseAnswerAutent() { QByteArray content = TestFileHelper::readFile(":/paos/Transmit2.xml"); - QScopedPointer transmit(dynamic_cast(TransmitParser().parse(content))); + QScopedPointer transmit(static_cast(TransmitParser().parse(content))); QVERIFY(!transmit.isNull()); auto inputApduInfos = transmit->getInputApduInfos(); diff --git a/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp b/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp index 712f61c..7348d65 100644 --- a/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp +++ b/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp @@ -9,8 +9,8 @@ #include "asn1/ASN1Util.h" #include "asn1/CVCertificate.h" #include "context/AuthContext.h" -#include "paos/retrieve/DidAuthenticateEac1Parser.h" +#include "TestAuthContext.h" #include #include #include @@ -31,11 +31,7 @@ class test_StateCertificateDescriptionCheck private Q_SLOTS: void init() { - mAuthContext.reset(new AuthContext(nullptr)); - QSharedPointer didAuthEac1(dynamic_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml")))); - mAuthContext->setDidAuthenticateEac1(didAuthEac1); - mAuthContext->setTerminalCvc(didAuthEac1->getCvCertificates().at(0)); - mAuthContext->setDvCvc(didAuthEac1->getCvCertificates().at(1)); + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); mAuthContext->setTcTokenUrl(QUrl("https://dev-demo.governikus-eid.de:8443/Autent-DemoApplication/RequestServlet;jsessionid=14w5aKuENyd2D4ZsMmuaeX2g")); mState.reset(new StateCertificateDescriptionCheck(mAuthContext)); diff --git a/test/qt/core/states/test_StateCheckRefreshAddress.cpp b/test/qt/core/states/test_StateCheckRefreshAddress.cpp index cc08625..3e9feb7 100644 --- a/test/qt/core/states/test_StateCheckRefreshAddress.cpp +++ b/test/qt/core/states/test_StateCheckRefreshAddress.cpp @@ -4,7 +4,9 @@ #include "states/StateCheckRefreshAddress.h" +#include "MockNetworkManager.h" #include "context/AuthContext.h" +#include "states/StateBuilder.h" #include #include @@ -27,8 +29,8 @@ class test_StateCheckRefreshAddress void init() { mAuthContext.reset(new AuthContext(nullptr)); - mState.reset(new StateCheckRefreshAddress(mAuthContext)); - mState->setStateName("StateCheckRefreshAddress"); + mAuthContext->setNetworkManager(new MockNetworkManager); + mState.reset(StateBuilder::createState(mAuthContext)); connect(this, &test_StateCheckRefreshAddress::fireStateStart, mState.data(), &AbstractState::onEntry, Qt::ConnectionType::DirectConnection); } @@ -40,16 +42,36 @@ class test_StateCheckRefreshAddress } + void mappingToCommunicationError() + { + const QVector states = QVector() + << GlobalStatus::Code::Network_Ssl_Establishment_Error + << GlobalStatus::Code::Network_Ssl_Establishment_Error + << GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length + << GlobalStatus::Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length + << GlobalStatus::Code::Workflow_Nerwork_Ssl_Hash_Not_In_Certificate_Description + << GlobalStatus::Code::Workflow_Network_Empty_Redirect_Url + << GlobalStatus::Code::Workflow_Network_Expected_Redirect + << GlobalStatus::Code::Workflow_Network_Invalid_Scheme + << GlobalStatus::Code::Workflow_Network_Malformed_Redirect_Url + << GlobalStatus::Code::Network_TimeOut + << GlobalStatus::Code::Network_Proxy_Error; + + for (const GlobalStatus::Code state : states) + { + const Result& result = GlobalStatus(state); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_AL_Communication_Error); + } + } + + void sendGetRequestWithoutAnyAdditionalParameters() { QUrl redirectUrl("http://localhost:12345/test_StateCheckRefreshAddress/"); - Result result = Result::createCommunicationError("Fehlertext"); - mAuthContext->setResult(result); + mAuthContext->setStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); mState->mUrl = redirectUrl; mState->sendGetRequest(); - - mState->mReply->abort(); QCOMPARE(mState->mReply->request().url(), redirectUrl); } diff --git a/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp b/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp index c43d430..d1dc0a0 100644 --- a/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp +++ b/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp @@ -8,8 +8,8 @@ #include "states/StateExtractCvcsFromEac1IntputType.h" +#include "TestAuthContext.h" #include "TestFileHelper.h" -#include "paos/retrieve/DidAuthenticateEac1Parser.h" #include #include @@ -44,11 +44,11 @@ class test_StateExtractCvcsFromEac1InputType void init() { - mAuthContext.reset(new AuthContext(nullptr)); + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_3.xml")); + mState.reset(new StateExtractCvcsFromEac1IntputType(mAuthContext)); mState->setStateName("StateExtractCvcsFromEac1IntputType"); - QSharedPointer didAuthEac1(dynamic_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1_3.xml")))); - mAuthContext->setDidAuthenticateEac1(didAuthEac1); + mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.clear(); connect(this, &test_StateExtractCvcsFromEac1InputType::fireStateStart, mState.data(), &AbstractState::onEntry, Qt::ConnectionType::DirectConnection); } diff --git a/test/qt/core/states/test_StateGenericSendReceive.cpp b/test/qt/core/states/test_StateGenericSendReceive.cpp index 71435c2..685f4f6 100644 --- a/test/qt/core/states/test_StateGenericSendReceive.cpp +++ b/test/qt/core/states/test_StateGenericSendReceive.cpp @@ -2,6 +2,7 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ +#include "TestAuthContext.h" #include "controller/AuthController.h" #include "paos/invoke/InitializeFrameworkResponse.h" #include "paos/retrieve/InitializeFramework.h" @@ -33,7 +34,7 @@ class test_StateGenericSendReceive private Q_SLOTS: void init() { - mAuthContext.reset(new AuthContext(nullptr)); + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); QFile tcTokenFile(":/tctoken/ok.xml"); QVERIFY(tcTokenFile.open(QIODevice::ReadOnly)); @@ -114,6 +115,28 @@ class test_StateGenericSendReceive } + void mappingToTrustedChannelError() + { + const QVector states = QVector() + << GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error + << GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server + << GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description + << GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received + << GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length + << GlobalStatus::Code::Workflow_TrustedChannel_TimeOut + << GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error + << GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error + << GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error + << GlobalStatus::Code::Workflow_TrustedChannel_Other_Network_Error; + + for (const GlobalStatus::Code state : states) + { + const Result& result = Result(GlobalStatus(state)); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed); + } + } + + void cleanup() { mAuthContext.reset(); diff --git a/test/qt/core/states/test_StatePreVerification.cpp b/test/qt/core/states/test_StatePreVerification.cpp index 1a02f2c..70ac6b2 100644 --- a/test/qt/core/states/test_StatePreVerification.cpp +++ b/test/qt/core/states/test_StatePreVerification.cpp @@ -9,11 +9,12 @@ #include "AppSettings.h" #include "TestFileHelper.h" #include "paos/retrieve/DidAuthenticateEac1.h" -#include "paos/retrieve/DidAuthenticateEac1Parser.h" +#include "TestAuthContext.h" #include #include + using namespace governikus; @@ -32,10 +33,7 @@ class test_StatePreVerification { AbstractSettings::mTestDir.clear(); AppSettings::getInstance().load(); - mAuthContext.reset(new AuthContext(nullptr)); - QByteArray eac1Content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml"); - QSharedPointer didAuthEac1(dynamic_cast(DidAuthenticateEac1Parser().parse(eac1Content))); - mAuthContext->setDidAuthenticateEac1(didAuthEac1); + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); mAuthContext->initCvcChainBuilder(); diff --git a/test/qt/core/states/test_StatePrepareChat.cpp b/test/qt/core/states/test_StatePrepareChat.cpp deleted file mode 100644 index 6b983e8..0000000 --- a/test/qt/core/states/test_StatePrepareChat.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*! - * \brief Unit tests for \ref StatePreVerification - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "states/StatePrepareChat.h" - -#include "TestFileHelper.h" -#include "paos/retrieve/DidAuthenticateEac1.h" -#include "paos/retrieve/DidAuthenticateEac1Parser.h" -#include "states/StateBuilder.h" - -#include -#include - -using namespace governikus; - - -class test_StatePrepareChat - : public QObject -{ - Q_OBJECT - QScopedPointer mState; - QSharedPointer mAuthContext; - - void verifyEffectiveChat() - { - // effective chat is set to required chat plus optional chat - QSharedPointer effectiveChat = mState->getContext()->getEffectiveChat(); - QSharedPointer optionalChat = mState->getContext()->getOptionalChat(); - QSharedPointer requiredChat = mState->getContext()->getRequiredChat(); - - QSet optionalPlusRequired; - if (requiredChat) - { - optionalPlusRequired += requiredChat->getAccessRights(); - } - if (optionalChat) - { - optionalPlusRequired += optionalChat->getAccessRights(); - } - QCOMPARE(optionalPlusRequired, effectiveChat->getAccessRights()); - } - - - Q_SIGNALS: - void fireStateStart(QEvent* pEvent); - - private Q_SLOTS: - void init() - { - mAuthContext.reset(new AuthContext(nullptr)); - QSharedPointer didAuthEac1(dynamic_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1_3.xml")))); - mAuthContext->setDidAuthenticateEac1(didAuthEac1); - mAuthContext->setTerminalCvc(didAuthEac1->getCvCertificates().at(0)); - mAuthContext->setDvCvc(didAuthEac1->getCvCertificates().at(1)); - - mState.reset(StateBuilder::createState(mAuthContext)); - connect(this, &test_StatePrepareChat::fireStateStart, mState.data(), &AbstractState::onEntry, Qt::ConnectionType::DirectConnection); - } - - - void cleanup() - { - mAuthContext.clear(); - mState.reset(); - } - - - void testNoOptionalChatNoRequiredChat() - { - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat.reset(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat.reset(); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), mState->getContext()->getTerminalCvc()->getBody().getCHAT().getAccessRights()); - QVERIFY(!mState->getContext()->getRequiredChat()); - verifyEffectiveChat(); - } - - - void testOptionalChatNoRequiredChat() - { - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat.reset(); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), mState->getContext()->mDIDAuthenticateEAC1->getOptionalChat()->getAccessRights()); - QVERIFY(!mState->getContext()->getRequiredChat()); - verifyEffectiveChat(); - } - - - void testNoOptionalChatRequiredChat() - { - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat.reset(); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QVERIFY(!mState->getContext()->getOptionalChat()); - QCOMPARE(mState->getContext()->getRequiredChat()->getAccessRights(), mState->getContext()->mDIDAuthenticateEAC1->getRequiredChat()->getAccessRights()); - verifyEffectiveChat(); - } - - - void testOptionalChatRequiredChat_butNoIntersection() - { - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), mState->getContext()->mDIDAuthenticateEAC1->getOptionalChat()->getAccessRights()); - QCOMPARE(mState->getContext()->getRequiredChat()->getAccessRights(), mState->getContext()->mDIDAuthenticateEAC1->getRequiredChat()->getAccessRights()); - verifyEffectiveChat(); - } - - - void testOptionalChatRequiredChat_butIntersection() - { - QSet optionalChatFromEac1WithoutDG05 = mAuthContext->mDIDAuthenticateEAC1->getOptionalChat()->getAccessRights(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat->setAccessRight(AccessRight::READ_DG05); // Family name also in required chat - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - - - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), optionalChatFromEac1WithoutDG05); - QCOMPARE(mState->getContext()->getRequiredChat()->getAccessRights(), mState->getContext()->mDIDAuthenticateEAC1->getRequiredChat()->getAccessRights()); - verifyEffectiveChat(); - } - - - void testEncodeEffectiveChat() - { - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QVERIFY(!mState->getContext()->getEffectiveChat()->encode().isEmpty()); - } - - - void testOptionalChatWithNotAllowedAccessRight() - { - QSet accessRights = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat->getAccessRights(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat->setAccessRight(AccessRight::PIN_MANAGEMENT); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), accessRights); - } - - - void testRequiredChatWithNotAllowedAccessRight() - { - QSet accessRights = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat->getAccessRights(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat->setAccessRight(AccessRight::PIN_MANAGEMENT); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getRequiredChat()->getAccessRights(), accessRights); - } - - - void testOptionalChatWithNotDisplayedAccessRight() - { - mAuthContext->mTerminalCvc->mBody->mChat->setAccessRight(AccessRight::READ_DG18); - QSet accessRights = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat->getAccessRights(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mOptionalChat->setAccessRight(AccessRight::READ_DG18); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getOptionalChat()->getAccessRights(), accessRights); - } - - - void testRequiredChatWithNotDisplayedAccessRight() - { - mAuthContext->mTerminalCvc->mBody->mChat->setAccessRight(AccessRight::READ_DG18); - QSet accessRights = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat->getAccessRights(); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mRequiredChat->setAccessRight(AccessRight::READ_DG18); - - QSignalSpy spy(mState.data(), &StatePrepareChat::fireSuccess); - Q_EMIT fireStateStart(nullptr); - mAuthContext->setStateApproved(); - - QCOMPARE(spy.count(), 1); - QCOMPARE(mState->getContext()->getRequiredChat()->getAccessRights(), accessRights); - } - - -}; - -QTEST_GUILESS_MAIN(test_StatePrepareChat) -#include "test_StatePrepareChat.moc" diff --git a/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp b/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp index 4f2d932..08f805d 100644 --- a/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp +++ b/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp @@ -7,6 +7,7 @@ #include "states/StateProcessCertificatesFromEac2.h" #include "Commands.h" +#include "TestAuthContext.h" #include "TestFileHelper.h" #include "asn1/CVCertificateChainBuilder.h" #include "paos/retrieve/DidAuthenticateEac1.h" @@ -32,10 +33,8 @@ class test_StateProcessCertificatesFromEac2 private Q_SLOTS: void init() { - mAuthContext.reset(new AuthContext(nullptr)); - QSharedPointer didAuthEac1(dynamic_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml")))); - mAuthContext->setDidAuthenticateEac1(didAuthEac1); - QSharedPointer didAuthEac2(dynamic_cast(DidAuthenticateEac2Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC2.xml")))); + mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); + QSharedPointer didAuthEac2(static_cast(DidAuthenticateEac2Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC2.xml")))); mAuthContext->setDidAuthenticateEac2(didAuthEac2); EstablishPACEChannelOutput paceOutput; paceOutput.parse(QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput.hex")), PACE_PIN_ID::PACE_PIN); diff --git a/test/qt/core/states/test_StateRedirectBrowser.cpp b/test/qt/core/states/test_StateRedirectBrowser.cpp index 6a27047..add9f27 100644 --- a/test/qt/core/states/test_StateRedirectBrowser.cpp +++ b/test/qt/core/states/test_StateRedirectBrowser.cpp @@ -50,7 +50,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -64,7 +64,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -78,7 +78,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -92,7 +92,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -107,7 +107,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -122,7 +122,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendErroPageCalled()); } @@ -137,7 +137,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); } @@ -152,7 +152,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); } @@ -168,7 +168,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); } @@ -184,7 +184,7 @@ class test_StateRedirectBrowser mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - QVERIFY(dynamic_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); + QVERIFY(qobject_cast(mAuthContext->getActivationContext())->isSendRedirectCalled()); } diff --git a/test/qt/core/states/test_StateStartPaosResponse.cpp b/test/qt/core/states/test_StateStartPaosResponse.cpp index caa23fd..b9d881a 100644 --- a/test/qt/core/states/test_StateStartPaosResponse.cpp +++ b/test/qt/core/states/test_StateStartPaosResponse.cpp @@ -41,20 +41,38 @@ class test_StateStartPaosResponse } - void takeResultFromStartPAOSResponse() + void doNotTakeResultFromStartPAOSResponse() { QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse3.xml"))); mAuthContext->setStartPaosResponse(startPAOSResponse); - mAuthContext->setResult(Result::createCancelByUserError()); + mAuthContext->setStatus(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)); QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireError); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); - QVERIFY(mState->getContext()->getResult().getMajor() == Result::Major::Error); - QVERIFY(mState->getContext()->getResult().getMinor() == Result::Minor::DP_Timeout_Error); - QVERIFY(mState->getContext()->getResult().getMessage() == QString("Detail message")); + const Result& result = mState->getContext()->getStatus(); + QCOMPARE(result.getMajor(), Result::Major::Error); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User); + } + + + void takeResultFromStartPAOSResponse() + { + QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse3.xml"))); + mAuthContext->setStartPaosResponse(startPAOSResponse); + mAuthContext->setStatus(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::OK)); + + QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireError); + + Q_EMIT fireStateStart(nullptr); + mAuthContext->setStateApproved(); + + const Result& result = mState->getContext()->getStatus(); + QCOMPARE(result.getMajor(), Result::Major::Error); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_DP_Timeout_Error); + QCOMPARE(result.getMessage(), QString("The operation was terminated as the set time was exceeded.")); } diff --git a/test/qt/core/states/test_TermsOfUsage.cpp b/test/qt/core/states/test_TermsOfUsage.cpp index ad20182..166ef7e 100644 --- a/test/qt/core/states/test_TermsOfUsage.cpp +++ b/test/qt/core/states/test_TermsOfUsage.cpp @@ -48,7 +48,7 @@ class test_TermsOfUsage << QStringLiteral("- Login B\u00FCrgerkonto \"Mein Hagen\" -") << QStringLiteral("- Verifikation von Personendaten zur Alters- und Identit\u00E4tsfeststellung -") << QStringLiteral("- Registrierung f\u00FCr die Virtuelle Poststelle bei der Deutschen Emissionshandelsstelle -") - << "see details under more..."; + << QString(); mCVCList << ":/core/step/2014_07_03_cvcDescription0.bin" << ":/core/step/2014_07_03_cvcDescription1.bin" << ":/core/step/2014_07_03_cvcDescription2.bin" << ":/core/step/2014_07_03_cvcDescription3.bin" @@ -100,7 +100,7 @@ class test_TermsOfUsage { QFAIL(certDescr->getPurpose().toUtf8().constData()); } - QCOMPARE(certDescr->getPurpose(), QStringLiteral("see details under more...")); + QCOMPARE(certDescr->getPurpose(), QString()); } diff --git a/test/qt/core/test_CertificateChecker.cpp b/test/qt/core/test_CertificateChecker.cpp index 4478bf3..1bf101e 100644 --- a/test/qt/core/test_CertificateChecker.cpp +++ b/test/qt/core/test_CertificateChecker.cpp @@ -19,6 +19,7 @@ using namespace governikus; +Q_DECLARE_METATYPE(QSsl::KeyAlgorithm) class test_CertificateChecker : public QObject @@ -33,10 +34,6 @@ class test_CertificateChecker BIO_write(bio, pPemEncodedEvpPKey.constData(), pPemEncodedEvpPKey.length()); QSslKey key(PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr), QSsl::PublicKey); BIO_free(bio); - - Q_ASSERT(!key.isNull()); - Q_ASSERT(key.algorithm() == QSsl::KeyAlgorithm::Opaque); - return key; } @@ -62,47 +59,45 @@ class test_CertificateChecker QSharedPointer model(new AuthContext(new MockActivationContext())); QCOMPARE(model->getCertificateList().size(), 0); - QCOMPARE(CertificateChecker::checkAndSaveCertificate(certs.at(0), QUrl("dummy"), model), QString()); + QCOMPARE(CertificateChecker::checkAndSaveCertificate(certs.at(0), QUrl("dummy"), model), CertificateChecker::CertificateStatus::Good); QCOMPARE(model->getCertificateList().size(), 1); } - void hasCertificateKeyLengthRsa() + void hasUpdateCertificateKeyLength() { - QVERIFY(CertificateChecker::hasValidCertificateKeyLength(certs.at(0))); - - - QSslCertificate invalidCert(TestFileHelper::readFile(":/core/invalid.keysize.rsa.der")); - QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - QVERIFY(!CertificateChecker::hasValidCertificateKeyLength(invalidCert)); - - QCOMPARE(spy.count(), 2); - auto param = spy.takeLast(); - QVERIFY(param.at(0).toString().contains("RSA key with insufficient key size found 1024")); + for (const auto& cert : qAsConst(certs)) + { + QVERIFY(CertificateChecker::hasValidCertificateKeyLength(cert)); + } } - void hasCertificateKeyLengthDsa() + void hasCertificateKeyLength_data() { - QSslCertificate invalidCert(TestFileHelper::readFile(":/core/invalid.keysize.dsa.der")); - QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - QVERIFY(!CertificateChecker::hasValidCertificateKeyLength(invalidCert)); + QTest::addColumn("filename"); + QTest::addColumn("output"); - QCOMPARE(spy.count(), 2); - auto param = spy.takeLast(); - QVERIFY(param.at(0).toString().contains("DSA key with insufficient key size found 1024")); + QTest::newRow("rsa") << ":/core/invalid.keysize.rsa.der" << "Rsa key with insufficient key size found 1024"; + QTest::newRow("dsa") << ":/core/invalid.keysize.dsa.der" << "Dsa key with insufficient key size found 1024"; + QTest::newRow("ec") << ":/core/invalid.keysize.ec.der" << "Ec key with insufficient key size found 128"; } - void hasCertificateKeyLengthEc() + void hasCertificateKeyLength() { - QSslCertificate invalidCert(TestFileHelper::readFile(":/core/invalid.keysize.ec.der")); + QFETCH(QString, filename); + QFETCH(QString, output); + + const auto& content = TestFileHelper::readFile(filename); + QVERIFY(!content.isEmpty()); + QSslCertificate invalidCert(content); QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); QVERIFY(!CertificateChecker::hasValidCertificateKeyLength(invalidCert)); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.count(), 3); auto param = spy.takeLast(); - QVERIFY(param.at(0).toString().contains("EC key with insufficient key size found 128")); + QVERIFY(param.at(0).toString().contains(output)); } @@ -120,120 +115,119 @@ class test_CertificateChecker } - void hasValidEphemeralKeyLength_ec112() + void hasValidEphemeralKeyLength_data() { + QTest::addColumn("pem"); + QTest::addColumn("algorithm"); + QTest::addColumn("sufficient"); + /* * openssl ecparam -name secp112r2 -out secp112r2_param.pem * openssl ecparam -in secp112r2_param.pem -genkey -noout -out secp112r2_key.pem * openssl ec -in secp112r2_key.pem -pubout -out secp112r2_pubkey.pem */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MDIwEAYHKoZIzj0CAQYFK4EEAAcDHgAEWo89aCax3oUWJho7rFZ1u70WqghvA7Tf\n" - "SXXiZw==\n" - "-----END PUBLIC KEY-----"); - QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(!CertificateChecker::hasValidEphemeralKeyLength(key)); - } + QByteArray ec112("-----BEGIN PUBLIC KEY-----\n" + "MDIwEAYHKoZIzj0CAQYFK4EEAAcDHgAEWo89aCax3oUWJho7rFZ1u70WqghvA7Tf\n" + "SXXiZw==\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("ec112") << ec112 << QSsl::KeyAlgorithm::Ec << false; - void hasValidEphemeralKeyLength_ec521() - { /* * openssl ecparam -name secp521r1 -out secp521r1_param.pem * openssl ecparam -in secp521r1_param.pem -genkey -noout -out secp521r1_key.pem * openssl ec -in secp521r1_key.pem -pubout -out secp521r1_pubkey.pem */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBi5e64Y/7EGT7Tbpe5h4cZGSpNidN\n" - "fiPz6F/aG1yApWkTgqVoQTUCahP851skkDI6PzHedE67CR2KPJ8VNt6WmuIAc4Cg\n" - "zBwxpgBC09TO/3D8fS70xVqBX6dzA4lO9MUZCqgBMt2LTFpklUabviy657kcRQ+H\n" - "tTAy2sDy+bhcj1UyWlE=\n" - "-----END PUBLIC KEY-----"); - QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(CertificateChecker::hasValidEphemeralKeyLength(key)); - } + QByteArray ec521("-----BEGIN PUBLIC KEY-----\n" + "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBi5e64Y/7EGT7Tbpe5h4cZGSpNidN\n" + "fiPz6F/aG1yApWkTgqVoQTUCahP851skkDI6PzHedE67CR2KPJ8VNt6WmuIAc4Cg\n" + "zBwxpgBC09TO/3D8fS70xVqBX6dzA4lO9MUZCqgBMt2LTFpklUabviy657kcRQ+H\n" + "tTAy2sDy+bhcj1UyWlE=\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("ec521") << ec521 << QSsl::KeyAlgorithm::Ec << true; - - void hasValidEphemeralKeyLength_dsa768() - { /* * openssl dsaparam -out dsa768_param.pem 1024 * openssl gendsa -out dsa768_key.pem dsa768_param.pem * openssl dsa -in dsa768_key.pem -pubout -out dsa768_pubkey.pem */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MIIBUTCB6AYHKoZIzjgEATCB3AJhAMZ8q4KifsiCkTcL/qaqrghMK1Ah2EC6cO3b\n" - "a0Dq1FhA7cEQpe0YVcFhcnjd6CCEGz+Zl5nlHGKpgrjdBUZZP66JIFy/WhUb2adZ\n" - "HRcswrSlE/NQS+sPH3CA0WddlcLaDwIVAKsBnl++V6aRAvYR9HVxr5LajwnVAmBq\n" - "7heqwtm9j317cWptXSwR1jKKWPqkOXzaxSVG1PhEEGXTq6PeQgoBRivzbE+/Ome8\n" - "DqfcBsIOCMc47bupEUqK38fmnALGLaig7cup3njaNkxyuoQPngtb0qUiT0dy7dED\n" - "ZAACYQCz1c7kF720wMi9SnrpPD3mZWsC3dqOn5r8EwxanHnkf4KyPctawqGmhZsK\n" - "b3586zIW9Fdg/Rq4yda8GzMLVAtF540s3k5RmsJvnxPEGXlc3c+wEOKR/iHwPrg4\n" - "DNXOVys=\n" - "-----END PUBLIC KEY-----"); - QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(!CertificateChecker::hasValidEphemeralKeyLength(key)); - } + QByteArray dsa768("-----BEGIN PUBLIC KEY-----\n" + "MIIBUTCB6AYHKoZIzjgEATCB3AJhAMZ8q4KifsiCkTcL/qaqrghMK1Ah2EC6cO3b\n" + "a0Dq1FhA7cEQpe0YVcFhcnjd6CCEGz+Zl5nlHGKpgrjdBUZZP66JIFy/WhUb2adZ\n" + "HRcswrSlE/NQS+sPH3CA0WddlcLaDwIVAKsBnl++V6aRAvYR9HVxr5LajwnVAmBq\n" + "7heqwtm9j317cWptXSwR1jKKWPqkOXzaxSVG1PhEEGXTq6PeQgoBRivzbE+/Ome8\n" + "DqfcBsIOCMc47bupEUqK38fmnALGLaig7cup3njaNkxyuoQPngtb0qUiT0dy7dED\n" + "ZAACYQCz1c7kF720wMi9SnrpPD3mZWsC3dqOn5r8EwxanHnkf4KyPctawqGmhZsK\n" + "b3586zIW9Fdg/Rq4yda8GzMLVAtF540s3k5RmsJvnxPEGXlc3c+wEOKR/iHwPrg4\n" + "DNXOVys=\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("dsa768") << dsa768 << QSsl::KeyAlgorithm::Dsa << false; - - void hasValidEphemeralKeyLength_dsa1024() - { /* * openssl dsaparam -out dsa1024_param.pem 1024 * openssl gendsa -out dsa1024_key.pem dsa1024_param.pem * openssl dsa -in dsa1024_key.pem -pubout -out dsa1024_pubkey.pem */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MIIBtzCCASwGByqGSM44BAEwggEfAoGBAMGEyYRk7Hj45r/1vnY4FFIPSLGDnq6g\n" - "60T514zhDaL3A9qXdy+U/i2zm+wscG0mP+9SuznBpTRCM063saCmfQODTCwtg/nZ\n" - "Hn7XGfT1dp5jyqzLDLJ+OSGkazLpUXg5gMPRtju7H8z4oPQMaZZX7bnafBbkQ/Xo\n" - "X9Gn5PGpWqaNAhUA1YRAaKf5eR8cC+SRWIIvP8b3pMcCgYEAmf5LMvR+m2akqKu2\n" - "piW7dN1PxyH0Ixx12aQVF4Hek1cHK6LZW/a/SGrG1pdvz60iq/6aA3vyt2CI8rRi\n" - "mjlCjM5YGGYCKn6l6cTrGQCB2QL7ThIeKFAmPy2wLWe2uGUa12texb4PGKGV7HsO\n" - "wnWAsuMYQ8DLM5tT1v8s/779g/wDgYQAAoGASzXSQchr3SyX5vxTtbZ3v8x/a7nZ\n" - "HAYEiBXfVG8iW+kaAGkyU0L0AIFXJFTUYbjI3EAO24kyFmwWI2e8BkXmibIuAlwY\n" - "1vSGQgpXPK6250pSrx8r8pngr9Qxrt8ElFpLtK+Of6Th/wSTe8COYbXSOP/6Yx7v\n" - "6cObyPo7eAmX8Sg=\n" - "-----END PUBLIC KEY-----"); - QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(CertificateChecker::hasValidEphemeralKeyLength(key)); - } + QByteArray dsa1024("-----BEGIN PUBLIC KEY-----\n" + "MIIBtzCCASwGByqGSM44BAEwggEfAoGBAMGEyYRk7Hj45r/1vnY4FFIPSLGDnq6g\n" + "60T514zhDaL3A9qXdy+U/i2zm+wscG0mP+9SuznBpTRCM063saCmfQODTCwtg/nZ\n" + "Hn7XGfT1dp5jyqzLDLJ+OSGkazLpUXg5gMPRtju7H8z4oPQMaZZX7bnafBbkQ/Xo\n" + "X9Gn5PGpWqaNAhUA1YRAaKf5eR8cC+SRWIIvP8b3pMcCgYEAmf5LMvR+m2akqKu2\n" + "piW7dN1PxyH0Ixx12aQVF4Hek1cHK6LZW/a/SGrG1pdvz60iq/6aA3vyt2CI8rRi\n" + "mjlCjM5YGGYCKn6l6cTrGQCB2QL7ThIeKFAmPy2wLWe2uGUa12texb4PGKGV7HsO\n" + "wnWAsuMYQ8DLM5tT1v8s/779g/wDgYQAAoGASzXSQchr3SyX5vxTtbZ3v8x/a7nZ\n" + "HAYEiBXfVG8iW+kaAGkyU0L0AIFXJFTUYbjI3EAO24kyFmwWI2e8BkXmibIuAlwY\n" + "1vSGQgpXPK6250pSrx8r8pngr9Qxrt8ElFpLtK+Of6Th/wSTe8COYbXSOP/6Yx7v\n" + "6cObyPo7eAmX8Sg=\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("dsa1024") << dsa1024 << QSsl::KeyAlgorithm::Dsa << true; - - void hasValidEphemeralKeyLength_rsa1024() - { /* * openssl genrsa -out rsa1024_key.pem 1024 * openssl rsa -in rsa1024_key.pem -out rsa1024_pubkey.pem -pubout */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3cWoq9XuQI1soyaOM4hjVw4Lc\n" - "TA1HCypXuF/GaTmvxc82J+2F6ISxNFWnSXOs+wpgavXgpfDL7od5fo8EbnMRZLXQ\n" - "tHKRnCy0sQiCQqmSNmWe4qeLwXslKxm1fqj3/tvrX+0VxDVxXz5jS0HH7hHMdELQ\n" - "om/I1IppJFS4IkqEoQIDAQAB\n" - "-----END PUBLIC KEY-----"); - QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(!CertificateChecker::hasValidEphemeralKeyLength(key)); - } + QByteArray rsa1024("-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3cWoq9XuQI1soyaOM4hjVw4Lc\n" + "TA1HCypXuF/GaTmvxc82J+2F6ISxNFWnSXOs+wpgavXgpfDL7od5fo8EbnMRZLXQ\n" + "tHKRnCy0sQiCQqmSNmWe4qeLwXslKxm1fqj3/tvrX+0VxDVxXz5jS0HH7hHMdELQ\n" + "om/I1IppJFS4IkqEoQIDAQAB\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("rsa1024") << rsa1024 << QSsl::KeyAlgorithm::Rsa << false; - - void hasValidEphemeralKeyLength_rsa2048() - { /* * openssl genrsa -out rsa2048_key.pem 2048 * openssl rsa -in rsa2048_key.pem -out rsa2048_pubkey.pem -pubout */ - QByteArray pem("-----BEGIN PUBLIC KEY-----\n" - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs1xh1ymbXRDOBxDmx2I9\n" - "oQbBvqE3QYK5ktPI9mHX38lwQ71AYw7pUxsGzCwwLDRBnHNc1gKtn8IoXhtujsWi\n" - "FvVpayI0GQkJ1Pob66Vr7DY9ZC9dfsJddZi+ce1cAdzg3Od/31y5c3Tiz0laNTkv\n" - "tyGhyyIovfPDJbdX2Srgg8GJAo0AtYJjVCJxZX5TDJLHmBdvK61ZXotgYIjkl7lA\n" - "DO9y31b/10IiLpFcgIUMI+8oF8OypQ/24XKIPVSJm4DZZkjSbUCuwT/mA+61m0no\n" - "q0hOP6K9hZ7pBZvqLZ0gZdVWqarIf9w/I5yS2QGN9jgJN/oJIKyljlreGuSagST/\n" - "5wIDAQAB\n" - "-----END PUBLIC KEY-----"); + QByteArray rsa2048("-----BEGIN PUBLIC KEY-----\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs1xh1ymbXRDOBxDmx2I9\n" + "oQbBvqE3QYK5ktPI9mHX38lwQ71AYw7pUxsGzCwwLDRBnHNc1gKtn8IoXhtujsWi\n" + "FvVpayI0GQkJ1Pob66Vr7DY9ZC9dfsJddZi+ce1cAdzg3Od/31y5c3Tiz0laNTkv\n" + "tyGhyyIovfPDJbdX2Srgg8GJAo0AtYJjVCJxZX5TDJLHmBdvK61ZXotgYIjkl7lA\n" + "DO9y31b/10IiLpFcgIUMI+8oF8OypQ/24XKIPVSJm4DZZkjSbUCuwT/mA+61m0no\n" + "q0hOP6K9hZ7pBZvqLZ0gZdVWqarIf9w/I5yS2QGN9jgJN/oJIKyljlreGuSagST/\n" + "5wIDAQAB\n" + "-----END PUBLIC KEY-----"); + QTest::newRow("rsa2048") << rsa2048 << QSsl::KeyAlgorithm::Rsa << true; + } + + + void hasValidEphemeralKeyLength() + { + QFETCH(QByteArray, pem); + QFETCH(QSsl::KeyAlgorithm, algorithm); + QFETCH(bool, sufficient); + QSslKey key = createQSslKeyWithHandle(pem); - QVERIFY(CertificateChecker::hasValidEphemeralKeyLength(key)); + QVERIFY(!key.isNull()); + + #if QT_VERSION >= 0x050800 + QCOMPARE(key.algorithm(), algorithm); + #else + Q_UNUSED(algorithm) + QCOMPARE(key.algorithm(), QSsl::Opaque); + #endif + + QCOMPARE(CertificateChecker::hasValidEphemeralKeyLength(key), sufficient); } diff --git a/test/qt/drivers/test_ReaderDetector.cpp b/test/qt/drivers/test_ReaderDetector.cpp index 07ab894..1a9d3ef 100644 --- a/test/qt/drivers/test_ReaderDetector.cpp +++ b/test/qt/drivers/test_ReaderDetector.cpp @@ -179,8 +179,8 @@ class test_ReaderDetector void nonSupportedDeviceAttached_noAttachedDevicesFound() { ReaderDetectorMock readerDetector({ - {0x413C, 0x2107} - }); + {0x413C, 0x2107} + }); QCOMPARE(readerDetector.getAttachedDevices({}).size(), 0); } @@ -189,8 +189,8 @@ class test_ReaderDetector void supportedDeviceAttachedButNoDriverInstalled_attachedDeviceFound() { ReaderDetectorMock readerDetector({ - {0x0C4B, 0x0501} - }); + {0x0C4B, 0x0501} + }); const auto devs = readerDetector.getAttachedDevices({}); QCOMPARE(devs.size(), 1); @@ -206,8 +206,8 @@ class test_ReaderDetector static const ReaderManagerPlugInType PLUGIN_TYPE = ReaderManagerPlugInType::UNKNOWN; ReaderDetectorMock readerDetector({ - {0x0C4B, 0x0501} - }); + {0x0C4B, 0x0501} + }); const auto devs = readerDetector.getAttachedDevices({ReaderInfo(PLUGIN_TYPE, READER_NAME, READER_TYPE)}); diff --git a/test/qt/global/test_CardReturnCode.cpp b/test/qt/global/test_CardReturnCode.cpp new file mode 100644 index 0000000..a1bf96b --- /dev/null +++ b/test/qt/global/test_CardReturnCode.cpp @@ -0,0 +1,55 @@ +/*! + * \brief Unit tests for return codes. + * + * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + */ + +#include +#include +#include + +#include "Result.h" + +using namespace governikus; + + +class test_CardReturnCode + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void check_errorCodeToMessage() + { + QCOMPARE(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER).toErrorDescription(), + QString("The process was cancelled by the user.")); + } + + + void check_errorCodeToResult() + { + QCOMPARE(Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)).getMinor(), GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User); + } + + + void check_errorCodeToError() + { + const Result& result = Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User); + QCOMPARE(result.getMessage(), QString("The process was cancelled by the user.")); + } + + + void checkConsistency() + { + for (auto returnCode : Enum::getList()) + { + QVERIFY(!CardReturnCodeUtil::toGlobalStatus(returnCode).toErrorDescription().isEmpty()); + } + } + + +}; + +QTEST_GUILESS_MAIN(test_CardReturnCode) +#include "test_CardReturnCode.moc" diff --git a/test/qt/global/test_EnumHelper.cpp b/test/qt/global/test_EnumHelper.cpp index 46562ce..4d83419 100644 --- a/test/qt/global/test_EnumHelper.cpp +++ b/test/qt/global/test_EnumHelper.cpp @@ -25,6 +25,20 @@ class test_EnumHelper { Q_OBJECT + private: + void testBadConverion(const int pValue, const QString& pExpectedOutput) + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + + TestEnum1 badEnumValue = static_cast(pValue); + QCOMPARE(Enum::getName(badEnumValue), QLatin1String()); + + QCOMPARE(spy.count(), 1); + auto result = spy.takeFirst(); + QVERIFY(result.at(0).toString().endsWith(pExpectedOutput)); + } + + private Q_SLOTS: void initTestCase() { @@ -67,7 +81,7 @@ class test_EnumHelper QCOMPARE(spy.count(), 1); auto result = spy.takeFirst(); - QVERIFY(result.at(0).toString().endsWith("\"FIRST\"\n")); + QVERIFY(result.at(0).toString().endsWith("FIRST\n")); } @@ -76,21 +90,13 @@ class test_EnumHelper QCOMPARE(Enum::getCount(), 3); QCOMPARE(Enum::getName(), QStringLiteral("TestEnum1")); QCOMPARE(Enum::getName(TestEnum1::FIRST), QStringLiteral("FIRST")); + QCOMPARE(Enum::getName(TestEnum1::SECOND), QStringLiteral("SECOND")); + QCOMPARE(Enum::getName(TestEnum1::THIRD), QStringLiteral("THIRD")); - TestEnum1 badEnumValue = static_cast(6); - QCOMPARE(Enum::getName(badEnumValue), QStringLiteral("UNKNOWN(0x6)")); - badEnumValue = static_cast(255); - QCOMPARE(Enum::getName(badEnumValue), QStringLiteral("UNKNOWN(0xff)")); - badEnumValue = static_cast(365); - QCOMPARE(Enum::getName(badEnumValue), QStringLiteral("UNKNOWN(0x16d)")); - badEnumValue = static_cast(2147483647); - QCOMPARE(Enum::getName(badEnumValue), QStringLiteral("UNKNOWN(0x7fffffff)")); - - QCOMPARE(EnumTestEnum1::getCount(), 3); - QCOMPARE(EnumTestEnum1::getName(), QStringLiteral("TestEnum1")); - QCOMPARE(EnumTestEnum1::getName(TestEnum1::SECOND), QStringLiteral("SECOND")); - - QCOMPARE(EnumTestEnum1::getName(EnumTestEnum1::TestEnum1::THIRD), QStringLiteral("THIRD")); + testBadConverion(6, QStringLiteral("UNKNOWN 0x6\n")); + testBadConverion(255, QStringLiteral("UNKNOWN 0xff\n")); + testBadConverion(365, QStringLiteral("UNKNOWN 0x16d\n")); + testBadConverion(2147483647, QStringLiteral("UNKNOWN 0x7fffffff\n")); QCOMPARE(getEnumName(TestEnum1::SECOND), QStringLiteral("SECOND")); QCOMPARE(getEnumName(EnumTestEnum1::TestEnum1::SECOND), QStringLiteral("SECOND")); @@ -102,7 +108,7 @@ class test_EnumHelper const QVector& list1 = Enum::getList(); QCOMPARE(list1.size(), 3); - const QVector& list2 = EnumTestEnum2::getList(); + const QVector& list2 = Enum::getList(); QCOMPARE(list2.size(), 3); QCOMPARE(list1, list2); @@ -119,39 +125,37 @@ class test_EnumHelper QVERIFY(!Enum::isValue(static_cast(999))); QVERIFY(Enum::isValue(static_cast(0))); - QVERIFY(!EnumTestEnum2::isValue(static_cast(0xbb))); - QVERIFY(EnumTestEnum2::isValue(static_cast(0xFF))); - QVERIFY(EnumTestEnum2::isValue(static_cast(0xaa))); + QVERIFY(!Enum::isValue(static_cast(0xbb))); + QVERIFY(Enum::isValue(static_cast(0xFF))); + QVERIFY(Enum::isValue(static_cast(0xaa))); QVERIFY(!Enum::isValue(char(999))); QVERIFY(Enum::isValue(char(0))); - QVERIFY(!EnumTestEnum2::isValue(char(0xbb))); - QVERIFY(EnumTestEnum2::isValue(char(0xff))); - QVERIFY(EnumTestEnum2::isValue(char(0xaa))); + QVERIFY(!Enum::isValue(char(0xbb))); + QVERIFY(Enum::isValue(char(0xff))); + QVERIFY(Enum::isValue(char(0xaa))); } void fromString() { - QCOMPARE(EnumTestEnum1::fromString("SECOND", TestEnum1::THIRD), TestEnum1::SECOND); - QVERIFY(EnumTestEnum1::fromString("SECOND", TestEnum1::THIRD) != TestEnum1::FIRST); + QCOMPARE(Enum::fromString("SECOND", TestEnum1::THIRD), TestEnum1::SECOND); + QVERIFY(Enum::fromString("SECOND", TestEnum1::THIRD) != TestEnum1::FIRST); - QCOMPARE(EnumTestEnum1::fromString("FIRST", TestEnum1::THIRD), TestEnum1::FIRST); - QVERIFY(EnumTestEnum1::fromString("FIRST", TestEnum1::THIRD) != TestEnum1::SECOND); + QCOMPARE(Enum::fromString("FIRST", TestEnum1::THIRD), TestEnum1::FIRST); + QVERIFY(Enum::fromString("FIRST", TestEnum1::THIRD) != TestEnum1::SECOND); - QVERIFY(EnumTestEnum1::fromString("first", TestEnum1::THIRD) != TestEnum1::FIRST); - QVERIFY(EnumTestEnum1::fromString("second", TestEnum1::THIRD) != TestEnum1::SECOND); + QVERIFY(Enum::fromString("first", TestEnum1::THIRD) != TestEnum1::FIRST); + QVERIFY(Enum::fromString("second", TestEnum1::THIRD) != TestEnum1::SECOND); - QVERIFY(EnumTestEnum1::fromString("first", TestEnum1::THIRD) != TestEnum1::SECOND); - QVERIFY(EnumTestEnum1::fromString("second", TestEnum1::THIRD) != TestEnum1::FIRST); + QVERIFY(Enum::fromString("first", TestEnum1::THIRD) != TestEnum1::SECOND); + QVERIFY(Enum::fromString("second", TestEnum1::THIRD) != TestEnum1::FIRST); QCOMPARE(Enum::fromString("abc", TestEnum1::THIRD), TestEnum1::THIRD); - QCOMPARE(EnumTestEnum1::fromString("abc", TestEnum1::THIRD), TestEnum1::THIRD); - QVERIFY(EnumTestEnum1::fromString("FIRST", TestEnum1::THIRD) != TestEnum1::THIRD); + QVERIFY(Enum::fromString("FIRST", TestEnum1::THIRD) != TestEnum1::THIRD); QString value = "FIRST"; - QVERIFY(EnumTestEnum1::fromString(value, TestEnum1::THIRD) != TestEnum1::THIRD); QVERIFY(Enum::fromString(value, TestEnum1::THIRD) != TestEnum1::THIRD); } diff --git a/test/qt/global/test_EnvHolder.cpp b/test/qt/global/test_EnvHolder.cpp new file mode 100644 index 0000000..ddcbfad --- /dev/null +++ b/test/qt/global/test_EnvHolder.cpp @@ -0,0 +1,340 @@ +/*! + * \brief Unit tests for \ref EnvHolder + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "EnvHolder.h" + +#include + +using namespace governikus; + +namespace +{ +class AbstractTestInstance +{ + Q_GADGET + + public: + virtual ~AbstractTestInstance() + { + } + + + virtual QString dummy() = 0; +}; + +class AbstractTestInstanceImpl + : public AbstractTestInstance +{ + Q_GADGET + + public: + virtual QString dummy() + { + return QStringLiteral("impl"); + } + + +}; + +class MockedAbstractTestInstance + : public AbstractTestInstance +{ + Q_GADGET + + public: + virtual QString dummy() + { + return QStringLiteral("mocked"); + } + + +}; + +class TestInstance +{ + Q_GADGET + + protected: + TestInstance() = default; + virtual ~TestInstance() + { + } + + + public: + static TestInstance& getInstance() + { + static TestInstance instance; + return instance; + } + + + virtual QString something() + { + return QStringLiteral("orig"); + } + + +}; + +class TestMockedInstance + : public TestInstance +{ + public: + virtual QString something() override + { + return QStringLiteral("mocked"); + } + + +}; + +class TestSharedInstance + : public QObject +{ + Q_OBJECT + + public: + virtual QString something() + { + return QStringLiteral("orig"); + } + + +}; + +class TestMockedSharedInstance + : public TestSharedInstance +{ + Q_OBJECT + + public: + virtual QString something() override + { + return QStringLiteral("mocked"); + } + + +}; + +class TestAbstractUnmanagedInstance +{ + Q_GADGET + + public: + virtual ~TestAbstractUnmanagedInstance() = default; + virtual QString something() = 0; +}; + +class TestUnmanagedInstance + : public TestAbstractUnmanagedInstance +{ + Q_GADGET + + public: + virtual QString something() override + { + return QStringLiteral("TestUnmanagedInstance"); + } + + +}; + + +} + +namespace governikus +{ + +template<> bool singleton(TestAbstractUnmanagedInstance*& pPtr) +{ + static TestUnmanagedInstance instance; + pPtr = &instance; + return false; +} + + +template<> bool singleton(AbstractTestInstance*& pPtr) +{ + pPtr = new AbstractTestInstanceImpl; + return true; +} + + +template<> AbstractTestInstance* createNewObject() +{ + return new AbstractTestInstanceImpl; +} + + +template<> AbstractTestInstance* createNewObject(QString&& pStr) +{ + class tmpCtor + : public AbstractTestInstance + { + private: + const QString mDummy; + + public: + tmpCtor(const QString& pDummy) : mDummy(pDummy) + { + } + + + virtual QString dummy() override + { + return mDummy; + } + + + }; + + return new tmpCtor(pStr); +} + + +} + + +class test_EnvHolder + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void cleanup() + { + EnvHolder::clear(); + } + + + void mockGet() + { + auto orig = EnvHolder::get(); + QVERIFY(orig); + QCOMPARE(orig->something(), QLatin1String("orig")); + + TestMockedInstance mock; + EnvHolder::set(TestInstance::staticMetaObject, &mock); + auto mocked = EnvHolder::get(); + QVERIFY(mocked); + QCOMPARE(mocked->something(), QLatin1String("mocked")); + + EnvHolder::set(TestInstance::staticMetaObject); + auto orig_again = EnvHolder::get(); + QVERIFY(orig_again); + QCOMPARE(orig_again->something(), QLatin1String("orig")); + } + + + void mockAbstract() + { + auto impl = EnvHolder::get(); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("impl")); + + auto impl2 = EnvHolder::get(); + QVERIFY(impl == impl2); + + MockedAbstractTestInstance m; + EnvHolder::set(AbstractTestInstance::staticMetaObject, &m); + auto mocked = EnvHolder::get(); + QVERIFY(mocked); + QVERIFY(mocked != impl); + QCOMPARE(mocked->dummy(), QLatin1String("mocked")); + } + + + void mockShared() + { + auto orig = EnvHolder::shared(); + QVERIFY(orig); + QCOMPARE(orig->something(), QLatin1String("orig")); + + auto orig2 = EnvHolder::shared(); + QVERIFY(orig == orig2); + + auto mock = QSharedPointer::create(); + EnvHolder::setShared(TestSharedInstance::staticMetaObject, mock); + auto mocked = EnvHolder::shared(); + QVERIFY(mocked); + QCOMPARE(mocked->something(), QLatin1String("mocked")); + QVERIFY(mock == mocked); + QVERIFY(orig != mocked); + + EnvHolder::setShared(TestSharedInstance::staticMetaObject); + auto orig3 = EnvHolder::shared(); + QVERIFY(orig != orig3); + QCOMPARE(orig3->something(), QLatin1String("orig")); + } + + + void getUnmanagedSingleton() + { + auto first = EnvHolder::get(); + QVERIFY(first); + QCOMPARE(first->something(), QLatin1String("TestUnmanagedInstance")); + + auto second = EnvHolder::get(); + QVERIFY(second); + QVERIFY(first == second); + } + + + void mockCreateNewInstance() + { + auto implOrig = EnvHolder::create(); + QVERIFY(implOrig); + QCOMPARE(implOrig->dummy(), QLatin1String("impl")); + delete implOrig; + + EnvHolder::setCreator(AbstractTestInstance::staticMetaObject, [] { + class tmp : public AbstractTestInstanceImpl + { + virtual QString dummy() + { + return QStringLiteral("lambda"); + } + }; + return new tmp; + }); + + auto impl = EnvHolder::create(); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("lambda")); + + auto impl2 = EnvHolder::create(); + QVERIFY(impl2); + QCOMPARE(impl2->dummy(), QLatin1String("lambda")); + QVERIFY(impl != impl2); + + delete impl; + delete impl2; + } + + + void mockArgs() + { + auto impl = EnvHolder::create(QString("flupp")); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("flupp")); + delete impl; + + EnvHolder::setCreator(AbstractTestInstance::staticMetaObject, [] { + return new AbstractTestInstanceImpl; + }); + + auto orig = EnvHolder::create(QString("flupp")); + QVERIFY(orig); + QCOMPARE(orig->dummy(), QLatin1String("impl")); + delete orig; + } + + +}; + +QTEST_GUILESS_MAIN(test_EnvHolder) +#include "test_EnvHolder.moc" diff --git a/test/qt/global/test_ErrorMessage.cpp b/test/qt/global/test_ErrorMessage.cpp deleted file mode 100644 index a6a4f3d..0000000 --- a/test/qt/global/test_ErrorMessage.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * \brief Unit tests for \ref ErrorMessage - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "ErrorMessage.h" - -#include - -using namespace governikus; - -class test_ErrorMessage - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void toString() - { - QSKIP("Will be refactored in next release"); - - auto str = ErrorMessage::toString(ErrorMessageId::PROXY_ERROR); - QCOMPARE(str, QString("Establishing a connection via the proxy did not succeed.\nPlease contact Your administrator or our support at https://www.ausweisapp.bund.de/service/support/")); - - str = ErrorMessage::toString(ErrorMessageId::SSL_ERROR); - QCOMPARE(str, QString("It wasn't possible to connect to the server: a secure connection could not be established.\nPlease contact Your service provider or our support at https://www.ausweisapp.bund.de/service/support/")); - } - - -}; - -QTEST_GUILESS_MAIN(test_ErrorMessage) -#include "test_ErrorMessage.moc" diff --git a/test/qt/global/test_HashAlgorithmUtil.cpp b/test/qt/global/test_HashAlgorithmUtil.cpp deleted file mode 100644 index 39f2081..0000000 --- a/test/qt/global/test_HashAlgorithmUtil.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*! - * test_HashAlgorithmUtil.cpp - * - * \brief Unit tests for \ref result - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "HashAlgorithmUtil.h" - -#include "LogHandler.h" - -#include - -using namespace governikus; - -class test_HashAlgorithmUtil - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: -#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0) - - void initTestCase() - { - LogHandler::getInstance().init(); - } - - - void cleanup() - { - LogHandler::getInstance().resetBacklog(); - } - - - void names() - { - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Md4), QString("MD4")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Md5), QString("MD5")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha1), QString("SHA1")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha224), QString("SHA224")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha256), QString("SHA256")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha384), QString("SHA384")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha512), QString("SHA512")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha3_224), QString("SHA3_224")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha3_256), QString("SHA3_256")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha3_384), QString("SHA3_384")); - QCOMPARE(HashAlgorithmUtil::getName(QCryptographicHash::Sha3_512), QString("SHA3_512")); - } - - - void debugStream() - { - QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - QCryptographicHash::Algorithm algo = QCryptographicHash::Sha3_224; - qDebug() << "output" << algo; - - QCOMPARE(spy.count(), 1); - auto param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("output SHA3_224")); - } - - -#endif - - -}; - -QTEST_GUILESS_MAIN(test_HashAlgorithmUtil) -#include "test_HashAlgorithmUtil.moc" diff --git a/test/qt/global/test_ReturnCodeUtil.cpp b/test/qt/global/test_ReturnCodeUtil.cpp deleted file mode 100644 index 5faac6c..0000000 --- a/test/qt/global/test_ReturnCodeUtil.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * \brief Unit tests for return codes. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ReturnCodeUtil.h" - -#include -#include -#include - -using namespace governikus; - - -class test_ReturnCodeUtil - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void check_errorCodeToString() - { - QCOMPARE(ReturnCodeUtil::toString(ReturnCode::CANCELLATION_BY_USER), - QString("The process was cancelled by the user.")); - } - - - void check_errorCodeToMessage() - { - QCOMPARE(ReturnCodeUtil::toMessage(ReturnCode::CANCELLATION_BY_USER), - QString("The process was cancelled by the user.")); - } - - - void check_errorCodeToResult() - { - QCOMPARE(ReturnCodeUtil::toResult(ReturnCode::CANCELLATION_BY_USER), - Result::Minor::SAL_Cancellation_by_User); - } - - - void check_errorCodeToError() - { - auto error = ReturnCodeUtil::toError(ReturnCode::CANCELLATION_BY_USER); - QCOMPARE(error.first, Result::Minor::SAL_Cancellation_by_User); - QCOMPARE(error.second, QString("The process was cancelled by the user.")); - } - - - void checkConsistency() - { - for (auto returnCode : EnumReturnCode::getList()) - { - QVERIFY(!ReturnCodeUtil::toString(returnCode).isEmpty()); - QVERIFY(!ReturnCodeUtil::toMessage(returnCode).isEmpty()); - } - } - - -}; - -QTEST_GUILESS_MAIN(test_ReturnCodeUtil) -#include "test_ReturnCodeUtil.moc" diff --git a/test/qt/global/test_result.cpp b/test/qt/global/test_result.cpp index 3b9fce8..5389a85 100644 --- a/test/qt/global/test_result.cpp +++ b/test/qt/global/test_result.cpp @@ -9,6 +9,7 @@ #include "LogHandler.h" #include "Result.h" +#include #include using namespace governikus; @@ -39,15 +40,15 @@ class test_result void parse() { - QCOMPARE(Result::parseMajor("crap"), Result::Major::null); - QCOMPARE(Result::parseMinor("crap"), Result::Minor::null); + QCOMPARE(Result::parseMajor("crap"), Result::Major::Unknown); + QCOMPARE(Result::parseMinor("crap"), GlobalStatus::Code::Unknown_Error); QVERIFY(!Result::isMajor("crap")); QVERIFY(!Result::isMinor("crap")); QCOMPARE(Result::parseMajor("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok"), Result::Major::Ok); QCOMPARE(Result::parseMinor("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#noPermission"), - Result::Minor::AL_No_Permission); + GlobalStatus::Code::Paos_Error_AL_No_Permission); QVERIFY(Result::isMajor("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok")); QVERIFY(Result::isMinor("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#noPermission")); @@ -56,20 +57,10 @@ class test_result void createInternalError() { - Result result = Result::createInternalError(); + Result result = Result(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity); QCOMPARE(result.getMajor(), Result::Major::Error); - QCOMPARE(result.getMinor(), Result::Minor::AL_Internal_Error); - QCOMPARE(result.getMessage(), QString()); - QCOMPARE(result.getMessageLang(), QString("en")); - } - - - void createInternalErrorMessage() - { - Result result = Result::createInternalError("test message"); - QCOMPARE(result.getMajor(), Result::Major::Error); - QCOMPARE(result.getMinor(), Result::Minor::AL_Internal_Error); - QCOMPARE(result.getMessage(), QString("test message")); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Paos_Error_AL_Internal_Error); + QCOMPARE(result.getMessage(), QString("The authenticity of your ID card could not be confirmed.")); QCOMPARE(result.getMessageLang(), QString("en")); } @@ -78,7 +69,7 @@ class test_result { Result result = Result::createOk(); QCOMPARE(result.getMajor(), Result::Major::Ok); - QCOMPARE(result.getMinor(), Result::Minor::null); + QCOMPARE(result.getMinor(), GlobalStatus::Code::Unknown_Error); QCOMPARE(result.getMessage(), QString()); QCOMPARE(result.getMessageLang(), QString("en")); } @@ -95,31 +86,31 @@ class test_result spy.clear(); - qDebug() << Result::createInternalError("dummy message"); + qDebug() << Result(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity); QCOMPARE(spy.count(), 1); param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#internalError | dummy message\"")); + QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#internalError | The authenticity of your ID card could not be confirmed.\"")); spy.clear(); - qDebug() << Result::createCancelByUserError(); + qDebug() << Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)); QCOMPARE(spy.count(), 1); param = spy.takeFirst(); QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/sal#cancellationByUser | The process was cancelled by the user.\"")); spy.clear(); - qDebug() << Result::createError(ReturnCode::UNDEFINED); + qDebug() << Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::UNDEFINED)); QCOMPARE(spy.count(), 1); param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError | An unknown error occurred: UNDEFINED\"")); + QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError | An unexpected error has occurred during processing.\"")); spy.clear(); - qDebug() << Result::createCertChainInterruptedError(""); + qDebug() << Result(GlobalStatus::Code::Workflow_Preverification_Error); QCOMPARE(spy.count(), 1); param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/sal#certificateChainInterrupted | \"")); + QVERIFY(param.at(0).toString().contains("Result: \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error | http://www.bsi.bund.de/ecard/api/1.1/resultminor/sal#certificateChainInterrupted | Pre-verification failed.\"")); } @@ -134,13 +125,60 @@ class test_result "\"language\":\"en\",\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\"," "\"message\":\"The process was cancelled by the user.\"," "\"minor\":\"http://www.bsi.bund.de/ecard/api/1.1/resultminor/sal#cancellationByUser\"}"; - QCOMPARE(bytes(Result::createCancelByUserError().toJson()), expected); + QCOMPARE(bytes(Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)).toJson()), expected); expected = "{\"description\":\"A Communication error occurred during processing.\"," "\"language\":\"en\",\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\"," - "\"message\":\"BAMM!\"," + "\"message\":\"The selected card reader cannot be accessed anymore.\"," "\"minor\":\"http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#communicationError\"}"; - QCOMPARE(bytes(Result::createCommunicationError("BAMM!").toJson()), expected); + QCOMPARE(bytes(Result(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible).toJson()), expected); + } + + + void comparison() + { + QVERIFY(!(Result::createOk() == Result(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)))); + + const Result& result = Result::createOk(); + QVERIFY(result == Result(result.toStatus())); + } + + + void conversion_data() + { + QTest::addColumn("minor"); + + const QMetaEnum& metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < metaEnum.keyCount(); i++) + { + const GlobalStatus::Code minor = static_cast(i); + const char* name = metaEnum.valueToKey(i); + const QString check = QString::fromStdString(name); + + if (minor == GlobalStatus::Code::Paos_Unexpected_Warning || !check.startsWith(QLatin1String("Paos_"))) + { + continue; + } + + QTest::newRow(name) << minor; + } + } + + + void conversion() + { + QFETCH(GlobalStatus::Code, minor); + + const Result result_1(Result::Major::Error, minor, "Game Over :(", Origin::Client); + QVERIFY(result_1 == Result(result_1.toStatus())); + + const Result result_2(Result::Major::Error, minor, "Game Over :(", Origin::Server); + QVERIFY(!(result_2 == Result(result_2.toStatus()))); + + const Result result_3(Result::Major::Error, minor, Result::getMessage(minor), Origin::Server); + QVERIFY(result_3 == Result(result_3.toStatus())); + + QVERIFY(!(result_1 == result_2)); } diff --git a/test/qt/jsonapi/test_Message.cpp b/test/qt/jsonapi/test_Message.cpp index 9afde28..8899c6e 100644 --- a/test/qt/jsonapi/test_Message.cpp +++ b/test/qt/jsonapi/test_Message.cpp @@ -130,7 +130,7 @@ class test_Message QVERIFY(context->isStateApproved()); context->setStateApproved(false); // reset - auto msg = QByteArray("{\"cmd\":\"SET_CAN\",\"can\": \"12345\"}"); + auto msg = QByteArray("{\"cmd\":\"SET_CAN\",\"value\": \"12345\"}"); auto expectedBadState = QByteArray("{\"error\":\"SET_CAN\",\"msg\":\"BAD_STATE\"}"); QCOMPARE(dispatcher.processCommand(msg), expectedBadState); @@ -208,7 +208,7 @@ class test_Message void finishAuthContext() { const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); - context->setResult(Result::createOk()); + context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://dummy")); MessageDispatcher dispatcher; dispatcher.init(context); diff --git a/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp b/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp index 252c4f6..c628ff9 100644 --- a/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp +++ b/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp @@ -9,6 +9,7 @@ #include "InternalActivationContext.h" #include "MessageDispatcher.h" +#include "TestAuthContext.h" #include using namespace governikus; @@ -26,12 +27,11 @@ class test_MsgHandlerAccessRights } - QSharedPointer getContextWithChat() + QSharedPointer getContextWithChat() { - QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); - context->setRequiredChat(getChat({AccessRight::READ_DG01, AccessRight::READ_DG04})); - context->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION, AccessRight::READ_DG21})); - context->setEffectiveChat(getChat({AccessRight::READ_DG01, AccessRight::READ_DG04, AccessRight::READ_DG21, AccessRight::AGE_VERIFICATION})); + QSharedPointer context(new TestAuthContext(new InternalActivationContext(QUrl("http://dummy")), ":/paos/DIDAuthenticateEAC1.xml")); + context->setRequiredAccessRights({AccessRight::READ_DG01, AccessRight::READ_DG04}); + context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::READ_DG05}); return context; } @@ -42,7 +42,7 @@ class test_MsgHandlerAccessRights MessageDispatcher dispatcher; dispatcher.init(getContextWithChat()); - QCOMPARE(dispatcher.processStateChange("StateEditAccessRights"), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processStateChange("StateEditAccessRights"), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); } @@ -69,7 +69,7 @@ class test_MsgHandlerAccessRights QVERIFY(!context->isStateApproved()); QByteArray msg = QByteArray("{\"cmd\": \"GET_ACCESS_RIGHTS\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"ACCEPT\"}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray()); @@ -84,7 +84,7 @@ class test_MsgHandlerAccessRights QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QByteArray msg = QByteArray("{\"cmd\": \"GET_ACCESS_RIGHTS\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); } @@ -95,49 +95,49 @@ class test_MsgHandlerAccessRights QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QByteArray msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [8,\"11\"]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data needs to be integer\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data needs to be integer\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0, 123]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data is invalid\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data is invalid\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); - msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [28]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8],\"optional\":[28,0],\"required\":[11,8]}}")); + msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [12]}"); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0, 11]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data is invalid\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Entry in 'raw' data is invalid\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8],\"optional\":[12,0],\"required\":[11,8]}}")); - msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0,28]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0,12]}"); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); - msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0,28]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0,12]}"); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": []}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8],\"optional\":[12,0],\"required\":[11,8]}}")); } void setAccessRightsWithoutChat() { - const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); - context->setEffectiveChat(getChat({})); + const auto& context = getContextWithChat(); + context->setOptionalAccessRights({}); MessageDispatcher dispatcher; dispatcher.init(context); QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QByteArray msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"No optional access rights available\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[],\"optional\":[],\"required\":[]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"No optional access rights available\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8],\"optional\":[],\"required\":[11,8]}}")); - context->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION})); + context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION}); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0]}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[0],\"optional\":[0],\"required\":[]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[11,8,0],\"optional\":[0],\"required\":[11,8]}}")); - context->setOptionalChat(QSharedPointer()); - context->setRequiredChat(getChat({AccessRight::AGE_VERIFICATION})); + context->setRequiredAccessRights({AccessRight::AGE_VERIFICATION}); + context->setOptionalAccessRights({}); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": [0]}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"No optional access rights available\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[0],\"optional\":[],\"required\":[0]}}")); } @@ -150,10 +150,10 @@ class test_MsgHandlerAccessRights QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QByteArray msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"raw\": null}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Invalid 'raw' data\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Invalid 'raw' data\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); msg = QByteArray("{\"cmd\": \"SET_ACCESS_RIGHTS\", \"RAW\": []}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"'raw' cannot be undefined\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[28,11,8,0],\"optional\":[28,0],\"required\":[11,8]}}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"'raw' cannot be undefined\",\"msg\":\"ACCESS_RIGHTS\",\"raw\":{\"effective\":[12,11,8,0],\"optional\":[12,0],\"required\":[11,8]}}")); } diff --git a/test/qt/jsonapi/test_MsgHandlerAuth.cpp b/test/qt/jsonapi/test_MsgHandlerAuth.cpp index d5ebc66..b172ab8 100644 --- a/test/qt/jsonapi/test_MsgHandlerAuth.cpp +++ b/test/qt/jsonapi/test_MsgHandlerAuth.cpp @@ -132,7 +132,7 @@ class test_MsgHandlerAuth void result() { const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); - context->setResult(Result::createOk()); + context->setStatus(GlobalStatus::Code::No_Error); MsgHandlerAuth msg(context); QCOMPARE(msg.toJson(), QByteArray("{\"msg\":\"AUTH\",\"result\":{\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\"}}")); } @@ -141,7 +141,7 @@ class test_MsgHandlerAuth void resultWithUrl() { const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); - context->setResult(Result::createOk()); + context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://www.governikus.de")); MsgHandlerAuth msg(context); QCOMPARE(msg.toJson(), QByteArray("{\"msg\":\"AUTH\",\"result\":{\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\"},\"url\":\"http://www.governikus.de\"}")); @@ -162,13 +162,14 @@ class test_MsgHandlerAuth ""))); const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); - context->setResult(Result::createCommunicationError()); + context->setStatus(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible); context->setTcToken(token); MsgHandlerAuth msg(context); QCOMPARE(msg.toJson(), QByteArray("{\"msg\":\"AUTH\"," "\"result\":{\"description\":\"A Communication error occurred during processing.\"," "\"language\":\"en\"," "\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\"," + "\"message\":\"The selected card reader cannot be accessed anymore.\"," "\"minor\":\"http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#communicationError\"}," "\"url\":\"https://service.example.de/ComError?7eb39f62\"}")); } diff --git a/test/qt/jsonapi/test_MsgHandlerCertificate.cpp b/test/qt/jsonapi/test_MsgHandlerCertificate.cpp index 6dd0b26..239054f 100644 --- a/test/qt/jsonapi/test_MsgHandlerCertificate.cpp +++ b/test/qt/jsonapi/test_MsgHandlerCertificate.cpp @@ -10,7 +10,7 @@ #include "MessageDispatcher.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" -#include "TestFileHelper.h" +#include "TestAuthContext.h" #include using namespace governikus; @@ -20,20 +20,11 @@ class test_MsgHandlerCertificate { Q_OBJECT - QSharedPointer getChat(const std::initializer_list& pList) - { - auto chat = newObject(); - chat->setAccessRights(QSet(pList)); - return chat; - } - - QSharedPointer getContext() { - QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); - context->setRequiredChat(getChat({AccessRight::READ_DG01})); - context->setOptionalChat(getChat({AccessRight::AGE_VERIFICATION})); - context->setEffectiveChat(getChat({AccessRight::READ_DG01, AccessRight::AGE_VERIFICATION})); + QSharedPointer context(new TestAuthContext(new InternalActivationContext(QUrl("http://dummy")), ":/paos/DIDAuthenticateEAC1.xml")); + context->setRequiredAccessRights({AccessRight::READ_DG01}); + context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION}); return context; } @@ -54,8 +45,6 @@ class test_MsgHandlerCertificate void getCertificate() { auto context = getContext(); - QSharedPointer eac1(dynamic_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1.xml")))); - context->setDidAuthenticateEac1(eac1); MessageDispatcher dispatcher; dispatcher.init(context); diff --git a/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp b/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp index f2e9198..f97cdba 100644 --- a/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp +++ b/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp @@ -66,7 +66,7 @@ class test_MsgHandlerEnterCan MessageDispatcher dispatcher; setValidCanState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_CAN\", \"can\": 123456}"); + QByteArray msg("{\"cmd\": \"SET_CAN\", \"value\": 123456}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Invalid value\",\"msg\":\"ENTER_CAN\"}")); } @@ -76,23 +76,23 @@ class test_MsgHandlerEnterCan MessageDispatcher dispatcher; setValidCanState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_CAN\", \"can\": \"12345\"}"); + QByteArray msg("{\"cmd\": \"SET_CAN\", \"value\": \"12345\"}"); QByteArray expected("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_CAN\"}"); QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"1234567\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"1234567\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"abcdef\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"abcdef\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"123456a\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"123456a\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"12x456\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"12x456\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); } @@ -102,10 +102,10 @@ class test_MsgHandlerEnterCan MessageDispatcher dispatcher; setValidCanState(dispatcher, QStringLiteral("invalid")); - QByteArray msg("{\"cmd\": \"SET_CAN\", \"can\": \"12345\"}"); + QByteArray msg("{\"cmd\": \"SET_CAN\", \"value\": \"12345\"}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"SET_CAN\",\"msg\":\"BAD_STATE\"}")); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"123456\"}"; + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"123456\"}"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"SET_CAN\",\"msg\":\"BAD_STATE\"}")); } @@ -115,7 +115,7 @@ class test_MsgHandlerEnterCan MessageDispatcher dispatcher; setValidCanState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_CAN\", \"can\": \"123456\"}"); + QByteArray msg("{\"cmd\": \"SET_CAN\", \"value\": \"123456\"}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray()); } @@ -131,14 +131,14 @@ class test_MsgHandlerEnterCan context->setReaderName("MockReader"); QCOMPARE(dispatcher.processStateChange("StateEstablishPaceCan"), QByteArray("{\"msg\":\"ENTER_CAN\"}")); - QByteArray msg = "{\"cmd\": \"SET_CAN\", \"can\": \"54321\"}"; + QByteArray msg = "{\"cmd\": \"SET_CAN\", \"value\": \"54321\"}"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_CAN\"}")); context->setReaderName("MockReader CARD"); - QCOMPARE(dispatcher.processStateChange("StateEstablishPaceCan"), QByteArray("{\"msg\":\"ENTER_CAN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); - msg = "{\"cmd\": \"SET_CAN\", \"can\": \"54321\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_CAN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); + QCOMPARE(dispatcher.processStateChange("StateEstablishPaceCan"), QByteArray("{\"msg\":\"ENTER_CAN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); + msg = "{\"cmd\": \"SET_CAN\", \"value\": \"54321\"}"; + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_CAN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); } diff --git a/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp b/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp index 96bedd0..89170c1 100644 --- a/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp +++ b/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp @@ -66,7 +66,7 @@ class test_MsgHandlerEnterPin MessageDispatcher dispatcher; setValidPinState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_PIN\", \"pin\": 123456}"); + QByteArray msg("{\"cmd\": \"SET_PIN\", \"value\": 123456}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"Invalid value\",\"msg\":\"ENTER_PIN\"}")); } @@ -76,23 +76,23 @@ class test_MsgHandlerEnterPin MessageDispatcher dispatcher; setValidPinState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_PIN\", \"pin\": \"12345\"}"); + QByteArray msg("{\"cmd\": \"SET_PIN\", \"value\": \"12345\"}"); QByteArray expected("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_PIN\"}"); QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"1234567\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"1234567\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"abcdef\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"abcdef\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"123456a\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"123456a\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"12x456\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"12x456\"}"; QCOMPARE(dispatcher.processCommand(msg), expected); } @@ -102,10 +102,10 @@ class test_MsgHandlerEnterPin MessageDispatcher dispatcher; setValidPinState(dispatcher, QStringLiteral("invalid")); - QByteArray msg("{\"cmd\": \"SET_PIN\", \"pin\": \"12345\"}"); + QByteArray msg("{\"cmd\": \"SET_PIN\", \"value\": \"12345\"}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"SET_PIN\",\"msg\":\"BAD_STATE\"}")); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"123456\"}"; + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"123456\"}"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"SET_PIN\",\"msg\":\"BAD_STATE\"}")); } @@ -115,7 +115,7 @@ class test_MsgHandlerEnterPin MessageDispatcher dispatcher; setValidPinState(dispatcher); - QByteArray msg("{\"cmd\": \"SET_PIN\", \"pin\": \"123456\"}"); + QByteArray msg("{\"cmd\": \"SET_PIN\", \"value\": \"123456\"}"); QCOMPARE(dispatcher.processCommand(msg), QByteArray()); } @@ -131,14 +131,14 @@ class test_MsgHandlerEnterPin context->setReaderName("MockReader"); QCOMPARE(dispatcher.processStateChange("StateEstablishPacePin"), QByteArray("{\"msg\":\"ENTER_PIN\"}")); - QByteArray msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"54321\"}"; + QByteArray msg = "{\"cmd\": \"SET_PIN\", \"value\": \"54321\"}"; QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_PIN\"}")); context->setReaderName("MockReader CARD"); - QCOMPARE(dispatcher.processStateChange("StateEstablishPacePin"), QByteArray("{\"msg\":\"ENTER_PIN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); - msg = "{\"cmd\": \"SET_PIN\", \"pin\": \"54321\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_PIN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); + QCOMPARE(dispatcher.processStateChange("StateEstablishPacePin"), QByteArray("{\"msg\":\"ENTER_PIN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); + msg = "{\"cmd\": \"SET_PIN\", \"value\": \"54321\"}"; + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"error\":\"You must provide 6 digits\",\"msg\":\"ENTER_PIN\",\"reader\":{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader CARD\"}}")); } diff --git a/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp b/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp new file mode 100644 index 0000000..d8739a1 --- /dev/null +++ b/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp @@ -0,0 +1,49 @@ +/*! + * \brief Unit tests for \ref MsgHandlerEnterPuk + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "messages/MsgHandlerEnterPuk.h" + +#include "MessageDispatcher.h" + +#include +#include + +Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) + +using namespace governikus; + +class test_MsgHandlerEnterPuk + : public QObject +{ + Q_OBJECT + + static void setValidState(MessageDispatcher& pDispatcher, const QString& pState = QStringLiteral("StateEstablishPacePuk")) + { + QSharedPointer context(new WorkflowContext()); + pDispatcher.init(context); + + QByteArray expected; + if (pState == QLatin1String("StateEstablishPacePuk")) + { + expected = "{\"msg\":\"ENTER_PUK\"}"; + } + + QCOMPARE(pDispatcher.processStateChange(pState), expected); + } + + + private Q_SLOTS: + void stateMsg() + { + MessageDispatcher dispatcher; + setValidState(dispatcher); + } + + +}; + +QTEST_GUILESS_MAIN(test_MsgHandlerEnterPuk) +#include "test_MsgHandlerEnterPuk.moc" diff --git a/test/qt/jsonapi/test_MsgHandlerInternalError.cpp b/test/qt/jsonapi/test_MsgHandlerInternalError.cpp index 83e0244..47aa4e2 100644 --- a/test/qt/jsonapi/test_MsgHandlerInternalError.cpp +++ b/test/qt/jsonapi/test_MsgHandlerInternalError.cpp @@ -47,9 +47,10 @@ class test_MsgHandlerInternalError void msgVoid() { - MsgHandler msg = MsgHandler::MsgVoid; + MsgHandler msg = MsgHandler::Void; QCOMPARE(msg.toJson(), QByteArray("{\"msg\":\"INTERNAL_ERROR\"}")); QCOMPARE(msg.getOutput(), QByteArray()); + QVERIFY(msg.isVoid()); } diff --git a/test/qt/jsonapi/test_MsgHandlerReader.cpp b/test/qt/jsonapi/test_MsgHandlerReader.cpp index f7fc817..12c1548 100644 --- a/test/qt/jsonapi/test_MsgHandlerReader.cpp +++ b/test/qt/jsonapi/test_MsgHandlerReader.cpp @@ -43,7 +43,7 @@ class test_MsgHandlerReader QCOMPARE(noReader.toJson(), QByteArray("{\"attached\":false,\"msg\":\"READER\",\"name\":\"MockReader\"}")); MsgHandlerReader reader("MockReader 0815"); - QCOMPARE(reader.toJson(), QByteArray("{\"attached\":true,\"card\":{\"inserted\":false},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(reader.toJson(), QByteArray("{\"attached\":true,\"card\":null,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); } @@ -67,7 +67,7 @@ class test_MsgHandlerReader QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":false,\"msg\":\"READER\",\"name\":\"MockReader 081\"}")); msg = "{\"cmd\": \"GET_READER\", \"name\": \"MockReader 0815\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"inserted\":false},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":null,\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); MockReaderManagerPlugIn::getInstance().removeReader("MockReader 0815"); msg = "{\"cmd\": \"GET_READER\", \"name\": \"MockReader 0815\"}"; @@ -82,7 +82,7 @@ class test_MsgHandlerReader MessageDispatcher dispatcher; QByteArray msg("{\"cmd\": \"GET_READER\", \"name\": \"MockReader 0815\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); } @@ -107,19 +107,19 @@ class test_MsgHandlerReader MessageDispatcher dispatcher; QByteArray msg("{\"cmd\": \"GET_READER\", \"name\": \"MockReader 0815\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"MockReader 0815\"}")); msg = "{\"cmd\": \"GET_READER\", \"name\": \"ReaderMock\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"ReaderMock\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"msg\":\"READER\",\"name\":\"ReaderMock\"}")); msg = "{\"cmd\": \"GET_READER\", \"name\": \"ReaderMockXYZ\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"inserted\":false},\"msg\":\"READER\",\"name\":\"ReaderMockXYZ\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":null,\"msg\":\"READER\",\"name\":\"ReaderMockXYZ\"}")); msg = "{\"cmd\": \"GET_READER\", \"name\": \"SpecialMock\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"inserted\":false},\"msg\":\"READER\",\"name\":\"SpecialMock\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":null,\"msg\":\"READER\",\"name\":\"SpecialMock\"}")); msg = "{\"cmd\": \"GET_READER\", \"name\": \"SpecialMockWithGermanCard\"}"; - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":true,\"inserted\":true,\"retryCounter\":3},\"msg\":\"READER\",\"name\":\"SpecialMockWithGermanCard\"}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"attached\":true,\"card\":{\"deactivated\":true,\"retryCounter\":3},\"msg\":\"READER\",\"name\":\"SpecialMockWithGermanCard\"}")); } diff --git a/test/qt/jsonapi/test_MsgHandlerReaderList.cpp b/test/qt/jsonapi/test_MsgHandlerReaderList.cpp index c674eb6..2003854 100644 --- a/test/qt/jsonapi/test_MsgHandlerReaderList.cpp +++ b/test/qt/jsonapi/test_MsgHandlerReaderList.cpp @@ -48,7 +48,7 @@ class test_MsgHandlerReaderList MessageDispatcher dispatcher; QByteArray msg("{\"cmd\": \"GET_READER_LIST\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"reader\":[{\"attached\":true,\"card\":{\"inserted\":false},\"name\":\"MockReader 0815\"}]}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"reader\":[{\"attached\":true,\"card\":null,\"name\":\"MockReader 0815\"}]}")); } @@ -59,7 +59,7 @@ class test_MsgHandlerReaderList MessageDispatcher dispatcher; QByteArray msg("{\"cmd\": \"GET_READER_LIST\"}"); - QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"reader\":[{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader 0815\"}]}")); + QCOMPARE(dispatcher.processCommand(msg), QByteArray("{\"msg\":\"READER_LIST\",\"reader\":[{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader 0815\"}]}")); } @@ -86,11 +86,11 @@ class test_MsgHandlerReaderList QByteArray msg("{\"cmd\": \"GET_READER_LIST\"}"); QByteArray expected("{\"msg\":\"READER_LIST\",\"reader\":[" - "{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"MockReader 0815\"}," - "{\"attached\":true,\"card\":{\"deactivated\":false,\"inserted\":true,\"retryCounter\":-1},\"name\":\"ReaderMock\"}," - "{\"attached\":true,\"card\":{\"inserted\":false},\"name\":\"ReaderMockXYZ\"}," - "{\"attached\":true,\"card\":{\"inserted\":false},\"name\":\"SpecialMock\"}," - "{\"attached\":true,\"card\":{\"deactivated\":true,\"inserted\":true,\"retryCounter\":3},\"name\":\"SpecialMockWithGermanCard\"}" + "{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"MockReader 0815\"}," + "{\"attached\":true,\"card\":{\"deactivated\":false,\"retryCounter\":-1},\"name\":\"ReaderMock\"}," + "{\"attached\":true,\"card\":null,\"name\":\"ReaderMockXYZ\"}," + "{\"attached\":true,\"card\":null,\"name\":\"SpecialMock\"}," + "{\"attached\":true,\"card\":{\"deactivated\":true,\"retryCounter\":3},\"name\":\"SpecialMockWithGermanCard\"}" "]}"); QCOMPARE(dispatcher.processCommand(msg), expected); diff --git a/test/qt/network/test_DatagramHandlerImpl.cpp b/test/qt/network/test_DatagramHandlerImpl.cpp new file mode 100644 index 0000000..029dbe2 --- /dev/null +++ b/test/qt/network/test_DatagramHandlerImpl.cpp @@ -0,0 +1,205 @@ +/*! + * \brief Unit tests for \ref DatagramHandlerImpl + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "DatagramHandlerImpl.h" + +#include "EnvHolder.h" +#include "LogHandler.h" + +#include +#include +#include + +using namespace governikus; + + +class test_DatagramHandlerImpl + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + DatagramHandler::registerMetaTypes(); + LogHandler::getInstance().init(); + } + + + void init() + { + DatagramHandlerImpl::cPort = 0; + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void startUpShutDown() + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + QSharedPointer socket(EnvHolder::create()); + + QVERIFY(socket->isBound()); + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Bound on port:")); + + socket.reset(); + QCOMPARE(spy.count(), 1); + param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Shutdown socket")); + } + + + void cannotStart() + { + #ifdef Q_OS_WIN + QSKIP("Windows does not block privileged ports"); + #endif + + DatagramHandlerImpl::cPort = 80; + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + QSharedPointer socket(EnvHolder::create()); + + QVERIFY(!socket->isBound()); + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Cannot bind socket: \"The address is protected\"")); + } + + + void getNonJsonDatagram() + { + QSharedPointer socket(EnvHolder::create()); + QVERIFY(socket->isBound()); + QSignalSpy spySocket(socket.data(), &DatagramHandler::fireNewMessage); + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + QUdpSocket clientSocket; + #ifndef QT_NO_NETWORKPROXY + clientSocket.setProxy(QNetworkProxy::NoProxy); + #endif + + auto written = clientSocket.writeDatagram("dummy", QHostAddress::LocalHost, socket.staticCast()->mSocket->localPort()); + spy.wait(); + QCOMPARE(written, 5); + + QCOMPARE(spySocket.count(), 0); + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Datagram does not contain valid JSON: \"dummy\"")); + } + + + void getJsonDatagram_data() + { + QTest::addColumn("broadcast"); + + QTest::newRow("WithBroadcast") << true; + QTest::newRow("WithoutBroadcast") << false; + } + + + void getJsonDatagram() + { + QFETCH(bool, broadcast); + + #ifdef Q_OS_FREEBSD + if (broadcast) + { + QSKIP("FreeBSD does not like that"); + } + #endif + + QSharedPointer socket(EnvHolder::create()); + QVERIFY(socket->isBound()); + QSignalSpy spySocket(socket.data(), &DatagramHandler::fireNewMessage); + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + QUdpSocket clientSocket; + #ifndef QT_NO_NETWORKPROXY + clientSocket.setProxy(QNetworkProxy::NoProxy); + #endif + + QByteArray data("{\"key\":\"value\"}"); + auto written = clientSocket.writeDatagram(data, broadcast ? QHostAddress::Broadcast : QHostAddress::LocalHost, socket.staticCast()->mSocket->localPort()); + spy.wait(); + QCOMPARE(written, data.size()); + + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Fire new message")); + + QCOMPARE(spySocket.count(), 1); + const auto& msg = spySocket.takeFirst(); + QCOMPARE(msg.size(), 2); + QCOMPARE(msg.at(0).toJsonDocument().toJson(QJsonDocument::Compact), data); + } + + + void sendDatagram_data() + { + QTest::addColumn("broadcast"); + + QTest::newRow("WithBroadcast") << true; + QTest::newRow("WithoutBroadcast") << false; + } + + + void sendDatagram() + { + QFETCH(bool, broadcast); + + QUdpSocket receiver; + #ifndef QT_NO_NETWORKPROXY + receiver.setProxy(QNetworkProxy::NoProxy); + #endif + + QVERIFY(receiver.bind()); + QSignalSpy spyReceiver(&receiver, &QUdpSocket::readyRead); + + QSharedPointer socket(EnvHolder::create()); + DatagramHandlerImpl::cPort = receiver.localPort(); + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + + QJsonObject obj; + obj["test"] = "dummy"; + QJsonDocument doc; + doc.setObject(obj); + if (broadcast) + { + #ifdef Q_OS_FREEBSD + QSKIP("FreeBSD does not like that"); + #endif + QVERIFY(socket->send(doc)); + } + else + { + QVERIFY(socket->send(doc, QHostAddress::LocalHost)); + } + + spyReceiver.wait(); + + QCOMPARE(spyReceiver.count(), 1); + QCOMPARE(spy.count(), 0); + + QVERIFY(receiver.hasPendingDatagrams()); + QByteArray msg; + msg.resize(static_cast(receiver.pendingDatagramSize())); + receiver.readDatagram(msg.data(), msg.size()); + QCOMPARE(msg, QByteArray("{\"test\":\"dummy\"}")); + } + + +}; + +QTEST_GUILESS_MAIN(test_DatagramHandlerImpl) +#include "test_DatagramHandlerImpl.moc" diff --git a/test/qt/network/test_HttpRequest.cpp b/test/qt/network/test_HttpRequest.cpp new file mode 100644 index 0000000..e6793d1 --- /dev/null +++ b/test/qt/network/test_HttpRequest.cpp @@ -0,0 +1,92 @@ +/*! + * \brief Unit tests for \ref HttpResponse + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpRequest.h" + +#include "MockSocket.h" + +#include + +using namespace governikus; + + +class test_HttpRequest + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void parseEmptyBody() + { + MockSocket* socket = new MockSocket; + socket->mReadBuffer = QByteArray("GET /favicon.ico HTTP/1.1\r\n" + "Host: Dummy.de\r\n" + "\r\n\r\n"); + + HttpRequest request(socket); + QVERIFY(!request.isUpgrade()); + QCOMPARE(request.getMethod(), QByteArray("GET")); + QCOMPARE(request.getHeader().size(), 1); + QCOMPARE(request.getHeader("host"), QByteArray("Dummy.de")); + QCOMPARE(request.getUrl(), QUrl("/favicon.ico")); + QCOMPARE(request.getBody().size(), 0); + } + + + void isUpgrade() + { + MockSocket* socket = new MockSocket; + socket->mReadBuffer = QByteArray("GET / HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: chat, superchat\r\n" + "Sec-WebSocket-Version: 13\r\n" + "\r\n\r\n"); + + HttpRequest request(socket); + QVERIFY(request.isUpgrade()); + QCOMPARE(request.getMethod(), QByteArray("GET")); + QCOMPARE(request.getHeader().size(), 7); + QCOMPARE(request.getHeader("host"), QByteArray("server.example.com")); + QCOMPARE(request.getHeader("upgrade"), QByteArray("websocket")); + QCOMPARE(request.getHeader("connection"), QByteArray("Upgrade")); + QCOMPARE(request.getUrl(), QUrl("/")); + QCOMPARE(request.getBody().size(), 0); + } + + + void tcTokenURL() + { + MockSocket* socket = new MockSocket; + socket->mReadBuffer = QByteArray("GET /eID-Client?tcTokenURL=https%3A%2F%2Ftest.governikus-eid.de%3A443%2FAutent-DemoApplication%2FRequestServlet%3Fprovider%3Ddemo_epa_20%26redirect%3Dtrue HTTP/1.1\r\n" + "Host: 127.0.0.1:24727\r\n" + "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: de-DE,de;q=0.8,en-US;q=0.5,en;q=0.3\r\n" + "Accept-Encoding: gzip, deflate\r\n" + "Cookie: csrftoken=4LcbL9banTtJjpsDRc9du7M4u1rPJZhY; rbsessionid=nevw98w871u0p5ed8cvwfk5yyqh19dh6\r\n" + "DNT: 1\r\n" + "Connection: keep-alive\r\n" + "Upgrade-Insecure-Requests: 1\r\n" + "\r\n\r\n"); + + HttpRequest request(socket); + QVERIFY(!request.isUpgrade()); + QCOMPARE(request.getMethod(), QByteArray("GET")); + QCOMPARE(request.getHeader().size(), 9); + QCOMPARE(request.getHeader("host"), QByteArray("127.0.0.1:24727")); + QCOMPARE(request.getUrl(), QUrl("/eID-Client?tcTokenURL=https%3A%2F%2Ftest.governikus-eid.de%3A443%2FAutent-DemoApplication%2FRequestServlet%3Fprovider%3Ddemo_epa_20%26redirect%3Dtrue")); + QCOMPARE(request.getBody().size(), 0); + } + + +}; + +QTEST_GUILESS_MAIN(test_HttpRequest) +#include "test_HttpRequest.moc" diff --git a/test/qt/network/test_HttpResponse.cpp b/test/qt/network/test_HttpResponse.cpp new file mode 100644 index 0000000..1b154eb --- /dev/null +++ b/test/qt/network/test_HttpResponse.cpp @@ -0,0 +1,104 @@ +/*! + * \brief Unit tests for \ref HttpResponse + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpResponse.h" + +#include "MockSocket.h" + +#include + +using namespace governikus; + + +class test_HttpResponse + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void init() + { + QCoreApplication::setApplicationVersion("1.2"); + } + + + void someHeader() + { + HttpResponse response; + response.setStatus(HttpStatusCode::NON_AUTHORITATIVE_INFORMATION); + const auto& msg = response.getMessage(); + + QVERIFY(msg.contains("HTTP/1.0 203 NON AUTHORITATIVE INFORMATION")); + QVERIFY(msg.contains("Content-Length: 0")); + QVERIFY(msg.contains("Date: ")); + QVERIFY(msg.contains("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.2)")); + QCOMPARE(msg.size(), 158); + } + + + void body() + { + HttpResponse response; + response.setStatus(HttpStatusCode::OK); + response.setBody(QByteArray("this is dummy content"), QByteArray("text/plain")); + const auto& msg = response.getMessage(); + + QVERIFY(msg.contains("HTTP/1.0 200 OK")); + QVERIFY(msg.contains("Content-Length: 21")); + QVERIFY(msg.contains("Content-Type: text/plain")); + QVERIFY(msg.contains("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.2)")); + QVERIFY(msg.contains("\r\n\r\nthis is dummy content")); + } + + + void valid() + { + HttpResponse response; + QVERIFY(!response.isValid()); + response.setBody("dummy"); + QVERIFY(!response.isValid()); + response.setStatus(HttpStatusCode::OK); + QVERIFY(response.isValid()); + } + + + void ctorNoBody() + { + HttpResponse response(HttpStatusCode::OK); + QVERIFY(response.isValid()); + QCOMPARE(response.getStatus(), HttpStatusCode::OK); + QVERIFY(response.getBody().isEmpty()); + QCOMPARE(response.getHeader("Content-Length"), QByteArray("0")); + QVERIFY(response.getHeader("Content-Type").isEmpty()); + } + + + void ctorNoContentType() + { + HttpResponse response(HttpStatusCode::OK, "hello"); + QVERIFY(response.isValid()); + QCOMPARE(response.getStatus(), HttpStatusCode::OK); + QCOMPARE(response.getBody(), QByteArray("hello")); + QCOMPARE(response.getHeader("Content-Length"), QByteArray("5")); + QVERIFY(response.getHeader("Content-Type").isEmpty()); + } + + + void ctor() + { + HttpResponse response(HttpStatusCode::OK, "hello", "text/plain"); + QVERIFY(response.isValid()); + QCOMPARE(response.getStatus(), HttpStatusCode::OK); + QCOMPARE(response.getBody(), QByteArray("hello")); + QCOMPARE(response.getHeader("Content-Length"), QByteArray("5")); + QCOMPARE(response.getHeader("Content-Type"), QByteArray("text/plain")); + } + + +}; + +QTEST_GUILESS_MAIN(test_HttpResponse) +#include "test_HttpResponse.moc" diff --git a/test/qt/network/test_HttpServer.cpp b/test/qt/network/test_HttpServer.cpp new file mode 100644 index 0000000..cad1a5f --- /dev/null +++ b/test/qt/network/test_HttpServer.cpp @@ -0,0 +1,163 @@ +/*! + * \brief Unit tests for \ref HttpResponse + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "HttpServer.h" + +#include "EnvHolder.h" +#include "LogHandler.h" +#include "MockSocket.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + + +class test_HttpServer + : public QObject +{ + Q_OBJECT + + private: + QNetworkAccessManager mAccessManager; + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void init() + { + HttpServer::cPort = 0; + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void startUpShutDown() + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + auto server = EnvHolder::shared(); + + QVERIFY(server->isListening()); + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Listening on port:")); + + server.reset(); + QCOMPARE(spy.count(), 1); + param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Shutdown server")); + } + + + void cannotStart() + { + #ifdef Q_OS_WIN + QSKIP("Windows does not block privileged ports"); + #endif + + HttpServer::cPort = 80; + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + HttpServer server; + + QVERIFY(!server.isListening()); + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + QVERIFY(param.at(0).toString().contains("Cannot start server: \"The address is protected\"")); + } + + + void sendRequest() + { + HttpServer server; + QVERIFY(server.isListening()); + QSignalSpy spyServer(&server, &HttpServer::fireNewHttpRequest); + + auto url = QUrl("http://localhost:" + QString::number(server.getServerPort()) + "/eID-Client?tcTokenURL=https%3A%2F%2Fdummy.de"); + auto reply = mAccessManager.get(QNetworkRequest(url)); + QSignalSpy spyClient(reply, &QNetworkReply::finished); + + spyServer.wait(); + QCOMPARE(spyServer.count(), 1); + auto param = spyServer.takeFirst(); + auto httpRequest = qvariant_cast >(param.at(0)); + QCOMPARE(httpRequest->getMethod(), QByteArray("GET")); + QCOMPARE(httpRequest->getUrl(), QUrl("/eID-Client?tcTokenURL=https%3A%2F%2Fdummy.de")); + + QVERIFY(httpRequest->send(HttpStatusCode::NOT_FOUND)); + + spyClient.wait(); + QCOMPARE(spyClient.count(), 1); + QCOMPARE(reply->error(), QNetworkReply::ContentNotFoundError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 404); + } + + + void websocketUpgrade() + { + HttpServer server; + QVERIFY(server.isListening()); + QSignalSpy spyServer(&server, &HttpServer::fireNewWebSocketRequest); + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.getServerPort()))); + request.setRawHeader("upgrade", "websocket"); + request.setRawHeader("connection", "upgrade"); + mAccessManager.get(request); + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + spyServer.wait(); + QCOMPARE(spyServer.count(), 1); + auto param = spyServer.takeFirst(); + auto socket = qvariant_cast >(param.at(0)); + QVERIFY(socket->bytesAvailable() > 0); // check rollbackTransaction + const auto& requestData = socket->readAll(); + QVERIFY(requestData.contains("GET / HTTP/1.1")); + QVERIFY(requestData.contains("connection: upgrade")); + QVERIFY(requestData.contains("upgrade: websocket")); + QVERIFY(requestData.contains("\r\n\r\n")); + + param = spy.takeLast(); + QVERIFY(param.at(0).toString().contains("Upgrade to websocket requested")); + } + + + void unknownUpgrade() + { + HttpServer server; + QVERIFY(server.isListening()); + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.getServerPort()))); + request.setRawHeader("upgrade", "unknown"); + request.setRawHeader("connection", "upgrade"); + auto reply = mAccessManager.get(request); + QSignalSpy spyClient(reply, &QNetworkReply::finished); + + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + spyClient.wait(); + QCOMPARE(spyClient.count(), 1); + QCOMPARE(reply->error(), QNetworkReply::ContentNotFoundError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 404); + + auto param = spy.takeLast(); + QVERIFY(param.at(0).toString().contains("Unknown upgrade requested")); + } + + +}; + +QTEST_GUILESS_MAIN(test_HttpServer) +#include "test_HttpServer.moc" diff --git a/test/qt/network/test_NetworkManager.cpp b/test/qt/network/test_NetworkManager.cpp index 98bc83f..6262943 100644 --- a/test/qt/network/test_NetworkManager.cpp +++ b/test/qt/network/test_NetworkManager.cpp @@ -1,5 +1,5 @@ /*! - * \brief Unit tests for \ref test_NetworkManager + * \brief Unit tests for \ref NetworkManager * * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ @@ -34,29 +34,6 @@ class test_NetworkManager } - void setProxy() - { - QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - - NetworkManager::getGlobalInstance().setProxy(QNetworkProxy::NoProxy); - - QNetworkProxyQuery query; - QCOMPARE(QNetworkProxyFactory::proxyForQuery(query).size(), 1); - - QCOMPARE(spy.count(), 3); - auto param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("proxy -> none")); - spy.clear(); - - NetworkManager::getGlobalInstance().setProxy(QNetworkProxy::DefaultProxy); - QCOMPARE(QNetworkProxyFactory::proxyForQuery(query).size(), 1); - - QCOMPARE(spy.count(), 3); - param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("proxy -> system")); - } - - void paosRequestAttached() { QNetworkRequest request(QUrl("https://dummy")); diff --git a/test/qt/network/test_TlsConfiguration.cpp b/test/qt/network/test_TlsConfiguration.cpp index 5741570..5351821 100644 --- a/test/qt/network/test_TlsConfiguration.cpp +++ b/test/qt/network/test_TlsConfiguration.cpp @@ -4,9 +4,11 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ -#include "AppSettings.h" #include "TlsConfiguration.h" +#include "AppSettings.h" +#include "MockNetworkReply.h" + #include @@ -24,23 +26,18 @@ class test_TlsConfiguration } - void createSslConfiguration() - { - QSslConfiguration config = TlsConfiguration::createSslConfiguration(); - QCOMPARE(config.ciphers().size(), 24); - } - - void containsFatalError() { + MockNetworkReply reply; QList errors; - QVERIFY(!TlsConfiguration::containsFatalError(errors)); + + QVERIFY(!TlsConfiguration::containsFatalError(&reply, errors)); errors.append(QSslError(QSslError::SslError::SelfSignedCertificate)); - QVERIFY(!TlsConfiguration::containsFatalError(errors)); + QVERIFY(!TlsConfiguration::containsFatalError(&reply, errors)); errors.append(QSslError(QSslError::SslError::SubjectIssuerMismatch)); - QVERIFY(TlsConfiguration::containsFatalError(errors)); + QVERIFY(TlsConfiguration::containsFatalError(&reply, errors)); } diff --git a/test/qt/pcsc/test_pcscReaderFeature.cpp b/test/qt/pcsc/test_pcscReaderFeature.cpp index 37d8ecf..c30dc71 100644 --- a/test/qt/pcsc/test_pcscReaderFeature.cpp +++ b/test/qt/pcsc/test_pcscReaderFeature.cpp @@ -26,19 +26,19 @@ class test_pcscReaderFeature void featuresCyberjackBasis() { QByteArray featuresTLV = QByteArray::fromHex("120442330012"); - PcscReaderFeature readerFeature(featuresTLV.constData(), featuresTLV.length()); + PcscReaderFeature readerFeature(featuresTLV.constData(), static_cast(featuresTLV.length())); QCOMPARE(readerFeature.toString(), QString("[TLV_PROPERTIES]")); QCOMPARE(readerFeature.getFeatures().size(), 1); QVERIFY(readerFeature.getFeatures().contains(FeatureID::TLV_PROPERTIES)); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::TLV_PROPERTIES), 1110638610); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::TLV_PROPERTIES), PCSC_INT(1110638610)); } void featuresCyberjackStandard() { QByteArray featuresTLV = QByteArray::fromHex("060442000db2070442000db3080442000db4090442000db5200442000dcc"); - PcscReaderFeature readerFeature(featuresTLV.constData(), featuresTLV.length()); + PcscReaderFeature readerFeature(featuresTLV.constData(), static_cast(featuresTLV.length())); QCOMPARE(readerFeature.toString(), QString("[VERIFY_PIN_DIRECT MODIFY_PIN_DIRECT MCT_READERDIRECT MCT_UNIVERSAL EXECUTE_PACE]")); QCOMPARE(readerFeature.getFeatures().size(), 5); @@ -48,11 +48,11 @@ class test_pcscReaderFeature QVERIFY(readerFeature.getFeatures().contains(FeatureID::MCT_UNIVERSAL)); QVERIFY(readerFeature.getFeatures().contains(FeatureID::EXECUTE_PACE)); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::VERIFY_PIN_DIRECT), 1107299762); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::MODIFY_PIN_DIRECT), 1107299763); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::MCT_READERDIRECT), 1107299764); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::MCT_UNIVERSAL), 1107299765); - QCOMPARE(readerFeature.getFeatures().value(FeatureID::EXECUTE_PACE), 1107299788); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::VERIFY_PIN_DIRECT), PCSC_INT(1107299762)); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::MODIFY_PIN_DIRECT), PCSC_INT(1107299763)); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::MCT_READERDIRECT), PCSC_INT(1107299764)); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::MCT_UNIVERSAL), PCSC_INT(1107299765)); + QCOMPARE(readerFeature.getFeatures().value(FeatureID::EXECUTE_PACE), PCSC_INT(1107299788)); } @@ -67,7 +67,7 @@ class test_pcscReaderFeature void capabilitiesCyberjackStandard() { QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010060"); - PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), capabilitiesTLV.length()); + PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), static_cast(capabilitiesTLV.length())); QCOMPARE(paceCapa.toString(), QString("[EID GENERIC]")); QCOMPARE(paceCapa.getPaceCapabilities().size(), 2); QVERIFY(paceCapa.getPaceCapabilities().contains(PaceCapabilityId::EID)); @@ -78,7 +78,7 @@ class test_pcscReaderFeature void capabilitiesCyberjackKomfort() { QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010070"); - PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), capabilitiesTLV.length()); + PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), static_cast(capabilitiesTLV.length())); QCOMPARE(paceCapa.toString(), QString("[ESIGN EID GENERIC]")); QCOMPARE(paceCapa.getPaceCapabilities().size(), 3); QVERIFY(paceCapa.getPaceCapabilities().contains(PaceCapabilityId::EID)); diff --git a/test/qt/qml/test_ProviderModel.cpp b/test/qt/qml/test_ProviderModel.cpp new file mode 100644 index 0000000..284eae2 --- /dev/null +++ b/test/qt/qml/test_ProviderModel.cpp @@ -0,0 +1,74 @@ +/*! + * \brief Unit tests for \ref ProviderModel + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "ProviderModel.h" + +#include +#include + + +using namespace governikus; + + +class test_ProviderModel + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void createAmountStringForCents() + { + QVERIFY(ProviderModel::createAmountString(3.9).contains(QString("3.9"))); + } + + + void createAmountStringForEur() + { + QVERIFY(ProviderModel::createAmountString(289).contains(QString("2.89"))); + } + + + void createCostStringMinute() + { + const auto& msg = ProviderModel::createCostString(1.9, 2.9); + QVERIFY(msg.contains(QString("1.9"))); + QVERIFY(!msg.contains(QString("2.9"))); + } + + + void createCostStringCall() + { + const auto& msg = ProviderModel::createCostString(0.0, 2.9); + QVERIFY(!msg.contains(QString("0.0"))); + QVERIFY(msg.contains(QString("2.9"))); + } + + + void createCostStringEmpty() + { + const auto& msg = ProviderModel::createCostString(0.0, 0.0); + QVERIFY(msg.isEmpty()); + } + + + void createCostStringNullCost() + { + const auto& msg = ProviderModel::createCostString(CallCost()); + QVERIFY(msg.isNull()); + } + + + void createCostString() + { + const auto& msg = ProviderModel::createCostString(CallCost(0.0, 3.9, 0.0, 42.0, 0.0)); + QVERIFY(!msg.isNull()); + } + + +}; + +QTEST_GUILESS_MAIN(test_ProviderModel) +#include "test_ProviderModel.moc" diff --git a/test/qt/remote/test_notificationHandler.cpp b/test/qt/remote/test_notificationHandler.cpp new file mode 100644 index 0000000..ae1759d --- /dev/null +++ b/test/qt/remote/test_notificationHandler.cpp @@ -0,0 +1,182 @@ +/*! + * \brief Unit tests for \ref NotificationParser + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ +#include "NotificationHandler.h" + +#include "MockDataChannel.h" +#include "RemoteCardNotificationChecker.h" + +#include +#include + +using namespace governikus; + + +class NotificationHandlerSpy + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mNotificationHandler; + bool mClosed; + GlobalStatus::Code mCloseCode; + QVector > mReceivedNotifications; + + public: + NotificationHandlerSpy(const QSharedPointer pNotificationHandler); + virtual ~NotificationHandlerSpy(); + + bool isClosed() const; + GlobalStatus::Code getCloseCode() const; + const QVector >& getReceivedNotifications() const; + + private Q_SLOTS: + void onClosed(GlobalStatus::Code pCloseCode); + void onReceived(const QSharedPointer& pNotification); +}; + + +NotificationHandlerSpy::NotificationHandlerSpy(const QSharedPointer pNotificationHandler) + : mNotificationHandler(pNotificationHandler) + , mClosed(false) + , mCloseCode(GlobalStatus::Code::RemoteReader_CloseCode_Undefined) +{ + connect(mNotificationHandler.data(), &NotificationHandler::fireClosed, this, &NotificationHandlerSpy::onClosed); + connect(mNotificationHandler.data(), &NotificationHandler::fireReceived, this, &NotificationHandlerSpy::onReceived); +} + + +NotificationHandlerSpy::~NotificationHandlerSpy() +{ + disconnect(mNotificationHandler.data(), &NotificationHandler::fireClosed, this, &NotificationHandlerSpy::onClosed); + disconnect(mNotificationHandler.data(), &NotificationHandler::fireReceived, this, &NotificationHandlerSpy::onReceived); +} + + +bool NotificationHandlerSpy::isClosed() const +{ + return mClosed; +} + + +GlobalStatus::Code NotificationHandlerSpy::getCloseCode() const +{ + return mCloseCode; +} + + +const QVector >& NotificationHandlerSpy::getReceivedNotifications() const +{ + return mReceivedNotifications; +} + + +void NotificationHandlerSpy::onClosed(GlobalStatus::Code pCloseCode) +{ + mClosed = true; + mCloseCode = pCloseCode; +} + + +void NotificationHandlerSpy::onReceived(const QSharedPointer& pNotification) +{ + mReceivedNotifications += pNotification; +} + + +class test_notificationHandler + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mChecker; + + private Q_SLOTS: + void channelClosedNormally() + { + const QSharedPointer channel(new MockDataChannel()); + const QSharedPointer handler(new NotificationHandler(channel)); + NotificationHandlerSpy spy(handler); + + channel->close(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); + } + + + void channelClosedAbnormally() + { + const QSharedPointer channel(new MockDataChannel()); + const QSharedPointer handler(new NotificationHandler(channel)); + NotificationHandlerSpy spy(handler); + + channel->closeAbnormal(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); + } + + + void notificationsAreDelivered() + { + const QSharedPointer clientChannel(new MockDataChannel()); + const QSharedPointer clientHandler(new NotificationHandler(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverHandler(new NotificationHandler(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + + NotificationHandlerSpy spy(serverHandler); + + clientHandler->send(QSharedPointer(new ConnectCmd(QStringLiteral("NFC Reader")))); + clientHandler->send(QSharedPointer(new TransmitCmd(QStringLiteral("NFC Reader"), QByteArray::fromHex("00A402022F00")))); + clientHandler->send(QSharedPointer(new DisconnectCmd(QStringLiteral("NFC Reader")))); + + const QVector > receivedNotifications = spy.getReceivedNotifications(); + QCOMPARE(receivedNotifications.size(), 3); + QCOMPARE(receivedNotifications.at(0)->getType(), CardNotificationType::CONNECT); + receivedNotifications.at(0)->accept(mChecker); + + QCOMPARE(receivedNotifications.at(1)->getType(), CardNotificationType::TRANSMIT); + receivedNotifications.at(1)->accept(mChecker); + + QCOMPARE(receivedNotifications.at(2)->getType(), CardNotificationType::DISCONNECT); + receivedNotifications.at(2)->accept(mChecker); + } + + + void channelIsClosedWhenNotificationHandlerIsDestroyed() + { + const QSharedPointer clientChannel(new MockDataChannel()); + QSharedPointer clientHandler(new NotificationHandler(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverHandler(new NotificationHandler(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + connect(clientChannel.data(), &DataChannel::fireClosed, serverChannel.data(), &DataChannel::close, Qt::DirectConnection); + + NotificationHandlerSpy spy(serverHandler); + QVERIFY(!spy.isClosed()); + // Destroying a notification handler should close the underlying channel. + clientHandler.reset(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); + } + + + public: + test_notificationHandler() + : mChecker(new RemoteCardNotificationChecker()) + { + } + + +}; + +QTEST_GUILESS_MAIN(test_notificationHandler) +#include "test_notificationHandler.moc" diff --git a/test/qt/remote/test_notificationParser.cpp b/test/qt/remote/test_notificationParser.cpp new file mode 100644 index 0000000..9d6751b --- /dev/null +++ b/test/qt/remote/test_notificationParser.cpp @@ -0,0 +1,190 @@ +/*! + * \brief Unit tests for \ref NotificationParser + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ +#include "NotificationParser.h" + +#include "RemoteCardNotificationChecker.h" + +#include +#include + +using namespace governikus; + +class test_notificationParser + : public QObject +{ + Q_OBJECT + + private: + const NotificationParser mParser; + + const QSharedPointer mChecker; + + void parseAndVerify(const char* pJsonByteData) + { + const QByteArray jsonData(pJsonByteData); + const QSharedPointer notification = mParser.parse(jsonData); + + QVERIFY(!notification.isNull()); + notification->accept(mChecker); + } + + + private Q_SLOTS: + void invalidJsonInput() + { + const QByteArray jsonData("bla bla"); + const QSharedPointer notification = mParser.parse(jsonData); + + QVERIFY(notification.isNull()); + } + + + void remoteReaderDiscoverCmd() + { + parseAndVerify("{\n\"cmd\": \"REMOTE_READER_DISCOVER\"\n}"); + } + + + void remoteReaderOfferMsg() + { + parseAndVerify("{\n" + " \"msg\": \"REMOTE_READER_OFFER\",\n" + " \"deviceName\": \"Sony Xperia Z5 compact\",\n" + " \"encrypted\": true,\n" + " \"port\": 24728,\n" + " \"availableApiLevels\": [1, 2, 3, 4]\n" + "}"); + } + + + void getApiLevelCmd() + { + parseAndVerify("{\n\"cmd\": \"GET_API_LEVEL\"\n}"); + } + + + void setApiLevelCmd() + { + parseAndVerify("{\n" + " \"cmd\": \"SET_API_LEVEL\",\n" + " \"level\": 1\n" + "}"); + } + + + void apiLevelMsg() + { + parseAndVerify("{\n" + " \"msg\": \"API_LEVEL\",\n" + " \"error\": \"No error\",\n" + " \"available\": [1, 2, 3, 4],\n" + " \"current\": 2\n" + "}"); + } + + + void getReaderListCmd() + { + parseAndVerify("{\n \"cmd\": \"GET_READER_LIST\" }"); + } + + + void readerListMsg() + { + parseAndVerify("{\n" + " \"msg\": \"READER_LIST\",\n" + " \"readers\": [\n" + " {\n" + " \"name\": \"NFC Reader\",\n" + " \"attached\": true,\n" + " \"extendedLength\": \"SUPPORTED\",\n" + " \"card\": {\n" + " \"EFCardAccess\": \"3181C10000\",\n" + " \"retryCounter\": 3,\n" + " \"pinDeactivated\": false,\n" + " \"connected\": false\n" + " }\n" + " }\n" + " ]\n" + "}"); + } + + + void readerMsg() + { + parseAndVerify("{\n" + " \"msg\": \"READER\",\n" + " \"reader\": {\n" + " \"name\": \"NFC Reader\",\n" + " \"attached\": false,\n" + " \"extendedLength\": \"SUPPORTED\",\n" + " \"card\": null\n" + " },\n" + " \"error\": \"Optional error message\"\n" + "}"); + } + + + void connectCmd() + { + parseAndVerify("{\n" + " \"cmd\": \"CONNECT\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}"); + } + + + void disconnectCmd() + { + parseAndVerify("{\n" + " \"cmd\": \"DISCONNECT\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}"); + } + + + void transmitCmd() + { + parseAndVerify("{\n" + " \"cmd\": \"TRANSMIT\",\n" + " \"readerName\": \"NFC Reader\",\n" + " \"commandApdu\": \"00A402022F00\"\n" + "}"); + } + + + void transmitResponseMsg() + { + parseAndVerify("{\n" + " \"msg\": \"TRANSMIT_RESPONSE\",\n" + " \"readerName\": \"NFC Reader\",\n" + " \"error\": \"Optional error message\",\n" + " \"responseApdu\": \"9000\"\n" + "}"); + } + + + void unsupportedMsg() + { + parseAndVerify("{\n" + " \"msg\": \"UNSUPPORTED\",\n" + " \"error\": \"Invalid command\"\n" + "}"); + } + + + public: + test_notificationParser() + : mParser() + , mChecker(new RemoteCardNotificationChecker()) + { + } + + +}; + +QTEST_GUILESS_MAIN(test_notificationParser) +#include "test_notificationParser.moc" diff --git a/test/qt/remote/test_remoteCardNotifications.cpp b/test/qt/remote/test_remoteCardNotifications.cpp new file mode 100644 index 0000000..60bb045 --- /dev/null +++ b/test/qt/remote/test_remoteCardNotifications.cpp @@ -0,0 +1,422 @@ +/*! + * \brief Unit tests for \ref RemoteCardNotifications + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ +#include "RemoteCardNotifications.h" + +#include "RemoteCardNotificationChecker.h" + +#include +#include + +using namespace governikus; + +class test_remoteCardNotifications + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mChecker; + + private Q_SLOTS: + void remoteReaderDiscoverCmd() + { + const RemoteReaderDiscoverCmd notification; + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + const QJsonObject& object = document.object(); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("REMOTE_READER_DISCOVER")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"REMOTE_READER_DISCOVER\"\n" + "}\n")); + } + + + void remoteReaderOfferMsg() + { + const RemoteReaderOfferMsg notification(QStringLiteral("Sony Xperia Z5 compact"), + true, + 24728, + QVector({1, 2, 3, 4})); + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("REMOTE_READER_OFFER")); + QCOMPARE(object.value(QLatin1String("deviceName")).toString(), QStringLiteral("Sony Xperia Z5 compact")); + QVERIFY(object.value(QLatin1String("encrypted")).toBool()); + QCOMPARE(object.value(QLatin1String("port")).toInt(), 24728); + const QJsonValue apiLevels = object.value(QLatin1String("availableApiLevels")); + QVERIFY(apiLevels.isArray()); + QCOMPARE(apiLevels.toArray().size(), 4); + QCOMPARE(apiLevels.toArray().at(0).toInt(), 1); + QCOMPARE(apiLevels.toArray().at(1).toInt(), 2); + QCOMPARE(apiLevels.toArray().at(2).toInt(), 3); + QCOMPARE(apiLevels.toArray().at(3).toInt(), 4); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"availableApiLevels\": [\n" + " 1,\n" + " 2,\n" + " 3,\n" + " 4\n" + " ],\n" + " \"deviceName\": \"Sony Xperia Z5 compact\",\n" + " \"encrypted\": true,\n" + " \"msg\": \"REMOTE_READER_OFFER\",\n" + " \"port\": 24728\n" + "}\n")); + } + + + void getApiLevelCmd() + { + const GetApiLevelCmd notification; + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("GET_API_LEVEL")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"GET_API_LEVEL\"\n" + "}\n")); + } + + + void setApiLevelCmd() + { + const SetApiLevelCmd notification(1); + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("SET_API_LEVEL")); + QCOMPARE(object.value(QLatin1String("level")).toInt(), 1); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"SET_API_LEVEL\",\n" + " \"level\": 1\n" + "}\n")); + } + + + void apiLevelMsg() + { + const ApiLevelMsg notification(QStringLiteral("No error"), QVector({1, 2, 3, 4}), 2); + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 4); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("API_LEVEL")); + QCOMPARE(object.value(QLatin1String("error")).toString(), QStringLiteral("No error")); + const QJsonValue apiLevels = object.value(QLatin1String("available")); + QVERIFY(apiLevels.isArray()); + QCOMPARE(apiLevels.toArray().size(), 4); + QCOMPARE(apiLevels.toArray().at(0).toInt(), 1); + QCOMPARE(apiLevels.toArray().at(1).toInt(), 2); + QCOMPARE(apiLevels.toArray().at(2).toInt(), 3); + QCOMPARE(apiLevels.toArray().at(3).toInt(), 4); + + QCOMPARE(object.value(QLatin1String("current")).toInt(), 2); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"available\": [\n" + " 1,\n" + " 2,\n" + " 3,\n" + " 4\n" + " ],\n" + " \"current\": 2,\n" + " \"error\": \"No error\",\n" + " \"msg\": \"API_LEVEL\"\n" + "}\n")); + } + + + void getReaderListCmd() + { + GetReaderListCmd notification; + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("GET_READER_LIST")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"GET_READER_LIST\"\n" + "}\n")); + } + + + void readerListMsg() + { + const ReaderListMsg notification(QVector({ + ReaderDescription(QStringLiteral("NFC Reader"), + true /* attached */, + ExtendedLengthApduSupportCode::SUPPORTED, + CardDescription(QByteArray::fromHex("3181C10000"), + 3, + false /* pinDeactivated */, + false /* connected */)) + })); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("READER_LIST")); + + const QJsonValue jsonReaders = object.value(QLatin1String("readers")); + QVERIFY(jsonReaders.isArray()); + QCOMPARE(jsonReaders.toArray().size(), 1); + + const QJsonValue jsonReader = jsonReaders.toArray().at(0); + QVERIFY(jsonReader.isObject()); + const QJsonObject readerObject = jsonReader.toObject(); + + QCOMPARE(readerObject.value(QLatin1String("name")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(readerObject.value(QLatin1String("attached")).toBool(), true); + QCOMPARE(readerObject.value(QLatin1String("extendedLength")).toString(), QStringLiteral("SUPPORTED")); + + const QJsonValue jsonCard = readerObject.value(QLatin1String("card")); + QVERIFY(jsonCard.isObject()); + const QJsonObject cardObject = jsonCard.toObject(); + + QCOMPARE(cardObject.value(QLatin1String("EFCardAccess")).toString().toUpper(), QStringLiteral("3181C10000")); + QCOMPARE(cardObject.value(QLatin1String("retryCounter")).toInt(), 3); + QVERIFY(!cardObject.value(QLatin1String("pinDeactivated")).toBool(true)); + QVERIFY(!cardObject.value(QLatin1String("connected")).toBool(true)); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"msg\": \"READER_LIST\",\n" + " \"readers\": [\n" + " {\n" + " \"attached\": true,\n" + " \"card\": {\n" + " \"EFCardAccess\": \"3181c10000\",\n" + " \"connected\": false,\n" + " \"pinDeactivated\": false,\n" + " \"retryCounter\": 3\n" + " },\n" + " \"extendedLength\": \"SUPPORTED\",\n" + " \"name\": \"NFC Reader\"\n" + " }\n" + " ]\n" + "}\n")); + } + + + void readerMsg() + { + const ReaderMsg notification(ReaderDescription(QStringLiteral("NFC Reader"), + false /* attached */, + ExtendedLengthApduSupportCode::SUPPORTED, + CardDescription()), + QStringLiteral("Optional error message")); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("READER")); + + const QJsonValue jsonReader = object.value(QLatin1String("reader")); + QVERIFY(jsonReader.isObject()); + const QJsonObject readerObject = jsonReader.toObject(); + QCOMPARE(readerObject.size(), 4); + QCOMPARE(readerObject.value(QLatin1String("name")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(readerObject.value(QLatin1String("attached")).toBool(true), false); + QCOMPARE(readerObject.value(QLatin1String("extendedLength")).toString(), QStringLiteral("SUPPORTED")); + + // No card is represented by null. + QVERIFY(readerObject.value(QLatin1String("card")).isNull()); + + QCOMPARE(object.value(QLatin1String("error")).toString(), QStringLiteral("Optional error message")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"error\": \"Optional error message\",\n" + " \"msg\": \"READER\",\n" + " \"reader\": {\n" + " \"attached\": false,\n" + " \"card\": null,\n" + " \"extendedLength\": \"SUPPORTED\",\n" + " \"name\": \"NFC Reader\"\n" + " }\n" + "}\n")); + } + + + void connectCmd() + { + const ConnectCmd notification(QStringLiteral("NFC Reader")); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("CONNECT")); + QCOMPARE(object.value(QLatin1String("readerName")).toString(), QStringLiteral("NFC Reader")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"CONNECT\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}\n")); + } + + + void disconnectCmd() + { + const DisconnectCmd notification(QStringLiteral("NFC Reader")); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("DISCONNECT")); + QCOMPARE(object.value(QLatin1String("readerName")).toString(), QStringLiteral("NFC Reader")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"DISCONNECT\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}\n")); + } + + + void transmitCmd() + { + const TransmitCmd notification(QStringLiteral("NFC Reader"), QByteArray::fromHex("00A402022F00")); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("cmd")).toString(), QStringLiteral("TRANSMIT")); + QCOMPARE(object.value(QLatin1String("readerName")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("commandApdu")).toString().toUpper(), QStringLiteral("00A402022F00")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"cmd\": \"TRANSMIT\",\n" + " \"commandApdu\": \"00a402022f00\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}\n")); + } + + + void transmitResponseMsg() + { + const TransmitResponseMsg notification(QStringLiteral("NFC Reader"), + QStringLiteral("Optional error message"), + QByteArray::fromHex("9000")); + + notification.accept(mChecker); + + // Json + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 4); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("TRANSMIT_RESPONSE")); + QCOMPARE(object.value(QLatin1String("readerName")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("error")).toString(), QStringLiteral("Optional error message")); + QCOMPARE(object.value(QLatin1String("responseApdu")).toString().toUpper(), QStringLiteral("9000")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"error\": \"Optional error message\",\n" + " \"msg\": \"TRANSMIT_RESPONSE\",\n" + " \"readerName\": \"NFC Reader\",\n" + " \"responseApdu\": \"9000\"\n" + "}\n")); + } + + + void unsupportedMsg() + { + const UnsupportedMsg notification(QStringLiteral("Invalid command")); + + notification.accept(mChecker); + + const QJsonDocument document = notification.toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("UNSUPPORTED")); + QCOMPARE(object.value(QLatin1String("error")).toString(), QStringLiteral("Invalid command")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"error\": \"Invalid command\",\n" + " \"msg\": \"UNSUPPORTED\"\n" + "}\n")); + } + + + public: + test_remoteCardNotifications() + : mChecker(new RemoteCardNotificationChecker()) + { + } + + +}; + +QTEST_GUILESS_MAIN(test_remoteCardNotifications) +#include "test_remoteCardNotifications.moc" diff --git a/test/qt/services/test_AppService.cpp b/test/qt/services/test_AppService.cpp new file mode 100644 index 0000000..8de5a63 --- /dev/null +++ b/test/qt/services/test_AppService.cpp @@ -0,0 +1,65 @@ +/*! + * \brief Unit tests for \ref AppUpdateService + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "AppUpdateService.h" + +#include "LogHandler.h" +#include "MockHttpServer.h" +#include "TestFileHelper.h" + +#include + +using namespace governikus; + + +class test_AppService + : public QObject +{ + Q_OBJECT + + private: + MockHttpServer mServer; + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void init() + { + mServer.reset(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void notSecureConnection() + { + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + + auto& instance = AppUpdateService::getInstance(); + instance.setUpdateUrl(mServer.getAddress()); + + QSignalSpy spy(&instance, &UpdateService::fireUpdateFinished); + instance.runUpdate(); + spy.wait(); + QCOMPARE(spy.count(), 1); + + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("It wasn't possible to connect to the server: a secure connection could not be established."))); + QVERIFY(!instance.getUpdateData().isValid()); + } + + +}; + +QTEST_GUILESS_MAIN(test_AppService) +#include "test_AppService.moc" diff --git a/test/qt/services/test_ProviderParser.cpp b/test/qt/services/test_ProviderParser.cpp index 7a39c9d..4fb09de 100644 --- a/test/qt/services/test_ProviderParser.cpp +++ b/test/qt/services/test_ProviderParser.cpp @@ -154,6 +154,96 @@ class test_ProviderParser } + void parseTcTokenUrl() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " }," + " {" + " \"tcTokenUrl\": \"https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf\"" + " }" + " ]" + "}"); + + QSharedPointer providerSettings = parser.parse(data); + + QVERIFY(providerSettings); + QVERIFY(providerSettings->getIssueDate().isNull()); + QCOMPARE(providerSettings->getProviders().size(), 2); + + auto provider = providerSettings->getProviders()[0]; + QCOMPARE(provider.getTcTokenUrl(), QString()); + + provider = providerSettings->getProviders()[1]; + QCOMPARE(provider.getTcTokenUrl(), QStringLiteral("https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf")); + } + + + void parseClientUrl() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " }," + " {" + " \"clientUrl\": \"https://www.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeld\"" + " }" + " ]" + "}"); + + QSharedPointer providerSettings = parser.parse(data); + + QVERIFY(providerSettings); + QVERIFY(providerSettings->getIssueDate().isNull()); + QCOMPARE(providerSettings->getProviders().size(), 2); + + auto provider = providerSettings->getProviders()[0]; + QCOMPARE(provider.getTcTokenUrl(), QString()); + + provider = providerSettings->getProviders()[1]; + QCOMPARE(provider.getClientUrl(), QStringLiteral("https://www.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeld")); + } + + + void parseSubjectUrls() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " }," + " {" + " \"subjectUrls\": []" + " }," + " {" + " \"subjectUrls\": [\"https://npa.allianz.de/bla1\"]" + " }," + " {" + " \"subjectUrls\": [\"https://npa.allianz.de/bla1\", \"https://npa.allianz.de/bla2\"]" + " }" + " ]" + "}"); + + QSharedPointer providerSettings = parser.parse(data); + + QVERIFY(providerSettings); + QVERIFY(providerSettings->getIssueDate().isNull()); + QCOMPARE(providerSettings->getProviders().size(), 4); + + auto provider = providerSettings->getProviders()[0]; + QCOMPARE(provider.getSubjectUrls(), QStringList()); + + provider = providerSettings->getProviders()[1]; + QCOMPARE(provider.getSubjectUrls(), QStringList()); + + provider = providerSettings->getProviders()[2]; + QCOMPARE(provider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1")})); + + provider = providerSettings->getProviders()[3]; + QCOMPARE(provider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1"), QStringLiteral("https://npa.allianz.de/bla2")})); + } + + void defaultProviders() { QByteArray data = TestFileHelper::readFile(QCoreApplication::applicationDirPath() + "/default-providers.json"); @@ -166,6 +256,17 @@ class test_ProviderParser } + void parseCallCosts() + { + QByteArray data = TestFileHelper::readFile(QCoreApplication::applicationDirPath() + "/default-providers.json"); + + QSharedPointer providerSettings = parser.parse(data); + + QVERIFY(providerSettings); + QCOMPARE(providerSettings->mCallCosts.size(), 17); + } + + }; QTEST_GUILESS_MAIN(test_ProviderParser) diff --git a/test/qt/settings/test_AppSettings.cpp b/test/qt/settings/test_AppSettings.cpp index eff25e4..dcb28de 100644 --- a/test/qt/settings/test_AppSettings.cpp +++ b/test/qt/settings/test_AppSettings.cpp @@ -56,17 +56,16 @@ class test_AppSettings otherSettings->getProviderSettings().setIssueDate(QDateTime(QDate(1989, 11, 9))); QVERIFY(*settings == *otherSettings); - auto proxyType = settings->getProxySettings().getProxyType() == QNetworkProxy::DefaultProxy ? QNetworkProxy::NoProxy : QNetworkProxy::DefaultProxy; - settings->getProxySettings().setProxyType(proxyType); - QVERIFY(*settings != *otherSettings); - otherSettings->getProxySettings().setProxyType(proxyType); - QVERIFY(*settings == *otherSettings); - settings->getSecureStorage().load(); QVERIFY(*settings != *otherSettings); otherSettings->getSecureStorage().load(); QVERIFY(*settings == *otherSettings); + settings->getRemoteReaderSettings().setServerName(QLatin1String("Google Pixel")); + QVERIFY(*settings != *otherSettings); + otherSettings->getRemoteReaderSettings().setServerName(QLatin1String("Google Pixel")); + QVERIFY(*settings == *otherSettings); + delete otherSettings; } diff --git a/test/qt/settings/test_ProviderSettings.cpp b/test/qt/settings/test_ProviderSettings.cpp index fe9d89b..52b699b 100644 --- a/test/qt/settings/test_ProviderSettings.cpp +++ b/test/qt/settings/test_ProviderSettings.cpp @@ -4,12 +4,12 @@ * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG */ +#include "ProviderSettings.h" + #include #include #include -#include "ProviderSettings.h" - using namespace governikus; @@ -93,6 +93,47 @@ class test_ProviderSettings } + void testProviderUrls() + { + const Provider provider1( + /* short name */ QString(), + /* long name */ QString(), + /* short description */ QString(), + /* long description */ QString(), + /* address */ QStringLiteral("ftp://homepage.com/form"), + /* homepage */ QStringLiteral("ftp://www.homepage.de/bla/bla1") + ); + QCOMPARE(provider1.getAddressDomain(), QStringLiteral("homepage.com")); + QCOMPARE(provider1.getHomepageBase(), QStringLiteral("www.homepage.de")); + + const Provider provider2( + /* short name */ QString(), + /* long name */ QString(), + /* short description */ QString(), + /* long description */ QString(), + /* address */ QStringLiteral("https://homepage.com/form"), + /* homepage */ QStringLiteral("https://www.homepage.de/bla/bla1") + ); + QCOMPARE(provider2.getAddressDomain(), QStringLiteral("homepage.com")); + QCOMPARE(provider2.getHomepageBase(), QStringLiteral("www.homepage.de")); + + const Provider provider3( + /* short name */ QString(), + /* long name */ QString(), + /* short description */ QString(), + /* long description */ QString(), + /* address */ QStringLiteral("homepage.com/form"), + /* homepage */ QStringLiteral("www.homepage.de/bla/bla1") + ); + QCOMPARE(provider3.getAddressDomain(), QStringLiteral("homepage.com")); + QCOMPARE(provider3.getHomepageBase(), QStringLiteral("www.homepage.de")); + + const Provider provider4; + QCOMPARE(provider4.getAddressDomain(), QString()); + QCOMPARE(provider4.getHomepageBase(), QString()); + } + + void testProviderFields() { settings.reset(new ProviderSettings(settings->getIssueDate(), QVector())); @@ -112,7 +153,11 @@ class test_ProviderSettings /* email */ QStringLiteral("abc@def.de"), /* postal address */ QStringLiteral("Am Fallturm 9\n28359 Bremen"), /* icon */ QStringLiteral("images/npa.ico"), - /* image */ QStringLiteral("images/iOS/Header-Ausweisapp@3x.png")); + /* image */ QStringLiteral("images/iOS/Header-Ausweisapp@3x.png"), + /* tcTokenUrl */ QStringLiteral("https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf"), + /* clientUrl */ QStringLiteral("https://www.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeld"), + /* subjectUrls */ QStringList({QStringLiteral("https://npa.allianz.de/bla1"), QStringLiteral("https://npa.allianz.de/bla1")}) + ); const QVector providers = { provider @@ -141,6 +186,87 @@ class test_ProviderSettings QCOMPARE(otherProvider.getPostalAddress(), QStringLiteral("Am Fallturm 9\n28359 Bremen")); QCOMPARE(otherProvider.getIcon(), QStringLiteral("images/npa.ico")); QCOMPARE(otherProvider.getImage(), QStringLiteral("images/iOS/Header-Ausweisapp@3x.png")); + QCOMPARE(otherProvider.getTcTokenUrl(), QStringLiteral("https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf")); + QCOMPARE(otherProvider.getClientUrl(), QStringLiteral("https://www.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeld")); + QCOMPARE(otherProvider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1"), QStringLiteral("https://npa.allianz.de/bla1")})); + } + + + void callCostSave() + { + QMap callCosts; + callCosts.insert("1805", CallCost(0, 3.9, 0, 42, 0)); + callCosts.insert("1806", CallCost(0, 4.9, 0, 43, 0)); + + settings->setCallCosts(callCosts); + QVERIFY(settings->isUnsaved()); + + settings->save(); + QVERIFY(!settings->isUnsaved()); + } + + + void callCostLoad() + { + QMap callCosts; + callCosts.insert("1805", CallCost(0, 3.9, 0, 42, 0)); + callCosts.insert("1806", CallCost(0, 4.9, 0, 43, 0)); + settings->setCallCosts(callCosts); + settings->save(); + + settings.reset(new ProviderSettings()); + settings->load(); + + QCOMPARE(settings->mCallCosts, callCosts); + } + + + void getCallCost() + { + QMap callCosts; + callCosts.insert("1805", CallCost(0, 3.9, 0, 42, 0)); + callCosts.insert("1806", CallCost(0, 4.9, 0, 43, 0)); + settings->setCallCosts(callCosts); + + const CallCost& callCost = settings->getCallCost(QStringLiteral("+49 1805-123456789")); + + QVERIFY(!callCost.isNull()); + QCOMPARE(callCost.getFreeSeconds(), 0); + QCOMPARE(callCost.getLandlineCentsPerMinute(), 3.9); + QCOMPARE(callCost.getLandlineCentsPerCall(), 0.0); + QCOMPARE(callCost.getMobileCentsPerMinute(), 42.0); + QCOMPARE(callCost.getMobileCentsPerCall(), 0.0); + } + + + void getCallCost_withDelimiters() + { + QMap callCosts; + callCosts.insert("1805", CallCost(0, 3.9, 0, 42, 0)); + callCosts.insert("1806", CallCost(0, 4.9, 0, 43, 0)); + settings->setCallCosts(callCosts); + + const CallCost& callCost = settings->getCallCost(QStringLiteral("+49 1-8/05-123456789")); + + QVERIFY(!callCost.isNull()); + QCOMPARE(callCost.getFreeSeconds(), 0); + QCOMPARE(callCost.getLandlineCentsPerMinute(), 3.9); + QCOMPARE(callCost.getLandlineCentsPerCall(), 0.0); + QCOMPARE(callCost.getMobileCentsPerMinute(), 42.0); + QCOMPARE(callCost.getMobileCentsPerCall(), 0.0); + } + + + void getCallCost_nonExisting() + { + QMap callCosts; + callCosts.insert("1805", CallCost(0, 3.9, 0, 42, 0)); + callCosts.insert("1806", CallCost(0, 4.9, 0, 43, 0)); + settings->setCallCosts(callCosts); + + const CallCost& callCost = settings->getCallCost(QStringLiteral("123456")); + + QVERIFY(callCost.isNull()); } diff --git a/test/qt/settings/test_ProxySettings.cpp b/test/qt/settings/test_ProxySettings.cpp deleted file mode 100644 index 74eef6f..0000000 --- a/test/qt/settings/test_ProxySettings.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*! - * \brief Unit tests for \ref ProxySettings - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include -#include -#include - -#include "ProxySettings.h" - - -using namespace governikus; - -class test_ProxySettings - : public QObject -{ - Q_OBJECT - QScopedPointer settings; - - private Q_SLOTS: - void init() - { - AbstractSettings::mTestDir.clear(); - settings.reset(new ProxySettings()); - } - - - void testEquals() - { - QSKIP("Proxy settings are disabled"); - ProxySettings otherSettings; - otherSettings.load(); - - QVERIFY(*settings == otherSettings); - - settings->setProxyType(settings->getProxyType() == QNetworkProxy::NoProxy ? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy); - QVERIFY(*settings != otherSettings); - otherSettings.setProxyType(settings->getProxyType()); - } - - - void testProxyType() - { - QSKIP("Proxy settings are disabled"); - auto initial = settings->getProxyType(); - auto newValue = initial == QNetworkProxy::NoProxy ? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy; - - settings->setProxyType(newValue); - QCOMPARE(settings->getProxyType(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); - - - settings->setProxyType(initial); - QCOMPARE(settings->getProxyType(), initial); - settings->save(); - - } - - -}; - -QTEST_GUILESS_MAIN(test_ProxySettings) -#include "test_ProxySettings.moc" diff --git a/test/qt/settings/test_RemoteReaderSettings.cpp b/test/qt/settings/test_RemoteReaderSettings.cpp new file mode 100644 index 0000000..2ca9a04 --- /dev/null +++ b/test/qt/settings/test_RemoteReaderSettings.cpp @@ -0,0 +1,134 @@ +/*! + * \brief Unit tests for \ref RemoteReaderSettings + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include + +#include "RemoteReaderSettings.h" +#include "TestFileHelper.h" + + +using namespace governikus; + + +class test_RemoteReaderSettings + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void init() + { + AbstractSettings::mTestDir.clear(); + } + + + void testStandardValues() + { + RemoteReaderSettings settings; + + QCOMPARE(settings.getServerName(), QLatin1String("RemoteReader")); + QCOMPARE(settings.useEncryption(), false); + QCOMPARE(settings.getPassword(), QString("")); + } + + + void testServerName() + { + RemoteReaderSettings settings; + QCOMPARE(settings.getServerName(), QLatin1String("RemoteReader")); + settings.load(); + QCOMPARE(settings.getServerName(), QLatin1String("RemoteReader")); + settings.save(); + QCOMPARE(settings.getServerName(), QLatin1String("RemoteReader")); + settings.setServerName(QLatin1String("Google Pixel")); + QCOMPARE(settings.getServerName(), QLatin1String("Google Pixel")); + settings.load(); + QCOMPARE(settings.getServerName(), QLatin1String("RemoteReader")); + settings.setServerName(QLatin1String("Google Pixel")); + settings.save(); + QCOMPARE(settings.getServerName(), QLatin1String("Google Pixel")); + settings.load(); + QCOMPARE(settings.getServerName(), QLatin1String("Google Pixel")); + } + + + void testUseEncryption() + { + RemoteReaderSettings settings; + QCOMPARE(settings.useEncryption(), false); + settings.load(); + QCOMPARE(settings.useEncryption(), false); + settings.save(); + QCOMPARE(settings.useEncryption(), false); + settings.setEncryption(true); + QCOMPARE(settings.useEncryption(), true); + settings.load(); + QCOMPARE(settings.useEncryption(), false); + settings.setEncryption(true); + settings.save(); + QCOMPARE(settings.useEncryption(), true); + settings.load(); + QCOMPARE(settings.useEncryption(), true); + } + + + void testPassword() + { + RemoteReaderSettings settings; + QCOMPARE(settings.getPassword(), QString("")); + settings.load(); + QCOMPARE(settings.getPassword(), QString("")); + settings.save(); + QCOMPARE(settings.getPassword(), QString("")); + settings.setPassword(QLatin1String("Hallo123")); + QCOMPARE(settings.getPassword(), QLatin1String("Hallo123")); + settings.load(); + QCOMPARE(settings.getPassword(), QString("")); + settings.setPassword(QLatin1String("Hallo123")); + settings.save(); + QCOMPARE(settings.getPassword(), QLatin1String("Hallo123")); + settings.load(); + QCOMPARE(settings.getPassword(), QLatin1String("Hallo123")); + } + + + void testEquals() + { + RemoteReaderSettings settings1; + RemoteReaderSettings settings2; + QVERIFY(settings1 == settings2); + QVERIFY(settings2 == settings1); + + settings1.setServerName(QLatin1String("Google Pixel")); + QVERIFY(settings1 != settings2); + QVERIFY(settings2 != settings1); + + settings2.setServerName(QLatin1String("Google Pixel")); + QVERIFY(settings1 == settings2); + QVERIFY(settings2 == settings1); + + settings1.setEncryption(true); + QVERIFY(settings1 != settings2); + QVERIFY(settings2 != settings1); + + settings2.setEncryption(true); + QVERIFY(settings1 == settings2); + QVERIFY(settings2 == settings1); + + settings1.setPassword(QLatin1String("Hallo123")); + QVERIFY(settings1 != settings2); + QVERIFY(settings2 != settings1); + + settings2.setPassword(QLatin1String("Hallo123")); + QVERIFY(settings1 == settings2); + QVERIFY(settings2 == settings1); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteReaderSettings) +#include "test_RemoteReaderSettings.moc" diff --git a/test/qt/settings/test_SecureStorage.cpp b/test/qt/settings/test_SecureStorage.cpp index 4f771cb..dfbfb80 100644 --- a/test/qt/settings/test_SecureStorage.cpp +++ b/test/qt/settings/test_SecureStorage.cpp @@ -43,14 +43,32 @@ class test_SecureStorage void testGetCVRootCertificates() { QVector > cvcs = CVCertificate::fromHex(secureStorage.getCVRootCertificates(true)); - QCOMPARE(cvcs.count(), 4); - } + cvcs += CVCertificate::fromHex(secureStorage.getCVRootCertificates(false)); + const int count = cvcs.count(); + QCOMPARE(count, 10); - void testGetCVRootCertificatesTest() - { - QVector > cvcs = CVCertificate::fromHex(secureStorage.getCVRootCertificates(false)); - QCOMPARE(cvcs.count(), 4); + // Check that each certificate has a unique car/chr. + for (int j = 0; j < count; ++j) + { + for (int i = 0; i < j; ++i) + { + const CVCertificateBody& bodyI = cvcs[i]->getBody(); + const QByteArray carI = bodyI.getCertificationAuthorityReference(); + const QByteArray chrI = bodyI.getCertificateHolderReference(); + + const CVCertificateBody& bodyJ = cvcs[j]->getBody(); + const QByteArray carJ = bodyJ.getCertificationAuthorityReference(); + const QByteArray chrJ = bodyJ.getCertificateHolderReference(); + + if (carI == carJ && chrI == chrJ) + { + qWarning() << "certificate" << i << "and certificate" << j << "have the same car/chr"; + } + + QVERIFY(carI != carJ || chrI != chrJ); + } + } } @@ -78,47 +96,65 @@ class test_SecureStorage void testAppcast() { - QCOMPARE(secureStorage.getAppcastUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/Appcast.xml")); - QCOMPARE(secureStorage.getAppcastBetaUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/beta/Appcast.xml")); + QCOMPARE(secureStorage.getAppcastUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/Appcast.json")); + QCOMPARE(secureStorage.getAppcastBetaUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/beta/Appcast.json")); + } + + + void testMinStaticKeySizes() + { + QCOMPARE(secureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Rsa), 2000); + QCOMPARE(secureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Dsa), 2000); + QCOMPARE(secureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Ec), 224); + } + + + void testMinEphemeralKeySizes() + { + QCOMPARE(secureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Rsa), 2000); + QCOMPARE(secureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Dsa), 1024); + QCOMPARE(secureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Ec), 224); } void testSignatureAlgorithms() { - QCOMPARE(secureStorage.getSignatureAlgorithms().size(), 12); - QCOMPARE(secureStorage.getSignatureAlgorithms().first().first, QSsl::KeyAlgorithm::Rsa); - QCOMPARE(secureStorage.getSignatureAlgorithms().first().second, QCryptographicHash::Algorithm::Sha512); - QCOMPARE(secureStorage.getSignatureAlgorithms().last().first, QSsl::KeyAlgorithm::Ec); - QCOMPARE(secureStorage.getSignatureAlgorithms().last().second, QCryptographicHash::Algorithm::Sha224); + const auto& tlsSettings = secureStorage.getTlsSettings(); + QCOMPARE(tlsSettings.getSignatureAlgorithms().size(), 12); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constFirst().first, QSsl::KeyAlgorithm::Rsa); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constFirst().second, QCryptographicHash::Algorithm::Sha512); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constLast().first, QSsl::KeyAlgorithm::Ec); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constLast().second, QCryptographicHash::Algorithm::Sha224); } void testSignatureAlgorithmsPsk() { - QCOMPARE(secureStorage.getSignatureAlgorithmsPsk().size(), 4); - QCOMPARE(secureStorage.getSignatureAlgorithmsPsk().first().first, QSsl::KeyAlgorithm::Rsa); - QCOMPARE(secureStorage.getSignatureAlgorithmsPsk().first().second, QCryptographicHash::Algorithm::Sha512); - QCOMPARE(secureStorage.getSignatureAlgorithmsPsk().last().first, QSsl::KeyAlgorithm::Rsa); - QCOMPARE(secureStorage.getSignatureAlgorithmsPsk().last().second, QCryptographicHash::Algorithm::Sha224); + const auto& tlsSettings = secureStorage.getTlsSettingsPsk(); + QCOMPARE(tlsSettings.getSignatureAlgorithms().size(), 4); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constFirst().first, QSsl::KeyAlgorithm::Rsa); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constFirst().second, QCryptographicHash::Algorithm::Sha512); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constLast().first, QSsl::KeyAlgorithm::Rsa); + QCOMPARE(tlsSettings.getSignatureAlgorithms().constLast().second, QCryptographicHash::Algorithm::Sha224); } void orderOfCiphers() { - const auto& ciphersForwardSecrecy = secureStorage.getCiphersWithForwardSecrecy(); - QCOMPARE(ciphersForwardSecrecy.count(), 16); - QCOMPARE(ciphersForwardSecrecy.first(), QStringLiteral("ECDHE-ECDSA-AES256-GCM-SHA384")); - QCOMPARE(ciphersForwardSecrecy.last(), QStringLiteral("DHE-RSA-AES128-SHA256")); + const auto& ciphersForwardSecrecy = secureStorage.getTlsSettings().getCiphers(); + QCOMPARE(ciphersForwardSecrecy.count(), 24); + QCOMPARE(ciphersForwardSecrecy.first(), QSslCipher("ECDHE-ECDSA-AES256-GCM-SHA384")); + QCOMPARE(ciphersForwardSecrecy.last(), QSslCipher("DHE-RSA-AES128-SHA")); - const auto& ciphersPsk = secureStorage.getCiphersWithPsk(); + const auto& ciphersPsk = secureStorage.getTlsSettingsPsk().getCiphers(); QCOMPARE(ciphersPsk.count(), 5); - QCOMPARE(ciphersPsk.first(), QStringLiteral("RSA-PSK-AES256-GCM-SHA384")); - QCOMPARE(ciphersPsk.last(), QStringLiteral("RSA-PSK-AES256-CBC-SHA")); + QCOMPARE(ciphersPsk.first(), QSslCipher("RSA-PSK-AES256-GCM-SHA384")); + QCOMPARE(ciphersPsk.last(), QSslCipher("RSA-PSK-AES256-CBC-SHA")); - const auto& ciphersEc = secureStorage.getAllowedSslEllipticCurves(); + const auto& ciphersEc = secureStorage.getTlsSettings().getEllipticCurves(); QCOMPARE(ciphersEc.count(), 6); - QCOMPARE(ciphersEc.first(), QStringLiteral("brainpoolP512r1")); - QCOMPARE(ciphersEc.last(), QStringLiteral("secp224r1")); + QCOMPARE(ciphersEc.first(), QSslEllipticCurve::fromLongName("brainpoolP512r1")); + QCOMPARE(ciphersEc.last(), QSslEllipticCurve::fromLongName("secp224r1")); } @@ -133,13 +169,32 @@ class test_SecureStorage void getSslProtocolVersion() { - QCOMPARE(secureStorage.getSslProtocolVersion(), QSsl::SslProtocol::TlsV1_0OrLater); + QCOMPARE(secureStorage.getTlsSettings().getProtocolVersion(), QSsl::SslProtocol::TlsV1_0OrLater); } void getSslProtocolVersionPsk() { - QCOMPARE(secureStorage.getSslProtocolVersionPsk(), QSsl::SslProtocol::TlsV1_1OrLater); + QCOMPARE(secureStorage.getTlsSettingsPsk().getProtocolVersion(), QSsl::SslProtocol::TlsV1_1OrLater); + } + + + void getConfiguration_data() + { + QTest::addColumn("configuration"); + QTest::addColumn("cipherSize"); + + QTest::newRow("ciphers non PSK") << secureStorage.getTlsSettings().getConfiguration() << 24; + QTest::newRow("ciphers for PSK") << secureStorage.getTlsSettingsPsk().getConfiguration() << 5; + } + + + void getConfiguration() + { + QFETCH(QSslConfiguration, configuration); + QFETCH(int, cipherSize); + + QCOMPARE(configuration.ciphers().size(), cipherSize); } diff --git a/test/qt/settings/test_TlsSettings.cpp b/test/qt/settings/test_TlsSettings.cpp new file mode 100644 index 0000000..fb4defd --- /dev/null +++ b/test/qt/settings/test_TlsSettings.cpp @@ -0,0 +1,156 @@ +/*! + * \brief Unit tests for \ref TlsSettings + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "TlsSettings.h" + +#include +#include + + +using namespace governikus; + + +class test_TlsSettings + : public QObject +{ + Q_OBJECT + TlsSettings mTlsSettings; + + private Q_SLOTS: + void initTestCase() + { + mTlsSettings = TlsSettings(); + } + + + void testDefaults() + { + QByteArray config("{}"); + + mTlsSettings.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsSettings.getProtocolVersion(), QSsl::SecureProtocols); + QCOMPARE(mTlsSettings.getCiphers().size(), 0); + QCOMPARE(mTlsSettings.getEllipticCurves().size(), 0); + QCOMPARE(mTlsSettings.getSignatureAlgorithms().size(), 0); + } + + + void testLoadprotocolVersion() + { + QByteArray config("{" + " \"protocolVersion\": \"TlsV1_0OrLater\"" + "}"); + + mTlsSettings.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsSettings.getProtocolVersion(), QSsl::TlsV1_0OrLater); + } + + + void testLoadCiphers() + { + QByteArray config("{" + " \"ciphers\": [\"ECDHE-ECDSA-AES256-GCM-SHA384\",\"DHE-RSA-AES256-SHA256\"]" + "}"); + + mTlsSettings.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsSettings.getCiphers().size(), 2); + QCOMPARE(mTlsSettings.getCiphers()[0], QSslCipher("ECDHE-ECDSA-AES256-GCM-SHA384")); + QCOMPARE(mTlsSettings.getCiphers()[1], QSslCipher("DHE-RSA-AES256-SHA256")); + } + + + void testLoadEllipticCurves() + { + QByteArray config("{" + " \"ellipticCurves\": [\"brainpoolP512r1\", \"brainpoolP384r1\"]" + "}"); + + mTlsSettings.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsSettings.getEllipticCurves().size(), 2); + QCOMPARE(mTlsSettings.getEllipticCurves()[0], QSslEllipticCurve::fromLongName("brainpoolP512r1")); + QCOMPARE(mTlsSettings.getEllipticCurves()[1], QSslEllipticCurve::fromLongName("brainpoolP384r1")); + } + + + void testLoadSignatureAlgorithms() + { + QByteArray config("{" + " \"signatureAlgorithms\": [\"Rsa+Sha512\", \"Dsa+Sha384\", \"Ec+Sha256\"]" + "}"); + + mTlsSettings.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsSettings.getSignatureAlgorithms().size(), 3); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[0].first, QSsl::Rsa); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[0].second, QCryptographicHash::Sha512); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[1].first, QSsl::Dsa); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[1].second, QCryptographicHash::Sha384); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[2].first, QSsl::Ec); + QCOMPARE(mTlsSettings.getSignatureAlgorithms()[2].second, QCryptographicHash::Sha256); + } + + + void testEquals_data() + { + QTest::addColumn("config1"); + QTest::addColumn("config2"); + QTest::addColumn("isEqual"); + + QByteArrayList configs({"", + "{" + " \"protocolVersion\": \"TlsV1_0OrLater\"" + "}", + "{" + " \"protocolVersion\": \"TlsV1_0OrLater\"," + " \"ciphers\": [\"ECDHE-ECDSA-AES256-GCM-SHA384\",\"DHE-RSA-AES256-SHA256\"]" + "}", + "{" + " \"protocolVersion\": \"TlsV1_0OrLater\"," + " \"ciphers\": [\"ECDHE-ECDSA-AES256-GCM-SHA384\",\"DHE-RSA-AES256-SHA256\"]," + " \"ellipticCurves\": [\"brainpoolP512r1\", \"brainpoolP384r1\"]" + "}", + "{" + " \"protocolVersion\": \"TlsV1_0OrLater\"," + " \"ciphers\": [\"ECDHE-ECDSA-AES256-GCM-SHA384\",\"DHE-RSA-AES256-SHA256\"]," + " \"ellipticCurves\": [\"brainpoolP512r1\", \"brainpoolP384r1\"]," + " \"signatureAlgorithms\": [\"Rsa+Sha512\", \"Dsa+Sha384\", \"Ec+Sha256\"]" + "}"}); + + for (int i = 0; i < configs.size(); ++i) + { + if (i > 0) + { + const auto& name1 = QStringLiteral("config%1 != config%2").arg(i - 1).arg(i).toLatin1(); + QTest::newRow(name1.data()) << configs[i - 1] << configs[i] << false; + } + const auto& name2 = QStringLiteral("config%1 == config%1").arg(i).toLatin1(); + QTest::newRow(name2.data()) << configs[i] << configs[i] << true; + } + } + + + void testEquals() + { + QFETCH(QByteArray, config1); + QFETCH(QByteArray, config2); + QFETCH(bool, isEqual); + + TlsSettings settings1, settings2; + settings1.load(QJsonDocument::fromJson(config1).object()); + settings2.load(QJsonDocument::fromJson(config2).object()); + + QCOMPARE(settings1 == settings2, isEqual); + } + + +}; + +QTEST_GUILESS_MAIN(test_TlsSettings) +#include "test_TlsSettings.moc" diff --git a/test/qt/websocket/test_UIPlugInWebSocket.cpp b/test/qt/websocket/test_UIPlugInWebSocket.cpp new file mode 100644 index 0000000..bc04d03 --- /dev/null +++ b/test/qt/websocket/test_UIPlugInWebSocket.cpp @@ -0,0 +1,141 @@ +/*! + * \brief Unit tests for \ref UIPlugInWebSocket + * + * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + */ + +#include "UIPlugInWebSocket.h" +#include "WebSocketHelper.h" + +#include +#include +#include +#include + +using namespace governikus; + + +class test_UIPlugInWebSocket + : public QObject +{ + Q_OBJECT + + private: + static const int PROCESS_TIMEOUT = 15000; + + QScopedPointer mApp2; + QScopedPointer mWebSocket; + QScopedPointer mHelper; + + private Q_SLOTS: + void initTestCase() + { + #ifdef Q_OS_WIN + QSKIP("Not supported"); + #endif + + #ifdef Q_OS_BSD4 + QSKIP("TODO: Platform plugin seems broken"); + #endif + } + + + void init() + { + qRegisterMetaType("QProcess::ProcessState"); + + QString path = QCoreApplication::applicationDirPath() + "/../../src/"; + QString app = path + "AusweisApp2"; + #ifdef Q_OS_WIN + app += ".exe"; + #endif + + QStringList args; + args << "--ui" << "websocket"; + args << "--port" << "0"; + args << "--port-websocket" << "0"; + #ifndef Q_OS_WIN + args << "-platform" << "offscreen"; + #endif + + mApp2.reset(new QProcess()); + mApp2->setProgram(app); + mApp2->setWorkingDirectory(path); + mApp2->setArguments(args); + + mApp2->start(); + mApp2->waitForStarted(PROCESS_TIMEOUT); + QCOMPARE(mApp2->state(), QProcess::Running); + + QFile portInfoFile(WEBSOCKET_PORT_FILENAME(mApp2->processId())); + for (int i = 0; i < PROCESS_TIMEOUT && portInfoFile.size() == 0; i += 200) + { + QThread::msleep(200); + } + QVERIFY(portInfoFile.size() != 0); + QVERIFY(portInfoFile.open(QIODevice::ReadOnly)); + + quint16 webSocketPort = 0; + QTextStream(&portInfoFile) >> webSocketPort; + QVERIFY(webSocketPort > 0); + + mHelper.reset(new WebSocketHelper(webSocketPort)); + QCOMPARE(mHelper->getState(), QAbstractSocket::SocketState::ConnectedState); + } + + + void cleanup() + { + mHelper.reset(); + + mApp2->terminate(); + mApp2->waitForFinished(PROCESS_TIMEOUT); + QCOMPARE(mApp2->state(), QProcess::NotRunning); + QCOMPARE(mApp2->exitCode(), 0); + + if (mApp2->state() != QProcess::NotRunning) + { + mApp2->kill(); + } + } + + + void runAndStop() + { + } + + + void getInfoAndApiLevel() + { + mHelper->sendMessage("{\"cmd\": \"GET_INFO\"}"); + QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ + return pMessage["msg"] == "INFO" && + pMessage["VersionInfo"].toObject()["Name"] == "AusweisApp2"; + })); + + + mHelper->sendMessage("{\"cmd\": \"GET_API_LEVEL\"}"); + QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ + return pMessage["msg"] == "API_LEVEL" && + pMessage["available"].toArray().size() >= 1; + })); + } + + + void tryLocalhostAuth() + { + mHelper->sendMessage("{\"cmd\": \"RUN_AUTH\", \"tcTokenURL\" : \"https://localhost/\"}"); + QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ + return pMessage["msg"] == "AUTH"; + })); + + QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ + return pMessage["result"].toObject()["major"].toString().endsWith("#error"); + })); + } + + +}; + +QTEST_GUILESS_MAIN(test_UIPlugInWebSocket) +#include "test_UIPlugInWebSocket.moc" diff --git a/uncrustify.cfg b/uncrustify.cfg index 0e9fd5f..34de8e4 100644 --- a/uncrustify.cfg +++ b/uncrustify.cfg @@ -116,6 +116,7 @@ indent_switch_case=4 indent_case_shift=0 indent_case_brace=0 indent_access_spec=0 +indent_paren_open_brace=true nl_max=3 nl_after_func_body=3 nl_before_block_comment=2