diff --git a/CMakeLists.txt b/CMakeLists.txt index 62c7b5f..13178ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.3.0) +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) IF(POLICY CMP0020) CMAKE_POLICY(SET CMP0020 NEW) @@ -33,7 +33,7 @@ ELSE() ENDIF() -PROJECT(AusweisApp2 VERSION 1.12.4 LANGUAGES ${LANGUAGES}) +PROJECT(AusweisApp2 VERSION 1.14.0 LANGUAGES ${LANGUAGES}) # Set TWEAK if not defined in PROJECT_VERSION above to # have a valid tweak version without propagating it @@ -67,6 +67,7 @@ MESSAGE(STATUS "VENDOR: ${VENDOR}") MESSAGE(STATUS "VERSION: ${PROJECT_VERSION}") IF(ANDROID) + GET_ANDROID_TOOLCHAIN_VARS(ANDROID_TOOLCHAIN_PREFIX ANDROID_TOOLCHAIN_MACHINE_NAME) IF(NOT BUILD_PREVIEW) SET(BUILD_PREVIEW false) ENDIF() @@ -78,6 +79,13 @@ IF(ANDROID) MESSAGE(STATUS "ANDROID_VERSION_CODE: ${ANDROID_VERSION_CODE}") ENDIF() +IF(IOS) + IF(NOT USE_DISTRIBUTION_PROFILE) + SET(USE_DISTRIBUTION_PROFILE false) + ENDIF() + MESSAGE(STATUS "USE_DISTRIBUTION_PROFILE: ${USE_DISTRIBUTION_PROFILE}") +ENDIF() + IF("${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}") MESSAGE(FATAL_ERROR "in tree building is not supported!") ENDIF() diff --git a/LICENSE.officially.txt b/LICENSE.officially.txt index 4790228..0990aa8 100644 --- a/LICENSE.officially.txt +++ b/LICENSE.officially.txt @@ -466,7 +466,7 @@ Die verwendeten OpenSource-Bibliotheken unterliegen den folgenden Nutzungsbeding Qt Lizenz: LGPL v3 - Version: 5.8.0 + Version: 5.9.3 Adresse: https://www.qt.io/ http_parser @@ -661,11 +661,7 @@ permanent authorization for you to choose that version for the Library. -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. +Copyright Joyent, Inc. and other Node contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/LICENSE.txt b/LICENSE.txt index ff3dee9..e43986d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -416,7 +416,7 @@ Die verwendeten OpenSource-Bibliotheken unterliegen den folgenden Nutzungsbeding Qt Lizenz: LGPL v3 - Version: 5.8.0 + Version: 5.9.3 Adresse: https://www.qt.io/ http_parser @@ -611,11 +611,7 @@ permanent authorization for you to choose that version for the Library. -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. +Copyright Joyent, Inc. and other Node contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/README.rst b/README.rst index 6857986..3927a6e 100644 --- a/README.rst +++ b/README.rst @@ -170,3 +170,23 @@ Nachdem die Build-Umgebung eingerichtet ist, kann je nach System ein Package ers $ make install $ make apk + + + +Reproduzierbarer Build +---------------------- +Wir sind stets bemüht den Build des offiziellen Binaries der AusweisApp2 nachvollziehbar zu gestalten. +Daher haben wir unter anderem eine README in dem Unterordner ``./libs`` hinterlegt, die den Aufbau +der Buildumgebung und den Build der externen Bibliotheken beschreibt. +Anhand dieser Anleitung können Sie nachvollziehen, wie unser internes Buildsystem aufgebaut ist und +welche Compiler bzw. Compiler-Versionen wir verwenden. + +Im Unterordner ``./resources/jenkins/`` ist es möglich, unsere Konfiguration des CI-Servers einzusehen. +Die Konfiguration besteht aus mehreren Dockerfiles und JobDSL-Dateien. + +Anhand dieser Skripte ist es möglich, den Build der AusweisApp2 zu reproduzieren. +Ein Unterschied zum offiziellen Binary sollte lediglich in eventuellen Pfaden, +einem Datum bzw. Zeitstempel und Signaturen bestehen. + +.. seealso:: + https://reproducible-builds.org/ diff --git a/cmake/Appcast.cmake b/cmake/Appcast.cmake index 59b75ea..32e089a 100644 --- a/cmake/Appcast.cmake +++ b/cmake/Appcast.cmake @@ -47,15 +47,15 @@ IF(MAC OR LINUX OR WIN32) FILE(GLOB TAR_GZ_FILES ${PROJECT_BINARY_DIR}/*.tar.gz) IF(DMG_FILES) - ADD_APPCAST_FILE("${DMG_FILES}" "Q_OS_MAC") + ADD_APPCAST_FILE("${DMG_FILES}" "mac") ENDIF() IF(MSI_FILES) - ADD_APPCAST_FILE("${MSI_FILES}" "Q_OS_WIN32") + ADD_APPCAST_FILE("${MSI_FILES}" "win") ENDIF() IF(TAR_GZ_FILES) - ADD_APPCAST_FILE("${TAR_GZ_FILES}" "SOURCES") + ADD_APPCAST_FILE("${TAR_GZ_FILES}" "src") ENDIF() IF(APPCAST_ITEMS) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index 0694de2..5c30804 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -9,14 +9,12 @@ ADD_DEFINITIONS(-DQT_NO_EXCEPTIONS) IF(QT_VENDOR STREQUAL "Governikus") ADD_DEFINITIONS(-DGOVERNIKUS_QT) + ADD_DEFINITIONS(-DQT_DEPRECATED_WARNINGS) ENDIF() -IF(CMAKE_VERSION VERSION_LESS 3.2) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -ELSE() - SET(CMAKE_CXX_STANDARD 11) - SET(CMAKE_CXX_STANDARD_REQUIRED ON) -ENDIF() +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED ON) +SET(CMAKE_CXX_EXTENSIONS OFF) IF(NOT DEFINED WARNINGS_ARE_ERRORS AND VENDOR_GOVERNIKUS) SET(WARNINGS_ARE_ERRORS ON) @@ -32,11 +30,17 @@ 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") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wcast-qual -Wshadow") + + ADD_FLAG(-flto VAR CMAKE_EXE_LINKER_FLAGS_RELEASE CMAKE_SHARED_LINKER_FLAGS_RELEASE LINK -flto) 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(-Wold-style-cast) + ADD_FLAG(-Wmost) + ADD_FLAG(-Wpedantic) + ADD_FLAG(-Wvla) ADD_FLAG(-Wconversion) ADD_FLAG(-Wloop-analysis) ADD_FLAG(-Wlogical-op) @@ -44,20 +48,28 @@ ELSE() ADD_FLAG(-Wduplicated-cond) ADD_FLAG(-Wweak-vtables) ADD_FLAG(-Wcovered-switch-default) + ADD_FLAG(-Wduplicated-branches) + ADD_FLAG(-Wdocumentation) + ADD_FLAG(-Wsuggest-override) + ADD_FLAG(-Winconsistent-missing-override) + ADD_FLAG(-Winconsistent-missing-destructor-override) + ADD_FLAG(-Wnon-virtual-dtor) + ADD_FLAG(-Winitializer-overrides) + ADD_FLAG(-Wunreachable-code-aggressive) + ADD_FLAG(-Wnewline-eof) 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_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-limit=64 -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now") + ENDIF() 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) + IF(WARNINGS_ARE_ERRORS) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") ENDIF() @@ -73,17 +85,21 @@ ELSE() SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0") 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) + IF(NOT SANITIZER_SKIP_ASAN) + SET(SANITIZER_FLAGS "-fsanitize=address") + SET(SANITIZER_LINK_FLAGS "-fsanitize=address") ENDIF() + SET(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls") + ADD_FLAG("${SANITIZER_FLAGS} -fsanitize=unsigned-integer-overflow -fsanitize-address-use-after-scope" "${SANITIZER_FLAGS}" LINK "${SANITIZER_LINK_FLAGS} -fsanitize=undefined") + ENDIF() + + IF(CMAKE_CXX_COMPILER_ID STREQUAL Intel) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd1875,1682,2259,654,177") ENDIF() ENDIF() -# enable Objective-C support on MacOS X -IF(APPLE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ObjC++") +IF(APPLE AND NOT IOS) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ObjC++ -mmacosx-version-min=10.9") ENDIF() diff --git a/cmake/DVCS.cmake b/cmake/DVCS.cmake index 11b40c8..ce7e3f6 100644 --- a/cmake/DVCS.cmake +++ b/cmake/DVCS.cmake @@ -93,12 +93,6 @@ MACRO(GET_DVCS_INFO) DVCS_CALL("revision" "-" id -i) ELSEIF(GIT_FOUND) DVCS_CALL("revision" "-" rev-parse --verify --short HEAD) - DVCS_EXECUTE(dvcs_clean_wc diff-index --quiet HEAD) - IF(NOT DEFINED dvcs_clean_wc) - MESSAGE(STATUS "DVCS: dirty working copy") - SET(dvcs_revision ${dvcs_revision}+) - SET(VERSION_DVCS ${VERSION_DVCS}+) - ENDIF() ENDIF() ENDMACRO() diff --git a/cmake/DefaultFiles.cmake b/cmake/DefaultFiles.cmake index 90eaef5..7737992 100644 --- a/cmake/DefaultFiles.cmake +++ b/cmake/DefaultFiles.cmake @@ -1,38 +1,27 @@ +SET(REMOTE_CONFIG_URL_PROD https://appl.governikus-asp.de/ausweisapp2) IF(JENKINS_APPCAST) - SET(REMOTE_CONFIG_URL https://buildautentapp/job/${JENKINS_APPCAST}/lastSuccessfulBuild/artifact CACHE STRING "Remote config download URL" FORCE) + SET(REMOTE_CONFIG_URL https://vtf-aajenkins.tf.bos-test.de/job/${JENKINS_APPCAST}/lastSuccessfulBuild/artifact CACHE STRING "Remote config download URL" FORCE) ELSE() - SET(REMOTE_CONFIG_URL https://appl.governikus-asp.de/ausweisapp2 CACHE STRING "Remote config download URL" FORCE) + SET(REMOTE_CONFIG_URL ${REMOTE_CONFIG_URL_PROD} CACHE STRING "Remote config download URL" FORCE) ENDIF() FUNCTION(CONFIGURE_DEFAULT_FILES _destination) - # Set DEFAULT_PROVIDER_FILE to replace this in config.json.in. - IF(IOS) - SET(DEFAULT_PROVIDER_FILE default-providers-ios.json) - ELSE() - SET(DEFAULT_PROVIDER_FILE default-providers.json) - ENDIF() - IF(JENKINS_APPCAST) SET(REMOTE_CONFIG_PATH_APPCAST /build) SET(REMOTE_CONFIG_PATH_APPCAST_BETA /build) SET(REMOTE_CONFIG_PATH_PROVIDERS /source/resources) - SET(REMOTE_CONFIG_PATH_DRIVERS /source/resources) + SET(REMOTE_CONFIG_PATH_READERS /source/resources) ELSE() SET(REMOTE_CONFIG_PATH_APPCAST ) SET(REMOTE_CONFIG_PATH_APPCAST_BETA /beta) SET(REMOTE_CONFIG_PATH_PROVIDERS ) - SET(REMOTE_CONFIG_PATH_DRIVERS /driver) + SET(REMOTE_CONFIG_PATH_READERS /reader) ENDIF() + SET(REMOTE_CONFIG_URL_READER_IMAGES ${REMOTE_CONFIG_URL_PROD}/reader) # Copy secure storage file, so that the AusweisApp2 can be started from the build directory. CONFIGURE_FILE(${RESOURCES_DIR}/config.json.in ${_destination}/config.json @ONLY) - # The same with default providers - CONFIGURE_FILE(${RESOURCES_DIR}/${DEFAULT_PROVIDER_FILE} ${_destination}/default-providers.json COPYONLY) - - # The same with default supported devices - CONFIGURE_FILE(${RESOURCES_DIR}/default-supported-devices.json ${_destination}/default-supported-devices.json COPYONLY) - # Copy qtlogging.ini file CONFIGURE_FILE(${RESOURCES_DIR}/qtlogging.ini ${_destination}/qtlogging.ini COPYONLY) ENDFUNCTION() diff --git a/cmake/Helper.cmake b/cmake/Helper.cmake index 44d3945..64534f8 100644 --- a/cmake/Helper.cmake +++ b/cmake/Helper.cmake @@ -1,9 +1,22 @@ INCLUDE(CheckCXXCompilerFlag) -INCLUDE(CMakeParseArguments) +# Check if a compiler flag is supported by current compiler. +# +# Options +# NOQUOTES: Do not add quotes to the variable (not used if it is a TARGET) +# +# Parameter +# NAME: Add a human readable name. This is for configure output only to +# group multiple flags or to indicate the usage. +# LINK: Use these linker flags to try the compiler flag. The linker +# flags won't be added. They are for testing only. +# VAR: Checked compiler flags will be added to these variables. (default: CMAKE_CXX_FLAGS) +# It is possible to add multiple VAR parameter. +# If VAR parameter is a cmake TARGET the compiler flag will be added +# to the COMPILE_FLAGS property of this TARGET only. FUNCTION(ADD_FLAG) SET(options NOQUOTES) - SET(oneValueArgs) + SET(oneValueArgs NAME) SET(multiValueArgs LINK VAR) cmake_parse_arguments(_PARAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -16,13 +29,19 @@ FUNCTION(ADD_FLAG) ENDIF() FOREACH(flag ${_PARAM_UNPARSED_ARGUMENTS}) - STRING(REPLACE "-" "_" flagname ${flag}) + SET(flagname ${flag}) + IF(_PARAM_NAME) + SET(flagname "${flagname}_${_PARAM_NAME}") + ENDIF() + STRING(REPLACE "-" "_" flagname ${flagname}) STRING(REPLACE " " "_" flagname ${flagname}) CHECK_CXX_COMPILER_FLAG(${flag} ${flagname}) IF(${flagname}) FOREACH(var ${_PARAM_VAR}) - IF(_PARAM_NOQUOTES) + IF (${var} MATCHES "^AusweisApp") + SET_PROPERTY(TARGET ${var} APPEND_STRING PROPERTY COMPILE_FLAGS " ${flag}") + ELSEIF(_PARAM_NOQUOTES) SET(${var} ${${var}} ${flag} PARENT_SCOPE) ELSE() SET(${var} "${${var}} ${flag}" PARENT_SCOPE) @@ -36,10 +55,6 @@ ENDFUNCTION() FUNCTION(GET_FILE_MATCHER _result_remove _result_keep) - IF(NOT ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") - LIST(APPEND matcher_remove "_debug") - ENDIF() - IF(NOT ANDROID) LIST(APPEND matcher_remove "_android") ELSE() @@ -115,9 +130,11 @@ FUNCTION(ADD_PLATFORM_LIBRARY _name) GET_FILE_MATCHER(matcher_remove matcher_keep) FOREACH(file ${FILES}) + STRING(REPLACE "${CMAKE_SOURCE_DIR}" "" file_stripped "${file}") + SET(keep FALSE) FOREACH(match ${matcher_keep}) - IF("${file}" MATCHES ${match}) + IF("${file_stripped}" MATCHES ${match}) SET(keep TRUE) BREAK() ENDIF() @@ -125,10 +142,10 @@ FUNCTION(ADD_PLATFORM_LIBRARY _name) IF(NOT keep) FOREACH(match ${matcher_remove}) - IF("${file}" MATCHES ${match}) + IF("${file_stripped}" MATCHES ${match}) LIST(REMOVE_ITEM FILES "${file}") BREAK() - ELSEIF("${file}" MATCHES "_generic") + ELSEIF("${file_stripped}" MATCHES "_generic") LIST(REMOVE_ITEM FILES "${file}") LIST(APPEND GENERICS "${file}") BREAK() @@ -144,7 +161,8 @@ FUNCTION(ADD_PLATFORM_LIBRARY _name) SET(found FALSE) FOREACH(file ${FILES}) - IF("${file}" MATCHES "${generic_basename}" AND NOT "${file}" MATCHES ".h$") + STRING(REPLACE "${CMAKE_SOURCE_DIR}" "" file_stripped "${file}") + IF("${file_stripped}" MATCHES "${generic_basename}" AND NOT "${file_stripped}" MATCHES ".h$") SET(found TRUE) BREAK() ENDIF() @@ -160,61 +178,22 @@ FUNCTION(ADD_PLATFORM_LIBRARY _name) ENDFUNCTION() -# This FUNCTION is a workaround for a "bug" in cmake to use OBJECT LIBRARIES with IMPORTED TARGETS like Qt -# http://www.cmake.org/Bug/view.php?id=14778 FUNCTION(ADD_OBJECT_LIBRARY TargetName Files) - ADD_LIBRARY(${TargetName} OBJECT ${Files}) + SET(_name ${TargetName}_ObjectLib) + ADD_LIBRARY(${_name} OBJECT ${Files}) FOREACH(MODULE ${ARGN}) - TARGET_INCLUDE_DIRECTORIES(${TargetName} PRIVATE $) - TARGET_COMPILE_DEFINITIONS(${TargetName} PRIVATE $) + TARGET_INCLUDE_DIRECTORIES(${_name} SYSTEM PRIVATE $) + TARGET_COMPILE_DEFINITIONS(${_name} PRIVATE $) ENDFOREACH() IF(Qt5_POSITION_INDEPENDENT_CODE) - SET_TARGET_PROPERTIES(${TargetName} PROPERTIES POSITION_INDEPENDENT_CODE ON) - ENDIF() -ENDFUNCTION() - - -FUNCTION(GET_QUOTED_STRING _dest _str _filename) - IF(CMAKE_GENERATOR STREQUAL Xcode AND CMAKE_VERSION VERSION_LESS "3.5") - SET(tmp_var \\\\"${_str}\\\\") - ELSEIF(NOT "${_filename}" MATCHES ".rc$") - SET(tmp_var \\"${_str}\\") - ELSE() - SET(tmp_var ${_str}) + SET_TARGET_PROPERTIES(${_name} PROPERTIES POSITION_INDEPENDENT_CODE ON) ENDIF() - SET(${_dest} ${tmp_var} PARENT_SCOPE) -ENDFUNCTION() - -FUNCTION(ADD_STRING_DEFINITION _str _def) - IF(ARGN) - FOREACH(arg ${ARGN}) - IF (${arg} MATCHES "^AusweisApp") - SET(ARG_TYPE TARGET) - ELSE() - SET(ARG_TYPE SOURCE) - ENDIF() - - IF(NOT "${_str}" STREQUAL "") - GET_QUOTED_STRING(tmp_var ${_str} ${arg}) - SET(tmp_var =\"${tmp_var}\") - ENDIF() - - SET_PROPERTY(${ARG_TYPE} ${arg} APPEND_STRING PROPERTY COMPILE_FLAGS " -D${_def}${tmp_var}") - ENDFOREACH() - ELSE() - IF(NOT "${_str}" STREQUAL "") - GET_QUOTED_STRING(tmp_var ${_str} ${arg}) - SET(tmp_var =${tmp_var}) - ENDIF() - ADD_DEFINITIONS(-D${_def}${tmp_var}) - ENDIF() -ENDFUNCTION() - -FUNCTION(ADD_DEFINITION _def) - ADD_STRING_DEFINITION("" ${_def} ${ARGN}) + ADD_LIBRARY(${TargetName} INTERFACE) + TARGET_SOURCES(${TargetName} INTERFACE $) + TARGET_INCLUDE_DIRECTORIES(${TargetName} INTERFACE "$") ENDFUNCTION() @@ -241,6 +220,17 @@ FUNCTION(DIRLIST_OF_FILES _result _files) SET(${_result} ${dirlist} PARENT_SCOPE) ENDFUNCTION() + +FUNCTION(GET_ANDROID_TOOLCHAIN_VARS _prefix _machine) + 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(${_prefix} ${ANDROID_TOOLCHAIN_PREFIX} PARENT_SCOPE) + SET(${_machine} ${ANDROID_TOOLCHAIN_MACHINE_NAME} PARENT_SCOPE) +ENDFUNCTION() + + IF("${CMAKE_SYSTEM_NAME}" MATCHES "BSD") SET(BSD true) ENDIF() @@ -285,6 +275,11 @@ IF(NOT COMMAND FIND_HOST_PACKAGE) ENDIF() FUNCTION(FETCH_TARGET_LOCATION _destination _target) + SET(options NAME) + SET(oneValueArgs) + SET(multiValueArgs) + cmake_parse_arguments(_PARAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + GET_TARGET_PROPERTY(tmp "${_target}" IMPORTED_LOCATION_${CMAKE_BUILD_TYPE}) IF(NOT tmp) @@ -299,6 +294,11 @@ FUNCTION(FETCH_TARGET_LOCATION _destination _target) GET_TARGET_PROPERTY(tmp "${_target}" IMPORTED_LOCATION) ENDIF() + IF(_PARAM_NAME) + GET_FILENAME_COMPONENT(realpath "${tmp}" REALPATH) + GET_FILENAME_COMPONENT(tmp "${realpath}" NAME) + ENDIF() + SET(${_destination} ${tmp} PARENT_SCOPE) ENDFUNCTION() @@ -326,6 +326,7 @@ IF(WIN32) SET(SIGNTOOL_PARAMS ${SIGNTOOL_PARAMS} /n ${WIN_SIGN_SUBJECT_NAME}) MESSAGE(STATUS "Files will be signed using: ${WIN_SIGN_SUBJECT_NAME}") ELSE() + STRING(REPLACE "\\" "/" WIN_SIGN_KEYSTORE "${WIN_SIGN_KEYSTORE}") SET(SIGNTOOL_PARAMS ${SIGNTOOL_PARAMS} /f ${WIN_SIGN_KEYSTORE} /p ${WIN_SIGN_KEYSTORE_PSW}) MESSAGE(STATUS "Files will be signed using: ${WIN_SIGN_KEYSTORE}") ENDIF() diff --git a/cmake/Install.cmake b/cmake/Install.cmake index eb8e9c5..b0729e3 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -80,19 +80,6 @@ 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) @@ -100,9 +87,8 @@ 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};\${QtQuickPLUGINS}\" \"${TOOLCHAIN_LIB_PATH};\${ADDITIONAL_DIRS}\") + FIXUP_BUNDLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}\" \"\${QTPLUGINS}\" \"${TOOLCHAIN_LIB_PATH};\${ADDITIONAL_DIRS}\") " COMPONENT Runtime) LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtCore.framework") @@ -111,18 +97,13 @@ ELSEIF(APPLE AND NOT IOS) LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtNetwork.framework") 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") - 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") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtPrintSupport.framework") # remove if disabled in Qt + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/Frameworks/QtWebSockets.framework") - FOREACH (OPENSSL_LIBRARY ${OPENSSL_LIBRARIES}) - GET_FILENAME_COMPONENT(OPENSSL_LIBRARY_REAL ${OPENSSL_LIBRARY} REALPATH) - GET_FILENAME_COMPONENT(OPENSSL_LIBRARY_NAME ${OPENSSL_LIBRARY_REAL} NAME) - LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/MacOS/${OPENSSL_LIBRARY_NAME}") - ENDFOREACH() + FETCH_TARGET_LOCATION(opensslCryptoName "OpenSSL::Crypto" NAME) + FETCH_TARGET_LOCATION(opensslSslName "OpenSSL::SSL" NAME) + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/MacOS/${opensslCryptoName}") + LIST(APPEND ADDITIONAL_BUNDLE_FILES_TO_SIGN "/Contents/MacOS/${opensslSslName}") # set it to parent scope to be able to access it from Packaging.cmake SET(ADDITIONAL_BUNDLE_FILES_TO_SIGN ${ADDITIONAL_BUNDLE_FILES_TO_SIGN} PARENT_SCOPE) @@ -154,7 +135,6 @@ ELSEIF(ANDROID) 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") @@ -169,11 +149,6 @@ ELSEIF(ANDROID) 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) @@ -248,18 +223,3 @@ 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 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() - -# default-providers.json -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/default-providers.json DESTINATION ${DEFAULT_FILE_DESTINATION} COMPONENT Runtime) - -# default-supported-devices.json -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/default-supported-devices.json DESTINATION ${DEFAULT_FILE_DESTINATION} COMPONENT Runtime) diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index 8c2e307..f042776 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -1,30 +1,34 @@ # Set CMAKE_PREFIX_PATH with toolchain directory -IF(MINGW)# AND CMAKE_VERSION VERSION_LESS 3.3.0) # see https://public.kitware.com/Bug/view.php?id=15409 +# see https://public.kitware.com/Bug/view.php?id=15409 +IF(MINGW) SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib") ENDIF() -SET(MIN_QT_VERSION 5.8) +SET(MIN_QT_VERSION 5.9) 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(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) - FIND_PACKAGE(Qt5QuickWidgets ${MIN_QT_VERSION} REQUIRED) - FIND_PACKAGE(Qt5PrintSupport ${MIN_QT_VERSION} REQUIRED) IF(WIN32) FIND_PACKAGE(Qt5WinExtras ${MIN_QT_VERSION} REQUIRED) ENDIF() ENDIF() +IF(ANDROID OR IOS OR WINDOWS_STORE OR "${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") + FIND_PACKAGE(Qt5Nfc ${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) +ENDIF() + + IF(LINUX OR ANDROID OR IOS) FIND_PACKAGE(Qt5Bluetooth ${MIN_QT_VERSION} REQUIRED) ENDIF() @@ -58,19 +62,20 @@ IF(MINGW AND NOT CMAKE_CROSSCOMPILING) SET(tmp_crosscompile_enabled TRUE) SET(CMAKE_CROSSCOMPILING ON) ENDIF() -FIND_PACKAGE(OpenSSL 1.0.2 REQUIRED) +IF(QT_VENDOR STREQUAL "Governikus") + FIND_PACKAGE(OpenSSL 1.0.2 REQUIRED) # see openssl_rsa_psk.patch +ELSE() + FIND_PACKAGE(OpenSSL 1.1 REQUIRED) +ENDIF() IF(tmp_crosscompile_enabled) SET(CMAKE_CROSSCOMPILING OFF) ENDIF() IF(ANDROID) - STRING(REPLACE "libssl.so" "libgovssl.so" OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES}") - STRING(REPLACE "libcrypto.so" "libgovcrypto.so" OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES}") - - STRING(REPLACE "libssl.so" "libgovssl.so" OPENSSL_SSL_LIBRARY "${OPENSSL_SSL_LIBRARY}") - STRING(REPLACE "libcrypto.so" "libgovcrypto.so" OPENSSL_CRYPTO_LIBRARY "${OPENSSL_CRYPTO_LIBRARY}") - - MESSAGE(STATUS "Rewrite OPENSSL_LIBRARIES: ${OPENSSL_LIBRARIES}") + GET_TARGET_PROPERTY(CryptoLib OpenSSL::Crypto IMPORTED_LOCATION) + STRING(REPLACE "libcrypto.so" "libgovcrypto.so" CryptoLib "${CryptoLib}") + MESSAGE(STATUS "Rewrite OpenSSL::Crypto: ${CryptoLib}") + SET_TARGET_PROPERTIES(OpenSSL::Crypto PROPERTIES IMPORTED_LOCATION "${CryptoLib}") ENDIF() @@ -117,4 +122,8 @@ ENDIF() IF("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") FIND_PACKAGE(Qt5Test ${MIN_QT_VERSION} REQUIRED) FIND_PACKAGE(Qt5QuickTest ${MIN_QT_VERSION} REQUIRED) + + IF(DESKTOP AND NOT APPLE) + FIND_PACKAGE(Qt5UiPlugin ${MIN_QT_VERSION}) + ENDIF() ENDIF() diff --git a/cmake/Messages.cmake b/cmake/Messages.cmake index 302c577..c149e3c 100644 --- a/cmake/Messages.cmake +++ b/cmake/Messages.cmake @@ -7,17 +7,36 @@ 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}") +MESSAGE(STATUS "CMAKE_SYSROOT_LINK: ${CMAKE_SYSROOT_LINK}") +MESSAGE(STATUS "CMAKE_SYSROOT_COMPILE: ${CMAKE_SYSROOT_COMPILE}") +MESSAGE(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") IF(ANDROID) + FUNCTION(READ_REVISION _var _regex _file) + IF(EXISTS "${_file}") + FILE(READ "${_file}" content) + STRING(REGEX MATCH "${_regex}" _unused "${content}") + SET(${_var} ${CMAKE_MATCH_1} PARENT_SCOPE) + ENDIF() + ENDFUNCTION() + 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_TOOLCHAIN_PREFIX: ${ANDROID_TOOLCHAIN_PREFIX}") + MESSAGE(STATUS "ANDROID_TOOLCHAIN_MACHINE_NAME: ${ANDROID_TOOLCHAIN_MACHINE_NAME}") MESSAGE(STATUS "ANDROID_SDK: ${ANDROID_SDK}") MESSAGE(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}") + READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_NDK}/source.properties") + MESSAGE(STATUS "ANDROID_NDK_REVISION: ${ANDROID_NDK_REVISION}") + + READ_REVISION(ANDROID_SDK_REVISION ".*Revision=([0-9|\\.]+)" "${ANDROID_SDK}/tools/source.properties") + MESSAGE(STATUS "ANDROID_SDK_REVISION: ${ANDROID_SDK_REVISION}") + ELSEIF(IOS) MESSAGE(STATUS "CMAKE_IOS_SDK_ROOT: ${CMAKE_IOS_SDK_ROOT}") MESSAGE(STATUS "CMAKE_IOS_DEVELOPER_ROOT: ${CMAKE_IOS_DEVELOPER_ROOT}") diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index ecaa56a..817cde3 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -71,6 +71,7 @@ LIST(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.cproject") LIST(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.reviewboardrc") LIST(APPEND CPACK_SOURCE_IGNORE_FILES "utils/tlscheck") LIST(APPEND CPACK_SOURCE_IGNORE_FILES "utils/testbedtool") +LIST(APPEND CPACK_SOURCE_IGNORE_FILES "utils/fuzzing") SET(CPACK_MONOLITHIC_INSTALL true) @@ -97,7 +98,7 @@ IF(WIN32) ELSEIF(IOS) FILE(WRITE ${PROJECT_BINARY_DIR}/ipa.cmake " - SET(BUNDLE_DIRS \"\${CONFIG}-iphoneos;UninstalledProducts;UninstalledProducts/iphoneos\") + SET(BUNDLE_DIRS \"\${CONFIG}-iphoneos;\${CONFIG};UninstalledProducts;UninstalledProducts/iphoneos\") FOREACH(dir \${BUNDLE_DIRS}) SET(tmpBundleDir ${PROJECT_BINARY_DIR}/src/\${dir}/${PROJECT_NAME}.app) diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index a6df4de..05db2eb 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -175,66 +175,143 @@ 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 - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 36x36 android/ldpi/npa_preview.png - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 48x48 android/mdpi/npa_preview.png - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 72x72 android/hdpi/npa_preview.png - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 96x96 android/xhdpi/npa_preview.png - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 144x144 android/xxhdpi/npa_preview.png - COMMAND ${CONVERT_CMD} npa_preview.svg -resize 192x192 android/xxxhdpi/npa_preview.png + SET(CONVERT_CMD convert) + SET(BACKGROUND_COLOR "transparent") + + ADD_CUSTOM_TARGET(npaicons.win + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -define icon:auto-resize=256,96,64,48,40,32,24,20,16 npa.svg npa.ico WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.android.preview + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 36x36 npa_preview.svg android/ldpi/npa_preview.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 48x48 npa_preview.svg android/mdpi/npa_preview.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 72x72 npa_preview.svg android/hdpi/npa_preview.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 96x96 npa_preview.svg android/xhdpi/npa_preview.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 144x144 npa_preview.svg android/xxhdpi/npa_preview.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 192x192 npa_preview.svg android/xxxhdpi/npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.android.beta + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 36x36 npa_beta.svg android/ldpi/npa_beta.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 48x48 npa_beta.svg android/mdpi/npa_beta.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 72x72 npa_beta.svg android/hdpi/npa_beta.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 96x96 npa_beta.svg android/xhdpi/npa_beta.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 144x144 npa_beta.svg android/xxhdpi/npa_beta.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 192x192 npa_beta.svg android/xxxhdpi/npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.android + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 36x36 npa.svg android/ldpi/npa.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 48x48 npa.svg android/mdpi/npa.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 72x72 npa.svg android/hdpi/npa.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 96x96 npa.svg android/xhdpi/npa.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 144x144 npa.svg android/xxhdpi/npa.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 192x192 npa.svg android/xxxhdpi/npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.ios.beta + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 29x29 npa_beta.svg iOS/appIcons/beta/iconSmall.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 58x58 npa_beta.svg iOS/appIcons/beta/iconSmall@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 87x87 npa_beta.svg iOS/appIcons/beta/iconSmall@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 40x40 npa_beta.svg iOS/appIcons/beta/iconSmall40.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 80x80 npa_beta.svg iOS/appIcons/beta/iconSmall40@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 120x120 npa_beta.svg iOS/appIcons/beta/iconSmall40@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 120x120 npa_beta.svg iOS/appIcons/beta/icon60@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 180x180 npa_beta.svg iOS/appIcons/beta/icon60@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 76x76 npa_beta.svg iOS/appIcons/beta/icon76.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 152x152 npa_beta.svg iOS/appIcons/beta/icon76@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 167x167 npa_beta.svg iOS/appIcons/beta/icon83.5@2x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.ios + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 29x29 npa.svg iOS/appIcons/iconSmall.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 58x58 npa.svg iOS/appIcons/iconSmall@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 87x87 npa.svg iOS/appIcons/iconSmall@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 40x40 npa.svg iOS/appIcons/iconSmall40.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 80x80 npa.svg iOS/appIcons/iconSmall40@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 120x120 npa.svg iOS/appIcons/iconSmall40@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 120x120 npa.svg iOS/appIcons/icon60@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 180x180 npa.svg iOS/appIcons/icon60@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 76x76 npa.svg iOS/appIcons/icon76.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 152x152 npa.svg iOS/appIcons/icon76@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 167x167 npa.svg iOS/appIcons/icon83.5@2x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + SET(BACKGROUND_COLOR "rgb\(220,235,246\)") + + ADD_CUSTOM_TARGET(npaicons.iphone + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 320x320 -gravity center -extent 640x1136 npa.svg iOS/launchImages/Default-568h@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 320x320 -gravity center -extent 640x1136 npa.svg iOS/launchImages/launchImage568@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 480x480 -gravity center -extent 960x1704 npa.svg iOS/launchImages/launchImage568@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 353x353 -gravity center -extent 705x1334 npa.svg iOS/launchImages/launchImage667@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 563x563 -gravity center -extent 1125x2001 npa.svg iOS/launchImages/launchImage667@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 414x414 -gravity center -extent 828x1472 npa.svg iOS/launchImages/launchImage736@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 621x621 -gravity center -extent 1242x2208 npa.svg iOS/launchImages/launchImage736@3x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons.ipad + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 768x768 -gravity center -extent 2048x1536 npa.svg iOS/launchImages/launchImage1024@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 1152x1152 -gravity center -extent 3072x2304 npa.svg iOS/launchImages/launchImage1024@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 834x834 -gravity center -extent 2224x1668 npa.svg iOS/launchImages/launchImage1112@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 1251x1251 -gravity center -extent 3336x2502 npa.svg iOS/launchImages/launchImage1112@3x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 1024x1024 -gravity center -extent 2732x2048 npa.svg iOS/launchImages/launchImage1366@2x.png + COMMAND ${CONVERT_CMD} -background '${BACKGROUND_COLOR}' -resize 1536x1536 -gravity center -extent 4098x3072 npa.svg iOS/launchImages/launchImage1366@3x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(npaicons DEPENDS npaicons.win npaicons.ios npaicons.ios.beta npaicons.iphone npaicons.ipad npaicons.android npaicons.android.beta npaicons.android.preview) 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 + ADD_CUSTOM_TARGET(pngquant.ios.beta + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall.png -- iOS/appIcons/beta/iconSmall.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall@2x.png -- iOS/appIcons/beta/iconSmall@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall@3x.png -- iOS/appIcons/beta/iconSmall@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall40.png -- iOS/appIcons/beta/iconSmall40.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall40@2x.png -- iOS/appIcons/beta/iconSmall40@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/iconSmall40@3x.png -- iOS/appIcons/beta/iconSmall40@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/icon60@2x.png -- iOS/appIcons/beta/icon60@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/icon60@3x.png -- iOS/appIcons/beta/icon60@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/icon76.png -- iOS/appIcons/beta/icon76.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/icon76@2x.png -- iOS/appIcons/beta/icon76@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/beta/icon83.5@2x.png -- iOS/appIcons/beta/icon83.5@2x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant.ios + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall.png -- iOS/appIcons/iconSmall.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall@2x.png -- iOS/appIcons/iconSmall@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall@3x.png -- iOS/appIcons/iconSmall@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall40.png -- iOS/appIcons/iconSmall40.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall40@2x.png -- iOS/appIcons/iconSmall40@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/iconSmall40@3x.png -- iOS/appIcons/iconSmall40@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/icon60@2x.png -- iOS/appIcons/icon60@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/icon60@3x.png -- iOS/appIcons/icon60@3x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/icon76.png -- iOS/appIcons/icon76.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/icon76@2x.png -- iOS/appIcons/icon76@2x.png + COMMAND ${PNGQUANT_CMD} iOS/appIcons/icon83.5@2x.png -- iOS/appIcons/icon83.5@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/Default-568h@2x.png -- iOS/launchImages/Default-568h@2x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant.iphone + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage568@2x.png -- iOS/launchImages/launchImage568@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage568@3x.png -- iOS/launchImages/launchImage568@3x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage667@2x.png -- iOS/launchImages/launchImage667@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage667@3x.png -- iOS/launchImages/launchImage667@3x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage736@2x.png -- iOS/launchImages/launchImage736@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage736@3x.png -- iOS/launchImages/launchImage736@3x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant.ipad + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1024@2x.png -- iOS/launchImages/launchImage1024@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1024@3x.png -- iOS/launchImages/launchImage1024@3x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1112@2x.png -- iOS/launchImages/launchImage1112@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1112@3x.png -- iOS/launchImages/launchImage1112@3x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1366@2x.png -- iOS/launchImages/launchImage1366@2x.png + COMMAND ${PNGQUANT_CMD} iOS/launchImages/launchImage1366@3x.png -- iOS/launchImages/launchImage1366@3x.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant.android.preview COMMAND ${PNGQUANT_CMD} android/ldpi/npa_preview.png -- android/ldpi/npa_preview.png COMMAND ${PNGQUANT_CMD} android/mdpi/npa_preview.png -- android/mdpi/npa_preview.png COMMAND ${PNGQUANT_CMD} android/hdpi/npa_preview.png -- android/hdpi/npa_preview.png @@ -242,6 +319,41 @@ SET(PNGQUANT_CMD pngquant -f -o) COMMAND ${PNGQUANT_CMD} android/xxhdpi/npa_preview.png -- android/xxhdpi/npa_preview.png COMMAND ${PNGQUANT_CMD} android/xxxhdpi/npa_preview.png -- android/xxxhdpi/npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant.android.beta + 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) + + ADD_CUSTOM_TARGET(pngquant.android + 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 + WORKING_DIRECTORY ${RESOURCES_DIR}/images) + + ADD_CUSTOM_TARGET(pngquant DEPENDS pngquant.ios pngquant.ios.beta pngquant.iphone pngquant.ipad pngquant.android pngquant.android.beta pngquant.android.preview) +ENDIF() + +IF(NOT JAVA_EXECUTABLE) + FIND_PACKAGE(Java COMPONENTS Runtime) + IF(Java_JAVA_EXECUTABLE) + SET(JAVA_EXECUTABLE "${Java_JAVA_EXECUTABLE}") + ENDIF() +ENDIF() +IF(JAVA_EXECUTABLE) + FIND_FILE(PLANTUML plantuml.jar PATHS ENV HOME NO_DEFAULT_PATH) + IF(PLANTUML) + MESSAGE(STATUS "Target uml.statemachines is available using: ${PLANTUML}") + CONFIGURE_FILE(${RESOURCES_DIR}/statemachine.sh.in ${PROJECT_BINARY_DIR}/statemachine.sh @ONLY) + ADD_CUSTOM_TARGET(uml.statemachines COMMAND ./statemachine.sh WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + ENDIF() ENDIF() INCLUDE(Sphinx) diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index ce73809..afb1d11 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -15,3 +15,7 @@ IF(CMAKE_ANDROID_ARCH_ABI MATCHES "arm64-v8a") ELSE() SET(CMAKE_SYSTEM_VERSION 18) ENDIF() + +SET(CMAKE_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH} CACHE string "android find search path root") +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/cmake/cmd.cmake b/cmake/cmd.cmake new file mode 100644 index 0000000..935cf71 --- /dev/null +++ b/cmake/cmd.cmake @@ -0,0 +1,52 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0) + +########################################### +#### Usage: cmake -DCMD= -P cmake/cmd.cmake +########################################### + +FUNCTION(MESSAGE type) + IF(ARGV0 STREQUAL "STDOUT") + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E echo "${ARGN}") + ELSE() + _MESSAGE(${type} "${ARGN}") + ENDIF() +ENDFUNCTION() + + +FUNCTION(CREATE_HASH) + IF(NOT FILES) + MESSAGE(FATAL_ERROR "You need to specify 'FILES'") + ENDIF() + + IF(NOT ALGORITHM) + SET(ALGORITHM SHA256) + ENDIF() + STRING(TOLOWER "${ALGORITHM}" HASHFILE_ENDING) + + FILE(GLOB GLOBBED_FILES RELATIVE "${CMAKE_CURRENT_BINARY_DIR}" "${FILES}") + + FOREACH(f ${GLOBBED_FILES}) + FILE(${ALGORITHM} ${f} fHash) + SET(OUTPUT "${fHash} ${f}") + MESSAGE(STDOUT ${OUTPUT}) + IF(CREATE_FILE) + FILE(WRITE ${f}.${HASHFILE_ENDING} "${OUTPUT}\n") + ENDIF() + ENDFOREACH() +ENDFUNCTION() + + + + + + + +IF(NOT CMD) + MESSAGE(FATAL_ERROR "You need to specify 'CMD'") +ENDIF() + +IF(CMD STREQUAL "HASH") + CREATE_HASH() +ELSE() + MESSAGE(FATAL_ERROR "Unknown CMD: ${CMD}") +ENDIF() diff --git a/cmake/iOS.toolchain.cmake b/cmake/iOS.toolchain.cmake index 887f15e..e1968f1 100644 --- a/cmake/iOS.toolchain.cmake +++ b/cmake/iOS.toolchain.cmake @@ -166,7 +166,7 @@ set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS su # set the architecture for iOS if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7 arm64) + set (IOS_ARCH arm64) elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") set (IOS_ARCH i386) elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") diff --git a/docs/releasenotes/1.14.0.rst b/docs/releasenotes/1.14.0.rst new file mode 100644 index 0000000..683b160 --- /dev/null +++ b/docs/releasenotes/1.14.0.rst @@ -0,0 +1,42 @@ +AusweisApp2 1.14.0 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 20. Dezember 2017 + + + +Anwender +"""""""" + - Eine neue Funktion ermöglicht die Verwendung eines + geeigneten Smartphones als Kartenlesegerät über WLAN. + + - Umstellmöglichkeit der Sprache zur Laufzeit ermöglicht. + + - Fortschrittsanzeige unter Windows im Taskbar-Button. + + - Verbesserungen bei der Erstellung von PDFs. + + - Speicherung der Protokolldateien verbessert. + + - Einstellungsbereich für das Verwalten von + Kartenlesegeräten hinzugefügt. + + - Grafiken der Kartenlesegeräte erneuert und erweitert. + + - Unter macOS wird die Bandbreite im WLAN nicht mehr + beeinträchtigt. + + - Beim Ausweisen ohne aktivierte Online-Ausweisfunktion wurde + fälschlicherweise nach der PUK gefragt. + + - Unter Windows 10 kommt es nicht mehr zu einem Absturz + bei Proxies mit Passwort-Authentisierung. + + +Entwickler +"""""""""" + - Aktualisierung von OpenSSL auf die Version 1.0.2n. + + - Aktualisierung von Qt auf die Version 5.9.3. + + - Unterstützung von OpenSSL 1.1.0. diff --git a/docs/releasenotes/appcast.rst b/docs/releasenotes/appcast.rst index 46d29c7..a81a1ae 100644 --- a/docs/releasenotes/appcast.rst +++ b/docs/releasenotes/appcast.rst @@ -4,10 +4,6 @@ Release Notes .. toctree:: :maxdepth: 1 - 1.12.4 - 1.12.3 - 1.12.2 - 1.12.1 - 1.12.0 + 1.14.0 announce issues diff --git a/docs/releasenotes/general.rst b/docs/releasenotes/general.rst index fb51694..b656bf6 100644 --- a/docs/releasenotes/general.rst +++ b/docs/releasenotes/general.rst @@ -5,7 +5,7 @@ Die AusweisApp2 ist eine Software, die Sie auf Ihrem Computer installieren, um s Ihrem Personalausweis bzw. Ihrem elektronischen Aufenthaltstitel online auszuweisen. Für die Nutzung der Online-Ausweisfunktion benötigen die Nutzerinnen und Nutzer eine -Software, mit deren Hilfe eine sichere Verbindung zwischen Kartenlesegerät, +Software, mit deren Hilfe eine sichere Verbindung zwischen Kartenlesegerät oder Smartphone, Personalausweis und eID-Diensteanbieter hergestellt werden kann. Sie ermöglicht den verschlüsselten Datenaustausch zwischen Personalausweis und eID-Dienst. diff --git a/docs/releasenotes/issues.rst b/docs/releasenotes/issues.rst index 9cda8b6..3f80fb1 100644 --- a/docs/releasenotes/issues.rst +++ b/docs/releasenotes/issues.rst @@ -7,14 +7,7 @@ Die nachfolgende Liste bezieht sich auf die aktuelle Version der AusweisApp2. es bei Benutzern mit eingeschränkten Berechtigungen zu Problemen mit der Online-Ausweisfunktion kommen. - - Bei Erhöhung der Schriftgröße über 175% kommt es zu Darstellungsfehlern. - - - Wenn unter OS X ein Kartenleser mit aufliegendem Ausweisdokument - angeschlossen wird und eine Selbstauskunft angestartet wurde, kann unter - Umständen die AusweisApp2 einfrieren. - - - Beim Ausweisen ohne aktivierte Online-Ausweisfunktion wird derzeit - fälschlicherweise nach der PUK gefragt. + - Bei Erhöhung der Schriftgröße über 175% kommt es zur Nutzungseinschränkung. - Derzeit kommt es noch zu leichten Schwierigkeiten bei der Bedienbarkeit mit der Tastatur. @@ -25,8 +18,12 @@ Die nachfolgende Liste bezieht sich auf die aktuelle Version der AusweisApp2. - Bei Verwendung des Screenreaders JAWS unter Windows, kann es zu leichten Irritationen bei der angegebenen Bedienung kommen. - - Unter Mac OS im WLAN kann die Bandbreite beeinträchtigt werden, wenn die - AusweisApp2 im Hintergrund läuft. + - Wenn die AusweisApp2 heruntergefahren wird, während eine Authentisierung + oder eine PIN-Änderung mit Komfort-Kartenlesegerät durchgeführt wird, + kann es unter Windows und macOS zu einem Absturz kommen. - - Unter Mac OS kommt es vereinzelt zu Problemen bei der Verwendung des Kobil - ID Token. + - Die PIN-Änderung über ein Smartphone als Kartenlesegerät wird nicht + unterstützt. + + - Unter Umständen kommt es zu Stabilitätsproblemen der NFC-Schnittstelle + auf Android. diff --git a/docs/releasenotes/support.rst b/docs/releasenotes/support.rst index 7ffc2f0..a234ca3 100644 --- a/docs/releasenotes/support.rst +++ b/docs/releasenotes/support.rst @@ -8,14 +8,14 @@ der AusweisApp2 unterstützt. Betriebssysteme """"""""""""""" - - OS X 10.9 - - OS X 10.10 - OS X 10.11 - macOS 10.12 + - macOS 10.13 + - Windows 7 SP1 (32bit / 64bit) - Windows 8.1 (64bit) @@ -48,13 +48,13 @@ und sollte daher mit allen marktüblichen Browsern verwendet werden können. Im Rahmen der Qualitätssicherung werden die folgenden Browserversionen getestet. - - Firefox 55 + - Firefox 57 - - Chrome 61 + - Chrome 62 - Internet Explorer 11 - - Safari 10 + - Safari 11 @@ -90,6 +90,13 @@ Zusätzlich werden folgende nicht zertifizierte Kartenleser getestet. Aktuelle Informationen zu Kartenlesern finden Sie auf unserer Webseite: https://www.ausweisapp.bund.de/fragen-und-antworten/voraussetzungen/ +Alle NFC-fähigen Smartphones bzw. Tablets, die die Onlineausweisfunktionalität +unterstützen, können als Kartenlesegerät verwendet werden. +Dabei ist es notwendig die mobile AusweisApp2 auf dem jeweiligen Smartphone +zu installieren und zu starten. + +Details hierzu befinden sich auf der Homepage: +https://www.ausweisapp.bund.de/mobile-geraete/ Android @@ -105,9 +112,9 @@ Im mobilen Umfeld ist die Funktionalität jedoch abhängig von der vom Diensteanbieter umgesetzten Aktivierung. Daher empfehlen wir einen der folgenden Browser zu verwenden. - - Firefox Klar 1.3 + - Firefox Klar 2.5 - - Chrome 61 + - Chrome 63 - Android System WebView 60 @@ -119,6 +126,10 @@ Alle NFC-fähigen Smartphones bzw. Tablets, die die Onlineausweisfunktionalität unterstützen. Details hierzu befinden sich auf der Homepage: https://www.ausweisapp.bund.de/mobile-geraete/ +Ebenfalls ist es möglich ein weiteres Smartphone als Kartenlesegerät zu +verwenden. Dabei ist es notwendig die mobile AusweisApp2 auf dem jeweiligen +Smartphone zu installieren und zu starten. + Darüber hinaus ist die Verwendung eines Bluetooth-Kartenlesegeräts möglich. Folgendes Bluetooth-Kartenlesegerät wird von der AusweiApp2 unterstützt: diff --git a/docs/releasenotes/versions.rst b/docs/releasenotes/versions.rst index 4c6b8a7..99a38d4 100644 --- a/docs/releasenotes/versions.rst +++ b/docs/releasenotes/versions.rst @@ -1,6 +1,14 @@ Versionen ========= +Versionszweig 1.14 +------------------ +.. toctree:: + :maxdepth: 1 + + 1.14.0 + + Versionszweig 1.12 ------------------ .. toctree:: diff --git a/docs/sdk/android.rst b/docs/sdk/android.rst index 22e5b9f..997c897 100644 --- a/docs/sdk/android.rst +++ b/docs/sdk/android.rst @@ -65,6 +65,11 @@ JSON messages from the SDK. Furthermore it has a function which is called when an existing connection with the SDK is dropped by the SDK. Both interfaces are listed below and you need to import them into your build environment. +.. important:: + It is required that you place the AIDL files under subdirectory + "aidl/com.governikus.ausweisapp2". Also the interface methods + names must be exactly the same. + .. seealso:: https://developer.android.com/guide/components/aidl.html @@ -125,7 +130,7 @@ fingerprint of the authentic SDK certificate is the following: .. code-block:: text - B0 2A C7 6B 50 A4 97 AE 81 0A EA C2 25 98 18 7B 3D 42 90 27 7D 08 51 A7 FA 8E 1A EA 5A 97 98 70 + B0:2A:C7:6B:50:A4:97:AE:81:0A:EA:C2:25:98:18:7B:3D:42:90:27:7D:08:51:A7:FA:8E:1A:EA:5A:97:98:70 @@ -143,7 +148,7 @@ hash value of a signed application on Android can be verified. public class AusweisApp2Validator { private static final String PACKAGE = "com.governikus.ausweisapp2"; - private static final String FINGERPRINT = "..." // see above; + private static final String FINGERPRINT = "..."; // see above public boolean isValid() { @@ -188,17 +193,15 @@ To differentiate between different connected clients, virtual sessions are used once the binding is completed. These sessions are discussed in a separate section, section :ref:`android_create_session`. -.. seealso:: - :ref:`android_disconnect_sdk` - Create connection ^^^^^^^^^^^^^^^^^ -First of all, in order to bind to the service, one needs to instantiate -an Android ServiceConnection. Subsequently, the object is passed to the -Android API and the contained methods are invoked by Android on service -connection and disconnection. +First of all, in order to bind to the service, one needs to instantiate an +Android ServiceConnection. +Subsequently, the object is passed to the Android API and the contained +methods are invoked +by Android on service connection and disconnection. .. code-block:: java @@ -226,12 +229,13 @@ connection and disconnection. Bind service to raw connection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In order to perform the actual binding a directed Intent, which -identifies the AusweisApp2 SDK, is created. This Intent is send -to the Android API along with the ServiceConnection created above. +In order to perform the actual binding a directed Intent, which identifies +the AusweisApp2 SDK, is created. +This Intent is send to +the Android API along with the ServiceConnection created above. This API call either starts up the SDK if it is the first client, -or connects to the running SDK instance if there is already -another client bound. +or connects to the running SDK instance +if there is already another client bound. .. code-block:: java @@ -472,14 +476,15 @@ The **receive** method is called each time the SDK sends a message. :ref:`android_create_session` - .. _android_disconnect_sdk: Disconnect from SDK ------------------- In order to disconnect from the AusweisApp2 SDK you need to invalidate your -instance of **IBinder**. You can unbind from the SDK Android service to undo -your binding, like shown in the code listing below. +instance of **IBinder**. There are two possibilities to do this. The first +one is to unbind from the SDK Android service to undo your binding, like +shown in the code listing below. The second one is to return false in the +**pingBinder** function of your IBinder instance. .. code-block:: java @@ -670,10 +675,7 @@ are shown in code listing below. } } - -This class must now be added to the activity: - -.. code-block:: java + // [...] ForegroundDispatcher mDispatcher = new ForegroundDispatcher(this); diff --git a/docs/sdk/workflow.rst b/docs/sdk/workflow.rst index 00c8980..1ef2145 100644 --- a/docs/sdk/workflow.rst +++ b/docs/sdk/workflow.rst @@ -104,7 +104,7 @@ We assume that the user did not connect the card reader. {"cmd": "CANCEL"} - {"msg": "AUTH", "result": {"description":"The operation was aborted due to cancellation by user.","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"},"url":"https://test.governikus-eid.de/DEMO/?errID=123456"} + {"msg": "AUTH", "result": {"description":"The process was cancelled by the user.","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"},"url":"https://test.governikus-eid.de/DEMO/?errID=123456"} @@ -134,5 +134,5 @@ We assume that the user did not connect the card reader. {"cmd": "CANCEL"} - {"msg": "AUTH", "result": {"description":"The operation was aborted due to cancellation by user.","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"},"url":"https://test.governikus-eid.de/DEMO/?errID=123456"} + {"msg": "AUTH", "result": {"description":"The process was cancelled by the user.","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"},"url":"https://test.governikus-eid.de/DEMO/?errID=123456"} diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index df6f39c..84f81c5 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.3.0) +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) IF(POLICY CMP0010) CMAKE_POLICY(SET CMP0010 NEW) @@ -19,6 +19,13 @@ INCLUDE(ExternalProject) INCLUDE(Helper) INCLUDE(DVCS) +IF(ANDROID) + GET_ANDROID_TOOLCHAIN_VARS(ANDROID_TOOLCHAIN_PREFIX ANDROID_TOOLCHAIN_MACHINE_NAME) + IF(CMAKE_SYSROOT_COMPILE) + SET(UNIFIED_INCLUDE ${CMAKE_SYSROOT_COMPILE}/usr/include) + ENDIF() +ENDIF() + ADD_FLAG(-fstack-protector-strong -fstack-protector NOQUOTES VAR COMPILER_FLAGS) @@ -97,11 +104,11 @@ INCLUDE(Messages) ################################## Versionen -SET(QT 5.8.0) -SET(QT_HASH 0f4c54386d3dbac0606a936a7145cebb7b94b0ca2d29bc001ea49642984824b6) +SET(QT 5.9.3) +SET(QT_HASH 57acd8f03f830c2d7dc29fbe28aaa96781b2b9bdddce94196e6761a0f88c6046) -SET(OPENSSL 1.0.2k) -SET(OPENSSL_HASH 6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0) +SET(OPENSSL 1.0.2n) +SET(OPENSSL_HASH 370babb75f278c39e0c50e8c4e7493bc0f18db6867478341a832a982fd15a8fe) ################################## Files SET(QT_FILE qt-everywhere-opensource-src-${QT}.tar.xz) @@ -115,7 +122,7 @@ ELSE() ENDIF() STRING(SUBSTRING ${QT} 0 3 QT_SUBVERSION) -SET(QT_URL http://download.qt.io/${QT_DEST_DIR}/qt/${QT_SUBVERSION}/${QT}/single) +SET(QT_URL https://download.qt.io/${QT_DEST_DIR}/qt/${QT_SUBVERSION}/${QT}/single) SET(OPENSSL_URL https://www.openssl.org/source) IF(ANDROID OR APPLE) @@ -127,24 +134,6 @@ IF(ANDROID OR APPLE) ENDIF() ENDIF() -################################## Android NDK /SDK -######################################################################### - -IF(ANDROID) - 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() -ENDIF() - -IF(IOS) - SET(HOST --host=arm-apple-darwin7) - SET(HOST64 --host=aarch64-apple-darwin) - SET(IOS_ARCH armv7) - SET(IOS_ARCH64 arm64) -ENDIF() SET(ENABLED_TARGETS) @@ -157,10 +146,11 @@ SET(OPENSSL_CONFIGURE_FLAGS no-ssl2 no-ssl3 no-ssl3-method no-dtls no-srp no-ide IF(IOS) SET(OPENSSL_PATCH_COMMAND ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/openssl_iOS.patch && ) SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} iphoneos-cross) - SET(OPENSSL_PATCH_AFTER_CONFIGURE ${SH_CMD} ${PATCHES_DIR}/openssl_iOS_perl.sh ${CMAKE_IOS_SDK_ROOT} &&) + SET(OPENSSL_ENV export CROSS_TOP=${CMAKE_IOS_DEVELOPER_ROOT} && export CROSS_SDK=iPhoneOS.sdk &&) + SET(OPENSSL_COMPILER_FLAGS "-arch arm64") ELSEIF(APPLE) SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} darwin64-x86_64-cc) - #SET(OPENSSL_PATCH_AFTER_CONFIGURE ${SH_CMD} ${PATCHES_DIR}/openssl_MacOS_perl.sh &&) + SET(COMPILER_FLAGS "${COMPILER_FLAGS} -mmacosx-version-min=10.9") ELSEIF(MINGW) SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} mingw) ELSEIF(MSVC) @@ -181,19 +171,25 @@ ELSEIF(ANDROID) ENDIF() SET(OPENSSL_ENV export ANDROID_DEV=${CMAKE_SYSROOT}/usr &&) + IF(UNIFIED_INCLUDE) + SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} -D__ANDROID_API__=${CMAKE_SYSTEM_VERSION} -isystem${UNIFIED_INCLUDE} -isystem${UNIFIED_INCLUDE}/${ANDROID_TOOLCHAIN_MACHINE_NAME}) + ENDIF() 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) SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} BSD-x86_64) ELSEIF(LINUX) - SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} linux-x86_64) + IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686") + SET(OPENSSL_ARCH linux-generic32) + ELSE() + SET(OPENSSL_ARCH linux-x86_64) + ENDIF() + SET(OPENSSL_CONFIGURE_FLAGS ${OPENSSL_CONFIGURE_FLAGS} ${OPENSSL_ARCH}) ELSE() MESSAGE(FATAL_ERROR "Unsupported system") ENDIF() IF(NOT OPENSSL_PREBUILD) - SET(OPENSSL_PREBUILD ${OPENSSL_PATCH_AFTER_CONFIGURE} ${MAKE} depend) + SET(OPENSSL_PREBUILD ${MAKE} depend) ENDIF() IF(NOT OPENSSL_INSTALL_TARGET) @@ -201,42 +197,6 @@ IF(NOT OPENSSL_INSTALL_TARGET) ENDIF() # OpenSSL does not support multiple make jobs! -IF(IOS) - ExternalProject_Add(openssl64 - URL ${OPENSSL_URL}/${OPENSSL_FILE} - URL_HASH SHA256=${OPENSSL_HASH} - DOWNLOAD_DIR ${PACKAGES_DIR} - - 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}" - BUILD_COMMAND ${OPENSSL_PATCH_AFTER_CONFIGURE} ${MAKE} depend && ${MAKE} - BUILD_IN_SOURCE 1 - INSTALL_COMMAND ${MAKE} install_sw - ) - - ExternalProject_Add(openssl - DEPENDS openssl64 - URL ${OPENSSL_URL}/${OPENSSL_FILE} - URL_HASH SHA256=${OPENSSL_HASH} - DOWNLOAD_DIR ${PACKAGES_DIR} - - 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}" - BUILD_COMMAND ${OPENSSL_PATCH_AFTER_CONFIGURE} ${MAKE} depend && ${MAKE} - BUILD_IN_SOURCE 1 - INSTALL_COMMAND ${MAKE} install_sw - ) - - ADD_CUSTOM_COMMAND(TARGET openssl POST_BUILD COMMAND ${SH_CMD} ${PATCHES_DIR}/create_multi_architecture_build.sh ${PROJECT_BINARY_DIR}/openssl-prefix/tmp ${PROJECT_BINARY_DIR}/openssl64-prefix/tmp ${DESTINATION_DIR}) -ELSE() ExternalProject_Add(openssl URL ${OPENSSL_URL}/${OPENSSL_FILE} URL_HASH SHA256=${OPENSSL_HASH} @@ -258,7 +218,6 @@ ExternalProject_Add_Step(openssl prebuild DEPENDEES configure DEPENDERS build WORKING_DIRECTORY ) -ENDIF() IF(UNIX) ADD_CUSTOM_COMMAND(TARGET openssl POST_BUILD COMMAND chmod 755 ${DESTINATION_DIR}/lib/libssl*${CMAKE_SHARED_LIBRARY_SUFFIX} ${DESTINATION_DIR}/lib/libcrypto*${CMAKE_SHARED_LIBRARY_SUFFIX}) @@ -287,9 +246,18 @@ ELSE() SET(QT_CONFIGURE_FLAGS -release -no-qml-debug) ENDIF() + 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) + +LIST(APPEND NO_FEATURES bearermanagement ftp paint_debug) +LIST(APPEND NO_FEATURES imageformat_bmp imageformat_ppm imageformat_xbm) +LIST(APPEND NO_FEATURES sharedmemory textodfwriter) +FOREACH(feature ${NO_FEATURES}) + SET(QT_CONFIGURE_FLAGS ${QT_CONFIGURE_FLAGS} -no-feature-${feature}) +ENDFOREACH() + 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_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 -skip qtwayland -skip qtremoteobjects -skip qtspeech -skip qtwebview) SET(QT_CONFIGURE ./configure) IF(IOS) @@ -339,17 +307,12 @@ ExternalProject_Add(qt PATCH_COMMAND ${QT_PATCH_COMMAND} ${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 && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Register-additional-meta-types.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Change-build-configuration-for-Qt-on-iOS.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Disable-unused-imageformats.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Avoid-using-deprecated-APIs-on-iOS-10.0.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-Add-IsoDep-to-the-techList-on-Android.patch && + ${PATCH_CMD} -p1 ${PATCH_OPTIONS} ${PATCHES_DIR}/qt-macOS-iOS-Fix-garbled-text-under-some-conditions.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} diff --git a/libs/README.rst b/libs/README.rst index 664a75a..aa4d77a 100644 --- a/libs/README.rst +++ b/libs/README.rst @@ -17,7 +17,7 @@ Unterstützte Compiler: Notwendige Bibliotheken: -- Qt >= 5.8 +- Qt >= 5.9 - http://www.qt.io/download/ @@ -31,12 +31,12 @@ Notwendige Bibliotheken: - openssl_rsa_psk.patch -- pcsclite >= 1.8 (nur Linux) +- pcsclite >= 1.8 (nur Linux/FreeBSD) Notwendige Tools: -- CMake >= 3.3.0 (>= 3.7.1 für Android) +- CMake >= 3.5.0 (>= 3.7.1 für Android) - http://www.cmake.org @@ -221,7 +221,7 @@ Komponenten vorhanden sein: 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. - - Getestet: 26.0.1 + - Getestet: 27.0.1 - Um Qt erfolgreich zu bauen, sind verschiedene API Level von Android notwendig. Diese sollten mindestens Level 18 und 21 sein. Nähere Informationen dazu diff --git a/patches/create_multi_architecture_build.sh b/patches/create_multi_architecture_build.sh deleted file mode 100755 index b4d2aa9..0000000 --- a/patches/create_multi_architecture_build.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -DIR=$1 -DIR64=$2 -PREFIX_PATH=$3 - -# -# Copy content of all folders except the library files -# -echo "Copy content to ${PREFIX_PATH}:" -for dir in ${DIR}/* ; do - if [ -d $dir ] - then - dirname=$(basename "$dir") - if [ "$dirname" != "lib" ] - then - echo "* Copy content of ${dir}" - mkdir -p ${PREFIX_PATH}/${dirname} - cp -R ${dir}/* ${PREFIX_PATH}/${dirname} - fi - fi -done - -# -# Make multi-architecture libraries -# -echo "Create multi-architecture libraries in ${PREFIX_PATH}/lib:" -mkdir -p ${PREFIX_PATH}/lib -cd ${PREFIX_PATH}/lib -for file in ${DIR}/lib/* ; do - filename=$(basename "$file") - - if [[ ( $filename == *.dylib ) || ( $filename == *.a ) ]] - then - if [ -h $file ] - then - # create symbolic links for multi-architecture library - - resolvedfilename=$(readlink "$file") - echo "* Create sym link ${filename}" - ln -s ${resolvedfilename} ${filename} - else - # create multi-architecture library - - file64=${DIR64}/lib/${filename} - if [ -f $file64 ] - then - echo "* Create lib ${filename}" - lipo $file $file64 -create -output ${filename} - else - echo "* 64bit library not found ${file64}" - fi - fi - elif [[ ( $filename == pkgconfig ) ]] - then - - mkdir -p ${PREFIX_PATH}/lib/pkgconfig - for configfile in ${DIR}/lib/pkgconfig/* ; do - configfilename=$(basename "$configfile") - sed "s:${DIR}:${PREFIX_PATH}:g" "$configfile" > pkgconfig/${configfilename} - echo "* Copy adapted package config file ${configfilename}" - done - elif [ -f $file ] - then - echo "* Skip file ${filename}" - else - echo "* Skip directory ${filename}" - fi -done - diff --git a/patches/openssl-fix-no-engine-build.patch b/patches/openssl-fix-no-engine-build.patch index 0d574f8..c7b24ea 100644 --- a/patches/openssl-fix-no-engine-build.patch +++ b/patches/openssl-fix-no-engine-build.patch @@ -1,4 +1,4 @@ -From 08b250d56592b8e385cfc37c2d938b839653c264 Mon Sep 17 00:00:00 2001 +From aeae7469061c1675d651224789fc664d6809b0d9 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 @@ -11,10 +11,10 @@ Reviewed-by: Richard Levitte 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 +diff --git x/crypto/ts/ts.h y/crypto/ts/ts.h +index 2daa1b2fb5..fc8c14b2d0 100644 +--- x/crypto/ts/ts.h ++++ y/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, @@ -27,10 +27,10 @@ index 2daa1b2fb..fc8c14b2d 100644 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 +diff --git x/util/libeay.num y/util/libeay.num +index fddfe1cbb2..a76424ceab 100755 +--- x/util/libeay.num ++++ y/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: @@ -49,15 +49,15 @@ index 2094ab364..23ade08e2 100755 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 +diff --git x/util/mk1mf.pl y/util/mk1mf.pl +index 6b31496ed1..ccfb24ca55 100755 +--- x/util/mk1mf.pl ++++ y/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\" +- \$(CP) \$(E_SHLIB) \"\$(INSTALLTOP)${o}lib${o}engines\" EOF } } @@ -71,5 +71,5 @@ index 7a3ae11f7..6ada6fa62 100755 exe: \$(T_EXE) \$(BIN_D)$o\$(E_EXE)$exep -- -2.11.0 +2.15.0 diff --git a/patches/openssl_MacOS_perl.sh b/patches/openssl_MacOS_perl.sh deleted file mode 100755 index 9e875b2..0000000 --- a/patches/openssl_MacOS_perl.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -echo "Patching..." - -perl -i -pe "s|^MAKEDEPPROG=makedepend|MAKEDEPPROG= \\\$(CC) -M|g" Makefile diff --git a/patches/openssl_iOS_perl.sh b/patches/openssl_iOS_perl.sh deleted file mode 100755 index 4d75e45..0000000 --- a/patches/openssl_iOS_perl.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -echo "Patching..." - -SDK=$1 -echo "SDK: ${SDK}" - -perl -i -pe "s|^CC= (.*)|CC= \$1 -miphoneos-version-min=7.1|g" Makefile -perl -i -pe "s|^MAKEDEPPROG=makedepend|MAKEDEPPROG= \\\$(CC) -M|g" Makefile -perl -i -pe "s|isysroot\s\S+\s|isysroot ${SDK} |g" Makefile diff --git a/patches/openssl_rsa_psk.patch b/patches/openssl_rsa_psk.patch index 05c2f66..80d3cad 100644 --- a/patches/openssl_rsa_psk.patch +++ b/patches/openssl_rsa_psk.patch @@ -1,4 +1,4 @@ -From 496ac24b811593df82490643d574a037aa47d80e Mon Sep 17 00:00:00 2001 +From e681bc2125a396ff34aab4c3f629683dd0ce28bb 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 @@ -12,21 +12,21 @@ This work has been sponsored by Governikus GmbH & Co. KG. PR: 2464 --- doc/apps/ciphers.pod | 12 +++ - ssl/s3_clnt.c | 122 ++++++++++++++++++++++----- + ssl/s3_clnt.c | 106 ++++++++++++++++++++---- ssl/s3_lib.c | 206 +++++++++++++++++++++++++++++++++++++++++++++- - ssl/s3_srvr.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++--- + ssl/s3_srvr.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++--- ssl/ssl.h | 2 + ssl/ssl_ciph.c | 9 +- ssl/ssl_lib.c | 6 ++ ssl/ssl_locl.h | 2 + ssl/tls1.h | 36 ++++++++ - 9 files changed, 587 insertions(+), 35 deletions(-) + 9 files changed, 572 insertions(+), 33 deletions(-) diff --git x/doc/apps/ciphers.pod y/doc/apps/ciphers.pod -index 922455725..234350faa 100644 +index fa16124d08..45db06c168 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. +@@ -585,10 +585,22 @@ Note: these ciphers can also be used in SSL v3. =head2 Pre shared keying (PSK) cipheruites @@ -50,10 +50,10 @@ index 922455725..234350faa 100644 =head2 Deprecated SSL v2.0 cipher suites. diff --git x/ssl/s3_clnt.c y/ssl/s3_clnt.c -index 32f2f1aee..cd05f4d52 100644 +index 5b8b2da59f..ae0d4d840c 100644 --- x/ssl/s3_clnt.c +++ y/ssl/s3_clnt.c -@@ -337,7 +337,7 @@ int ssl3_connect(SSL *s) +@@ -342,7 +342,7 @@ int ssl3_connect(SSL *s) } #endif /* Check if it is anon DH/ECDH, SRP auth */ @@ -62,7 +62,7 @@ index 32f2f1aee..cd05f4d52 100644 if (! (s->s3->tmp. new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) -@@ -1419,9 +1419,9 @@ int ssl3_get_key_exchange(SSL *s) +@@ -1424,9 +1424,9 @@ int ssl3_get_key_exchange(SSL *s) } #ifndef OPENSSL_NO_PSK /* @@ -75,53 +75,30 @@ index 32f2f1aee..cd05f4d52 100644 */ if (alg_k & SSL_kPSK) { s->session->sess_cert = ssl_sess_cert_new(); -@@ -1466,7 +1466,12 @@ int ssl3_get_key_exchange(SSL *s) +@@ -1471,7 +1471,12 @@ int ssl3_get_key_exchange(SSL *s) al = SSL_AD_DECODE_ERROR; #ifndef OPENSSL_NO_PSK - if (alg_k & SSL_kPSK) { + /* handle PSK identity hint */ -+ if (alg_k & (SSL_kPSK ++ if (alg_k & SSL_kPSK +#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK ++ || alg_k & SSL_kRSAPSK +#endif -+ )) { ++ ) { param_len = 2; if (param_len > n) { SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); -@@ -1610,7 +1615,11 @@ int ssl3_get_key_exchange(SSL *s) - } else - #endif /* !OPENSSL_NO_SRP */ - #ifndef OPENSSL_NO_RSA -- if (alg_k & SSL_kRSA) { -+ if (alg_k & (SSL_kRSA -+#ifndef OPENSSL_NO_PSK -+ | SSL_kRSAPSK -+#endif -+ )) { - /* Temporary RSA keys only allowed in export ciphersuites */ - if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { - al = SSL_AD_UNEXPECTED_MESSAGE; -@@ -2034,8 +2043,16 @@ int ssl3_get_key_exchange(SSL *s) - } +@@ -2041,7 +2046,7 @@ int ssl3_get_key_exchange(SSL *s) } } else { -- /* aNULL, aSRP or kPSK do not need public keys */ + /* aNULL, aSRP or kPSK do not need public keys */ - if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_kPSK)) { -+ /* aNULL, aSRP, kPSK or kRSAPSK do not need public keys */ -+ if (!(alg_a & (SSL_aNULL | SSL_aSRP)) -+#ifndef OPENSSL_NO_PSK -+ && !(alg_k & (SSL_kPSK -+#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK -+#endif -+ )) -+#endif -+ ) { ++ if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_kPSK) && !(alg_k & SSL_kRSAPSK)) { /* Might be wrong key type, check it */ if (ssl3_check_cert_and_algorithm(s)) /* Otherwise this shouldn't happen */ -@@ -3124,7 +3141,11 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3130,7 +3135,11 @@ int ssl3_send_client_key_exchange(SSL *s) } #endif #ifndef OPENSSL_NO_PSK @@ -134,7 +111,7 @@ index 32f2f1aee..cd05f4d52 100644 /* * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a * \0-terminated identity. The last byte is for us for simulating -@@ -3132,8 +3153,8 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3138,8 +3147,8 @@ int ssl3_send_client_key_exchange(SSL *s) */ char identity[PSK_MAX_IDENTITY_LEN + 2]; size_t identity_len; @@ -144,7 +121,7 @@ index 32f2f1aee..cd05f4d52 100644 unsigned int pre_ms_len = 0, psk_len = 0; int psk_err = 1; -@@ -3165,14 +3186,34 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3171,14 +3180,34 @@ int ssl3_send_client_key_exchange(SSL *s) ERR_R_INTERNAL_ERROR); goto psk_err; } @@ -187,7 +164,7 @@ index 32f2f1aee..cd05f4d52 100644 if (s->session->psk_identity_hint != NULL) OPENSSL_free(s->session->psk_identity_hint); -@@ -3202,8 +3243,41 @@ int ssl3_send_client_key_exchange(SSL *s) +@@ -3208,8 +3237,41 @@ int ssl3_send_client_key_exchange(SSL *s) pre_ms_len); s2n(identity_len, p); memcpy(p, identity, identity_len); @@ -229,34 +206,34 @@ index 32f2f1aee..cd05f4d52 100644 psk_err: OPENSSL_cleanse(identity, sizeof(identity)); OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); -@@ -3574,7 +3648,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) +@@ -3580,7 +3642,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) } #endif #ifndef OPENSSL_NO_RSA - if (alg_k & SSL_kRSA) { -+ if (alg_k & (SSL_kRSA ++ if (alg_k & SSL_kRSA +#ifndef OPENSSL_NO_PSK -+ | SSL_kRSAPSK ++ || alg_k & SSL_kRSAPSK +#endif -+ )) { ++ ) { 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, -@@ -3641,7 +3719,11 @@ int ssl3_check_cert_and_algorithm(SSL *s) +@@ -3647,7 +3713,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 - if (alg_k & SSL_kRSA) { -+ if (alg_k & (SSL_kRSA ++ if (alg_k & SSL_kRSA +#ifndef OPENSSL_NO_PSK -+ | SSL_kRSAPSK ++ || alg_k & SSL_kRSAPSK +#endif -+ )) { ++ ) { if (rsa == NULL) { 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 0385e039c..ce69ec470 100644 +index 1014a3fce1..0187d508a1 100644 --- x/ssl/s3_lib.c +++ y/ssl/s3_lib.c @@ -1765,6 +1765,74 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[] = { @@ -482,15 +459,15 @@ index 0385e039c..ce69ec470 100644 #ifndef OPENSSL_NO_PSK /* with PSK there must be server callback set */ - if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL) -+ if ((alg_k & (SSL_kPSK | SSL_kRSAPSK)) && s->psk_server_callback == NULL) ++ if ((alg_k & SSL_kPSK || alg_k & SSL_kRSAPSK) && s->psk_server_callback == NULL) continue; #endif /* OPENSSL_NO_PSK */ diff --git x/ssl/s3_srvr.c y/ssl/s3_srvr.c -index ea56f9ca8..2b1797cc8 100644 +index 0fb4845d44..3498836e7d 100644 --- x/ssl/s3_srvr.c +++ y/ssl/s3_srvr.c -@@ -458,19 +458,23 @@ int ssl3_accept(SSL *s) +@@ -467,19 +467,22 @@ int ssl3_accept(SSL *s) /* * only send if a DH key exchange, fortezza or RSA but we have a @@ -513,15 +490,14 @@ index ea56f9ca8..2b1797cc8 100644 - */ #ifndef OPENSSL_NO_PSK - || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) -+ || ((alg_k & (SSL_kPSK ++ || (alg_k & SSL_kPSK && s->ctx->psk_identity_hint) +#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK ++ || (alg_k & SSL_kRSAPSK && s->ctx->psk_identity_hint) +#endif -+ )) && s->ctx->psk_identity_hint) #endif #ifndef OPENSSL_NO_SRP /* SRP: send ServerKeyExchange */ -@@ -526,11 +530,14 @@ int ssl3_accept(SSL *s) +@@ -535,11 +538,14 @@ int ssl3_accept(SSL *s) (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) || /* don't request certificate for SRP auth */ (s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP) @@ -538,49 +514,56 @@ index ea56f9ca8..2b1797cc8 100644 /* no cert request */ skip = 1; s->s3->tmp.cert_request = 0; -@@ -1830,7 +1837,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1835,7 +1841,11 @@ int ssl3_send_server_key_exchange(SSL *s) } else #endif /* !OPENSSL_NO_ECDH */ #ifndef OPENSSL_NO_PSK - if (type & SSL_kPSK) { -+ if (type & (SSL_kPSK ++ if (type & SSL_kPSK +#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK ++ || type & SSL_kRSAPSK +#endif -+ )) { ++ ) { /* * reserve size for record length and PSK identity hint */ -@@ -1879,7 +1890,14 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1884,7 +1894,8 @@ int ssl3_send_server_key_exchange(SSL *s) } if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) - && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { -+#ifndef OPENSSL_NO_PSK -+ && !(s->s3->tmp.new_cipher->algorithm_mkey & (SSL_kPSK -+#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK -+#endif -+ )) -+#endif -+ ) { ++ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) ++ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kRSAPSK)) { if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md)) == NULL) { al = SSL_AD_DECODE_ERROR; -@@ -1953,7 +1971,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1899,6 +1910,12 @@ int ssl3_send_server_key_exchange(SSL *s) + } else { + pkey = NULL; + kn = 0; ++ /* Allow space for signature algorithm */ ++ if (SSL_USE_SIGALGS(s)) { ++ kn += 4; ++ const unsigned char *sig; ++ kn += tls12_get_psigalgs(s, 1, &sig); ++ } + } + + if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) { +@@ -1958,7 +1975,11 @@ int ssl3_send_server_key_exchange(SSL *s) #endif #ifndef OPENSSL_NO_PSK - if (type & SSL_kPSK) { -+ if (type & (SSL_kPSK ++ if (type & SSL_kPSK +#ifndef OPENSSL_NO_RSA -+ | SSL_kRSAPSK ++ || type & SSL_kRSAPSK +#endif -+ )) { ++ ) { /* copy PSK identity hint */ s2n(strlen(s->ctx->psk_identity_hint), p); strncpy((char *)p, s->ctx->psk_identity_hint, -@@ -1969,7 +1991,11 @@ int ssl3_send_server_key_exchange(SSL *s) +@@ -1974,7 +1995,11 @@ int ssl3_send_server_key_exchange(SSL *s) * points to the space at the end. */ #ifndef OPENSSL_NO_RSA @@ -593,7 +576,7 @@ index ea56f9ca8..2b1797cc8 100644 q = md_buf; j = 0; for (num = 2; num > 0; num--) { -@@ -2843,6 +2869,181 @@ int ssl3_get_client_key_exchange(SSL *s) +@@ -2870,6 +2895,181 @@ int ssl3_get_client_key_exchange(SSL *s) goto f_err; } else #endif @@ -776,7 +759,7 @@ index ea56f9ca8..2b1797cc8 100644 if (alg_k & SSL_kSRP) { int param_len; diff --git x/ssl/ssl.h y/ssl/ssl.h -index 90aeb0ce4..78cf2212e 100644 +index 90aeb0ce4e..78cf2212ed 100644 --- x/ssl/ssl.h +++ y/ssl/ssl.h @@ -254,6 +254,7 @@ extern "C" { @@ -796,7 +779,7 @@ index 90aeb0ce4..78cf2212e 100644 # define SSL_TXT_DES "DES" diff --git x/ssl/ssl_ciph.c y/ssl/ssl_ciph.c -index 2ad8f4392..33f6da1be 100644 +index ccdf00fa1b..19c4ac0656 100644 --- x/ssl/ssl_ciph.c +++ y/ssl/ssl_ciph.c @@ -263,6 +263,7 @@ static const SSL_CIPHER cipher_aliases[] = { @@ -844,10 +827,10 @@ index 2ad8f4392..33f6da1be 100644 kx = "SRP"; break; diff --git x/ssl/ssl_lib.c y/ssl/ssl_lib.c -index f8054dae6..b835f1fa5 100644 +index 3539f4b8d2..df6a45bdc4 100644 --- x/ssl/ssl_lib.c +++ y/ssl/ssl_lib.c -@@ -2434,8 +2434,14 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) +@@ -2442,8 +2442,14 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) #ifndef OPENSSL_NO_PSK mask_k |= SSL_kPSK; @@ -863,7 +846,7 @@ index f8054dae6..b835f1fa5 100644 #endif diff --git x/ssl/ssl_locl.h y/ssl/ssl_locl.h -index d50edd18c..3c59fff1b 100644 +index aeffc00634..25b9f1d5b1 100644 --- x/ssl/ssl_locl.h +++ y/ssl/ssl_locl.h @@ -314,6 +314,8 @@ @@ -876,7 +859,7 @@ index d50edd18c..3c59fff1b 100644 /* Bits for algorithm_auth (server authentication) */ /* RSA auth */ diff --git x/ssl/tls1.h y/ssl/tls1.h -index 7e237d063..173be499f 100644 +index dd1d8c109e..e04e7ddabc 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 +913,5 @@ index 7e237d063..173be499f 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.11.0 +2.15.0 diff --git a/patches/qt-Add-IsoDep-to-the-techList-on-Android.patch b/patches/qt-Add-IsoDep-to-the-techList-on-Android.patch new file mode 100644 index 0000000..04b5938 --- /dev/null +++ b/patches/qt-Add-IsoDep-to-the-techList-on-Android.patch @@ -0,0 +1,25 @@ +From e06d2d0d163501fdb0926175d7c539c7bb413d70 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Wed, 22 Nov 2017 07:35:56 +0100 +Subject: Add IsoDep to the techList on Android + +Change-Id: I26c183c1344cd0d9323fcedde82347487eebdffb +--- + src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java | 1 + + 1 file changed, 1 insertion(+) + +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 345b87d3..a1ae5c37 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 +@@ -127,6 +127,7 @@ public class QtNfc + filters[2] = new IntentFilter(); + filters[2].addAction(NfcAdapter.ACTION_TECH_DISCOVERED); + String[][] techList = new String[][]{ ++ {"android.nfc.tech.IsoDep"}, + {"android.nfc.tech.Ndef"}, + {"android.nfc.tech.NdefFormatable"} + }; +-- +2.14.2 + diff --git a/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch b/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch deleted file mode 100644 index 4538465..0000000 --- a/patches/qt-Add-debug-stream-operator-for-QNetworkProxyQuery.patch +++ /dev/null @@ -1,80 +0,0 @@ -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 deleted file mode 100644 index 309c334..0000000 --- a/patches/qt-Allow-using-nfc-when-running-as-a-service.patch +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index a049d99..0000000 --- a/patches/qt-Android-Add-support-for-sendCommand-to-QNearFieldTarget.patch +++ /dev/null @@ -1,180 +0,0 @@ -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 deleted file mode 100644 index ec910c9..0000000 --- a/patches/qt-Android-QNearfieldTarget-Introduce-maxCommandLength.patch +++ /dev/null @@ -1,374 +0,0 @@ -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-Avoid-using-deprecated-APIs-on-iOS-10.0.patch b/patches/qt-Avoid-using-deprecated-APIs-on-iOS-10.0.patch new file mode 100644 index 0000000..5a5d405 --- /dev/null +++ b/patches/qt-Avoid-using-deprecated-APIs-on-iOS-10.0.patch @@ -0,0 +1,73 @@ +From 26383dba15ceed74b36dd71e5b1837c63aade927 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Thu, 14 Sep 2017 12:47:11 +0200 +Subject: Avoid using deprecated APIs on iOS 10.0+ + +Change-Id: Ic9dc6a24ef793a29c2652ad37bc11120e2e6ceef +--- + src/gui/util/qdesktopservices.cpp | 13 +++++++++++++ + src/plugins/platforms/ios/qiosservices.mm | 14 ++++++++++++-- + 2 files changed, 25 insertions(+), 2 deletions(-) + +diff --git x/qtbase/src/gui/util/qdesktopservices.cpp y/qtbase/src/gui/util/qdesktopservices.cpp +index c9747877f7..77ccc02aa5 100644 +--- x/qtbase/src/gui/util/qdesktopservices.cpp ++++ y/qtbase/src/gui/util/qdesktopservices.cpp +@@ -177,6 +177,19 @@ void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler) + still fail to launch or fail to open the requested URL. This result will not be reported back + to the application. + ++ \warning URLs passed to this function on iOS will not load unless their schemes are ++ listed in the \c LSApplicationQueriesSchemes key of the application's Info.plist file. ++ For more information, see the Apple Developer Documentation for ++ \l{https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl}{canOpenURL(_:)}. ++ For example, the following lines enable URLs with the HTTPS scheme: ++ ++ \code ++ LSApplicationQueriesSchemes ++ ++ https ++ ++ \endcode ++ + \sa setUrlHandler() + */ + bool QDesktopServices::openUrl(const QUrl &url) +diff --git x/qtbase/src/plugins/platforms/ios/qiosservices.mm y/qtbase/src/plugins/platforms/ios/qiosservices.mm +index 0ecc8e123f..a963a5c05d 100644 +--- x/qtbase/src/plugins/platforms/ios/qiosservices.mm ++++ y/qtbase/src/plugins/platforms/ios/qiosservices.mm +@@ -41,6 +41,7 @@ + + #include + #include ++#include + + #import + +@@ -55,11 +56,20 @@ bool QIOSServices::openUrl(const QUrl &url) + return openDocument(url); + + NSURL *nsUrl = url.toNSURL(); ++ UIApplication *application = [UIApplication sharedApplication]; + +- if (![[UIApplication sharedApplication] canOpenURL:nsUrl]) ++ if (![application canOpenURL:nsUrl]) + return false; + +- return [[UIApplication sharedApplication] openURL:nsUrl]; ++#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 100000, 100000, __WATCHOS_NA) ++ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 10)) { ++ [application openURL:nsUrl options:@{} completionHandler:nil]; ++ return true; ++ } else ++#endif ++ { ++ return [application openURL:nsUrl]; ++ } + } + + bool QIOSServices::openDocument(const QUrl &url) +-- +2.14.1 + diff --git a/patches/qt-Change-build-configuration-for-Qt-on-iOS.patch b/patches/qt-Change-build-configuration-for-Qt-on-iOS.patch new file mode 100644 index 0000000..18a0870 --- /dev/null +++ b/patches/qt-Change-build-configuration-for-Qt-on-iOS.patch @@ -0,0 +1,32 @@ +From 1f505127d1dba4b755fc00360a5bffff8163acb7 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Wed, 19 Jul 2017 09:44:01 +0200 +Subject: Change build configuration for Qt on iOS +--- + mkspecs/macx-ios-clang/qmake.conf | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git x/qtbase/mkspecs/macx-ios-clang/qmake.conf y/qtbase/mkspecs/macx-ios-clang/qmake.conf +index 825e03aa85..fe783faee3 100644 +--- x/qtbase/mkspecs/macx-ios-clang/qmake.conf ++++ y/qtbase/mkspecs/macx-ios-clang/qmake.conf +@@ -2,13 +2,13 @@ + # qmake configuration for macx-ios-clang + # + +-QMAKE_IOS_DEPLOYMENT_TARGET = 8.0 ++QMAKE_IOS_DEPLOYMENT_TARGET = 10.0 + + # Universal target (iPhone and iPad) + QMAKE_APPLE_TARGETED_DEVICE_FAMILY = 1,2 + +-QMAKE_APPLE_DEVICE_ARCHS = armv7 arm64 +-QMAKE_APPLE_SIMULATOR_ARCHS = i386 x86_64 ++QMAKE_APPLE_DEVICE_ARCHS = arm64 ++QMAKE_APPLE_SIMULATOR_ARCHS = x86_64 + + include(../common/ios.conf) + include(../common/gcc-base-mac.conf) +-- +2.13.2 + diff --git a/patches/qt-Disable-unused-imageformats.patch b/patches/qt-Disable-unused-imageformats.patch new file mode 100644 index 0000000..a1f3496 --- /dev/null +++ b/patches/qt-Disable-unused-imageformats.patch @@ -0,0 +1,26 @@ +From 978caa044d4e1c52c90a87490defbac387db58d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Mon, 25 Sep 2017 14:10:56 +0200 +Subject: [PATCH] Disable unused imageformats + +--- + src/plugins/imageformats/imageformats.pro | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git x/qtimageformats/src/plugins/imageformats/imageformats.pro y/qtimageformats/src/plugins/imageformats/imageformats.pro +index 8c79379..2aa80f5 100644 +--- x/qtimageformats/src/plugins/imageformats/imageformats.pro ++++ y/qtimageformats/src/plugins/imageformats/imageformats.pro +@@ -16,8 +16,7 @@ config_jasper { + SUBDIRS += macjp2 + } + +-winrt { + SUBDIRS -= tiff \ + tga \ ++ wbmp \ + webp +-} +-- +2.14.1 + diff --git a/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch b/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch deleted file mode 100644 index d0c7a92..0000000 --- a/patches/qt-Do-not-request-an-unnessessary-dangerous-right.patch +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index da571dd..0000000 --- a/patches/qt-Introduce-QNetworkAccessManager-clearConnectionCache.patch +++ /dev/null @@ -1,140 +0,0 @@ -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-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch b/patches/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch deleted file mode 100644 index 8c6a98f..0000000 --- a/patches/qt-Introduce-QNetworkAccessManager-useAuthenticationManagerFrom.patch +++ /dev/null @@ -1,59 +0,0 @@ -From e1ba5a3265be01d7d353bf82e4d8af331edbb434 Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Tue, 13 Sep 2016 14:24:25 +0200 -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 -using the AuthenticationManager from a different NetworkAccessManager. - -[ChangeLog][QtCore][QNetworkAccessManager] Introduce useAuthenticationManagerFrom() - -Change-Id: If61f0d03fc8b2f159bad869d0a2b650170e1e174 ---- - src/network/access/qnetworkaccessmanager.cpp | 15 +++++++++++++++ - src/network/access/qnetworkaccessmanager.h | 2 ++ - 2 files changed, 17 insertions(+) - -diff --git x/qtbase/src/network/access/qnetworkaccessmanager.cpp y/qtbase/src/network/access/qnetworkaccessmanager.cpp -index b763547a15..83cb33ce72 100644 ---- x/qtbase/src/network/access/qnetworkaccessmanager.cpp -+++ y/qtbase/src/network/access/qnetworkaccessmanager.cpp -@@ -1079,6 +1079,21 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) - } - - /*! -+ \since 5.9 -+ -+ Sets the manager's authentication manager to be the one from -+ \a accessManager. This is useful when you need to use a new connection, -+ but keep already-entered user-credentials for usability reasons. -+*/ -+void QNetworkAccessManager::useAuthenticationManagerFrom(const QNetworkAccessManager& accessManager) -+{ -+ const QNetworkAccessManagerPrivate * const e = accessManager.d_func(); -+ -+ Q_D(QNetworkAccessManager); -+ d->authenticationManager = e->authenticationManager; -+} -+ -+/*! - \since 4.7 - - 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 649013cced..24f3c7147c 100644 ---- x/qtbase/src/network/access/qnetworkaccessmanager.h -+++ y/qtbase/src/network/access/qnetworkaccessmanager.h -@@ -149,6 +149,8 @@ public: - #endif - void connectToHost(const QString &hostName, quint16 port = 80); - -+ void useAuthenticationManagerFrom(const QNetworkAccessManager& accessManager); -+ - Q_SIGNALS: - #ifndef QT_NO_NETWORKPROXY - void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); --- -2.11.0 - diff --git a/patches/qt-Make-server-side-signature-algorithms-configurable.patch b/patches/qt-Make-server-side-signature-algorithms-configurable.patch index 96675d4..7da685e 100644 --- a/patches/qt-Make-server-side-signature-algorithms-configurable.patch +++ b/patches/qt-Make-server-side-signature-algorithms-configurable.patch @@ -1,4 +1,4 @@ -From 992a338b639e4df6da16659dc238dbaae0ae802f Mon Sep 17 00:00:00 2001 +From b0404383ab573d7550a6564405bb9b1316ff193a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=C3=B6sch?= Date: Thu, 21 Apr 2016 09:19:19 +0200 Subject: [PATCH] Make server side signature algorithms configurable @@ -10,18 +10,17 @@ server side. Change-Id: Ia178efd4778b91863fcc919bf50219115b300d77 --- - src/network/ssl/qsslconfiguration.cpp | 42 +++++++++++++ - 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 | 70 ++++++++++++++++++++++ - 8 files changed, 177 insertions(+), 1 deletion(-) + src/network/ssl/qsslconfiguration.cpp | 42 ++++++++++++++++++++++++ + 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 +++ + 7 files changed, 107 insertions(+), 1 deletion(-) diff --git x/qtbase/src/network/ssl/qsslconfiguration.cpp y/qtbase/src/network/ssl/qsslconfiguration.cpp -index 75a880f..37f99fe 100644 +index 75a880f115..37f99feef1 100644 --- x/qtbase/src/network/ssl/qsslconfiguration.cpp +++ y/qtbase/src/network/ssl/qsslconfiguration.cpp @@ -221,6 +221,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const @@ -40,10 +39,11 @@ index 75a880f..37f99fe 100644 d->sslOptions == QSslConfigurationPrivate::defaultSslOptions && d->sslSession.isNull() && d->sslSessionTicketLifeTimeHint == -1 && -@@ -870,6 +872,46 @@ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParame +@@ -869,6 +871,46 @@ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParame + d->dhParams = dhparams; } - /*! ++/*! + \since 5.9 + + Returns the connection's current list of supported signature @@ -83,12 +83,11 @@ index 75a880f..37f99fe 100644 + d->signatureAndHashAlgorithms = algorithms; +} + -+/*! + /*! \since 5.3 - 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 1c57beb..4d3e512 100644 +index 1c57bebd65..4d3e5129d5 100644 --- x/qtbase/src/network/ssl/qsslconfiguration.h +++ y/qtbase/src/network/ssl/qsslconfiguration.h @@ -56,10 +56,13 @@ @@ -117,7 +116,7 @@ index 1c57beb..4d3e512 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 6adf2c9..7be2539 100644 +index 6adf2c9b54..7be253973b 100644 --- x/qtbase/src/network/ssl/qsslconfiguration_p.h +++ y/qtbase/src/network/ssl/qsslconfiguration_p.h @@ -75,6 +75,9 @@ @@ -140,7 +139,7 @@ index 6adf2c9..7be2539 100644 int sslSessionTicketLifeTimeHint; diff --git x/qtbase/src/network/ssl/qsslcontext_openssl.cpp y/qtbase/src/network/ssl/qsslcontext_openssl.cpp -index c92d8fc..29df53a 100644 +index c92d8fc3f8..29df53abc0 100644 --- x/qtbase/src/network/ssl/qsslcontext_openssl.cpp +++ y/qtbase/src/network/ssl/qsslcontext_openssl.cpp @@ -42,6 +42,7 @@ @@ -210,7 +209,7 @@ index c92d8fc..29df53a 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 +index 06a31af5e5..c8c8e1941b 100644 --- x/qtbase/src/network/ssl/qsslcontext_openssl_p.h +++ y/qtbase/src/network/ssl/qsslcontext_openssl_p.h @@ -54,6 +54,7 @@ @@ -222,7 +221,7 @@ index 06a31af..c8c8e194 100644 #include #include diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp -index 29e1f32..8257112 100644 +index 8eba5db9fe..c0aa8b9bdf 100644 --- x/qtbase/src/network/ssl/qsslsocket.cpp +++ y/qtbase/src/network/ssl/qsslsocket.cpp @@ -922,6 +922,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) @@ -233,7 +232,7 @@ index 29e1f32..8257112 100644 d->configuration.sslOptions = configuration.d->sslOptions; d->configuration.sslSession = configuration.sessionTicket(); d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint(); -@@ -2230,6 +2231,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri +@@ -2249,6 +2250,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->peerVerifyDepth = global->peerVerifyDepth; ptr->sslOptions = global->sslOptions; ptr->ellipticCurves = global->ellipticCurves; @@ -242,7 +241,7 @@ index 29e1f32..8257112 100644 /*! diff --git x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h -index b35a895..d4cd493 100644 +index b35a895d38..d4cd493c45 100644 --- x/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ y/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -517,6 +517,11 @@ int q_EC_curve_nist2nid(const char *name); @@ -257,94 +256,6 @@ index b35a895..d4cd493 100644 // PKCS#12 support 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 4eb26d1..79a55cc 100644 ---- x/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp -+++ y/qtbase/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp -@@ -236,6 +236,8 @@ private slots: - void ephemeralServerKey(); - void allowedProtocolNegotiation(); - void pskServer(); -+ void signatureAlgorithm_data(); -+ void signatureAlgorithm(); - #endif - - 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); -+Q_DECLARE_METATYPE(SigAlgPair); -+ -+void tst_QSslSocket::signatureAlgorithm_data() -+{ -+ QTest::addColumn("serverSigAlgPair"); -+ QTest::addColumn("serverProtocol"); -+ QTest::addColumn("clientSigAlgPair"); -+ QTest::addColumn("clientProtocol"); -+ QTest::addColumn("state"); -+ -+ auto rsaSha256 = SigAlgPair(QSsl::Rsa, QCryptographicHash::Sha256); -+ auto rsaSha512 = SigAlgPair(QSsl::Rsa, QCryptographicHash::Sha512); -+ auto ecdsaSha512= SigAlgPair(QSsl::Ec, QCryptographicHash::Sha512); -+ -+ QTest::newRow("match_TlsV1_2") << rsaSha256 << QSsl::TlsV1_2 << rsaSha256 << QSsl::AnyProtocol << QAbstractSocket::ConnectedState; -+ QTest::newRow("no_hashalg_match_TlsV1_2") << rsaSha256 << QSsl::TlsV1_2 << rsaSha512 << QSsl::AnyProtocol << QAbstractSocket::UnconnectedState; -+ QTest::newRow("no_sigalg_match_TlsV1_2") << ecdsaSha512 << QSsl::TlsV1_2 << rsaSha512 << QSsl::AnyProtocol << QAbstractSocket::UnconnectedState; -+ QTest::newRow("no_cipher_match_AnyProtocol") << rsaSha512 << QSsl::TlsV1_2 << ecdsaSha512 << QSsl::AnyProtocol << QAbstractSocket::UnconnectedState; -+ -+ // signature algorithms do not match, but are ignored because the tls version is not v1.2 -+ QTest::newRow("client_ignore_TlsV1_1") << rsaSha256 << QSsl::TlsV1_1 << rsaSha512 << QSsl::AnyProtocol << QAbstractSocket::ConnectedState; -+ QTest::newRow("server_ignore_TlsV1_1") << rsaSha256 << QSsl::AnyProtocol << rsaSha512 << QSsl::TlsV1_1 << QAbstractSocket::ConnectedState; -+ QTest::newRow("client_ignore_TlsV1_0") << rsaSha256 << QSsl::TlsV1_0 << rsaSha512 << QSsl::AnyProtocol << QAbstractSocket::ConnectedState; -+ QTest::newRow("server_ignore_TlsV1_0") << rsaSha256 << QSsl::AnyProtocol << rsaSha512 << QSsl::TlsV1_0 << QAbstractSocket::ConnectedState; -+} -+ -+ -+void tst_QSslSocket::signatureAlgorithm() -+{ -+ QFETCH_GLOBAL(bool, setProxy); -+ if (!QSslSocket::supportsSsl() || setProxy) -+ return; -+ -+ QFETCH(SigAlgPair, serverSigAlgPair); -+ QFETCH(QSsl::SslProtocol, serverProtocol); -+ QFETCH(SigAlgPair, clientSigAlgPair); -+ QFETCH(QSsl::SslProtocol, clientProtocol); -+ QFETCH(QAbstractSocket::SocketState, state); -+ -+ -+ SslServer server; -+ server.protocol = serverProtocol; -+ server.config.setCiphers({QSslCipher("ECDHE-RSA-AES256-SHA")}); -+ server.config.setSignatureAndHashAlgorithms({serverSigAlgPair}); -+ QVERIFY(server.listen()); -+ -+ QSslConfiguration clientConfig = QSslConfiguration::defaultConfiguration(); -+ clientConfig.setSignatureAndHashAlgorithms({clientSigAlgPair}); -+ clientConfig.setProtocol(clientProtocol); -+ QSslSocket client; -+ client.setSslConfiguration(clientConfig); -+ socket = &client; -+ -+ QEventLoop loop; -+ QTimer::singleShot(5000, &loop, SLOT(quit())); -+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit())); -+ connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(ignoreErrorSlot())); -+ connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit())); -+ -+ -+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); -+ loop.exec(); -+ QCOMPARE(client.state(), state); -+} -+ - - #endif // QT_NO_OPENSSL - -- -2.10.2 +2.15.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 deleted file mode 100644 index 93aec2a..0000000 --- a/patches/qt-Make-variant-selection-possible-if-base-is-missing.patch +++ /dev/null @@ -1,69 +0,0 @@ -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 deleted file mode 100644 index b66b7cb..0000000 --- a/patches/qt-QNearfieldTarget-Introduce-set-keepConnection-and-disconnect.patch +++ /dev/null @@ -1,681 +0,0 @@ -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-Register-additional-meta-types.patch b/patches/qt-Register-additional-meta-types.patch new file mode 100644 index 0000000..047614f --- /dev/null +++ b/patches/qt-Register-additional-meta-types.patch @@ -0,0 +1,123 @@ +From 3885257e655cefd1f8b18247aff76020c75379e1 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Fri, 24 Mar 2017 11:20:14 +0100 +Subject: [PATCH] Register additional meta types + +Register QLowEnergyCharacteristic and QLowEnergyDescriptor +as meta types because they are used in signals. + +[ChangeLog][QtBluetooth] Register QLowEnergyCharacteristic +and QLowEnergyDescriptor as meta types. It is therefore +necessary to declare them as meta types in the header files. +This commit will cause conflicts with existing meta type +declarations in applications using Qt. These declarations +need to be removed. + +Change-Id: I18f33b1b2f159cffd6efbacc37178286b86a06e0 +Reviewed-by: Alex Blasche +--- + src/bluetooth/osx/osxbtcentralmanager.mm | 2 -- + src/bluetooth/qlowenergycharacteristic.h | 2 ++ + src/bluetooth/qlowenergycontroller_p.h | 5 ----- + src/bluetooth/qlowenergydescriptor.h | 2 ++ + src/bluetooth/qlowenergyservice.cpp | 2 ++ + .../test/tst_qlowenergycontroller-gattserver.cpp | 4 ---- + tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp | 3 --- + 7 files changed, 6 insertions(+), 14 deletions(-) + +diff --git x/qtconnectivity/src/bluetooth/osx/osxbtcentralmanager.mm y/qtconnectivity/src/bluetooth/osx/osxbtcentralmanager.mm +index ec046d1b..70473f1f 100644 +--- x/qtconnectivity/src/bluetooth/osx/osxbtcentralmanager.mm ++++ y/qtconnectivity/src/bluetooth/osx/osxbtcentralmanager.mm +@@ -48,8 +48,6 @@ + #include + #include + +-Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +-Q_DECLARE_METATYPE(QLowEnergyDescriptor) + Q_DECLARE_METATYPE(QLowEnergyHandle) + + QT_BEGIN_NAMESPACE +diff --git x/qtconnectivity/src/bluetooth/qlowenergycharacteristic.h y/qtconnectivity/src/bluetooth/qlowenergycharacteristic.h +index b991e9a2..154c9936 100644 +--- x/qtconnectivity/src/bluetooth/qlowenergycharacteristic.h ++++ y/qtconnectivity/src/bluetooth/qlowenergycharacteristic.h +@@ -107,4 +107,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QLowEnergyCharacteristic::PropertyTypes) + + QT_END_NAMESPACE + ++Q_DECLARE_METATYPE(QLowEnergyCharacteristic) ++ + #endif // QLOWENERGYCHARACTERISTIC_H +diff --git x/qtconnectivity/src/bluetooth/qlowenergycontroller_p.h y/qtconnectivity/src/bluetooth/qlowenergycontroller_p.h +index b92716e9..6e866144 100644 +--- x/qtconnectivity/src/bluetooth/qlowenergycontroller_p.h ++++ y/qtconnectivity/src/bluetooth/qlowenergycontroller_p.h +@@ -497,11 +497,6 @@ Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivate::Attribute, Q_MOVABLE_TYPE); + + QT_END_NAMESPACE + +-#ifdef QT_WINRT_BLUETOOTH +-Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +-Q_DECLARE_METATYPE(QLowEnergyDescriptor) +-#endif // QT_WINRT_BLUETOOTH +- + #endif // QT_OSX_BLUETOOTH || QT_IOS_BLUETOOTH + + #endif // QLOWENERGYCONTROLLERPRIVATE_P_H +diff --git x/qtconnectivity/src/bluetooth/qlowenergydescriptor.h y/qtconnectivity/src/bluetooth/qlowenergydescriptor.h +index 1dfe1c35..9e71fc56 100644 +--- x/qtconnectivity/src/bluetooth/qlowenergydescriptor.h ++++ y/qtconnectivity/src/bluetooth/qlowenergydescriptor.h +@@ -89,4 +89,6 @@ protected: + + QT_END_NAMESPACE + ++Q_DECLARE_METATYPE(QLowEnergyDescriptor) ++ + #endif // QLOWENERGYDESCRIPTOR_H +diff --git x/qtconnectivity/src/bluetooth/qlowenergyservice.cpp y/qtconnectivity/src/bluetooth/qlowenergyservice.cpp +index 6e33c565..9d3129fd 100644 +--- x/qtconnectivity/src/bluetooth/qlowenergyservice.cpp ++++ y/qtconnectivity/src/bluetooth/qlowenergyservice.cpp +@@ -380,6 +380,8 @@ QLowEnergyService::QLowEnergyService(QSharedPointer p, + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); ++ qRegisterMetaType(); ++ qRegisterMetaType(); + + connect(p.data(), SIGNAL(error(QLowEnergyService::ServiceError)), + this, SIGNAL(error(QLowEnergyService::ServiceError))); +diff --git x/qtconnectivity/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp y/qtconnectivity/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp +index 3df27d92..e01457eb 100644 +--- x/qtconnectivity/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp ++++ y/qtconnectivity/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp +@@ -243,10 +243,6 @@ void TestQLowEnergyControllerGattServer::advertisedData() + QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid(quint16(0x2000)))); + } + +-// TODO: Why on earth is this not in the library??? +-Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +-Q_DECLARE_METATYPE(QLowEnergyDescriptor) +- + void TestQLowEnergyControllerGattServer::serverCommunication() + { + qRegisterMetaType(); +diff --git x/qtconnectivity/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp y/qtconnectivity/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp +index 7b02dbcd..c6fd83e6 100644 +--- x/qtconnectivity/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp ++++ y/qtconnectivity/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp +@@ -91,9 +91,6 @@ private: + QList foundServices; + }; + +-Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +-Q_DECLARE_METATYPE(QLowEnergyDescriptor) +- + tst_QLowEnergyController::tst_QLowEnergyController() + { + qRegisterMetaType(); +-- +2.14.2 + 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 deleted file mode 100644 index 8d5468e..0000000 --- a/patches/qt-Use-apksigner-by-default-if-available-to-sign-the-AP.patch +++ /dev/null @@ -1,176 +0,0 @@ -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 deleted file mode 100644 index 5fb28cc..0000000 --- a/patches/qt-Use-defaultSize-according-to-svg-standard-in-svg-plugin.patch +++ /dev/null @@ -1,379 +0,0 @@ -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-macOS-iOS-Fix-garbled-text-under-some-conditions.patch b/patches/qt-macOS-iOS-Fix-garbled-text-under-some-conditions.patch new file mode 100644 index 0000000..34ba698 --- /dev/null +++ b/patches/qt-macOS-iOS-Fix-garbled-text-under-some-conditions.patch @@ -0,0 +1,90 @@ +From 13f25c979fe4396e6d5a76bf183341229da2bacd Mon Sep 17 00:00:00 2001 +From: Eskil Abrahamsen Blomfeldt +Date: Thu, 30 Nov 2017 15:00:26 +0100 +Subject: [PATCH] macOS/iOS: Fix garbled text under some conditions + +There seems to be an issue in CoreText which may cause an existing +font descriptor to give unreliable results if it refers to one of +the system theme fonts. Since we do not know all function calls +or events that may trigger this bug, the safe route is to always +create fresh font descriptors when creating fonts for these +descriptors. The impact on performance should be small, as Qt has +its own internal caches. + +[ChangeLog][macOS/iOS][Text] Fixed an issue where text using +one of the system theme fonts would under certain circumstances +display random glyphs. + +Task-number: QTBUG-63476 +Change-Id: I9e9b253018c63976345eec1439a6b78de2cab869 +--- + .../fontdatabases/mac/qcoretextfontdatabase.mm | 24 ++++++++++++++-------- + .../fontdatabases/mac/qcoretextfontdatabase_p.h | 4 +++- + 2 files changed, 19 insertions(+), 9 deletions(-) + +diff --git x/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm y/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +index 6347d4d231..237e8a89a5 100644 +--- x/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm ++++ y/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +@@ -416,7 +416,19 @@ extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); + template <> + QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QFontDef &fontDef, void *usrPtr) + { +- CTFontDescriptorRef descriptor = static_cast(usrPtr); ++ QCFType descriptor = QCFType::constructFromGet( ++ static_cast(usrPtr)); ++ ++ // CoreText will sometimes invalidate information in font descriptors that refer ++ // to system fonts in certain function calls or application states. While the descriptor ++ // looks the same from the outside, some internal plumbing is different, causing the results ++ // of creating CTFonts from those descriptors unreliable. The work-around for this ++ // is to copy the attributes of those descriptors each time we make a new CTFont ++ // from them instead of referring to the original, as that may trigger the CoreText bug. ++ if (m_systemFontDescriptors.contains(descriptor)) { ++ QCFType attributes = CTFontDescriptorCopyAttributes(descriptor); ++ descriptor = CTFontDescriptorCreateWithAttributes(attributes); ++ } + + // Since we do not pass in the destination DPI to CoreText when making + // the font, we need to pass in a point size which is scaled to include +@@ -427,14 +439,10 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine + qreal scaledPointSize = fontDef.pixelSize; + + CGAffineTransform matrix = qt_transform_from_fontdef(fontDef); +- CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix); +- if (font) { +- QFontEngine *engine = new QCoreTextFontEngine(font, fontDef); +- CFRelease(font); +- return engine; +- } ++ if (QCFType font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix)) ++ return new QCoreTextFontEngine(font, fontDef); + +- return NULL; ++ return nullptr; + } + + #ifndef QT_NO_FREETYPE +diff --git x/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h y/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +index 9612b909f1..e14d1d6e6e 100644 +--- x/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h ++++ y/qtbase/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +@@ -91,12 +91,14 @@ public: + QFont *themeFont(QPlatformTheme::Font) const; + const QHash &themeFonts() const; + ++protected: ++ mutable QSet m_systemFontDescriptors; ++ + private: + void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString()); + + mutable QString defaultFontName; + +- mutable QSet m_systemFontDescriptors; + mutable QHash m_themeFonts; + bool m_hasPopulatedAliases; + }; +-- +2.15.1 + diff --git a/patches/soname/openssl_makefile.shared.patch b/patches/soname/openssl_makefile.shared.patch deleted file mode 100644 index ac80d8a..0000000 --- a/patches/soname/openssl_makefile.shared.patch +++ /dev/null @@ -1,49 +0,0 @@ ---- Makefile.shared.orig 2014-05-09 12:44:04.801960645 +0200 -+++ Makefile.shared 2014-05-09 13:08:04.595689322 +0200 -@@ -109,23 +109,7 @@ - $${SHAREDCMD} $${SHAREDFLAGS} \ - -o $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX \ - $$ALLSYMSFLAGS $$SHOBJECTS $$NOALLSYMSFLAGS $$LIBDEPS \ -- ) && $(SYMLINK_SO) -- --SYMLINK_SO= \ -- if [ -n "$$INHIBIT_SYMLINKS" ]; then :; else \ -- prev=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX; \ -- if [ -n "$$SHLIB_COMPAT" ]; then \ -- for x in $$SHLIB_COMPAT; do \ -- ( $(SET_X); rm -f $$SHLIB$$x$$SHLIB_SUFFIX; \ -- ln -s $$prev $$SHLIB$$x$$SHLIB_SUFFIX ); \ -- prev=$$SHLIB$$x$$SHLIB_SUFFIX; \ -- done; \ -- fi; \ -- if [ -n "$$SHLIB_SOVER" ]; then \ -- ( $(SET_X); rm -f $$SHLIB$$SHLIB_SUFFIX; \ -- ln -s $$prev $$SHLIB$$SHLIB_SUFFIX ); \ -- fi; \ -- fi -+ ) - - LINK_SO_A= SHOBJECTS="lib$(LIBNAME).a $(LIBEXTRAS)"; $(LINK_SO) - LINK_SO_O= SHOBJECTS="$(LIBEXTRAS)"; $(LINK_SO) -@@ -578,18 +562,15 @@ - symlink.gnu symlink.solaris symlink.svr3 symlink.svr5 symlink.irix \ - symlink.aix symlink.reliantunix: - @ $(CALC_VERSIONS); \ -- SHLIB=lib$(LIBNAME).so; \ -- $(SYMLINK_SO) -+ SHLIB=lib$(LIBNAME).so; - symlink.darwin: - @ $(CALC_VERSIONS); \ - SHLIB=lib$(LIBNAME); \ -- SHLIB_SUFFIX=.dylib; \ -- $(SYMLINK_SO) -+ SHLIB_SUFFIX=.dylib; - symlink.hpux: - @ $(CALC_VERSIONS); \ - SHLIB=lib$(LIBNAME).sl; \ -- expr $(PLATFORM) : '.*ia64' > /dev/null && SHLIB=lib$(LIBNAME).so; \ -- $(SYMLINK_SO) -+ expr $(PLATFORM) : '.*ia64' > /dev/null && SHLIB=lib$(LIBNAME).so; - # The following lines means those specific architectures do no symlinks - symlink.cygwin symlink.alpha-osf1 symlink.tru64 symlink.tru64-rpath symlink.beos: - diff --git a/patches/soname/openssl_sed.sh b/patches/soname/openssl_sed.sh deleted file mode 100755 index 4e29edf..0000000 --- a/patches/soname/openssl_sed.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -echo "Patching Configure..." -#sed -i 's/.so.\\$(SHLIB_MAJOR).\\$(SHLIB_MINOR)/.so/g' Configure -sed -i 's/.\\$(SHLIB_MAJOR).\\$(SHLIB_MINOR)//g' Configure - -echo "Patching Makefile..." -sed -i 's/$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX/$$SHLIB/g' Makefile.shared - diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index e78a850..2590f11 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -1,7 +1,23 @@ +FUNCTION(WRITE_QRC _dest_file _dir _prefix) + FILE(GLOB_RECURSE files "${_dir}/*") + + FILE(WRITE "${_dest_file}" "\n") + FOREACH(file ${files}) + STRING(REPLACE "${_dir}/" "" file_alias "${file}") + FILE(APPEND "${_dest_file}" "${file}\n") + ENDFOREACH() + FILE(APPEND "${_dest_file}" "") +ENDFUNCTION() + + SET(QRC_FILES "ausweisapp.qrc") IF(IOS OR ANDROID OR ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") LIST(APPEND QRC_FILES "ausweisapp_mobile.qrc") + + SET(ausweisapp_qml.qrc "${CMAKE_CURRENT_BINARY_DIR}/ausweisapp_qml.qrc") + WRITE_QRC("${ausweisapp_qml.qrc}" "${CMAKE_CURRENT_SOURCE_DIR}/qml" "qml") + LIST(APPEND QRC_FILES "${ausweisapp_qml.qrc}") ENDIF() IF(DESKTOP) @@ -12,7 +28,3 @@ 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) -ENDIF() diff --git a/resources/ausweisapp.qrc b/resources/ausweisapp.qrc index b643c6a..cc266d0 100644 --- a/resources/ausweisapp.qrc +++ b/resources/ausweisapp.qrc @@ -29,7 +29,6 @@ images/iOS/tabBar/Pin-on.png images/iOS/tabBar/Verlauf-off.png images/iOS/tabBar/Verlauf-on.png - images/icon_Bluetooth.svg images/icon_Pin.svg images/iOS/tabBar/More-off.svg images/iOS/tabBar/More-on.svg @@ -57,28 +56,34 @@ 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/provider/categoryIcons/+android/general.svg + images/provider/categoryIcons/+android/citizen.svg + images/provider/categoryIcons/+android/finance.svg + images/provider/categoryIcons/+android/insurance.svg + images/provider/categoryIcons/+android/other.svg + images/provider/categoryIcons/+android/general_bg.svg + images/provider/categoryIcons/+android/general_button.svg + images/provider/categoryIcons/+android/citizen_bg.svg + images/provider/categoryIcons/+android/citizen_button.svg + images/provider/categoryIcons/+android/finance_bg.svg + images/provider/categoryIcons/+android/finance_button.svg + images/provider/categoryIcons/+android/insurance_bg.svg + images/provider/categoryIcons/+android/insurance_button.svg + images/provider/categoryIcons/+android/other_bg.svg + images/provider/categoryIcons/+android/other_button.svg + images/provider/categoryIcons/+android/general_section.svg + images/provider/categoryIcons/+android/citizen_section.svg + images/provider/categoryIcons/+android/finance_section.svg + images/provider/categoryIcons/+android/insurance_section.svg + images/provider/categoryIcons/+android/other_section.svg + updatable-files/supported-providers.json images/icon_nfc.svg + images/icon_remote.svg + images/icon_bluetooth.svg images/phone_nfc.svg + images/phone_remote.svg images/phone_bluetooth.svg + images/location_flag_de.svg + images/location_flag_en.svg diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index b70fd74..c1552a8 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -2,13 +2,12 @@ html_templates/alreadyactive.html html_templates/error.html - stylesheets/common.qss stylesheets/macos.qss stylesheets/windows.qss stylesheets/desktop.qss - images/beta.svg + images/green_check_mark.svg images/MenuSelected.png images/MenuUnselected.png images/MenuUnselectedDisabled.png @@ -19,6 +18,8 @@ images/start_nPA_eAT.png images/busy_animation.gif images/html_message_section.jpg + images/padlock.svg + images/padlock_empty.svg images/randompin/btn_normal_0.png images/randompin/btn_normal_1.png images/randompin/btn_normal_2.png @@ -33,36 +34,63 @@ 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 - images/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png - 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_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_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 - images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png - images/reader/img_FEIG_myAXXES_basic.png - images/reader/img_FEIG_myAXXES_basic_mit_ausweis.png - images/reader/img_Gemalto_Prox_SU.png - images/reader/img_Gemalto_Prox_SU_mit_ausweis.png - images/reader/img_Gemalto_Prox_DU.png - images/reader/img_Gemalto_Prox_DU_mit_ausweis.png + images/reader/default_more_reader.png + images/reader/default_no_card.png + images/reader/default_no_reader.png + images/reader/default_reader.png + images/reader/default_reader_mit_ausweis.png + updatable-files/supported-readers.json + updatable-files/reader/img_ACS_ACR122U.png + updatable-files/reader/img_ACS_ACR122U_mit_ausweis.png + updatable-files/reader/img_ACS_ACR1252U.png + updatable-files/reader/img_ACS_ACR1252U_mit_ausweis.png + updatable-files/reader/img_ACS_ACR1281U.png + updatable-files/reader/img_ACS_ACR1281U_mit_ausweis.png + updatable-files/reader/img_Cherry_TC_1200.png + updatable-files/reader/img_Cherry_TC_1200_mit_ausweis.png + updatable-files/reader/img_Cherry_TC_1300.png + updatable-files/reader/img_Cherry_TC_1300_mit_ausweis.png + updatable-files/reader/img_cyberjack_wave.png + updatable-files/reader/img_cyberjack_wave_mit_ausweis.png + updatable-files/reader/img_FEIG_myAXXES_basic.png + updatable-files/reader/img_FEIG_myAXXES_basic_mit_ausweis.png + updatable-files/reader/img_Gemalto_Prox_DU.png + updatable-files/reader/img_Gemalto_Prox_DU_mit_ausweis.png + updatable-files/reader/img_Gemalto_Prox_SU.png + updatable-files/reader/img_Gemalto_Prox_SU_mit_ausweis.png + updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2.png + updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png + updatable-files/reader/img_HID_Omnikey_5421.png + updatable-files/reader/img_HID_Omnikey_5421_mit_ausweis.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL_mit_ausweis.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL.png + updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL_mit_ausweis.png + updatable-files/reader/img_Identive_Cloud_3700_F.png + updatable-files/reader/img_Identive_Cloud_3700_F_mit_ausweis.png + updatable-files/reader/img_Identive_Cloud_4700_F.png + updatable-files/reader/img_Identive_Cloud_4700_F_mit_ausweis.png + updatable-files/reader/img_Identive_Cloud_4701_F.png + updatable-files/reader/img_Identive_Cloud_4701_F_mit_ausweis.png + updatable-files/reader/img_Identive_SCL011.png + updatable-files/reader/img_Identive_SCL011_mit_ausweis.png + updatable-files/reader/img_Identive_SCL3711.png + updatable-files/reader/img_Identive_SCL3711_mit_ausweis.png + updatable-files/reader/img_Identive_SDI010.png + updatable-files/reader/img_Identive_SDI010_mit_ausweis.png + updatable-files/reader/img_Identive_SDI011.png + updatable-files/reader/img_Identive_SDI011_mit_ausweis.png + updatable-files/reader/img_KOBIL_ID_Token.png + updatable-files/reader/img_KOBIL_ID_Token_mit_ausweis.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard.png + updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png + updatable-files/reader/img_RemoteReader.png + updatable-files/reader/img_RemoteReader_mit_ausweis.png diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index 40ad763..a1d2118 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -13,6 +13,7 @@ images/android/navigation/ausweisen.svg images/android/navigation/anbieter.svg images/android/navigation/balloon.svg + images/android/navigation/remoteleser.svg images/android/navigation/verlauf.svg images/android/navigation/pin.svg images/android/navigation/versionsinformation.svg @@ -40,22 +41,27 @@ images/android/android_arrow_back_white.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 + images/iOS/more/icon_mehr_license.svg + images/iOS/more/icon_mehr_remotereader.svg + images/iOS/more/icon_mehr_upload.svg + images/provider/categoryIcons/general.svg + images/provider/categoryIcons/citizen.svg + images/provider/categoryIcons/finance.svg + images/provider/categoryIcons/insurance.svg + images/provider/categoryIcons/other.svg + images/provider/categoryIcons/+android/general_bg.svg + images/provider/categoryIcons/+android/general_button.svg + images/provider/categoryIcons/+android/citizen_bg.svg + images/provider/categoryIcons/+android/citizen_button.svg + images/provider/categoryIcons/+android/finance_bg.svg + images/provider/categoryIcons/+android/finance_button.svg + images/provider/categoryIcons/+android/insurance_bg.svg + images/provider/categoryIcons/+android/insurance_button.svg + images/provider/categoryIcons/+android/other_bg.svg + images/provider/categoryIcons/+android/other_button.svg + images/phone_to_pc.svg + images/android/navigation/remotesettings.svg + images/trash_icon.svg diff --git a/resources/config.json.in b/resources/config.json.in index 9bef63e..8b1fba7 100644 --- a/resources/config.json.in +++ b/resources/config.json.in @@ -3,9 +3,9 @@ "_comment_1": "array of CVCs; hex encoded", "_comment_2": [ - "certificate 1: DECVCAeID00103_DECVCAeID00104", - "certificate 2: DECVCAeID00102_DECVCAeID00103", - "certificate 3: DECVCAeID00102" + "DECVCAeID00103_DECVCAeID00104", + "DECVCAeID00102_DECVCAeID00103", + "DECVCAeID00102" ], "cvRootCertificates": [ "7F218201B67F4E82016E5F290100420E44454356434165494430303130337F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104241D8627338B64F20077FFD558909A096C635DDB222852038EAAE642E869A40173D588F817D95DB2A6A0F077EA5EE63596A20F85BC3CB176D2F98D88D90219AA8701015F200E44454356434165494430303130347F4C12060904007F0007030102025305FC0F13FFFF5F25060105000901045F24060108000901045F3740313A81ED8734E7A8C45F16B55FB603E63027B7F44C2DE3A8E782552D35949DB221CA33BD41A01DA6A1288C7885714FC3A03FA45683B75D3884930EC6738AF8A0", @@ -15,13 +15,13 @@ "_comment_3": "array of Test-CVCs; hex encoded", "_comment_4": [ - "certificate 4: DETESTeID00001", - "certificate 5: DETESTeID00002_DETESTeID00001", - "certificate 6: DETESTeID00004_DETESTeID00002", - "certificate 7: DETESTeID00005_DETESTeID00004", - "certificate 8: DECVCAeIDCTL0401_DECVCAeIDCTL0402", - "certificate 9: DECVCAeIDCT00001_DECVCAeIDCTL0401", - "certificate 10: DECVCAeIDCT00001_DECVCAeIDCT00001" + "DETESTeID00001", + "DETESTeID00001_DETESTeID00002", + "DETESTeID00002_DETESTeID00004", + "DETESTeID00004_DETESTeID00005", + "DECVCAeIDCTL0401_DECVCAeIDCTL0402", + "DECVCAeIDCT00001_DECVCAeIDCTL0401", + "DECVCAeIDCT00001_DECVCAeIDCT00001" ], "cvRootCertificatesTest": [ "7F218201B67F4E82016E5F290100420E44455445535465494430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104184BB519FC2A8F52DC0DC73112FACFE914F2A49B678DD5799A2B1DFE95E1A66359014E22FA8D66438413CEBA6CF0E215576B673376BF617AF4DFE9761D2290148701015F200E44455445535465494430303030317F4C12060904007F0007030102025305FE0F01FFFF5F25060100000801035F24060103000801035F37409F25EBFAF4B91E4C60A1683754C5DC076A3179753EF97D9F8CB01FE1DCD3B8C83E7A26602AB1F344BE5706006D79A9FF6A9716404DC83B9F30E1213B393128A2", @@ -35,16 +35,16 @@ "_comment_5": "array of certificates for checking the authenticity of updates; DER format, hex encoded", "updateCertificates": [ - "308206f8308205e0a003020102020840b202f4450f40bf300d06092a864886f70d01010505003076310b300906035504061302444531253023060355040a131c542d53797374656d7320496e7465726e6174696f6e616c20476d6248311e301c060355040b131554727573742043656e7465722053657276696365733120301e0603550403131754656c6553656320536572766572506173732043412031301e170d3132303832313037353132345a170d3135303832363233353935395a3081ab310b3009060355040613024445312d302b060355040a0c246272656d656e206f6e6c696e6520736572766963657320476d6248202620436f2e204b47310b3009060355040b13025345310f300d060355040813064272656d656e310f300d060355040713064272656d656e3124302206092a864886f70d01090116156265747269656240626f732d6272656d656e2e6465311830160603550403130f6170706c2e626f732d6173702e646530820122300d06092a864886f70d01010105000382010f003082010a0282010100baa234d61141856dcc308a4fe30d1eaeb3e3356971e79a7c8257ce0ff15cd786a24670b58f2e0e2ba609805b9db94e7a68c5216375e9549c45c7d2d40ad9ecd1332adb6a94c8b312cc71097a671ff3ebec674f2decde539b619c867b1873deafa8eaeda61b335d483a260196903e4f3922cb3d66e30b6e22cfed5e249f7847b37d53b00409edd52e7148a72e2baf22194ec408496b6726ef5c8e2495e88e1c0193ab46f75b9e6fb0cfd100ab314a59337eb80d7c0449ff523606ea72e357e153182353d9cbe92567507f39c6d6545d3d561657703c6d6858a0cfa322c086bab2366f7df64cf8697f85e0d054a7c1283c7858cc2192082b9e14f88ce6388928d30203010001a38203523082034e301f0603551d2304183016801433dc9e96ecd8e8351f6d901b0b38a4af741bc658300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030206082b06010505070301301d0603551d0e041604146a2f35506e2da75862fe292c02f2222d28d4051c304f0603551d2004483046304406092b06010401bd470d023037303506082b060105050702011629687474703a2f2f7777772e74656c657365632e64652f736572766572706173732f6370732e68746d6c308201220603551d1f04820119308201153045a043a041863f687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f726c2f54656c655365635f536572766572506173735f43415f312e63726c3081cba081c8a081c58681c26c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f636e3d54656c65536563253230536572766572506173732532304341253230312c6f753d547275737425323043656e74657225323053657276696365732c6f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c633d64653f63657274696669636174655265766f636174696f6e6c6973743f626173653f63657274696669636174655265766f636174696f6e6c6973743d2a3082013a06082b060105050701010482012c30820128303306082b060105050730018627687474703a2f2f6f6373702e736572766572706173732e74656c657365632e64652f6f63737072304c06082b060105050730028640687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f6372742f54656c655365635f536572766572506173735f43415f312e6365723081a206082b060105050730028681956c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f636e3d54656c65536563253230536572766572506173732532304341253230312c6f753d547275737425323043656e74657225323053657276696365732c6f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c633d64653f63414365727469666963617465300c0603551d130101ff04023000301a0603551d1104133011820f6170706c2e626f732d6173702e6465300d06092a864886f70d0101050500038201010026a20d746b23686fa3d7513bf46ee88fbc1d895a7626576cd3ca16fa4a483a36bbe72bdb1aafd1f653a30c7e512870037eeba1706c75082248402061c5a2b39abe2c7a13433c6344cdfb9fb83ddee505bc406d7aa00b35b32ace9faffea387d1dd5982ac7e09c2687d5d33853885fea902e30dde7870457ac3431db6f64314a768b293a1ba097cf7b25d0abb83090f8a1b9a8fe009fe63f9fe6029b06e0d4e95e3995c6a93812a783493f66b69270f64d472637a8b30cb5870676ccaf98a4655e843c5c255d57e19388b60c5ffc6fd65f3eb17353279a68b609681b2bd7c629f4e6061619df736f78eabb2761a3ef9b3dcc87abcbca781620297f576ea9ce06a", "308208673082074fa00302010202086b5eeeb3f0155141300d06092a864886f70d01010b05003081d8310b300906035504061302444531253023060355040a131c542d53797374656d7320496e7465726e6174696f6e616c20476d6248311e301c060355040b131554727573742043656e7465722053657276696365733120301e0603550403131754656c6553656320536572766572506173732043412032311c301a060355040813134e6f7264726865696e205765737466616c656e310e300c0603550411130535373235303110300e060355040713074e65747068656e3120301e06035504091317556e7465726520496e647573747269657374722e203230301e170d3135303532303039353335315a170d3138303532353233353935395a3081a6310b30090603550406130244453121301f060355040a0c18476f7665726e696b757320476d6248202620436f2e204b47310b3009060355040b13025345310f300d060355040813064272656d656e310f300d060355040713064272656d656e3124302206092a864886f70d01090116156265747269656240676f7665726e696b75732e6465311f301d060355040313166170706c2e676f7665726e696b75732d6173702e646530820222300d06092a864886f70d01010105000382020f003082020a0282020100c1d969514392105ce65b089b7357f75356f076b21168233d1eb57ae81f826c74258ec4814c48a3e99633fcac1fb444412cba421c1569d21b6317b6614b096203ab5b605128671764d30186dec09716d2173bfab911a9ad3d2d0b850ff2595dd9c72113bd64879c39c39b3debbfdd7f8d68e8d1bdaf2cca0508583bd59b965ec5f4950e4fbbe48b7be351237d478253bc34ac5aed9448f5ae31878067bdad75179cb776ef19f8e49e62b830de8279142233030189c20008345553847b7edc6471bf7c15c98b087159b44faa5a35fe16adc285e4d8266fab49b7b4e7fbcbd91767e05dbb45a5564cb11abcbeb0ff66869ca72dd7919eae796340fb5b26fb8ecc65b8380d3eb30e46150725e2156ad156773a79b482133b846b247868a6d3fcc18f96cfc6044fb7678fd79c04fb580b7bfb86e3252554b9a97dfd6fb9ae0e0d8d663a56b471d37752fc88a172151494553d78a39ade4669076e5ddfa13fd684b7eb800efedf9af8f90d4bab6d80378b950d43ef6de6f9ca5dccb81ecbbf820126d90923c5b87462af2acf0fc460599b2d7022e488f20069e2b3e80e057ebbd1454891929c2e0252688a1c0e801eb8bec795251087a755a6edcd22759a5c1869550d63b0596cb5ac20a7e5cb11f5412598990092cbe058b4ec67b98dd9ed2b2a5f8b7994e92b89a1ef51517beb2e2594cb8007d514f988968c52246a18945fba0adf0203010001a38203633082035f301f0603551d2304183016801415bbded6256fbdf2319f6213dc5ca6f465b46df2300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030206082b06010505070301301d0603551d0e041604148c76a1377b9cad8059a5d4126a53bc633671ca1c30590603551d2004523050304406092b06010401bd470d023037303506082b060105050702011629687474703a2f2f7777772e74656c657365632e64652f736572766572706173732f6370732e68746d6c3008060667810c010202308201220603551d1f04820119308201153045a043a041863f687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f726c2f54656c655365635f536572766572506173735f43415f322e63726c3081cba081c8a081c58681c26c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f636e3d54656c65536563253230536572766572506173732532304341253230322c6f753d547275737425323043656e74657225323053657276696365732c6f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c633d64653f63657274696669636174655265766f636174696f6e6c6973743f626173653f63657274696669636174655265766f636174696f6e6c6973743d2a3082013a06082b060105050701010482012c30820128303306082b060105050730018627687474703a2f2f6f6373702e736572766572706173732e74656c657365632e64652f6f63737072304c06082b060105050730028640687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f6372742f54656c655365635f536572766572506173735f43415f322e6365723081a206082b060105050730028681956c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f636e3d54656c65536563253230536572766572506173732532304341253230322c6f753d547275737425323043656e74657225323053657276696365732c6f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c633d64653f63414365727469666963617465300c0603551d130101ff0402300030210603551d11041a301882166170706c2e676f7665726e696b75732d6173702e6465300d06092a864886f70d01010b050003820101005f35f8a5ed5fe3879dbb137d1505768bff7635e3c7824735bf8c0b1bdd02335de7928f484192925c29738b034b152805935aa54d92abc3be5c7cfec5017ca506a33c2b15fdb2762037b0b4615e39d7697f64dba763ad0b6e05b7e8b6dd29c7ace3ec86ea74a82ce9a5575166375849afbd48cebdbd18bfdab0f905b094b4e686649bee5fba153ff5786cbb5926807891ae07871127a887c2e2747dcfd1bd18d34b0642eb2fa8309e8b434b2cf91ab0e918c3f3c59d70aa096a46abfc50b3e66baacd7748b7ef98110760cce271c1528ed4e84ae9144983ad26aa27f00a527053c50739d2592ad13179a33eb1d299081be8b9824bc63ac70e1ad518380df08a56%", - "308202eb308201d3a003020102020437a18b8a300d06092a864886f70d01010b05003026310b3009060355040613024445311730150603550403130e6275696c64617574656e74617070301e170d3134303732343131323334325a170d3234303732313131323334325a3026310b3009060355040613024445311730150603550403130e6275696c64617574656e7461707030820122300d06092a864886f70d01010105000382010f003082010a0282010100ca573d1c79c72f15dd80020b39886bec2de9004556eabc833f61b86aac3b4658ed8ecf7f32cb3daeb34576b49ff13e9eaaafa5ce2cf7cb13df2f89be6a1659f79cca6b4276b90914594e74998f9b9fffa0c8efdf4409be91a195458e1a0dce707cb1573cab99d297c80e8026c2f299fd97b8bbf14b172094f17abe50483a2e1df0cf6629d024cf5b752a1bb0edbe172dcce7ed30cc3c193ba742bff2e0afa0f15c414f27bdb374f65ac71c0c7af3a4a5fe1707d22bed1b63019e659c42e763c601f45d60094be915a422a0c183da33e8b3909cf83c0d7dfd3d5ffd1a92cf00c07961b284ddbef1e9b9d5536e12630cefa8493c8244edd2f687b09d38e79f639d0203010001a321301f301d0603551d0e04160414b29d3e7f193789f68d2234738a2773e737c4ce1c300d06092a864886f70d01010b0500038201010030800530f9d3abb215e8c8da5ee62ee083bdd8fce00d673702d00fac194eabd4c0b9338166a6dd76711651e685d0b9a50cdf2dc4872edeb5f4369372fb0d70d8fe02892b962e5fafd73add31ec0fd6708aa6ad2c82beca260773dd3e62460d1e416ac8d931e221b1bcf8255abd44933d38660e5bad639c38fb7dbbcf1f9504e20b27d75810b5ab475ce061d725b54628b4cfd7bd53f29d93a8ecb16e96df9ff654da55ea8ed1700c8d3135b1bc97655595a56f75dfb101c27341309602dce89e9c4db08a7c19d7fb199394f0ec478c4f246dbab0a37c2cea22b5b2b4c9e589a640611348b77dddd0fc412c9980cb5d516b274b9649debdd22df123cd06495924%" + "308205633082044ba00302010202135100000749e339b5a8a2ecb8e8000000000749300d06092a864886f70d01010b0500304431153013060a0992268993f22c64011916056c6f63616c31153013060a0992268993f22c6401191605626f736b67311430120603550403130b676f766b67726f6f746361301e170d3136313232393039343930325a170d3138313232393039353930325a307c310b3009060355040613024445310b3009060355040813024445310f300d060355040713064272656d656e31163014060355040a130d476f7665726e696b7573204b47311c301a060355040b131353797374656d7320456e67696e656572696e6731193017060355040314102a2e74662e626f732d746573742e646530820122300d06092a864886f70d01010105000382010f003082010a0282010100c2ce4b611d136b4a99f43bd6487c323f812f00c433ed7ec3d343b93c1b064ba12ff3f950634bbba55283ea48bf91d3a6736ee17c3467918b22d9ba1d55f9b8593461b42ed54454d15577abe0ec286203c4c33a82aae8216c802f8f81f1d06473f85acbf6ba69357828030a97086aa1bc6836cae3916d2d83f24c153a05402e13828a30822e7a861395be7d7c511b84baf4bc4a5daeb3db755b37e8ffb5dd18f8ac22c018801e212ab59b96e64b85c3d418c577c33ef73cc0ba5fef68041ba39fa0b795e7b5eabfa408c36ca582572ca2adde4cd104ccad376eaa06b41e737121f349eedb063438b406bd32dc032659e9cbad809afb5679d8a7d776a916ead35b0203010001a382021430820210300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b0601050507030130240603551d11041d301b82102a2e74662e626f732d746573742e646582012a87040ad2f861301d0603551d0e04160414262451b4431de1ccdb523d93038d7e01c4a3d153301f0603551d230418301680144b7e48a7b2f2db121642634bcd7e1c0deee96285303b0603551d1f043430323030a02ea02c862a687474703a2f2f676f7663726c2e676f7665726e696b75732e64652f63726c2f7265766f6b652e63726c3081eb06082b060105050701010481de3081db3081aa06082b0601050507300286819d6c6461703a2f2f2f434e3d676f766b67726f6f7463612c434e3d4149412c434e3d5075626c69632532304b657925323053657276696365732c434e3d53657276696365732c434e3d436f6e66696775726174696f6e2c44433d626f736b672c44433d6c6f63616c3f634143657274696669636174653f626173653f6f626a656374436c6173733d63657274696669636174696f6e417574686f72697479302c06082b060105050730018620687474703a2f2f676f7663726c2e676f7665726e696b75732e64652f6f637370303b06092b0601040182371507042e302c06242b060104018237150887a4920efcad6b83a98117819cb41586e9ea5a1791ff2e87b7af7c020164020109301b06092b060104018237150a040e300c300a06082b06010505070301300d06092a864886f70d01010b05000382010100a41dd5971c9b983bc3369bc9f3046481ff05aab5b47fac27a8cb7f917585b15c5acfbc8d083375a459b0642974968f4e00ad501d715dfb8a9e098437459ddcbba5a7d49f0278bd841b89fb93e86683bd89334f6b5ab556834e1fb4ec86647e812438e17512ee87b01bd0679b3abf4a67fe7272eae0c4cd9ed174d70b2728e72361cded46a42d445dfe244efb55feb1eee13f614d30237ee399b4108bc596b8aab377ad98d22c87ce4ce976ec1ceac512c33d6941b715d9fa60882b4644f9a066dcd51ff6c429af37cfa38f06444e6682d09643b2866a23a42da0ae21a787e8fe40aa2b21aa55a10aa42097c9a219528ac4968eb12cec5f223791a40d21fcce05", + "3082083a30820722a003020102020900d5b6a4dc1fd8854a300d06092a864886f70d01010b05003081df310b300906035504061302444531253023060355040a0c1c542d53797374656d7320496e7465726e6174696f6e616c20476d6248311f301d060355040b0c16542d53797374656d732054727573742043656e746572311c301a06035504080c134e6f7264726865696e205765737466616c656e310e300c06035504110c0535373235303110300e06035504070c074e65747068656e3120301e06035504090c17556e7465726520496e647573747269657374722e2032303126302406035504030c1d54656c65536563205365727665725061737320436c6173732032204341301e170d3137313230313130343733325a170d3230313230363233353935395a308180310b30090603550406130244453121301f060355040a0c18476f7665726e696b757320476d6248202620436f2e204b47310b3009060355040b13025345310f300d060355040813064272656d656e310f300d060355040713064272656d656e311f301d060355040313166170706c2e676f7665726e696b75732d6173702e646530820222300d06092a864886f70d01010105000382020f003082020a0282020100c1d969514392105ce65b089b7357f75356f076b21168233d1eb57ae81f826c74258ec4814c48a3e99633fcac1fb444412cba421c1569d21b6317b6614b096203ab5b605128671764d30186dec09716d2173bfab911a9ad3d2d0b850ff2595dd9c72113bd64879c39c39b3debbfdd7f8d68e8d1bdaf2cca0508583bd59b965ec5f4950e4fbbe48b7be351237d478253bc34ac5aed9448f5ae31878067bdad75179cb776ef19f8e49e62b830de8279142233030189c20008345553847b7edc6471bf7c15c98b087159b44faa5a35fe16adc285e4d8266fab49b7b4e7fbcbd91767e05dbb45a5564cb11abcbeb0ff66869ca72dd7919eae796340fb5b26fb8ecc65b8380d3eb30e46150725e2156ad156773a79b482133b846b247868a6d3fcc18f96cfc6044fb7678fd79c04fb580b7bfb86e3252554b9a97dfd6fb9ae0e0d8d663a56b471d37752fc88a172151494553d78a39ade4669076e5ddfa13fd684b7eb800efedf9af8f90d4bab6d80378b950d43ef6de6f9ca5dccb81ecbbf820126d90923c5b87462af2acf0fc460599b2d7022e488f20069e2b3e80e057ebbd1454891929c2e0252688a1c0e801eb8bec795251087a755a6edcd22759a5c1869550d63b0596cb5ac20a7e5cb11f5412598990092cbe058b4ec67b98dd9ed2b2a5f8b7994e92b89a1ef51517beb2e2594cb8007d514f988968c52246a18945fba0adf0203010001a382035430820350301f0603551d2304183016801494c87446f53ab4464826f82bca341e5626041200300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030206082b06010505070301301d0603551d0e041604148c76a1377b9cad8059a5d4126a53bc633671ca1c305a0603551d20045330513045060a2b06010401bd470d17013037303506082b060105050702011629687474703a2f2f7777772e74656c657365632e64652f736572766572706173732f6370732e68746d6c3008060667810c010202308201030603551d1f0481fb3081f83040a03ea03c863a687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f726c2f536572766572506173735f436c6173735f322e63726c3081b3a081b0a081ad8681aa6c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f434e3d54656c6553656325323053657276657250617373253230436c6173732532303225323043412c4f553d542d53797374656d73253230547275737425323043656e7465722c4f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c433d44453f43657274696669636174655265766f636174696f6e4c6973743082014906082b060105050701010482013b30820137303306082b060105050730018627687474703a2f2f6f6373702e736572766572706173732e74656c657365632e64652f6f63737072305206082b060105050730028646687474703a2f2f63726c2e736572766572706173732e74656c657365632e64652f6372742f54656c655365635f536572766572506173735f436c6173735f325f43412e6365723081ab06082b0601050507300286819e6c6461703a2f2f6c6461702e736572766572706173732e74656c657365632e64652f434e3d54656c6553656325323053657276657250617373253230436c6173732532303225323043412c4f553d542d53797374656d73253230547275737425323043656e7465722c4f3d542d53797374656d73253230496e7465726e6174696f6e616c253230476d62482c433d44453f63414365727469666963617465300c0603551d130101ff0402300030210603551d11041a301882166170706c2e676f7665726e696b75732d6173702e6465300d06092a864886f70d01010b050003820101006376f829a32345d2d590176bf2294d9ab6fe44e6c7db3b467bd597eebda4121d6e8795ec33de253ff9f271857c4a1ddf4b80b080464a51741a53de5137be13fc482e41b3649afbb571bfec2a894022d933ca60c691a99f31fe40209e7ca2e7fcd15d33baf8c1d20e107750cbd8628bc883af062a622f29c36574decaf97ef00471bbbe81380042ab82e46788491e4f77e58168f154d5210748263bfb8b2c3c82937436f758e1b2360c22458803a304eb90a4617bdcaa591176f4002e63dce3c9a3c7dcec83472dec70346544105118227fce63bae6a6686950846f65f30de621c1e5d6b7b20f3ce7d8ebbd95667c89123adb9efcbdd5ea1ba6e71b152bea43d3" ], - "tlsSettings" : { - "protocolVersion": "TlsV1_0OrLater", + "tlsSettings": { + "protocolVersion": "TlsV1_0OrLater", "_comment_1": "ciphers are ordered by preference", "ciphers": [ - "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-GCM-SHA384", "DHE-DSS-AES256-GCM-SHA384", "DHE-RSA-AES256-GCM-SHA384", @@ -71,15 +71,15 @@ ], "_comment_2": "prime256v1 := secp256r1", "ellipticCurves": [ - "brainpoolP512r1", + "brainpoolP512r1", "brainpoolP384r1", "brainpoolP256r1", "secp384r1", "prime256v1", "secp224r1" ], - "signatureAlgorithms" : [ - "Rsa+Sha512", + "signatureAlgorithms": [ + "Rsa+Sha512", "Dsa+Sha512", "Ec+Sha512", "Rsa+Sha384", @@ -94,34 +94,78 @@ ] }, - "tlsSettingsPsk" : { - "protocolVersion": "TlsV1_1OrLater", + "tlsSettingsPsk": { + "protocolVersion": "TlsV1_1OrLater", "_comment_1": "ciphers are ordered by preference", "ciphers": [ - "RSA-PSK-AES256-GCM-SHA384", + "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", + "signatureAlgorithms": [ + "Rsa+Sha512", "Rsa+Sha384", "Rsa+Sha256", "Rsa+Sha224" ] }, - "minStaticKeySizes": { - "Rsa": 2000, + "tlsSettingsRemoteReader": { + "protocolVersion": "TlsV1_2OrLater", + "_comment_1": "ciphers are ordered by preference", + "ciphers": [ + "ECDHE-RSA-AES256-GCM-SHA384", + "DHE-RSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-SHA384", + "DHE-RSA-AES256-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-SHA256", + "DHE-RSA-AES128-SHA256" + ], + "ellipticCurves": [ + "brainpoolP512r1", + "brainpoolP384r1", + "brainpoolP256r1", + "secp384r1", + "prime256v1", + "secp224r1" + ], + "signatureAlgorithms": [ + "Rsa+Sha512", + "Rsa+Sha384", + "Rsa+Sha256" + ] + }, + + "tlsSettingsRemoteReaderPairing": { + "protocolVersion": "TlsV1_2OrLater", + "_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" + ], + "signatureAlgorithms": [ + "Rsa+Sha512", + "Rsa+Sha384", + "Rsa+Sha256" + ] + }, + + "minStaticKeySizes": { + "Rsa": 2000, "Dsa": 2000, "Ec": 224 }, - "minEphemeralKeySizes": { - "Rsa": 2000, - "Dsa": 1024, + "minEphemeralKeySizes": { + "Rsa": 2000, + "Dsa": 2000, "Ec": 224 }, @@ -134,13 +178,8 @@ "testCertDescr": "30820266060A04007F00070301030101A1160C14476F7665726E696B757320546573742044564341A21A1318687474703A2F2F7777772E676F7665726E696B75732E6465A31A0C18476F7665726E696B757320476D6248202620436F2E204B47A420131E68747470733A2F2F746573742E676F7665726E696B75732D6569642E6465A582014F0C82014B416E736368726966743A090D0A476F7665726E696B757320476D6248202620436F2E204B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E090D0A0D0A452D4D61696C2D416472657373653A09686240626F732D6272656D656E2E6465090D0A0D0A5A7765636B20646573204175736C657365766F7267616E67733A0944656D6F6E7374726174696F6E20646573206549442D53657276696365090D0A0D0A5A757374C3A46E6469676520446174656E73636875747A61756673696368743A090D0A446965204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656EA64B134968747470733A2F2F746573742E676F7665726E696B75732D6569642E64653A3434332F417574656E742D44656D6F4170706C69636174696F6E2F5265636569766572536572766C6574A74631440420D2E54E1D26FC5DFC3408609831BBE4CFE3204365604849E7B094623566B54A760420E224D25B448DC054C023392CA11017751041D762F83D880895B3018D8EC2B290" }, - "drivers": { - "updateUrl": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_DRIVERS@/default-supported-devices.json" - }, - - "providers": { - "updateUrl": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_PROVIDERS@/@DEFAULT_PROVIDER_FILE@", - "iconsUpdateUrlBase": "@REMOTE_CONFIG_URL@@REMOTE_CONFIG_PATH_PROVIDERS@/provider/" + "updateServer": { + "baseUrl": "@REMOTE_CONFIG_URL@/updatable-files" }, "updates": { diff --git a/resources/default-providers-ios.json b/resources/default-providers-ios.json deleted file mode 100644 index b443f43..0000000 --- a/resources/default-providers-ios.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "issueDate": "2015-10-29T06:25:00+1:00", - "provider": [ - { - "name": "Beantragung Schwerbehindertenausweis Saarland", - "address": "https://gatewaylas.saarland.de/FV/Onlineantrag", - "phone": "", - "email": "", - "postaladdress": "", - "category": "citizen" - }, - { - "name": "Bürgerportal Rheinland Pfalz", - "address": "http://www.rlpdirekt.de/rheinland-pfalz", - "phone": "", - "email": "", - "postaladdress": "", - "category": "citizen" - }, - { - "name": ":::(bit)kasten", - "address": "https://www.bitkasten.de/", - "phone": "", - "email": "", - "postaladdress": "", - "category": "other" - }, - { - "name": "Bürgerkonto Test (Testausweis erforderlich)", - "address": "https://bk.test.bos-asp.de/BuergerKontoTestSPTest/", - "phone": "", - "email": "", - "postaladdress": "", - "category": "other" - }, - { - "name": "OpenPGP-eID", - "address": "https://pgp.governikus-eid.de/pgp", - "phone": "", - "email": "", - "postaladdress": "", - "category": "other" - }, - { - "name": "SkIDentity Service", - "address": "https://skidentity.de/service", - "phone": "", - "email": "", - "postaladdress": "", - "category": "other" - } - ] -} diff --git a/resources/default-providers.json b/resources/default-providers.json deleted file mode 100644 index 8cfc8f2..0000000 --- a/resources/default-providers.json +++ /dev/null @@ -1,964 +0,0 @@ -{ - "issueDate": "2017-09-15T11: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/", - "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", - "subjectUrls": ["https://www.bitkasten.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Allianz Maklerportal"}, - "address": "https://makler.allianz.de", - "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.", - "subjectUrls": ["https://npa.allianz.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Akteneinsicht in Stasi-Unterlagen"}, - "longName": {"" : "Akteneinsicht in Stasi-Unterlagen"}, - "shortDescription": {"": "Antragstellung auf Einsicht in Stasi-Unterlagen für Privatpersonen."}, - "longDescription": {"": "Privatpersonen können online mittels neuem Personalausweis ohne weitere Wege die Einsichtnahme in die von der Stasi angelegten Akten zur eigenen Person oder zu verstorbenen/vermissten nahen Angehörigen beantragen."}, - "address": "https://www.bstu.bund.de/DE/Akteneinsicht/Privatpersonen/Online-Antrag/online-antrag_node.html", - "homepage": "https://www.bstu.bund.de", - "phone": "+49 30 23 24-7000", - "email": "post@bstu.bund.de", - "postalAddress": "Der Bundesbeauftragte für die Unterlagen des Staatssicherheitsdienstes der ehemaligen Deutschen Demokratischen Republik (BStU)
Karl-Liebknecht-Straße 31/33
10178 Berlin", - "image": "stasi_image.jpg", - "icon": "stasi_icon.png", - "category": "citizen", - "subjectUrls": ["https://www.bstu-formulare.de/lip"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Ausweis Auskunft des Bundes"}, - "address": "https://www.buergerserviceportal.de/bund/ausweisapp/bspx_selbstauskunft", - "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", - "subjectUrls": ["https://www.buergerserviceportal.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG Online"}, - "address": "https://www.bafoegonline.bva.bund.de/", - "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": "Bundesverwaltungsamt
BT-BAföG
50728 Köln", - "category": "citizen", - "tcTokenUrl" : "", - "clientUrl" : "https://www.bafoegonline.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeldenMitNpaPreFlow", - "subjectUrls": ["https://e-id.bva.bund.de"] - }, - { - "exclude": ["ios"], - "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", - "homepage": "https://afoegfofa.osrz-akdb.de", - "phone": "+49 89 / 5903 - 0", - "email": "", - "postalAddress": "Anstalt für Kommunale Datenverarbeitung in Bayern (AKDB)
Hansastraße 12-16
80686 München", - "category": "citizen", - "subjectUrls": ["https://www.buergerserviceportal.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG Online Bayern (Studentenwerk)"}, - "address": "https://www.bafoeg-bayern.de", - "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": [] - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG 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", - "homepage": "https://www.berlin-bafoeg.de", - "phone": "+49 30 939 39 - 70", - "email": "info@stw.berlin", - "postalAddress": "studierendenWERK BERLIN
BAföG-Amt
Behrenstraße 40/41
10117 Berlin", - "image": "BafoegBerlin_image.jpg", - "icon": "BafoegBerlin_icon.png", - "category": "citizen", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "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", - "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"] - }, - { - "exclude": ["ios"], - "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", - "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"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG Hessen"}, - "longName": {"" : "BAföG/AFBG hessenweit"}, - "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", - "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"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG Online Mecklenburg-Vorpommern"}, - "address": "http://www.bm.regierung-mv.de/bafoeg", - "homepage": "http://www.regierung-mv.de/", - "phone": "", - "email": "", - "postalAddress": "Ministerium für Bildung, Wissenschaft und Kultur Mecklenburg-Vorpommern
Werderstraße 124
19055 Schwerin", - "category": "citizen", - "subjectUrls": ["https://fms.mv-regierung.de"] - }, - { - "exclude": ["ios"], - "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", - "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": [] - }, - { - "exclude": ["ios"], - "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/", - "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" - }, - { - "exclude": ["ios"], - "shortName": {"" : "BAföG Online Sachsen"}, - "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"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "bahn.de"}, - "address": "https://www.bahn.de/p/view/meinebahn/login.shtml", - "homepage": "https://www.bahn.de", - "phone": "+49 1806 - 996633", - "email": "reiseportal@bahn.de", - "postalAddress": "DB Vertrieb GmbH
Stephensonstraße 1
60326 Frankfurt am Main", - "category": "other", - "subjectUrls": ["https://www.bahn.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", - "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", - "homepage": "http://www.saarland.de/index.htm", - "phone": "+49 681/9978-2181", - "email": "", - "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.", - "subjectUrls": ["https://tbklas.saarland.de"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://formular.arbeitsagentur.de"] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://epetitionen.bundestag.de"] - }, - { - "exclude": ["ios"], - "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": "webmaster@buergerschaft.bremen.de", - "postalAddress": "", - "category": "citizen", - "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": "https://www.stadt-muenster.de/rathaus/online-dienste.html", - "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.", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "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": "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", - "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", - "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", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.nrw"] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.nrw"] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.nrw"] - }, - { - "exclude": ["ios"], - "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", - "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"] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.de"] - }, - { - "exclude": ["ios"], - "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/", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.de"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://www.cosmosdirekt.de"] - }, - { - "exclude": ["ios"], - "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/", - "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", - "subjectUrls": ["https://mein.foxdox.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Datev - Arbeitnehmer online / Lohn- und Gehaltsabrechnung"}, - "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/ano/", - "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", - "subjectUrls": ["https://secure6.datev.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Deutsche Post AG - POSTIDENT Verfahren"}, - "longName": {"" : "Deutsche Post AG - POSTIDENT Verfahren"}, - "shortDescription": {"": "Durch das Onlineverfahren POSTIDENT mit dem neuem Personalausweis, können Sie sich schnell und einfach online mit Ihrem neuen Personalausweis identifizieren."}, - "longDescription": {"": "Durch das Onlineverfahren POSTIDENT mit dem neuem Personalausweis, können Sie sich schnell und einfach online mit Ihrem neuen Personalausweis z.B. zur Eröffnung eines Tagesgeldkontos identifizieren: Sie werden hierzu von Ihrer Bank automatisch auf das POSTIDENT Portal geleitet und können sich mithilfe Ihres neuen Personalausweises mit freigeschalteter Online-Ausweisfunktion, einem Kartenlesegerät sowie der AusweisApp2 in wenigen Minuten sicher identifizieren."}, - "address": "https://www.deutschepost.de/de/p/postident/identifizierungsverfahren/postident-npa.html", - "homepage": "https://www.deutschepost.de/de/p/postident.html", - "email": "info@deutschepost.de", - "postalAddress": "Deutsche Post AG
Charles-de-Gaulle-Str. 20
53113 Bonn", - "image": "DeutschePost_image.jpg", - "icon": "DeutschePost_icon.png", - "category": "finance" - }, - { - "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", - "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.", - "subjectUrls": ["https://www.eservice-drv.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "eAntrag der Investitionsbank Berlin (IBB)"}, - "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://www.ibb.de/de/service/eantrag/eantrag.html", - "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.", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "shortName": {"" : "easy Login - Der Zugang für Finanz- & Versicherungsvermittler"}, - "address": "http://www.easy-login.de", - "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.", - "subjectUrls": ["https://easy-login.vdg-portal.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "ELSTER"}, - "longName": {"" : "ELSTER - Die elektronische Steuererklärung"}, - "shortDescription": {"": "Abwicklung der Steuererklärungen und -anmeldungen über das Internet."}, - "longDescription": {"": "ELSTER bietet im Rahmen der Registrierung, welche Voraussetzung für die Abwicklung der Steuererklärungen und Steueranmeldungen über das Internet ist, die Möglichkeit der Nutzung der Online-Ausweisfunktion."}, - "address": "https://www.elster.de", - "homepage": "https://www.elster.de", - "phone": "+49 89 9991 - 0", - "email": "info@elster.de", - "postalAddress": "Bayerisches Landesamt für Steuern - Dienststelle München
80284 München", - "image": "elster_image.png", - "icon": "elster_icon.png", - "category": "citizen", - "tcTokenUrlInfo" : "Registration required.", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "shortName": {"" : "ERGO Direkt Lebensversicherung AG"}, - "address": "https://ergodirekt.de/de/persoenlicherbereich.html#login", - "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", - "homepage": "https://www.berlin.de", - "phone": "+49 30 90269 – 0", - "email": "", - "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", - "category": "other", - "tcTokenUrlInfo" : "Car lizence number required", - "subjectUrls": [] - }, - { - "exclude": ["ios", "android"], - "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/", - "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.", - "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", - "homepage": "https://www.berlin.de", - "phone": "+49 30 90269 – 0", - "email": "", - "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", - "category": "other", - "tcTokenUrlInfo" : "Car lizence number required.", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "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": "dataporthamburggateway-service@dataport.de", - "postalAddress": "Bürgermeister Olaf Scholz
Rathausmarkt 1
20095 Hamburg", - "category": "citizen", - "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", - "subjectUrls": ["https://gateway.hamburg.de"] - }, - { - "exclude": ["ios"], - "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/", - "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", - "subjectUrls": ["https://www.huk24.de"] - }, - { - "shortName": {"" : "Kreis Borken"}, - "longName": {"" : "Kreis Borken - Kfz-Abmeldung Internet"}, - "shortDescription": {"": "Authentisierung für internetbasierte Kfz-Abmeldung."}, - "longDescription": {"": "Für die internetbasierte Kfz-Abmeldung wird die eID-Funktionalität des neuen Personalausweises benötigt."}, - "address": "https://formulare-extern.de/administrationCenter/Form-Solutions/05554004-0001/eID/eIDMandatory?directlink=https%3A%2F%2Fformulare-extern.de%2Fmetaform%2FForm-Solutions%2Fsid%2Fassistant%2F55dc839be4b054042fb93dba%3FeIDComplete%3Dtrue", - "homepage": "https://www.kreis-borken.de", - "phone": "+49 2861 / 82 - 2059", - "email": "zulassungsstelle@kreis-borken.de", - "postalAddress": "Kfz-Zulassungsstelle Borken
Burloer Str. 93
46325 Borken", - "image": "KreisBorken_image.png", - "icon": "KreisBorken_icon.svg", - "category": "citizen", - "tcTokenUrlInfo" : "", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://www.buergerservice.org"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://www.sixform.com"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "ID-Safe des Landkreis Würzburg"}, - "address": "https://www.buergerservice.org/ID-Safe-Wuerzburg", - "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", - "subjectUrls": ["https://www.buergerservice.org"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": [] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Kraftfahrt-Bundesamt - Registerauskunft"}, - "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. Die erforderlichen Daten werden dann von Ihrem Personalausweis ausgelesen. Die Auskunft erhalten Sie innerhalb weniger Tage per Post."}, - "address": "https://www.kba-online.de/registerauskunft/app/registeranfrage.html", - "homepage": "http://www.kba.de/", - "phone": "+49 461 316-0", - "email": "poststelle@kba.de", - "postalAddress": "Kraftfahrt-Bundesamt
Fördestraße 16
24944 Flensburg", - "category": "citizen", - "tcTokenUrl" : "https://www.kba-online.de:443/registerauskunft/app/eidstart.html;jsessionid=HZFFDC4E848A794D83A1D3032252F3F905?ref=HZFFDC4E848A794D83A1D3032252F3F905", - "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway.", - "subjectUrls": ["https://www.kba-online.de/registerauskunft"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://www.vbl.de"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://www.lvm.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Mentana-Claimsoft AG - Registrierung beim De-Mail Dienst"}, - "address": "https://www.fp-demail.de/", - "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.", - "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/", - "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", - "subjectUrls": ["https://pgp.governikus-eid.de"] - }, - { - "shortName": {"" : "Techniker Krankenkasse"}, - "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/118032", - "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": "insurance", - "tcTokenUrlInfo" : "Registration required", - "subjectUrls": ["https://www.tk.de"] - }, - { - "exclude": ["ios"], - "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", - "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", - "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/ausweisapp2/ausprobieren-meine-daten-einsehen/", - "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"] - }, - { - "exclude": ["ios"], - "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", - "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.", - "subjectUrls": ["https://www.buergerserviceportal.nrw"] - }, - { - "shortName": {"" : "SkIDentity Service"}, - "longName": {"" : "SkIDentity Service"}, - "longDescription": {"": "SkIDentity unterstützt die Umsetzung der Cyber-Sicherheitsstrategie der Bundesregierung und macht den elektronischen Personalausweis im Internet sehr leicht und mobil nutzbar. Der SkIDentity-Dienst bietet „Mobile eID as a Service“ und leitet bei Bedarf aus elektronischen Ausweisdokumenten kryptographisch geschützte „Cloud Identitäten“ ab, die auf beliebige Smartphones übertragen und dort sicher mobil genutzt werden können. Darüber hinaus kann auch die bislang aufwändige eID-Integration in einem komfortablen Portal erfolgen und die vertrauenswürdigen Identitäten kommen nun selbst aus einer vom Bundesamt für Sicherheit in der Informationstechnik (BSI) zertifizierten „Secure Cloud Infrastructure“."}, - "address": "https://skidentity.de/service", - "homepage": "https://www.skidentity.de", - "phone": "+49 9571 604 8014", - "email": "detlef.huehnlein@ecsec.de", - "postalAddress": "ecsec GmbH
Sudetenstraße 16
96247 Michelau", - "category": "other", - "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", - "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", - "subjectUrls": ["https://meinkonto.nuernberg.de"] - }, - { - "exclude": ["ios"], - "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/", - "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.", - "subjectUrls": ["https://tbk.ego-mv.de/BuergerKontoWeb"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Telekom DeMail für Privat- und Geschäftskunden"}, - "address": "https://www.telekom.de/de-mail", - "homepage": "https://www.telekom.de/", - "phone": "+49 800 33 01000", - "email": "", - "postalAddress": "Telekom Deutschland GmbH
Landgrabenweg 151
53227 Bonn", - "category": "other", - "tcTokenUrlInfo" : "Registration required", - "subjectUrls": ["https://www.de-mail.t-online.de"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "T-Systems DeMail für Großkunden"}, - "address": "https://www.t-systems.de/de-mail", - "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", - "subjectUrls": ["https://www.de-mail.t-systems.de"] - }, - { - "exclude": ["ios"], - "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", - "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", - "subjectUrls": ["https://ea.stadt-koeln.de"] - }, - { - "exclude": ["ios"], - "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"] - }, - { - "exclude": ["ios"], - "shortName": {"" : "Vollstreckungsportal"}, - "longDescription": {"": "Herzlich willkommen auf dem Gemeinsamen Vollstreckungsportal der Länder."}, - "address": "https://www.vollstreckungsportal.de/auskunft/priv/anmelden.jsf?type=npa", - "homepage": "https://www.vollstreckungsportal.de/", - "phone": "", - "email": "bundesportal@ag-hagen.nrw.de", - "postalAddress": "Land Nordrhein-Westfalen
vertreten durch das Justizministerium
Martin-Luther-Platz 40
40212 Düsseldorf", - "category": "citizen", - "tcTokenUrlInfo" : "Registration required.", - "subjectUrls": ["https://www.vollstreckungsportal.de"] - } - ] -} diff --git a/resources/default-supported-devices.json b/resources/default-supported-devices.json deleted file mode 100644 index 3071203..0000000 --- a/resources/default-supported-devices.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "IssueDate": "2015-11-24T12:00:00+1:00", - "SupportedDevices": - [ - { - "ReaderType": "REINER_cyberJack_RFID_komfort", - "VendorId": "0x0C4B", - "ProductId": "0x0501", - "Name": "REINER SCT cyberJack RFID komfort", - "Drivers": - [ - { - "Platforms": ["WV_WINDOWS7", "WV_WINDOWS8", "WV_WINDOWS8_1", "WV_WINDOWS10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/bc_7_2_3.exe" - }, - { - "Platforms": ["MV_10_9", "MV_10_10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/pcsc-cyberjack_3.99.5final.SP07-universal-signed.pkg" - }, - { - "Platforms": ["MV_10_11", "MV_10_12"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/01_pcsc-cyberjack_3.99.5final.SP08-universal-osx10.11-signed.pkg" - }, - { - "Platforms": ["LINUX"], - "URL": "https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-komfort-linux.html" - } - ] - }, - - { - "ReaderType": "REINER_cyberJack_RFID_standard", - "VendorId": "0x0C4B", - "ProductId": "0x0500", - "Name": "REINER SCT cyberJack RFID standard", - "Drivers": - [ - { - "Platforms": ["WV_WINDOWS7", "WV_WINDOWS8", "WV_WINDOWS8_1", "WV_WINDOWS10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/bc_7_2_3.exe" - }, - { - "Platforms": ["MV_10_9", "MV_10_10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/pcsc-cyberjack_3.99.5final.SP07-universal-signed.pkg" - }, - { - "Platforms": ["MV_10_11", "MV_10_12"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/01_pcsc-cyberjack_3.99.5final.SP08-universal-osx10.11-signed.pkg" - }, - { - "Platforms": ["LINUX"], - "URL": "https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-standard-linux.html" - } - ] - }, - - { - "ReaderType": "REINER_cyberJack_RFID_basis", - "VendorId": "0x0C4B", - "ProductId": "0x9102", - "Name": "REINER SCT cyberJack RFID basis", - "Drivers": - [ - { - "Platforms": ["WV_WINDOWS7", "WV_WINDOWS8", "WV_WINDOWS8_1", "WV_WINDOWS10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/01_cJRFIDbasisIFD.exe" - }, - { - "Platforms": ["MV_10_9", "MV_10_10", "MV_10_11", "MV_10_12"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/ifd-ccid-1.4.8-universal-signed.pkg" - }, - { - "Platforms": ["LINUX"], - "URL": "https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-basis-linux.html" - } - ] - }, - - { - "ReaderType": "SCM_SDI011", - "VendorId": "0x04E6", - "ProductId": "0x512B", - "Name": "SDI011 Contactless Reader", - "Drivers": - [ - { - "Platforms": ["WV_WINDOWS7", "WV_WINDOWS8", "WV_WINDOWS8_1", "WV_WINDOWS10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/SDI011_win_installer_V1.01.zip" - }, - { - "Platforms": ["MV_10_9", "MV_10_10", "MV_10_11", "MV_10_12"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/SDI011_mac_V5.0.18.zip" - }, - { - "Platforms": ["LINUX"], - "URL": "http://support.identive-group.com/npa_downloads.php" - } - ] - }, - - { - "ReaderType": "SCM_SCL011_Contactless_Reader", - "VendorId": "0x04E6", - "ProductId": "0x5292", - "Name": "SCL01x Contactless Reader", - "Drivers": - [ - { - "Platforms": ["WV_WINDOWS7", "WV_WINDOWS8", "WV_WINDOWS8_1", "WV_WINDOWS10"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/SCL011_win_installer_V1.01.zip" - }, - { - "Platforms": ["MV_10_9", "MV_10_10", "MV_10_11", "MV_10_12"], - "URL": "https://appl.governikus-asp.de/ausweisapp2/driver/SCL011_V2.09_mac.zip" - }, - { - "Platforms": ["LINUX"], - "URL": "http://support.identive-group.com/npa_downloads.php" - } - ] - } - ] -} diff --git a/resources/hooks/formatting b/resources/hooks/formatting deleted file mode 100755 index dfa78e8..0000000 --- a/resources/hooks/formatting +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -root=$(hg root) -revs=$(hg log -r "$HG_NODE:tip" --template '{rev} ') #Intentional space after {rev} -builddir=$root/build -rc=0 - -for rev in $revs -do - hg update -C -r $rev > /dev/null - rm -rf $builddir - mkdir $builddir - cd $builddir - cmake -DENABLE_DVCS=false -Dtools.only=true $root > /dev/null - make format > /dev/null - cd $root - STATUS=$(hg status | wc -c) - if [ "$STATUS" != "0" ]; then - desc=$(hg log -r $rev --template '{firstline(desc)}') - echo "Changeset $rev is not formatted correctly: $desc" - rc=-1 - break - fi -done - -rm -rf $builddir -hg update -C null > /dev/null -exit $rc - diff --git a/resources/images/android/arrowLeftWhite.svg b/resources/images/android/arrowLeftWhite.svg index eaa3030..bbdc59c 100644 --- a/resources/images/android/arrowLeftWhite.svg +++ b/resources/images/android/arrowLeftWhite.svg @@ -1,11 +1,10 @@ - - + + width="14px" height="32px" viewBox="0 0 14 32" xml:space="preserve"> - diff --git a/resources/images/android/arrowRight.svg b/resources/images/android/arrowRight.svg index cfd991f..0f3d647 100644 --- a/resources/images/android/arrowRight.svg +++ b/resources/images/android/arrowRight.svg @@ -1,7 +1,7 @@ + width="70px" height="160px" viewBox="0 0 14 32" enable-background="new 0 0 14 32" xml:space="preserve"> diff --git a/resources/images/android/arrowRightWhite.svg b/resources/images/android/arrowRightWhite.svg index e5a3879..b017764 100644 --- a/resources/images/android/arrowRightWhite.svg +++ b/resources/images/android/arrowRightWhite.svg @@ -1,11 +1,10 @@ - - + + width="14px" height="32px" viewBox="0 0 14 32" xml:space="preserve"> - diff --git a/resources/images/android/navigation/balloon.svg b/resources/images/android/navigation/balloon.svg index 9dbf87f..1325056 100644 --- a/resources/images/android/navigation/balloon.svg +++ b/resources/images/android/navigation/balloon.svg @@ -1,5 +1,5 @@ - + + + + diff --git a/resources/images/android/navigation/remotesettings.svg b/resources/images/android/navigation/remotesettings.svg new file mode 100644 index 0000000..e0cee90 --- /dev/null +++ b/resources/images/android/navigation/remotesettings.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + diff --git a/resources/images/android/navigation/support.svg b/resources/images/android/navigation/support.svg index 6eaa164..1f251af 100644 --- a/resources/images/android/navigation/support.svg +++ b/resources/images/android/navigation/support.svg @@ -1,7 +1,9 @@ - + - - + + + diff --git a/resources/images/autentapp2.iconset/icon_128x128.png b/resources/images/autentapp2.iconset/icon_128x128.png deleted file mode 100644 index 7375e62..0000000 Binary files a/resources/images/autentapp2.iconset/icon_128x128.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_128x128@2x.png b/resources/images/autentapp2.iconset/icon_128x128@2x.png deleted file mode 100644 index 344c865..0000000 Binary files a/resources/images/autentapp2.iconset/icon_128x128@2x.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_16x16.png b/resources/images/autentapp2.iconset/icon_16x16.png deleted file mode 100644 index 9155972..0000000 Binary files a/resources/images/autentapp2.iconset/icon_16x16.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_16x16@2x.png b/resources/images/autentapp2.iconset/icon_16x16@2x.png deleted file mode 100644 index 94217c5..0000000 Binary files a/resources/images/autentapp2.iconset/icon_16x16@2x.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_256x256.png b/resources/images/autentapp2.iconset/icon_256x256.png deleted file mode 100644 index 344c865..0000000 Binary files a/resources/images/autentapp2.iconset/icon_256x256.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_256x256@2x.png b/resources/images/autentapp2.iconset/icon_256x256@2x.png deleted file mode 100644 index ebbe464..0000000 Binary files a/resources/images/autentapp2.iconset/icon_256x256@2x.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_32x32.png b/resources/images/autentapp2.iconset/icon_32x32.png deleted file mode 100644 index 94217c5..0000000 Binary files a/resources/images/autentapp2.iconset/icon_32x32.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_32x32@2x.png b/resources/images/autentapp2.iconset/icon_32x32@2x.png deleted file mode 100644 index 74707af..0000000 Binary files a/resources/images/autentapp2.iconset/icon_32x32@2x.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_512x512.png b/resources/images/autentapp2.iconset/icon_512x512.png deleted file mode 100644 index ebbe464..0000000 Binary files a/resources/images/autentapp2.iconset/icon_512x512.png and /dev/null differ diff --git a/resources/images/autentapp2.iconset/icon_512x512@2x.png b/resources/images/autentapp2.iconset/icon_512x512@2x.png deleted file mode 100644 index aec5c6d..0000000 Binary files a/resources/images/autentapp2.iconset/icon_512x512@2x.png and /dev/null differ diff --git a/resources/images/green_check_mark.svg b/resources/images/green_check_mark.svg new file mode 100755 index 0000000..9ebfea5 --- /dev/null +++ b/resources/images/green_check_mark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/gruener_Haken.svg b/resources/images/gruener_Haken.svg index 09d0a7c..59e2423 100755 --- a/resources/images/gruener_Haken.svg +++ b/resources/images/gruener_Haken.svg @@ -1,9 +1,7 @@ - + + diff --git a/resources/images/iOS/appIcons/beta/icon60@2x.png b/resources/images/iOS/appIcons/beta/icon60@2x.png new file mode 100644 index 0000000..c66dd0b Binary files /dev/null and b/resources/images/iOS/appIcons/beta/icon60@2x.png differ diff --git a/resources/images/iOS/appIcons/beta/icon60@3x.png b/resources/images/iOS/appIcons/beta/icon60@3x.png new file mode 100644 index 0000000..0e33ae8 Binary files /dev/null and b/resources/images/iOS/appIcons/beta/icon60@3x.png differ diff --git a/resources/images/iOS/appIcons/beta/icon76.png b/resources/images/iOS/appIcons/beta/icon76.png new file mode 100644 index 0000000..0394f1f Binary files /dev/null and b/resources/images/iOS/appIcons/beta/icon76.png differ diff --git a/resources/images/iOS/appIcons/beta/icon76@2x.png b/resources/images/iOS/appIcons/beta/icon76@2x.png new file mode 100644 index 0000000..acbc9bc Binary files /dev/null and b/resources/images/iOS/appIcons/beta/icon76@2x.png differ diff --git a/resources/images/iOS/appIcons/beta/icon83.5@2x.png b/resources/images/iOS/appIcons/beta/icon83.5@2x.png new file mode 100644 index 0000000..931fb4f Binary files /dev/null and b/resources/images/iOS/appIcons/beta/icon83.5@2x.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall.png b/resources/images/iOS/appIcons/beta/iconSmall.png new file mode 100644 index 0000000..1d44829 Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall40.png b/resources/images/iOS/appIcons/beta/iconSmall40.png new file mode 100644 index 0000000..a1e3f67 Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall40.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall40@2x.png b/resources/images/iOS/appIcons/beta/iconSmall40@2x.png new file mode 100644 index 0000000..3f19d76 Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall40@2x.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall40@3x.png b/resources/images/iOS/appIcons/beta/iconSmall40@3x.png new file mode 100644 index 0000000..c66dd0b Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall40@3x.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall@2x.png b/resources/images/iOS/appIcons/beta/iconSmall@2x.png new file mode 100644 index 0000000..37e8b9b Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall@2x.png differ diff --git a/resources/images/iOS/appIcons/beta/iconSmall@3x.png b/resources/images/iOS/appIcons/beta/iconSmall@3x.png new file mode 100644 index 0000000..d3a0140 Binary files /dev/null and b/resources/images/iOS/appIcons/beta/iconSmall@3x.png differ diff --git a/resources/images/iOS/appIcons/icon29x29@2x.png b/resources/images/iOS/appIcons/icon29x29@2x.png deleted file mode 100644 index fcc7d7a..0000000 Binary files a/resources/images/iOS/appIcons/icon29x29@2x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon29x29@2x~ipad.png b/resources/images/iOS/appIcons/icon29x29@2x~ipad.png deleted file mode 100644 index fcc7d7a..0000000 Binary files a/resources/images/iOS/appIcons/icon29x29@2x~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon29x29@3x.png b/resources/images/iOS/appIcons/icon29x29@3x.png deleted file mode 100644 index 381900e..0000000 Binary files a/resources/images/iOS/appIcons/icon29x29@3x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon29x29~ipad.png b/resources/images/iOS/appIcons/icon29x29~ipad.png deleted file mode 100644 index 3023a72..0000000 Binary files a/resources/images/iOS/appIcons/icon29x29~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon40x40@2x.png b/resources/images/iOS/appIcons/icon40x40@2x.png deleted file mode 100644 index 749e80f..0000000 Binary files a/resources/images/iOS/appIcons/icon40x40@2x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon40x40@2x~ipad.png b/resources/images/iOS/appIcons/icon40x40@2x~ipad.png deleted file mode 100644 index 749e80f..0000000 Binary files a/resources/images/iOS/appIcons/icon40x40@2x~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon40x40@3x.png b/resources/images/iOS/appIcons/icon40x40@3x.png deleted file mode 100644 index 9cfd9be..0000000 Binary files a/resources/images/iOS/appIcons/icon40x40@3x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon40x40~ipad.png b/resources/images/iOS/appIcons/icon40x40~ipad.png deleted file mode 100644 index c5ed9c6..0000000 Binary files a/resources/images/iOS/appIcons/icon40x40~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon60@2x.png b/resources/images/iOS/appIcons/icon60@2x.png new file mode 100644 index 0000000..6f82d20 Binary files /dev/null and b/resources/images/iOS/appIcons/icon60@2x.png differ diff --git a/resources/images/iOS/appIcons/icon60@3x.png b/resources/images/iOS/appIcons/icon60@3x.png new file mode 100644 index 0000000..415d941 Binary files /dev/null and b/resources/images/iOS/appIcons/icon60@3x.png differ diff --git a/resources/images/iOS/appIcons/icon60x60@2x.png b/resources/images/iOS/appIcons/icon60x60@2x.png deleted file mode 100644 index 9cfd9be..0000000 Binary files a/resources/images/iOS/appIcons/icon60x60@2x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon60x60@3x.png b/resources/images/iOS/appIcons/icon60x60@3x.png deleted file mode 100644 index 135fb06..0000000 Binary files a/resources/images/iOS/appIcons/icon60x60@3x.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon76.png b/resources/images/iOS/appIcons/icon76.png new file mode 100644 index 0000000..7963669 Binary files /dev/null and b/resources/images/iOS/appIcons/icon76.png differ diff --git a/resources/images/iOS/appIcons/icon76@2x.png b/resources/images/iOS/appIcons/icon76@2x.png new file mode 100644 index 0000000..796f589 Binary files /dev/null and b/resources/images/iOS/appIcons/icon76@2x.png differ diff --git a/resources/images/iOS/appIcons/icon76x76@2x~ipad.png b/resources/images/iOS/appIcons/icon76x76@2x~ipad.png deleted file mode 100644 index 7e5d4a5..0000000 Binary files a/resources/images/iOS/appIcons/icon76x76@2x~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon76x76~ipad.png b/resources/images/iOS/appIcons/icon76x76~ipad.png deleted file mode 100644 index 182904f..0000000 Binary files a/resources/images/iOS/appIcons/icon76x76~ipad.png and /dev/null differ diff --git a/resources/images/iOS/appIcons/icon83.5@2x.png b/resources/images/iOS/appIcons/icon83.5@2x.png new file mode 100644 index 0000000..06dc3bb Binary files /dev/null and b/resources/images/iOS/appIcons/icon83.5@2x.png differ diff --git a/resources/images/iOS/appIcons/iconSmall.png b/resources/images/iOS/appIcons/iconSmall.png new file mode 100644 index 0000000..5428afb Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall.png differ diff --git a/resources/images/iOS/appIcons/iconSmall40.png b/resources/images/iOS/appIcons/iconSmall40.png new file mode 100644 index 0000000..1a967c2 Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall40.png differ diff --git a/resources/images/iOS/appIcons/iconSmall40@2x.png b/resources/images/iOS/appIcons/iconSmall40@2x.png new file mode 100644 index 0000000..93e1942 Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall40@2x.png differ diff --git a/resources/images/iOS/appIcons/iconSmall40@3x.png b/resources/images/iOS/appIcons/iconSmall40@3x.png new file mode 100644 index 0000000..6f82d20 Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall40@3x.png differ diff --git a/resources/images/iOS/appIcons/iconSmall@2x.png b/resources/images/iOS/appIcons/iconSmall@2x.png new file mode 100644 index 0000000..79e6754 Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall@2x.png differ diff --git a/resources/images/iOS/appIcons/iconSmall@3x.png b/resources/images/iOS/appIcons/iconSmall@3x.png new file mode 100644 index 0000000..8e66b90 Binary files /dev/null and b/resources/images/iOS/appIcons/iconSmall@3x.png differ diff --git a/resources/images/iOS/launchIcons/launchIcon.png b/resources/images/iOS/launchIcons/launchIcon.png deleted file mode 100644 index 1950b57..0000000 Binary files a/resources/images/iOS/launchIcons/launchIcon.png and /dev/null differ diff --git a/resources/images/iOS/launchIcons/launchIcon6.png b/resources/images/iOS/launchIcons/launchIcon6.png deleted file mode 100644 index 6006f1f..0000000 Binary files a/resources/images/iOS/launchIcons/launchIcon6.png and /dev/null differ diff --git a/resources/images/iOS/launchIcons/launchIcon6p.png b/resources/images/iOS/launchIcons/launchIcon6p.png deleted file mode 100644 index ffc7d4a..0000000 Binary files a/resources/images/iOS/launchIcons/launchIcon6p.png and /dev/null differ diff --git a/resources/images/iOS/launchImages/Default-568h@2x.png b/resources/images/iOS/launchImages/Default-568h@2x.png new file mode 100644 index 0000000..3e96d42 Binary files /dev/null and b/resources/images/iOS/launchImages/Default-568h@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1024@2x.png b/resources/images/iOS/launchImages/launchImage1024@2x.png new file mode 100644 index 0000000..49b614d Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1024@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1024@3x.png b/resources/images/iOS/launchImages/launchImage1024@3x.png new file mode 100644 index 0000000..49adb83 Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1024@3x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1112@2x.png b/resources/images/iOS/launchImages/launchImage1112@2x.png new file mode 100644 index 0000000..97f41a2 Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1112@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1112@3x.png b/resources/images/iOS/launchImages/launchImage1112@3x.png new file mode 100644 index 0000000..592076e Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1112@3x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1366@2x.png b/resources/images/iOS/launchImages/launchImage1366@2x.png new file mode 100644 index 0000000..82f716c Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1366@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage1366@3x.png b/resources/images/iOS/launchImages/launchImage1366@3x.png new file mode 100644 index 0000000..d3b039e Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage1366@3x.png differ diff --git a/resources/images/iOS/launchImages/launchImage568@2x.png b/resources/images/iOS/launchImages/launchImage568@2x.png new file mode 100644 index 0000000..3e96d42 Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage568@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage568@3x.png b/resources/images/iOS/launchImages/launchImage568@3x.png new file mode 100644 index 0000000..8a91010 Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage568@3x.png differ diff --git a/resources/images/iOS/launchImages/launchImage667@2x.png b/resources/images/iOS/launchImages/launchImage667@2x.png new file mode 100644 index 0000000..b8bb764 Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage667@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage667@3x.png b/resources/images/iOS/launchImages/launchImage667@3x.png new file mode 100644 index 0000000..68ae22f Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage667@3x.png differ diff --git a/resources/images/iOS/launchImages/launchImage736@2x.png b/resources/images/iOS/launchImages/launchImage736@2x.png new file mode 100644 index 0000000..4fa2ffa Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage736@2x.png differ diff --git a/resources/images/iOS/launchImages/launchImage736@3x.png b/resources/images/iOS/launchImages/launchImage736@3x.png new file mode 100644 index 0000000..6c6dfbd Binary files /dev/null and b/resources/images/iOS/launchImages/launchImage736@3x.png differ diff --git a/resources/images/iOS/more/icon_mehr_license.svg b/resources/images/iOS/more/icon_mehr_license.svg new file mode 100644 index 0000000..d43dc87 --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_license.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + § + diff --git a/resources/images/iOS/more/icon_mehr_remotereader.svg b/resources/images/iOS/more/icon_mehr_remotereader.svg new file mode 100644 index 0000000..31955bc --- /dev/null +++ b/resources/images/iOS/more/icon_mehr_remotereader.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/resources/images/icon_attention.svg b/resources/images/icon_attention.svg index ac9a9fa..2e37ab1 100644 --- a/resources/images/icon_attention.svg +++ b/resources/images/icon_attention.svg @@ -1,14 +1,7 @@ - - - + - - - - - - diff --git a/resources/images/icon_Bluetooth.svg b/resources/images/icon_bluetooth.svg similarity index 100% rename from resources/images/icon_Bluetooth.svg rename to resources/images/icon_bluetooth.svg diff --git a/resources/images/icon_remote.svg b/resources/images/icon_remote.svg new file mode 100644 index 0000000..6f7223f --- /dev/null +++ b/resources/images/icon_remote.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/location_flag_de.svg b/resources/images/location_flag_de.svg new file mode 100644 index 0000000..fe3392b --- /dev/null +++ b/resources/images/location_flag_de.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/location_flag_en.svg b/resources/images/location_flag_en.svg new file mode 100644 index 0000000..717e0cd --- /dev/null +++ b/resources/images/location_flag_en.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/images/padlock.svg b/resources/images/padlock.svg new file mode 100644 index 0000000..d7ee69c --- /dev/null +++ b/resources/images/padlock.svg @@ -0,0 +1,6 @@ + + + + diff --git a/resources/images/padlock_empty.svg b/resources/images/padlock_empty.svg new file mode 100644 index 0000000..4090a66 --- /dev/null +++ b/resources/images/padlock_empty.svg @@ -0,0 +1,2 @@ + + diff --git a/resources/images/phone_remote.svg b/resources/images/phone_remote.svg new file mode 100644 index 0000000..0940f49 --- /dev/null +++ b/resources/images/phone_remote.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/phone_to_pc.svg b/resources/images/phone_to_pc.svg new file mode 100644 index 0000000..486ebb9 --- /dev/null +++ b/resources/images/phone_to_pc.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices.svg b/resources/images/provider/categoryIcons/+android/citizen.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/CitizenServices.svg rename to resources/images/provider/categoryIcons/+android/citizen.svg diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_bg.svg b/resources/images/provider/categoryIcons/+android/citizen_bg.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/CitizenServices_bg.svg rename to resources/images/provider/categoryIcons/+android/citizen_bg.svg diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_button.svg b/resources/images/provider/categoryIcons/+android/citizen_button.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/CitizenServices_button.svg rename to resources/images/provider/categoryIcons/+android/citizen_button.svg diff --git a/resources/images/provider/categoryIcons/+android/CitizenServices_section.svg b/resources/images/provider/categoryIcons/+android/citizen_section.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/CitizenServices_section.svg rename to resources/images/provider/categoryIcons/+android/citizen_section.svg diff --git a/resources/images/provider/categoryIcons/+android/Financials.svg b/resources/images/provider/categoryIcons/+android/finance.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Financials.svg rename to resources/images/provider/categoryIcons/+android/finance.svg diff --git a/resources/images/provider/categoryIcons/+android/Financials_bg.svg b/resources/images/provider/categoryIcons/+android/finance_bg.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Financials_bg.svg rename to resources/images/provider/categoryIcons/+android/finance_bg.svg diff --git a/resources/images/provider/categoryIcons/+android/Financials_button.svg b/resources/images/provider/categoryIcons/+android/finance_button.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Financials_button.svg rename to resources/images/provider/categoryIcons/+android/finance_button.svg diff --git a/resources/images/provider/categoryIcons/+android/Financials_section.svg b/resources/images/provider/categoryIcons/+android/finance_section.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Financials_section.svg rename to resources/images/provider/categoryIcons/+android/finance_section.svg diff --git a/resources/images/provider/categoryIcons/+android/General.svg b/resources/images/provider/categoryIcons/+android/general.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/General.svg rename to resources/images/provider/categoryIcons/+android/general.svg diff --git a/resources/images/provider/categoryIcons/+android/General_bg.svg b/resources/images/provider/categoryIcons/+android/general_bg.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/General_bg.svg rename to resources/images/provider/categoryIcons/+android/general_bg.svg diff --git a/resources/images/provider/categoryIcons/+android/General_button.svg b/resources/images/provider/categoryIcons/+android/general_button.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/General_button.svg rename to resources/images/provider/categoryIcons/+android/general_button.svg diff --git a/resources/images/provider/categoryIcons/+android/General_section.svg b/resources/images/provider/categoryIcons/+android/general_section.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/General_section.svg rename to resources/images/provider/categoryIcons/+android/general_section.svg diff --git a/resources/images/provider/categoryIcons/+android/Insurances.svg b/resources/images/provider/categoryIcons/+android/insurance.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Insurances.svg rename to resources/images/provider/categoryIcons/+android/insurance.svg diff --git a/resources/images/provider/categoryIcons/+android/Insurances_bg.svg b/resources/images/provider/categoryIcons/+android/insurance_bg.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Insurances_bg.svg rename to resources/images/provider/categoryIcons/+android/insurance_bg.svg diff --git a/resources/images/provider/categoryIcons/+android/Insurances_button.svg b/resources/images/provider/categoryIcons/+android/insurance_button.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Insurances_button.svg rename to resources/images/provider/categoryIcons/+android/insurance_button.svg diff --git a/resources/images/provider/categoryIcons/+android/Insurances_section.svg b/resources/images/provider/categoryIcons/+android/insurance_section.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/Insurances_section.svg rename to resources/images/provider/categoryIcons/+android/insurance_section.svg diff --git a/resources/images/provider/categoryIcons/+android/OtherServices.svg b/resources/images/provider/categoryIcons/+android/other.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/OtherServices.svg rename to resources/images/provider/categoryIcons/+android/other.svg diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_bg.svg b/resources/images/provider/categoryIcons/+android/other_bg.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/OtherServices_bg.svg rename to resources/images/provider/categoryIcons/+android/other_bg.svg diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_button.svg b/resources/images/provider/categoryIcons/+android/other_button.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/OtherServices_button.svg rename to resources/images/provider/categoryIcons/+android/other_button.svg diff --git a/resources/images/provider/categoryIcons/+android/OtherServices_section.svg b/resources/images/provider/categoryIcons/+android/other_section.svg similarity index 100% rename from resources/images/provider/categoryIcons/+android/OtherServices_section.svg rename to resources/images/provider/categoryIcons/+android/other_section.svg diff --git a/resources/images/provider/categoryIcons/CitizenServices.svg b/resources/images/provider/categoryIcons/citizen.svg similarity index 100% rename from resources/images/provider/categoryIcons/CitizenServices.svg rename to resources/images/provider/categoryIcons/citizen.svg diff --git a/resources/images/provider/categoryIcons/Financials.svg b/resources/images/provider/categoryIcons/finance.svg similarity index 100% rename from resources/images/provider/categoryIcons/Financials.svg rename to resources/images/provider/categoryIcons/finance.svg diff --git a/resources/images/provider/categoryIcons/General.svg b/resources/images/provider/categoryIcons/general.svg similarity index 100% rename from resources/images/provider/categoryIcons/General.svg rename to resources/images/provider/categoryIcons/general.svg diff --git a/resources/images/provider/categoryIcons/Insurances.svg b/resources/images/provider/categoryIcons/insurance.svg similarity index 100% rename from resources/images/provider/categoryIcons/Insurances.svg rename to resources/images/provider/categoryIcons/insurance.svg diff --git a/resources/images/provider/categoryIcons/OtherServices.svg b/resources/images/provider/categoryIcons/other.svg similarity index 100% rename from resources/images/provider/categoryIcons/OtherServices.svg rename to resources/images/provider/categoryIcons/other.svg diff --git a/resources/images/provider/information.svg b/resources/images/provider/information.svg index 1931571..b7d8c48 100644 --- a/resources/images/provider/information.svg +++ b/resources/images/provider/information.svg @@ -1,5 +1,5 @@ - + diff --git a/resources/images/reader/default_more_cardreader.png b/resources/images/reader/default_more_cardreader.png deleted file mode 100644 index 4c24abb..0000000 Binary files a/resources/images/reader/default_more_cardreader.png and /dev/null differ diff --git a/resources/images/reader/default_more_cardreader.svg b/resources/images/reader/default_more_cardreader.svg deleted file mode 100644 index 06a6848..0000000 --- a/resources/images/reader/default_more_cardreader.svg +++ /dev/null @@ -1,325 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/reader/default_more_reader.png b/resources/images/reader/default_more_reader.png new file mode 100755 index 0000000..ebacd8c Binary files /dev/null and b/resources/images/reader/default_more_reader.png differ diff --git a/resources/images/reader/default_no_card_found.png b/resources/images/reader/default_no_card.png similarity index 100% rename from resources/images/reader/default_no_card_found.png rename to resources/images/reader/default_no_card.png diff --git a/resources/images/reader/default_no_card_found.svg b/resources/images/reader/default_no_card_found.svg deleted file mode 100644 index 7d2e85b..0000000 --- a/resources/images/reader/default_no_card_found.svg +++ /dev/null @@ -1,884 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/reader/default_no_cardreader_01.svg b/resources/images/reader/default_no_cardreader_01.svg deleted file mode 100644 index 821201c..0000000 --- a/resources/images/reader/default_no_cardreader_01.svg +++ /dev/null @@ -1,392 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/reader/default_no_cardreader_01.png b/resources/images/reader/default_no_reader.png similarity index 100% rename from resources/images/reader/default_no_cardreader_01.png rename to resources/images/reader/default_no_reader.png diff --git a/resources/images/reader/default_reader.png b/resources/images/reader/default_reader.png new file mode 100755 index 0000000..ebacd8c Binary files /dev/null and b/resources/images/reader/default_reader.png differ diff --git a/resources/images/reader/default_reader_mit_ausweis.png b/resources/images/reader/default_reader_mit_ausweis.png new file mode 100644 index 0000000..49cc2b3 Binary files /dev/null and b/resources/images/reader/default_reader_mit_ausweis.png differ diff --git a/resources/images/reader/img_ACS_ACR1281U.png b/resources/images/reader/img_ACS_ACR1281U.png deleted file mode 100644 index ca1aa8a..0000000 Binary files a/resources/images/reader/img_ACS_ACR1281U.png and /dev/null differ diff --git a/resources/images/reader/img_ACS_ACR1281U_mit_ausweis.png b/resources/images/reader/img_ACS_ACR1281U_mit_ausweis.png deleted file mode 100644 index 790301e..0000000 Binary files a/resources/images/reader/img_ACS_ACR1281U_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_FEIG_myAXXES_basic.png b/resources/images/reader/img_FEIG_myAXXES_basic.png deleted file mode 100644 index e01c47e..0000000 Binary files a/resources/images/reader/img_FEIG_myAXXES_basic.png and /dev/null differ diff --git a/resources/images/reader/img_FEIG_myAXXES_basic_mit_ausweis.png b/resources/images/reader/img_FEIG_myAXXES_basic_mit_ausweis.png deleted file mode 100644 index 0924bb4..0000000 Binary files a/resources/images/reader/img_FEIG_myAXXES_basic_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Gemalto_Prox_DU.png b/resources/images/reader/img_Gemalto_Prox_DU.png deleted file mode 100644 index ba51331..0000000 Binary files a/resources/images/reader/img_Gemalto_Prox_DU.png and /dev/null differ diff --git a/resources/images/reader/img_Gemalto_Prox_DU_mit_ausweis.png b/resources/images/reader/img_Gemalto_Prox_DU_mit_ausweis.png deleted file mode 100644 index d05a9fd..0000000 Binary files a/resources/images/reader/img_Gemalto_Prox_DU_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Gemalto_Prox_SU.png b/resources/images/reader/img_Gemalto_Prox_SU.png deleted file mode 100644 index b804164..0000000 Binary files a/resources/images/reader/img_Gemalto_Prox_SU.png and /dev/null differ diff --git a/resources/images/reader/img_Gemalto_Prox_SU_mit_ausweis.png b/resources/images/reader/img_Gemalto_Prox_SU_mit_ausweis.png deleted file mode 100644 index d3ce6e9..0000000 Binary files a/resources/images/reader/img_Gemalto_Prox_SU_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Identive_SCL011.png b/resources/images/reader/img_Identive_SCL011.png deleted file mode 100644 index 9cbabe8..0000000 Binary files a/resources/images/reader/img_Identive_SCL011.png and /dev/null differ diff --git a/resources/images/reader/img_Identive_SCL011_mit_ausweis.png b/resources/images/reader/img_Identive_SCL011_mit_ausweis.png deleted file mode 100644 index e199a69..0000000 Binary files a/resources/images/reader/img_Identive_SCL011_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Identive_SDI011.png b/resources/images/reader/img_Identive_SDI011.png deleted file mode 100644 index 1544f9b..0000000 Binary files a/resources/images/reader/img_Identive_SDI011.png and /dev/null differ diff --git a/resources/images/reader/img_Identive_SDI011_mit_ausweis.png b/resources/images/reader/img_Identive_SDI011_mit_ausweis.png deleted file mode 100644 index d556527..0000000 Binary files a/resources/images/reader/img_Identive_SDI011_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_KOBIL_ID_Token.png b/resources/images/reader/img_KOBIL_ID_Token.png deleted file mode 100644 index 6e89541..0000000 Binary files a/resources/images/reader/img_KOBIL_ID_Token.png and /dev/null differ diff --git a/resources/images/reader/img_KOBIL_ID_Token_mit_ausweis.png b/resources/images/reader/img_KOBIL_ID_Token_mit_ausweis.png deleted file mode 100644 index be3c4cb..0000000 Binary files a/resources/images/reader/img_KOBIL_ID_Token_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis.png deleted file mode 100644 index d694fd8..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png deleted file mode 100644 index 8e266f7..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png deleted file mode 100644 index 7381bee..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png deleted file mode 100644 index 2aa1d41..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard.png deleted file mode 100644 index 1ce9d27..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard.png and /dev/null differ diff --git a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png b/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png deleted file mode 100644 index 871d39d..0000000 Binary files a/resources/images/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/img_cyberjack_wave.png b/resources/images/reader/img_cyberjack_wave.png deleted file mode 100644 index 5a82a0b..0000000 Binary files a/resources/images/reader/img_cyberjack_wave.png and /dev/null differ diff --git a/resources/images/reader/img_cyberjack_wave_mit_ausweis.png b/resources/images/reader/img_cyberjack_wave_mit_ausweis.png deleted file mode 100644 index 6f35152..0000000 Binary files a/resources/images/reader/img_cyberjack_wave_mit_ausweis.png and /dev/null differ diff --git a/resources/images/reader/src/img_DefaultReader_mit_ausweis.svg b/resources/images/reader/src/img_DefaultReader_mit_ausweis.svg new file mode 100644 index 0000000..0c64be9 --- /dev/null +++ b/resources/images/reader/src/img_DefaultReader_mit_ausweis.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/reader/src/img_Personalausweis.png b/resources/images/reader/src/img_Personalausweis.png new file mode 100644 index 0000000..a80502e Binary files /dev/null and b/resources/images/reader/src/img_Personalausweis.png differ diff --git a/resources/images/reader/src/img_RemoteReader.svg b/resources/images/reader/src/img_RemoteReader.svg new file mode 100644 index 0000000..a2eb55e --- /dev/null +++ b/resources/images/reader/src/img_RemoteReader.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/reader/src/img_RemoteReader_mit_ausweis.svg b/resources/images/reader/src/img_RemoteReader_mit_ausweis.svg new file mode 100644 index 0000000..6a5fda0 --- /dev/null +++ b/resources/images/reader/src/img_RemoteReader_mit_ausweis.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/reader/src/img_Remote_Display.png b/resources/images/reader/src/img_Remote_Display.png new file mode 100755 index 0000000..b919fac Binary files /dev/null and b/resources/images/reader/src/img_Remote_Display.png differ diff --git a/resources/images/rotes_X.svg b/resources/images/rotes_X.svg index dfea783..65c75c9 100644 --- a/resources/images/rotes_X.svg +++ b/resources/images/rotes_X.svg @@ -2,6 +2,6 @@ - - + + diff --git a/resources/images/trash_icon.svg b/resources/images/trash_icon.svg new file mode 100644 index 0000000..4ed5556 --- /dev/null +++ b/resources/images/trash_icon.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/resources/jenkins/docker/README.rst b/resources/jenkins/docker/README.rst new file mode 100644 index 0000000..849a6b4 --- /dev/null +++ b/resources/jenkins/docker/README.rst @@ -0,0 +1,24 @@ +Jenkins Swarm +============= + +Diese Dockerfiles werden zum Generieren von Jenkins Agents +verwendet. Das Shellskript "generate.sh" erstellt alle +Docker Images anhand der Dockerfiles neu. + +Alle Basis-Images werden "FROM scratch" erzeugt. Dafür +ist es notwendig das "rootfs" manuell in die folgenden +Ordner zu kopieren. + +Alpine +------ + - https://alpinelinux.org/downloads/ + - alpine-minirootfs-*-x86_64.tar.gz + +Arch +---- + - https://mirrors.kernel.org/archlinux/iso/latest/ + - archlinux-bootstrap-*-x86_64.tar.gz + + - https://busybox.net/downloads/binaries/ + - busybox-x86_64 + diff --git a/resources/jenkins/docker/alpine/Dockerfile b/resources/jenkins/docker/alpine/Dockerfile new file mode 100644 index 0000000..75acf6c --- /dev/null +++ b/resources/jenkins/docker/alpine/Dockerfile @@ -0,0 +1,8 @@ +FROM scratch +MAINTAINER Governikus KG + +ARG version="3.6.2" +ARG arch="x86_64" +ADD alpine-minirootfs-$version-$arch.tar.gz / + +RUN apk --no-cache upgrade diff --git a/resources/jenkins/docker/android/Dockerfile b/resources/jenkins/docker/android/Dockerfile new file mode 100644 index 0000000..1d06872 --- /dev/null +++ b/resources/jenkins/docker/android/Dockerfile @@ -0,0 +1,32 @@ +FROM arch:latest +MAINTAINER Governikus KG + +ENV NAME=Android LABELS=Android + +RUN echo "[multilib]" >> /etc/pacman.conf && echo 'Include = /etc/pacman.d/mirrorlist' >> /etc/pacman.conf + +RUN chown -R governikus: /var/cache/pacman/pkg/ + +ARG JENKINS_SWARM_VERSION=3.6 +ARG TINI_VERSION=0.16.1 +RUN curl -L -o /sbin/tini https://github.com/krallin/tini/releases/download/v$TINI_VERSION/tini-static-muslc-amd64 && chmod 755 /sbin/tini && \ + curl -L -o /swarm-client.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/$JENKINS_SWARM_VERSION/swarm-client-$JENKINS_SWARM_VERSION.jar +ADD ../swarm/swarm.sh / + +USER governikus +RUN mkdir -p /home/governikus/.ccache && mkdir -p /home/governikus/workspace && mkdir -p /home/governikus/packages +VOLUME /home/governikus/.ccache + +# key for ncurses sources +RUN gpg --receive-keys 702353E0F7E48EDB + +RUN pacaur -Sy --noconfirm cmake ccache python2-hglib apache-ant jdk8-openjdk jre8-openjdk-headless mercurial python2-hglib \ + android-ndk-10e android-sdk-25.2.5 android-sdk-build-tools android-sdk-platform-tools \ + android-platform-18 android-platform-21 android-platform-25 \ + && rm -rf /var/cache/pacman/pkg/* && rm -rf /home/governikus/.cache/pacaur + +RUN pacman -Qi android-sdk-build-tools | grep Version | sed -E 's|.*r([0-9]+\.[0-9]\.[0-9]).*|export ANDROID_BUILD_TOOLS_REVISION=\1|' > /home/governikus/build_tools.sh +RUN echo '. /etc/profile ; . /home/governikus/build_tools.sh ;' >> /home/governikus/.profile + +ENTRYPOINT ["/sbin/tini", "--"] +CMD sh -l -c /swarm.sh diff --git a/resources/jenkins/docker/arch/Dockerfile b/resources/jenkins/docker/arch/Dockerfile new file mode 100644 index 0000000..6f4f61a --- /dev/null +++ b/resources/jenkins/docker/arch/Dockerfile @@ -0,0 +1,54 @@ +FROM scratch +MAINTAINER Governikus KG + +ARG box="busybox-x86_64" +ARG version="2017.10.01" + +ADD $box /tmp/busybox +ADD archlinux-bootstrap-$version-x86_64.tar.gz / + +# Clean up rootfs +RUN ["/tmp/busybox", "rm", "-rf", \ + "/root.x86_64/etc/hosts", \ + "/root.x86_64/etc/hostname", \ + "/root.x86_64/etc/mtab", \ + "/root.x86_64/etc/resolv.conf", \ + "/root.x86_64/dev", \ + "/root.x86_64/proc", \ + "/root.x86_64/sys" \ + ] + +RUN ["/tmp/busybox", "sh", "-c", "/tmp/busybox cp -af /root.x86_64/* /"] + +RUN rm -rf /tmp/busybox /root.x86_64 + +# Init Arch +RUN pacman-key --init && pacman-key --populate archlinux + +RUN echo 'Server = http://mirrors.kernel.org/archlinux/$repo/os/$arch' > /etc/pacman.d/mirrorlist &&\ + echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen &&\ + echo 'LANG="en_US.UTF-8"' > /etc/locale.conf + +RUN pacman -Syu --noconfirm base-devel lzop +RUN locale-gen; + +RUN sed -i "s|PKGEXT='.pkg.tar.xz'|PKGEXT='.pkg.tar.lzo'|" /etc/makepkg.conf + +RUN useradd governikus -m -s /usr/bin/bash -G wheel +RUN echo '%wheel ALL=(ALL) NOPASSWD: /usr/bin/pacman' > /etc/sudoers.d/pacman + +# Helper for AUR +RUN mkdir /tmp/p &&\ + curl -L -o /tmp/p/cower.tar.gz https://aur.archlinux.org/cgit/aur.git/snapshot/cower.tar.gz &&\ + curl -L -o /tmp/p/pacaur.tar.gz https://aur.archlinux.org/cgit/aur.git/snapshot/pacaur.tar.gz + +RUN cd /tmp/p && tar xf cower.tar.gz && tar xf pacaur.tar.gz &&\ + chown -R governikus /tmp/p &&\ + su - governikus -c "source /etc/profile.d/perlbin.sh && cd /tmp/p/cower && makepkg -si --noconfirm --skippgpcheck" &&\ + su - governikus -c "source /etc/profile.d/perlbin.sh && cd /tmp/p/pacaur && makepkg -si --noconfirm --skippgpcheck" + +# pacaur requires VISUAL, EDITOR or vi +RUN pacman -S --noconfirm vi + + +RUN rm -rf /tmp/p && rm -rf /var/cache/pacman/pkg/* && rm -rf /home/governikus/.cache/pacaur diff --git a/resources/jenkins/docker/common/Dockerfile b/resources/jenkins/docker/common/Dockerfile new file mode 100644 index 0000000..874fc27 --- /dev/null +++ b/resources/jenkins/docker/common/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:swarm +MAINTAINER Governikus KG + +ENV NAME=Common LABELS=Common + +RUN apk --no-cache add cmake make uncrustify py2-pip && pip install python-hglib && apk del py2-pip + +USER governikus + +ENTRYPOINT ["/sbin/tini", "--"] +CMD /swarm.sh diff --git a/resources/jenkins/docker/docs/Dockerfile b/resources/jenkins/docker/docs/Dockerfile new file mode 100644 index 0000000..6690752 --- /dev/null +++ b/resources/jenkins/docker/docs/Dockerfile @@ -0,0 +1,21 @@ +FROM alpine:swarm +MAINTAINER Governikus KG + +ENV NAME=Docs LABELS=Docs + +# Clean up if texlive package is fixed in Alpine +RUN sed -i -e 's/v3.6/edge/' /etc/apk/repositories && \ + echo '@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories && \ + apk --no-cache add cmake make py2-sphinx py2-setuptools py2-pip py2-hglib icu-libs poppler zziplib texlive-full@testing && \ + wget http://ftp.math.utah.edu/pub/tex/historic/systems/texlive/2016/texlive-20160523b-texmf.tar.xz && \ + cmake -E tar xf texlive-20160523b-texmf.tar.xz && \ + cp -r /texlive-20160523-texmf/texmf-dist /usr/share && \ + rm -rf texlive* && \ + apk --no-cache fix texlive && \ + ln -s /usr/bin/mktexlsr /usr/bin/mktexlsr.pl && \ + pip install doc8 cloud_sptheme + +USER governikus + +ENTRYPOINT ["/sbin/tini", "--"] +CMD sh -l -c /swarm.sh diff --git a/resources/jenkins/docker/generate.sh b/resources/jenkins/docker/generate.sh new file mode 100755 index 0000000..83472cd --- /dev/null +++ b/resources/jenkins/docker/generate.sh @@ -0,0 +1,36 @@ +#!/bin/sh +set -e + +################### Alpine +cd alpine +ls alpine-minirootfs-*.tar.gz >/dev/null + +echo "Building base Alpine ..." +docker build -t alpine:latest . + +images=(swarm trigger common docs linux) +for i in "${images[@]}" +do + echo "Building $i ..." + cd ../$i + docker build -t alpine:$i . +done + + + +################### Arch +cd ../arch +ls archlinux-bootstrap-*.tar.gz >/dev/null +ls busybox* >/dev/null + +echo "Building base Arch ..." +docker build -t arch:latest . + +images=(android) +for i in "${images[@]}" +do + echo "Building $i ..." + cd ../$i + docker build -t arch:$i . +done + diff --git a/resources/jenkins/docker/linux/Dockerfile b/resources/jenkins/docker/linux/Dockerfile new file mode 100644 index 0000000..12b9650 --- /dev/null +++ b/resources/jenkins/docker/linux/Dockerfile @@ -0,0 +1,17 @@ +FROM alpine:swarm +MAINTAINER Governikus KG + +ENV NAME=Linux LABELS="Linux g++ clang++" + +RUN apk --no-cache add cmake make g++ clang clang-analyzer mercurial ccache gcovr cloc cppcheck pkgconf ninja pcsc-lite-dev binutils-gold \ + mesa-dev libx11-dev libxkbcommon-dev xcb-util-wm-dev xcb-util-image-dev xcb-util-keysyms-dev \ + py2-pip && \ + ln -s /usr/libexec/c++-analyzer /usr/local/bin && ln -s /usr/libexec/ccc-analyzer /usr/local/bin && \ + pip install python-hglib && apk del py2-pip + +USER governikus +RUN mkdir -p /home/governikus/.ccache && mkdir -p /home/governikus/workspace && mkdir -p /home/governikus/packages +VOLUME /home/governikus/.ccache + +ENTRYPOINT ["/sbin/tini", "--"] +CMD /swarm.sh diff --git a/resources/jenkins/docker/swarm/Dockerfile b/resources/jenkins/docker/swarm/Dockerfile new file mode 100644 index 0000000..2e3e994 --- /dev/null +++ b/resources/jenkins/docker/swarm/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:latest +MAINTAINER Governikus KG + +ARG JENKINS_SWARM_VERSION=3.6 +ENV EXECUTOR=3 LABELS= NAME= PASSWORD= + +RUN adduser governikus -s /bin/sh -D +RUN apk --no-cache add openjdk8-jre tini mercurial wget +RUN wget -O /swarm-client.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/$JENKINS_SWARM_VERSION/swarm-client-$JENKINS_SWARM_VERSION.jar + +ADD swarm.sh / diff --git a/resources/jenkins/docker/swarm/swarm.sh b/resources/jenkins/docker/swarm/swarm.sh new file mode 100755 index 0000000..ba44c1a --- /dev/null +++ b/resources/jenkins/docker/swarm/swarm.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +dest=${DESTINATION:-/home/governikus} +name=${NAME:-undefined} +executor=${EXECUTOR:-1} +labels=${LABELS:-undefined} +mode=${MODE:-exclusive} +master=${MASTER:-https://vtf-aajenkins.tf.bos-test.de/} +user=${USER:-aajenkins} +fingerprints=${FINGERPRINTS:-68:21:59:5C:C0:B0:1F:78:FF:23:DE:D4:D8:05:0F:74:38:B2:A5:A4:F2:1B:5B:A7:AA:81:2A:A1:46:A8:EB:3A} + +/usr/bin/java \ + -jar /swarm-client.jar \ + -name $name \ + -mode $mode \ + -executors $executor \ + -labels "$labels" \ + -master $master \ + -username $user \ + -passwordEnvVariable PASSWORD \ + -sslFingerprints $fingerprints \ + -fsroot $dest + diff --git a/resources/jenkins/docker/trigger/Dockerfile b/resources/jenkins/docker/trigger/Dockerfile new file mode 100644 index 0000000..ae76b8e --- /dev/null +++ b/resources/jenkins/docker/trigger/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:swarm +MAINTAINER Governikus KG + +ENV NAME=Trigger LABELS="Trigger Seeder" + +USER governikus + +ENTRYPOINT ["/sbin/tini", "--"] +CMD /swarm.sh diff --git a/resources/jenkins/dsl/Builds/Build_Analyze.groovy b/resources/jenkins/dsl/Builds/Build_Analyze.groovy index c1f4cd9..3528c0f 100644 --- a/resources/jenkins/dsl/Builds/Build_Analyze.groovy +++ b/resources/jenkins/dsl/Builds/Build_Analyze.groovy @@ -37,7 +37,7 @@ j.with publishers { - tasks('source/**/*.cpp,source/**/*.h,source/**/*.m,source/**/*.mm,source/**/*.cmake,source/**/CMakeLists.txt', '', 'FIXME', 'TODO', 'FINDME', true) + tasks('source/**/*.cpp,source/**/*.h,source/**/*.m,source/**/*.mm,source/**/*.qml,source/**/*.js,source/**/*.cmake,source/**/CMakeLists.txt', '', 'FIXME', 'TODO', 'FINDME', true) { defaultEncoding('UTF-8') } diff --git a/resources/jenkins/dsl/Builds/Build_MacOS.groovy b/resources/jenkins/dsl/Builds/Build_MacOS.groovy index f7ed02b..ecd9e67 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS.groovy @@ -14,14 +14,15 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip('''\ cd build; cmake ../source -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - -DBUILD_SHARED_LIBS=true + -DBUILD_SHARED_LIBS=on + -DSANITIZER=on ''')) shell('''\ diff --git a/resources/jenkins/dsl/Builds/Build_MacOS_DMG.groovy b/resources/jenkins/dsl/Builds/Build_MacOS_DMG.groovy index 2d5b8d7..42643b3 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS_DMG.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS_DMG.groovy @@ -14,7 +14,7 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip("""\ cd build; diff --git a/resources/jenkins/dsl/Builds/Build_Translation.groovy b/resources/jenkins/dsl/Builds/Build_Translation.groovy new file mode 100644 index 0000000..fc35211 --- /dev/null +++ b/resources/jenkins/dsl/Builds/Build_Translation.groovy @@ -0,0 +1,27 @@ +import common.Build +import static common.Constants.strip + +def j = new Build + ( + name: 'Translation', + libraries: 'Linux', + label: 'Linux', + artifacts: 'source/resources/translations/*.ts' + ).generate(this) + + +j.with +{ + steps + { + shell(strip('''\ + cd build; + cmake ../source + -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist + -DUPDATE_TRANSLATIONS=ON + -DUPDATE_TRANSLATIONS_NO_OBSOLETE=ON + ''')) + + shell('cd build; make update.translations') + } +} diff --git a/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy b/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy index 90d1603..718cc55 100644 --- a/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win32_GNU.groovy @@ -25,6 +25,7 @@ j.with batchFile('''\ set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% + set PATH=%WORKSPACE%/build/src;%WORKSPACE%/build/test/helper;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% diff --git a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy index fc94f73..904a0cc 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy @@ -14,7 +14,7 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip('''\ cd build; @@ -25,7 +25,7 @@ j.with -GXcode ''')) - shell('cd build; CC=${CC_IOS} xcodebuild -target install -configuration Release PROVISIONING_PROFILE=${PROVISIONING_PROFILE_DEBUG}') + shell('cd build; xcodebuild -target install -configuration Release ARCHS=arm64') shell('cd build; xcodebuild -target ipa -configuration Release') } } diff --git a/resources/jenkins/dsl/Libraries/Libs_iOS.groovy b/resources/jenkins/dsl/Libraries/Libs_iOS.groovy index 9b8154d..c5c663f 100644 --- a/resources/jenkins/dsl/Libraries/Libs_iOS.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_iOS.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") diff --git a/resources/jenkins/dsl/Releases/Release_Android.groovy b/resources/jenkins/dsl/Releases/Release_Android.groovy index 5cc85b4..9d4db61 100644 --- a/resources/jenkins/dsl/Releases/Release_Android.groovy +++ b/resources/jenkins/dsl/Releases/Release_Android.groovy @@ -19,10 +19,13 @@ j.with parameters { stringParam("ANDROID_VERSION_CODE", "0", "See https://play.google.com/apps/publish/") + booleanParam("BUILD_PREVIEW", false, "Use com.governikus.ausweisapp2.dev as package name") } steps { + buildDescription('', 'ANDROID_VERSION_CODE: ${ANDROID_VERSION_CODE}
BUILD_PREVIEW: ${BUILD_PREVIEW}') + shell(strip("""\ cd build; cmake ../source -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist @@ -33,6 +36,7 @@ j.with -DAPK_SIGN_KEYSTORE_ALIAS=\${APK_SIGN_KEYSTORE_ALIAS} -DAPK_SIGN_KEYSTORE_PSW=\${APK_SIGN_KEYSTORE_PSW} -DANDROID_VERSION_CODE=\${ANDROID_VERSION_CODE} + -DBUILD_PREVIEW=\${BUILD_PREVIEW} """)) shell('cd build; make \${MAKE_FLAGS} install') diff --git a/resources/jenkins/dsl/Releases/Release_Appcast.groovy b/resources/jenkins/dsl/Releases/Release_Appcast.groovy index 3f86416..a68e750 100644 --- a/resources/jenkins/dsl/Releases/Release_Appcast.groovy +++ b/resources/jenkins/dsl/Releases/Release_Appcast.groovy @@ -3,5 +3,14 @@ import common.Appcast def j = new Appcast ( namePrefix: 'Release_', - tagName: 'release' + releaseJob: true ).generate(this) + + +j.with +{ + parameters + { + stringParam('changeset', 'release', 'Build given changeset (tag) as release') + } +} diff --git a/resources/jenkins/dsl/Releases/Release_MacOS.groovy b/resources/jenkins/dsl/Releases/Release_MacOS.groovy index 87d060b..df8cb0d 100644 --- a/resources/jenkins/dsl/Releases/Release_MacOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_MacOS.groovy @@ -14,7 +14,7 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip("""\ cd build; diff --git a/resources/jenkins/dsl/Releases/Release_iOS.groovy b/resources/jenkins/dsl/Releases/Release_iOS.groovy index 9f8b4fb..3c62fa8 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS.groovy @@ -12,9 +12,16 @@ def j = new Release j.with { + parameters + { + booleanParam("USE_DISTRIBUTION_PROFILE", true, "Use the provisioning profile necessary to upload AusweisApp2 to the AppStore") + } + steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + buildDescription('', 'USE_DISTRIBUTION_PROFILE: ${USE_DISTRIBUTION_PROFILE}') + + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip('''\ cd build; @@ -22,10 +29,11 @@ j.with -DCMAKE_BUILD_TYPE=release -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake + -DUSE_DISTRIBUTION_PROFILE=\${USE_DISTRIBUTION_PROFILE} -GXcode ''')) - shell('cd build; xcodebuild -target install -configuration Release PROVISIONING_PROFILE=${PROVISIONING_PROFILE_RELEASE}') + shell('cd build; xcodebuild -target install -configuration Release ARCHS=arm64') shell('cd build; xcodebuild -target ipa -configuration Release') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Android.groovy index 67cecd4..a0cb896 100644 --- a/resources/jenkins/dsl/Reviews/Review_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Android.groovy @@ -22,7 +22,7 @@ j.with shell(strip("""\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_BUILD_TYPE=debug -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/android.toolchain.cmake diff --git a/resources/jenkins/dsl/Reviews/Review_Docs.groovy b/resources/jenkins/dsl/Reviews/Review_Docs.groovy index 1b1d96f..10ba186 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docs.groovy @@ -10,11 +10,13 @@ def j = new Review j.with { + concurrentBuild() + steps { shell('cd source; python resources/jenkins/import.py') - shell('cd build; cmake ../source -DCMAKE_BUILD_TYPE=release -Dtools.only=true') + shell('cd build; cmake -Werror=dev ../source -DCMAKE_BUILD_TYPE=release -Dtools.only=true') shell('cd build; make notes') shell('cd build; make notes.latex.pdf') diff --git a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy index 9963f1a..f336b99 100644 --- a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy @@ -10,16 +10,18 @@ def j = new Review j.with { + concurrentBuild() + steps { shell('''\ cd source - hg revert --all + hg revert -a -C hg --config extensions.hgext.purge= purge --all hg --config extensions.hgext.strip= strip -r 'secret() or draft()' --no-backup --force 2>/dev/null || echo "No changeset stripped" '''.stripIndent().trim()) - shell('cd build; cmake ../source -Dtools.only=true') + shell('cd build; cmake -Werror=dev ../source -Dtools.only=true') shell('''\ cd build @@ -28,7 +30,9 @@ j.with STATUS=$(hg status | wc -c) if [ "$STATUS" != "0" ]; then + echo 'Current repository state is not formatted!' hg addremove + hg diff hg commit -m "fix formatting" -s fi @@ -46,6 +50,8 @@ j.with STATUS=$(hg status | wc -c) if [ "$STATUS" != "0" ]; then echo 'FORMATTING FAILED: Patch is not formatted' + hg diff + hg revert -a -C exit 0 fi '''.stripIndent().trim()) diff --git a/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy index 9fd6e51..bc61b77 100644 --- a/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy +++ b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy @@ -28,7 +28,7 @@ j.with shell(strip('''\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DBUILD_SHARED_LIBS=on diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy index c98806b..5976b18 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy @@ -13,7 +13,7 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') shell("cd build; cmake ../source/libs -DCMAKE_BUILD_TYPE=release -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -DPACKAGES_DIR=\${PACKAGES_DIR}") diff --git a/resources/jenkins/dsl/Reviews/Review_Linux.groovy b/resources/jenkins/dsl/Reviews/Review_Linux.groovy index fc00440..d300569 100644 --- a/resources/jenkins/dsl/Reviews/Review_Linux.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Linux.groovy @@ -35,7 +35,7 @@ j.with shell(strip('''\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=${Compiler} diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy index 9173037..1ad32f7 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy @@ -18,14 +18,15 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip('''\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_PREFIX_PATH=${WORKSPACE}/libs/build/dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - -DBUILD_SHARED_LIBS=true + -DBUILD_SHARED_LIBS=on + -DSANITIZER=on ''')) shell('''\ diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS_DMG.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS_DMG.groovy index e77b4e7..dab4e21 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS_DMG.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS_DMG.groovy @@ -16,11 +16,11 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') shell(strip("""\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=release diff --git a/resources/jenkins/dsl/Reviews/Review_Source.groovy b/resources/jenkins/dsl/Reviews/Review_Source.groovy index f9a486d..042b387 100644 --- a/resources/jenkins/dsl/Reviews/Review_Source.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Source.groovy @@ -10,11 +10,13 @@ def j = new Review j.with { + concurrentBuild() + steps { shell('cd source; python resources/jenkins/import.py') - shell('cd build; cmake ../source -DCMAKE_BUILD_TYPE=release -Dtools.only=true') + shell('cd build; cmake -Werror=dev ../source -DCMAKE_BUILD_TYPE=release -Dtools.only=true') shell('cd build; make package_source') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy index 6a97976..a37c515 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_GNU.groovy @@ -20,7 +20,7 @@ j.with batchFile(strip("""\ cd build & - cmake ../source -G\"MinGW Makefiles\" + cmake -Werror=dev ../source -G\"MinGW Makefiles\" -DCMAKE_PREFIX_PATH=%WORKSPACE%\\libs\\build\\dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache """)) @@ -29,7 +29,7 @@ j.with batchFile('''\ set PATH=%WORKSPACE%/libs/build/dist/bin;%PATH% - set PATH=%WORKSPACE%/install;%PATH% + set PATH=%WORKSPACE%/build/src;%WORKSPACE%/build/test/helper;%PATH% set QT_PLUGIN_PATH=%WORKSPACE%/libs/build/dist/plugins set QML2_IMPORT_PATH=%WORKSPACE%/libs/build/dist/qml cd build & ctest %MAKE_FLAGS% diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_GNU_MSI.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_GNU_MSI.groovy index ed135eb..ca4557e 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_GNU_MSI.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_GNU_MSI.groovy @@ -18,7 +18,7 @@ j.with batchFile(strip("""\ cd build & - cmake ../source -G\"MinGW Makefiles\" + cmake -Werror=dev ../source -G\"MinGW Makefiles\" -DCMAKE_PREFIX_PATH=%WORKSPACE%\\libs\\build\\dist -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=release diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy index 4b89d96..7346423 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC.groovy @@ -20,7 +20,7 @@ j.with batchFile('''\ cd build call vcvarsall.bat - cmake ../source -DCMAKE_CXX_COMPILER=clcache -DCMAKE_PREFIX_PATH=%WORKSPACE%/libs/build/dist -GNinja + cmake -Werror=dev ../source -DCMAKE_CXX_COMPILER=clcache -DCMAKE_PREFIX_PATH=%WORKSPACE%/libs/build/dist -GNinja '''.stripIndent().trim()) batchFile('''\ diff --git a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC_MSI.groovy b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC_MSI.groovy index feed3c2..6185f5a 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win32_MSVC_MSI.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win32_MSVC_MSI.groovy @@ -18,7 +18,7 @@ j.with batchFile('''\ cd build call vcvarsall.bat - cmake ../source -DCMAKE_BUILD_TYPE=release -DCMAKE_CXX_COMPILER=clcache -DCMAKE_PREFIX_PATH=%WORKSPACE%/libs/build/dist -GNinja -DWIN_SIGN_KEYSTORE=%WIN_SIGN_KEYSTORE% -DWIN_SIGN_KEYSTORE_PSW=%WIN_SIGN_KEYSTORE_PSW% -DWIN_SIGN_SUBJECT_NAME=%WIN_SIGN_SUBJECT_NAME% + cmake -Werror=dev ../source -DCMAKE_BUILD_TYPE=release -DCMAKE_CXX_COMPILER=clcache -DCMAKE_PREFIX_PATH=%WORKSPACE%/libs/build/dist -GNinja -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/Reviews/Review_iOS_IPA.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy index 1b96331..dd03563 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy @@ -16,18 +16,18 @@ j.with { shell('cd source; python resources/jenkins/import.py') - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain') + shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') shell(strip('''\ cd build; - cmake ../source + cmake -Werror=dev ../source -DCMAKE_BUILD_TYPE=release -DCMAKE_PREFIX_PATH=\${WORKSPACE}/libs/build/dist -DCMAKE_TOOLCHAIN_FILE=../source/cmake/iOS.toolchain.cmake -GXcode ''')) - shell('cd build; CC=${CC_IOS} xcodebuild -target install -configuration Release PROVISIONING_PROFILE=${PROVISIONING_PROFILE_DEBUG}') + shell('cd build; xcodebuild -target install -configuration Release ARCHS=arm64') shell('cd build; xcodebuild -target ipa -configuration Release') } } diff --git a/resources/jenkins/dsl/View_Review.groovy b/resources/jenkins/dsl/View_Review.groovy index 5e1bf40..dc51b92 100644 --- a/resources/jenkins/dsl/View_Review.groovy +++ b/resources/jenkins/dsl/View_Review.groovy @@ -7,7 +7,7 @@ categorizedJobsView('Review') categorizationCriteria { - regexGroupingRule('([a-z])+_Review_(.)*', 'Branches') + regexGroupingRule('([a-z|0-9|.])+_Review_(.)*', 'Branches') } categorizationCriteria diff --git a/resources/jenkins/dsl/Views/View_Branch.groovy b/resources/jenkins/dsl/Views/View_Branch.groovy index c04ab7e..3e971d0 100644 --- a/resources/jenkins/dsl/Views/View_Branch.groovy +++ b/resources/jenkins/dsl/Views/View_Branch.groovy @@ -7,7 +7,7 @@ categorizedJobsView("${MERCURIAL_REVISION_BRANCH}") categorizationCriteria { - regexGroupingRule('^[a-z]*_Libs_', '_Libraries_') + regexGroupingRule('^[a-z|0-9|.]*_Libs_', '_Libraries_') regexGroupingRule('_Review_', '_Reviews_') } diff --git a/resources/jenkins/dsl/common/Appcast.groovy b/resources/jenkins/dsl/common/Appcast.groovy index 909c42d..31175a8 100644 --- a/resources/jenkins/dsl/common/Appcast.groovy +++ b/resources/jenkins/dsl/common/Appcast.groovy @@ -18,7 +18,7 @@ class Appcast extends Build { def prefixSource = '' - if(getTagName()) + if(getReleaseJob()) prefixSource = 'Release_' return buildName(prefixSource, artifactJob) @@ -30,7 +30,7 @@ class Appcast extends Build j.with { - if(!getTagName()) + if(!getReleaseJob()) { triggers { @@ -73,7 +73,7 @@ class Appcast extends Build } } - def appCastJob = getTagName() ? '' : '-DJENKINS_APPCAST=\${JOB_NAME}' + def appCastJob = getReleaseJob() ? '' : '-DJENKINS_APPCAST=\${JOB_NAME}' shell("cd build; cmake ../source -DCMAKE_BUILD_TYPE=release -Dtools.only=true ${appCastJob}") shell('cd build; cmake -E copy docs/notes/singlehtml/de/appcast.html ReleaseNotes.html') } diff --git a/resources/jenkins/dsl/common/Build.groovy b/resources/jenkins/dsl/common/Build.groovy index 16eb420..3400061 100644 --- a/resources/jenkins/dsl/common/Build.groovy +++ b/resources/jenkins/dsl/common/Build.groovy @@ -16,10 +16,10 @@ class Build String libraries String artifacts String label - String tagName String trigger = '@daily' String excludePattern = 'source/**' List oldBuilds = [7, 15] + boolean releaseJob = false boolean xunit = false boolean cleanup = false boolean sendMail = true @@ -36,7 +36,7 @@ class Build { def branchPrefix = '' - if(!getTagName()) + if(!getReleaseJob()) { if(libs && getReview()) branchPrefix = '${Libraries}_' @@ -56,7 +56,7 @@ class Build { def prefix = 'Libs_' - if(getTagName()) + if(getReleaseJob()) { prefix = '${MERCURIAL_REVISION_BRANCH}_' + prefix } @@ -104,7 +104,7 @@ class Build { preBuildCleanup() { - if(!getTagName() && getExcludePattern()) + if(!getReleaseJob() && getExcludePattern()) excludePattern(getExcludePattern()) deleteDirectories(true) @@ -125,8 +125,8 @@ class Build { hg(dslFactory.MERCURIAL_REPOSITORY_URL) { - if(getTagName()) - tag(getTagName()) + if(getReleaseJob()) + tag('${changeset}') else branch(dslFactory.MERCURIAL_REVISION_BRANCH) diff --git a/resources/jenkins/dsl/common/Constants.groovy b/resources/jenkins/dsl/common/Constants.groovy index 5cf8a1b..1ab601d 100644 --- a/resources/jenkins/dsl/common/Constants.groovy +++ b/resources/jenkins/dsl/common/Constants.groovy @@ -33,7 +33,7 @@ class Constants static String genMsgName(String name, nameGenerator) { def jobName = nameGenerator(name) - def envJobName = jobName.replaceAll('-', '_').toUpperCase() + def envJobName = jobName.replaceAll('-', '_').replaceAll('\\.', '_').toUpperCase() return name + ': [' + getEnvResult(envJobName) + '](${JENKINS_URL}job/' + jobName + '/' + getEnvNumber(envJobName) + '/)' } @@ -45,7 +45,7 @@ class Constants jobs.each { String name = nameGenerator("${it}") - name = name.replaceAll('-', '_').toUpperCase() + name = name.replaceAll('-', '_').replaceAll('\\.', '_').toUpperCase() map << [(name + '_BUILD_RESULT'):''] map << [(name + '_BUILD_NUMBER'):''] } diff --git a/resources/jenkins/dsl/common/Release.groovy b/resources/jenkins/dsl/common/Release.groovy index a148824..127ee53 100644 --- a/resources/jenkins/dsl/common/Release.groovy +++ b/resources/jenkins/dsl/common/Release.groovy @@ -8,9 +8,9 @@ import common.Build class Release extends Build { String namePrefix = 'Release_' - String tagName = 'release' String trigger = null List oldBuilds = null + boolean releaseJob = true boolean cleanup = true boolean sendMail = false @@ -20,7 +20,10 @@ class Release extends Build j.with { - + parameters + { + stringParam('changeset', 'release', 'Build given changeset (tag) as release') + } } return j diff --git a/resources/jenkins/dsl/install.py b/resources/jenkins/dsl/install.py index 71b56cd..9905264 100755 --- a/resources/jenkins/dsl/install.py +++ b/resources/jenkins/dsl/install.py @@ -17,7 +17,7 @@ import time if len(sys.argv) is not 2: print('Please provide address of jenkins server') - print('Example: buildautentapp:8090') + print('Example: localhost:8090') sys.exit(1) if not shutil.which('java'): @@ -86,6 +86,7 @@ plugins.append('parameterized-trigger') plugins.append('show-build-parameters') plugins.append('sloccount') plugins.append('sidebar-link') +plugins.append('swarm') plugins.append('tasks') plugins.append('text-finder') plugins.append('timestamper') diff --git a/resources/packaging/android/AndroidManifest.xml.in b/resources/packaging/android/AndroidManifest.xml.in index eddf62e..f6ce899 100644 --- a/resources/packaging/android/AndroidManifest.xml.in +++ b/resources/packaging/android/AndroidManifest.xml.in @@ -1,11 +1,14 @@ + + + android:theme="@style/Theme.NoTitle" + android:resizeableActivity="false"> @@ -26,18 +29,14 @@ - + - + - - - - @@ -89,9 +88,9 @@ --> - + - + - - diff --git a/resources/packaging/android/nfc_tech_filter.xml b/resources/packaging/android/nfc_tech_filter.xml deleted file mode 100644 index 3dc985a..0000000 --- a/resources/packaging/android/nfc_tech_filter.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - android.nfc.tech.IsoDep - - diff --git a/resources/packaging/ios/MacOSXBundleInfo.plist.in b/resources/packaging/ios/MacOSXBundleInfo.plist.in index bb4b7dd..2073339 100644 --- a/resources/packaging/ios/MacOSXBundleInfo.plist.in +++ b/resources/packaging/ios/MacOSXBundleInfo.plist.in @@ -14,9 +14,9 @@ CFBundleIconFiles - icon29x29 - icon40x40 - icon60x60 + iconSmall + iconSmall40 + icon60 @@ -26,10 +26,11 @@ CFBundleIconFiles - icon29x29 - icon40x40 - icon60x60 - icon76x76 + iconSmall + iconSmall40 + icon60 + icon76 + icon83.5 @@ -60,6 +61,10 @@ CSResourcesFileMapped + LSApplicationQueriesSchemes + + https + LSRequiresCarbon UIRequiresFullScreen @@ -68,30 +73,87 @@ UILaunchImageMinimumOSVersion - 7.0 + 10.0 UILaunchImageName - launchIcon + launchImage568 + UILaunchImageOrientation + Portrait UILaunchImageSize {320, 568} UILaunchImageMinimumOSVersion - 7.0 + 10.0 UILaunchImageName - launchIcon6 + launchImage667 + UILaunchImageOrientation + Portrait UILaunchImageSize {375, 667} UILaunchImageMinimumOSVersion - 7.0 + 10.0 UILaunchImageName - launchIcon6p + launchImage736 + UILaunchImageOrientation + Portrait UILaunchImageSize {414, 736} + UILaunchImages~ipad + + + UILaunchImageMinimumOSVersion + 10.0 + UILaunchImageName + launchImage1024 + UILaunchImageOrientation + Landscape + UILaunchImageSize + {768, 1024} + + + UILaunchImageMinimumOSVersion + 10.0 + UILaunchImageName + launchImage1112 + UILaunchImageOrientation + Landscape + UILaunchImageSize + {834, 1112} + + + UILaunchImageMinimumOSVersion + 10.0 + UILaunchImageName + launchImage1366 + UILaunchImageOrientation + Landscape + UILaunchImageSize + {1024, 1366} + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} + UIBackgroundModes + + bluetooth-central + fetch + + NSBluetoothPeripheralUsageDescription + AusweisApp2 needs Bluetooth to enable the required card reader. + NFCReaderUsageDescription + AusweisApp2 needs NFC to access the ID card. diff --git a/resources/packaging/ios/de.lproj/InfoPlist.strings b/resources/packaging/ios/de.lproj/InfoPlist.strings new file mode 100644 index 0000000..e000b6b --- /dev/null +++ b/resources/packaging/ios/de.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +NSBluetoothPeripheralUsageDescription = "Die AusweisApp2 nutzt Bluetooth, um auf das benötigte Kartenlesegerät zuzugreifen."; +NFCReaderUsageDescription = "Die AusweisApp2 nutzt NFC, um auf den Personalausweis zuzugreifen."; diff --git a/resources/packaging/win/WIX.template.in b/resources/packaging/win/WIX.template.in index 67979c9..9e04ee5 100644 --- a/resources/packaging/win/WIX.template.in +++ b/resources/packaging/win/WIX.template.in @@ -46,25 +46,6 @@ - - - - - - - - - AUTOSTART - - - - - - - @@ -83,37 +64,13 @@ + - - - - - - - SYSTEMSETTINGS and NOT Installed - - - - - - - - - Installed and NOT REINSTALL - - - @@ -144,7 +101,6 @@ - diff --git a/resources/qml/+android/ContentArea.qml b/resources/qml/+android/ContentArea.qml index 7b369b5..f32096a 100644 --- a/resources/qml/+android/ContentArea.qml +++ b/resources/qml/+android/ContentArea.qml @@ -1,55 +1,75 @@ import QtQuick 2.5 -import "global" +import Governikus.Global 1.0 +import Governikus.PinView 1.0 +import Governikus.InformationView 1.0 +import Governikus.RemoteServiceView 1.0 +import Governikus.FeedbackView 1.0 +import Governikus.DeveloperView 1.0 +import Governikus.IdentifyView 1.0 +import Governikus.ProviderView 1.0 +import Governikus.HistoryView 1.0 Item { id: baseItem - - function getVisibleItem() { - return baseItem.visibleChildren[0] - } + property alias ready: identifyView.ready + readonly property var visibleItem: visibleChildren[0] + readonly property var currentSectionPage: if (visibleItem) visibleItem.currentSectionPage TabBarView { id: identifyView anchors.fill: parent visible: baseItem.state === "identify" - source: "identify/IdentifyView.qml" + sourceComponent: IdentifyView {} } TabBarView { anchors.fill: parent visible: baseItem.state === "provider" - source: "provider/ProviderView.qml" + prefetch: identifyView.ready + sourceComponent: ProviderView {} } TabBarView { anchors.fill: parent visible: baseItem.state === "history" - source: "history/HistoryView.qml" + prefetch: identifyView.ready + sourceComponent: HistoryView {} } TabBarView { id: pinView anchors.fill: parent visible: baseItem.state === "pin" - source: "pin/PinView.qml" + prefetch: identifyView.ready + sourceComponent: PinView {} + } + + TabBarView { + anchors.fill: parent + visible: baseItem.state === "remoteservice" + prefetch: identifyView.ready + sourceComponent: RemoteServiceView {} } TabBarView { anchors.fill: parent visible: baseItem.state === "feedback" - source: "more/Feedback.qml" + prefetch: identifyView.ready + sourceComponent: Feedback {} } TabBarView { anchors.fill: parent visible: baseItem.state === "information" - source: "more/Information.qml" + prefetch: identifyView.ready + sourceComponent: Information {} } TabBarView { anchors.fill: parent visible: baseItem.state === "developeroptions" - source: "more/DeveloperView.qml" + prefetch: identifyView.ready + sourceComponent: DeveloperView {} } } diff --git a/resources/qml/+android/Navigation.qml b/resources/qml/+android/Navigation.qml deleted file mode 100644 index bebb5e3..0000000 --- a/resources/qml/+android/Navigation.qml +++ /dev/null @@ -1,84 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.0 - -import "global" - -Item { - id: navigation - state: "identify" - width: !PlatformConstants.is_tablet || lockedAndHidden ? 0 : Constants.menubar_width - - property bool lockedAndHidden: true - property bool isOpen: drawer.position > 0 - property int currentIndex: 0 - - onLockedAndHiddenChanged: { - if (lockedAndHidden) { - drawer.close() - } - } - - function open() { - if (!lockedAndHidden) { - drawer.open() - } - } - - function close() { - drawer.close() - } - - Rectangle { - visible: PlatformConstants.is_tablet - anchors.top: parent.top - anchors.left: parent.left - anchors.bottom: parent.bottom - width: Math.max(parent.width, appWindow.leftOverlayMargin); - color: Constants.background_color - clip: true - - NavigationView { - navigationController: navigation - } - - Rectangle { - id: iconBarBorder - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - width: Utils.dp(2) - color: PlatformConstants.grey_border - } - } - - Drawer { - id: drawer - topPadding: Constants.titlebar_height - height: appWindow.height - width: Utils.dp(250) - opacity: PlatformConstants.is_tablet ? 0 : 1 - background: Item { - opacity: 0 - visible: !lockedAndHidden && drawer.position > 0 - - MouseArea { - anchors.fill: parent - onClicked: drawer.close() - } - } - - dragMargin: lockedAndHidden ? 0 : Utils.dp(Qt.styleHints.startDragDistance) - - onPositionChanged: { - if (PlatformConstants.is_tablet && position > 0) { - appWindow.leftOverlayMargin = Constants.menubar_width + (width - Constants.menubar_width) * position - } else { - appWindow.leftOverlayMargin = 0 - } - } - - contentItem: NavigationView { - navigationController: navigation - } - } -} diff --git a/resources/qml/+android/NavigationItem.qml b/resources/qml/+android/NavigationItem.qml deleted file mode 100644 index 7d7112a..0000000 --- a/resources/qml/+android/NavigationItem.qml +++ /dev/null @@ -1,40 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item { - property alias source: tabImage.source - property alias text: tabText.text - signal clicked - - Item { - id: tabImageItem - height: parent.height - width: Constants.menubar_width - anchors.left: parent.left - - Image { - id: tabImage - height: Utils.dp(35) - sourceSize.height: 96; - fillMode: Image.PreserveAspectFit - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - } - } - - Text { - id: tabText - anchors.left: tabImageItem.right - anchors.leftMargin: Utils.dp(10) - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Constants.small_font_size - renderType: Text.NativeRendering - color: "black" - } - - MouseArea { - anchors.fill: parent - onClicked: parent.clicked() - } -} diff --git a/resources/qml/+android/NavigationView.qml b/resources/qml/+android/NavigationView.qml deleted file mode 100644 index 4b31c67..0000000 --- a/resources/qml/+android/NavigationView.qml +++ /dev/null @@ -1,92 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.0 - -import "global" - - -Rectangle { - id: content - height: appWindow.height - Constants.titlebar_height - width: Utils.dp(250) - color: Constants.background_color - - property var navigationController: null - - ListModel { - id: navModel - - ListElement { - image: "qrc:///images/android/navigation/ausweisen.svg" - desc: qsTr("Identify") - condition: "identify" - } - - ListElement { - image: "qrc:///images/android/navigation/anbieter.svg" - desc: qsTr("Provider") - condition: "provider" - } - - ListElement { - image: "qrc:///images/android/navigation/verlauf.svg" - desc: qsTr("History") - condition: "history" - } - - ListElement { - image: "qrc:///images/android/navigation/pin.svg" - desc: qsTr("PIN Management") - condition: "pin" - } - - ListElement { - image: "qrc:///images/android/navigation/balloon.svg" - desc: qsTr("Dialog & Feedback") - condition: "feedback" - } - - ListElement { - image: "qrc:///images/android/navigation/faq.svg" - desc: qsTr("Info & Help") - condition: "information" - } - - ListElement { - image: "qrc:///images/zahnraeder.svg" - desc: qsTr("Developer options") - condition: "developeroptions" - } - } - - - ListView { - id: listView - anchors.fill: parent - boundsBehavior: Flickable.StopAtBounds - model: navModel - currentIndex: navigationController.currentIndex - - highlight: Rectangle { - color: "black" - opacity: 0.1 - height: Utils.dp(45) - width: content.width - y: listView.currentItem.y - } - highlightFollowsCurrentItem: false - - delegate: NavigationItem { - height: Utils.dp(45) - width: content.width - source: image - text: desc - onClicked: { - navigationController.currentIndex = index - navigationController.state = condition - navigationController.close() - } - // Hide developer options if we are not using developer build (debug build) - visible: condition !== "developeroptions" || plugin.developerBuild - } - } -} diff --git a/resources/qml/+android/ProviderContactTab.qml b/resources/qml/+android/ProviderContactTab.qml deleted file mode 100644 index 750c88f..0000000 --- a/resources/qml/+android/ProviderContactTab.qml +++ /dev/null @@ -1,63 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.2 - -import "../" -import "global" - -Item { - id: baseItem - property alias contactModel: infoList.model - readonly property int contentHeight: infoList.contentHeight - - - ListView { - id: infoList - anchors.fill: parent - interactive: false - - delegate: Item { - id: delegateItem - width: parent.width - height: Math.max(textItem.height, Utils.dp(50)) - - Image { - id: imageItem - fillMode: Image.PreserveAspectFit - height: Utils.dp(24) - width: Utils.dp(24) - anchors.left: parent.left - anchors.leftMargin: Utils.dp(15) - anchors.verticalCenter: parent.verticalCenter - source: Qt.resolvedUrl(model.iconSource) - } - - Text { - id: textItem - text: !!model.text ? model.text : qsTr("Unknown") - verticalAlignment: Text.AlignVCenter - anchors.left: imageItem.right - anchors.leftMargin: Utils.dp(20) - anchors.right: parent.right - anchors.rightMargin: Utils.dp(10) - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Utils.dp(16) - wrapMode: Text.WordWrap - textFormat: Text.RichText - } - - MouseArea { - anchors.fill: delegateItem - enabled: !!model.link - onClicked: Qt.openUrlExternally(model.link) - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: 1 - color: Constants.grey - } - } - } -} diff --git a/resources/qml/+android/ProviderHeader.qml b/resources/qml/+android/ProviderHeader.qml deleted file mode 100644 index 7bd67a9..0000000 --- a/resources/qml/+android/ProviderHeader.qml +++ /dev/null @@ -1,172 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Rectangle { - id: baseItem - - // Properties that are set by ProviderView or ProviderDetailView - property string selectedCategory: selectedProvider ? selectedProvider.category : "" - property var selectedProvider - - // This is interpreted by the SectionPage component - readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : (customProviderImage ? Math.max(0, 0.5 - shadow.opacity) : 0) - - // 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: backgroundImage - - source: baseItem.backgroundImage - height: width / 1.80 - width: parent.width - anchors.left: parent.left - anchors.top: parent.top - fillMode: Image.PreserveAspectCrop - - function transition() { - 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: 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 { - id: providerInfo - height: visible ? column.height + 2 * Constants.pane_padding : 0 - width: parent.width - anchors.left: parent.left - anchors.top: backgroundImage.bottom - - visible: !!selectedProvider - - 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 deleted file mode 100644 index d183ab1..0000000 --- a/resources/qml/+android/ProviderInfoSection.qml +++ /dev/null @@ -1,43 +0,0 @@ -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 deleted file mode 100644 index 4d64f01..0000000 --- a/resources/qml/+android/ResultView.qml +++ /dev/null @@ -1,71 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Window 2.2 - -import "global" - -SectionPage { - id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: baseItem.clicked() } - - property alias text: resultText.text - property bool isError: false - signal clicked - - Rectangle { - anchors.fill: parent - color: Constants.background_color - } - - // See: http://tagasks.com/in_qtqml_how_to_load_different_images_for_different_device_densities_android - property int ppi: Screen.pixelDensity * 25.4 - - readonly property string imageDir: { - if (ppi >= 360) - "xxxhdpi" - else if (ppi >= 270) - "xxhdpi" - else if (ppi >= 180) - "xhdpi" - else if (ppi >= 135) - "hdpi" - else - "mdpi" - } - - 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 - } - - Text { - id: resultText - 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 deleted file mode 100644 index 37db5e7..0000000 --- a/resources/qml/+android/TitleBar.qml +++ /dev/null @@ -1,145 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 1.4 - -import "global" - -Item -{ - property int duration: 300 - property alias titleBarOpacity: background.opacity - id: titleBar - height: Constants.titlebar_height - - 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() { - rightActionStack.clear() - - setColor(PlatformConstants.blue) - menuAction = standardMenuAction - titleItem = standardTitle - } - - function push(leftAction, headerAction, rightAction, color) { - // TODO Remove Stack because we no longer need it - rightActionStack.pop() - - setColor(color) - menuAction = leftAction - titleItem = headerAction - rightActionStack.push(rightAction) - } - - function setColor(color) { - background.color = color - } - - Rectangle { - id: background - color: PlatformConstants.blue - anchors.top: parent.top - anchors.left: PlatformConstants.is_tablet ? hamburgerFrame.right : parent.left - anchors.bottom: parent.bottom - anchors.right: parent.right - - onColorChanged: statusBarUtil.setStatusBarColor(String(color)) - Behavior on color { ColorAnimation { duration: titleBar.duration } } - } - - Rectangle { - id: hamburgerFrame - height: parent.height - width: Constants.menubar_width - anchors.left: parent.left - color: background.color - opacity: PlatformConstants.is_tablet ? 1 : 0 - } - - Hamburger { - id: burger - anchors.horizontalCenter: hamburgerFrame.horizontalCenter - height: parent.height - width: height - state: navBar.isOpen ? "back" : menuAction.state - - MouseArea { - anchors.fill: parent - onClicked: { - switch (burger.state) { - case "": - navBar.open() - break - case "back": - if (navBar.isOpen) { - navBar.close() - } else { - menuAction.clicked() - } - break - default: - menuAction.clicked() - } - } - } - } - - 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) - - anchors.centerIn: parent - height: parent.height - width: Math.max(_width, 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" } - } - } - } - - 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.bottom: parent.bottom - width: currentItem ? currentItem.contentWidth : 0 - delegate: StackViewDelegate { - pushTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - } - } - } -} diff --git a/resources/qml/+android/TitleBarAction.qml b/resources/qml/+android/TitleBarAction.qml deleted file mode 100644 index d154e8f..0000000 --- a/resources/qml/+android/TitleBarAction.qml +++ /dev/null @@ -1,4 +0,0 @@ -import QtQuick 2.7 - -Text { -} diff --git a/resources/qml/+android/TitleBarMenuAction.qml b/resources/qml/+android/TitleBarMenuAction.qml deleted file mode 100644 index 6861272..0000000 --- a/resources/qml/+android/TitleBarMenuAction.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.7 - -Item { - property string state - signal clicked -} diff --git a/resources/qml/+ios/ContentArea.qml b/resources/qml/+ios/ContentArea.qml new file mode 100644 index 0000000..4234bbd --- /dev/null +++ b/resources/qml/+ios/ContentArea.qml @@ -0,0 +1,52 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.PinView 1.0 +import Governikus.MoreView 1.0 +import Governikus.IdentifyView 1.0 +import Governikus.ProviderView 1.0 +import Governikus.HistoryView 1.0 + +Item { + id: baseItem + property alias ready: identifyView.ready + readonly property var visibleItem: visibleChildren[0] + readonly property var currentSectionPage: if (visibleItem) visibleItem.currentSectionPage + + TabBarView { + id: identifyView + anchors.fill: parent + visible: baseItem.state === "identify" + sourceComponent: IdentifyView {} + } + + TabBarView { + anchors.fill: parent + visible: baseItem.state === "provider" + prefetch: identifyView.ready + sourceComponent: ProviderView {} + } + + TabBarView { + anchors.fill: parent + visible: baseItem.state === "history" + prefetch: identifyView.ready + sourceComponent: HistoryView {} + } + + TabBarView { + id: pinView + anchors.fill: parent + visible: baseItem.state === "pin" + prefetch: identifyView.ready + sourceComponent: PinView {} + } + + TabBarView { + anchors.fill: parent + visible: baseItem.state === "more" + prefetch: identifyView.ready + sourceComponent: MoreView {} + } + +} diff --git a/resources/qml/BluetoothProgressIndicator.qml b/resources/qml/BluetoothProgressIndicator.qml deleted file mode 100644 index 0db0733..0000000 --- a/resources/qml/BluetoothProgressIndicator.qml +++ /dev/null @@ -1,64 +0,0 @@ -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 deleted file mode 100644 index 807eefa..0000000 --- a/resources/qml/BluetoothWorkflow.qml +++ /dev/null @@ -1,97 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.1 - -import "global" - -Item { - id: baseItem - signal abortBluetooth - - 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" || - state === "bt_enterpuk" || state === "bt_changepin_entercan" || - state === "bt_changepin_enterpin" || state === "bt_identify_entercan" || - state === "bt_identify_enterpin" - } - - BluetoothProgressIndicator { - id: progressIndicator - anchors.left: parent.left - anchors.top: parent.top - anchors.right: parent.right - 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" :"" - } - - 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 - - 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.") : "" - - 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") : "" - - 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/BusyImageIndicator.qml b/resources/qml/BusyImageIndicator.qml deleted file mode 100644 index 1d0de93..0000000 --- a/resources/qml/BusyImageIndicator.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - - -Item { - property string image - property alias running: busyIndicator.running - - BusyIndicator { - id: busyIndicator - anchors.centerIn: parent - height: img.height - width: height - running: false - style: NpaBusyIndicatorStyle {factor: 1.2} - } - - Image { - id: img - anchors.centerIn: parent - width: parent.width - fillMode: Image.PreserveAspectFit - smooth: true - source: image - } -} diff --git a/resources/qml/CardReader.qml b/resources/qml/CardReader.qml deleted file mode 100644 index 3136367..0000000 --- a/resources/qml/CardReader.qml +++ /dev/null @@ -1,213 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item { - property bool pinFieldAnimation: true - property bool cardAnimation: true - - id: baseItem - width: height * 3 / 7 - - Timer { - property int index - - id: onTimer - interval: 1500 - running: pinFieldAnimation || cardAnimation - triggeredOnStart: true - - onTriggered: { - onTimer.triggeredOnStart = false - if (pinFieldAnimation) - { - onTimer.index = Utils.getRandomInt(0, 9) - repeater.itemAt(onTimer.index).state = "on" - } - - if (cardAnimation) - { - card.state = "out" - } - - offTimer.restart() - } - } - - Timer { - id: offTimer - interval: 500 - onTriggered: { - if (onTimer.index != undefined) - { - repeater.itemAt(onTimer.index).state = "off" - } - - card.state = "in" - - onTimer.restart() - } - } - - - - Rectangle { - id: reader - color: "#92cef9" - radius: height * 0.05 - anchors.bottom: parent.bottom - width: parent.width - height: parent.height * 5 / 7 - - Rectangle { - id: slot - color: "white" - radius: 10 - height: reader.height * 0.05 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: parent.height * 0.05 - anchors.leftMargin: parent.width * 0.2 - anchors.rightMargin: parent.width * 0.2 - } - - Rectangle { - id: card - color: Constants.blue - radius: height * 0.05 - anchors.horizontalCenter: parent.horizontalCenter - height: baseItem.height * 1.5 / 7 - width: baseItem.width * 0.5 - - onVisibleChanged: y = reader.mapFromItem(pinView, pinView.x, card.y).y - - Rectangle { - id: cardStripe1 - color: "white" - radius: 10 - height: parent.height * 0.1 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: parent.height * 0.1 - anchors.leftMargin: parent.width * 0.1 - anchors.rightMargin: parent.width * 0.1 - } - - Rectangle { - id: cardStripe2 - color: "white" - radius: cardStripe1.radius - height: parent.height * 0.1 - anchors.top: cardStripe1.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: parent.height * 0.2 - anchors.leftMargin: parent.width * 0.1 - anchors.rightMargin: parent.width * 0.1 - } - - MouseArea { - anchors.fill: parent - onClicked: card.state = card.state === "out" ? "in" : "out" - } - - states: [ - State { - name: "out" - AnchorChanges {target: card; anchors.bottom: reader.top} - }, - State { - name: "in" - AnchorChanges {target: card; anchors.bottom: slot.verticalCenter} - } - ] - - transitions: [ - Transition { - AnchorAnimation {duration: 500} - } - ] - } - - Rectangle { - readonly property int margin: parent.width * 0.1 - id: display - color: "white" - radius: height * 0.2 - height: reader.height * 0.2 - anchors.bottom: pinGrid.top - anchors.margins: margin - anchors.left: parent.left - anchors.right: parent.right - } - - Grid { - id: pinGrid - anchors.bottom: reader.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: display.margin - - columns: 3 - spacing: anchors.margins - height: width - - Repeater { - id: repeater - model: 9 - - Item { - readonly property int _size: (reader.width - 4 * pinGrid.spacing) / 3 - property alias state: pinButtonCircle.state - - id: pinButton - width: _size - height: width - - Rectangle { - id: pinButtonCircle - anchors.centerIn: parent - width: pinButton._size - height: width - radius: width * 0.5 - - Behavior on color { - ColorAnimation { - duration: 250 - } - } - - Behavior on width { - NumberAnimation { - duration: 1000 - easing.type: Easing.OutElastic - } - } - - MouseArea { - anchors.fill: parent - onClicked: pinButton.state = pinButton.state === "off" ? "on" : "off" - } - - state: "off" - - states: [ - State { - name: "off" - PropertyChanges {target: pinButtonCircle; color: "white"} - PropertyChanges {target: pinButtonCircle; width: pinButton._size} - }, - State { - name: "on" - PropertyChanges {target: pinButtonCircle; color: Constants.blue} - PropertyChanges {target: pinButtonCircle; width: pinButton._size + pinButton._size * 0.3} - } - ] - } - } - } - } - } -} diff --git a/resources/qml/ContentArea.qml b/resources/qml/ContentArea.qml index c90e510..4b11736 100644 --- a/resources/qml/ContentArea.qml +++ b/resources/qml/ContentArea.qml @@ -1,44 +1,3 @@ -import QtQuick 2.5 - -import "global" - Item { - id: baseItem - - function getVisibleItem() { - return baseItem.visibleChildren[0] - } - - TabBarView { - id: identifyView - anchors.fill: parent - visible: baseItem.state === "identify" - source: "identify/IdentifyView.qml" - } - - TabBarView { - anchors.fill: parent - visible: baseItem.state === "provider" - source: "provider/ProviderView.qml" - } - - TabBarView { - anchors.fill: parent - visible: baseItem.state === "history" - source: "history/HistoryView.qml" - } - - TabBarView { - id: pinView - anchors.fill: parent - visible: baseItem.state === "pin" - source: "pin/PinView.qml" - } - - TabBarView { - anchors.fill: parent - visible: baseItem.state === "more" - source: "more/MoreView.qml" - } - + id: dummy } diff --git a/resources/qml/ContentAreaLoader.qml b/resources/qml/ContentAreaLoader.qml new file mode 100644 index 0000000..fb5ecfd --- /dev/null +++ b/resources/qml/ContentAreaLoader.qml @@ -0,0 +1,28 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +// This proxy Component interrupts the QML parsing process by using a URL for +// the Loader. The parsing of the included file is continued in a background +// process by the loader. This way the splash screen is shown while the Loader +// parses the given source. +Item { + id: baseItem + property bool ready: false + readonly property var visibleItem: if (loader.item) loader.item.visibleChildren[0] + readonly property var currentSectionPage: if (visibleItem) visibleItem.currentSectionPage + + Loader { + id: loader + anchors.fill: parent + + asynchronous: true + source: "ContentAreaSelector.qml" + onStatusChanged: { + if (status === Loader.Ready){ + baseItem.ready = Qt.binding(function() {return loader.item.ready}) + item.state = Qt.binding(function() {return baseItem.state}) + } + } + } +} diff --git a/resources/qml/ContentAreaSelector.qml b/resources/qml/ContentAreaSelector.qml new file mode 100644 index 0000000..2b5109e --- /dev/null +++ b/resources/qml/ContentAreaSelector.qml @@ -0,0 +1,8 @@ +import QtQuick 2.5 + +// This proxy file is required since a Component loaded via the Loader.source URL +// does not know which platform selector is in charge. +ContentArea { + id: contentArea + anchors.fill: parent +} diff --git a/resources/qml/EnterPinView.qml b/resources/qml/EnterPinView.qml deleted file mode 100644 index e070720..0000000 --- a/resources/qml/EnterPinView.qml +++ /dev/null @@ -1,124 +0,0 @@ -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/Governikus/DeveloperView/DeveloperView.qml b/resources/qml/Governikus/DeveloperView/DeveloperView.qml new file mode 100644 index 0000000..40cecc0 --- /dev/null +++ b/resources/qml/Governikus/DeveloperView/DeveloperView.qml @@ -0,0 +1,97 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + + +SectionPage { + id: root + leftTitleBarAction: TitleBarAction { state: !topLevelPage ? "back" : ""; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: qsTr("Developer options") + settingsModel.translationTrigger; font.bold: true } + + content: Item + { + height: pane.height + 2 * Constants.component_spacing + width: root.width + + Column + { + anchors.fill: parent + anchors.margins: Constants.component_spacing + + Pane { + id: pane + + 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 + + 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 } + } + } + } + + GroupBox { + title: "Use test uri for selfauthentication:" + height: implicitHeight + width: implicitWidth + + 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 } + } + } + } + } + } + } +} diff --git a/resources/qml/Governikus/DeveloperView/qmldir b/resources/qml/Governikus/DeveloperView/qmldir new file mode 100644 index 0000000..fc88bd6 --- /dev/null +++ b/resources/qml/Governikus/DeveloperView/qmldir @@ -0,0 +1,2 @@ +module DeveloperView +DeveloperView 1.0 DeveloperView.qml diff --git a/resources/qml/Governikus/EnterPinView/EnterPinView.qml b/resources/qml/Governikus/EnterPinView/EnterPinView.qml new file mode 100644 index 0000000..c9a4681 --- /dev/null +++ b/resources/qml/Governikus/EnterPinView/EnterPinView.qml @@ -0,0 +1,118 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 + +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: (!pinField.confirmedInput ? qsTr("The entered PIN does not match the new PIN. Please correct your input.") : + !!numberModel.inputError ? numberModel.inputError : + baseItem.state === "CAN" ? qsTr("You have entered the wrong PIN twice. Prior to 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 6-digit PIN of your choice.") : + baseItem.state === "PIN_NEW_AGAIN" ? qsTr("Please enter your new 6-digit PIN again.") : + baseItem.state === "PIN" ? qsTr("Please enter your personal PIN.") : + /*"PIN_OR_TRANSPORT_PIN"*/ qsTr("Please enter your current PIN or your initial transport PIN first.") + ) + settingsModel.translationTrigger + } + 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/Governikus/EnterPinView/PinField.qml b/resources/qml/Governikus/EnterPinView/PinField.qml new file mode 100644 index 0000000..b563c19 --- /dev/null +++ b/resources/qml/Governikus/EnterPinView/PinField.qml @@ -0,0 +1,65 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 + +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/Governikus/EnterPinView/PinPad.qml b/resources/qml/Governikus/EnterPinView/PinPad.qml new file mode 100644 index 0000000..47232f0 --- /dev/null +++ b/resources/qml/Governikus/EnterPinView/PinPad.qml @@ -0,0 +1,46 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 + +GridLayout { + id: baseItem + + 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 + } + 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/Governikus/EnterPinView/PinPadButton.qml b/resources/qml/Governikus/EnterPinView/PinPadButton.qml new file mode 100644 index 0000000..abf910e --- /dev/null +++ b/resources/qml/Governikus/EnterPinView/PinPadButton.qml @@ -0,0 +1,42 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import Governikus.Global 1.0 + +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/Governikus/EnterPinView/qmldir b/resources/qml/Governikus/EnterPinView/qmldir new file mode 100644 index 0000000..94099f3 --- /dev/null +++ b/resources/qml/Governikus/EnterPinView/qmldir @@ -0,0 +1,2 @@ +module EnterPinView +EnterPinView 1.0 EnterPinView.qml diff --git a/resources/qml/Governikus/FeedbackView/Feedback.qml b/resources/qml/Governikus/FeedbackView/Feedback.qml new file mode 100644 index 0000000..8228bcf --- /dev/null +++ b/resources/qml/Governikus/FeedbackView/Feedback.qml @@ -0,0 +1,117 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + + +SectionPage { + id: root + headerTitleBarAction: TitleBarAction { text: qsTr("Help & Feedback") + settingsModel.translationTrigger; 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") + settingsModel.translationTrigger + 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.") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + } + + Pane { + Loader { + readonly property string titleText: qsTr("FAQ") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("Do you have questions how to use AusweisApp2?") + settingsModel.translationTrigger + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/questions-and-answers/frequently-asked-questions/")) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Support") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("You need further help?") + settingsModel.translationTrigger + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/questions-and-answers/support/")) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Rate AusweisApp2") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("Please rate us in the Google Play Store.") + settingsModel.translationTrigger + 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("Report error") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("You found a bug? Please tell us, so we can fix it.") + settingsModel.translationTrigger + readonly property string emailAddress: "support.ausweisapp2@governikus.de" + readonly property string emailSubject: qsTr("Android log file") + settingsModel.translationTrigger + readonly property string emailBody: qsTr("") + settingsModel.translationTrigger + function onClickFunction() { qmlExtension.mailLog(emailAddress, emailSubject, emailBody) } + width: parent.width + sourceComponent: subMenu + } + } + } + } +} diff --git a/resources/qml/Governikus/FeedbackView/qmldir b/resources/qml/Governikus/FeedbackView/qmldir new file mode 100644 index 0000000..da44e42 --- /dev/null +++ b/resources/qml/Governikus/FeedbackView/qmldir @@ -0,0 +1,2 @@ +module FeedbackView +Feedback 1.0 Feedback.qml diff --git a/resources/qml/Governikus/Global/+android/+tablet/PlatformConstants.qml b/resources/qml/Governikus/Global/+android/+tablet/PlatformConstants.qml new file mode 100644 index 0000000..861146c --- /dev/null +++ b/resources/qml/Governikus/Global/+android/+tablet/PlatformConstants.qml @@ -0,0 +1,29 @@ +pragma Singleton + +import QtQuick 2.5 + +import "Utils.js" as Utils + +Item { + readonly property color grey_light: "#bbbbbb" + readonly property color grey_border: "lightslategrey" + readonly property color blue_dark: "#324d66" + readonly property color blue_light: "#659bcd" + readonly property color primary_text: "#ffffff" + readonly property color secondary_text: "#444444" + readonly property color accent_color: "#7879b2" + readonly property color second_accent_color: "#a3cb7f" + 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: "#7879b2" + readonly property int button_height: Utils.dp(36) + readonly property bool use_history_list_delete_area: false + + readonly property bool is_layout_android: true + readonly property bool is_layout_ios: false + readonly property bool is_tablet: true + readonly property bool leftNavigation: true + readonly property bool bottomNavigation: false +} diff --git a/resources/qml/Governikus/Global/+android/GButton.qml b/resources/qml/Governikus/Global/+android/GButton.qml new file mode 100644 index 0000000..d28a84e --- /dev/null +++ b/resources/qml/Governikus/Global/+android/GButton.qml @@ -0,0 +1,101 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "Utils.js" as Utils +import "." as Gov + +/* + * Custom implementation to be replaced with template specialization of Qt.labs.controls Button + * Android style guide for material design is adapted. + */ +Item { + property alias text: textItem.text + property color buttonColor: Gov.Constants.blue + property int maxWidth: 0 + property alias iconSource: icon.source + + signal clicked + + height: Gov.Constants.button_height + width: Math.max(textItem.implicitWidth + (icon.visible ? (icon.width + icon.anchors.leftMargin) : 0) + (2 * Utils.dp(16)), Utils.dp(88)) + + state: "normal" + states: [ + State { name: "normal"; when: !mouseArea.pressed + PropertyChanges { target: darkLayer; width: 0 } + PropertyChanges { target: shadow; verticalOffset: Utils.dp(2) } + }, + State { name: "pressed"; when: mouseArea.pressed + PropertyChanges { target: darkLayer; width: 2 * rect.width } + PropertyChanges { target: shadow; verticalOffset: Utils.dp(8) } + } + ] + transitions: [ + Transition { + from: "normal"; to: "pressed"; reversible: false + PropertyAnimation { target: darkLayer; property: "width"} + PropertyAnimation { target: shadow; property: "verticalOffset"} + } + ] + + Rectangle { + id: rect + anchors.fill: parent + color: enabled ? buttonColor : "#10000000" + radius: Utils.dp(3) + + Item { + anchors.fill: parent + clip: true + Rectangle { + id: darkLayer + x: mouseArea.containsMouse ? mouseArea.mouseX - width * 0.5 : 0 + height: parent.height + color: "#000000" + opacity: 0.2 + radius: Utils.dp(3) + } + } + + } + + DropShadow { + id: shadow + anchors.fill: rect + radius: 8.0 + fast: true + color: "#40000000" + source: rect + } + + Image { + id: icon + visible: source.toString().length > 0 + height: rect.height - Utils.dp(10) + width: height + anchors.left: rect.left + anchors.leftMargin: Utils.dp(5) + anchors.verticalCenter: rect.verticalCenter + } + + Text { + id: textItem + anchors.left: rect.left + anchors.right: rect.right + anchors.verticalCenter: rect.verticalCenter + anchors.leftMargin: icon.visible ? icon.width + icon.anchors.leftMargin : 0 + horizontalAlignment: Text.AlignHCenter + color: enabled ? "white" : "#40000000" + font.capitalization: Font.AllUppercase + font.bold: true + font.pixelSize: Utils.dp(16) + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: parent.clicked() + } +} + diff --git a/resources/qml/Governikus/Global/+android/GCheckBox.qml b/resources/qml/Governikus/Global/+android/GCheckBox.qml new file mode 100644 index 0000000..542b61f --- /dev/null +++ b/resources/qml/Governikus/Global/+android/GCheckBox.qml @@ -0,0 +1,51 @@ +import QtQuick 2.7 + +import "Utils.js" as Utils +import "." as Gov + +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 ? Gov.Constants.accent_color : "white") : Gov.Constants.grey + border.color: checked ? Gov.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: Gov.Constants.normal_font_size + } + } + + MouseArea { + anchors.fill: row + onClicked: if (enabled) box.checked = !box.checked + } +} diff --git a/resources/qml/Governikus/Global/+android/LabeledText.qml b/resources/qml/Governikus/Global/+android/LabeledText.qml new file mode 100644 index 0000000..6de66c4 --- /dev/null +++ b/resources/qml/Governikus/Global/+android/LabeledText.qml @@ -0,0 +1,40 @@ +import QtQuick 2.5 + +import "." as Gov + +Item { + property alias label: labelText.text + property alias text: bodyText.text + property alias textFormat: bodyText.textFormat + property int margin + property int fontUppercase + + signal linkActivated(string link) + + height: childrenRect.height + margin + + Text { + id: bodyText + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: margin + anchors.right: parent.right + anchors.rightMargin: margin + font.pixelSize: Gov.Constants.normal_font_size + font.capitalization: fontUppercase + wrapMode: Text.WordWrap + onLinkActivated: parent.linkActivated(link) + } + + Text { + id: labelText + anchors.top: bodyText.bottom + anchors.left: parent.left + anchors.leftMargin: margin + anchors.right: parent.right + anchors.rightMargin: margin + font.pixelSize: Gov.Constants.label_font_size + color: Gov.Constants.blue + wrapMode: Text.WordWrap + } +} diff --git a/resources/qml/Governikus/Global/+android/Pane.qml b/resources/qml/Governikus/Global/+android/Pane.qml new file mode 100644 index 0000000..2ebe8a2 --- /dev/null +++ b/resources/qml/Governikus/Global/+android/Pane.qml @@ -0,0 +1,50 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "." as Gov + + +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: Gov.Constants.pane_padding + anchors.rightMargin: Gov.Constants.pane_padding + + Text { + id: titleText + height: implicitHeight * 2 + width: parent.width + visible: text !== "" + verticalAlignment: Text.AlignVCenter + font.pixelSize: Gov.Constants.header_font_size + color: Gov.Constants.blue + } + Item { width: parent.width; height: Gov.Constants.pane_padding } + Column { + id: paneContent + width: parent.width + spacing: Gov.Constants.pane_spacing + } + Item { width: parent.width; height: Gov.Constants.pane_padding } + } + + layer.enabled: true + layer.effect: DropShadow { + radius: 8 + samples: 8 + source: root + color: Gov.Constants.grey + verticalOffset: 2 + } +} diff --git a/resources/qml/Governikus/Global/+android/PlatformConstants.qml b/resources/qml/Governikus/Global/+android/PlatformConstants.qml new file mode 100644 index 0000000..256055a --- /dev/null +++ b/resources/qml/Governikus/Global/+android/PlatformConstants.qml @@ -0,0 +1,29 @@ +pragma Singleton + +import QtQuick 2.5 + +import "Utils.js" as Utils + +Item { + readonly property color grey_light: "#bbbbbb" + readonly property color grey_border: "lightslategrey" + readonly property color blue_dark: "#324d66" + readonly property color blue_light: "#659bcd" + readonly property color primary_text: "#ffffff" + readonly property color secondary_text: "#444444" + readonly property color accent_color: "#7879b2" + readonly property color second_accent_color: "#a3cb7f" + 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: "#7879b2" + readonly property int button_height: Utils.dp(36) + readonly property bool use_history_list_delete_area: false + + readonly property bool is_layout_android: true + readonly property bool is_layout_ios: false + readonly property bool is_tablet: false + readonly property bool leftNavigation: true + readonly property bool bottomNavigation: false +} diff --git a/resources/qml/Governikus/Global/+ios/+tablet/Pane.qml b/resources/qml/Governikus/Global/+ios/+tablet/Pane.qml new file mode 100644 index 0000000..d1ab6fd --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/+tablet/Pane.qml @@ -0,0 +1,50 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "." + + +Rectangle { + id: root + property alias title: titleText.text + property alias spacing: paneContent.spacing + default property alias paneChildren: paneContent.children + + anchors.left: parent.left + anchors.right: parent.right + height: childrenRect.height + color: "white" + + 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/Governikus/Global/+ios/+tablet/PlatformConstants.qml b/resources/qml/Governikus/Global/+ios/+tablet/PlatformConstants.qml new file mode 100644 index 0000000..27380a6 --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/+tablet/PlatformConstants.qml @@ -0,0 +1,29 @@ +pragma Singleton + +import QtQuick 2.5 + +import "Utils.js" as Utils + +Item { + readonly property color grey_light: "#8e8e93" + readonly property color grey_border: "lightslategrey" + readonly property color blue_dark: "#0076ff" + readonly property color blue_light: "#54c7fc" + readonly property color primary_text: "#ffffff" + readonly property color secondary_text: "#000000" + readonly property color accent_color: "#000000" + readonly property color second_accent_color: "#000000" + readonly property int titlebar_font_size: Utils.sp(16) + readonly property int provider_section_height: Utils.dp(50) + readonly property int history_section_height: Utils.dp(60) + readonly property int history_delegate_spacing: 0 + readonly property color history_delegate_address_color: "#00878F" + readonly property int button_height: Utils.dp(40) + readonly property bool use_history_list_delete_area: true + + readonly property bool is_layout_android: false + readonly property bool is_layout_ios: true + readonly property bool is_tablet: true + readonly property bool leftNavigation: false + readonly property bool bottomNavigation: true +} diff --git a/resources/qml/Governikus/Global/+ios/GButton.qml b/resources/qml/Governikus/Global/+ios/GButton.qml new file mode 100644 index 0000000..03be62b --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/GButton.qml @@ -0,0 +1,46 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import "." + +/* Custom implementation to be replaced with template specialization of Qt.labs.controls Button*/ +Rectangle { + property alias text: textItem.text + property color buttonColor : Constants.blue + property int maxWidth: 0 + property int preferedWidth: parent.width - 4 * Constants.component_spacing + + signal clicked + + color: enabled ? buttonColor : "#10000000" + height: Constants.button_height + width: maxWidth > 0 ? Math.min(maxWidth, preferedWidth) : preferedWidth + clip: true + + Text { + id: textItem + anchors.centerIn: parent + color: enabled ? "white" : "#40000000" + opacity: mouseArea.containsMouse ? 0.5 : 1 + font.pixelSize: Utils.dp(16) + } + MouseArea{ + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: parent.clicked() + } + + RadialGradient { + x: mouseArea.mouseX - width * 0.5 + height: parent.height + width: height * 2 + visible: mouseArea.pressed + opacity: 1 + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.rgba(255,255,255,1) } + GradientStop { position: 0.2; color: Qt.rgba(255,255,255,0.5) } + GradientStop { position: 0.4; color: Qt.rgba(255,255,255,0) } + } + } +} diff --git a/resources/qml/Governikus/Global/+ios/GCheckBox.qml b/resources/qml/Governikus/Global/+ios/GCheckBox.qml new file mode 100644 index 0000000..dd5839c --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/GCheckBox.qml @@ -0,0 +1,37 @@ +import QtQuick 2.7 + +import "." + +Item { + property bool checked: false + property alias text: description.text + + height: Utils.dp(20) + width: row.width + + Row { + id: row + height: parent.height + spacing: Utils.dp(6) + + Image { + id: image + source: checked && enabled ? "qrc:///images/iOS/CheckedCheckbox.png" : "" + height: parent.height + width: height + fillMode: Image.PreserveAspectFit + } + + Text { + id: description + visible: text !== "" + anchors.verticalCenter: image.verticalCenter + font.pixelSize: Constants.normal_font_size + } + } + + MouseArea { + anchors.fill: row + onClicked: if (enabled) checked = !checked + } +} diff --git a/resources/qml/global/LabeledText.qml b/resources/qml/Governikus/Global/+ios/LabeledText.qml similarity index 100% rename from resources/qml/global/LabeledText.qml rename to resources/qml/Governikus/Global/+ios/LabeledText.qml diff --git a/resources/qml/Governikus/Global/+ios/Pane.qml b/resources/qml/Governikus/Global/+ios/Pane.qml new file mode 100644 index 0000000..d6a6a05 --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/Pane.qml @@ -0,0 +1,47 @@ +import QtQuick 2.5 + +import "." + + +Column { + id: root + property alias title: titleText.text + property alias spacing: paneContent.spacing + default property alias paneData: paneContent.data + + anchors.left: parent.left + anchors.right: parent.right + + Text { + id: titleText + height: Utils.dp(30) + visible: text !== "" + anchors.left: parent.left + anchors.leftMargin: Constants.pane_padding + font.pixelSize: Constants.header_font_size + font.capitalization: Font.AllUppercase + color: Constants.grey + } + + Rectangle { width: parent.width; height: 1; color: Constants.grey} + Rectangle { + color: "white" + width: parent.width + height: childrenRect.height + + Column { + width: parent.width + Item { width: parent.width; height: Constants.pane_padding } + Column { + id: paneContent + anchors.left: parent.left + anchors.leftMargin: Constants.pane_padding + anchors.right: parent.right + anchors.rightMargin: Constants.pane_padding + spacing: Constants.component_spacing + } + Item { width: parent.width; height: Constants.pane_padding } + } + } + Rectangle { width: parent.width; height: 1; color: Constants.grey} +} diff --git a/resources/qml/Governikus/Global/+ios/PlatformConstants.qml b/resources/qml/Governikus/Global/+ios/PlatformConstants.qml new file mode 100644 index 0000000..4b8ad5d --- /dev/null +++ b/resources/qml/Governikus/Global/+ios/PlatformConstants.qml @@ -0,0 +1,29 @@ +pragma Singleton + +import QtQuick 2.5 + +import "Utils.js" as Utils + +Item { + readonly property color grey_light: "#8e8e93" + readonly property color grey_border: "lightslategrey" + readonly property color blue_dark: "#0076ff" + readonly property color blue_light: "#54c7fc" + readonly property color primary_text: "#ffffff" + readonly property color secondary_text: "#000000" + readonly property color accent_color: "#000000" + readonly property color second_accent_color: "#000000" + readonly property int titlebar_font_size: Utils.sp(16) + readonly property int provider_section_height: Utils.dp(50) + readonly property int history_section_height: Utils.dp(85) + readonly property int history_delegate_spacing: 0 + readonly property color history_delegate_address_color: "#00878F" + readonly property int button_height: Utils.dp(40) + readonly property bool use_history_list_delete_area: true + + readonly property bool is_layout_android: false + readonly property bool is_layout_ios: true + readonly property bool is_tablet: false + readonly property bool leftNavigation: false + readonly property bool bottomNavigation: true +} diff --git a/resources/qml/Governikus/Global/Category.js b/resources/qml/Governikus/Global/Category.js new file mode 100644 index 0000000..b40ee37 --- /dev/null +++ b/resources/qml/Governikus/Global/Category.js @@ -0,0 +1,86 @@ +function getTableValue(table, key, defaultValue) { + return key in table ? table[key] : defaultValue +} + + +function displayString(cat) { + var CATEGORY_TO_DISPLAY_STRING = { + "": qsTr("Provider"), + "all": qsTr("All"), + "citizen": qsTr("Citizen services"), + "insurance": qsTr("Insurances"), + "finance": qsTr("Financials"), + "other": qsTr("Other services") + } + 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" + +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) { + return getTableValue(CATEGORY_TO_COLOR, cat, CATEGORY_COLOR_NONE) +} + + +var CATEGORY_TO_IMAGE_NAME = { + "citizen": "citizen", + "insurance": "insurance", + "finance": "finance", + "other": "other", + "all": "general", + "": "general" +} + +function imageName(cat) { + return getTableValue(CATEGORY_TO_IMAGE_NAME, cat, "general") +} + + +function getPlatform() { + return plugin.platformStyle.indexOf("android") !== -1 ? "+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/Governikus/Global/Constants.qml b/resources/qml/Governikus/Global/Constants.qml new file mode 100644 index 0000000..5599fd3 --- /dev/null +++ b/resources/qml/Governikus/Global/Constants.qml @@ -0,0 +1,60 @@ +pragma Singleton + +import QtQuick 2.5 +import QtQuick.Window 2.2 + +import "Utils.js" as Utils +import "." as Gov + + +Item { + readonly property bool use_history_list_delete_area: Gov.PlatformConstants.use_history_list_delete_area + + readonly property color background_color: "#dcebf6" + readonly property color blue: "#659bcd" + readonly property color green: "#a3cb7f" + readonly property color red: "#cc0000" + readonly property color grey: "#8e8e93" + + readonly property color primary_text: Gov.PlatformConstants.primary_text + readonly property color secondary_text: Gov.PlatformConstants.secondary_text + readonly property color accent_color: Gov.PlatformConstants.accent_color + readonly property color second_accent_color: Gov.PlatformConstants.second_accent_color + + readonly property int header_font_size: thresholdReduce(22) + readonly property int normal_font_size: thresholdReduce(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_spacing: Utils.dp(18) + readonly property int titlebar_font_size: Gov.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: Gov.PlatformConstants.provider_section_height + + readonly property int history_section_height: Gov.PlatformConstants.history_section_height + readonly property int history_delegate_spacing: Gov.PlatformConstants.history_delegate_spacing + readonly property color history_delegate_address_color: Gov.PlatformConstants.history_delegate_address_color + + readonly property int button_height: Gov.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) + readonly property int groupbox_spacing: Utils.dp(10) + + function thresholdReduce(value) { + var w = Screen.width + if (w > 415) { + return Utils.sp(value) + } + return Utils.sp(value * w / 415) + } +} diff --git a/resources/qml/Governikus/Global/GButton.qml b/resources/qml/Governikus/Global/GButton.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Global/GButton.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Global/GCheckBox.qml b/resources/qml/Governikus/Global/GCheckBox.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Global/GCheckBox.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Global/GSwitch.qml b/resources/qml/Governikus/Global/GSwitch.qml new file mode 100644 index 0000000..ed44bc8 --- /dev/null +++ b/resources/qml/Governikus/Global/GSwitch.qml @@ -0,0 +1,74 @@ +import QtQuick 2.7 + +import "Utils.js" as Utils +import "." as Gov + +MouseArea { + property alias isOn: toggleswitch.isOn + width: Utils.dp(60) + height: Utils.dp(48) + + onClicked: toggleswitch.toggle() + + Item { + id: toggleswitch + anchors.fill: parent + anchors.topMargin: Utils.dp(12) + anchors.bottomMargin: Utils.dp(12) + + property bool isOn: false + onIsOnChanged: state = (isOn ? "on" : "off") + + readonly property int dragMax: width - height + + function toggle() { + isOn = !isOn + } + + function releaseSwitch() { + isOn = (button.x > dragMax / 2) + button.x = (isOn ? dragMax : 0) + } + + Rectangle { + id: background + anchors.fill: parent + anchors.margins: parent.height / 4 + radius: height / 2 + color: isOn ? Qt.lighter(Gov.Constants.blue, 1.55) : "lightgray" + } + + Rectangle { + id: button + height: parent.height + width: height + radius: width + color: isOn ? Gov.Constants.blue : "darkgray" + + MouseArea { + anchors.fill: parent + drag.target: button + drag.axis: Drag.XAxis + drag.minimumX: 0 + drag.maximumX: toggleswitch.dragMax + onClicked: toggleswitch.toggle() + onReleased: toggleswitch.releaseSwitch() + } + } + + states: [ + State { + name: "on" + PropertyChanges { target: button; x: toggleswitch.dragMax } + }, + State { + name: "off" + PropertyChanges { target: button; x: 0 } + } + ] + + transitions: Transition { + NumberAnimation { properties: "x"; easing.type: Easing.InOutQuad; duration: 200 } + } + } +} diff --git a/resources/qml/Governikus/Global/GTextField.qml b/resources/qml/Governikus/Global/GTextField.qml new file mode 100644 index 0000000..bbf26b0 --- /dev/null +++ b/resources/qml/Governikus/Global/GTextField.qml @@ -0,0 +1,40 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "Utils.js" as Utils +import "." as Gov + +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: Gov.Constants.red + color: enabled ? "white" : Gov.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: Gov.Constants.normal_font_size + onAccepted: parent.accepted() + style: TextFieldStyle { + background: Rectangle {} + } + } + + onActiveFocusChanged: if (focus) field.forceActiveFocus() +} diff --git a/resources/qml/Governikus/Global/LabeledText.qml b/resources/qml/Governikus/Global/LabeledText.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Global/LabeledText.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Global/LocationButton.qml b/resources/qml/Governikus/Global/LocationButton.qml new file mode 100644 index 0000000..8b9e739 --- /dev/null +++ b/resources/qml/Governikus/Global/LocationButton.qml @@ -0,0 +1,48 @@ +import QtQuick 2.7 + +import "Utils.js" as Utils +import "." as Gov + +MouseArea { + property string language + property string name + property string image + + height: Utils.dp(35) + width: height + + onClicked: { + settingsModel.language = language + if (typeof(navigationController) !== "undefined") { + navigationController.close() + } + } + + Rectangle { + opacity: 0.1 + border.color: "black" + border.width: settingsModel.language === language ? 0 : Utils.dp(1) + color: settingsModel.language === language ? "black" : Gov.Constants.background_color + anchors.fill: parent + radius: Utils.dp(3) + } + + Text { + text: name + + anchors.margins: Utils.dp(2) + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: Gov.Constants.small_font_size + } + + Image { + source: image + fillMode: Image.PreserveAspectFit + + anchors.margins: Utils.dp(4) + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.right: parent.right + } +} diff --git a/resources/qml/Governikus/Global/Pane.qml b/resources/qml/Governikus/Global/Pane.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Global/Pane.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Global/PlatformConstants.qml b/resources/qml/Governikus/Global/PlatformConstants.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Global/PlatformConstants.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Global/SectionPage.qml b/resources/qml/Governikus/Global/SectionPage.qml new file mode 100644 index 0000000..d95f24c --- /dev/null +++ b/resources/qml/Governikus/Global/SectionPage.qml @@ -0,0 +1,58 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +Item { + signal firePush(var sectionPage, var properties) + signal firePop() + signal firePopAll() + + property bool topLevelPage: false + + property var leftTitleBarAction: TitleBarAction {} + property var headerTitleBarAction: TitleBarAction {} + property var rightTitleBarAction: Item {} + property var subTitleBarAction: Item {} + + property color titleBarColor: Constants.blue + /* if the header component has a property named titleBarOpacity, use it, otherwise use default value*/ + readonly property real titleBarOpacity: headerLoader.item && typeof(headerLoader.item.titleBarOpacity) != "undefined" ? headerLoader.item.titleBarOpacity : 1 + + property alias header: headerLoader.sourceComponent + property alias content: contentLoader.sourceComponent + property alias contentY: flickable.contentY + property bool disableFlicking: false + + Flickable { + property real startContentY: 0 + id: flickable + clip: true + flickableDirection: Flickable.VerticalFlick + contentWidth: flickableContent.width + contentHeight: flickableContent.height + anchors.bottom: parent.bottom + width: parent.width + /* if a header is set, it is shown as background of the TitleBar, so we need to expand the height*/ + height: headerLoader.item ? parent.height + Constants.titlebar_height : parent.height + onMovementStarted: { + startContentY = contentY + } + onContentYChanged: { + if (disableFlicking || contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } + Column { + id: flickableContent + Loader { + id: headerLoader + readonly property alias contentY: flickable.contentY + } + Loader { + id: contentLoader + readonly property alias contentY: flickable.contentY + } + } + } +} diff --git a/resources/qml/global/Utils.js b/resources/qml/Governikus/Global/Utils.js similarity index 100% rename from resources/qml/global/Utils.js rename to resources/qml/Governikus/Global/Utils.js diff --git a/resources/qml/Governikus/Global/qmldir b/resources/qml/Governikus/Global/qmldir new file mode 100644 index 0000000..afca3a9 --- /dev/null +++ b/resources/qml/Governikus/Global/qmldir @@ -0,0 +1,13 @@ +module Global +singleton Constants 1.0 Constants.qml +singleton PlatformConstants 1.0 PlatformConstants.qml +Utils 1.0 Utils.js +Category 1.0 Category.js +LabeledText 1.0 LabeledText.qml +Pane 1.0 Pane.qml +GCheckBox 1.0 GCheckBox.qml +GTextField 1.0 GTextField.qml +GButton 1.0 GButton.qml +LocationButton 1.0 LocationButton.qml +SectionPage 1.0 SectionPage.qml +GSwitch 1.0 GSwitch.qml diff --git a/resources/qml/Governikus/HistoryView/+android/+tablet/HistoryView.qml b/resources/qml/Governikus/HistoryView/+android/+tablet/HistoryView.qml new file mode 100644 index 0000000..b97f193 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+android/+tablet/HistoryView.qml @@ -0,0 +1,56 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Provider 1.0 + +SectionPage { + property alias listViewModel: listView.model + property var selectedIndices: [] + + headerTitleBarAction: TitleBarAction { text: qsTr("History") + settingsModel.translationTrigger; font.bold: true } + + Text { + anchors.centerIn: parent + text: qsTr("Currently there are no history entries.") + settingsModel.translationTrigger + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: listView.count === 0 + } + + ListView { + id: listView + anchors.fill: parent + model: historyModel + onContentYChanged: { + if (contentY < 0) { + // prevent flicking over the top + contentY = 0 + } + } + + delegate: + HistoryListViewDelegate { + id: historyDelegate + anchors.left: parent.left + anchors.right: parent.right + height: Utils.dp(120) + property var historyModelItem: model + listModel: historyModel + showDetail: false + } + } + + ProviderDetailView_tablet { + id: providerHistoryView + visible: false + } + + HistoryViewDetails { + id: detailsHistoryView + visible: false + } +} diff --git a/resources/qml/Governikus/HistoryView/+android/CustomSwipeBar.qml b/resources/qml/Governikus/HistoryView/+android/CustomSwipeBar.qml new file mode 100644 index 0000000..814a0ed --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+android/CustomSwipeBar.qml @@ -0,0 +1,55 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as QtControls + +import Governikus.Global 1.0 + +QtControls.TabBar { + id: rootItem + + height: firstButton.height + width: parent.width + + 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") + settingsModel.translationTrigger + +/* + contentItem: Text { + text: qsTr("Contact") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + font.capitalization: Font.AllUppercase + elide: Text.ElideRight + opacity: enabled ? 1 : 0.3 + color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue + 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") + settingsModel.translationTrigger + +/* + contentItem: Text { + text: qsTr("History") + settingsModel.translationTrigger + font.capitalization: Font.AllUppercase + font.pixelSize: Constants.normal_font_size + elide: Text.ElideRight + opacity: enabled ? 1 : 0.3 + color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } +*/ + } +} diff --git a/resources/qml/Governikus/HistoryView/+android/HistoryItemImage.qml b/resources/qml/Governikus/HistoryView/+android/HistoryItemImage.qml new file mode 100644 index 0000000..1a1ceac --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+android/HistoryItemImage.qml @@ -0,0 +1,51 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + id: baseItem + + property string imageUrl: "" + + 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(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: categoryImage + anchors.centerIn: parent + 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.fill: background + anchors.margins: parent.imageMargin + asynchronous: true + + visible: baseItem.imageUrl !== "" + fillMode: Image.PreserveAspectFit + } +} diff --git a/resources/qml/Governikus/HistoryView/+android/HistoryListViewDelegate.qml b/resources/qml/Governikus/HistoryView/+android/HistoryListViewDelegate.qml new file mode 100644 index 0000000..bca8aa3 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+android/HistoryListViewDelegate.qml @@ -0,0 +1,23 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 + +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: borderLine + color: "black" + height: Utils.dp(1) + width: parent.width + anchors.top: contentItem.bottom + anchors.bottom: parent.bottom + } +} diff --git a/resources/qml/Governikus/HistoryView/+android/HistoryView.qml b/resources/qml/Governikus/HistoryView/+android/HistoryView.qml new file mode 100644 index 0000000..d41786e --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+android/HistoryView.qml @@ -0,0 +1,55 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + property alias listViewModel: listView.model + property var selectedIndices: [] + + headerTitleBarAction: TitleBarAction { text: qsTr("History") + settingsModel.translationTrigger; font.bold: true } + + Text { + anchors.centerIn: parent + text: qsTr("Currently there are no history entries.") + settingsModel.translationTrigger + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: listView.count === 0 + } + + ListView { + id: listView + anchors.fill: parent + model: historyModel + onContentYChanged: { + if (contentY < 0) { + // prevent flicking over the top + contentY = 0 + } + } + + delegate: + HistoryListViewDelegate { + id: historyDelegate + anchors.left: parent.left + anchors.right: parent.right + height: Utils.dp(120) + listModel: historyModel + property var historyModelItem: model + showDetail: false + } + } + + HistoryViewPage { + id: providerHistoryView + visible: false + } + + HistoryViewDetails { + id: detailsHistoryView + visible: false + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/+tablet/HistoryView.qml b/resources/qml/Governikus/HistoryView/+ios/+tablet/HistoryView.qml new file mode 100644 index 0000000..b4d800a --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/+tablet/HistoryView.qml @@ -0,0 +1,98 @@ +import QtQml.Models 2.2 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Provider 1.0 + +SectionPage { + leftTitleBarAction: TitleBarAction { + id: leftAction + + state: "edit" + states: [ + State { name: "edit"; when: !historyListView.selectable }, + State { name: "cancel"; when: historyListView.selectable } + ] + onClicked: { + if (state === "edit") { + state = "cancel" + historyListView.selectable = true + } + else { + state = "edit" + historyListView.selectable = false + historyListView.cancelDeletion() + } + } + } + + headerTitleBarAction: Text { text: qsTr("History") + settingsModel.translationTrigger; font.bold: true } + + rightTitleBarAction: TitleBarAction { + id: rightAction + + states: [ + State { + name: "none" + when: leftAction.state == "edit" + PropertyChanges { target: rightAction; text: "" } + }, + State { + name: "delete" + when: historyListView.selectable && historyListView.selectedIndices.length !== 0 + PropertyChanges { target: rightAction; text: qsTr("Delete") + settingsModel.translationTrigger } + }, + State { + name: "deleteAll" + when: historyListView.selectable && historyListView.selectedIndices.length === 0 + PropertyChanges { target: rightAction; text: qsTr("Delete all") + settingsModel.translationTrigger } + } + ] + onClicked: { + historyListView.performDeletion() + historyListView.selectable = false + } + } + + HistoryViewBackground { + visible: historyListView.count !== 0 + } + + Text { + anchors.centerIn: parent + text: qsTr("Currently there are no history entries.") + settingsModel.translationTrigger + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: historyListView.count === 0 + } + + HistoryListView { + id: historyListView + anchors.fill: parent + + listViewModel: historyModel + delegate: HistoryListViewDelegate { + id: historyDelegate + showDetail: false + } + + onSelectedIndicesChanged: { + if (!historyListView.selectable) { + leftAction.state = historyListView.selectedIndices.length !== 0 ? "cancel" : "edit" + } + } + } + + ProviderDetailView_tablet { + id: providerHistoryView + visible: false + } + + HistoryViewDetails { + id: detailsHistoryView + visible: false + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/CustomSwipeBar.qml b/resources/qml/Governikus/HistoryView/+ios/CustomSwipeBar.qml new file mode 100644 index 0000000..b961d2e --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/CustomSwipeBar.qml @@ -0,0 +1,58 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +Rectangle { + id: rootItem + property int currentIndex + + anchors.horizontalCenter: parent.horizontalCenter + width: descriptionTab.width + contactTab.width + 2 * border.width + height: descriptionTab.height + 2 * border.width + + border.color: Constants.blue + border.width: Utils.dp(1) + radius: Utils.dp(3) + clip: true + + Row { + id: row + readonly property int maxContentWidth: Math.max(descriptionText.contentWidth, contactText.contentWidth) + + anchors.centerIn: parent + Rectangle { + id: descriptionTab + width: row.maxContentWidth + Utils.dp(6) + height: descriptionText.contentHeight + Utils.dp(6) + color: rootItem.currentIndex === 0 ? Constants.blue : "white" + Text { + id: descriptionText + anchors.centerIn: parent + color: rootItem.currentIndex === 0 ? "white" : Constants.blue + text: qsTr("Contact") + settingsModel.translationTrigger + } + MouseArea { + anchors.fill: parent + onClicked: rootItem.currentIndex = 0 + } + } + Rectangle { + id: contactTab + width: row.maxContentWidth + Utils.dp(6) + height: contactText.contentHeight + Utils.dp(6) + color: rootItem.currentIndex === 1 ? Constants.blue : "white" + Text { + id: contactText + anchors.centerIn: parent + color: rootItem.currentIndex === 1 ? "white" : Constants.blue + text: qsTr("History") + settingsModel.translationTrigger + } + MouseArea { + anchors.fill: parent + onClicked: rootItem.currentIndex = 1 + } + } + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/HistoryDetails.qml b/resources/qml/Governikus/HistoryView/+ios/HistoryDetails.qml new file mode 100644 index 0000000..3e0c923 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/HistoryDetails.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + property string providerAddress: "" + + property int listItemIndex: -1 + + property var listModel + + anchors.right: parent.right + anchors.margins: Utils.dp(5) + height: parent.height + width: parent.height * 0.4 + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: width + + border.color: Constants.history_delegate_address_color + border.width: Utils.dp(1) + radius: width + + Text { + anchors.centerIn: parent + text: "i" + color: parent.border.color + } + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/HistoryItemImage.qml b/resources/qml/Governikus/HistoryView/+ios/HistoryItemImage.qml new file mode 100644 index 0000000..77de8c6 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/HistoryItemImage.qml @@ -0,0 +1,26 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + property string imageUrl: "" + + id: baseItem + + anchors.left: parent.left + anchors.leftMargin: Utils.dp(10) + + height: parent.height + width: Utils.dp(40) + + Image { + source: baseItem.imageUrl !== "" ? + baseItem.imageUrl : + (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown")) + asynchronous: true + height: Math.min(parent.height * 0.6, parent.width) + width: height + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/HistoryListViewDelegate.qml b/resources/qml/Governikus/HistoryView/+ios/HistoryListViewDelegate.qml new file mode 100644 index 0000000..e84ff81 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/HistoryListViewDelegate.qml @@ -0,0 +1,21 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + +Item { + property bool showDetail: false + + property var listModel + + id: baseItem + + HistoryListViewDelegateContent { + showDetail: baseItem.showDetail + listModel: baseItem.listModel + + width: parent.width + height: parent.height + } +} diff --git a/resources/qml/Governikus/HistoryView/+ios/HistoryView.qml b/resources/qml/Governikus/HistoryView/+ios/HistoryView.qml new file mode 100644 index 0000000..c48b16b --- /dev/null +++ b/resources/qml/Governikus/HistoryView/+ios/HistoryView.qml @@ -0,0 +1,97 @@ +import QtQml.Models 2.2 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + leftTitleBarAction: TitleBarAction { + id: leftAction + + state: "edit" + states: [ + State { name: "edit"; when: !historyListView.selectable }, + State { name: "cancel"; when: historyListView.selectable } + ] + onClicked: { + if (state === "edit") { + state = "cancel" + historyListView.selectable = true + } + else { + state = "edit" + historyListView.selectable = false + historyListView.cancelDeletion() + } + } + } + + headerTitleBarAction: Text { text: qsTr("History") + settingsModel.translationTrigger; font.bold: true } + + rightTitleBarAction: TitleBarAction { + id: rightAction + + states: [ + State { + name: "none" + when: leftAction.state == "edit" + PropertyChanges { target: rightAction; text: "" } + }, + State { + name: "delete" + when: historyListView.selectable && historyListView.selectedIndices.length !== 0 + PropertyChanges { target: rightAction; text: qsTr("Delete") + settingsModel.translationTrigger } + }, + State { + name: "deleteAll" + when: historyListView.selectable && historyListView.selectedIndices.length === 0 + PropertyChanges { target: rightAction; text: qsTr("Delete all") + settingsModel.translationTrigger } + } + ] + onClicked: { + historyListView.performDeletion() + historyListView.selectable = false + } + } + + HistoryViewBackground { + visible: historyListView.count !== 0 + } + + Text { + anchors.centerIn: parent + text: qsTr("Currently there are no history entries.") + settingsModel.translationTrigger + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: historyListView.count === 0 + } + + HistoryListView { + id: historyListView + anchors.fill: parent + + listViewModel: historyModel + delegate: HistoryListViewDelegate { + id: historyDelegate + showDetail: false + } + + onSelectedIndicesChanged: { + if (!historyListView.selectable) { + leftAction.state = historyListView.selectedIndices.length !== 0 ? "cancel" : "edit" + } + } + } + + HistoryViewPage { + id: providerHistoryView + visible: false + } + + HistoryViewDetails { + id: detailsHistoryView + visible: false + } +} diff --git a/resources/qml/Governikus/HistoryView/CustomSwipeBar.qml b/resources/qml/Governikus/HistoryView/CustomSwipeBar.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/CustomSwipeBar.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/HistoryView/HistoryDetails.qml b/resources/qml/Governikus/HistoryView/HistoryDetails.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryDetails.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/HistoryView/HistoryItemImage.qml b/resources/qml/Governikus/HistoryView/HistoryItemImage.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryItemImage.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/HistoryView/HistoryListView.qml b/resources/qml/Governikus/HistoryView/HistoryListView.qml new file mode 100644 index 0000000..20c68e8 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryListView.qml @@ -0,0 +1,221 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + +Item { + id: baseItem + + property alias listViewModel: listView.model + property alias interactive: listView.interactive + readonly property int count: listView.count + property bool deletable: true + property bool selectable: false + property var selectedIndices: [] + property Component delegate + + readonly property int contentHeight: listView.contentHeight + + function requestDeletion(index) { + selectedIndices.push(index) + selectedIndices = selectedIndices //to have the change signal emitted + } + + + function cancelDeletion(cancelIndex) { + if (arguments.length === 1) { + var reducedSelection = []; + selectedIndices.map(function (index) { + if (index !== cancelIndex) { + reducedSelection.push(index) + } + }) + selectedIndices = reducedSelection + } + else { + selectedIndices = [] + } + } + + + function performDeletion() { + if (selectedIndices.length === 0) { + listViewModel.removeRows(0, historyModel.rowCount()) + } + else { + // sort in descending order, so that the indices don't change after partial deletion + selectedIndices.sort(function(a,b){return b-a}) + selectedIndices.map(function (index) { + listViewModel.removeRows(index, 1) + }) + selectedIndices = [] //to have the change signal emitted + } + } + + + ListView { + id: listView + anchors.fill: parent + focus: true + spacing: Utils.dp(5) + + delegate: Item { + id: delegateItem + width: parent.width + height: delegateLoader.height + + Connections { + target: baseItem + onSelectedIndicesChanged: { + if (baseItem.selectedIndices.indexOf(model.index) === -1) { + flickable.state = "hideDeleteConfirmation" + checkBox.checked = false + } + } + } + + Rectangle { + id: confirmDeletionRect + height: parent.height + width: parent.width / 4 + anchors.right: parent.right + anchors.rightMargin: Utils.dp(10) + anchors.top: parent.top + anchors.topMargin: Utils.dp(8) + anchors.bottom: parent.bottom + anchors.bottomMargin: Utils.dp(8) + + color: "red" + + Text { + anchors.centerIn: parent + text: qsTr("Delete") + settingsModel.translationTrigger + color: "white" + } + } + + Flickable { + id: flickable + anchors.fill: parent + contentWidth: parent.width + confirmDeletionRect.width + contentHeight: parent.height + flickableDirection: Flickable.HorizontalFlick + interactive: baseItem.deletable && !baseItem.selectable && Constants.use_history_list_delete_area + + Item { + id: delegateContent + width: delegateItem.width + height: delegateItem.height + + CheckBox { + id: checkBox + width: Utils.dp(40) + height: parent.height + + style: IosCheckBoxStyle {} + onClicked: checked ? requestDeletion(model.index) : cancelDeletion(model.index) + } + Loader { + id: delegateLoader + anchors.left: checkBox.right + anchors.right: parent.right + height: Constants.history_section_height + sourceComponent: baseItem.delegate + property var historyModelItem: model + } + + states: [ + State { + name: "notSelectable" + when: !baseItem.selectable + PropertyChanges { target: checkBox; opacity: 0 } + AnchorChanges { target: checkBox; anchors.left: undefined} + AnchorChanges { target: checkBox; anchors.right: delegateContent.left} + }, + State { + name: "selectable" + when: baseItem.selectable + PropertyChanges { target: checkBox; opacity: 1 } + AnchorChanges { target: checkBox; anchors.left: delegateContent.left} + AnchorChanges { target: checkBox; anchors.right: undefined} + } + ] + state: "notSelectable" + + transitions: [ + Transition { + from: "notSelectable" + to: "selectable" + reversible: true + animations: + [ + AnchorAnimation { duration: 200 }, + PropertyAnimation { target: checkBox; properties: "opacity"; duration: 200 } + ] + } + ] + } + + onMovementStarted: { + delegateItem.ListView.view.currentIndex = index + state = "moving" + requestDeletion(model.index) + } + onMovementEnded: { + var ratio = contentX / confirmDeletionRect.width + if (ratio > 0.4) { + state = "showDeleteConfirmation" + } + else { + state = "hideDeleteConfirmation" + cancelDeletion(model.index) + } + } + + state: "hideDeleteConfirmation" + states: [ + State { + name: "moving" + }, + State { + name: "showDeleteConfirmation" + PropertyChanges { target: flickable; contentX: confirmDeletionRect.width } + PropertyChanges { target: cancelDeletionMouseArea; enabled: true } + PropertyChanges { target: confirmDeletionMouseArea; enabled: true } + }, + State { + name: "hideDeleteConfirmation" + PropertyChanges { target: flickable; contentX: 0 } + PropertyChanges { target: cancelDeletionMouseArea; enabled: false } + PropertyChanges { target: confirmDeletionMouseArea; enabled: false } + } + ] + Behavior on contentX { + NumberAnimation { duration: 500; easing.type: Easing.OutQuart } + } + } + } + + removeDisplaced: Transition { + NumberAnimation { properties: "y"; duration: 500; easing.type: Easing.OutQuart } + } + } + + MouseArea { + id: cancelDeletionMouseArea + enabled: false + anchors.fill: parent + onClicked: cancelDeletion() + } + + MouseArea { + id: confirmDeletionMouseArea + enabled: false + width: listView.currentItem ? listView.currentItem.width / 4 : 0 + height: listView.currentItem ? listView.currentItem.height : 0 + x: listView.currentItem ? listView.currentItem.width - width : 0 + y: listView.currentItem ? listView.currentItem.y - listView.contentY : 0 + onClicked: performDeletion() + } +} diff --git a/resources/qml/Governikus/HistoryView/HistoryListViewDelegate.qml b/resources/qml/Governikus/HistoryView/HistoryListViewDelegate.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryListViewDelegate.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/HistoryView/HistoryListViewDelegateContent.qml b/resources/qml/Governikus/HistoryView/HistoryListViewDelegateContent.qml new file mode 100644 index 0000000..2e483ce --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryListViewDelegateContent.qml @@ -0,0 +1,119 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + +Item { + id: baseItem + + property bool showDetail: false + property var listModel + + Rectangle { + id: background + color: "white" + 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 { + id: purposeObject + anchors.verticalCenter: parent.verticalCenter + anchors.left: showDetail ? parent.left : categoryImage.right + anchors.leftMargin: showDetail ? 0 : Utils.dp(15) + anchors.right: deleteButton.left + + Column { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + + spacing: Constants.history_delegate_spacing + + Text { + id: dateTimeText + + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.label_font_size + font.capitalization: Font.AllUppercase + color: Constants.blue + text: (!historyModelItem ? "" : + Utils.isToday(historyModelItem.dateTime) ? qsTr("today") : + Utils.isYesterday(historyModelItem.dateTime) ? qsTr("yesterday") : + Utils.isThisWeek(historyModelItem.dateTime) ? historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) : + historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")) + ) + settingsModel.translationTrigger + } + Text { + id: subjectText + + anchors.left: parent.left + anchors.right: parent.right + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.label_font_size + wrapMode: Text.WordWrap + text: historyModelItem ? historyModelItem.subject : "" + } + Text { + id: purposeText + + anchors.left: parent.left + anchors.right: parent.right + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.small_font_size + color: Constants.history_delegate_address_color + wrapMode: Text.WordWrap + text: historyModelItem ? !!historyModelItem.purpose ? historyModelItem.purpose : qsTr("Tap for more details") + settingsModel.translationTrigger : "" + } + } + } + + Image { + height: Utils.dp(35) + source: "qrc:///images/android/arrowRight.svg" + anchors.right: parent.right + anchors.verticalCenter: purposeObject.verticalCenter + anchors.rightMargin: Utils.dp(2) + fillMode: Image.PreserveAspectFit + } + + MouseArea { + anchors.fill: parent + onClicked: firePush(detailsHistoryView, { historyModelItem: historyModelItem }) + } + + MouseArea { + id: deleteButton + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: Utils.dp(5) + height: parent.height * 0.3 + width: height + visible: PlatformConstants.is_layout_ios ? false : true + + onClicked: { + if (typeof(listModel) === "object") { + listModel.removeRows(historyModelItem ? historyModelItem.index : -1, 1) + } + } + + Image { + height: Utils.dp(21) + anchors.right: parent.right + anchors.top: parent.top + source: "qrc:///images/trash_icon.svg" + fillMode: Image.PreserveAspectFit + } + } + } +} diff --git a/resources/qml/Governikus/HistoryView/HistoryView.qml b/resources/qml/Governikus/HistoryView/HistoryView.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryView.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/HistoryView/HistoryViewBackground.qml b/resources/qml/Governikus/HistoryView/HistoryViewBackground.qml new file mode 100644 index 0000000..8c98b2d --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryViewBackground.qml @@ -0,0 +1,15 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Rectangle { + id: redLine + height: parent.height + width: Utils.dp(2) + + anchors.left: parent.left + anchors.leftMargin: Utils.dp(30) + + color: "red" + opacity: 0.05 +} diff --git a/resources/qml/Governikus/HistoryView/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/HistoryViewDetails.qml new file mode 100644 index 0000000..886a819 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryViewDetails.qml @@ -0,0 +1,66 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: root + property var historyModelItem + + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: historyModelItem ? historyModelItem.subject : ""; font.bold: true } + titleBarColor: Category.displayColor(historyModelItem ? historyModelItem.providerCategory : "") + + content: Item { + height: pane.height + 2 * Constants.component_spacing + width: root.width + + Column { + anchors.fill: parent + anchors.margins: Constants.component_spacing + + Pane { + id: pane + title: qsTr("Provider Information") + settingsModel.translationTrigger + + LabeledText { + label: qsTr("Provider name") + settingsModel.translationTrigger + text: historyModelItem ? historyModelItem.subject : "" + width: parent.width + } + + LabeledText { + label: qsTr("Purpose") + settingsModel.translationTrigger + text: historyModelItem ? historyModelItem.purpose : "" + width: parent.width + } + + LabeledText { + label: qsTr("Date") + settingsModel.translationTrigger + text:{ + if (!historyModelItem) { + return ""; + } + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")) + settingsModel.translationTrigger + } + width: parent.width + fontUppercase: Font.AllUppercase + } + + LabeledText { + label: qsTr("Requested data") + settingsModel.translationTrigger + text: historyModelItem ? historyModelItem.requestedData : "" + width: parent.width + } + + LabeledText { + label: qsTr("Terms of usage") + settingsModel.translationTrigger + text: historyModelItem ? historyModelItem.termsOfUsage : "" + width: parent.width + } + } + } + } +} diff --git a/resources/qml/Governikus/HistoryView/HistoryViewPage.qml b/resources/qml/Governikus/HistoryView/HistoryViewPage.qml new file mode 100644 index 0000000..468b25c --- /dev/null +++ b/resources/qml/Governikus/HistoryView/HistoryViewPage.qml @@ -0,0 +1,84 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + property var historyModelItem + readonly property real headerHeight: Utils.dp(200) + ProviderModelItem { + id: provider + modelItem: baseItem.historyModelItem + } + + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: historyModelItem ? historyModelItem.subject : ""; font.bold: true } + titleBarColor: !!provider.category ? Category.displayColor(provider.category) : "" + + + header: ProviderHeader { + id: providerHeader + width: baseItem.width + selectedProvider: provider + } + + content: Item { + height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing + width: baseItem.width + + CustomSwipeBar { + id: swipeBar + currentIndex: swipeView.currentIndex + anchors.top: parent.top + anchors.topMargin: Utils.dp(20) + } + + Rectangle { + id: swipeViewBackground + anchors.top: swipeBar.bottom + anchors.horizontalCenter: swipeBar.horizontalCenter + height: swipeView.height + 2 * Constants.component_spacing + width: parent.width + + 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 + + currentIndex: swipeBar.currentIndex + clip: true + + ProviderContactTab { + id: providerInfo + contactModel: provider.contactModel + } + + HistoryListView { + id: detailsHistoryListView + interactive: false + deletable: false + + 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/Governikus/HistoryView/IosCheckBoxStyle.qml b/resources/qml/Governikus/HistoryView/IosCheckBoxStyle.qml new file mode 100644 index 0000000..d873418 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/IosCheckBoxStyle.qml @@ -0,0 +1,37 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + +CheckBoxStyle { + id: style + spacing: 0 + + indicator: Component { + Rectangle { + id: rectangle + implicitWidth: control.width + implicitHeight: control.height + color: Constants.background_color + + Rectangle { + anchors.centerIn: parent + height: Utils.dp(radius * 2 + border.width * 2) + width: height + radius: 8 + border.color: control.activeFocus ? Constants.blue : Constants.grey + border.width: 1 + color: style.control.parent.color ? style.control.parent.color : "white" + + Rectangle { + visible: control.checked + color: Constants.blue + border.color: "#333" + radius: parent.radius + anchors.fill: parent + } + } + } + } +} diff --git a/resources/qml/Governikus/HistoryView/qmldir b/resources/qml/Governikus/HistoryView/qmldir new file mode 100644 index 0000000..47e86b6 --- /dev/null +++ b/resources/qml/Governikus/HistoryView/qmldir @@ -0,0 +1,2 @@ +module HistoryView +HistoryView 1.0 HistoryView.qml diff --git a/resources/qml/Governikus/IdentifyView/+android/+tablet/IdentifyViewContent.qml b/resources/qml/Governikus/IdentifyView/+android/+tablet/IdentifyViewContent.qml new file mode 100644 index 0000000..1efe4ed --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+android/+tablet/IdentifyViewContent.qml @@ -0,0 +1,157 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Item { + id: root + height: infoPane.height + 2 * Constants.component_spacing + + Column { + id: infoPane + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + + spacing: Constants.pane_spacing + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("You are about to identify yourself towards the following service provider:") + settingsModel.translationTrigger + } + + Pane { + + 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") + settingsModel.translationTrigger + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + name: certificateDescriptionModel.purpose + } + } + + MouseArea { + anchors.fill: parent + onClicked: firePush(certificateDescriptionPage, {}) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false + } + } + + + Item { + height: parent.height + width: (parent.width - Constants.pane_spacing) / 2 + + GButton { + id: button + iconSource: "qrc:///images/npa.svg" + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + buttonColor: applicationModel.currentWorkflow === "" && settingsModel.useSelfauthenticationTestUri ? Constants.red : Constants.blue + + text: qsTr("Identify now") + settingsModel.translationTrigger + onClicked: { + if (applicationModel.currentWorkflow === "") { + selfAuthenticationModel.startWorkflow(); + } + else if (applicationModel.currentWorkflow === "authentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + } + } + } + } + } + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("The following data will be transferred to the service provider when you enter the PIN:") + settingsModel.translationTrigger + } + + Pane { + Column { + height: childrenRect.height + width: parent.width + spacing: Utils.dp(30) + + Column { + id: transactionInfo + + width: parent.width + visible: !!transactionInfoText.text + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: qsTr("Transactional information") + settingsModel.translationTrigger + 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") + settingsModel.translationTrigger + columns: optionalData.visible ? 2 : 3 + chat: chatModel.required + } + + DataGroup { + id: optionalData + width: parent.width * 0.37 - Constants.pane_spacing + + title: qsTr("Optional Data") + settingsModel.translationTrigger + chat: chatModel.optional + } + } + } + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/+android/DataGroup.qml b/resources/qml/Governikus/IdentifyView/+android/DataGroup.qml new file mode 100644 index 0000000..f272be0 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+android/DataGroup.qml @@ -0,0 +1,114 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + + +Rectangle { + id: root + property string title; + property int columns: 1 + property var chat + + width: parent.width + height: column.height + visible: repeater.count > 0 + + Column { + id: column + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: title + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } + + Rectangle { + width: parent.width + height: Utils.dp(40) + visible: repeater.count < 1 + Text { + id: emptyText + anchors.verticalCenter: parent.verticalCenter + width: parent.width + font.pixelSize: Constants.normal_font_size + text: qsTr("No data requested") + settingsModel.translationTrigger + } + Rectangle { + anchors.top: parent.bottom + anchors.topMargin: -height + height: 1 + width: parent.width + color: Constants.grey + } + } + + 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: (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 + } + + Rectangle { + 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/Governikus/IdentifyView/+android/IdentifyViewContent.qml b/resources/qml/Governikus/IdentifyView/+android/IdentifyViewContent.qml new file mode 100644 index 0000000..94d14cd --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+android/IdentifyViewContent.qml @@ -0,0 +1,135 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Item { + height: identifycolumn.height + Utils.dp(30) + + Column { + id: identifycolumn + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + + spacing: Constants.component_spacing + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("You are about to identify yourself towards the following service provider:") + settingsModel.translationTrigger + } + + Pane { + + Item { + width: parent.width + height: providerEntries.height + + 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") + settingsModel.translationTrigger + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + name: certificateDescriptionModel.purpose + } + } + + 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: firePush(certificateDescriptionPage, {}) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false + } + } + } + + GButton { + iconSource: "qrc:///images/npa.svg" + anchors.horizontalCenter: parent.horizontalCenter + buttonColor: applicationModel.currentWorkflow === "" && settingsModel.useSelfauthenticationTestUri ? Constants.red : Constants.blue + text: qsTr("Identify now") + settingsModel.translationTrigger; + onClicked: { + if (applicationModel.currentWorkflow === "") { + selfAuthenticationModel.startWorkflow(); + } + else if (applicationModel.currentWorkflow === "authentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + } + } + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("The following data will be transferred to the service provider when you enter the PIN:") + settingsModel.translationTrigger + } + + Pane { + width: parent.width + + Column { + id: transactionInfo + + width: parent.width + visible: !!transactionInfoText.text + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: qsTr("Transactional information") + settingsModel.translationTrigger + 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") + settingsModel.translationTrigger + chat: chatModel.required + } + + DataGroup { + title: qsTr("Optional Data") + settingsModel.translationTrigger + chat: chatModel.optional + } + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/+ios/+tablet/DataGroup.qml b/resources/qml/Governikus/IdentifyView/+ios/+tablet/DataGroup.qml new file mode 100644 index 0000000..f272be0 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+ios/+tablet/DataGroup.qml @@ -0,0 +1,114 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + + +Rectangle { + id: root + property string title; + property int columns: 1 + property var chat + + width: parent.width + height: column.height + visible: repeater.count > 0 + + Column { + id: column + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: title + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } + + Rectangle { + width: parent.width + height: Utils.dp(40) + visible: repeater.count < 1 + Text { + id: emptyText + anchors.verticalCenter: parent.verticalCenter + width: parent.width + font.pixelSize: Constants.normal_font_size + text: qsTr("No data requested") + settingsModel.translationTrigger + } + Rectangle { + anchors.top: parent.bottom + anchors.topMargin: -height + height: 1 + width: parent.width + color: Constants.grey + } + } + + 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: (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 + } + + Rectangle { + 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/Governikus/IdentifyView/+ios/+tablet/IdentifyViewContent.qml b/resources/qml/Governikus/IdentifyView/+ios/+tablet/IdentifyViewContent.qml new file mode 100644 index 0000000..f22afb3 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+ios/+tablet/IdentifyViewContent.qml @@ -0,0 +1,150 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Item { + height: identifycolumn.height + Utils.dp(30) + + Column { + id: identifycolumn + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + + spacing: Constants.component_spacing + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("You are about to identify yourself towards the following service provider:") + settingsModel.translationTrigger + } + + Pane { + + Item { + width: parent.width + height: providerEntries.height + + 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") + settingsModel.translationTrigger + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + name: certificateDescriptionModel.purpose + } + } + + 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: firePush(certificateDescriptionPage, {}) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false + } + } + } + + GButton { + anchors.horizontalCenter: parent.horizontalCenter + buttonColor: applicationModel.currentWorkflow === "" && settingsModel.useSelfauthenticationTestUri ? Constants.red : Constants.blue + text: qsTr("Identify now") + settingsModel.translationTrigger; + onClicked: { + if (applicationModel.currentWorkflow === "") { + selfAuthenticationModel.startWorkflow(); + } + else if (applicationModel.currentWorkflow === "authentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + } + } + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("The following data will be transferred to the service provider when you enter the PIN:") + settingsModel.translationTrigger + } + + Pane { + Column { + height: childrenRect.height + width: parent.width + spacing: Utils.dp(30) + + Column { + id: transactionInfo + + width: parent.width + visible: !!transactionInfoText.text + + Text { + height: implicitHeight * 1.5 + verticalAlignment: Text.AlignTop + text: qsTr("Transactional information") + settingsModel.translationTrigger + 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") + settingsModel.translationTrigger + columns: optionalData.visible ? 2 : 3 + chat: chatModel.required + } + + DataGroup { + id: optionalData + width: parent.width * 0.37 - Constants.pane_spacing + + title: qsTr("Optional Data") + settingsModel.translationTrigger + chat: chatModel.optional + } + } + } + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/+ios/DataGroup.qml b/resources/qml/Governikus/IdentifyView/+ios/DataGroup.qml new file mode 100644 index 0000000..7d659c2 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+ios/DataGroup.qml @@ -0,0 +1,65 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + + +Pane { + property alias chat: repeater.model + + id: pane + spacing: 0 + visible: repeater.count > 0 + anchors.topMargin: Constants.component_spacing + anchors.top: header.bottom + + Repeater { + id: repeater + + Rectangle { + width: parent.width + height: Utils.dp(40) + radius: 3 + color: "white" + Text { + id: dataGroup + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.right: checkBox.left + width: parent.width + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + text: name + } + Rectangle { + anchors.top: parent.bottom + anchors.topMargin: -height + height: 1 + anchors.left: dataGroup.left + anchors.right: dataGroup.right + 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.fill: parent + color: Constants.grey + opacity: parent.pressed ? 0.5 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + } + } + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewContent.qml b/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewContent.qml new file mode 100644 index 0000000..65b2cfb --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewContent.qml @@ -0,0 +1,120 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Item { + height: identifycolumn.height + Utils.dp(30) + + Column { + id: identifycolumn + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + + spacing: Constants.component_spacing + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("You are about to identify yourself towards the following service provider:") + settingsModel.translationTrigger + } + + Pane { + + Item { + width: parent.width + height: providerEntries.height + + 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") + settingsModel.translationTrigger + name: certificateDescriptionModel.subjectName + } + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + name: certificateDescriptionModel.purpose + } + } + + 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: firePush(certificateDescriptionPage, {}) + } + + CertificateDescriptionPage { + id: certificateDescriptionPage + name: certificateDescriptionModel.subjectName + visible: false + } + } + } + + GButton { + anchors.horizontalCenter: parent.horizontalCenter + buttonColor: applicationModel.currentWorkflow === "" && settingsModel.useSelfauthenticationTestUri ? Constants.red : Constants.blue + text: qsTr("Identify now") + settingsModel.translationTrigger; + onClicked: { + if (applicationModel.currentWorkflow === "") { + selfAuthenticationModel.startWorkflow(); + } + else if (applicationModel.currentWorkflow === "authentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + } + } + + Text { + font.pixelSize: Constants.normal_font_size + width: parent.width + wrapMode: Text.WordWrap + text: qsTr("The following data will be transferred to the service provider when you enter the PIN:") + settingsModel.translationTrigger + } + + Pane { + id: transactionInfo + title: qsTr("Transactional information") + settingsModel.translationTrigger + visible: !!transactionInfoText.text + + Text { + id: transactionInfoText + + width: parent.width + font.pixelSize: Constants.normal_font_size + text: authModel.transactionInfo + wrapMode: Text.WordWrap + } + } + + DataGroup { + title: qsTr("Required Data") + settingsModel.translationTrigger + chat: chatModel.required + } + + DataGroup { + title: qsTr("Optional Data") + settingsModel.translationTrigger + chat: chatModel.optional + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewHeader.qml b/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewHeader.qml new file mode 100644 index 0000000..62ae188 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/+ios/IdentifyViewHeader.qml @@ -0,0 +1,97 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + + +Item { + id: header + /* this is interpreted by the SectionPage component */ + readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : 0 + + Image { + id: dna + width: parent.width + source: "qrc:///images/iOS/Header-Ausweisapp@3x.png" + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: (parent.height - 2 * Constants.titlebar_height) * transition() + + function transition() { + return Math.min(1, contentY / Constants.titlebar_height) + } + + Rectangle { + id: shadow + anchors.fill: parent + color: Constants.blue + opacity: Math.min(1, 0.5 + parent.transition() * 0.5) + } + } + + Item { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: information.top + + LocationButton { + id: lang_de + + language: "de" + name: "DE" + image: "qrc:///images/location_flag_de.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: lang_en.left + } + + LocationButton { + id: lang_en + + language: "en" + name: "EN" + image: "qrc:///images/location_flag_en.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: parent.right + } + } + + Item { + id: information + height: Math.max(npa.height, text.height) + anchors.margins: Constants.component_spacing + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + Image { + id: npa + anchors.left: parent.left + anchors.verticalCenter: information.verticalCenter + + height: Utils.dp(60) + width: height + source: "qrc:///images/npa.svg" + } + Text { + id: text + anchors.verticalCenter: npa.verticalCenter + anchors.left: npa.right + 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) + ) + settingsModel.translationTrigger + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/CertificateDescriptionPage.qml b/resources/qml/Governikus/IdentifyView/CertificateDescriptionPage.qml new file mode 100644 index 0000000..d8e89a8 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/CertificateDescriptionPage.qml @@ -0,0 +1,54 @@ +import QtQml.Models 2.2 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage +{ + id: root + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: name; font.bold: true } + + property string name + + content: Item + { + height: pane.height + 2 * Constants.component_spacing + width: root.width + + Column + { + anchors.fill: parent + anchors.margins: Constants.component_spacing + + Pane { + id: pane + + Text { + height: implicitHeight * 2 + verticalAlignment: Text.AlignVCenter + text: qsTr("Provider Information") + settingsModel.translationTrigger + color: Constants.blue + font.pixelSize: Constants.header_font_size + elide: Text.ElideRight + } + + 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/Governikus/IdentifyView/DataGroup.qml b/resources/qml/Governikus/IdentifyView/DataGroup.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/DataGroup.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/IdentifyView/IdentifyController.qml b/resources/qml/Governikus/IdentifyView/IdentifyController.qml new file mode 100644 index 0000000..876cc8e --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/IdentifyController.qml @@ -0,0 +1,149 @@ +import QtQuick 2.5 + + +Item { + id: controller + readonly property string currentState: authModel.currentState + property bool showRemoveCardFeedback: false + + property bool locationPermissionConfirmed: false + onLocationPermissionConfirmedChanged: { + // If the user has given location permission: continue Bluetooth workflow. + if (authModel.readerPlugInType === "BLUETOOTH" && applicationModel.bluetoothEnabled && applicationModel.locationPermissionRequired && locationPermissionConfirmed) { + numberModel.continueWorkflow() + } + } + + states: [ + State { + when: authModel.currentState === "StateGetTcToken" && !connectivityManager.networkInterfaceActive + StateChangeScript { + script: firePush(checkConnectivityView, {}) + } + }, + State { + when: authModel.currentState === "StateGetTcToken" && connectivityManager.networkInterfaceActive + StateChangeScript { + script: { + firePush(identifyProgressView, {}) + numberModel.continueWorkflow() + } + } + } + ] + + Component.onCompleted: if (authModel.currentState === "StateProcessing") processStateChange() + + Connections { + target: authModel + onFireCurrentStateChanged: processStateChange() + // This is necessary because onCurrentStateChanged is not + // working, when we need to process a state a second time + } + + function processStateChange() { + switch (authModel.currentState) { + case "": + break; + case "StateGetTcToken": + enterPinView.state = "INITIAL" + identifyWorkflow.state = "initial" + navBar.lockedAndHidden = true + navBar.state = "identify" + navBar.currentIndex = 0 + break + case "StateEditAccessRights": + if (applicationModel.currentWorkflow === "selfauthentication") { + chatModel.transferAccessRights() + numberModel.continueWorkflow() + } + if (applicationModel.currentWorkflow === "authentication") { + firePopAll() + } + + if (Qt.platform.os === "android") { + authModel.readerPlugInType = "NFC"; + } else if (Qt.platform.os === "ios") { + authModel.readerPlugInType = "BLUETOOTH"; + } else { + authModel.readerPlugInType = "PCSC"; + } + break + case "StateSelectReader": + firePush(identifyWorkflow, {}) + if (authModel.readerPlugInType === "BLUETOOTH" && applicationModel.bluetoothEnabled && applicationModel.locationPermissionRequired && !locationPermissionConfirmed) { + // Stop the workflow here until the user has confirmed the location permission. + setIdentifyWorkflowState("reader") + } + else + { + setIdentifyWorkflowStateAndContinue("reader") + } + break + case "StateConnectCard": + setIdentifyWorkflowStateAndContinue("card") + break + case "StateHandleRetryCounter": + if (!authModel.isBasicReader) { + firePush(identifyProgressView, {}) + } + setIdentifyWorkflowStateAndContinue("updateretrycounter") + break + case "StateEstablishPaceCan": + setIdentifyWorkflowStateAndRequestInput("identify_entercan", "CAN") + break + case "StateEstablishPacePin": + setIdentifyWorkflowStateAndRequestInput("identify_enterpin", "PIN") + break + case "StateDidAuthenticateEac1": + setIdentifyWorkflowStateAndContinue("identify_processing") + 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) + firePush(identifyResult, {}) + else { + if (applicationModel.currentWorkflow === "selfauthentication") { + firePush(selfAuthenticationData, {}) + } else { + numberModel.continueWorkflow() + firePopAll() + navBar.lockedAndHidden = false + } + } + break + default: + numberModel.continueWorkflow() + } + } + + function setIdentifyWorkflowState(pState) { + identifyWorkflow.state = pState + } + + function setIdentifyWorkflowStateAndContinue(pState) { + setIdentifyWorkflowState(pState); + numberModel.continueWorkflow() + } + + function setIdentifyWorkflowStateAndRequestInput(pState, pInput) { + identifyWorkflow.state = pState + if (authModel.isBasicReader) { + firePush(enterPinView, {state: pInput}) + } else { + numberModel.continueWorkflow() + } + } +} diff --git a/resources/qml/Governikus/IdentifyView/IdentifyView.qml b/resources/qml/Governikus/IdentifyView/IdentifyView.qml new file mode 100644 index 0000000..328c663 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/IdentifyView.qml @@ -0,0 +1,98 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import Governikus.EnterPinView 1.0 +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.ProgressView 1.0 +import Governikus.ResultView 1.0 + +SectionPage +{ + id: identifyEditChatView + leftTitleBarAction: TitleBarAction { + state: applicationModel.currentWorkflow === "authentication" ? "cancel" : "" + onClicked: authModel.cancelWorkflow() + } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + + content: IdentifyViewContent { + width: identifyEditChatView.width + } + + IdentifyController { + id: identifyController + } + + SelfAuthenticationData { + id: selfAuthenticationData + visible: false + } + + IdentifyWorkflow { + id: identifyWorkflow + visible: false + } + + EnterPinView { + id: enterPinView + leftTitleBarAction: TitleBarAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger } + visible: false + + onPinEntered: { + numberModel.continueWorkflow() + firePush(identifyProgressView, {}) + } + } + + ProgressView { + id: identifyProgressView + state: identifyWorkflow.state + leftTitleBarAction: TitleBarAction { state: authModel.isBasicReader ? "cancel" : "hidden"; onClicked: authModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + visible: false + text: qsTr("Authenticate") + settingsModel.translationTrigger + subText: (!visible ? "" : + authModel.isBasicReader ? + qsTr("Please wait a moment...") : + !!numberModel.inputError ? + numberModel.inputError : + numberModel.pinDeactivated ? + qsTr("The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the online identification function.") : + (state === "updateretrycounter" || state === "identify_enterpin") ? + qsTr("Please observe the display of your card reader.") : + (state === "identify_entercan") ? + qsTr("You have entered the wrong PIN twice. Prior to 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 === "enterpuk") ? + qsTr("You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking.") : + qsTr("Please wait a moment...") + ) + settingsModel.translationTrigger + subTextColor: !authModel.isBasicReader && (numberModel.inputError || numberModel.pinDeactivated || state === "identify_entercan" || state === "enterpuk") ? "red" : "black" + } + + ProgressView { + id: checkConnectivityView + leftTitleBarAction: TitleBarAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + visible: false + text: qsTr("No network connectivity") + settingsModel.translationTrigger + subText: qsTr("Please enable the network interface or cancel the workflow.") + settingsModel.translationTrigger + subTextColor: Constants.red + } + + ResultView { + id: identifyResult + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + isError: authModel.resultString + text: authModel.resultString + onClicked: { + numberModel.continueWorkflow() + firePopAll() + navBar.lockedAndHidden = false + } + visible: false + } +} diff --git a/resources/qml/Governikus/IdentifyView/IdentifyViewContent.qml b/resources/qml/Governikus/IdentifyView/IdentifyViewContent.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/IdentifyViewContent.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/IdentifyView/IdentifyWorkflow.qml b/resources/qml/Governikus/IdentifyView/IdentifyWorkflow.qml new file mode 100644 index 0000000..fe5dda9 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/IdentifyWorkflow.qml @@ -0,0 +1,43 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Workflow 1.0 + +SectionPage +{ + id: baseItem + + leftTitleBarAction: TitleBarAction { + enabled: !(baseItem.state === "identify_enterpin" || + baseItem.state === "identify_entercan") + state: enabled ? "cancel" : "hidden" + onClicked: authModel.cancelWorkflow() + } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + + NfcWorkflow + { + anchors.fill: parent + state: parent.state + visible: authModel.readerPlugInType === "NFC" + onRequestPluginType: authModel.readerPlugInType = pReaderPlugInType; + } + + RemoteWorkflow + { + anchors.fill: parent + state: parent.state + visible: authModel.readerPlugInType === "REMOTE" || authModel.readerPlugInType === "PCSC" + onRequestPluginType: authModel.readerPlugInType = pReaderPlugInType; + } + + BluetoothWorkflow + { + anchors.fill: parent + state: parent.state + visible: authModel.readerPlugInType === "BLUETOOTH" + onRequestPluginType: authModel.readerPlugInType = pReaderPlugInType; + } +} diff --git a/resources/qml/Governikus/IdentifyView/SelfAuthenticationData.qml b/resources/qml/Governikus/IdentifyView/SelfAuthenticationData.qml new file mode 100644 index 0000000..c21b4d7 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/SelfAuthenticationData.qml @@ -0,0 +1,87 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: root + leftTitleBarAction: TitleBarAction { state: "cancel"; onClicked: root.close() } + headerTitleBarAction: TitleBarAction { text: qsTr("Identify") + settingsModel.translationTrigger; font.bold: true } + + function close() { + numberModel.continueWorkflow() + firePopAll() + navBar.lockedAndHidden = false + } + + content: Item { + height: content.height + okButton.height + Constants.component_spacing + width: root.width + + Column { + id: content + width: parent.width + padding: Constants.component_spacing + spacing: Constants.component_spacing + + 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") + settingsModel.translationTrigger + font.pixelSize: PlatformConstants.is_tablet ? Constants.header_font_size : Constants.normal_font_size + color: Constants.blue + } + } + + 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 + Repeater { + model: selfAuthenticationModel + + LabeledText { + label: name + text: value === "" ? "---" : value + width: (pane.width - 2 * Constants.pane_padding - (grid.columns - 1) * grid.spacing) / grid.columns + } + } + } + } + } + } + + GButton { + id: okButton + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Constants.component_spacing + text: qsTr("Ok") + settingsModel.translationTrigger + onClicked: root.close() + } +} diff --git a/resources/qml/Governikus/IdentifyView/qmldir b/resources/qml/Governikus/IdentifyView/qmldir new file mode 100644 index 0000000..603a937 --- /dev/null +++ b/resources/qml/Governikus/IdentifyView/qmldir @@ -0,0 +1,2 @@ +module IdentifyView +IdentifyView 1.0 IdentifyView.qml diff --git a/resources/qml/Governikus/InformationView/Information.qml b/resources/qml/Governikus/InformationView/Information.qml new file mode 100644 index 0000000..ba75629 --- /dev/null +++ b/resources/qml/Governikus/InformationView/Information.qml @@ -0,0 +1,103 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.VersionInformationView 1.0 + + +SectionPage { + id: root + headerTitleBarAction: TitleBarAction { text: qsTr("Information") + settingsModel.translationTrigger; 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?") + settingsModel.translationTrigger + 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.") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + } + + Pane { + Loader { + readonly property string titleText: qsTr("Version information") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("Here you can see detailed information about AusweisApp2.") + settingsModel.translationTrigger + function onClickFunction() { firePush(versionInformationPage, {}) } + width: parent.width + sourceComponent: subMenu + } + Loader { width: parent.width; sourceComponent: lineSeparator } + Loader { + readonly property string titleText: qsTr("Software license") + settingsModel.translationTrigger + readonly property string descriptionText: qsTr("Read the software license text on the application homepage.") + settingsModel.translationTrigger + function onClickFunction() { Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/download/")) } + width: parent.width + sourceComponent: subMenu + } + } + } + } +} diff --git a/resources/qml/Governikus/InformationView/qmldir b/resources/qml/Governikus/InformationView/qmldir new file mode 100644 index 0000000..00cf3c7 --- /dev/null +++ b/resources/qml/Governikus/InformationView/qmldir @@ -0,0 +1,2 @@ +module InformationView +Information 1.0 Information.qml diff --git a/resources/qml/Governikus/MoreView/MoreView.qml b/resources/qml/Governikus/MoreView/MoreView.qml new file mode 100644 index 0000000..ffdefce --- /dev/null +++ b/resources/qml/Governikus/MoreView/MoreView.qml @@ -0,0 +1,135 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.VersionInformationView 1.0 +import Governikus.RemoteServiceView 1.0 +import Governikus.DeveloperView 1.0 + +SectionPage { + headerTitleBarAction: TitleBarAction { text: qsTr("More") + settingsModel.translationTrigger; font.bold: true } + + + Rectangle { + anchors.fill: menu + color: "white" + } + + Column { + id: menu + width: parent.width + anchors.top: parent.top + anchors.topMargin: Constants.component_spacing + + MoreViewMenuItem { + text: qsTr("Version information") + settingsModel.translationTrigger + imageSource: "qrc:///images/npa.svg" + showRightArrow: true + onClicked: firePush(versionInformationPage, {}) + } + + MoreViewMenuItem { + text: qsTr("FAQ") + settingsModel.translationTrigger + imageSource: "qrc:///images/iOS/more/icon_mehr_info.svg" + onClicked: Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/questions-and-answers/frequently-asked-questions/")) + } + + MoreViewMenuItem { + text: qsTr("Support") + settingsModel.translationTrigger + imageSource: "qrc:///images/iOS/more/icon_mehr_fragen.svg" + onClicked: Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/questions-and-answers/support/")) + } + + MoreViewMenuItem { + text: qsTr("Rate app") + settingsModel.translationTrigger; + 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") { + Qt.openUrlExternally("market://details?id=com.governikus.ausweisapp2") + } + else if (Qt.platform.os === "ios") { + Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/questions-and-answers/evaluate-us/")) + } + } + } + + MoreViewMenuItem { + text: qsTr("Software license") + settingsModel.translationTrigger + imageSource: "qrc:///images/iOS/more/icon_mehr_license.svg" + onClicked: Qt.openUrlExternally(qsTr("https://www.ausweisapp.bund.de/en/download/")) + } + + MoreViewMenuItem { + imageSource: "qrc:///images/android/navigation/remotesettings.svg" + text: qsTr("Configure remote service") + settingsModel.translationTrigger + showRightArrow: true + onClicked: firePush(remoteServiceSettings, {}) + } + + MoreViewMenuItem { + visible: plugin.developerBuild + text: qsTr("Developer options") + settingsModel.translationTrigger + imageSource: "qrc:///images/zahnraeder.svg" + showRightArrow: true + onClicked: firePush(developerView, {}) + } + } + + Item { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + LocationButton { + id: lang_de + + language: "de" + name: "DE" + image: "qrc:///images/location_flag_de.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: lang_en.left + } + + LocationButton { + id: lang_en + + language: "en" + name: "EN" + image: "qrc:///images/location_flag_en.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: parent.right + } + } + + Rectangle { + anchors.top: menu.top + height: 1; width: parent.width + color: Constants.grey + } + Rectangle { + anchors.bottom: menu.bottom + height: 1; width: parent.width + color: Constants.grey + } + + VersionInformation { + id: versionInformationPage + visible: false + } + + RemoteServiceSettings { + id: remoteServiceSettings + visible: false + } + + DeveloperView { + id: developerView + visible: false + } +} diff --git a/resources/qml/Governikus/MoreView/MoreViewMenuItem.qml b/resources/qml/Governikus/MoreView/MoreViewMenuItem.qml new file mode 100644 index 0000000..9d4efa0 --- /dev/null +++ b/resources/qml/Governikus/MoreView/MoreViewMenuItem.qml @@ -0,0 +1,61 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + + +Item { + property alias imageSource: imageItem.source + property alias text: textItem.text + property bool showRightArrow: false + signal clicked + height: Utils.dp(40) + width: parent.width + + Image { + id: imageItem + fillMode: Image.PreserveAspectFit + height: parent.height * 0.6 + width: height + anchors.left: parent.left + anchors.leftMargin: Utils.dp(15) + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: textItem + height: parent.height + verticalAlignment: Text.AlignVCenter + anchors.left: imageItem.right + anchors.leftMargin: Utils.dp(10) + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Utils.dp(16) + } + + 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: parent.showRightArrow + } + + MouseArea { + anchors.fill: parent + onClicked: parent.clicked() + } + + Rectangle { + anchors.bottom: parent.bottom + anchors.left: textItem.left + anchors.right: parent.right + height: 1 + color: Constants.grey + } + +} + diff --git a/resources/qml/Governikus/MoreView/qmldir b/resources/qml/Governikus/MoreView/qmldir new file mode 100644 index 0000000..5a542d2 --- /dev/null +++ b/resources/qml/Governikus/MoreView/qmldir @@ -0,0 +1,2 @@ +module MoreView +MoreView 1.0 MoreView.qml diff --git a/resources/qml/Governikus/Navigation/+android/Navigation.qml b/resources/qml/Governikus/Navigation/+android/Navigation.qml new file mode 100644 index 0000000..72180c9 --- /dev/null +++ b/resources/qml/Governikus/Navigation/+android/Navigation.qml @@ -0,0 +1,84 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 + +Item { + id: navigation + state: "identify" + width: !PlatformConstants.is_tablet || lockedAndHidden ? 0 : Constants.menubar_width + + property bool lockedAndHidden: true + property bool isOpen: drawer.position > 0 + property int currentIndex: 0 + + onLockedAndHiddenChanged: { + if (lockedAndHidden) { + drawer.close() + } + } + + function open() { + if (!lockedAndHidden) { + drawer.open() + } + } + + function close() { + drawer.close() + } + + Rectangle { + visible: PlatformConstants.is_tablet + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: parent.bottom + width: Math.max(parent.width, appWindow.leftOverlayMargin); + color: Constants.background_color + clip: true + + NavigationView { + navigationController: navigation + } + + Rectangle { + id: iconBarBorder + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + width: Utils.dp(2) + color: PlatformConstants.grey_border + } + } + + Drawer { + id: drawer + topPadding: Constants.titlebar_height + height: appWindow.height + width: Utils.dp(250) + opacity: PlatformConstants.is_tablet ? 0 : 1 + background: Item { + opacity: 0 + visible: !lockedAndHidden && drawer.position > 0 + + MouseArea { + anchors.fill: parent + onClicked: drawer.close() + } + } + + dragMargin: lockedAndHidden ? 0 : Utils.dp(Qt.styleHints.startDragDistance) + + onPositionChanged: { + if (PlatformConstants.is_tablet && position > 0) { + appWindow.leftOverlayMargin = Constants.menubar_width + (width - Constants.menubar_width) * position + } else { + appWindow.leftOverlayMargin = 0 + } + } + + contentItem: NavigationView { + navigationController: navigation + } + } +} diff --git a/resources/qml/Governikus/Navigation/+android/NavigationItem.qml b/resources/qml/Governikus/Navigation/+android/NavigationItem.qml new file mode 100644 index 0000000..592a396 --- /dev/null +++ b/resources/qml/Governikus/Navigation/+android/NavigationItem.qml @@ -0,0 +1,39 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + property alias source: tabImage.source + property alias text: tabText.text + signal clicked + + Item { + id: tabImageItem + height: parent.height + width: Constants.menubar_width + anchors.left: parent.left + + Image { + id: tabImage + height: Utils.dp(35) + fillMode: Image.PreserveAspectFit + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + } + } + + Text { + id: tabText + anchors.left: tabImageItem.right + anchors.leftMargin: Utils.dp(10) + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Constants.small_font_size + renderType: Text.NativeRendering + color: "black" + } + + MouseArea { + anchors.fill: parent + onClicked: parent.clicked() + } +} diff --git a/resources/qml/Governikus/Navigation/+android/NavigationView.qml b/resources/qml/Governikus/Navigation/+android/NavigationView.qml new file mode 100644 index 0000000..de6c63b --- /dev/null +++ b/resources/qml/Governikus/Navigation/+android/NavigationView.qml @@ -0,0 +1,121 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 + +Rectangle { + id: content + height: appWindow.height - Constants.titlebar_height + width: Utils.dp(250) + color: Constants.background_color + + property var navigationController: null + + ListModel { + id: navModel + + ListElement { + image: "qrc:///images/android/navigation/ausweisen.svg" + desc: QT_TR_NOOP("Identify") + condition: "identify" + } + + ListElement { + image: "qrc:///images/android/navigation/anbieter.svg" + desc: QT_TR_NOOP("Provider") + condition: "provider" + } + + ListElement { + image: "qrc:///images/android/navigation/verlauf.svg" + desc: QT_TR_NOOP("History") + condition: "history" + } + + ListElement { + image: "qrc:///images/android/navigation/pin.svg" + desc: QT_TR_NOOP("PIN Management") + condition: "pin" + } + + ListElement { + image: "qrc:///images/android/navigation/remoteleser.svg" + desc: QT_TR_NOOP("Smartphone as card reader") + condition: "remoteservice" + } + + ListElement { + image: "qrc:///images/android/navigation/support.svg" + desc: QT_TR_NOOP("Help & Feedback") + condition: "feedback" + } + + ListElement { + image: "qrc:///images/android/navigation/faq.svg" + desc: QT_TR_NOOP("Information") + condition: "information" + } + + ListElement { + image: "qrc:///images/zahnraeder.svg" + desc: QT_TR_NOOP("Developer options") + condition: "developeroptions" + } + } + + + ListView { + id: listView + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + model: navModel + currentIndex: navigationController.currentIndex + + highlight: Rectangle { + color: "black" + opacity: 0.1 + height: Utils.dp(45) + width: content.width + y: listView.currentItem.y + } + highlightFollowsCurrentItem: false + + delegate: NavigationItem { + height: Utils.dp(45) + width: content.width + source: image + text: qsTr(desc) + settingsModel.translationTrigger + onClicked: { + navigationController.currentIndex = index + navigationController.state = condition + navigationController.close() + } + // Hide developer options if we are not using developer build (debug build) + visible: condition !== "developeroptions" || plugin.developerBuild + } + } + + LocationButton { + id: lang_de + + language: "de" + name: "DE" + image: "qrc:///images/location_flag_de.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: lang_en.left + } + + LocationButton { + id: lang_en + + language: "en" + name: "EN" + image: "qrc:///images/location_flag_en.svg" + + anchors.margins: Constants.component_spacing + anchors.bottom: parent.bottom + anchors.right: parent.right + } +} diff --git a/resources/qml/Governikus/Navigation/+ios/Navigation.qml b/resources/qml/Governikus/Navigation/+ios/Navigation.qml new file mode 100644 index 0000000..70b82e0 --- /dev/null +++ b/resources/qml/Governikus/Navigation/+ios/Navigation.qml @@ -0,0 +1,29 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + + +Item { + property bool lockedAndHidden: false + property bool isOpen: true + + id: baseItem + state: "identify" + + height: childrenRect.height + Behavior on height { + NumberAnimation {duration: 200} + } + + + function open() { + } + + function close() { + } + + NavigationView { + visible: !baseItem.lockedAndHidden + height: visible ? Constants.tabbar_height : 0 + } +} diff --git a/resources/qml/Governikus/Navigation/+ios/NavigationItem.qml b/resources/qml/Governikus/Navigation/+ios/NavigationItem.qml new file mode 100644 index 0000000..f5b07bc --- /dev/null +++ b/resources/qml/Governikus/Navigation/+ios/NavigationItem.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + property alias source: tabImage.source + property alias text: tabText.text + property alias textColor: tabText.color + signal clicked + + Image { + id: tabImage + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 5 + anchors.top: parent.top + anchors.bottom: tabText.top + fillMode: Image.PreserveAspectFit + } + + Text { + id: tabText + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: font.pixelSize / 10 + font.pixelSize: Constants.small_font_size + renderType: Text.NativeRendering + } + + MouseArea { + anchors.fill: parent + onClicked: parent.clicked() + } +} diff --git a/resources/qml/Governikus/Navigation/+ios/NavigationView.qml b/resources/qml/Governikus/Navigation/+ios/NavigationView.qml new file mode 100644 index 0000000..d1467fa --- /dev/null +++ b/resources/qml/Governikus/Navigation/+ios/NavigationView.qml @@ -0,0 +1,78 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + + +Rectangle { + id: content + height: parent.height + width: parent.width + color: Constants.background_color + + ListModel { + id: navModel + + ListElement { + imageOn: "qrc:///images/iOS/tabBar/Ausweisen-on.png" + imageOff: "qrc:///images/iOS/tabBar/Ausweisen-off.png" + desc: QT_TR_NOOP("Identify") + condition: "identify" + } + + ListElement { + imageOn: "qrc:///images/iOS/tabBar/Anbieter-on.png" + imageOff: "qrc:///images/iOS/tabBar/Anbieter-off.png" + desc: QT_TR_NOOP("Provider") + condition: "provider" + } + + ListElement { + imageOn: "qrc:///images/iOS/tabBar/Verlauf-on.png" + imageOff: "qrc:///images/iOS/tabBar/Verlauf-off.png" + desc: QT_TR_NOOP("History") + condition: "history" + } + + ListElement { + imageOn: "qrc:///images/iOS/tabBar/Pin-on.png" + imageOff: "qrc:///images/iOS/tabBar/Pin-off.png" + desc: QT_TR_NOOP("PIN Management") + condition: "pin" + } + + ListElement { + imageOn: "qrc:///images/iOS/tabBar/More-on.svg" + imageOff: "qrc:///images/iOS/tabBar/More-off.svg" + desc: QT_TR_NOOP("More") + condition: "more" + } + } + + Rectangle { + id: topBorderLine + width: parent.width + height: Utils.dp(0.5) + color: Constants.grey + } + + Row { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: topBorderLine.bottom + + Repeater { + id: repeater + model: navModel + + delegate: NavigationItem { + height: parent.height + width: parent.width / navModel.count + source: baseItem.state === condition ? imageOn : imageOff + textColor: baseItem.state === condition ? Constants.blue : Constants.grey + text: qsTr(desc) + settingsModel.translationTrigger + onClicked: baseItem.state = condition + } + } + } +} diff --git a/resources/qml/Governikus/Navigation/Navigation.qml b/resources/qml/Governikus/Navigation/Navigation.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Navigation/Navigation.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Navigation/NavigationItem.qml b/resources/qml/Governikus/Navigation/NavigationItem.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Navigation/NavigationItem.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Navigation/NavigationView.qml b/resources/qml/Governikus/Navigation/NavigationView.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Navigation/NavigationView.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Navigation/qmldir b/resources/qml/Governikus/Navigation/qmldir new file mode 100644 index 0000000..5be0692 --- /dev/null +++ b/resources/qml/Governikus/Navigation/qmldir @@ -0,0 +1,2 @@ +module Navigation +Navigation 1.0 Navigation.qml diff --git a/resources/qml/Governikus/PinView/+android/PinViewContent.qml b/resources/qml/Governikus/PinView/+android/PinViewContent.qml new file mode 100644 index 0000000..4bd015a --- /dev/null +++ b/resources/qml/Governikus/PinView/+android/PinViewContent.qml @@ -0,0 +1,62 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + + +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.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" + } + + Text { + id: pinHeader + + text: qsTr("PIN Management") + settingsModel.translationTrigger + + anchors.top: pinIcon.bottom + anchors.topMargin: spacing + anchors.horizontalCenter: parent.horizontalCenter + + font.pixelSize: Constants.header_font_size + color: Constants.blue + } + + Text { + id: pinDesc + + anchors.margins: Utils.dp(10) + anchors.top: pinHeader.bottom + anchors.topMargin: Utils.dp(10) + anchors.horizontalCenter: parent.horizontalCenter + + 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.") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignHCenter + width: parent.width - Utils.dp(60) + wrapMode: Text.WordWrap + } + + GButton { + id: govButton + + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: Utils.dp(30) + + text: qsTr("Change PIN now") + settingsModel.translationTrigger + onClicked: changePinModel.startWorkflow() + } +} diff --git a/resources/qml/Governikus/PinView/+ios/PinViewContent.qml b/resources/qml/Governikus/PinView/+ios/PinViewContent.qml new file mode 100644 index 0000000..66cb5b9 --- /dev/null +++ b/resources/qml/Governikus/PinView/+ios/PinViewContent.qml @@ -0,0 +1,62 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + + +Item { + readonly property int spacing: (height - pinHeader.height - pinDesc.height - pinIcon.height - govButton.height - Utils.dp(40)) / 3 + + Text { + id: pinHeader + + text: qsTr("PIN Management") + settingsModel.translationTrigger + + anchors.top: parent.top + anchors.topMargin: spacing + anchors.horizontalCenter: parent.horizontalCenter + + font.pixelSize: Constants.header_font_size + color: Constants.blue + } + + Text { + id: pinDesc + + width: parent.width * 0.9 + + 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.") + settingsModel.translationTrigger + 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 + } + + Image { + id: pinIcon + + height: parent.height * 0.25 + width: height + + anchors.top: pinDesc.bottom + anchors.topMargin: spacing + anchors.horizontalCenter: parent.horizontalCenter + + fillMode: Image.PreserveAspectFit + smooth: true + source: "qrc:///images/icon_Pin.svg" + } + + GButton { + id: govButton + + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: Utils.dp(30) + + text: qsTr("Change PIN now") + settingsModel.translationTrigger + onClicked: changePinModel.startWorkflow() + } +} diff --git a/resources/qml/Governikus/PinView/ChangePinController.qml b/resources/qml/Governikus/PinView/ChangePinController.qml new file mode 100644 index 0000000..7898f10 --- /dev/null +++ b/resources/qml/Governikus/PinView/ChangePinController.qml @@ -0,0 +1,114 @@ +import QtQuick 2.5 + +Item { + id: controller + readonly property string currentState: changePinModel.currentState + property bool showRemoveCardFeedback: false + + property bool locationPermissionConfirmed: false + onLocationPermissionConfirmedChanged: { + // If the user has given location permission: continue Bluetooth workflow. + if (changePinModel.readerPlugInType === "BLUETOOTH" && applicationModel.bluetoothEnabled && applicationModel.locationPermissionRequired && locationPermissionConfirmed) { + numberModel.continueWorkflow() + } + } + + Connections { + target: changePinModel + + onFireNewContextSet: { + if (pinView.stack.currentItem !== pinWorkflow) + { + baseItem.firePopAll() + baseItem.firePush(pinWorkflow, {}) + + if (Qt.platform.os === "android") { + changePinModel.readerPlugInType = "NFC" + } else if (Qt.platform.os === "ios") { + changePinModel.readerPlugInType = "BLUETOOTH" + } else { + changePinModel.readerPlugInType = "PCSC" + } + } + + navBar.lockedAndHidden = true + enterPinView.state = "INITIAL" + setPinWorkflowState("initial") + } + + onFireCurrentStateChanged: processStateChange() + // This is necessary because onCurrentStateChanged is not + // working, when we need to process a state a second time + } + + function processStateChange() { + switch (changePinModel.currentState) { + case "": + break + case "StateSelectReader": + firePush(pinWorkflow, {}) + if (changePinModel.readerPlugInType === "BLUETOOTH" && applicationModel.bluetoothEnabled && applicationModel.locationPermissionRequired && !locationPermissionConfirmed) { + // Stop the workflow here until the user has confirmed the location permission. + setPinWorkflowState("reader") + } + else + { + setPinWorkflowStateAndContinue("reader") + } + break + case "StateConnectCard": + setPinWorkflowStateAndContinue("card") + break + case "StateHandleRetryCounter": + if (!changePinModel.isBasicReader) { + firePush(pinProgressView, {}) + } + setPinWorkflowStateAndContinue("updateretrycounter") + break + case "StateEstablishPacePuk": + setPinWorkflowStateAndRequestInput("enterpuk", "PUK") + break + case "StateEstablishPaceCan": + setPinWorkflowStateAndRequestInput("changepin_entercan", "CAN") + break + case "StateEstablishPacePin": + setPinWorkflowStateAndRequestInput("changepin_enterpin", "PIN_OR_TRANSPORT_PIN") + break + case "StateChangePin": + setPinWorkflowStateAndRequestInput("enternewpin", "PIN_NEW") + break + case "StateCleanUpReaderManager": + controller.showRemoveCardFeedback = numberModel.cardConnected && !changePinModel.error; + numberModel.continueWorkflow() + break; + case "FinalState": + if (controller.showRemoveCardFeedback) { + controller.showRemoveCardFeedback = false + qmlExtension.showFeedback(qsTr("You may now remove your ID card from the device.")) + } + baseItem.firePush(pinResult, {}) + navBar.lockedAndHidden = true + break + default: + numberModel.continueWorkflow() + } + } + + function setPinWorkflowState(pState) { + pinWorkflow.state = pState + } + + function setPinWorkflowStateAndContinue(pState) { + setPinWorkflowState(pState) + numberModel.continueWorkflow() + } + + function setPinWorkflowStateAndRequestInput(pState, pInput) { + pinWorkflow.state = pState + if (changePinModel.isBasicReader) { + baseItem.firePush(enterPinView, {state: pInput}) + } else { + numberModel.continueWorkflow() + } + } +} diff --git a/resources/qml/Governikus/PinView/PinView.qml b/resources/qml/Governikus/PinView/PinView.qml new file mode 100644 index 0000000..4c774ea --- /dev/null +++ b/resources/qml/Governikus/PinView/PinView.qml @@ -0,0 +1,83 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 +import QtQuick.Controls.Styles 1.4 + +import QtQml.StateMachine 1.0 as DSM + +import Governikus.EnterPinView 1.0 +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.ProgressView 1.0 +import Governikus.ResultView 1.0 + +SectionPage { + id: baseItem + + disableFlicking: true + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management") + settingsModel.translationTrigger; font.bold: true } + + ChangePinController { + id: changePinController + } + + content: PinViewContent { + height: baseItem.height + width: baseItem.width + } + + PinWorkflow { + id: pinWorkflow + visible: false + } + + ResultView { + id: pinResult + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management") + settingsModel.translationTrigger; font.bold: true } + isError: changePinModel.error + text: changePinModel.resultString + onClicked: { + numberModel.continueWorkflow() + firePopAll() + navBar.lockedAndHidden = false + } + visible: false + } + + EnterPinView { + id: enterPinView + leftTitleBarAction: TitleBarAction { state: "cancel"; onClicked: changePinModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("Change PIN") + settingsModel.translationTrigger } + visible: false + + onPinEntered: { + numberModel.continueWorkflow() + firePush(pinProgressView, {}) + } + } + + ProgressView { + id: pinProgressView + state: pinWorkflow.state + leftTitleBarAction: TitleBarAction { state: changePinModel.isBasicReader ? "cancel" : "hidden"; onClicked: changePinModel.cancelWorkflow() } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management") + settingsModel.translationTrigger; font.bold: true } + visible: false + text: qsTr("Change PIN") + settingsModel.translationTrigger + subText: (!visible ? "" : + changePinModel.isBasicReader ? + qsTr("Please wait a moment...") : + !!numberModel.inputError ? + numberModel.inputError : + numberModel.pinDeactivated ? + qsTr("The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the online identification function.") : + (state === "updateretrycounter" || state === "changepin_enterpin" || state === "enternewpin") ? + qsTr("Please observe the display of your card reader.") : + (state === "changepin_entercan") ? + qsTr("You have entered the wrong PIN twice. Prior to 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 === "enterpuk") ? + qsTr("You have entered a wrong PIN three times. Your PIN is now blocked. You have to enter the PUK now for unblocking.") : + qsTr("Please wait a moment...") + ) + settingsModel.translationTrigger + subTextColor: !changePinModel.isBasicReader && (numberModel.inputError || numberModel.pinDeactivated || state === "changepin_entercan" || state === "enterpuk") ? "red" : "black" + } +} diff --git a/resources/qml/Governikus/PinView/PinViewContent.qml b/resources/qml/Governikus/PinView/PinViewContent.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/PinView/PinViewContent.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/PinView/PinWorkflow.qml b/resources/qml/Governikus/PinView/PinWorkflow.qml new file mode 100644 index 0000000..6152f87 --- /dev/null +++ b/resources/qml/Governikus/PinView/PinWorkflow.qml @@ -0,0 +1,45 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Workflow 1.0 + +SectionPage +{ + id: baseItem + + leftTitleBarAction: TitleBarAction { + enabled: !(baseItem.state === "changepin_enterpin" || + baseItem.state === "changepin_entercan") + state: enabled ? "cancel" : "hidden" + onClicked: changePinModel.cancelWorkflow() + } + headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management") + settingsModel.translationTrigger; font.bold: true } + + NfcWorkflow + { + allowRemote: false + anchors.fill: parent + state: parent.state + visible: changePinModel.readerPlugInType === "NFC" + onRequestPluginType: changePinModel.readerPlugInType = pReaderPlugInType; + } + + RemoteWorkflow + { + anchors.fill: parent + state: parent.state + visible: changePinModel.readerPlugInType === "REMOTE" || changePinModel.readerPlugInType === "PCSC" + onRequestPluginType: changePinModel.readerPlugInType = pReaderPlugInType; + } + + BluetoothWorkflow + { + allowRemote: false + anchors.fill: parent + state: parent.state + visible: changePinModel.readerPlugInType === "BLUETOOTH" + onRequestPluginType: changePinModel.readerPlugInType = pReaderPlugInType; + } +} diff --git a/resources/qml/Governikus/PinView/qmldir b/resources/qml/Governikus/PinView/qmldir new file mode 100644 index 0000000..15b9514 --- /dev/null +++ b/resources/qml/Governikus/PinView/qmldir @@ -0,0 +1,2 @@ +module PinView +PinView 1.0 PinView.qml diff --git a/resources/qml/Governikus/ProgressView/ProgressView.qml b/resources/qml/Governikus/ProgressView/ProgressView.qml new file mode 100644 index 0000000..f5bdae6 --- /dev/null +++ b/resources/qml/Governikus/ProgressView/ProgressView.qml @@ -0,0 +1,51 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +SectionPage +{ + id: baseItem + property alias text: text.text + property alias subText: subText.text + property alias subTextColor: subText.color + + BusyIndicator { + id: busyIndicator + anchors.fill: circle + running: baseItem.visible + style: NpaBusyIndicatorStyle { factor: 1.2 } + } + Rectangle { + id: circle + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.top + anchors.verticalCenterOffset: PlatformConstants.is_tablet ? parent.height / 4 : parent.width / 2 + width: parent.height / 4 + height: width + radius: width / 2 + color: Constants.blue + } + Text { + id: text + anchors.top: circle.bottom + anchors.topMargin: Utils.dp(50) + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: Constants.header_font_size + font.weight: Font.Bold + color: Constants.blue + } + Text { + id: subText + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Constants.normal_font_size + anchors.top: text.bottom + anchors.topMargin: Utils.dp(10) + anchors.horizontalCenter: parent.horizontalCenter + width: baseItem.width * 0.8 + wrapMode: Text.WordWrap + } +} diff --git a/resources/qml/Governikus/ProgressView/qmldir b/resources/qml/Governikus/ProgressView/qmldir new file mode 100644 index 0000000..8ad9938 --- /dev/null +++ b/resources/qml/Governikus/ProgressView/qmldir @@ -0,0 +1,2 @@ +module ProgressView +ProgressView 1.0 ProgressView.qml diff --git a/resources/qml/Governikus/Provider/+android/ProviderDetailView.qml b/resources/qml/Governikus/Provider/+android/ProviderDetailView.qml new file mode 100644 index 0000000..f965fc3 --- /dev/null +++ b/resources/qml/Governikus/Provider/+android/ProviderDetailView.qml @@ -0,0 +1,115 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: provider.shortName } + titleBarColor: Category.displayColor(provider.category) + + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } + + + header: ProviderHeader { + id: ownHeader + width: baseItem.width + selectedProvider: provider + } + + content: Item { + height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing + width: baseItem.width + + TabBar { + id: swipeBar + height: firstButton.implicitHeight + anchors.top: parent.top + anchors.topMargin: Constants.component_spacing + anchors.left: parent.left + anchors.right: parent.right + + currentIndex: swipeView.currentIndex + + 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") + settingsModel.translationTrigger + +/* + contentItem: Text { + text: qsTr("DESCRIPTION") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + elide: Text.ElideRight + opacity: enabled ? 1 : 0.3 + color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } +*/ + } + + 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") + settingsModel.translationTrigger + +/* + contentItem: Text { + text: qsTr("CONTACT") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + elide: Text.ElideRight + opacity: enabled ? 1 : 0.3 + color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } +*/ + } + } + + Rectangle { + id: swipeViewBackground + anchors.top: swipeBar.bottom + anchors.horizontalCenter: swipeBar.horizontalCenter + height: swipeView.height + 2 * Constants.component_spacing + width: parent.width + + SwipeView { + id: swipeView + 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 { + id: providerText + text: (!!provider.longDescription ? provider.longDescription : qsTr("Description not available")) + settingsModel.translationTrigger + horizontalAlignment: Text.AlignLeft + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + } + + ProviderContactTab { + id: providerInfo + contactModel: provider.contactModel + } + } + } + } +} diff --git a/resources/qml/Governikus/Provider/+android/ProviderViewDelegate.qml b/resources/qml/Governikus/Provider/+android/ProviderViewDelegate.qml new file mode 100644 index 0000000..e32f158 --- /dev/null +++ b/resources/qml/Governikus/Provider/+android/ProviderViewDelegate.qml @@ -0,0 +1,133 @@ +import QtQml.Models 2.2 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +Rectangle { + + ProviderStyle { + id: providerStyle + } + + id: baseItem + width: parent.width + height: Constants.provider_section_height + color: Constants.background_color + clip: true + + Rectangle { + id: background + color: "white" + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: providerStyle.providerListItemRightMargin + anchors.top: parent.top + anchors.topMargin: providerStyle.providerListItemTopMargin + anchors.bottom: parent.bottom + anchors.bottomMargin: providerStyle.providerListItemBottomMargin + + Item { + property int childrenHeight: subjectText.height + addressText.height + + id: contentItem + height: Constants.provider_section_height + anchors.verticalCenter: parent.verticalCenter + + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: providerStyle.itemLeftMargin + anchors.rightMargin: Utils.dp(15) + + property int detailsLinkWidth: height / providerStyle.infoItemWidthFactor + + Text { + id: subjectText + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: detailsLink.left + + anchors.topMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 + anchors.rightMargin: Utils.dp(5) + + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.normal_font_size + color: providerStyle.subjectTextColor + font.bold: providerStyle.subjectTextFontBold + elide: Text.ElideRight + text: display + } + + Text { + id: addressText + + anchors.top: subjectText.bottom + anchors.left: parent.left + anchors.right: detailsLink.left + + anchors.topMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 + anchors.bottomMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 + + verticalAlignment: Text.AlignVCenter + font.pixelSize: providerStyle.addressTextFontSize + color: providerStyle.addressTextColor + elide: Text.ElideRight + text: providerAddressDomain + } + + Item { + id: detailsLink + anchors.right: parent.right + anchors.verticalCenter: providerStyle.providerListDetailsLinkPosition === "top" ? + subjectText.verticalCenter : + parent.verticalCenter + + anchors.margins: Utils.dp(5) + height: parent.height + width: contentItem.detailsLinkWidth + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: width + + border.color: providerStyle.providerListDetailsLinkBorder + border.width: 1 + radius: width + + color: providerStyle.providerListDetailsLinkBackground + + Text { + anchors.centerIn: parent + text: "i" + font.bold: providerStyle.providerListDetailsLinkBold + color: providerStyle.providerListDetailsLinkColor + } + } + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + firePush(providerDetailView, {providerModelItem: model}) + } + } + + Rectangle { + width: parent.width + anchors.top: parent.bottom + anchors.topMargin: -height + anchors.leftMargin: providerStyle.itemLeftMargin + anchors.left: parent.left + anchors.right: parent.right + visible: providerStyle.providerListItemsHaveBorder + height: visible ? 1 : 0 + color: Constants.grey + } +} diff --git a/resources/qml/Governikus/Provider/+ios/ProviderDetailView.qml b/resources/qml/Governikus/Provider/+ios/ProviderDetailView.qml new file mode 100644 index 0000000..142710a --- /dev/null +++ b/resources/qml/Governikus/Provider/+ios/ProviderDetailView.qml @@ -0,0 +1,118 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: provider.shortName } + titleBarColor: Category.displayColor(provider.category) + + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } + + + header: ProviderHeader { + id: ownHeader + width: baseItem.width + selectedProvider: provider + } + + content: Item { + height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing + width: baseItem.width + + Rectangle { + id: swipeBar + anchors.top: header.bottom + anchors.topMargin: Utils.dp(20) + anchors.horizontalCenter: parent.horizontalCenter + + width: descriptionTab.width + contactTab.width + 2 * border.width + height: descriptionTab.height + 2 * border.width + + border.color: Constants.blue + border.width: Utils.dp(1) + radius: Utils.dp(3) + clip: true + + Row { + id: row + readonly property int maxContentWidth: Math.max(descriptionText.contentWidth, contactText.contentWidth) + + anchors.centerIn: parent + Rectangle { + id: descriptionTab + width: row.maxContentWidth + Utils.dp(6) + height: descriptionText.contentHeight + Utils.dp(6) + color: swipeView.currentIndex === 0 ? Constants.blue : descriptiontMouseArea.pressed ? PlatformConstants.blue_light : "transparent" + Text { + id: descriptionText + anchors.centerIn: parent + color: swipeView.currentIndex === 0 ? "white" : Constants.blue + text: qsTr("Description") + settingsModel.translationTrigger + } + MouseArea { + id: descriptiontMouseArea + anchors.fill: parent + onClicked: swipeView.currentIndex = 0 + } + } + Rectangle { + id: contactTab + width: row.maxContentWidth + Utils.dp(6) + height: contactText.contentHeight + Utils.dp(6) + color: swipeView.currentIndex === 1 ? Constants.blue : contactMouseArea.pressed ? PlatformConstants.blue_light : "transparent" + Text { + id: contactText + anchors.centerIn: parent + color: swipeView.currentIndex === 1 ? "white" : Constants.blue + text: qsTr("Contact") + settingsModel.translationTrigger + } + MouseArea { + id: contactMouseArea + anchors.fill: parent + onClicked: swipeView.currentIndex = 1 + } + } + } + } + + Rectangle { + id: swipeViewBackground + anchors.top: swipeBar.bottom + anchors.horizontalCenter: swipeBar.horizontalCenter + height: swipeView.height + 2 * Constants.component_spacing + width: parent.width + + SwipeView { + id: swipeView + height: Math.max(providerText.contentHeight, providerInfo.contentHeight) + anchors.margins: Constants.component_spacing + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + clip: true + + Text { + id: providerText + text: (!!provider.longDescription ? provider.longDescription : qsTr("Description not available")) + settingsModel.translationTrigger + horizontalAlignment: Text.AlignLeft + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + } + + ProviderContactTab { + id: providerInfo + contactModel: provider.contactModel + } + } + } + } +} diff --git a/resources/qml/Governikus/Provider/+ios/ProviderViewDelegate.qml b/resources/qml/Governikus/Provider/+ios/ProviderViewDelegate.qml new file mode 100644 index 0000000..4bae152 --- /dev/null +++ b/resources/qml/Governikus/Provider/+ios/ProviderViewDelegate.qml @@ -0,0 +1,85 @@ +import QtQml.Models 2.2 +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +Rectangle { + id: baseItem + width: parent.width + height: Constants.provider_section_height + color: Constants.background_color + clip: true + + Rectangle { + id: background + color: "white" + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: Utils.dp(5) + anchors.top: parent.top + anchors.topMargin: Utils.dp(2) + anchors.bottom: parent.bottom + anchors.bottomMargin: Utils.dp(5) + + Item { + height: subjectText.height + addressText.height + anchors.verticalCenter: parent.verticalCenter + + anchors.left: parent.left + anchors.leftMargin: Utils.dp(5) + anchors.right: detailsLink.left + anchors.rightMargin: Utils.dp(15) + + Text { + id: subjectText + width: parent.width + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.normal_font_size + elide: Text.ElideRight + text: display + } + Text { + id: addressText + anchors.top: subjectText.bottom + width: parent.width + + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.small_font_size + color: PlatformConstants.blue_dark + elide: Text.ElideRight + text: providerAddressDomain + } + } + Item { + id: detailsLink + anchors.right: parent.right + anchors.margins: Utils.dp(5) + height: parent.height + width: parent.height / 2 + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: width + + border.color: PlatformConstants.blue_dark + border.width: 1 + radius: width + + Text { + anchors.centerIn: parent + text: qsTr("i") + settingsModel.translationTrigger + color: parent.border.color + } + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: firePush(providerDetailView, {providerModelItem: model}) + } +} diff --git a/resources/qml/Governikus/Provider/ProviderContactInfoItem_tablet.qml b/resources/qml/Governikus/Provider/ProviderContactInfoItem_tablet.qml new file mode 100644 index 0000000..731ad82 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderContactInfoItem_tablet.qml @@ -0,0 +1,42 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 + + +Rectangle { + id: baseItem + property alias imageSource: image.source + property alias itemText: text.text + property url link + property int sizeRecudctor: 0 + height: text.height + Utils.dp(20) + + + Image { + id: image + width: Utils.dp(25) - baseItem.sizeRecudctor + height: width + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + } + + Text { + id: text + anchors.left: image.right + anchors.leftMargin: Utils.dp(10) + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Constants.normal_font_size - baseItem.sizeRecudctor + 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/Governikus/Provider/ProviderContactInfo_tablet.qml b/resources/qml/Governikus/Provider/ProviderContactInfo_tablet.qml new file mode 100644 index 0000000..f004cf8 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderContactInfo_tablet.qml @@ -0,0 +1,66 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +Rectangle { + id: baseItem + property alias contactModel: contactListView.model + + onWidthChanged: info.resetSize() + onHeightChanged: info.resetSize() + + Column { + id: info + width: parent.width + + property int sizeRecudctor: 0 + function resetSize() { + if (childrenRect.height < baseItem.height) { + sizeRecudctor = 0 + } + } + function approximateSize() { + if (childrenRect.height > baseItem.height) { + sizeRecudctor = sizeRecudctor +1 + } + } + + onWidthChanged: info.approximateSize() + onHeightChanged: info.approximateSize() + onVisibleChanged: { info.resetSize(); info.approximateSize() } + onChildrenRectChanged: info.approximateSize() + + Text { + text: qsTr("Contact") + settingsModel.translationTrigger + padding: Constants.component_spacing + font.pixelSize: Constants.header_font_size + color: "white" + } + Rectangle { + // The delegates have space in between which is + // therefore the color of this very Rectangle. + anchors.left: parent.left + anchors.right: parent.right + height: contactListView.height + color: "white" + + ListView { + id: contactListView + width: parent.width + height: contentHeight + interactive: false + spacing: 2 + delegate: ProviderContactInfoItem_tablet { + anchors.left: parent.left + width: contactListView.width + color: baseItem.color + imageSource: Qt.resolvedUrl(model.iconSource) + itemText: (!!model.text ? model.text : qsTr("Unknown")) + settingsModel.translationTrigger + link: model.link + sizeRecudctor: info.sizeRecudctor + } + } + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderContactTab.qml b/resources/qml/Governikus/Provider/ProviderContactTab.qml new file mode 100644 index 0000000..eb2b705 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderContactTab.qml @@ -0,0 +1,62 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +Item { + id: baseItem + property alias contactModel: infoList.model + readonly property int contentHeight: infoList.contentHeight + + + ListView { + id: infoList + anchors.fill: parent + interactive: false + + delegate: Item { + id: delegateItem + width: parent.width + height: Math.max(textItem.height, Utils.dp(50)) + + Image { + id: imageItem + fillMode: Image.PreserveAspectFit + height: Utils.dp(24) + width: Utils.dp(24) + anchors.left: parent.left + anchors.leftMargin: Utils.dp(15) + anchors.verticalCenter: parent.verticalCenter + source: Qt.resolvedUrl(model.iconSource) + } + + Text { + id: textItem + text: !!model.text ? model.text : qsTr("Unknown") + settingsModel.translationTrigger + verticalAlignment: Text.AlignVCenter + anchors.left: imageItem.right + anchors.leftMargin: Utils.dp(20) + anchors.right: parent.right + anchors.rightMargin: Utils.dp(10) + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Utils.dp(16) + wrapMode: Text.WordWrap + textFormat: Text.RichText + } + + MouseArea { + anchors.fill: delegateItem + enabled: !!model.link + onClicked: Qt.openUrlExternally(model.link) + } + + Rectangle { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: 1 + color: Constants.grey + } + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailButtonBar_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailButtonBar_tablet.qml new file mode 100644 index 0000000..932e8eb --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailButtonBar_tablet.qml @@ -0,0 +1,44 @@ +import QtQuick 2.6 + +import Governikus.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 + asynchronous: true + height: 2 * baseItem.height + width: height + fillMode: Image.PreserveAspectFit + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.verticalCenter: baseItem.top + } + + GButton { + id: button + text: qsTr("ONLINE APPLICATION") + settingsModel.translationTrigger + buttonColor: baseItem.titleBarColor + maxWidth: parent.width - icon.width - 3 * Constants.component_spacing + 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/Governikus/Provider/ProviderDetailDescription_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailDescription_tablet.qml new file mode 100644 index 0000000..ac2a54e --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailDescription_tablet.qml @@ -0,0 +1,25 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 + + +Column { + id: baseItem + spacing: Constants.pane_spacing + + property string description: "" + + Text { + font.pixelSize: Constants.header_font_size + color: Constants.blue + text: qsTr("Description") + settingsModel.translationTrigger + } + + Text { + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignLeft + text: baseItem.description + width: parent.width + wrapMode: Text.Wrap + } +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailHistoryInfo_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailHistoryInfo_tablet.qml new file mode 100644 index 0000000..c5a83f2 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailHistoryInfo_tablet.qml @@ -0,0 +1,143 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Item { + id: baseItem + + property string providerName: "" + property string providerPostalAddress: "" + property string purposeText: "" + property string requestedDataText: "" + property string termsOfUsageText: "" + property string internalState: "off" + + Rectangle { + anchors.fill: baseItem + + color: "black" + opacity: 0.4 + } + + Flickable { + anchors.fill: baseItem + anchors.margins: Constants.component_spacing + contentHeight: infoRow.height + + onContentYChanged: { + if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } + + Row { + id: infoRow + height: Math.max(leftColumn.height, rightColumn.height) + 2 * Constants.pane_padding + spacing: Constants.component_spacing + + Item { + height: 1 + width: baseItem.width / 3 + + Pane { + id: leftPane + height: infoRow.height + } + + Column { + id: leftColumn + anchors.margins: Constants.pane_padding + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + spacing: Constants.pane_spacing + + ProviderInfoSection { + imageSource: "qrc:///images/provider/information.svg" + title: qsTr("Service provider") + settingsModel.translationTrigger + name: baseItem.providerName + } + + ProviderInfoSection { + imageSource: "qrc:///images/provider/purpose.svg" + title: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + name: baseItem.purposeText + } + + Text { + id: readDataTitle + width: parent.width + font.pixelSize: Constants.header_font_size + color: Constants.blue + text: qsTr("Read data") + settingsModel.translationTrigger + } + + Column { + id: infoTable + + width: parent.width + 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 + } + } + } + } + } + } + + Item { + height: 1 + width: baseItem.width / 3 * 2 - 3 * Constants.component_spacing + + Pane { + id: rightPane + height: infoRow.height + } + + Column { + id: rightColumn + anchors.margins: Constants.pane_padding + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + spacing: Constants.pane_spacing + + Text { + id: termsOfUsageTitle + text: qsTr("Terms of usage") + settingsModel.translationTrigger + font.pixelSize: Constants.header_font_size + color: Constants.blue + } + + Text { + id: termsOfUsageTextItem + + text: baseItem.termsOfUsageText + width: parent.width + elide: Text.ElideRight + wrapMode: Text.Wrap + font.pixelSize: Constants.normal_font_size + } + } + } + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailHistoryItem_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailHistoryItem_tablet.qml new file mode 100644 index 0000000..0b7d5ae --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailHistoryItem_tablet.qml @@ -0,0 +1,110 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +Item { + id: baseItem + + readonly property color backgroundColor: Constants.blue + readonly property int iconWidth: Utils.dp(18) + + property string providerName: "" + property string providerPostalAddress: "" + property var dateTime: "" + property string infoText: "" + property string purposeText: "" + property string requestedDataText: "" + property string termsOfUsageText: "" + property int itemHeight: 0 + property int itemMargin: 0 + property int lineHeight: itemHeight / 3 + property var openInfoFunction: function () {} + + height: itemHeight + 2 * itemMargin + + ProviderStyle { + id: providerStyle + + visible: false + } + + Rectangle { + anchors.fill: baseItem + color: "white" + } + + Column { + id: textColumn + + height: baseItem.itemHeight + width: baseItem.width - baseItem.iconWidth + + anchors.left: baseItem.left + anchors.top: baseItem.top + anchors.topMargin: baseItem.itemMargin + + Text { + height: baseItem.lineHeight + verticalAlignment: Text.AlignVCenter + font.pixelSize: Constants.label_font_size + font.capitalization: Font.AllUppercase + color: Constants.blue + text: (!new Date(dateTime) ? "" : + Utils.isToday(dateTime) ? qsTr("today") : + Utils.isYesterday(dateTime) ? qsTr("yesterday") : + Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) : + dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")) + ) + settingsModel.translationTrigger + } + + LabeledText { + label: !!purposeText ? purposeText : "" + text: (!!providerName ? providerName : qsTr("Touch for more details")) + settingsModel.translationTrigger + width: parent.width + height: baseItem.lineHeight + } + } + + Item { + id: detailsLink + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + height: width + width: iconWidth + + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + height: width + + border.color: providerStyle.providerListDetailsLinkBorder + border.width: 1 + radius: width + + color: providerStyle.providerListDetailsLinkBackground + Text { + anchors.centerIn: parent + + text: "i" + font.bold: providerStyle.providerListDetailsLinkBold + color: providerStyle.providerListDetailsLinkColor + } + } + } + + MouseArea { + anchors.fill: baseItem + onClicked: baseItem.openInfoFunction({ + providerName: baseItem.providerName, + providerPostalAddress: baseItem.providerPostalAddress, + purposeText: baseItem.purposeText, + requestedDataText: baseItem.requestedDataText, + termsOfUsageText: baseItem.termsOfUsageText + }) + } +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailHistory_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailHistory_tablet.qml new file mode 100644 index 0000000..dd93d9e --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailHistory_tablet.qml @@ -0,0 +1,44 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Column { + id: baseItem + spacing: Constants.pane_spacing + + property var openHistoryInfoFunc: function() { + } + + readonly property int historyItemHeight: Utils.dp(66) + readonly property int historyItemMargin: Utils.dp(8) + + Text { + id: headerText + + font.pixelSize: Constants.header_font_size + color: Constants.blue + text: qsTr("History") + settingsModel.translationTrigger + } + + Repeater { + model: historyModel.nameFilter + + ProviderDetailHistoryItem_tablet { + itemHeight: baseItem.historyItemHeight + itemMargin: baseItem.historyItemMargin + + width: parent.width + + providerName: subject + providerPostalAddress: providerPostalAddress + dateTime: model.dateTime + infoText: qsTr("Purpose for reading out requested data") + settingsModel.translationTrigger + purposeText: purpose + requestedDataText: requestedData + termsOfUsageText: termsOfUsage + + openInfoFunction: baseItem.openHistoryInfoFunc + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailView.qml b/resources/qml/Governikus/Provider/ProviderDetailView.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailView.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Provider/ProviderDetailView_tablet.qml b/resources/qml/Governikus/Provider/ProviderDetailView_tablet.qml new file mode 100644 index 0000000..b9d1382 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderDetailView_tablet.qml @@ -0,0 +1,175 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + readonly property TitleBarAction leftTitleBarAction: TitleBarAction { + state: "back" + onClicked: { + if (providerDetailsHistoryInfo.visible) { + providerDetailsHistoryInfo.visible = false + } + else { + firePop() + } + } + } + readonly property TitleBarAction headerTitleBarAction: TitleBarAction { + text: historyModelItem && historyModelItem.subject ? historyModelItem.subject : provider.shortName + font.bold: true + } + readonly property Item rightTitleBarAction: Item {} + readonly property color titleBarColor: Category.displayColor(provider.category) + readonly property real titleBarOpacity: 1 + + property alias historyModelItem: provider.modelItem + property alias providerModelItem: provider.modelItem + ProviderModelItem { + id: provider + } + + + content: Column { + id: mainContent + height: childrenRect.height + Constants.component_spacing + width: baseItem.width + + Row { + height: baseItem.height / 2 + width: parent.width + + Item { + height: parent.height + width: baseItem.width * 2 / 3 + anchors.top: parent.top + + Image { + id: image + source: provider.image + 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_tablet { + color: baseItem.titleBarColor + height: parent.height + width: baseItem.width / 3 - Constants.component_spacing + + contactModel: provider.contactModel + } + } + } + + Row { + id: lowerRow + height: Math.max(buttonBar.height + leftColumn.height, rightColumn.height) + 3 * Constants.pane_padding + width: parent.width + + Item { + height: 1 + width: lowerRow.width * 2 / 3 + + ProviderDetailButtonBar_tablet { + id: buttonBar + selectedCategory: provider.category + providerIcon: provider.icon + address: provider.address + titleBarColor: baseItem.titleBarColor + } + + Pane { + id: leftPane + anchors.margins: Constants.component_spacing + anchors.top: buttonBar.bottom + height: lowerRow.height - (buttonBar.height + Constants.pane_padding) + } + + ProviderDetailDescription_tablet { + id: leftColumn + anchors.margins: 2 * Constants.pane_padding + anchors.top: buttonBar.bottom + anchors.left: parent.left + anchors.right: parent.right + + description: provider.longDescription + } + } + + Item { + height: 1 + width: lowerRow.width / 3 - Constants.component_spacing + + Pane { + id: rightPane + anchors.topMargin: Constants.component_spacing + anchors.top: parent.top + height: lowerRow.height - Constants.pane_padding + } + + ProviderDetailHistory_tablet { + id: rightColumn + anchors.topMargin: 2 * Constants.pane_padding + anchors.leftMargin: Constants.pane_padding + anchors.rightMargin: Constants.pane_padding + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + openHistoryInfoFunc: baseItem.openHistoryInfoFunc + } + } + } + } + + 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'] + } + + ProviderDetailHistoryInfo_tablet { + id: providerDetailsHistoryInfo + + height: parent.height + width: parent.width + + anchors.top: baseItem.top + anchors.left: baseItem.left + + visible: false + } +} diff --git a/resources/qml/Governikus/Provider/ProviderHeader.qml b/resources/qml/Governikus/Provider/ProviderHeader.qml new file mode 100644 index 0000000..31c6762 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderHeader.qml @@ -0,0 +1,172 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Rectangle { + id: baseItem + + // Properties that are set by ProviderView or ProviderDetailView + property string selectedCategory: selectedProvider ? selectedProvider.category : "" + property var selectedProvider + + // This is interpreted by the SectionPage component + readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : (customProviderImage ? Math.max(0, 0.5 - shadow.opacity) : 0) + + // 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: backgroundImage + + source: baseItem.backgroundImage + height: width / 1.80 + width: parent.width + anchors.left: parent.left + anchors.top: parent.top + fillMode: Image.PreserveAspectCrop + + function transition() { + 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: 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 { + id: providerInfo + height: visible ? column.height + 2 * Constants.pane_padding : 0 + width: parent.width + anchors.left: parent.left + anchors.top: backgroundImage.bottom + + visible: !!selectedProvider + + 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 + } + + GButton { + id: providerButton + anchors.right: parent.right + buttonColor: shadowColor + text: qsTr("To service provider") + settingsModel.translationTrigger + onClicked: { + Qt.openUrlExternally(selectedProvider ? selectedProvider.address : "") + } + } + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderInfoSection.qml b/resources/qml/Governikus/Provider/ProviderInfoSection.qml new file mode 100644 index 0000000..763ee5a --- /dev/null +++ b/resources/qml/Governikus/Provider/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 Governikus.Global 1.0 + + +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") + settingsModel.translationTrigger + } +} diff --git a/resources/qml/Governikus/Provider/ProviderModelItem.qml b/resources/qml/Governikus/Provider/ProviderModelItem.qml new file mode 100644 index 0000000..9cc83e3 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderModelItem.qml @@ -0,0 +1,106 @@ +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: { + var dest + if (Qt.platform.os === "android") { + dest = 'geo:0,0?q=' + } + else if (Qt.platform.os === "ios") { + dest = 'maps:0,0?q=' + } + else { + dest = 'https://www.google.com/maps?q=' + } + + dest = !!postalAddress ? dest + encodeURIComponent(postalAddress.replace(//gi,' ')) : "" + setProperty(3, "text", !!postalAddress ? '' + postalAddress + "" : "") + setProperty(3, "link", dest) + } + + ListElement { + iconSource: "qrc:///images/provider/url.png" + label: QT_TR_NOOP("Homepage") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/mail.png" + label: QT_TR_NOOP("E-Mail") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/telefon.png" + label: QT_TR_NOOP("Phone") + text: "" + link: "" + } + + ListElement { + iconSource: "qrc:///images/provider/adresse.png" + label: QT_TR_NOOP("Contact") + text: "" + link: "" + } + } +} diff --git a/resources/qml/Governikus/Provider/ProviderViewDelegate.qml b/resources/qml/Governikus/Provider/ProviderViewDelegate.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Provider/ProviderViewDelegate.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Provider/qmldir b/resources/qml/Governikus/Provider/qmldir new file mode 100644 index 0000000..9adfe21 --- /dev/null +++ b/resources/qml/Governikus/Provider/qmldir @@ -0,0 +1,8 @@ +module ProviderInfo +ProviderInfoSection 1.0 ProviderInfoSection.qml +ProviderHeader 1.0 ProviderHeader.qml +ProviderModelItem 1.0 ProviderModelItem.qml +ProviderContactTab 1.0 ProviderContactTab.qml +ProviderDetailView 1.0 ProviderDetailView.qml +ProviderDetailView_tablet 1.0 ProviderDetailView_tablet.qml +ProviderViewDelegate 1.0 ProviderViewDelegate.qml diff --git a/resources/qml/Governikus/ProviderView/+android/+tablet/ProviderView.qml b/resources/qml/Governikus/ProviderView/+android/+tablet/ProviderView.qml new file mode 100644 index 0000000..f29f8e5 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+android/+tablet/ProviderView.qml @@ -0,0 +1,173 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Provider 1.0 + +SectionPage { + id: baseItem + + leftTitleBarAction: TitleBarAction {} + headerTitleBarAction: TitleBarAction { text: qsTr("Provider") + settingsModel.translationTrigger; font.bold: true } + rightTitleBarAction: SearchBar { + availableWidth: baseItem.width + onSearchTextChanged: providerModel.searchString = searchText + } + + titleBarColor: Constants.blue + + visible: false + property bool wasVisible: false + onVisibleChanged: wasVisible = true + + readonly property int headerHeight: Utils.dp(54) + readonly property int separatorHeight: Utils.dp(2) + + ProviderDetailView_tablet { + id: providerDetailView + visible: false + } + + function pushProviderDetails(model) { + historyModel.nameFilter.setProviderAddress(model.providerAddress) + firePush(providerDetailView, {providerModelItem: model}) + } + + Column { + id: content + + width: parent.width + + Rectangle { + + height: baseItem.headerHeight + width: parent.width + + color: "white" + + Row { + id: checkBoxesItem + + height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + padding: Utils.dp(30) + spacing: Utils.dp(30) + + transformOrigin: Item.Center + scale: Math.min(parent.width / width, 1) + + CategoryCheckbox_tablet { + id: checkBoxCitizen + + category: "citizen" + imageSource: Category.imageSource("citizen") + text: qsTr("Citizen services") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxFinance + + category: "finance" + imageSource: Category.imageSource("finance") + text: qsTr("Financials") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxInsurance + + category: "insurance" + imageSource: Category.imageSource("insurance") + text: qsTr("Insurances") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxOther + + category: "other" + imageSource: Category.imageSource("other") + text: qsTr("Other services") + settingsModel.translationTrigger + } + } + } + + Rectangle { + height: baseItem.separatorHeight + width: parent.width + + color: PlatformConstants.grey_border + } + + Rectangle { + id: mainPane + + height: baseItem.height - (baseItem.headerHeight + baseItem.separatorHeight) + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + color: Constants.background_color + + Text { + id: noResultsText + + anchors.centerIn: mainPane + text: qsTr("No match found") + settingsModel.translationTrigger + + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: !flickable.visible + } + + Flickable { + id: flickable + anchors.fill: mainPane + clip: true + flickableDirection: Flickable.VerticalFlick + visible: grid.hasResults + + contentHeight: grid.height + contentWidth: parent.width + + onContentYChanged: { + if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } + + Grid { + id: grid + 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 - 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 + + ProviderCard_tablet { + width: grid.cardWidth + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) + pushFunction: baseItem.pushProviderDetails + providerModelItem: baseItem.wasVisible ? model : undefined + } + } + + AdditionalResultsItem_tablet { + id: additionalResults + width: grid.cardWidth + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) + } + } + } + } + } +} diff --git a/resources/qml/Governikus/ProviderView/+android/ProviderView.qml b/resources/qml/Governikus/ProviderView/+android/ProviderView.qml new file mode 100644 index 0000000..0072660 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+android/ProviderView.qml @@ -0,0 +1,116 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Provider 1.0 +import Governikus.Style 1.0 + +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: TitleBarAction { + state: category !== "" ? "back" : "" + onClicked: { + if (state === "back") { + providerModel.setCategorySelection("") + } + } + } + + headerTitleBarAction: TitleBarAction { + text: Category.displayString(category) + settingsModel.translationTrigger + 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") + settingsModel.translationTrigger + 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/Governikus/ProviderView/+android/SearchBar.qml b/resources/qml/Governikus/ProviderView/+android/SearchBar.qml new file mode 100644 index 0000000..807d75f --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+android/SearchBar.qml @@ -0,0 +1,67 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import Governikus.Global 1.0 + + +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/Governikus/ProviderView/+ios/+tablet/ProviderView.qml b/resources/qml/Governikus/ProviderView/+ios/+tablet/ProviderView.qml new file mode 100644 index 0000000..f5bd838 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+ios/+tablet/ProviderView.qml @@ -0,0 +1,174 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Provider 1.0 + +SectionPage { + id: baseItem + + headerTitleBarAction: TitleBarAction { text: qsTr("Provider") + settingsModel.translationTrigger; font.bold: true } + subTitleBarAction: SearchBar { + width: baseItem.width + onSearchTextChanged: providerModel.searchString = searchText + } + + titleBarColor: Constants.blue + + visible: false + property bool wasVisible: false + onVisibleChanged: wasVisible = true + + readonly property var category: providerModel.categories.length === 0 ? "" : providerModel.categories[0] + + readonly property int headerHeight: Utils.dp(54) + readonly property int separatorHeight: Utils.dp(2) + + ProviderDetailView_tablet { + id: providerDetailView + visible: false + } + + function pushProviderDetails(model) { + historyModel.nameFilter.setProviderAddress(model.providerAddress) + firePush(providerDetailView, {providerModelItem: model}) + } + + Column { + id: content + + width: parent.width + + Rectangle { + + height: baseItem.headerHeight + width: parent.width + + color: "white" + + Row { + id: checkBoxesItem + + height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + padding: Utils.dp(30) + spacing: Utils.dp(30) + + transformOrigin: Item.Center + scale: Math.min(parent.width / width, 1) + + CategoryCheckbox_tablet { + id: checkBoxCitizen + + category: "citizen" + imageSource: Category.imageSource("citizen") + text: qsTr("Citizen services") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxFinance + + category: "finance" + imageSource: Category.imageSource("finance") + text: qsTr("Financials") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxInsurance + + category: "insurance" + imageSource: Category.imageSource("insurance") + text: qsTr("Insurances") + settingsModel.translationTrigger + } + + CategoryCheckbox_tablet { + id: checkBoxOther + + category: "other" + imageSource: Category.imageSource("other") + text: qsTr("Other services") + settingsModel.translationTrigger + } + } + } + + Rectangle { + height: baseItem.separatorHeight + width: parent.width + + color: PlatformConstants.grey_border + } + + Rectangle { + id: mainPane + + height: baseItem.height - (baseItem.headerHeight + baseItem.separatorHeight) + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + color: Constants.background_color + + Text { + id: noResultsText + + anchors.centerIn: mainPane + text: qsTr("No match found") + settingsModel.translationTrigger + + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + visible: !flickable.visible + } + + Flickable { + id: flickable + anchors.fill: mainPane + clip: true + flickableDirection: Flickable.VerticalFlick + visible: grid.hasResults + + contentHeight: grid.height + contentWidth: parent.width + + onContentYChanged: { + if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} + } + + Grid { + id: grid + 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 - 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 + + ProviderCard_tablet { + width: grid.cardWidth + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) + pushFunction: baseItem.pushProviderDetails + providerModelItem: baseItem.wasVisible ? model : undefined + } + } + + AdditionalResultsItem_tablet { + id: additionalResults + width: grid.cardWidth + headerHeight: width / 1.80 + textHeight: Utils.dp(64) + footerHeight: Utils.dp(30) + } + } + } + } + } +} diff --git a/resources/qml/Governikus/ProviderView/+ios/ProviderView.qml b/resources/qml/Governikus/ProviderView/+ios/ProviderView.qml new file mode 100644 index 0000000..02c4cf9 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+ios/ProviderView.qml @@ -0,0 +1,110 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Style 1.0 + +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: TitleBarAction { + state: category !== "" ? "back" : "" + onClicked: { + if (state === "back") { + providerModel.setCategorySelection("") + } + } + } + + headerTitleBarAction: TitleBarAction { + text: Category.displayString(category) + settingsModel.translationTrigger + font.bold: true + } + + subTitleBarAction: SearchBar { + width: baseItem.width + onSearchTextChanged: providerModel.searchString = searchText + } + + titleBarColor: Category.displayColor(category) + + ProviderDetailView { + id: providerDetailView + visible: false + } + + 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") + settingsModel.translationTrigger + 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/Governikus/ProviderView/+ios/SearchBar.qml b/resources/qml/Governikus/ProviderView/+ios/SearchBar.qml new file mode 100644 index 0000000..84b20e6 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/+ios/SearchBar.qml @@ -0,0 +1,150 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 + + +Item { + readonly property alias searchText: searchField.text + + id: baseItem + height: Constants.searchbar_height + + MouseArea { + id: pageArea + onClicked: pageArea.focus = true + + height: Constants.searchbar_height + width: parent.width + anchors.bottom: parent.bottom + + Rectangle { + anchors.left: parent.left + anchors.right: cancelButton.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.leftMargin: Utils.dp(8) + anchors.rightMargin: Utils.dp(10) + anchors.topMargin: Utils.dp(6) + anchors.bottomMargin: Utils.dp(8) + radius: Utils.dp(6) + color: "white" + + Image { + id: glassIcon + height: parent.height - 2 * anchors.leftMargin + width: height + anchors.left: parent.left + anchors.leftMargin: Utils.dp(4) + anchors.verticalCenter: parent.verticalCenter + source: "qrc:///images/iOS/search_icon.svg" + } + + TextField { + id: searchField + anchors.margins: Utils.dp(8) + anchors.verticalCenter: parent.verticalCenter + anchors.left: glassIcon.right + anchors.right: textEditX.left + horizontalAlignment: Text.AlignLeft + + style: TextFieldStyle { + background: Rectangle {} + } + + onVisibleChanged: { + if (visible === false){ + Qt.inputMethod.hide() + } + } + } + + Label { + id: searchLabel + anchors.left: searchField.left + anchors.leftMargin: Utils.dp(8) + anchors.verticalCenter: searchField.verticalCenter + text: qsTr("Search") + settingsModel.translationTrigger + color: Constants.grey + font.pixelSize: Constants.normal_font_size + visible: searchField.text.trim().length === 0 + } + + MouseArea { + id: textEditX + height: parent.height + width: height + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + enabled: searchField.text.length > 0 + + onClicked: { + searchField.text = "" + } + + Image { + anchors.margins: Utils.dp(4) + anchors.fill: parent + source: "qrc:///images/iOS/search_cancel.svg" + visible: parent.enabled + } + } + } + + DimmableTextButton { + id: cancelButton + + anchors.right: parent.right + anchors.rightMargin: visible ? Utils.dp(8) : 0 + anchors.verticalCenter: parent.verticalCenter + clip: true + visible: false + width: visible ? cancelButton.implicitWidth : 0 + font.family: "Helvetica" + font.pixelSize: Constants.normal_font_size + color: "white" + text: qsTr("Cancel") + settingsModel.translationTrigger + onClicked: { + searchField.text = "" + pageArea.clicked(null) + } + } + } + + states: [ + State { + name: "searchBarActive" + when: searchField.activeFocus || searchField.text.trim().length !== 0 + + PropertyChanges { + target: cancelButton + visible: true + } + }, + State { + name: "" + StateChangeScript { + script: { + Qt.inputMethod.hide() + } + } + + PropertyChanges { + target: cancelButton + visible: false + } + } + ] + + transitions: [ + Transition { + from: "*" + to: "*" + AnchorAnimation { + duration: 200; + easing.type: Easing.InOutQuad + } + } + ] +} diff --git a/resources/qml/Governikus/ProviderView/AdditionalResultsItem.qml b/resources/qml/Governikus/ProviderView/AdditionalResultsItem.qml new file mode 100644 index 0000000..6eb6686 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/AdditionalResultsItem.qml @@ -0,0 +1,58 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +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 + '' + settingsModel.translationTrigger + } + + 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/Governikus/ProviderView/AdditionalResultsItem_tablet.qml b/resources/qml/Governikus/ProviderView/AdditionalResultsItem_tablet.qml new file mode 100644 index 0000000..e329dea --- /dev/null +++ b/resources/qml/Governikus/ProviderView/AdditionalResultsItem_tablet.qml @@ -0,0 +1,70 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +Rectangle { + id: baseItem + height: column.height + + property int headerHeight: 0 + property int textHeight: 0 + property int footerHeight: 0 + property int totalHits: providerModel.additionalResultCount + + 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 + '' + settingsModel.translationTrigger + + anchors.centerIn: parent + + font.bold: true + font.pixelSize: Constants.normal_font_size + color: PlatformConstants.secondary_text + } + } + + Rectangle { + height: baseItem.footerHeight + width: parent.width + color: Constants.blue + } + } + + MouseArea { + anchors.fill: parent + onClicked: providerModel.addAdditionalResultCategories() + } +} diff --git a/resources/qml/Governikus/ProviderView/CategoryCheckbox_tablet.qml b/resources/qml/Governikus/ProviderView/CategoryCheckbox_tablet.qml new file mode 100644 index 0000000..8cb3f2a --- /dev/null +++ b/resources/qml/Governikus/ProviderView/CategoryCheckbox_tablet.qml @@ -0,0 +1,48 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 + +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.normal_font_size + anchors.verticalCenter: parent.verticalCenter + } + + GCheckBox { + id: checkbox + anchors.verticalCenter: parent.verticalCenter + visible: true + checked: providerModel.categories.indexOf(baseItem.category) !== -1 + } + } + + MouseArea { + anchors.fill: parent + onClicked: providerModel.updateCategorySelection(category, !checkbox.checked) + } +} diff --git a/resources/qml/Governikus/ProviderView/DimmableTextButton.qml b/resources/qml/Governikus/ProviderView/DimmableTextButton.qml new file mode 100644 index 0000000..0857e16 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/DimmableTextButton.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import Governikus.Global 1.0 + +Label { + id: label + signal clicked + + color: white + + MouseArea { + id: buttonArea + anchors.fill: parent + onClicked: { + parent.clicked() + } + } + + states: [ + State { + name: "pressed" + when: buttonArea.pressed + + PropertyChanges { + target: label + color: Constants.grey + } + } + ] + transitions: [ + ] +} diff --git a/resources/qml/Governikus/ProviderView/ProviderCardNameRow_tablet.qml b/resources/qml/Governikus/ProviderView/ProviderCardNameRow_tablet.qml new file mode 100644 index 0000000..b297c85 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/ProviderCardNameRow_tablet.qml @@ -0,0 +1,48 @@ +import QtQuick 2.6 + +import Governikus.Global 1.0 + + +Rectangle { + readonly property int padding: Constants.pane_padding / 2 + + property string providerName + property string headerIcon + property int nameHeight + property string providerCategory + + width: parent.width + + Image { + id: image + source: parent.headerIcon !== "" ? + parent.headerIcon : + Category.buttonImageSource(parent.providerCategory) + asynchronous: true + height: parent.height + width: height + fillMode: Image.PreserveAspectFit + anchors.top: parent.top + anchors.topMargin: -parent.padding + anchors.left: parent.left + anchors.leftMargin: parent.padding + } + + 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.secondary_text + } +} diff --git a/resources/qml/Governikus/ProviderView/ProviderCard_tablet.qml b/resources/qml/Governikus/ProviderView/ProviderCard_tablet.qml new file mode 100644 index 0000000..19ca431 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/ProviderCard_tablet.qml @@ -0,0 +1,70 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.Provider 1.0 + +Rectangle { + id: baseItem + height: column.height + color: Category.displayColor(provider.category) + + property int headerHeight: 0 + property int textHeight: 0 + property int footerHeight: 0 + + property alias providerModelItem: provider.modelItem + property var pushFunction: function(model) {} + + ProviderModelItem { + id: provider + } + + Column { + id: column + width: baseItem.width + + Image { + source: provider.image + asynchronous: true + height: baseItem.headerHeight + width: parent.width + fillMode: Image.PreserveAspectCrop + anchors.horizontalCenter: parent.horizontalCenter + } + + ProviderCardNameRow_tablet { + height: baseItem.textHeight + providerName: provider.longName !== "" ? provider.longName : provider.shortName + headerIcon: provider.icon + providerCategory: provider.category + } + + Rectangle { + color: Category.displayColor(provider.category) + height: baseItem.footerHeight + width: parent.width + + Text { + text: provider.homepageBase + + anchors.centerIn: parent + + leftPadding: Constants.pane_padding + rightPadding: Constants.pane_padding + elide: Text.ElideRight + maximumLineCount: 1 + + font.pixelSize: Constants.normal_font_size + color: "white" + + scale: Math.min(1, parent.width / (contentWidth + leftPadding + rightPadding)) + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: baseItem.pushFunction(providerModelItem) + } +} diff --git a/resources/qml/Governikus/ProviderView/ProviderContactInfoItem.qml b/resources/qml/Governikus/ProviderView/ProviderContactInfoItem.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/ProviderContactInfoItem.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/provider/ProviderDelegateModel.qml b/resources/qml/Governikus/ProviderView/ProviderDelegateModel.qml similarity index 100% rename from resources/qml/provider/ProviderDelegateModel.qml rename to resources/qml/Governikus/ProviderView/ProviderDelegateModel.qml diff --git a/resources/qml/Governikus/ProviderView/ProviderSectionDelegate.qml b/resources/qml/Governikus/ProviderView/ProviderSectionDelegate.qml new file mode 100644 index 0000000..981a152 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/ProviderSectionDelegate.qml @@ -0,0 +1,67 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 + +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) + settingsModel.translationTrigger + } + + 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/Governikus/ProviderView/ProviderView.qml b/resources/qml/Governikus/ProviderView/ProviderView.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/ProviderView.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/ProviderView/SearchBar.qml b/resources/qml/Governikus/ProviderView/SearchBar.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/SearchBar.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/ProviderView/qmldir b/resources/qml/Governikus/ProviderView/qmldir new file mode 100644 index 0000000..8b489f7 --- /dev/null +++ b/resources/qml/Governikus/ProviderView/qmldir @@ -0,0 +1,2 @@ +module ProviderView +ProviderView 1.0 ProviderView.qml diff --git a/resources/qml/Governikus/RemoteServiceView/AvailableDevicesListDelegate.qml b/resources/qml/Governikus/RemoteServiceView/AvailableDevicesListDelegate.qml new file mode 100644 index 0000000..3c070f9 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/AvailableDevicesListDelegate.qml @@ -0,0 +1,32 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 + +MouseArea { + height: Utils.dp(40) + + signal requestPairing(string pDeviceId) + + onClicked: { + requestPairing(deviceId) + } + + Text { + id: nameText + width: parent.width + font.pixelSize: Utils.sp(16) + anchors.verticalCenter: parent.verticalCenter + opacity: 0.87 + text: remoteDeviceName + } + + Rectangle { + width: parent.width + height: Utils.dp(1) + color: "black" + opacity: 0.1 + anchors.bottom: parent.bottom + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/KnownDevicesListDelegate.qml b/resources/qml/Governikus/RemoteServiceView/KnownDevicesListDelegate.qml new file mode 100644 index 0000000..fcedbbf --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/KnownDevicesListDelegate.qml @@ -0,0 +1,61 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 + +Item { + id: root + height: Utils.dp(60) + + Item { + id: textItem + height: childrenRect.height + width: parent.width * 0.8 + anchors.verticalCenter: root.verticalCenter + + Text { + id: nameText + font.pixelSize: Utils.sp(16) + opacity: 0.87 + text: remoteDeviceName + (isNetworkVisible ? qsTr(" (Available)"): "") + } + + Text { + id: dateText + anchors.top: nameText.bottom + anchors.topMargin: Utils.dp(2) + font.pixelSize: Utils.sp(14) + opacity: 0.38 + text: qsTr("Last connection: ") + lastConnected + } + } + + MouseArea { + id: iconClick + width: Utils.dp(44) + height: width + + anchors.right: root.right + anchors.verticalCenter: root.verticalCenter + + Image { + id: icon + width: Utils.dp(22) + height: width + anchors.centerIn: parent + source: "qrc:///images/iOS/search_cancel.svg" + } + + onClicked: { + remoteServiceModel.forgetDevice(deviceId) + } + } + + Rectangle { + width: parent.width + height: Utils.dp(1) + color: "black" + opacity: 0.1 + anchors.bottom: root.bottom + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml new file mode 100644 index 0000000..1a4a714 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml @@ -0,0 +1,53 @@ +import QtQuick 2.5 + +Item { + id: controller + + Connections { + target: remoteServiceModel + onFireCurrentStateChanged: { + switch (remoteServiceModel.currentState) { + case "": + break + case "StateStartRemoteService": + navBar.lockedAndHidden = true + if (Qt.platform.os === "android") { + remoteServiceModel.readerPlugInType = "NFC"; + } else { + remoteServiceModel.readerPlugInType = "PCSC"; + } + setWorkflowStateAndContinue("startRemoteService") + case "StateProcessRemoteMessages": + firePopAll() + numberModel.continueWorkflow() + break + case "StateEstablishPaceChannel": + enterPinView.state = "INITIAL" + setWorkflowStateAndRequestInput("establishPaceChannel") + break + case "FinalState": + numberModel.continueWorkflow() + navBar.lockedAndHidden = false + break + default: + numberModel.continueWorkflow() + } + } + } + + function setWorkflowState(pState) { + state = pState + } + + function setWorkflowStateAndContinue(pState) { + setWorkflowState(pState) + numberModel.continueWorkflow() + } + + function setWorkflowStateAndRequestInput(pState) { + setWorkflowState(pState) + if (remoteServiceModel.pinPadModeOn()) { + firePush(enterPinView, {state: remoteServiceModel.getPacePasswordId()}) + } + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServicePairingPopup.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServicePairingPopup.qml new file mode 100644 index 0000000..b627a25 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServicePairingPopup.qml @@ -0,0 +1,75 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import Governikus.Global 1.0 + +Popup { + property bool requestInput: false + property alias pin: name.text + property var deviceId + + id: popup + modal: true + focus: true + closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape + width: Utils.dp(250) + height: contentColumn.height + 2 * Constants.pane_padding + padding: Constants.pane_padding + + Connections { + target: remoteServiceModel + onFireEnvironmentChanged: close() + } + + Column { + id: contentColumn + width: parent.width + spacing: Constants.pane_spacing + + Text { + id: header + text: qsTr("Pairing code") + settingsModel.translationTrigger + font.pixelSize: Constants.header_font_size + font.bold: true + } + + Text { + id: info + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + text: ( requestInput + ? qsTr("Enter the pairing code shown on your other device to use it as a card reader") + : qsTr("Enter this code on your other device to use this device as a card reader") + ) + settingsModel.translationTrigger + } + + TextField { + id: name + width: parent.width + horizontalAlignment: Text.AlignHCenter + font.letterSpacing: Utils.dp(5) + font.pixelSize: Utils.sp(50) + font.bold: true + readOnly: !requestInput + inputMethodHints: Qt.ImhDigitsOnly + validator: RegExpValidator { regExp: /\d\d\d\d/ } + onAccepted: { + remoteServiceModel.connectToServer(deviceId, name.getText(0,4)) + close() + } + } + + GButton { + text: qsTr("Start pairing") + settingsModel.translationTrigger + width: parent.width + visible: requestInput + + onClicked: { + remoteServiceModel.connectToServer(deviceId, name.getText(0,4)) + close() + } + } + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml new file mode 100644 index 0000000..d9ea8a3 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml @@ -0,0 +1,231 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: rootPage + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: qsTr("Configure remote service") + settingsModel.translationTrigger; font.bold: true } + + onVisibleChanged: remoteServiceModel.detectRemoteDevices = visible + + Connections { + target: remoteServiceModel + onFirePairingFailed: qmlExtension.showFeedback(qsTr("Pairing failed. Please try again to activate pairing on your other device and enter the shown pairing code.")) + } + + content: Column { + id: mainColumn + width: rootPage.width + padding: Constants.pane_padding + spacing: Constants.component_spacing + + readonly property int usableWidth: width - 2 * padding + + Text { + id: errorMsg + width: parent.usableWidth + text: "" + color: Constants.red + font.pixelSize: Constants.normal_font_size + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + visible: text !== "" + } + + Column { + id: nameContainer + width: parent.usableWidth + + Text { + text: qsTr("Device name") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + font.bold: true + color: Constants.blue + } + + Text { + text: qsTr("Choose a device name here to identify it in the network:") + settingsModel.translationTrigger + width: parent.width + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignJustify + wrapMode: Text.WordWrap + } + + Item { + id: spacing + height: Utils.dp(5) + width: height + } + + GTextField { + id: serverName123 + width: parent.width + onAccepted: { + settingsModel.serverName = text + text = settingsModel.serverName + } + onVisibleChanged: if (visible) text = settingsModel.serverName + } + } + + Item { + id: pinPadModeContainer + visible: Qt.platform.os !== "ios" + width: parent.usableWidth + height: Math.max(pinPadModeText.height, pinPadModeSwitch.height) + + Item { + id: pinPadModeText + height: nameText.height + dateText.height + anchors.left: pinPadModeContainer.left + anchors.right: pinPadModeSwitch.left + anchors.rightMargin: Constants.component_spacing + anchors.verticalCenter: pinPadModeContainer.verticalCenter + Text { + id: nameText + anchors.bottomMargin: Utils.dp(2) + font.pixelSize: Utils.sp(16) + color: "#000000" + opacity: 0.87 + text: qsTr("PIN pad mode") + settingsModel.translationTrigger + } + + Text { + id: dateText + width: parent.width + anchors.top: nameText.bottom + font.pixelSize: Utils.sp(14) + color: "#000000" + opacity: 0.38 + text: qsTr("Enter PIN on smartphone") + settingsModel.translationTrigger + wrapMode: Text.WordWrap + } + } + + GSwitch { + id: pinPadModeSwitch + anchors.right: pinPadModeContainer.right + anchors.verticalCenter: pinPadModeContainer.verticalCenter + onIsOnChanged: settingsModel.pinPadMode = pinPadModeSwitch.isOn + onVisibleChanged: if (visible) isOn = settingsModel.pinPadMode + } + } + + Column { + width: parent.usableWidth + + Text { + text: qsTr("Paired devices") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + font.bold: true + color: Constants.blue + } + + Text { + text: qsTr("No device is paired.") + settingsModel.translationTrigger + width: parent.width + visible: !knownDeviceList.visible + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignJustify + wrapMode: Text.WordWrap + } + + ListView { + id: knownDeviceList + width: parent.width + height: childrenRect.height + model: remoteServiceModel.knownDevices + delegate: KnownDevicesListDelegate { + width: knownDeviceList.width + } + visible: count > 0 + interactive: false + } + } + + Column { + width: parent.usableWidth + + Text { + text: qsTr("Available devices") + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + font.bold: true + color: Constants.blue + } + + Text { + text: qsTr("No new remote reader was found on your network. Make sure that the remote reader functionality in AusweisApp2 on your other device is activated and that your devices are connected to the same network.") + settingsModel.translationTrigger + width: parent.width + visible: !searchDeviceList.visible + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignJustify + wrapMode: Text.WordWrap + } + + ListView { + id: searchDeviceList + width: parent.width + height: childrenRect.height + model: remoteServiceModel.availableRemoteDevices + delegate: AvailableDevicesListDelegate { + width: searchDeviceList.width + onRequestPairing: { + popup.deviceId = pDeviceId + popup.pin = "" + informationPairingPopup.open() + } + } + visible: count > 0 + interactive: false + } + } + } + + Popup { + id: informationPairingPopup + x: (rootPage.width - width) / 2 + y: (rootPage.height - height) / 2 + width: Utils.dp(250) + height: contentColumn.height + 2 * Constants.pane_padding + modal: true + focus: true + padding: Constants.pane_padding + closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape + + Column { + id: contentColumn + width: parent.width + spacing: Constants.pane_spacing + + Text { + id: info + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: Constants.normal_font_size + text: qsTr("Start the pairing mode on the other device if it is not already started.") + settingsModel.translationTrigger + } + + GButton { + text: qsTr("OK") + settingsModel.translationTrigger + width: parent.width + + onClicked: { + popup.open() + informationPairingPopup.close() + } + } + } + } + + RemoteServicePairingPopup { + id: popup + requestInput: true + + x: (rootPage.width - width) / 2 + y: Constants.pane_padding + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceView.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceView.qml new file mode 100644 index 0000000..11f9070 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceView.qml @@ -0,0 +1,241 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +import Governikus.EnterPinView 1.0 +import Governikus.Global 1.0 +import Governikus.Style 1.0 +import Governikus.TitleBar 1.0 +import Governikus.TechnologyInfo 1.0 + +SectionPage { + leftTitleBarAction: TitleBarAction { + state: remoteServiceModel.running ? "cancel" : "" + onClicked: startButton.clicked() + } + + headerTitleBarAction: TitleBarAction { + text: qsTr("Smartphone as card reader") + settingsModel.translationTrigger; + font.bold: true + } + + readonly property int maxWidth: Math.min(width - 2 * Constants.component_spacing, Utils.dp(500)) + id: root + + RemoteServiceSettings { + id: remoteSettings + visible: false + } + + RemoteServiceController { + id: controller + } + + RemoteServicePairingPopup { + id: popup + x: (root.width - width) / 2 + y: (root.height - height) / 2 + + pin: remoteServiceModel.psk.toString() + onPinChanged: { + if (pin === "") { + close() + } + } + onVisibleChanged: remoteServiceModel.setPairing(visible) + } + + Image { + id: image + source: "qrc:///images/phone_to_pc.svg" + anchors.top: parent.top + anchors.margins: Constants.component_spacing + anchors.horizontalCenter: parent.horizontalCenter + height: parent.height * 0.2 + width: parent.maxWidth + fillMode: Image.PreserveAspectFit + } + + Text { + id: text + + width: parent.maxWidth + anchors.top: image.bottom + anchors.margins: Constants.component_spacing + anchors.horizontalCenter: parent.horizontalCenter + + text: qsTr("Please start the remote service in order to use your smartphone as a card reader with AusweisApp2." + + " Please note: Both your devices have to be connected to the same WiFi.") + + settingsModel.translationTrigger + font.pixelSize: Constants.normal_font_size + horizontalAlignment: Text.AlignJustify + wrapMode: Text.WordWrap + } + + + GButton { + readonly property bool running: remoteServiceModel.running + readonly property bool canEnableNfc: remoteServiceModel.canEnableNfc + id: startButton + buttonColor: running ? "red" : "green" + anchors.top: text.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: Constants.component_spacing + onClicked: { + if (canEnableNfc) { + qmlExtension.showSettings("android.settings.NFC_SETTINGS") + } else { + var newRunning = !running; + remoteServiceModel.running = newRunning + qmlExtension.keepScreenOn(newRunning) + } + } + text: { + settingsModel.translationTrigger; // Bind this evaluation to the trigger. + + if (canEnableNfc) { + return qsTr("Enable NFC"); + } else if (running) { + return qsTr("Stop remote service"); + } else { + return qsTr("Start remote service"); + } + } + onRunningChanged: { + navBar.lockedAndHidden = running + } + enabled: remoteServiceModel.runnable || canEnableNfc + } + + GButton { + id: pairingButton + anchors.top: startButton.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: Constants.component_spacing + text: qsTr("Start pairing") + settingsModel.translationTrigger + opacity: 0 + enabled: opacity === 1 + onClicked: popup.open() + } + + Item { + id: statusText + + anchors.top: startButton.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Constants.component_spacing + anchors.topMargin: Constants.component_spacing * 2 + + Text { + id: error + width: text.width + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Utils.dp(16) + font.bold: true + color: "red" + wrapMode: Text.WordWrap + visible: !remoteServiceModel.runnable + text: remoteServiceModel.errorMessage; + } + + Item { + id: connectedText + anchors.fill: parent + opacity: 0 + + Text { + id: headText + anchors.top: connectedText.top + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: Constants.header_font_size + font.weight: Font.Bold + color: Constants.blue + + text: qsTr("Card access in progress") + settingsModel.translationTrigger; + } + Text { + id: subText + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Constants.normal_font_size + anchors.top: headText.bottom + anchors.topMargin: Utils.dp(10) + anchors.horizontalCenter: parent.horizontalCenter + width: connectedText.width * 0.8 + wrapMode: Text.WordWrap + + text: qsTr("Please pay attention to the display on your other device.") + settingsModel.translationTrigger; + } + + states: [ + State { name: "UNCONNECTED"; when: remoteServiceModel.running && !remoteServiceModel.connected + PropertyChanges { target: connectedText; opacity: 0 } + PropertyChanges { target: pairingButton; opacity: 1 } + }, + State { name: "CONNECTED"; when: remoteServiceModel.running && remoteServiceModel.connected + PropertyChanges { target: connectedText; opacity: 1 } + PropertyChanges { target: pairingButton; opacity: 0 } + } + ] + transitions: [ + Transition { + NumberAnimation { + property: "opacity" + duration: 500 + easing.type: Easing.InOutQuad + } + } + ] + } + } + + EnterPinView { + id: enterPinView + visible: false + + leftTitleBarAction: TitleBarAction { + state: "cancel" + onClicked: remoteServiceModel.cancelPasswordRequest() + } + + onPinEntered: { + numberModel.continueWorkflow() + } + } + + TechnologySwitchButton { + id: switchTo + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + onClicked: firePush(remoteSettings, {}) + imageSource: "qrc:///images/android/navigation/remotesettings.svg" + text: qsTr("Settings") + settingsModel.translationTrigger + opacity: 1 + enabled: opacity === 1 + } + + states: [ + State { name: "OFF"; when: !remoteServiceModel.running + PropertyChanges { target: pairingButton; opacity: 0 } + PropertyChanges { target: switchTo; opacity: 1 } + }, + State { name: "ON"; when: remoteServiceModel.running + PropertyChanges { target: pairingButton; opacity: 1 } + PropertyChanges { target: switchTo; opacity: 0 } + } + ] + transitions: [ + Transition { + NumberAnimation { + property: "opacity" + duration: 500 + easing.type: Easing.InOutQuad + } + } + ] +} diff --git a/resources/qml/Governikus/RemoteServiceView/qmldir b/resources/qml/Governikus/RemoteServiceView/qmldir new file mode 100644 index 0000000..f134ced --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/qmldir @@ -0,0 +1,4 @@ +module RemoteServiceView +RemoteServiceView 1.0 RemoteServiceView.qml +RemoteServiceSettings 1.0 RemoteServiceSettings.qml +RemoteServicePairingView 1.0 RemoteServicePairingView.qml diff --git a/resources/qml/Governikus/ResultView/+android/ResultView.qml b/resources/qml/Governikus/ResultView/+android/ResultView.qml new file mode 100644 index 0000000..24de0fb --- /dev/null +++ b/resources/qml/Governikus/ResultView/+android/ResultView.qml @@ -0,0 +1,72 @@ +import QtQuick 2.5 +import QtQuick.Window 2.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + leftTitleBarAction: TitleBarAction { state: "cancel"; onClicked: baseItem.clicked() } + + property alias text: resultText.text + property bool isError: false + signal clicked + + Rectangle { + anchors.fill: parent + color: Constants.background_color + } + + // See: http://tagasks.com/in_qtqml_how_to_load_different_images_for_different_device_densities_android + property int ppi: Screen.pixelDensity * 25.4 + + readonly property string imageDir: { + if (ppi >= 360) + "xxxhdpi" + else if (ppi >= 270) + "xxhdpi" + else if (ppi >= 180) + "xhdpi" + else if (ppi >= 135) + "hdpi" + else + "mdpi" + } + + 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 + } + + Text { + id: resultText + 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: isError ? Constants.red : Constants.blue + onLinkActivated: Qt.openUrlExternally(link) + } + + GButton { + id: button + width: Utils.dp(90) + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: Utils.dp(30) + + text: qsTr("Ok") + settingsModel.translationTrigger + onClicked: baseItem.clicked() + } +} diff --git a/resources/qml/Governikus/ResultView/+ios/ResultView.qml b/resources/qml/Governikus/ResultView/+ios/ResultView.qml new file mode 100644 index 0000000..1882980 --- /dev/null +++ b/resources/qml/Governikus/ResultView/+ios/ResultView.qml @@ -0,0 +1,47 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + +SectionPage { + id: baseItem + leftTitleBarAction: TitleBarAction { state: "hidden" } + + property alias text: resultText.text + property bool isError: false + signal clicked + + Rectangle { + anchors.fill: parent + color: Constants.background_color + } + + + Image { + id: resultImage + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: isError ? "qrc:///images/rotes_X.svg" : "qrc:///images/gruener_Haken.svg" + width: Utils.dp(160) + } + Text { + id: resultText + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: resultImage.bottom + width: parent.width * 0.9 + font.pixelSize: Constants.header_font_size + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + color: isError ? Constants.red : Constants.blue + onLinkActivated: Qt.openUrlExternally(link) + } + + GButton { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Utils.dp(30) + text: qsTr("Ok") + settingsModel.translationTrigger + onClicked: baseItem.clicked() + } +} diff --git a/resources/qml/Governikus/ResultView/ResultView.qml b/resources/qml/Governikus/ResultView/ResultView.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/ResultView/ResultView.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/ResultView/qmldir b/resources/qml/Governikus/ResultView/qmldir new file mode 100644 index 0000000..b2eec08 --- /dev/null +++ b/resources/qml/Governikus/ResultView/qmldir @@ -0,0 +1,2 @@ +module ResultView +ResultView 1.0 ResultView.qml diff --git a/resources/qml/Governikus/SplashScreen/SplashScreen.qml b/resources/qml/Governikus/SplashScreen/SplashScreen.qml new file mode 100644 index 0000000..af43f10 --- /dev/null +++ b/resources/qml/Governikus/SplashScreen/SplashScreen.qml @@ -0,0 +1,38 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +Rectangle { + id: splashScreen + visible: true + anchors.fill: parent + + signal fireHiding() + + readonly property var startTime: new Date().getTime() + + Image { + source: "qrc:/images/npa.svg" + height: Math.min(parent.width, parent.height) * 0.5 + width: height + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + visible: parent.visible + } + + function hide() { + if (!splashScreen.visible) { + return + } + + var TIMEOUT = 1000; + var remaining = startTime + TIMEOUT - new Date().getTime(); + var timer = Qt.createQmlObject("import QtQuick 2.0; Timer {}", splashScreen); + timer.interval = remaining > 0 ? remaining : 0; + timer.repeat = false; + timer.triggered.connect(function(){ + splashScreen.visible = false + fireHiding() + }) + timer.start(); + } +} diff --git a/resources/qml/Governikus/SplashScreen/qmldir b/resources/qml/Governikus/SplashScreen/qmldir new file mode 100644 index 0000000..c62cfae --- /dev/null +++ b/resources/qml/Governikus/SplashScreen/qmldir @@ -0,0 +1,2 @@ +module SplashScreen +SplashScreen 1.0 SplashScreen.qml diff --git a/resources/qml/Governikus/Style/+android/ProviderStyle.qml b/resources/qml/Governikus/Style/+android/ProviderStyle.qml new file mode 100644 index 0000000..db35540 --- /dev/null +++ b/resources/qml/Governikus/Style/+android/ProviderStyle.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + // Provider category list properties + readonly property int categoryFontPixelSize: Constants.titlebar_font_size + readonly property bool categoryFontBold: true + readonly property color categoryColor: Constants.accent_color + readonly property int leftIconMargin: Utils.dp(10) + readonly property int leftProviderListMargin: Utils.dp(20) + readonly property bool showCategoryRightArrow: false + + // Provider list item properties + readonly property int itemLeftMargin: Utils.dp(15) + readonly property color subjectTextColor: Constants.secondary_text + readonly property bool subjectTextFontBold: true + readonly property int addressTextFontSize: Utils.dp(12) + readonly property color addressTextColor: Constants.accent_color + readonly property double infoItemWidthFactor: 4.0 + + readonly property int providerListItemTopMargin: Utils.dp(0) + readonly property int providerListItemRightMargin: Utils.dp(0) + readonly property int providerListItemBottomMargin: Utils.dp(0) + + readonly property bool providerListItemsHaveBorder: true + + readonly property bool providerListDetailsLinkBold: true + readonly property color providerListDetailsLinkBorder: PlatformConstants.grey_light + readonly property color providerListDetailsLinkColor: Constants.primary_text + readonly property color providerListDetailsLinkBackground: PlatformConstants.grey_light + readonly property string providerListDetailsLinkPosition: "top" +} diff --git a/resources/qml/Governikus/Style/+ios/ProviderStyle.qml b/resources/qml/Governikus/Style/+ios/ProviderStyle.qml new file mode 100644 index 0000000..93572dc --- /dev/null +++ b/resources/qml/Governikus/Style/+ios/ProviderStyle.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + // Provider category list properties + 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) + readonly property int leftProviderListMargin: Utils.dp(0) + readonly property bool showCategoryRightArrow: true + + // Provider list item properties + readonly property int itemLeftMargin: Utils.dp(5) + readonly property color subjectTextColor: "#000000" // default color, which is? + readonly property bool subjectTextFontBold: false + readonly property int addressTextFontSize: Utils.dp(11) + readonly property color addressTextColor: PlatformConstants.blue_dark + readonly property double infoItemWidthFactor: 2.0 + + readonly property int providerListItemTopMargin: Utils.dp(2) + readonly property int providerListItemRightMargin: Utils.dp(5) + readonly property int providerListItemBottomMargin: Utils.dp(5) + + readonly property bool providerListItemsHaveBorder: true + + readonly property bool providerListDetailsLinkBold: false + readonly property color providerListDetailsLinkBorder: PlatformConstants.blue_dark + readonly property color providerListDetailsLinkColor: PlatformConstants.blue_dark + readonly property color providerListDetailsLinkBackground: "#ffffff" + readonly property string providerListDetailsLinkPosition: "middle" +} diff --git a/resources/qml/Governikus/Style/NpaBusyIndicatorStyle.qml b/resources/qml/Governikus/Style/NpaBusyIndicatorStyle.qml new file mode 100644 index 0000000..e62b0fc --- /dev/null +++ b/resources/qml/Governikus/Style/NpaBusyIndicatorStyle.qml @@ -0,0 +1,106 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtGraphicalEffects 1.0 + +import Governikus.Global 1.0 + +BusyIndicatorStyle +{ + property real factor: 1.1 + indicator: Item + { + id: busyIndicator + anchors.centerIn: parent + + state: control.running ? "running" : "notrunning" + states: [ + State{ name: "running" }, + State{ name: "notrunning" } + ] + + transitions: [ + Transition { from: "notrunning"; to: "running" + SequentialAnimation { + PropertyAnimation { target: timer; property: "running"; to: true } + PropertyAction { target: busyIndicator; property: "rotation"; value: 0 } + PropertyAction { target: green; property: "rotation"; value: 0 } + PropertyAction { target: blue; property: "rotation"; value: 0 } + PropertyAnimation { target: rect; property: "opacity"; to: 1 } + } + }, + Transition { from: "running"; to: "notrunning" + SequentialAnimation { + PropertyAction { target: timer; property: "running"; value: false } + PropertyAction { target: rect; property: "opacity"; value: 0 } + } + } + ] + + + Behavior on rotation { + NumberAnimation { duration: timer.interval; easing.type: Easing.Linear } + } + Rectangle { + id: rect + anchors.centerIn: parent + height: control.height * factor + width: height + radius: width / 2 + color: Constants.background_color + opacity: 0 + + Behavior on opacity { + NumberAnimation { duration: 200 } + } + } + + Timer { + id: timer + interval: 1000; repeat: true + onTriggered: { + green.rotation = green.rotation + Utils.getRandomInt(0, 135) + blue.rotation = blue.rotation + Utils.getRandomInt(0, 195) + busyIndicator.rotation = busyIndicator.rotation + 100 + } + } + + ConicalGradient { + id: green + anchors.fill: rect + source: rect + angle: 0.0 + cached: true + opacity: rect.opacity + gradient: Gradient + { + GradientStop {color: Constants.green; position: 0.0} + GradientStop {color: Constants.green; position: 0.50} + GradientStop {color: "transparent"; position: 0.5000000000000001} + GradientStop {color: "transparent"; position: 1.0} + } + Behavior on rotation { + NumberAnimation { duration: timer.interval; easing.type: Easing.InOutQuad } + } + } + ConicalGradient { + id: blue + anchors.fill: rect + source: rect + angle: 0.0 + cached: true + opacity: rect.opacity + gradient: Gradient + { + GradientStop {color: "transparent"; position: 0.0} + GradientStop {color: "transparent"; position: 0.50} + GradientStop {color: rect.color; position: 0.5000000000000001} + GradientStop {color: Constants.blue; position: 1.0} + } + Behavior on rotation { + NumberAnimation { duration: timer.interval; easing.type: Easing.InOutQuad } + } + } + } + +} diff --git a/resources/qml/Governikus/Style/ProviderStyle.qml b/resources/qml/Governikus/Style/ProviderStyle.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/Style/ProviderStyle.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/Style/qmldir b/resources/qml/Governikus/Style/qmldir new file mode 100644 index 0000000..ddcb96e --- /dev/null +++ b/resources/qml/Governikus/Style/qmldir @@ -0,0 +1,3 @@ +module Style +NpaBusyIndicatorStyle 1.0 NpaBusyIndicatorStyle.qml +ProviderStyle 1.0 ProviderStyle.qml diff --git a/resources/qml/Governikus/TechnologyInfo/+android/TechnologySwitch.qml b/resources/qml/Governikus/TechnologyInfo/+android/TechnologySwitch.qml new file mode 100644 index 0000000..f29a135 --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/+android/TechnologySwitch.qml @@ -0,0 +1,42 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 +import "." as Gov + +Item { + id: baseItem + height: technologyRow.height + + signal requestPluginType(string pReaderPlugInType) + + property bool allowRemote: true + property string selectedTechnology + + Row { + id: technologyRow + spacing: Utils.dp(20) + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + Gov.TechnologySwitchButton { + visible: selectedTechnology !== "NFC" + onClicked: baseItem.requestPluginType("NFC") + imageSource: "qrc:///images/icon_nfc.svg" + text: qsTr("NFC") + settingsModel.translationTrigger + } + + Gov.TechnologySwitchButton { + visible: allowRemote && selectedTechnology !== "REMOTE" + onClicked: baseItem.requestPluginType("REMOTE") + imageSource: "qrc:///images/icon_remote.svg" + text: qsTr("WiFi") + settingsModel.translationTrigger + } + + Gov.TechnologySwitchButton { + visible: selectedTechnology !== "BLUETOOTH" + onClicked: baseItem.requestPluginType("BLUETOOTH") + imageSource: "qrc:///images/icon_bluetooth.svg" + text: qsTr("Bluetooth") + settingsModel.translationTrigger + } + } +} diff --git a/resources/qml/Governikus/TechnologyInfo/+ios/TechnologySwitch.qml b/resources/qml/Governikus/TechnologyInfo/+ios/TechnologySwitch.qml new file mode 100644 index 0000000..c303ca0 --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/+ios/TechnologySwitch.qml @@ -0,0 +1,36 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 +import "." as Gov + +Item { + id: baseItem + height: technologyRow.height + + signal requestPluginType(string pReaderPlugInType) + + property bool allowRemote: true + property string selectedTechnology + + Row { + id: technologyRow + spacing: Utils.dp(20) + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + Gov.TechnologySwitchButton { + visible: allowRemote && selectedTechnology !== "REMOTE" + onClicked: baseItem.requestPluginType("REMOTE") + imageSource: "qrc:///images/icon_remote.svg" + text: qsTr("Use WiFi card reader instead
of Bluetooth card reader") + settingsModel.translationTrigger + + } + + Gov.TechnologySwitchButton { + visible: selectedTechnology !== "BLUETOOTH" + onClicked: baseItem.requestPluginType("BLUETOOTH") + imageSource: "qrc:///images/icon_bluetooth.svg" + text: qsTr("Use Bluetooth card reader instead
of remote card reader") + settingsModel.translationTrigger + } + } +} diff --git a/resources/qml/Governikus/TechnologyInfo/TechnologyInfo.qml b/resources/qml/Governikus/TechnologyInfo/TechnologyInfo.qml new file mode 100644 index 0000000..e00feea --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/TechnologyInfo.qml @@ -0,0 +1,98 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +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() + + Connections { + target: applicationModel + onFireCertificateRemoved: qmlExtension.showFeedback(qsTr("The device %1 was unpaired because it does not react to connection attempts. Retry the pairing process if you want to use this device to authenticate yourself.").arg(pDeviceName)) + } + + 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 + } + + GButton { + 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/Governikus/TechnologyInfo/TechnologySwitch.qml b/resources/qml/Governikus/TechnologyInfo/TechnologySwitch.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/TechnologySwitch.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/TechnologyInfo/TechnologySwitchButton.qml b/resources/qml/Governikus/TechnologyInfo/TechnologySwitchButton.qml new file mode 100644 index 0000000..9b900ce --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/TechnologySwitchButton.qml @@ -0,0 +1,55 @@ +import QtQuick 2.7 +import QtGraphicalEffects 1.0 + +import Governikus.Global 1.0 + +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 + 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/Governikus/TechnologyInfo/qmldir b/resources/qml/Governikus/TechnologyInfo/qmldir new file mode 100644 index 0000000..b78c29f --- /dev/null +++ b/resources/qml/Governikus/TechnologyInfo/qmldir @@ -0,0 +1,4 @@ +module TechnologyInfo +TechnologyInfo 1.0 TechnologyInfo.qml +TechnologySwitch 1.0 TechnologySwitch.qml +TechnologySwitchButton 1.0 TechnologySwitchButton.qml diff --git a/resources/qml/Governikus/TitleBar/+android/TitleBar.qml b/resources/qml/Governikus/TitleBar/+android/TitleBar.qml new file mode 100644 index 0000000..009376e --- /dev/null +++ b/resources/qml/Governikus/TitleBar/+android/TitleBar.qml @@ -0,0 +1,130 @@ +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +import Governikus.Global 1.0 + +Item +{ + property int duration: 300 + property alias titleBarOpacity: background.opacity + id: titleBar + height: Constants.titlebar_height + + readonly property TitleBarAction defaultLeftAction: TitleBarAction {} + readonly property TitleBarAction defaultTitle: TitleBarAction {} + readonly property Item defaultRightAction: Item {} + + readonly property TitleBarAction activeleftAction: leftAction ? leftAction : defaultLeftAction + readonly property TitleBarAction activeTitleItem: titleItem ? titleItem : defaultTitle + readonly property Item activeRightAction: rightAction ? rightAction : defaultRightAction + + property var leftAction + property var titleItem + property var rightAction + property var subTitleBarAction + property var color + + + Rectangle { + id: background + color: titleBar.color ? titleBar.color : Constants.blue + anchors.top: parent.top + anchors.left: PlatformConstants.is_tablet ? hamburgerFrame.right : parent.left + anchors.bottom: parent.bottom + anchors.right: parent.right + + onColorChanged: statusBarUtil.setStatusBarColor(String(color)) + Behavior on color { ColorAnimation { duration: titleBar.duration } } + } + + Rectangle { + id: hamburgerFrame + height: parent.height + width: Constants.menubar_width + anchors.left: parent.left + color: background.color + opacity: PlatformConstants.is_tablet ? 1 : 0 + } + + Hamburger { + id: burger + anchors.horizontalCenter: hamburgerFrame.horizontalCenter + height: parent.height + width: height + state: navBar.isOpen ? "back" : activeleftAction.state + + MouseArea { + anchors.fill: parent + onClicked: { + switch (burger.state) { + case "": + navBar.open() + break + case "back": + if (navBar.isOpen) { + navBar.close() + } else { + activeleftAction.clicked(mouse) + } + break + case "hidden": + break + default: + activeleftAction.clicked(mouse) + } + } + } + } + + Item { + id: titleText + property string text: activeTitleItem.text + property bool bold: activeTitleItem.font.bold + + anchors.left: burger.right + anchors.leftMargin: Constants.titlebar_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.titlebar_padding + (rightActionStack.width > 0 ? rightAction.width + Constants.titlebar_spacing : 0) + height: parent.height + 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" } + } + } + } + + 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 } + } + } + } + + } + + Item { + id: rightActionStack + anchors.margins: Constants.titlebar_padding + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: parent.bottom + width: rightAction ? activeRightAction.contentWidth : 0 + data: activeRightAction + } +} diff --git a/resources/qml/Governikus/TitleBar/+ios/TitleBar.qml b/resources/qml/Governikus/TitleBar/+ios/TitleBar.qml new file mode 100644 index 0000000..84221d3 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/+ios/TitleBar.qml @@ -0,0 +1,109 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.2 + +import Governikus.Global 1.0 + +Item { + property int duration: 300 + property alias titleBarOpacity: background.opacity + id: titleBar + height: Constants.titlebar_height + activeSubTitleBarAction.height + + readonly property var defaultLeftAction: Text {} + readonly property var defaultTitle: Text {} + readonly property var defaultRightAction: Text {} + readonly property var defaultSubTitleBarAction: Item {} + + property var activeleftAction: leftAction ? leftAction : defaultLeftAction + property var activeTitleItem: titleItem ? titleItem : defaultTitle + property var activeRightAction: rightAction ? rightAction : defaultRightAction + property var activeSubTitleBarAction: subTitleBarAction ? subTitleBarAction : defaultSubTitleBarAction + + property var leftAction + property var titleItem + property var rightAction + property var subTitleBarAction + property var color + + + Rectangle { + id: background + anchors.fill: parent + color: titleBar.color ? titleBar.color : Constants.blue + + Behavior on color { ColorAnimation { duration: titleBar.duration } } + } + + Item { + id: firstLine + + height: Constants.titlebar_height + width: parent.width + + Item { + data: activeleftAction + width: activeleftAction.width + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + } + + Item { + id: titleText + property string text: activeTitleItem.text + property bool bold: activeTitleItem.font.bold + + anchors.left: burger.right + anchors.leftMargin: Constants.titlebar_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.titlebar_padding + (rightActionStack.width > 0 ? rightAction.width + Constants.titlebar_spacing : 0) + height: parent.height + clip: true + + TitleBarText { + id: oldTitle + text: parent.text + width: parent.width + horizontalAlignment: Text.AlignHCenter + 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" } + } + } + } + + TitleBarText { + id: newTitle + text: parent.text + width: parent.width + font.bold: parent.bold + horizontalAlignment: Text.AlignHCenter + + 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 } + } + } + } + } + + Item { + data: activeRightAction + width: activeRightAction.width + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + } + } + + Item { + data: activeSubTitleBarAction + width: parent.width + anchors.top: firstLine.bottom + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/resources/qml/Governikus/TitleBar/Hamburger.qml b/resources/qml/Governikus/TitleBar/Hamburger.qml new file mode 100644 index 0000000..1073005 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/Hamburger.qml @@ -0,0 +1,105 @@ +import QtQuick 2.5 + +Item { + id: baseItem + property color color: "white" + visible: state !== "hidden" + + Item { + id: content + width: parent.width * 0.7 + height: parent.height * 0.7 + anchors.centerIn: parent + + property double itemWidth: width * 0.7 + property double itemHeight: content.height / 12 + property double itemArrowWidth: itemWidth * 0.6 + property double itemArrowMiddleWidth: itemWidth * 0.85 + property double itemArrowWidthDelta: itemArrowWidth / (2 * Math.SQRT2) + property double itemWidthDelta: itemWidth / (2 * Math.SQRT2) + property double itemHeightDelta: itemHeight / (2 * Math.SQRT2) + + Rectangle { + id: r0 + x: (content.width - content.itemWidth) * 0.5 + y: (2+0) / 6 * content.height - content.itemHeight * 0.5 + width: content.itemWidth + height: content.itemHeight + antialiasing: true + transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right + color: baseItem.color + } + + Rectangle { + id: r1 + x: (content.width - content.itemWidth) * 0.5 + y: (2+1) / 6 * content.height - content.itemHeight * 0.5 + width: content.itemWidth + height: content.itemHeight + antialiasing: true + transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right + color: baseItem.color + } + + Rectangle { + id: r2 + x: (content.width - content.itemWidth) * 0.5 + y: (2+2) / 6 * content.height - content.itemHeight * 0.5 + width: content.itemWidth + height: content.itemHeight + antialiasing: true + transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right + color: baseItem.color + } + } + + states: [ + State { + name: "back" + PropertyChanges { target: content; rotation: 180 } + PropertyChanges { target: r0; transformOrigin: Item.Right; rotation: 45; y: (content.height - content.itemHeight) * 0.5 + content.itemHeightDelta; width: content.itemArrowWidth; x: content.itemWidth * 0.5 } + PropertyChanges { target: r1; opacity: 1; width: content.itemArrowMiddleWidth; x: (content.width - content.itemArrowMiddleWidth - content.itemHeightDelta) * 0.5 } + PropertyChanges { target: r2; transformOrigin: Item.Right; rotation: -45; y: (content.height - content.itemHeight) * 0.5 - content.itemHeightDelta; width: content.itemArrowWidth; x: content.itemWidth * 0.5 } + }, + State { + name: "cancel" + PropertyChanges { target: content; rotation: 180 } + PropertyChanges { target: r0; transformOrigin: Item.Left; rotation: 45; x: content.width * 0.5 - content.itemWidthDelta; y: content.height * 0.5 - content.itemWidthDelta } + PropertyChanges { target: r1; opacity: 0; width: 0; x: (content.width - content.itemArrowMiddleWidth - content.itemHeightDelta) * 0.5 } + PropertyChanges { target: r2; transformOrigin: Item.Left; rotation: -45; x: content.width * 0.5 - content.itemWidthDelta; y: content.height * 0.5 + content.itemWidthDelta } + } + ] + + transitions: [ + Transition { + from: "cancel" + to: "back" + SequentialAnimation{ + PropertyAction { target: content; property: "rotation"; value: 0 } + PropertyAction { targets: [r0, r1, r2]; property: "transformOrigin"; value: Item.Right } + PropertyAction { targets: [r0, r1, r2]; property: "x"; value: (content.width - content.itemWidth) * 0.5 } + PropertyAction { target: r0; property: "y"; value: (content.height - content.itemHeight) * 0.5 + content.itemHeightDelta } + PropertyAction { target: r2; property: "y"; value: (content.height - content.itemHeight) * 0.5 + content.itemHeightDelta } + } + RotationAnimation { target: content; direction: RotationAnimation.Clockwise; duration: 300; easing.type: Easing.InOutQuad } + PropertyAnimation { targets: [r0, r1, r2]; properties: "width, y, x"; duration: 300; easing.type: Easing.InOutQuad } + }, + Transition { + from: "back" + to: "cancel" + SequentialAnimation{ + PropertyAction { target: content; property: "rotation"; value: 0 } + PropertyAction { targets: [r0, r1, r2]; property: "transformOrigin"; value: Item.Left } + PropertyAction { targets: [r0, r2]; property: "width"; value: content.itemWidth } + PropertyAction { target: r1; property: "width"; value: 0 } + PropertyAction { targets: [r0, r1, r2]; property: "x"; value: (content.width - content.itemWidth) * 0.5 } + } + RotationAnimation { target: content; direction: RotationAnimation.Clockwise; duration: 300; easing.type: Easing.InOutQuad } + PropertyAnimation { targets: [r0, r1, r2]; properties: "width, y, x"; duration: 300; easing.type: Easing.InOutQuad } + }, + Transition { + RotationAnimation { target: content; direction: RotationAnimation.Clockwise; duration: 300; easing.type: Easing.InOutQuad } + PropertyAnimation { targets: [r0, r1, r2]; properties: "opacity, width, rotation, y, x"; duration: 300; easing.type: Easing.InOutQuad } + } + ] +} diff --git a/resources/qml/Governikus/TitleBar/TitleBar.qml b/resources/qml/Governikus/TitleBar/TitleBar.qml new file mode 100644 index 0000000..4b11736 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/TitleBar.qml @@ -0,0 +1,3 @@ +Item { + id: dummy +} diff --git a/resources/qml/Governikus/TitleBar/TitleBarAction.qml b/resources/qml/Governikus/TitleBar/TitleBarAction.qml new file mode 100644 index 0000000..701eba6 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/TitleBarAction.qml @@ -0,0 +1,24 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 + +MouseArea { + property string text: "" + property alias font: titleBarText.font + + height: Constants.titlebar_height + width: titleBarText.width + 2 * Constants.titlebar_padding + anchors.centerIn: parent + + TitleBarText { + id: titleBarText + anchors.centerIn: parent + + text: ( parent.text !== "" ? parent.text : + parent.state === "cancel" ? qsTr("Cancel") : + parent.state === "edit" ? qsTr("Edit") : + parent.state === "back" ? qsTr("< back") : + parent.state === "hidden" ? "" : + "") + settingsModel.translationTrigger + } +} diff --git a/resources/qml/Governikus/TitleBar/TitleBarText.qml b/resources/qml/Governikus/TitleBar/TitleBarText.qml new file mode 100644 index 0000000..5cbe0a6 --- /dev/null +++ b/resources/qml/Governikus/TitleBar/TitleBarText.qml @@ -0,0 +1,12 @@ +import QtQuick 2.7 + +import Governikus.Global 1.0 + +Text { + id: textItem + anchors.verticalCenter: parent.verticalCenter + color: "white" + font.pixelSize: Constants.titlebar_font_size + maximumLineCount: 1 + elide: Text.ElideRight +} diff --git a/resources/qml/Governikus/TitleBar/qmldir b/resources/qml/Governikus/TitleBar/qmldir new file mode 100644 index 0000000..52cf30b --- /dev/null +++ b/resources/qml/Governikus/TitleBar/qmldir @@ -0,0 +1,4 @@ +module TitleBar +TitleBar 1.0 TitleBar.qml +TitleBarAction 1.0 TitleBarAction.qml +Hamburger 1.0 Hamburger.qml diff --git a/resources/qml/Governikus/VersionInformationView/VersionInformation.qml b/resources/qml/Governikus/VersionInformationView/VersionInformation.qml new file mode 100644 index 0000000..a074255 --- /dev/null +++ b/resources/qml/Governikus/VersionInformationView/VersionInformation.qml @@ -0,0 +1,41 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.2 + +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 + + +SectionPage +{ + id: root + leftTitleBarAction: TitleBarAction { state: "back"; onClicked: firePop() } + headerTitleBarAction: TitleBarAction { text: qsTr("Version Information") + settingsModel.translationTrigger; font.bold: true } + + content: Item + { + height: pane.height + 2 * Constants.component_spacing + width: root.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/Governikus/VersionInformationView/qmldir b/resources/qml/Governikus/VersionInformationView/qmldir new file mode 100644 index 0000000..652ae10 --- /dev/null +++ b/resources/qml/Governikus/VersionInformationView/qmldir @@ -0,0 +1,2 @@ +module VersionInformationView +VersionInformation 1.0 VersionInformation.qml diff --git a/resources/qml/Governikus/Workflow/BluetoothWorkflow.qml b/resources/qml/Governikus/Workflow/BluetoothWorkflow.qml new file mode 100644 index 0000000..4f87c8f --- /dev/null +++ b/resources/qml/Governikus/Workflow/BluetoothWorkflow.qml @@ -0,0 +1,93 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 +import Governikus.TechnologyInfo 1.0 + +Item { + id: baseItem + signal requestPluginType(string pReaderPlugInType) + + property alias allowRemote: technologySwitch.allowRemote + + property bool locationPermissionInfoConfirmed: false + onLocationPermissionInfoConfirmedChanged: { + if (identifyController) identifyController.locationPermissionConfirmed = locationPermissionInfoConfirmed + if (changePinController) changePinController.locationPermissionConfirmed = locationPermissionInfoConfirmed + } + + readonly property bool showLocationPermissionInfo: applicationModel.locationPermissionRequired && !locationPermissionInfoConfirmed + + onStateChanged: { + if (state === "reader") { + locationPermissionInfoConfirmed = false + } + } + + onShowLocationPermissionInfoChanged: { + if (applicationModel.bluetoothEnabled && !showLocationPermissionInfo) { + numberModel.continueWorkflow() + } + } + + ProgressIndicator { + id: progressIndicator + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + height: parent.height / 2 + imageIconSource: "qrc:///images/icon_bluetooth.svg" + imagePhoneSource: "qrc:///images/phone_bluetooth.svg" + state: (!applicationModel.bluetoothAvailable || !applicationModel.bluetoothEnabled || parent.showLocationPermissionInfo) ? "off" : + (baseItem.state === "reader") ? "one" : + (baseItem.state === "card") ? "two" : "" + } + + 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: technologySwitch.top + state: parent.state + + enableButtonVisible: applicationModel.bluetoothAvailable && (!applicationModel.bluetoothEnabled || parent.showLocationPermissionInfo) + enableButtonText: (!applicationModel.bluetoothEnabled ? qsTr("Enable Bluetooth") : qsTr("Continue")) + settingsModel.translationTrigger + onEnableClicked: { + if (!applicationModel.bluetoothEnabled) { + applicationModel.bluetoothEnabled = true + } else { + parent.locationPermissionInfoConfirmed = true + } + } + enableText: (!visible ? "" : + !applicationModel.bluetoothAvailable ? qsTr("Bluetooth is not supported by your device.") + "
" + qsTr("Please try NFC.") : + !applicationModel.bluetoothEnabled ? qsTr("Bluetooth is switched off.") + "
" + qsTr("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.") : "" + ) + settingsModel.translationTrigger + + titleText: ((baseItem.state === "reader") ? qsTr("Establish connection") : + (baseItem.state === "card") ? qsTr("Determine card") : "" + ) + settingsModel.translationTrigger + + subTitleText: (!visible ? "" : + !!numberModel.inputError ? numberModel.inputError : + (state === "reader") ? + qsTr("Search card reader...") : + (state === "card") ? + qsTr("Please insert your ID card.") : "" + ) + settingsModel.translationTrigger + subTitleTextRedColor: false + } + + TechnologySwitch { + id: technologySwitch + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + selectedTechnology: "BLUETOOTH" + onRequestPluginType: parent.requestPluginType(pReaderPlugInType) + } +} diff --git a/resources/qml/Governikus/Workflow/BusyImageIndicator.qml b/resources/qml/Governikus/Workflow/BusyImageIndicator.qml new file mode 100644 index 0000000..e6e875f --- /dev/null +++ b/resources/qml/Governikus/Workflow/BusyImageIndicator.qml @@ -0,0 +1,28 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Style 1.0 + +Item { + property string image + property alias running: busyIndicator.running + + BusyIndicator { + id: busyIndicator + anchors.centerIn: parent + height: img.height + width: height + running: false + style: NpaBusyIndicatorStyle {factor: 1.2} + } + + Image { + id: img + anchors.centerIn: parent + width: parent.width + fillMode: Image.PreserveAspectFit + smooth: true + source: image + } +} diff --git a/resources/qml/Governikus/Workflow/CardReader.qml b/resources/qml/Governikus/Workflow/CardReader.qml new file mode 100644 index 0000000..85f9efa --- /dev/null +++ b/resources/qml/Governikus/Workflow/CardReader.qml @@ -0,0 +1,213 @@ +import QtQuick 2.5 + +import Governikus.Global 1.0 + +Item { + property bool pinFieldAnimation: true + property bool cardAnimation: true + + id: baseItem + width: height * 3 / 7 + + Timer { + property int index + + id: onTimer + interval: 1500 + running: pinFieldAnimation || cardAnimation + triggeredOnStart: true + + onTriggered: { + onTimer.triggeredOnStart = false + if (pinFieldAnimation) + { + onTimer.index = Utils.getRandomInt(0, 9) + repeater.itemAt(onTimer.index).state = "on" + } + + if (cardAnimation) + { + card.state = "out" + } + + offTimer.restart() + } + } + + Timer { + id: offTimer + interval: 500 + onTriggered: { + if (onTimer.index != undefined) + { + repeater.itemAt(onTimer.index).state = "off" + } + + card.state = "in" + + onTimer.restart() + } + } + + + + Rectangle { + id: reader + color: "#92cef9" + radius: height * 0.05 + anchors.bottom: parent.bottom + width: parent.width + height: parent.height * 5 / 7 + + Rectangle { + id: slot + color: "white" + radius: 10 + height: reader.height * 0.05 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: parent.height * 0.05 + anchors.leftMargin: parent.width * 0.2 + anchors.rightMargin: parent.width * 0.2 + } + + Rectangle { + id: card + color: Constants.blue + radius: height * 0.05 + anchors.horizontalCenter: parent.horizontalCenter + height: baseItem.height * 1.5 / 7 + width: baseItem.width * 0.5 + + onVisibleChanged: y = reader.mapFromItem(pinView, pinView.x, card.y).y + + Rectangle { + id: cardStripe1 + color: "white" + radius: 10 + height: parent.height * 0.1 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: parent.height * 0.1 + anchors.leftMargin: parent.width * 0.1 + anchors.rightMargin: parent.width * 0.1 + } + + Rectangle { + id: cardStripe2 + color: "white" + radius: cardStripe1.radius + height: parent.height * 0.1 + anchors.top: cardStripe1.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: parent.height * 0.2 + anchors.leftMargin: parent.width * 0.1 + anchors.rightMargin: parent.width * 0.1 + } + + MouseArea { + anchors.fill: parent + onClicked: card.state = card.state === "out" ? "in" : "out" + } + + states: [ + State { + name: "out" + AnchorChanges {target: card; anchors.bottom: reader.top} + }, + State { + name: "in" + AnchorChanges {target: card; anchors.bottom: slot.verticalCenter} + } + ] + + transitions: [ + Transition { + AnchorAnimation {duration: 500} + } + ] + } + + Rectangle { + readonly property int margin: parent.width * 0.1 + id: display + color: "white" + radius: height * 0.2 + height: reader.height * 0.2 + anchors.bottom: pinGrid.top + anchors.margins: margin + anchors.left: parent.left + anchors.right: parent.right + } + + Grid { + id: pinGrid + anchors.bottom: reader.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: display.margin + + columns: 3 + spacing: anchors.margins + height: width + + Repeater { + id: repeater + model: 9 + + Item { + readonly property int _size: (reader.width - 4 * pinGrid.spacing) / 3 + property alias state: pinButtonCircle.state + + id: pinButton + width: _size + height: width + + Rectangle { + id: pinButtonCircle + anchors.centerIn: parent + width: pinButton._size + height: width + radius: width * 0.5 + + Behavior on color { + ColorAnimation { + duration: 250 + } + } + + Behavior on width { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutElastic + } + } + + MouseArea { + anchors.fill: parent + onClicked: pinButton.state = pinButton.state === "off" ? "on" : "off" + } + + state: "off" + + states: [ + State { + name: "off" + PropertyChanges {target: pinButtonCircle; color: "white"} + PropertyChanges {target: pinButtonCircle; width: pinButton._size} + }, + State { + name: "on" + PropertyChanges {target: pinButtonCircle; color: Constants.blue} + PropertyChanges {target: pinButtonCircle; width: pinButton._size + pinButton._size * 0.3} + } + ] + } + } + } + } + } +} diff --git a/resources/qml/Governikus/Workflow/NfcProgressIndicator.qml b/resources/qml/Governikus/Workflow/NfcProgressIndicator.qml new file mode 100644 index 0000000..6b88e58 --- /dev/null +++ b/resources/qml/Governikus/Workflow/NfcProgressIndicator.qml @@ -0,0 +1,92 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import Governikus.Global 1.0 + + +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/Governikus/Workflow/NfcWorkflow.qml b/resources/qml/Governikus/Workflow/NfcWorkflow.qml new file mode 100644 index 0000000..b452726 --- /dev/null +++ b/resources/qml/Governikus/Workflow/NfcWorkflow.qml @@ -0,0 +1,60 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 +import Governikus.TechnologyInfo 1.0 + +Item { + id: baseItem + signal requestPluginType(string pReaderPlugInType) + clip: true + + property alias allowRemote: technologySwitch.allowRemote + + NfcProgressIndicator { + id: progressIndicator + anchors.left: parent.left + anchors.right: parent.right + height: parent.height / 2 + state: visible && applicationModel.nfcAvailable && applicationModel.nfcEnabled ? "on" : "off" + } + + + TechnologyInfo { + anchors.left: parent.left + anchors.leftMargin: Utils.dp(5) + anchors.right: parent.right + anchors.rightMargin: anchors.leftMargin + anchors.top: progressIndicator.bottom + anchors.bottom: technologySwitch.top + clip: true + state: parent.state + + enableButtonVisible: applicationModel.nfcAvailable && !applicationModel.nfcEnabled + enableButtonText: qsTr("Go to NFC settings") + settingsModel.translationTrigger + onEnableClicked: qmlExtension.showSettings("android.settings.NFC_SETTINGS") + enableText: (!visible ? "" : + !applicationModel.nfcAvailable ? qsTr("NFC is not supported by your device.") + "
" + qsTr("Please try Bluetooth.") : + !applicationModel.nfcEnabled ? qsTr("NFC is switched off.") + "
" + qsTr("Please enable NFC in your system settings.") : "" + ) + settingsModel.translationTrigger + + titleText: qsTr("Establish connection") + settingsModel.translationTrigger + + subTitleText: (!visible ? "" : + numberModel.extendedLengthApdusUnsupported ? qsTr("Your device does not meet the technical requirements (Extended Length not supported). You require an additional 'Bluetooth card reader' or an additional 'smartphone as 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 the authority responsible for issuing your identification document to activate the online identification function.") : + qsTr("Please place your device
on your ID card.") + ) + settingsModel.translationTrigger + subTitleTextRedColor: numberModel.extendedLengthApdusUnsupported || numberModel.pinDeactivated + } + + + TechnologySwitch { + id: technologySwitch + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + selectedTechnology: "NFC" + onRequestPluginType: parent.requestPluginType(pReaderPlugInType) + } +} diff --git a/resources/qml/Governikus/Workflow/ProgressCircle.qml b/resources/qml/Governikus/Workflow/ProgressCircle.qml new file mode 100644 index 0000000..6296868 --- /dev/null +++ b/resources/qml/Governikus/Workflow/ProgressCircle.qml @@ -0,0 +1,100 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import Governikus.Global 1.0 + +Item { + id: baseItem + height: Utils.dp(70) + readonly property int _stepWidth: Utils.dp(60) + + Rectangle { + id: rec1 + anchors.left: baseItem.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + width: _stepWidth + height: Utils.dp(2) + color: Constants.blue + } + + Rectangle { + id: tCircle1 + anchors.verticalCenter: rec1.verticalCenter + anchors.horizontalCenter: rec1.left + width: state === "active" ? Utils.dp(70) : Utils.dp(25) + border.width + height: width + radius: width / 2 + color: Constants.background_color + border.color: "white" + border.width: state === "active" ? 2 : 0 + + state: "inactive" + states: [ + State { name: "active" + PropertyChanges { target: innerDisc; width: Utils.dp(50) } + }, + State { name: "inactive" + PropertyChanges { target: innerDisc; width: Utils.dp(25) } + } + ] + + transitions: [ + Transition { to: "active" + PropertyAnimation { target: innerDisc; property: "width"; duration: 1500; easing.type: Easing.OutBounce } + } + ] + + Rectangle { + id: innerDisc + anchors.centerIn: parent + color: tCircle1.state === "active" ? Constants.blue : "white" + radius: width / 2 + height: width + border.color: Constants.blue + border.width: 1 + Text { + anchors.centerIn: parent + text: "1" + font.bold: true + font.pixelSize: parent.height / 3 + color: tCircle1.state === "active" ? "white" : Constants.blue + } + } + } + + TextCircle { + id: tCircle2 + anchors.verticalCenter: rec1.verticalCenter + anchors.horizontalCenter: rec1.right + text: "2" + } + + state: "inactive" + states: [ + State { + name: "inactive" + PropertyChanges { target: tCircle1; state: "inactive" } + PropertyChanges { target: tCircle2; state: "inactive" } + PropertyChanges { target: rec1; anchors.leftMargin: 0 } + }, + State { + name: "one" + PropertyChanges { target: tCircle1; state: "active" } + PropertyChanges { target: tCircle2; state: "inactive" } + PropertyChanges { target: rec1; anchors.leftMargin: 0 } + }, + State { + name: "two" + PropertyChanges { target: tCircle1; state: "inactive" } + PropertyChanges { target: tCircle2; state: "active" } + PropertyChanges { target: rec1; anchors.leftMargin: -_stepWidth } + } + ] + + transitions: [ + Transition { + to: "two" + PropertyAnimation { target: rec1; property: "anchors.leftMargin"; duration: 500; easing.type: Easing.InOutCubic } + } + ] +} diff --git a/resources/qml/Governikus/Workflow/ProgressIndicator.qml b/resources/qml/Governikus/Workflow/ProgressIndicator.qml new file mode 100644 index 0000000..a400555 --- /dev/null +++ b/resources/qml/Governikus/Workflow/ProgressIndicator.qml @@ -0,0 +1,65 @@ +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +import Governikus.Global 1.0 + + +Item { + id: baseItem + property alias imageIconSource: busyIcon.image + property alias imagePhoneSource: phone.source + + Image { + id: phone + 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 { + id: busyIcon + anchors.centerIn: parent + width: height + height: parent.height - Utils.dp(40) + running: visible + visible: baseItem.state === "one" + } + + CardReader { + anchors.centerIn: parent + height: parent.height + visible: baseItem.state === "two" + cardAnimation: baseItem.state === "two" + pinFieldAnimation: false + } + } + + 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" + } +} diff --git a/resources/qml/Governikus/Workflow/RemoteWorkflow.qml b/resources/qml/Governikus/Workflow/RemoteWorkflow.qml new file mode 100644 index 0000000..1bb7915 --- /dev/null +++ b/resources/qml/Governikus/Workflow/RemoteWorkflow.qml @@ -0,0 +1,61 @@ +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import Governikus.Global 1.0 +import Governikus.TechnologyInfo 1.0 + +Item { + id: baseItem + signal requestPluginType(string pReaderPlugInType) + + ProgressIndicator { + id: progressIndicator + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + height: parent.height / 2 + imageIconSource: "qrc:///images/icon_remote.svg" + imagePhoneSource: "qrc:///images/phone_remote.svg" + state: applicationModel.foundSelectedReader ? "two" : "one" + } + + 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 + + enableButtonVisible: false + enableButtonText: (!applicationModel.wifiEnabled ? qsTr("Enable Wifi") : qsTr("Continue")) + settingsModel.translationTrigger + onEnableClicked: { + // open wifi dialogue + } + + titleText: (!applicationModel.foundSelectedReader ? + qsTr("Establish connection") : + qsTr("Determine card") + ) + settingsModel.translationTrigger + + subTitleText: (!visible ? "" : + !!numberModel.inputError ? numberModel.inputError : + !applicationModel.wifiEnabled ? qsTr("To use the remote service WiFi has to be activated. Please activate WiFi in your device settings.") : + !applicationModel.foundSelectedReader ? + qsTr("No paired and activated remote device was detected. Make sure that you have started remote service on you remote device.") : + qsTr("Please insert your ID card.") + ) + settingsModel.translationTrigger + subTitleTextRedColor: !applicationModel.wifiEnabled + } + + TechnologySwitch { + id: switchToNfcAction + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + selectedTechnology: "REMOTE" + onRequestPluginType: parent.requestPluginType(pReaderPlugInType) + } +} diff --git a/resources/qml/Governikus/Workflow/TextCircle.qml b/resources/qml/Governikus/Workflow/TextCircle.qml new file mode 100644 index 0000000..5c40837 --- /dev/null +++ b/resources/qml/Governikus/Workflow/TextCircle.qml @@ -0,0 +1,68 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +Item { + property alias text: t.text + height: Utils.dp(50) + width: height + + BusyIndicator { + id: busy + anchors.centerIn: parent + height: rec.height * 1.1 + width: height + running: false + style: NpaBusyIndicatorStyle {} + } + + Rectangle { + id: rec + border.width: 1 + border.color: Constants.blue + color: parent.state === "active" ? Constants.blue : "white" + height: parent.state === "active" ? parent.height : parent.height / 2 + width: height + radius: width * 0.5 + anchors.centerIn: parent + } + + Text { + id: t + anchors.centerIn: rec + font.bold: parent.state === "active" + font.pixelSize: rec.height / 3 + color: parent.state === "active" ? "white" : Constants.blue + } + + state:"inactive" + states: [ + State { name: "active" }, + State { name: "inactive" } + ] + + transitions: [ + Transition { + from: "inactive" + to: "active" + SequentialAnimation { + ParallelAnimation { + NumberAnimation {target: t; property: "font.pixelSize"; duration: 1000; easing.type: Easing.OutElastic} + ColorAnimation {duration: 100} + } + PropertyAnimation {target: busy; property: "running"; to: true} + } + }, + Transition { + from: "active" + to: "inactive" + SequentialAnimation { + PropertyAction {target: busy; property: "running"; value: false} + NumberAnimation {target: t; property: "font.pixelSize"; duration: 200} + } + } + ] +} diff --git a/resources/qml/Governikus/Workflow/qmldir b/resources/qml/Governikus/Workflow/qmldir new file mode 100644 index 0000000..83cd0f9 --- /dev/null +++ b/resources/qml/Governikus/Workflow/qmldir @@ -0,0 +1,4 @@ +module Workflow +NfcWorkflow 1.0 NfcWorkflow.qml +RemoteWorkflow 1.0 RemoteWorkflow.qml +BluetoothWorkflow 1.0 BluetoothWorkflow.qml diff --git a/resources/qml/Navigation.qml b/resources/qml/Navigation.qml deleted file mode 100644 index 6b3673b..0000000 --- a/resources/qml/Navigation.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick 2.5 - -import "global" - - -Item { - property bool lockedAndHidden: false - property bool isOpen: true - - id: baseItem - state: "identify" - visible: !lockedAndHidden - - height: visible ? Constants.tabbar_height : 0 - - - Behavior on height { - NumberAnimation {duration: 200} - } - - - function open() { - } - - function close() { - } - - NavigationView {} -} diff --git a/resources/qml/NavigationItem.qml b/resources/qml/NavigationItem.qml deleted file mode 100644 index 8d19586..0000000 --- a/resources/qml/NavigationItem.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item { - property alias source: tabImage.source - property alias text: tabText.text - property alias textColor: tabText.color - signal clicked - - Image { - id: tabImage - anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: 5 - anchors.top: parent.top - anchors.bottom: tabText.top - fillMode: Image.PreserveAspectFit - } - - Text { - id: tabText - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: font.pixelSize / 10 - font.pixelSize: Constants.small_font_size - renderType: Text.NativeRendering - } - - MouseArea { - anchors.fill: parent - onClicked: parent.clicked() - } -} diff --git a/resources/qml/NavigationView.qml b/resources/qml/NavigationView.qml deleted file mode 100644 index 4ae63cd..0000000 --- a/resources/qml/NavigationView.qml +++ /dev/null @@ -1,78 +0,0 @@ -import QtQuick 2.5 - -import "global" - - -Rectangle { - id: content - height: parent.height - width: parent.width - color: Constants.background_color - - ListModel { - id: navModel - - ListElement { - imageOn: "qrc:///images/iOS/tabBar/Ausweisen-on.png" - imageOff: "qrc:///images/iOS/tabBar/Ausweisen-off.png" - desc: qsTr("Identify") - condition: "identify" - } - - ListElement { - imageOn: "qrc:///images/iOS/tabBar/Anbieter-on.png" - imageOff: "qrc:///images/iOS/tabBar/Anbieter-off.png" - desc: qsTr("Provider") - condition: "provider" - } - - ListElement { - imageOn: "qrc:///images/iOS/tabBar/Verlauf-on.png" - imageOff: "qrc:///images/iOS/tabBar/Verlauf-off.png" - desc: qsTr("History") - condition: "history" - } - - ListElement { - imageOn: "qrc:///images/iOS/tabBar/Pin-on.png" - imageOff: "qrc:///images/iOS/tabBar/Pin-off.png" - desc: qsTr("PIN Management") - condition: "pin" - } - - ListElement { - imageOn: "qrc:///images/iOS/tabBar/More-on.svg" - imageOff: "qrc:///images/iOS/tabBar/More-off.svg" - desc: qsTr("More") - condition: "more" - } - } - - Rectangle { - id: topBorderLine - width: parent.width - height: Utils.dp(0.5) - color: Constants.grey - } - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.top: topBorderLine.bottom - - Repeater { - id: repeater - model: navModel - - delegate: NavigationItem { - height: parent.height - width: parent.width / navModel.count - source: baseItem.state === condition ? imageOn : imageOff - textColor: baseItem.state === condition ? Constants.blue : Constants.grey - text: desc - onClicked: baseItem.state = condition - } - } - } -} diff --git a/resources/qml/NfcProgressIndicator.qml b/resources/qml/NfcProgressIndicator.qml deleted file mode 100644 index ba568e7..0000000 --- a/resources/qml/NfcProgressIndicator.qml +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index 9177c8d..0000000 --- a/resources/qml/NfcWorkflow.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.1 - -import "global" - - -Item { - id: baseItem - signal abortNfc - clip: true - - NfcProgressIndicator { - id: progressIndicator - anchors.left: parent.left - anchors.right: parent.right - height: parent.height / 2 - state: visible && applicationModel.nfcAvailable && applicationModel.nfcEnabled ? "on" : "off" - } - - - 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/NpaBusyIndicatorStyle.qml b/resources/qml/NpaBusyIndicatorStyle.qml deleted file mode 100644 index 5580ce5..0000000 --- a/resources/qml/NpaBusyIndicatorStyle.qml +++ /dev/null @@ -1,106 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 - -import "global" - -BusyIndicatorStyle -{ - property real factor: 1.1 - indicator: Item - { - id: busyIndicator - anchors.centerIn: parent - - state: control.running ? "running" : "notrunning" - states: [ - State{ name: "running" }, - State{ name: "notrunning" } - ] - - transitions: [ - Transition { from: "notrunning"; to: "running" - SequentialAnimation { - PropertyAnimation { target: timer; property: "running"; to: true } - PropertyAction { target: busyIndicator; property: "rotation"; value: 0 } - PropertyAction { target: green; property: "rotation"; value: 0 } - PropertyAction { target: blue; property: "rotation"; value: 0 } - PropertyAnimation { target: rect; property: "opacity"; to: 1 } - } - }, - Transition { from: "running"; to: "notrunning" - SequentialAnimation { - PropertyAction { target: timer; property: "running"; value: false } - PropertyAction { target: rect; property: "opacity"; value: 0 } - } - } - ] - - - Behavior on rotation { - NumberAnimation { duration: timer.interval; easing.type: Easing.Linear } - } - Rectangle { - id: rect - anchors.centerIn: parent - height: control.height * factor - width: height - radius: width / 2 - color: Constants.background_color - opacity: 0 - - Behavior on opacity { - NumberAnimation { duration: 200 } - } - } - - Timer { - id: timer - interval: 1000; repeat: true - onTriggered: { - green.rotation = green.rotation + Utils.getRandomInt(0, 135) - blue.rotation = blue.rotation + Utils.getRandomInt(0, 195) - busyIndicator.rotation = busyIndicator.rotation + 100 - } - } - - ConicalGradient { - id: green - anchors.fill: rect - source: rect - angle: 0.0 - cached: true - opacity: rect.opacity - gradient: Gradient - { - GradientStop {color: Constants.green; position: 0.0} - GradientStop {color: Constants.green; position: 0.50} - GradientStop {color: "transparent"; position: 0.5000000000000001} - GradientStop {color: "transparent"; position: 1.0} - } - Behavior on rotation { - NumberAnimation { duration: timer.interval; easing.type: Easing.InOutQuad } - } - } - ConicalGradient { - id: blue - anchors.fill: rect - source: rect - angle: 0.0 - cached: true - opacity: rect.opacity - gradient: Gradient - { - GradientStop {color: "transparent"; position: 0.0} - GradientStop {color: "transparent"; position: 0.50} - GradientStop {color: rect.color; position: 0.5000000000000001} - GradientStop {color: Constants.blue; position: 1.0} - } - Behavior on rotation { - NumberAnimation { duration: timer.interval; easing.type: Easing.InOutQuad } - } - } - } - -} diff --git a/resources/qml/PinField.qml b/resources/qml/PinField.qml deleted file mode 100644 index 50a9b10..0000000 --- a/resources/qml/PinField.qml +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 736db5f..0000000 --- a/resources/qml/PinPad.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.1 - -import "global" - -GridLayout { - id: baseItem - - 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 - } - 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 deleted file mode 100644 index fdc3a6b..0000000 --- a/resources/qml/PinPadButton.qml +++ /dev/null @@ -1,42 +0,0 @@ -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/ProgressCircle.qml b/resources/qml/ProgressCircle.qml deleted file mode 100644 index c8081d3..0000000 --- a/resources/qml/ProgressCircle.qml +++ /dev/null @@ -1,117 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "global" - -Item { - id: baseItem - height: Utils.dp(70) - readonly property int _stepWidth: Utils.dp(60) - - Rectangle { - id: rec1 - anchors.horizontalCenter: baseItem.horizontalCenter - anchors.horizontalCenterOffset: _stepWidth - anchors.verticalCenter: parent.verticalCenter - width: 2 * _stepWidth - height: Utils.dp(2) - color: Constants.blue - } - - Rectangle { - id: tCircle1 - anchors.verticalCenter: rec1.verticalCenter - anchors.horizontalCenter: rec1.left - width: state === "active" ? Utils.dp(70) : Utils.dp(25) + border.width - height: width - radius: width / 2 - color: Constants.background_color - border.color: "white" - border.width: state === "active" ? 2 : 0 - - state: "inactive" - states: [ - State { name: "active" - PropertyChanges { target: innerDisc; width: Utils.dp(50) } - }, - State { name: "inactive" - PropertyChanges { target: innerDisc; width: Utils.dp(25) } - } - ] - - transitions: [ - Transition { to: "active" - PropertyAnimation { target: innerDisc; property: "width"; duration: 1500; easing.type: Easing.OutBounce } - } - ] - - Rectangle { - id: innerDisc - anchors.centerIn: parent - color: tCircle1.state === "active" ? Constants.blue : "white" - radius: width / 2 - height: width - border.color: Constants.blue - border.width: 1 - Text { - anchors.centerIn: parent - text: "1" - font.bold: true - font.pixelSize: parent.height / 3 - color: tCircle1.state === "active" ? "white" : Constants.blue - } - } - } - - TextCircle { - id: tCircle2 - anchors.verticalCenter: rec1.verticalCenter - anchors.horizontalCenter: rec1.horizontalCenter - text: "2" - } - - TextCircle { - id: tCircle3 - anchors.verticalCenter: rec1.verticalCenter - anchors.horizontalCenter: rec1.right - text: "3" - } - - state: "inactive" - states: [ - State { - name: "inactive" - PropertyChanges { target: tCircle1; state: "inactive" } - PropertyChanges { target: tCircle2; state: "inactive" } - PropertyChanges { target: tCircle3; state: "inactive" } - PropertyChanges { target: rec1; anchors.horizontalCenterOffset: _stepWidth } - }, - State { - name: "one" - PropertyChanges { target: tCircle1; state: "active" } - PropertyChanges { target: tCircle2; state: "inactive" } - PropertyChanges { target: tCircle3; state: "inactive" } - PropertyChanges { target: rec1; anchors.horizontalCenterOffset: _stepWidth } - }, - State { - name: "two" - PropertyChanges { target: tCircle1; state: "inactive" } - PropertyChanges { target: tCircle2; state: "active" } - PropertyChanges { target: tCircle3; state: "inactive" } - PropertyChanges { target: rec1; anchors.horizontalCenterOffset: Utils.dp(0) } - }, - State { - name: "three" - PropertyChanges { target: tCircle1; state: "inactive" } - PropertyChanges { target: tCircle2; state: "inactive" } - PropertyChanges { target: tCircle3; state: "active" } - PropertyChanges { target: rec1; anchors.horizontalCenterOffset: -_stepWidth } - } - ] - - transitions: [ - Transition { - PropertyAnimation { target: rec1; property: "anchors.horizontalCenterOffset"; duration: 500; easing.type: Easing.InOutCubic } - } - ] -} diff --git a/resources/qml/ProgressView.qml b/resources/qml/ProgressView.qml deleted file mode 100644 index 6e5b2a3..0000000 --- a/resources/qml/ProgressView.qml +++ /dev/null @@ -1,48 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "global" - -SectionPage -{ - id: baseItem - property alias text: text.text - property alias subText: subText.text - property alias subTextColor: subText.color - - BusyIndicator { - id: busyIndicator - anchors.fill: circle - running: baseItem.visible - style: NpaBusyIndicatorStyle { factor: 1.2 } - } - Rectangle { - id: circle - anchors.centerIn: parent - width: parent.height / 4 - height: width - radius: width / 2 - color: Constants.blue - } - Text { - id: text - anchors.top: circle.bottom - anchors.topMargin: Utils.dp(50) - anchors.horizontalCenter: parent.horizontalCenter - font.pixelSize: Constants.header_font_size - font.weight: Font.Bold - color: Constants.blue - } - Text { - id: subText - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font.pixelSize: Constants.normal_font_size - anchors.top: text.bottom - anchors.topMargin: Utils.dp(10) - anchors.horizontalCenter: parent.horizontalCenter - width: baseItem.width * 0.8 - wrapMode: Text.WordWrap - } -} diff --git a/resources/qml/ProviderContactTab.qml b/resources/qml/ProviderContactTab.qml deleted file mode 100644 index dcacac0..0000000 --- a/resources/qml/ProviderContactTab.qml +++ /dev/null @@ -1,42 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.2 - -import "../" -import "global" - -Item { - id: baseItem - property alias contactModel: repeater.model - - Pane { - id: pane - width: baseItem.width - - Repeater { - id: repeater - - Item { - height: info.height + Utils.dp(20) - width: pane.width - - LabeledText { - id: info - label: model.label - text: model.text - anchors.verticalCenter: parent.verticalCenter - width: parent.width - margin: 0 - onLinkActivated: Qt.openUrlExternally(link) - } - Rectangle { - visible: index != repeater.count - 1 - anchors.bottom: parent.bottom - anchors.left: info.left - anchors.right: parent.right - height: 1 - color: Constants.grey - } - } - } - } -} diff --git a/resources/qml/ProviderHeader.qml b/resources/qml/ProviderHeader.qml deleted file mode 100644 index 7f18bec..0000000 --- a/resources/qml/ProviderHeader.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Rectangle { - id: baseItem - - // Properties that are set by HistoryViewPage - property var selectedProvider - - // 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 - - 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 - } - - Button { - id: buttonText - width: baseItem.width / 2 - anchors.bottom: baseItem.bottom - anchors.right: parent.right - anchors.rightMargin: Constants.component_spacing - text: qsTr("Online Application") - onClicked: { - Qt.openUrlExternally(providerAddress) - } - } -} diff --git a/resources/qml/ProviderInfoSection.qml b/resources/qml/ProviderInfoSection.qml deleted file mode 100644 index 1f34098..0000000 --- a/resources/qml/ProviderInfoSection.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 -import QtQuick.Controls.Styles 1.4 - -import "global" -import "identify" - -Rectangle { - - property string imageSource - property string title - property string name - property bool showForwardAction: true - - width: parent.width - height: Utils.dp(40) - 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.length > 0 ? name : qsTr("Touch for more details") - } - 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 - } - SeparatorLine { - anchors.left: providerTitle.left - anchors.right: providerTitle.right - } - - MouseArea { - anchors.fill: parent - enabled: showForwardAction - onClicked: push(certificateDescriptionPage, {providerName: name}) - } - - CertificateDescriptionPage { - id: certificateDescriptionPage - visible: false - } -} diff --git a/resources/qml/ProviderModelItem.qml b/resources/qml/ProviderModelItem.qml deleted file mode 100644 index 25ad730..0000000 --- a/resources/qml/ProviderModelItem.qml +++ /dev/null @@ -1,94 +0,0 @@ -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 deleted file mode 100644 index d10c0bb..0000000 --- a/resources/qml/ResultView.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick 2.5 - -import "global" - -SectionPage { - id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "hidden" } - - property alias text: resultText.text - property bool isError: false - signal clicked - - Rectangle { - anchors.fill: parent - color: Constants.background_color - } - - - Image { - id: resultImage - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - fillMode: Image.PreserveAspectFit - source: isError ? "qrc:///images/rotes_X.svg" : "qrc:///images/gruener_Haken.svg" - width: Utils.dp(160) - } - Text { - id: resultText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: resultImage.bottom - width: parent.width * 0.9 - font.pixelSize: Constants.header_font_size - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - color: Constants.blue - onLinkActivated: Qt.openUrlExternally(link) - } - - Button { - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(30) - text: qsTr("Ok") - onClicked: baseItem.clicked() - } -} diff --git a/resources/qml/SectionPage.qml b/resources/qml/SectionPage.qml deleted file mode 100644 index 0ecb1c1..0000000 --- a/resources/qml/SectionPage.qml +++ /dev/null @@ -1,52 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "global" - -Item { - property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction {} - property TitleBarAction headerTitleBarAction: TitleBarAction {} - property Item rightTitleBarAction: Item {} - - property color titleBarColor: Constants.blue - /* if the header component has a property named titleBarOpacity, use it, otherwise use default value*/ - readonly property real titleBarOpacity: headerLoader.item && typeof(headerLoader.item.titleBarOpacity) != "undefined" ? headerLoader.item.titleBarOpacity : 1 - - property alias header: headerLoader.sourceComponent - property alias content: contentLoader.sourceComponent - property alias contentY: flickable.contentY - property bool disableFlicking: false - - onTitleBarColorChanged: titleBar.setColor(titleBarColor) - - Flickable { - property real startContentY: 0 - id: flickable - clip: true - flickableDirection: Flickable.VerticalFlick - contentWidth: flickableContent.width - contentHeight: flickableContent.height - anchors.bottom: parent.bottom - width: parent.width - /* if a header is set, it is shown as background of the TitleBar, so we need to expand the height*/ - height: headerLoader.item ? parent.height + Constants.titlebar_height : parent.height - onMovementStarted: { - startContentY = contentY - } - onContentYChanged: { - if (disableFlicking || contentY < 0) { contentY = 0 /* prevent flicking over the top */} - } - Column { - id: flickableContent - Loader { - id: headerLoader - readonly property alias contentY: flickable.contentY - } - Loader { - id: contentLoader - readonly property alias contentY: flickable.contentY - } - } - } -} diff --git a/resources/qml/TabBarView.qml b/resources/qml/TabBarView.qml index c612176..f059a38 100644 --- a/resources/qml/TabBarView.qml +++ b/resources/qml/TabBarView.qml @@ -2,12 +2,15 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.2 -import "global" +import Governikus.Global 1.0 Item { id: baseItem - property string source + property Component sourceComponent + readonly property bool ready: loader.status === Loader.Ready + property bool prefetch: false + readonly property var currentSectionPage: stack.currentItem property alias stack: stack @@ -21,9 +24,8 @@ Item { id: loader asynchronous: true onLoaded: { - appWindow.hideSplashScreen() - baseItem.pushed = true + item.topLevelPage = true push(item) for (var i = 0; i < baseItem.pendingItems.length; i++) { @@ -32,29 +34,21 @@ Item { } baseItem.pendingItems = [] - numberModel.continueWorkflow() } - source: parent.visible ? parent.source : loader.source - } - - onVisibleChanged: { - if (visible) { - titleBar.pushTabBarSubView(stack.currentItem) - } + sourceComponent: parent.visible || baseItem.prefetch ? parent.sourceComponent : loader.sourceComponent } StackView { id: stack anchors.fill: parent - - onCurrentItemChanged: { - titleBar.pushTabBarSubView(currentItem) - } } function push(sectionPage, properties) { if (baseItem.pushed) { + sectionPage.firePush.connect(baseItem.push) + sectionPage.firePop.connect(baseItem.pop) + sectionPage.firePopAll.connect(baseItem.popAll) stack.push(sectionPage, properties) } // Main item has not been loaded yet, delay push. @@ -63,7 +57,16 @@ Item { } } - function pop(item) { - stack.pop(item) + function pop() { + var sectionPage = stack.pop() + sectionPage.firePush.disconnect(baseItem.push) + sectionPage.firePop.disconnect(baseItem.pop) + sectionPage.firePopAll.disconnect(baseItem.popAll) + } + + function popAll() { + while (stack.depth > 1) { + pop() + } } } diff --git a/resources/qml/TechnologyInfo.qml b/resources/qml/TechnologyInfo.qml deleted file mode 100644 index ac3a6c8..0000000 --- a/resources/qml/TechnologyInfo.qml +++ /dev/null @@ -1,93 +0,0 @@ -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 deleted file mode 100644 index c7545e9..0000000 --- a/resources/qml/TechnologySwitchButton.qml +++ /dev/null @@ -1,56 +0,0 @@ -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/TextCircle.qml b/resources/qml/TextCircle.qml deleted file mode 100644 index f57be99..0000000 --- a/resources/qml/TextCircle.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "global" - -Item { - property alias text: t.text - height: Utils.dp(50) - width: height - - BusyIndicator { - id: busy - anchors.centerIn: parent - height: rec.height * 1.1 - width: height - running: false - style: NpaBusyIndicatorStyle {} - } - - Rectangle { - id: rec - border.width: 1 - border.color: Constants.blue - color: parent.state === "active" ? Constants.blue : "white" - height: parent.state === "active" ? parent.height : parent.height / 2 - width: height - radius: width * 0.5 - anchors.centerIn: parent - } - - Text { - id: t - anchors.centerIn: rec - font.bold: parent.state === "active" - font.pixelSize: rec.height / 3 - color: parent.state === "active" ? "white" : Constants.blue - } - - state:"inactive" - states: [ - State { name: "active" }, - State { name: "inactive" } - ] - - transitions: [ - Transition { - from: "inactive" - to: "active" - SequentialAnimation { - ParallelAnimation { - NumberAnimation {target: t; property: "font.pixelSize"; duration: 1000; easing.type: Easing.OutElastic} - ColorAnimation {duration: 100} - } - PropertyAnimation {target: busy; property: "running"; to: true} - } - }, - Transition { - from: "active" - to: "inactive" - SequentialAnimation { - PropertyAction {target: busy; property: "running"; value: false} - NumberAnimation {target: t; property: "font.pixelSize"; duration: 200} - } - } - ] -} diff --git a/resources/qml/TitleBar.qml b/resources/qml/TitleBar.qml deleted file mode 100644 index 1f11b75..0000000 --- a/resources/qml/TitleBar.qml +++ /dev/null @@ -1,157 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "global" - -Item -{ - property int duration: 300 - property alias titleBarOpacity: colorStack.opacity - id: titleBar - height: Constants.titlebar_height - - function reset() { - } - - function push(leftAction, headerAction, rightAction, color) { - colorStack.push(color) - leftActionStack.push(leftAction) - headerActionStack.push(headerAction) - rightActionStack.push(rightAction) - } - - - function pop(item) { - colorStack.pop(item) - leftActionStack.pop(item) - headerActionStack.pop(item) - rightActionStack.pop(item) - } - - function setColor(color) { - colorStack.color = color - } - - Rectangle { - id: colorStack - anchors.fill: parent - visible: false - property var stack - - 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) - } - - function push(nextColor) { - if (stack === undefined) { - // Workaround for Qt 5.6-beta: - // when *not* performing lazy initialization, - // the stack gets reset by unknown caller... - // - // TODO: report it or fix it - stack = [] - } - stack.push(nextColor) - color = nextColor - visible = true - } - function pop(item) { - // analogous to StackView.pop(), see QML documentation - if (typeof item === "undefined") { - stack.pop() - } - else if (item === null) { - while (stack.length > 1) { - stack.pop() - } - } - else { - console.error("NOT SUPPORTED") - } - color = stack[stack.length-1] - } - - Behavior on color { ColorAnimation { duration: titleBar.duration } } - } - - StackView { - id: leftActionStack - anchors.left: parent.left - anchors.leftMargin: 10 - height: parent.height - width: 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 } - } - } - } - - StackView { - property int _width: parent.width - 2 * Math.max(leftActionStack.width, rightActionStack.width) - 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 } - } - } - function getRelX(otherItem) { - return headerActionStack.mapFromItem(otherItem,otherItem.x,0).x - } - } - - StackView { - id: rightActionStack - anchors.right: parent.right - anchors.rightMargin: 10 - anchors.verticalCenter: parent.verticalCenter - height: parent.height - width: currentItem ? currentItem.contentWidth : 0 - delegate: StackViewDelegate { - pushTransition: StackViewTransition { - PropertyAnimation { duration: titleBar.duration; target: exitItem; property: "opacity"; to: 0 } - PropertyAnimation { duration: titleBar.duration; target: enterItem; property: "opacity"; from: 0; to: 1 } - } - } - } -} diff --git a/resources/qml/TitleBarAction.qml b/resources/qml/TitleBarAction.qml deleted file mode 100644 index bba9593..0000000 --- a/resources/qml/TitleBarAction.qml +++ /dev/null @@ -1,47 +0,0 @@ -import QtQuick 2.5 - -import "global" - -Item -{ - property string text - property alias font: textItem.font - readonly property alias contentWidth: invisibleText.contentWidth - signal clicked - - id: root - width: parent ? parent.width : undefined - height: parent ? parent.height : undefined - anchors.verticalCenter: parent ? parent.verticalCenter : undefined - - Behavior on text { - SequentialAnimation { - PropertyAnimation { target: root; property: "opacity"; to: 0; duration: 150 } - PropertyAction { target: root; property: "text" } - PropertyAnimation { target: root; property: "opacity"; to: 1; duration: 150 } - } - } - - Text { - id: invisibleText - visible: false - text: textItem.text - font.bold: textItem.font.bold - font.pointSize: textItem.font.pointSize - } - - TitleBarText { - id: textItem - anchors.horizontalCenter: parent.horizontalCenter - width: Math.min(parent.width, invisibleText.contentWidth) - text: root.text !== "" ? root.text : - root.state === "cancel" ? qsTr("Cancel") : - root.state === "edit" ? qsTr("Edit") : - root.state === "back" ? qsTr("< back") : "" - } - - MouseArea { - anchors.fill: parent - onClicked: root.clicked() - } -} diff --git a/resources/qml/TitleBarMenuAction.qml b/resources/qml/TitleBarMenuAction.qml deleted file mode 100644 index 01eba65..0000000 --- a/resources/qml/TitleBarMenuAction.qml +++ /dev/null @@ -1,3 +0,0 @@ -TitleBarAction { - -} diff --git a/resources/qml/TitleBarText.qml b/resources/qml/TitleBarText.qml deleted file mode 100644 index 93dc386..0000000 --- a/resources/qml/TitleBarText.qml +++ /dev/null @@ -1,13 +0,0 @@ -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/+tablet/PlatformConstants.qml b/resources/qml/global/+android/+tablet/PlatformConstants.qml deleted file mode 100644 index 809083d..0000000 --- a/resources/qml/global/+android/+tablet/PlatformConstants.qml +++ /dev/null @@ -1,37 +0,0 @@ -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/global/+android/Button.qml b/resources/qml/global/+android/Button.qml deleted file mode 100644 index fb2681e..0000000 --- a/resources/qml/global/+android/Button.qml +++ /dev/null @@ -1,83 +0,0 @@ -import QtQuick 2.5 -import QtGraphicalEffects 1.0 - -import "." - -/* - * Custom implementation to be replaced with template specialization of Qt.labs.controls Button - * Android style guide for material design is adapted. - */ -Item { - property alias text: textItem.text - property color buttonColor: Constants.blue - - signal clicked - - height: Constants.button_height - width: Math.max(textItem.implicitWidth + 2 * Utils.dp(16), Utils.dp(88)) - - state: "normal" - states: [ - State { name: "normal"; when: !mouseArea.pressed - PropertyChanges { target: darkLayer; width: 0 } - PropertyChanges { target: shadow; verticalOffset: Utils.dp(2) } - }, - State { name: "pressed"; when: mouseArea.pressed - PropertyChanges { target: darkLayer; width: 2 * rect.width } - PropertyChanges { target: shadow; verticalOffset: Utils.dp(8) } - } - ] - transitions: [ - Transition { - from: "normal"; to: "pressed"; reversible: false - PropertyAnimation { target: darkLayer; property: "width"} - PropertyAnimation { target: shadow; property: "verticalOffset"} - } - ] - - Rectangle { - id: rect - anchors.fill: parent - color: enabled ? buttonColor : "#10000000" - radius: Utils.dp(3) - - Item { - anchors.fill: parent - clip: true - Rectangle { - id: darkLayer - x: mouseArea.containsMouse ? mouseArea.mouseX - width * 0.5 : 0 - height: parent.height - color: "#000000" - opacity: 0.2 - radius: Utils.dp(3) - } - } - - } - - DropShadow { - id: shadow - anchors.fill: rect - radius: 8.0 - fast: true - color: "#40000000" - source: rect - } - - Text { - id: textItem - anchors.centerIn: rect - color: enabled ? "white" : "#40000000" - font.capitalization: Font.AllUppercase - font.bold: true - font.pixelSize: Utils.dp(16) - } - MouseArea{ - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: parent.clicked() - } -} - diff --git a/resources/qml/global/+android/GCheckBox.qml b/resources/qml/global/+android/GCheckBox.qml deleted file mode 100644 index e6dc792..0000000 --- a/resources/qml/global/+android/GCheckBox.qml +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index d8c743b..0000000 --- a/resources/qml/global/+android/LabeledText.qml +++ /dev/null @@ -1,40 +0,0 @@ -import QtQuick 2.5 - -import "." - -Item { - property alias label: labelText.text - property alias text: bodyText.text - property alias textFormat: bodyText.textFormat - property int margin - property int fontUppercase - - signal linkActivated(string link) - - height: childrenRect.height + margin - - Text { - id: bodyText - anchors.top: parent.top - anchors.left: parent.left - anchors.leftMargin: margin - anchors.right: parent.right - anchors.rightMargin: margin - font.pixelSize: Constants.normal_font_size - font.capitalization: fontUppercase - wrapMode: Text.WordWrap - onLinkActivated: parent.linkActivated(link) - } - - Text { - id: labelText - anchors.top: bodyText.bottom - anchors.left: parent.left - anchors.leftMargin: margin - anchors.right: parent.right - anchors.rightMargin: margin - 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 deleted file mode 100644 index 1c7706b..0000000 --- a/resources/qml/global/+android/Pane.qml +++ /dev/null @@ -1,50 +0,0 @@ -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/global/+android/PlatformConstants.qml b/resources/qml/global/+android/PlatformConstants.qml deleted file mode 100644 index 2a603e8..0000000 --- a/resources/qml/global/+android/PlatformConstants.qml +++ /dev/null @@ -1,37 +0,0 @@ -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: false - readonly property bool leftNavigation: true - readonly property bool bottomNavigation: false -} diff --git a/resources/qml/global/Button.qml b/resources/qml/global/Button.qml deleted file mode 100644 index e6b8ca3..0000000 --- a/resources/qml/global/Button.qml +++ /dev/null @@ -1,44 +0,0 @@ -import QtQuick 2.5 -import QtGraphicalEffects 1.0 - -import "." - -/* Custom implementation to be replaced with template specialization of Qt.labs.controls Button*/ -Rectangle { - property alias text: textItem.text - property color buttonColor : Constants.blue - - signal clicked - - color: enabled ? buttonColor : "#10000000" - height: Constants.button_height - width: parent.width - 2 * Utils.dp(20) - clip: true - - Text { - id: textItem - anchors.centerIn: parent - color: enabled ? "white" : "#40000000" - opacity: mouseArea.containsMouse ? 0.5 : 1 - font.pixelSize: Utils.dp(16) - } - MouseArea{ - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: parent.clicked() - } - - RadialGradient { - x: mouseArea.mouseX - width * 0.5 - height: parent.height - width: height * 2 - visible: mouseArea.pressed - opacity: 1 - gradient: Gradient { - GradientStop { position: 0.0; color: Qt.rgba(255,255,255,1) } - GradientStop { position: 0.2; color: Qt.rgba(255,255,255,0.5) } - GradientStop { position: 0.4; color: Qt.rgba(255,255,255,0) } - } - } -} diff --git a/resources/qml/global/Category.js b/resources/qml/global/Category.js deleted file mode 100644 index 6a55b97..0000000 --- a/resources/qml/global/Category.js +++ /dev/null @@ -1,87 +0,0 @@ -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" - -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) { - return getTableValue(CATEGORY_TO_COLOR, cat, CATEGORY_COLOR_NONE) -} - - -var CATEGORY_TO_IMAGE_NAME = { - "citizen": "CitizenServices", - "insurance": "Insurances", - "finance": "Financials", - "other": "OtherServices", - "all": "General", - "": "General" -} - -function imageName(cat) { - return getTableValue(CATEGORY_TO_IMAGE_NAME, cat, "General") -} - - -function getPlatform() { - return plugin.platformStyle.indexOf("android") !== -1 ? "+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/global/Constants.qml b/resources/qml/global/Constants.qml deleted file mode 100644 index 3f300cb..0000000 --- a/resources/qml/global/Constants.qml +++ /dev/null @@ -1,50 +0,0 @@ -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(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) - - 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/global/GCheckBox.qml b/resources/qml/global/GCheckBox.qml deleted file mode 100644 index 0b290bd..0000000 --- a/resources/qml/global/GCheckBox.qml +++ /dev/null @@ -1,12 +0,0 @@ -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/global/GTextField.qml b/resources/qml/global/GTextField.qml deleted file mode 100644 index 12ae727..0000000 --- a/resources/qml/global/GTextField.qml +++ /dev/null @@ -1,35 +0,0 @@ -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/Hamburger.qml b/resources/qml/global/Hamburger.qml deleted file mode 100644 index 851a516..0000000 --- a/resources/qml/global/Hamburger.qml +++ /dev/null @@ -1,80 +0,0 @@ -import QtQuick 2.5 - -Item { - id: baseItem - property color color: "white" - visible: state !== "hidden" - - Item { - id: content - width: parent.width * 0.7 - height: parent.height * 0.7 - anchors.centerIn: parent - - property double itemWidth: width * 0.7 - property double itemHeight: content.height / 12 - property double itemArrowWidth: itemWidth * 0.6 - property double itemArrowMiddleWidth: itemWidth * 0.85 - property double itemArrowWidthDelta: itemArrowWidth / (2 * Math.SQRT2) - property double itemWidthDelta: itemWidth / (2 * Math.SQRT2) - property double itemHeightDelta: itemHeight / (2 * Math.SQRT2) - - Rectangle { - id: r0 - x: (content.width - content.itemWidth) * 0.5 - y: (2+0) / 6 * content.height - content.itemHeight * 0.5 - width: content.itemWidth - height: content.itemHeight - antialiasing: true - transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right - color: baseItem.color - } - - Rectangle { - id: r1 - x: (content.width - content.itemWidth) * 0.5 - y: (2+1) / 6 * content.height - content.itemHeight * 0.5 - width: content.itemWidth - height: content.itemHeight - antialiasing: true - transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right - color: baseItem.color - } - - Rectangle { - id: r2 - x: (content.width - content.itemWidth) * 0.5 - y: (2+2) / 6 * content.height - content.itemHeight * 0.5 - width: content.itemWidth - height: content.itemHeight - antialiasing: true - transformOrigin: baseItem.state === "cancel" ? Item.Left : Item.Right - color: baseItem.color - } - } - - states: [ - State { - name: "back" - PropertyChanges { target: content; rotation: 180 } - PropertyChanges { target: r0; transformOrigin: Item.Right; rotation: 45; y: (content.height - content.itemHeight) * 0.5 + content.itemHeightDelta; width: content.itemArrowWidth; x: content.itemWidth * 0.6 } - PropertyChanges { target: r1; width: content.itemArrowMiddleWidth; x: (content.width - content.itemArrowMiddleWidth - content.itemHeightDelta) * 0.5 } - PropertyChanges { target: r2; transformOrigin: Item.Right; rotation: -45; y: (content.height - content.itemHeight) * 0.5 - content.itemHeightDelta; width: content.itemArrowWidth; x: content.itemWidth * 0.6 } - }, - - State { - name: "cancel" - PropertyChanges { target: content; rotation: 180 } - PropertyChanges { target: r0; transformOrigin: Item.Left; rotation: 45; x: content.width * 0.5 - content.itemWidthDelta; y: content.height * 0.5 - content.itemWidthDelta } - PropertyChanges { target: r1; opacity: 0 } - PropertyChanges { target: r2; transformOrigin: Item.Left; rotation: -45; x: content.width * 0.5 - content.itemWidthDelta; y: content.height * 0.5 + content.itemWidthDelta } - } - ] - - transitions: [ - Transition { - RotationAnimation { target: content; direction: RotationAnimation.Clockwise; duration: 300; easing.type: Easing.InOutQuad } - PropertyAnimation { targets: [r0, r1, r2]; properties: "opacity, width, rotation, y, x"; duration: 300; easing.type: Easing.InOutQuad } - } - ] -} diff --git a/resources/qml/global/Pane.qml b/resources/qml/global/Pane.qml deleted file mode 100644 index 5095247..0000000 --- a/resources/qml/global/Pane.qml +++ /dev/null @@ -1,49 +0,0 @@ -import QtQuick 2.5 - -import "." - - -Column { - id: root - property alias title: titleText.text - default property alias paneData: paneContent.data - readonly property real margin: Utils.dp(20) - readonly property real spacing: Utils.dp(20) - readonly property color color: "white" - - width: parent.width - height: childrenRect.height - - Text { - id: titleText - height: Utils.dp(30) - visible: text !== "" - anchors.left: parent.left - anchors.leftMargin: root.margin - font.pixelSize: Constants.header_font_size - font.capitalization: Font.AllUppercase - color: Constants.grey - } - - Rectangle { width: parent.width; height: 1; color: Constants.grey} - Rectangle { - color: root.color - width: parent.width - height: childrenRect.height - - Column { - width: parent.width - Item { width: parent.width; height: root.margin } - Column { - id: paneContent - anchors.left: parent.left - anchors.leftMargin: root.margin - anchors.right: parent.right - anchors.rightMargin: root.margin - spacing: root.spacing - } - Item { width: parent.width; height: root.margin } - } - } - Rectangle { width: parent.width; height: 1; color: Constants.grey} -} diff --git a/resources/qml/global/PlatformConstants.qml b/resources/qml/global/PlatformConstants.qml deleted file mode 100644 index a258d7e..0000000 --- a/resources/qml/global/PlatformConstants.qml +++ /dev/null @@ -1,37 +0,0 @@ -pragma Singleton - -import QtQuick 2.5 - -import "Utils.js" as Utils - -Item { - // iOS-specific constants, according to the iOS Human Interface Guidelines - readonly property color ios_blue_light: "#54c7fc" - readonly property color ios_yellow: "#ffcd00" - readonly property color ios_orange: "#ff9600" - readonly property color ios_purple: "#ff2851" - readonly property color ios_blue: "#0076ff" - readonly property color ios_green: "#44db5e" - readonly property color ios_red: "#ff3824" - readonly property color ios_grey: "#8e8e93" - - readonly property color all_image_background_color: "transparent" - readonly property color blue: "#659bcd" - readonly property color blue_dark: ios_blue - readonly property color blue_light: ios_blue_light - readonly property color primary_text: "#ffffff" - readonly property color secondary_text: "#000000" - readonly property color accent_color: "#000000" - readonly property color second_accent_color: "#000000" - readonly property int titlebar_font_size: Utils.sp(16) - readonly property int provider_section_height: Utils.dp(50) - readonly property int history_section_height: Utils.dp(60) - readonly property int history_delegate_spacing: 0 - readonly property color history_delegate_address_color: "#00878F" - readonly property int button_height: Utils.dp(40) - readonly property bool use_history_list_delete_area: true - - readonly property bool is_tablet: false - readonly property bool leftNavigation: false - readonly property bool bottomNavigation: true -} diff --git a/resources/qml/global/SeparatorLine.qml b/resources/qml/global/SeparatorLine.qml deleted file mode 100644 index 54802d0..0000000 --- a/resources/qml/global/SeparatorLine.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.5 - -import "." - -Rectangle { - height: 1; - width: parent.width; - color: Constants.grey -} diff --git a/resources/qml/global/qmldir b/resources/qml/global/qmldir deleted file mode 100644 index 5e8e2d7..0000000 --- a/resources/qml/global/qmldir +++ /dev/null @@ -1,10 +0,0 @@ -module Global -singleton Constants 1.0 Constants.qml -singleton PlatformConstants 1.0 PlatformConstants.qml -Separator 1.0 Separator.qml -Button 1.0 Button.qml -Utils 1.0 Utils.js -Category 1.0 Category.js -Hamburger 1.0 Hamburger.qml -LabeledText 1.0 LabeledText.qml -Pane 1.0 Pane.qml diff --git a/resources/qml/history/+android/+tablet/HistoryView.qml b/resources/qml/history/+android/+tablet/HistoryView.qml deleted file mode 100644 index f23067b..0000000 --- a/resources/qml/history/+android/+tablet/HistoryView.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Layouts 1.2 - -import "../../" -import "../../../" -import "../../../global" -import "../../../provider" - -SectionPage { - property alias listViewModel: listView.model - property var selectedIndices: [] - - headerTitleBarAction: TitleBarAction { text: qsTr("History"); font.bold: true } - - Text { - anchors.centerIn: parent - text: qsTr("Currently there are no history entries.") - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - visible: listView.count === 0 - } - - ListView { - id: listView - anchors.fill: parent - model: historyModel - onContentYChanged: { - if (contentY < 0) { - // prevent flicking over the top - contentY = 0 - } - } - - delegate: - HistoryListViewDelegate { - id: historyDelegate - anchors.left: parent.left - anchors.right: parent.right - height: Utils.dp(120) - property var historyModelItem: model - listModel: historyModel - showDetail: false - } - } - - ProviderDetailView { - id: providerHistoryView - visible: false - } - - HistoryViewDetails { - id: detailsHistoryView - visible: false - } -} diff --git a/resources/qml/history/+android/CustomSwipeBar.qml b/resources/qml/history/+android/CustomSwipeBar.qml deleted file mode 100644 index 107a5e0..0000000 --- a/resources/qml/history/+android/CustomSwipeBar.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 as QtControls - - -import "../" -import "../global" - -QtControls.TabBar { - id: rootItem - - height: firstButton.height - width: parent.width - - 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 - font.capitalization: Font.AllUppercase - elide: Text.ElideRight - opacity: enabled ? 1 : 0.3 - color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue - 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 - font.pixelSize: Constants.normal_font_size - elide: Text.ElideRight - opacity: enabled ? 1 : 0.3 - color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } -*/ - } -} diff --git a/resources/qml/history/+android/HistoryDetails.qml b/resources/qml/history/+android/HistoryDetails.qml deleted file mode 100644 index feec155..0000000 --- a/resources/qml/history/+android/HistoryDetails.qml +++ /dev/null @@ -1,93 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 - -import "../global" - -Item { - id: baseItem - - property string providerAddress - property int listItemIndex - - property var listModel - - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Utils.dp(5) - - height: parent.height * 0.3 - width: parent.height * 0.3 - - Image { - anchors.fill: parent - source: "qrc:///images/android/navigation/versionsinformation.svg" - - fillMode: Image.PreserveAspectFit - clip: true - } - - MouseArea { - anchors.fill: parent - onClicked: { - popUp.open() - } - } - - Popup { - id: popUp - x: - (width - baseItem.width) - padding: 0 - focus: true - modal: true - dim: false - - 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) - } - } - } - } - - 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 deleted file mode 100644 index 5549ca2..0000000 --- a/resources/qml/history/+android/HistoryItemImage.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Item { - id: baseItem - - property string imageUrl: "" - - 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(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: categoryImage - anchors.centerIn: parent - 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.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 deleted file mode 100644 index 3f86cd9..0000000 --- a/resources/qml/history/+android/HistoryListViewDelegate.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick 2.7 - -import "../" -import "../global" - -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: 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 deleted file mode 100644 index 1729da0..0000000 --- a/resources/qml/history/+android/HistoryView.qml +++ /dev/null @@ -1,56 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../../" -import "../../global" - -SectionPage { - property alias listViewModel: listView.model - property var selectedIndices: [] - - headerTitleBarAction: TitleBarAction { text: qsTr("History"); font.bold: true } - - Text { - anchors.centerIn: parent - text: qsTr("Currently there are no history entries.") - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - visible: listView.count === 0 - } - - ListView { - id: listView - anchors.fill: parent - model: historyModel - onContentYChanged: { - if (contentY < 0) { - // prevent flicking over the top - contentY = 0 - } - } - - delegate: - HistoryListViewDelegate { - id: historyDelegate - anchors.left: parent.left - anchors.right: parent.right - height: Utils.dp(120) - listModel: historyModel - property var historyModelItem: model - showDetail: false - } - } - - HistoryViewPage { - id: providerHistoryView - visible: false - } - - HistoryViewDetails { - id: detailsHistoryView - visible: false - } -} diff --git a/resources/qml/history/CustomSwipeBar.qml b/resources/qml/history/CustomSwipeBar.qml deleted file mode 100644 index 132fd4b..0000000 --- a/resources/qml/history/CustomSwipeBar.qml +++ /dev/null @@ -1,59 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - -Rectangle { - id: rootItem - property int currentIndex - - anchors.horizontalCenter: parent.horizontalCenter - width: descriptionTab.width + contactTab.width + 2 * border.width - height: descriptionTab.height + 2 * border.width - - border.color: Constants.blue - border.width: Utils.dp(1) - radius: Utils.dp(3) - clip: true - - Row { - id: row - readonly property int maxContentWidth: Math.max(descriptionText.contentWidth, contactText.contentWidth) - - anchors.centerIn: parent - Rectangle { - id: descriptionTab - width: row.maxContentWidth + Utils.dp(6) - height: descriptionText.contentHeight + Utils.dp(6) - color: rootItem.currentIndex === 0 ? Constants.blue : "white" - Text { - id: descriptionText - anchors.centerIn: parent - color: rootItem.currentIndex === 0 ? "white" : Constants.blue - text: qsTr("Contact") - } - MouseArea { - anchors.fill: parent - onClicked: rootItem.currentIndex = 0 - } - } - Rectangle { - id: contactTab - width: row.maxContentWidth + Utils.dp(6) - height: contactText.contentHeight + Utils.dp(6) - color: rootItem.currentIndex === 1 ? Constants.blue : "white" - Text { - id: contactText - anchors.centerIn: parent - color: rootItem.currentIndex === 1 ? "white" : Constants.blue - text: qsTr("History") - } - MouseArea { - anchors.fill: parent - onClicked: rootItem.currentIndex = 1 - } - } - } -} diff --git a/resources/qml/history/HistoryDetails.qml b/resources/qml/history/HistoryDetails.qml deleted file mode 100644 index ada36d7..0000000 --- a/resources/qml/history/HistoryDetails.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Item { - property string providerAddress: "" - - property int listItemIndex: -1 - - property var listModel - - anchors.right: parent.right - anchors.margins: Utils.dp(5) - height: parent.height - width: parent.height * 0.4 - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - height: width - - border.color: Constants.history_delegate_address_color - border.width: Utils.dp(1) - radius: width - - Text { - anchors.centerIn: parent - text: "i" - color: parent.border.color - } - } -} diff --git a/resources/qml/history/HistoryItemImage.qml b/resources/qml/history/HistoryItemImage.qml deleted file mode 100644 index 37f1869..0000000 --- a/resources/qml/history/HistoryItemImage.qml +++ /dev/null @@ -1,26 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Item { - property string imageUrl: "" - - id: baseItem - - anchors.left: parent.left - anchors.leftMargin: Utils.dp(10) - - height: parent.height - width: Utils.dp(40) - - Image { - source: baseItem.imageUrl !== "" ? - baseItem.imageUrl : - (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 deleted file mode 100644 index 0b5fb8f..0000000 --- a/resources/qml/history/HistoryListView.qml +++ /dev/null @@ -1,220 +0,0 @@ -import QtQuick 2.5 -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) - selectedIndices = selectedIndices //to have the change signal emitted - } - - - function cancelDeletion(cancelIndex) { - if (arguments.length === 1) { - var reducedSelection = []; - selectedIndices.map(function (index) { - if (index !== cancelIndex) { - reducedSelection.push(index) - } - }) - selectedIndices = reducedSelection - } - else { - selectedIndices = [] - } - } - - - function performDeletion() { - if (selectedIndices.length === 0) { - listViewModel.removeRows(0, historyModel.rowCount()) - } - else { - // sort in descending order, so that the indices don't change after partial deletion - selectedIndices.sort(function(a,b){return b-a}) - selectedIndices.map(function (index) { - listViewModel.removeRows(index, 1) - }) - selectedIndices = [] //to have the change signal emitted - } - } - - - ListView { - id: listView - anchors.fill: parent - focus: true - clip: true - spacing: Utils.dp(5) - interactive: false - - delegate: Item { - id: delegateItem - width: parent.width - height: delegateLoader.height - - Connections { - target: baseItem - onSelectedIndicesChanged: { - if (baseItem.selectedIndices.indexOf(model.index) === -1) { - flickable.state = "hideDeleteConfirmation" - checkBox.checked = false - } - } - } - - Rectangle { - id: confirmDeletionRect - height: parent.height - width: parent.width / 4 - anchors.right: parent.right - anchors.rightMargin: Utils.dp(10) - anchors.top: parent.top - anchors.topMargin: Utils.dp(8) - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(8) - - color: "red" - - Text { - anchors.centerIn: parent - text: qsTr("Delete") - color: "white" - } - } - - Flickable { - id: flickable - anchors.fill: parent - contentWidth: parent.width + confirmDeletionRect.width - contentHeight: parent.height - flickableDirection: Flickable.HorizontalFlick - interactive: !baseItem.selectable && Constants.use_history_list_delete_area - - Item { - id: delegateContent - width: delegateItem.width - height: delegateItem.height - - CheckBox { - id: checkBox - width: Utils.dp(40) - height: parent.height - - style: IosCheckBoxStyle {} - onClicked: checked ? requestDeletion(model.index) : cancelDeletion(model.index) - } - Loader { - id: delegateLoader - anchors.left: checkBox.right - anchors.right: parent.right - height: Constants.history_section_height - sourceComponent: baseItem.delegate - property var historyModelItem: model - } - - states: [ - State { - name: "notSelectable" - when: !baseItem.selectable - PropertyChanges { target: checkBox; opacity: 0 } - AnchorChanges { target: checkBox; anchors.left: undefined} - AnchorChanges { target: checkBox; anchors.right: delegateContent.left} - }, - State { - name: "selectable" - when: baseItem.selectable - PropertyChanges { target: checkBox; opacity: 1 } - AnchorChanges { target: checkBox; anchors.left: delegateContent.left} - AnchorChanges { target: checkBox; anchors.right: undefined} - } - ] - state: "notSelectable" - - transitions: [ - Transition { - from: "notSelectable" - to: "selectable" - reversible: true - animations: - [ - AnchorAnimation { duration: 200 }, - PropertyAnimation { target: checkBox; properties: "opacity"; duration: 200 } - ] - } - ] - } - - onMovementStarted: { - delegateItem.ListView.view.currentIndex = index - state = "moving" - requestDeletion(model.index) - } - onMovementEnded: { - var ratio = contentX / confirmDeletionRect.width - if (ratio > 0.4) { - state = "showDeleteConfirmation" - } - else { - state = "hideDeleteConfirmation" - cancelDeletion(model.index) - } - } - - state: "hideDeleteConfirmation" - states: [ - State { - name: "moving" - }, - State { - name: "showDeleteConfirmation" - PropertyChanges { target: flickable; contentX: confirmDeletionRect.width } - PropertyChanges { target: cancelDeletionMouseArea; enabled: true } - PropertyChanges { target: confirmDeletionMouseArea; enabled: true } - }, - State { - name: "hideDeleteConfirmation" - PropertyChanges { target: flickable; contentX: 0 } - PropertyChanges { target: cancelDeletionMouseArea; enabled: false } - PropertyChanges { target: confirmDeletionMouseArea; enabled: false } - } - ] - Behavior on contentX { - NumberAnimation { duration: 500; easing.type: Easing.OutQuart } - } - } - } - - removeDisplaced: Transition { - NumberAnimation { properties: "y"; duration: 500; easing.type: Easing.OutQuart } - } - } - - MouseArea { - id: cancelDeletionMouseArea - enabled: false - anchors.fill: parent - onClicked: cancelDeletion() - } - - MouseArea { - id: confirmDeletionMouseArea - enabled: false - width: listView.currentItem ? listView.currentItem.width / 4 : 0 - height: listView.currentItem ? listView.currentItem.height : 0 - x: listView.currentItem ? listView.currentItem.width - width : 0 - y: listView.currentItem ? listView.currentItem.y - listView.contentY : 0 - onClicked: performDeletion() - } -} diff --git a/resources/qml/history/HistoryListViewDelegate.qml b/resources/qml/history/HistoryListViewDelegate.qml deleted file mode 100644 index c86cbd9..0000000 --- a/resources/qml/history/HistoryListViewDelegate.qml +++ /dev/null @@ -1,21 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../global" - -Item { - property bool showDetail: false - - property var listModel - - id: baseItem - - HistoryListViewDelegateContent { - showDetail: baseItem.showDetail - listModel: baseItem.listModel - - width: parent.width - height: parent.height - } -} diff --git a/resources/qml/history/HistoryListViewDelegateContent.qml b/resources/qml/history/HistoryListViewDelegateContent.qml deleted file mode 100644 index 575ba75..0000000 --- a/resources/qml/history/HistoryListViewDelegateContent.qml +++ /dev/null @@ -1,141 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../global" - -Item { - id: baseItem - - property bool showDetail: false - property var listModel - - Rectangle { - id: background - color: "white" - 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: showDetail ? parent.left : categoryImage.right - anchors.leftMargin: showDetail ? Utils.dp(5) : 0 - anchors.right: detailsLink.left - - Column { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - - spacing: Constants.history_delegate_spacing - - Text { - id: dateTimeText - - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.label_font_size - font.capitalization: Font.AllUppercase - color: Constants.blue - 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 { - id: subjectText - - anchors.left: parent.left - anchors.right: parent.right - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.label_font_size - wrapMode: Text.WordWrap - text: historyModelItem ? historyModelItem.subject : "" - } - Text { - id: purposeText - - anchors.left: parent.left - anchors.right: parent.right - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.small_font_size - color: Constants.history_delegate_address_color - wrapMode: Text.WordWrap - text: !!historyModelItem.purpose ? historyModelItem.purpose : qsTr("Touch for more details") - } - } - } - - MouseArea { - anchors.fill: parent - 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: 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 deleted file mode 100644 index baeb73f..0000000 --- a/resources/qml/history/HistoryView.qml +++ /dev/null @@ -1,95 +0,0 @@ -import QtQml.Models 2.2 -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../" -import "../global" - -SectionPage { - leftTitleBarAction: TitleBarMenuAction { - id: leftAction - - state: "edit" - states: [ - State { name: "edit"; when: !historyListView.selectable }, - State { name: "cancel"; when: historyListView.selectable } - ] - onClicked: { - if (state === "edit") { - state = "cancel" - historyListView.selectable = true - } - else { - state = "edit" - historyListView.selectable = false - historyListView.cancelDeletion() - } - } - } - - rightTitleBarAction: TitleBarAction { - id: rightAction - - states: [ - State { - name: "none" - when: leftAction.state == "edit" - PropertyChanges { target: rightAction; text: "" } - }, - State { - name: "delete" - when: historyListView.selectable && historyListView.selectedIndices.length !== 0 - PropertyChanges { target: rightAction; text: qsTr("Delete") } - }, - State { - name: "deleteAll" - when: historyListView.selectable && historyListView.selectedIndices.length === 0 - PropertyChanges { target: rightAction; text: qsTr("Delete all") } - } - ] - onClicked: { - historyListView.performDeletion() - historyListView.selectable = false - } - } - - HistoryViewBackground { - visible: historyListView.count !== 0 - } - - Text { - anchors.centerIn: parent - text: qsTr("Currently there are no history entries.") - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - visible: historyListView.count === 0 - } - - HistoryListView { - id: historyListView - anchors.fill: parent - - listViewModel: historyModel - delegate: HistoryListViewDelegate { - id: historyDelegate - showDetail: false - } - - onSelectedIndicesChanged: { - if (!historyListView.selectable) { - leftAction.state = historyListView.selectedIndices.length !== 0 ? "cancel" : "edit" - } - } - } - - HistoryViewPage { - id: providerHistoryView - visible: false - } - - HistoryViewDetails { - id: detailsHistoryView - visible: false - } -} diff --git a/resources/qml/history/HistoryViewBackground.qml b/resources/qml/history/HistoryViewBackground.qml deleted file mode 100644 index a9d148a..0000000 --- a/resources/qml/history/HistoryViewBackground.qml +++ /dev/null @@ -1,15 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Rectangle { - id: redLine - height: parent.height - width: Utils.dp(2) - - anchors.left: parent.left - anchors.leftMargin: Utils.dp(30) - - color: "red" - opacity: 0.05 -} diff --git a/resources/qml/history/HistoryViewDetails.qml b/resources/qml/history/HistoryViewDetails.qml deleted file mode 100644 index b872808..0000000 --- a/resources/qml/history/HistoryViewDetails.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - -SectionPage { - id: root - property var historyModelItem - - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: historyModelItem ? historyModelItem.subject : ""; font.bold: true } - titleBarColor: Category.displayColor(historyModelItem ? historyModelItem.providerCategory : "") - - content: Item { - height: pane.height + 2 * Constants.component_spacing - width: root.width - - Column { - anchors.fill: parent - anchors.margins: Constants.component_spacing - - Pane { - id: pane - title: qsTr("Provider Information") - - LabeledText { - label: qsTr("Provider name") - text: historyModelItem ? historyModelItem.subject : "" - width: parent.width - } - - LabeledText { - label: qsTr("Purpose") - text: historyModelItem ? historyModelItem.purpose : "" - 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 deleted file mode 100644 index e26651b..0000000 --- a/resources/qml/history/HistoryViewPage.qml +++ /dev/null @@ -1,81 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 - -import "../" -import "../global" - -SectionPage { - id: baseItem - 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: historyModelItem ? historyModelItem.subject : ""; font.bold: true } - titleBarColor: !!provider.category ? Category.displayColor(provider.category) : "" - - - header: ProviderHeader { - id: providerHeader - width: baseItem.width - selectedProvider: provider - } - - content: Item { - height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing - width: baseItem.width - - CustomSwipeBar { - id: swipeBar - currentIndex: swipeView.currentIndex - anchors.top: parent.top - anchors.topMargin: Utils.dp(20) - } - - Rectangle { - id: swipeViewBackground - anchors.top: swipeBar.bottom - anchors.horizontalCenter: swipeBar.horizontalCenter - height: swipeView.height + 2 * Constants.component_spacing - width: parent.width - - 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 - - currentIndex: swipeBar.currentIndex - clip: true - - ProviderContactTab { - id: providerInfo - contactModel: provider.contactModel - } - - 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/history/IosCheckBoxStyle.qml b/resources/qml/history/IosCheckBoxStyle.qml deleted file mode 100644 index 17cd6b4..0000000 --- a/resources/qml/history/IosCheckBoxStyle.qml +++ /dev/null @@ -1,37 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../global" - -CheckBoxStyle { - id: style - spacing: 0 - - indicator: Component { - Rectangle { - id: rectangle - implicitWidth: control.width - implicitHeight: control.height - color: Constants.background_color - - Rectangle { - anchors.centerIn: parent - height: Utils.dp(radius * 2 + border.width * 2) - width: height - radius: 8 - border.color: control.activeFocus ? Constants.blue : Constants.grey - border.width: 1 - color: style.control.parent.color ? style.control.parent.color : "white" - - Rectangle { - visible: control.checked - color: Constants.blue - border.color: "#333" - radius: parent.radius - anchors.fill: parent - } - } - } - } -} diff --git a/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml b/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml deleted file mode 100644 index 828b819..0000000 --- a/resources/qml/identify/+android/+tablet/IdentifyViewContent.qml +++ /dev/null @@ -1,142 +0,0 @@ -import QtQuick 2.5 - -import ".." -import "../global" - - -Item { - id: root - height: infoPane.height + 2 * Constants.component_spacing - - Column { - id: infoPane - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Constants.component_spacing - - spacing: Constants.pane_spacing - - Pane { - - 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() - } - } - } - } - } - } - - Pane { - Column { - height: childrenRect.height - width: parent.width - spacing: Utils.dp(30) - - 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 - } - } - - 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 deleted file mode 100644 index 28aa72b..0000000 --- a/resources/qml/identify/+android/DataGroup.qml +++ /dev/null @@ -1,115 +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 { - id: root - property string title; - property int columns: 1 - property var chat - - width: parent.width - height: column.height - visible: repeater.count > 0 - - Column { - id: column - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - Text { - height: implicitHeight * 1.5 - verticalAlignment: Text.AlignTop - text: title - color: Constants.blue - font.pixelSize: Constants.header_font_size - elide: Text.ElideRight - } - - Rectangle { - width: parent.width - height: Utils.dp(40) - visible: repeater.count < 1 - Text { - id: emptyText - anchors.verticalCenter: parent.verticalCenter - width: parent.width - font.pixelSize: Constants.normal_font_size - text: qsTr("No data requested") - } - Rectangle { - anchors.top: parent.bottom - anchors.topMargin: -height - height: 1 - width: parent.width - color: Constants.grey - } - } - - 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: (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 - } - - Rectangle { - 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 deleted file mode 100644 index d34b5d6..0000000 --- a/resources/qml/identify/+android/IdentifyViewContent.qml +++ /dev/null @@ -1,120 +0,0 @@ -import QtQuick 2.5 - -import ".." -import "../global" - - -Item { - height: identifycolumn.height + Utils.dp(30) - - Column { - id: identifycolumn - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Constants.component_spacing - - spacing: Constants.component_spacing - - Pane { - - Item { - width: parent.width - height: providerEntries.height - - 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 - } - } - - 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") - onClicked: { - if (applicationModel.currentWorkflow === "") { - selfAuthenticationModel.startWorkflow(); - } - else if (applicationModel.currentWorkflow === "authentication") { - chatModel.transferAccessRights() - numberModel.continueWorkflow() - } - } - } - - Pane { - width: parent.width - - 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 - } - - DataGroup { - title: qsTr("Optional Data") - chat: chatModel.optional - } - } - } -} diff --git a/resources/qml/identify/+android/IdentifyViewHeader.qml b/resources/qml/identify/+android/IdentifyViewHeader.qml deleted file mode 100644 index d51a2d4..0000000 --- a/resources/qml/identify/+android/IdentifyViewHeader.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -Item { - id: header - /* this is interpreted by the SectionPage component */ - readonly property real titleBarOpacity: shadow.opacity === 1 ? 1 : 0 - - Image { - id: dna - width: parent.width - source: "qrc:///images/iOS/Header-Ausweisapp@3x.png" - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.bottomMargin: (parent.height - 2 * Constants.titlebar_height) * transition() - - function transition() { - return Math.min(1, contentY / Constants.titlebar_height) - } - - Rectangle { - id: shadow - anchors.fill: parent - color: Constants.blue - opacity: Math.min(1, 0.5 + parent.transition() * 0.5) - } - } - - Item { - id: information - height: Math.max(npa.height, text.height) - anchors.margins: Constants.component_spacing - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - - Image { - id: npa - anchors.left: parent.left - anchors.verticalCenter: information.verticalCenter - - height: Utils.dp(60) - width: height - source: "qrc:///images/npa.svg" - } - Text { - id: text - anchors.verticalCenter: npa.verticalCenter - anchors.left: npa.right - 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) - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - } - } -} diff --git a/resources/qml/identify/CertificateDescriptionPage.qml b/resources/qml/identify/CertificateDescriptionPage.qml deleted file mode 100644 index cc22eef..0000000 --- a/resources/qml/identify/CertificateDescriptionPage.qml +++ /dev/null @@ -1,54 +0,0 @@ -import QtQml.Models 2.2 -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - -SectionPage -{ - id: root - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: name; font.bold: true } - - property string name - - content: Item - { - height: pane.height + 2 * Constants.component_spacing - width: root.width - - Column - { - anchors.fill: parent - anchors.margins: Constants.component_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 - } - - 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 deleted file mode 100644 index 1b0470e..0000000 --- a/resources/qml/identify/DataGroup.qml +++ /dev/null @@ -1,102 +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" - - -Item { - property string title - property var chat - - width: parent.width - height: childrenRect.height - visible: repeater.count > 0 - - Text { - id: header - anchors.left: parent.left - anchors.leftMargin: Utils.dp(20) - - height: Utils.dp(20) - verticalAlignment: Text.AlignVCenter - text: title - color: Constants.grey - font.pixelSize: Constants.header_font_size - font.capitalization: Font.AllUppercase - elide: Text.ElideRight - } - - Column { - id: column - anchors.top: header.bottom - width: parent.width - - Repeater { - id: repeater - model: chat - - Rectangle { - width: parent.width - height: Utils.dp(40) - radius: 3 - color: "white" - Text { - id: dataGroup - 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: Constants.normal_font_size - wrapMode: Text.WordWrap - text: name - } - Rectangle { - anchors.top: parent.bottom - anchors.topMargin: -height - height: 1 - anchors.left: dataGroup.left - anchors.right: dataGroup.right - color: Constants.grey - } - GCheckBox { - id: checkBox - anchors.right: parent.right - anchors.rightMargin: Utils.dp(20) - anchors.verticalCenter: parent.verticalCenter - visible: optional - checked: selected - } - - MouseArea { - anchors.fill: parent - enabled: optional - onClicked: selected = !selected - Rectangle { - anchors.fill: parent - color: Constants.grey - opacity: parent.pressed ? 0.5 : 0 - Behavior on opacity { NumberAnimation { duration: 100 } } - } - } - } - } - } - Rectangle { - anchors.top: column.top - height: 1 - width: column.width - color: Constants.grey - } - Rectangle { - anchors.top: column.bottom - anchors.topMargin: -height - height: 1 - width: column.width - color: Constants.grey - } -} diff --git a/resources/qml/identify/IdentifyController.qml b/resources/qml/identify/IdentifyController.qml deleted file mode 100644 index b0b8057..0000000 --- a/resources/qml/identify/IdentifyController.qml +++ /dev/null @@ -1,131 +0,0 @@ -import QtQuick 2.5 - -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 - onFireCurrentStateChanged: { - switch (authModel.currentState) { - case "": - break; - case "StateGetTcToken": - enterPinView.state = "INITIAL" - navBar.lockedAndHidden = true - navBar.state = "identify" - navBar.currentIndex = 0 - identifyWorkflow.state = "initial" - break - case "StateEditAccessRights": - if (applicationModel.currentWorkflow === "selfauthentication") { - identifyView.push(identifyWorkflow) - chatModel.transferAccessRights() - 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": - identifyView.push(identifyWorkflow) - setIdentifyWorkflowStateAndContinue("connect") - break - case "StateSelectBluetoothReader": - identifyView.push(identifyWorkflow) - setIdentifyWorkflowState("connect") - if (applicationModel.bluetoothEnabled && !applicationModel.locationPermissionRequired) { - numberModel.continueWorkflow() - } - break - case "StateConnectCard": - setIdentifyWorkflowStateAndContinue("card") - break - case "StateUpdateRetryCounter": - setIdentifyWorkflowStateAndContinue("updateretrycounter") - break - case "StateEstablishPaceCan": - setIdentifyWorkflowStateAndRequestInput("identify_entercan", "CAN") - break - 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 { - numberModel.continueWorkflow() - titleBar.reset() - identifyView.pop(null) - navBar.lockedAndHidden = false - } - } - break - default: - numberModel.continueWorkflow() - } - } - } - - function setIdentifyWorkflowState(pState) { - identifyWorkflow.state = statePrefix + pState - } - - function setIdentifyWorkflowStateAndContinue(pState) { - setIdentifyWorkflowState(pState); - numberModel.continueWorkflow() - } - - function setIdentifyWorkflowStateAndRequestInput(pState, pInput) { - identifyWorkflow.state = statePrefix + pState - if (authModel.isBasicReader()) { - identifyView.push(enterPinView, {state: pInput}) - } else { - numberModel.continueWorkflow() - } - } -} diff --git a/resources/qml/identify/IdentifyView.qml b/resources/qml/identify/IdentifyView.qml deleted file mode 100644 index eae8b83..0000000 --- a/resources/qml/identify/IdentifyView.qml +++ /dev/null @@ -1,84 +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" - -SectionPage -{ - id: identifyEditChatView - leftTitleBarAction: TitleBarMenuAction { - state: applicationModel.currentWorkflow === "authentication" ? "cancel" : "" - onClicked: authModel.cancelWorkflow() - } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } - - header: IdentifyViewHeader { - height: identifyEditChatView.height * 0.4 - width: identifyEditChatView.width - } - content: IdentifyViewContent { - width: identifyEditChatView.width - } - - IdentifyController { - id: identifyController - } - - SelfAuthenticationData { - id: selfAuthenticationData - visible: false - } - - IdentifyWorkflow { - id: identifyWorkflow - visible: false - } - - EnterPinView { - id: enterPinView - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify") } - visible: false - - onPinEntered: { - numberModel.continueWorkflow() - identifyView.push(identifyProgressView) - } - } - - ProgressView { - id: identifyProgressView - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } - visible: false - text: qsTr("Processing") - 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: { - numberModel.continueWorkflow() - titleBar.reset() - identifyView.pop(null) - navBar.lockedAndHidden = false - } - visible: false - } -} diff --git a/resources/qml/identify/IdentifyViewContent.qml b/resources/qml/identify/IdentifyViewContent.qml deleted file mode 100644 index 1cb328b..0000000 --- a/resources/qml/identify/IdentifyViewContent.qml +++ /dev/null @@ -1,48 +0,0 @@ -import QtQuick 2.5 - -import ".." -import "../global" - - -Column{ - spacing: Utils.dp(30) - - Column { - width: parent.width - ProviderInfoSection { - imageSource: "qrc:///images/provider/information.svg" - title: qsTr("Service provider") - name: certificateDescriptionModel.subjectName - SeparatorLine {} - } - ProviderInfoSection { - imageSource: "qrc:///images/provider/purpose.svg" - title: qsTr("Purpose for reading out requested data") - name: certificateDescriptionModel.purpose - showForwardAction: false - SeparatorLine { anchors.bottom: parent.bottom } - } - } - Button { - anchors.horizontalCenter: parent.horizontalCenter - text: qsTr("Identify now") - onClicked: { - if (applicationModel.currentWorkflow === "") { - selfAuthenticationModel.startWorkflow(); - } - else if (applicationModel.currentWorkflow === "authentication") { - chatModel.transferAccessRights() - numberModel.continueWorkflow() - } - } - } - - DataGroup{ - title: qsTr("Required Data") - chat: chatModel.required - } - DataGroup{ - title: qsTr("Optional Data") - chat: chatModel.optional - } -} diff --git a/resources/qml/identify/IdentifyViewHeader.qml b/resources/qml/identify/IdentifyViewHeader.qml deleted file mode 100644 index 6ca24a5..0000000 --- a/resources/qml/identify/IdentifyViewHeader.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -Rectangle { - - width: parent.width - height: parent.height - - color: Constants.background_color - - Image { - id: dna - width: parent.width - height: parent.height * 0.7 - source: "qrc:///images/iOS/Header-Ausweisapp@3x.png" - fillMode: Image.PreserveAspectCrop - } - - Item { - id: information - anchors.left: dna.left - anchors.bottom: dna.bottom - - width: parent.width - height: parent.height * 0.2 - - Image { - id: npaIco - anchors.left: information.left - anchors.leftMargin: Utils.dp(15) - - height: Utils.dp(50) - width: height - source: "qrc:///images/npa.svg" - fillMode: Image.Stretch - } - - Text { - id: title - - anchors.top: npaIco.top - anchors.left: npaIco.right - anchors.leftMargin: Utils.dp(10) - anchors.right: parent.right - anchors.rightMargin: Utils.dp(5) - - text: applicationModel.currentWorkflow !== "authentication" ? qsTr("Hello, here you have the") : qsTr("Hello,") - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - } - - Text { - id: description - - anchors.top: title.bottom - anchors.topMargin: Utils.dp(5) - anchors.left: npaIco.right - anchors.leftMargin: Utils.dp(10) - anchors.right: parent.right - anchors.rightMargin: Utils.dp(5) - - 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) - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - } - } -} diff --git a/resources/qml/identify/IdentifyWorkflow.qml b/resources/qml/identify/IdentifyWorkflow.qml deleted file mode 100644 index e229d48..0000000 --- a/resources/qml/identify/IdentifyWorkflow.qml +++ /dev/null @@ -1,35 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "../" -import "../global" - -SectionPage -{ - id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: authModel.cancelWorkflow() } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } - - NfcWorkflow - { - anchors.fill: parent - state: parent.state - visible: parent.state.indexOf("nfc_") === 0 - onAbortNfc: { - identifyController.readerType = "BLUETOOTH" - authModel.abortCardSelection() - } - } - - - BluetoothWorkflow - { - 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 deleted file mode 100644 index c78246f..0000000 --- a/resources/qml/identify/SelfAuthenticationData.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick 2.7 - -import "../" -import "../global" - -SectionPage { - id: root - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: root.close() } - headerTitleBarAction: TitleBarAction { text: qsTr("Identify"); font.bold: true } - - function close() { - numberModel.continueWorkflow() - pop(null) - navBar.lockedAndHidden = false - } - - content: Item { - height: content.height + okButton.height + Constants.component_spacing - width: root.width - - Column { - id: content - width: parent.width - padding: Constants.component_spacing - spacing: Constants.component_spacing - - 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 - } - } - - 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 - Repeater { - model: selfAuthenticationModel - - LabeledText { - label: name - text: value === "" ? "---" : value - width: (pane.width - 2 * Constants.pane_padding - (grid.columns - 1) * grid.spacing) / grid.columns - } - } - } - } - } - } - - 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 61ae09f..3380b8d 100644 --- a/resources/qml/main.qml +++ b/resources/qml/main.qml @@ -4,7 +4,10 @@ import QtQuick.Controls 2.0 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 -import "global" +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Navigation 1.0 +import Governikus.SplashScreen 1.0 ApplicationWindow { id: appWindow @@ -14,10 +17,9 @@ 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" @@ -26,18 +28,19 @@ ApplicationWindow { header: TitleBar { id: titleBar - visible: splasScreenClosed + visible: !splashScreen.visible + + titleBarOpacity: contentArea.visibleItem && contentArea.visibleItem.stack.currentItem ? contentArea.visibleItem.stack.currentItem.titleBarOpacity : 1 + + property var currentSectionPage: if (contentArea) contentArea.currentSectionPage + + leftAction: if (currentSectionPage) currentSectionPage.leftTitleBarAction + titleItem: if (currentSectionPage) currentSectionPage.headerTitleBarAction + rightAction: if (currentSectionPage) currentSectionPage.rightTitleBarAction + subTitleBarAction: if (currentSectionPage) currentSectionPage.subTitleBarAction + color: if (currentSectionPage) currentSectionPage.titleBarColor - titleBarOpacity: contentArea.getVisibleItem() && contentArea.getVisibleItem().stack.currentItem ? contentArea.getVisibleItem().stack.currentItem.titleBarOpacity : 1 - function pushTabBarSubView(sectionPage) { - if (sectionPage) { - titleBar.push(sectionPage.leftTitleBarAction, - sectionPage.headerTitleBarAction, - sectionPage.rightTitleBarAction, - sectionPage.titleBarColor) - } - } } overlay.modal: Item { @@ -55,7 +58,7 @@ ApplicationWindow { } } - ContentArea { + ContentAreaLoader { id: contentArea state: navBar.state anchors.left: PlatformConstants.leftNavigation ? navBar.right : parent.left @@ -66,7 +69,7 @@ ApplicationWindow { Navigation { id: navBar - visible: splasScreenClosed + visible: !splashScreen.visible anchors.left: parent.left anchors.top: PlatformConstants.leftNavigation ? parent.top : undefined anchors.right: PlatformConstants.bottomNavigation ? parent.right : undefined @@ -74,11 +77,9 @@ ApplicationWindow { } onClosing: { - var visibleItem = contentArea.getVisibleItem() - - if (visibleItem) + if (contentArea.visibleItem) { - var activeStackView = visibleItem.stack + var activeStackView = contentArea.visibleItem.stack if (activeStackView.depth <= 1 && (!activeStackView.currentItem.leftTitleBarAction || activeStackView.currentItem.leftTitleBarAction.state === "")) { var currentTime = new Date().getTime(); @@ -95,7 +96,7 @@ ApplicationWindow { navBar.close() } else { - activeStackView.currentItem.leftTitleBarAction.clicked() + activeStackView.currentItem.leftTitleBarAction.clicked(undefined) } } } @@ -103,42 +104,16 @@ ApplicationWindow { close.accepted = false } - Rectangle { + SplashScreen { 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 + property alias ready: contentArea.ready + onReadyChanged: { + splashScreen.hide() if (!applicationModel.currentWorkflow) { navBar.lockedAndHidden = false } - }) - timer.start(); + } } } diff --git a/resources/qml/more/DeveloperView.qml b/resources/qml/more/DeveloperView.qml deleted file mode 100644 index 2086f8c..0000000 --- a/resources/qml/more/DeveloperView.qml +++ /dev/null @@ -1,97 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 - -import "../" -import "../global" - - -SectionPage { - id: root - leftTitleBarAction: TitleBarMenuAction { state: stack.depth > 1 ? "back" : ""; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: qsTr("Developer options"); font.bold: true } - - content: Item - { - height: pane.height + 2 * Constants.component_spacing - width: root.width - - Column - { - anchors.fill: parent - anchors.margins: Constants.component_spacing - - Pane { - id: pane - - 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 - - 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 } - } - } - } - - GroupBox { - title: "Use test uri for selfauthentication:" - height: implicitHeight - width: implicitWidth - - 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 } - } - } - } - } - } - } -} diff --git a/resources/qml/more/Feedback.qml b/resources/qml/more/Feedback.qml deleted file mode 100644 index b873622..0000000 --- a/resources/qml/more/Feedback.qml +++ /dev/null @@ -1,112 +0,0 @@ -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 deleted file mode 100644 index e9d01bc..0000000 --- a/resources/qml/more/Information.qml +++ /dev/null @@ -1,118 +0,0 @@ -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 deleted file mode 100644 index 13fc95e..0000000 --- a/resources/qml/more/MoreView.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -SectionPage { - headerTitleBarAction: TitleBarAction { text: qsTr("More"); font.bold: true } - - - Rectangle { - anchors.fill: menu - color: "white" - } - - Column { - id: menu - width: parent.width - anchors.top: parent.top - anchors.topMargin: Utils.dp(40) - - MoreViewMenuItem { - text: qsTr("Version information") - imageSource: "qrc:///images/npa.svg" - onClicked: push(versionInformationPage) - } - - MoreViewMenuItem { - text: qsTr("FAQ") - 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/iOS/more/icon_mehr_fragen.svg" - onClicked: push(supportPage) - } - - MoreViewMenuItem { - text: qsTr("Rate app"); - 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") { - Qt.openUrlExternally("market://details?id=com.governikus.ausweisapp2") - } - else if (Qt.platform.os === "ios") { - Qt.openUrlExternally("https://www.ausweisapp.bund.de/en/questions-and-answers/evaluate-us/") - } - } - } - - MoreViewMenuItem { - text: qsTr("Share"); - 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"), qsTr("Share with")) - } - - MoreViewMenuItem { - visible: plugin.developerBuild - text: qsTr("Developer options") - imageSource: "qrc:///images/zahnraeder.svg" - onClicked: push(developerView) - } - } - - Rectangle { - anchors.top: menu.top - height: 1; width: parent.width - color: Constants.grey - } - Rectangle { - anchors.bottom: menu.bottom - height: 1; width: parent.width - color: Constants.grey - } - - VersionInformation { - id: versionInformationPage - visible: false - } - - SupportView { - id: supportPage - visible: false - } - - DeveloperView { - id: developerView - visible: false - } -} diff --git a/resources/qml/more/MoreViewMenuItem.qml b/resources/qml/more/MoreViewMenuItem.qml deleted file mode 100644 index bdc3c82..0000000 --- a/resources/qml/more/MoreViewMenuItem.qml +++ /dev/null @@ -1,49 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -Item { - property alias text: textItem.text - property alias imageSource: imageItem.source - signal clicked - height: Utils.dp(40) - width: parent.width - - Image { - id: imageItem - fillMode: Image.PreserveAspectFit - height: parent.height * 0.6 - width: height - anchors.left: parent.left - anchors.leftMargin: Utils.dp(15) - anchors.verticalCenter: parent.verticalCenter - } - - Text { - id: textItem - height: parent.height - verticalAlignment: Text.AlignVCenter - anchors.left: imageItem.right - anchors.leftMargin: Utils.dp(10) - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Utils.dp(16) - } - MouseArea { - anchors.fill: parent - onClicked: parent.clicked() - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: textItem.left - anchors.right: parent.right - height: 1 - color: Constants.grey - } - -} - diff --git a/resources/qml/more/SupportView.qml b/resources/qml/more/SupportView.qml deleted file mode 100644 index 9461242..0000000 --- a/resources/qml/more/SupportView.qml +++ /dev/null @@ -1,49 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -SectionPage { - id: root - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: qsTr("Support"); font.bold: true } - - ListModel { - id: supportModel - ListElement { - label: qsTr("Via Email") - text: qsTr("You can reach our email support at support@ausweisapp.de") - } - ListElement { - label: qsTr("Via Phone") - text: qsTr("You can reach our phone support at +49 1805 348 743 (*14 ct./Minute from German landlines, mobile price may vary)") - } - ListElement { - label: qsTr("Support availability") - text: qsTr("Support is available from 9.00 to 17.00 on Monday-Friday, except on national holidays.") - } - } - - content: Column{ - width: root.width - Item { width: parent.width; height: Constants.titlebar_height } - Pane { - id: pane - width: root.width - height: childrenRect.height - Repeater { - model: supportModel - - LabeledText { - id: delegate - label: model.label - text: model.text - width: pane.width - } - } - } - } -} diff --git a/resources/qml/more/VersionInformation.qml b/resources/qml/more/VersionInformation.qml deleted file mode 100644 index d3e5654..0000000 --- a/resources/qml/more/VersionInformation.qml +++ /dev/null @@ -1,41 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - - -SectionPage -{ - id: root - leftTitleBarAction: TitleBarMenuAction { state: stack.depth > 1 ? "back" : ""; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: qsTr("Version Information"); font.bold: true } - - content: Item - { - height: pane.height + 2 * Constants.component_spacing - width: root.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 deleted file mode 100644 index b6a98b3..0000000 --- a/resources/qml/pin/+android/PinViewContent.qml +++ /dev/null @@ -1,63 +0,0 @@ -import QtQuick 2.5 - -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.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 Management") - - anchors.top: pinIcon.bottom - anchors.topMargin: spacing - anchors.horizontalCenter: parent.horizontalCenter - - font.pixelSize: Constants.header_font_size - color: Constants.blue - } - - Text { - id: pinDesc - - anchors.margins: Utils.dp(10) - anchors.top: pinHeader.bottom - anchors.topMargin: Utils.dp(10) - anchors.horizontalCenter: parent.horizontalCenter - - 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 - width: parent.width - Utils.dp(60) - wrapMode: Text.WordWrap - } - - Button { - id: govButton - - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Utils.dp(30) - - text: qsTr("Change PIN now") - onClicked: changePinModel.startWorkflow() - } -} diff --git a/resources/qml/pin/ChangePinController.qml b/resources/qml/pin/ChangePinController.qml deleted file mode 100644 index 8813ba5..0000000 --- a/resources/qml/pin/ChangePinController.qml +++ /dev/null @@ -1,96 +0,0 @@ -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 - - Connections { - target: changePinModel - onFireCurrentStateChanged: { - switch (changePinModel.currentState) { - case "": - break - case "StateSelectReaderType": - 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 = "BLUETOOTH" - setPinWorkflowState("connect") - if (applicationModel.bluetoothEnabled && !applicationModel.locationPermissionRequired) { - numberModel.continueWorkflow() - } - break - case "StateSelectNfcReader": - readerType = "NFC" - setPinWorkflowStateAndContinue("connect") - break - case "StateConnectCard": - setPinWorkflowStateAndContinue("card") - break - case "StateUpdateRetryCounter": - setPinWorkflowStateAndContinue("updateretrycounter") - break - case "StateEstablishPacePuk": - setPinWorkflowStateAndRequestInput("enterpuk", "PUK") - break - case "StateEstablishPaceCan": - setPinWorkflowStateAndRequestInput("changepin_entercan", "CAN") - break - case "StateEstablishPacePin": - setPinWorkflowStateAndRequestInput("changepin_enterpin", "PIN_OR_TRANSPORT_PIN") - break - 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: - numberModel.continueWorkflow() - } - - } - } - - function setPinWorkflowState(pState) { - pinWorkflow.state = statePrefix + pState - } - - function setPinWorkflowStateAndContinue(pState) { - setPinWorkflowState(pState) - numberModel.continueWorkflow() - } - - function setPinWorkflowStateAndRequestInput(pState, pInput) { - pinWorkflow.state = statePrefix + pState - if (changePinModel.isBasicReader()) { - pinView.push(enterPinView, {state: pInput}) - } else { - numberModel.continueWorkflow() - } - } -} diff --git a/resources/qml/pin/PinView.qml b/resources/qml/pin/PinView.qml deleted file mode 100644 index 95c4270..0000000 --- a/resources/qml/pin/PinView.qml +++ /dev/null @@ -1,63 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 -import QtQuick.Controls.Styles 1.4 - -import QtQml.StateMachine 1.0 as DSM - -import "../" -import "../global" - -SectionPage { - id: baseItem - - disableFlicking: true - headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } - - ChangePinController { - id: changePinControllern - } - - content: PinViewContent { - height: baseItem.height - width: baseItem.width - } - - PinWorkflow { - id: pinWorkflow - visible: false - } - - ResultView { - id: pinResult - headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } - isError: !changePinModel.changedPinSuccessfully - text: changePinModel.resultString - onClicked: { - numberModel.continueWorkflow() - pop(null) - navBar.lockedAndHidden = false - } - visible: false - } - - 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 Management"); font.bold: true } - visible: false - text: qsTr("Processing...") - } -} diff --git a/resources/qml/pin/PinViewContent.qml b/resources/qml/pin/PinViewContent.qml deleted file mode 100644 index 195cc8c..0000000 --- a/resources/qml/pin/PinViewContent.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick 2.5 - -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("PIN Management") - - anchors.top: parent.top - anchors.topMargin: spacing - anchors.horizontalCenter: parent.horizontalCenter - - font.pixelSize: Constants.header_font_size - color: Constants.blue - } - - Text { - id: pinDesc - - width: parent.width * 0.9 - - 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 - } - - Image { - id: pinIcon - - fillMode: Image.PreserveAspectFit - smooth: true - source: "qrc:///images/icon_Pin.svg" - sourceSize.height: 256 - - width: parent.width - - anchors.top: pinDesc.bottom - anchors.topMargin: spacing - anchors.horizontalCenter: parent.horizontalCenter - } - - Button { - id: govButton - - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Utils.dp(30) - - text: qsTr("Change PIN now") - onClicked: changePinModel.startWorkflow() - } -} diff --git a/resources/qml/pin/PinWorkflow.qml b/resources/qml/pin/PinWorkflow.qml deleted file mode 100644 index 6908372..0000000 --- a/resources/qml/pin/PinWorkflow.qml +++ /dev/null @@ -1,34 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "../" - -SectionPage -{ - id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "cancel"; onClicked: {changePinModel.cancelWorkflow()} } - headerTitleBarAction: TitleBarAction { text: qsTr("PIN Management"); font.bold: true } - - NfcWorkflow - { - anchors.fill: parent - state: parent.state - visible: parent.state.indexOf("nfc_") === 0 - onAbortNfc: { - changePinControllern.readerType = "BLUETOOTH" - changePinModel.abortCardSelection() - } - } - - - BluetoothWorkflow - { - 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/AdditionalResultsItem.qml b/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml deleted file mode 100644 index 7841fae..0000000 --- a/resources/qml/provider/+android/+tablet/AdditionalResultsItem.qml +++ /dev/null @@ -1,70 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 - -import "../global" - -Rectangle { - id: baseItem - height: column.height - - property int headerHeight: 0 - property int textHeight: 0 - property int footerHeight: 0 - property int totalHits: providerModel.additionalResultCount - - 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 - } - } - - 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 deleted file mode 100644 index 93115c6..0000000 --- a/resources/qml/provider/+android/+tablet/CategoryCheckbox.qml +++ /dev/null @@ -1,48 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 - -import "../../../global" - -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.normal_font_size - anchors.verticalCenter: parent.verticalCenter - } - - GCheckBox { - id: checkbox - anchors.verticalCenter: parent.verticalCenter - visible: true - checked: providerModel.categories.indexOf(baseItem.category) !== -1 - } - } - - MouseArea { - anchors.fill: parent - onClicked: providerModel.updateCategorySelection(category, !checkbox.checked) - } -} diff --git a/resources/qml/provider/+android/+tablet/ProviderCard.qml b/resources/qml/provider/+android/+tablet/ProviderCard.qml deleted file mode 100644 index 8ea4121..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderCard.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 - -import "../../../global" - -Rectangle { - id: baseItem - height: column.height - color: Category.displayColor(providerModel.providerCategory) - - property int headerHeight: 0 - property int textHeight: 0 - property int footerHeight: 0 - - property var providerModel: null - property var pushFunction: function(model) {} - - Column { - id: column - width: baseItem.width - - Image { - source: providerModel.providerImage !== "" ? providerModel.providerImage : - Category.backgroundImageSource(providerModel.providerCategory) - asynchronous: true - height: baseItem.headerHeight - width: parent.width - fillMode: Image.PreserveAspectCrop - anchors.horizontalCenter: parent.horizontalCenter - } - - ProviderCardNameRow { - height: baseItem.textHeight - providerName: providerModel.providerLongName !== "" ? providerModel.providerLongName : providerModel.providerShortName - headerIcon: providerModel.providerIcon - providerCategory: providerModel.providerCategory - } - - Rectangle { - color: Category.displayColor(providerModel.providerCategory) - height: baseItem.footerHeight - width: parent.width - - Text { - text: providerModel.providerHomepageBase - - anchors.centerIn: parent - - leftPadding: Constants.pane_padding - rightPadding: Constants.pane_padding - elide: Text.ElideRight - maximumLineCount: 1 - - font.pixelSize: Constants.normal_font_size - color: "white" - - scale: Math.min(1, parent.width / (contentWidth + leftPadding + rightPadding)) - } - } - } - - MouseArea { - anchors.fill: parent - onClicked: baseItem.pushFunction(providerModel) - } -} diff --git a/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml b/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml deleted file mode 100644 index f09ca6a..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderCardNameRow.qml +++ /dev/null @@ -1,48 +0,0 @@ -import QtQuick 2.6 - -import "../../../global" - - -Rectangle { - readonly property int padding: Constants.pane_padding / 2 - - property string providerName - property string headerIcon - property int nameHeight - property string providerCategory - - width: parent.width - - Image { - id: image - source: parent.headerIcon !== "" ? - parent.headerIcon : - Category.buttonImageSource(parent.providerCategory) - asynchronous: true - height: parent.height - width: height - fillMode: Image.PreserveAspectFit - anchors.top: parent.top - anchors.topMargin: -parent.padding - anchors.left: parent.left - anchors.leftMargin: parent.padding - } - - 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 deleted file mode 100644 index 8cdcbd2..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderContactInfo.qml +++ /dev/null @@ -1,55 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 - -import "../global" - - -Rectangle { - id: baseItem - property alias contactModel: contactListView.model - - onHeightChanged: { info.scalingAllowed = true; info.updateScaleFactor() } - onVisibleChanged: info.scalingAllowed = visible - - Column { - 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 { - 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/provider/+android/+tablet/ProviderContactInfoItem.qml b/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml deleted file mode 100644 index f44f1ac..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderContactInfoItem.qml +++ /dev/null @@ -1,45 +0,0 @@ -import QtQuick 2.6 - -import "../global" - - -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/provider/+android/+tablet/ProviderDetailButtonBar.qml b/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml deleted file mode 100644 index 1f31e43..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailButtonBar.qml +++ /dev/null @@ -1,44 +0,0 @@ -import QtQuick 2.6 - -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 - - 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") - 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/provider/+android/+tablet/ProviderDetailDescription.qml b/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml deleted file mode 100644 index f901d82..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailDescription.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick 2.6 - -import "../global" - - -Column { - id: baseItem - spacing: Constants.pane_spacing - - property string description: "" - - Text { - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - text: qsTr("Description") - } - - 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 deleted file mode 100644 index f61e750..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistory.qml +++ /dev/null @@ -1,44 +0,0 @@ -import QtQuick 2.6 - -import "../global" - - -Column { - id: baseItem - spacing: Constants.pane_spacing - - property var openHistoryInfoFunc: function() { - } - - readonly property int historyItemHeight: Utils.dp(66) - readonly property int historyItemMargin: Utils.dp(8) - - Text { - id: headerText - - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - text: qsTr("History") - } - - Repeater { - model: historyModel.nameFilter - - ProviderDetailHistoryItem { - itemHeight: baseItem.historyItemHeight - itemMargin: baseItem.historyItemMargin - - width: parent.width - - providerName: subject - providerPostalAddress: providerPostalAddress - dateTime: model.dateTime - infoText: qsTr("Purpose for reading out requested data") - purposeText: purpose - requestedDataText: requestedData - termsOfUsageText: termsOfUsage - - openInfoFunction: baseItem.openHistoryInfoFunc - } - } -} diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml deleted file mode 100644 index cb283c4..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryInfo.qml +++ /dev/null @@ -1,134 +0,0 @@ -import QtQuick 2.6 - -import ".." -import "../global" - - -Rectangle { - id: baseItem - - property string providerName: "" - property string providerPostalAddress: "" - property string purposeText: "" - property string requestedDataText: "" - property string termsOfUsageText: "" - property string internalState: "off" - - color: "transparent" - - Rectangle { - anchors.fill: baseItem - - color: "black" - opacity: 0.4 - } - - Flickable { - anchors.fill: baseItem - anchors.margins: Constants.component_spacing - contentHeight: infoRow.height - - onContentYChanged: { - if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} - } - - Row { - id: infoRow - height: childrenRect.height - spacing: Constants.component_spacing - - property int maxContentHeight: Math.max(leftPane.contentHeight, rightPane.contentHeight) - - Column { - width: baseItem.width / 3 - - Pane { - id: leftPane - height: childrenRect.height + verticalSpace - - readonly property int contentHeight: childrenRect.height - property int verticalSpace: infoRow.maxContentHeight - contentHeight - - ProviderInfoSection { - imageSource: "qrc:///images/provider/information.svg" - title: qsTr("Service provider") - name: baseItem.providerName - } - - ProviderInfoSection { - imageSource: "qrc:///images/provider/purpose.svg" - title: qsTr("Purpose for reading out requested data") - name: baseItem.purposeText - } - - Text { - id: readDataTitle - width: parent.width - font.pixelSize: Constants.header_font_size - color: PlatformConstants.blue_primary - text: qsTr("Read data") - } - - Column { - id: infoTable - - width: parent.width - 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 - } - } - } - } - } - } - - Column { - width: baseItem.width / 3 * 2 - 3 * Constants.component_spacing - - Pane { - id: rightPane - height: childrenRect.height + verticalSpace - - 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 - } - - Text { - id: termsOfUsageTextItem - - text: baseItem.termsOfUsageText - width: parent.width - elide: Text.ElideRight - wrapMode: Text.Wrap - font.pixelSize: Constants.normal_font_size - } - } - } - } - } -} diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml b/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml deleted file mode 100644 index 3e438be..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailHistoryItem.qml +++ /dev/null @@ -1,119 +0,0 @@ -import QtQuick 2.6 - -import "../global" - - -Item { - id: baseItem - - readonly property color backgroundColor: PlatformConstants.blue - readonly property int iconWidth: Utils.dp(18) - - property string providerName: "" - property string providerPostalAddress: "" - property var dateTime: "" - property string infoText: "" - property string purposeText: "" - property string requestedDataText: "" - property string termsOfUsageText: "" - property int itemHeight: 0 - property int itemMargin: 0 - property int lineHeight: itemHeight / 3 - property var openInfoFunction: function () {} - - height: itemHeight + 2 * itemMargin - - ProviderStyle { - id: providerStyle - - visible: false - } - - Rectangle { - anchors.fill: baseItem - color: "white" - } - - Column { - id: textColumn - - height: baseItem.itemHeight - width: baseItem.width - baseItem.iconWidth - - anchors.left: baseItem.left - anchors.top: baseItem.top - anchors.topMargin: baseItem.itemMargin - - Text { - height: baseItem.lineHeight - 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")) - } - } - - LabeledText { - label: infoText - text: !!purposeText ? purposeText : qsTr("Touch for more details") - width: parent.width - height: baseItem.lineHeight - } - } - - Item { - id: detailsLink - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - height: width - width: iconWidth - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - height: width - - border.color: providerStyle.providerListDetailsLinkBorder - border.width: 1 - radius: width - - color: providerStyle.providerListDetailsLinkBackground - Text { - anchors.centerIn: parent - - text: "i" - font.bold: providerStyle.providerListDetailsLinkBold - color: providerStyle.providerListDetailsLinkColor - } - } - } - - MouseArea { - anchors.fill: baseItem - onClicked: baseItem.openInfoFunction({ - providerName: baseItem.providerName, - providerPostalAddress: baseItem.providerPostalAddress, - purposeText: baseItem.purposeText, - requestedDataText: baseItem.requestedDataText, - termsOfUsageText: baseItem.termsOfUsageText - }) - } -} diff --git a/resources/qml/provider/+android/+tablet/ProviderDetailView.qml b/resources/qml/provider/+android/+tablet/ProviderDetailView.qml deleted file mode 100644 index b4af925..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderDetailView.qml +++ /dev/null @@ -1,174 +0,0 @@ -import QtQuick 2.6 - -import "." -import ".." -import "../global" - - -SectionPage { - id: baseItem - readonly property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction { - state: "back" - onClicked: { - if (providerDetailsHistoryInfo.visible) { - providerDetailsHistoryInfo.visible = false - } - else { - pop() - } - } - } - 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 - - property alias historyModelItem: provider.modelItem - property alias providerModelItem: provider.modelItem - ProviderModelItem { - id: provider - } - - - content: Column { - id: mainContent - height: childrenRect.height + Constants.component_spacing - width: baseItem.width - - Row { - height: baseItem.height / 2 - width: parent.width - - 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 - } - } - } - - Row { - id: lowerRow - height: childrenRect.height - width: parent.width - - property int maxContentHeight: Math.max(leftPane.contentHeight + buttonBar.height, rightPane.contentHeight) - - Column { - id: leftColumn - width: lowerRow.width * 2 / 3 - spacing: Constants.pane_spacing - - ProviderDetailButtonBar { - id: buttonBar - selectedCategory: provider.category - providerIcon: provider.icon - address: provider.address - titleBarColor: baseItem.titleBarColor - } - - Pane { - id: leftPane - anchors.leftMargin: Constants.component_spacing - anchors.rightMargin: Constants.component_spacing - height: childrenRect.height - buttonBar.height + verticalSpace - - readonly property int contentHeight: childrenRect.height - property int verticalSpace: lowerRow.maxContentHeight - contentHeight - - ProviderDetailDescription { - id: descriptionData - width: parent.width - description: provider.longDescription - } - } - } - - 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 - } - } - } - } - } - - 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'] - } - - ProviderDetailHistoryInfo { - id: providerDetailsHistoryInfo - - height: parent.height - width: parent.width - - 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 deleted file mode 100644 index e3e3ee6..0000000 --- a/resources/qml/provider/+android/+tablet/ProviderView.qml +++ /dev/null @@ -1,172 +0,0 @@ -import QtQuick 2.6 - -import "../.." -import "../../.." -import "../../../global" - - -Item { - id: baseItem - - property TitleBarMenuAction leftTitleBarAction: TitleBarMenuAction {} - property TitleBarAction headerTitleBarAction: TitleBarAction { text: qsTr("Provider"); font.bold: true } - property Item rightTitleBarAction: SearchBar { - availableWidth: baseItem.width - onSearchTextChanged: providerModel.searchString = searchText - } - - property color titleBarColor: Constants.blue - - readonly property real titleBarOpacity: 1 - readonly property int headerHeight: Utils.dp(54) - readonly property int separatorHeight: Utils.dp(2) - - visible: false - - ProviderDetailView { - id: providerDetailView - visible: false - } - - function pushProviderDetails(model) { - historyModel.nameFilter.setProviderAddress(model.providerAddress) - push(providerDetailView, {providerModelItem: model}) - } - - Column { - id: content - - width: parent.width - - Rectangle { - - height: baseItem.headerHeight - width: parent.width - - color: "white" - - Row { - id: checkBoxesItem - - height: parent.height - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - - padding: Utils.dp(30) - spacing: Utils.dp(30) - - transformOrigin: Item.Center - scale: Math.min(parent.width / width, 1) - - 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") - } - } - } - - Rectangle { - height: baseItem.separatorHeight - width: parent.width - - color: PlatformConstants.grey_border - } - - Rectangle { - id: mainPane - - height: baseItem.height - (baseItem.headerHeight + baseItem.separatorHeight) - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - color: Constants.background_color - - Text { - id: noResultsText - - anchors.centerIn: mainPane - text: qsTr("No match found") - - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - visible: !flickable.visible - } - - Flickable { - id: flickable - anchors.fill: mainPane - clip: true - flickableDirection: Flickable.VerticalFlick - visible: grid.hasResults - - contentHeight: grid.height - contentWidth: parent.width - - onContentYChanged: { - if (contentY < 0) { contentY = 0 /* prevent flicking over the top */} - } - - Grid { - id: grid - 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 - 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 - - ProviderCard { - width: grid.cardWidth - headerHeight: width / 1.80 - textHeight: Utils.dp(64) - footerHeight: Utils.dp(30) - pushFunction: baseItem.pushProviderDetails - providerModel: model - } - } - - AdditionalResultsItem { - id: additionalResults - 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 deleted file mode 100644 index ee03ea4..0000000 --- a/resources/qml/provider/+android/ProviderDetailView.qml +++ /dev/null @@ -1,114 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 - -import "../" -import "../global" - -SectionPage { - id: baseItem - - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: provider.shortName } - titleBarColor: Category.displayColor(provider.category) - - property alias providerModelItem: provider.modelItem - ProviderModelItem { - id: provider - } - - - header: ProviderHeader { - id: ownHeader - width: baseItem.width - selectedProvider: provider - } - - content: Item { - height: swipeBar.height + swipeViewBackground.height + Constants.component_spacing - width: baseItem.width - - TabBar { - id: swipeBar - height: firstButton.implicitHeight - anchors.top: parent.top - anchors.topMargin: Constants.component_spacing - anchors.left: parent.left - anchors.right: parent.right - - currentIndex: swipeView.currentIndex - - 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 - elide: Text.ElideRight - opacity: enabled ? 1 : 0.3 - color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } -*/ - } - - 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 - elide: Text.ElideRight - opacity: enabled ? 1 : 0.3 - color: !parent.checked ? "black" : parent.pressed ? "black" : Constants.blue - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } -*/ - } - } - - Rectangle { - id: swipeViewBackground - anchors.top: swipeBar.bottom - anchors.horizontalCenter: swipeBar.horizontalCenter - height: swipeView.height + 2 * Constants.component_spacing - width: parent.width - - SwipeView { - id: swipeView - 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 { - id: providerText - text: !!provider.longDescription ? provider.longDescription : qsTr("Description not available") - horizontalAlignment: Text.AlignJustify - wrapMode: Text.WordWrap - font.pixelSize: Constants.normal_font_size - } - - ProviderContactTab { - id: providerInfo - contactModel: provider.contactModel - } - } - } - } -} diff --git a/resources/qml/provider/+android/ProviderStyle.qml b/resources/qml/provider/+android/ProviderStyle.qml deleted file mode 100644 index a862b17..0000000 --- a/resources/qml/provider/+android/ProviderStyle.qml +++ /dev/null @@ -1,38 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Item { - // ProviderViewHeader properties for ProviderView - readonly property bool showSearchBar: false - readonly property bool showHeaderButtonsInProviderView: true - readonly property string headerBackgroundInProviderView: "qrc:///images/provider/categoryIcons/General_bg.png" - - // Provider category list properties - readonly property int categoryFontPixelSize: Constants.titlebar_font_size - readonly property bool categoryFontBold: true - readonly property color categoryColor: Constants.accent_color - readonly property int leftIconMargin: Utils.dp(10) - readonly property int leftProviderListMargin: Utils.dp(20) - readonly property bool showCategoryRightArrow: false - - // Provider list item properties - readonly property int itemLeftMargin: Utils.dp(15) - readonly property color subjectTextColor: Constants.secondary_text - readonly property bool subjectTextFontBold: true - readonly property int addressTextFontSize: Utils.dp(12) - readonly property color addressTextColor: Constants.accent_color - readonly property double infoItemWidthFactor: 4.0 - - readonly property int providerListItemTopMargin: Utils.dp(0) - readonly property int providerListItemRightMargin: Utils.dp(0) - readonly property int providerListItemBottomMargin: Utils.dp(0) - - readonly property bool providerListItemsHaveBorder: true - - readonly property bool providerListDetailsLinkBold: true - readonly property color providerListDetailsLinkBorder: PlatformConstants.grey_light - readonly property color providerListDetailsLinkColor: Constants.primary_text - readonly property color providerListDetailsLinkBackground: PlatformConstants.grey_light - readonly property string providerListDetailsLinkPosition: "top" -} diff --git a/resources/qml/provider/+android/ProviderView.qml b/resources/qml/provider/+android/ProviderView.qml deleted file mode 100644 index 873cae9..0000000 --- a/resources/qml/provider/+android/ProviderView.qml +++ /dev/null @@ -1,114 +0,0 @@ -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 deleted file mode 100644 index 0fadff5..0000000 --- a/resources/qml/provider/+android/ProviderViewDelegate.qml +++ /dev/null @@ -1,131 +0,0 @@ -import QtQml.Models 2.2 -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - -Rectangle { - - ProviderStyle { - id: providerStyle - } - - id: baseItem - width: parent.width - height: Constants.provider_section_height - color: Constants.background_color - clip: true - - Rectangle { - id: background - color: "white" - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: providerStyle.providerListItemRightMargin - anchors.top: parent.top - anchors.topMargin: providerStyle.providerListItemTopMargin - anchors.bottom: parent.bottom - anchors.bottomMargin: providerStyle.providerListItemBottomMargin - - Item { - property int childrenHeight: subjectText.height + addressText.height - - id: contentItem - height: Constants.provider_section_height - anchors.verticalCenter: parent.verticalCenter - - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: providerStyle.itemLeftMargin - anchors.rightMargin: Utils.dp(15) - - property int detailsLinkWidth: height / providerStyle.infoItemWidthFactor - - Text { - id: subjectText - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: detailsLink.left - - anchors.topMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 - anchors.rightMargin: Utils.dp(5) - - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.normal_font_size - color: providerStyle.subjectTextColor - font.bold: providerStyle.subjectTextFontBold - elide: Text.ElideRight - text: display - } - - Text { - id: addressText - - anchors.top: subjectText.bottom - anchors.left: parent.left - anchors.right: detailsLink.left - - anchors.topMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 - anchors.bottomMargin: (Constants.provider_section_height - contentItem.childrenHeight) / 3 - - verticalAlignment: Text.AlignVCenter - font.pixelSize: providerStyle.addressTextFontSize - color: providerStyle.addressTextColor - elide: Text.ElideRight - text: providerAddressDomain - } - - Item { - id: detailsLink - anchors.right: parent.right - anchors.verticalCenter: providerStyle.providerListDetailsLinkPosition === "top" ? - subjectText.verticalCenter : - parent.verticalCenter - - anchors.margins: Utils.dp(5) - height: parent.height - width: contentItem.detailsLinkWidth - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - height: width - - border.color: providerStyle.providerListDetailsLinkBorder - border.width: 1 - radius: width - - color: providerStyle.providerListDetailsLinkBackground - - Text { - anchors.centerIn: parent - text: "i" - font.bold: providerStyle.providerListDetailsLinkBold - color: providerStyle.providerListDetailsLinkColor - } - } - } - } - } - - MouseArea { - anchors.fill: parent - onClicked: push(providerDetailView, {providerModelItem: model}) - } - - Rectangle { - width: parent.width - anchors.top: parent.bottom - anchors.topMargin: -height - anchors.leftMargin: providerStyle.itemLeftMargin - anchors.left: parent.left - anchors.right: parent.right - visible: providerStyle.providerListItemsHaveBorder - height: visible ? 1 : 0 - color: Constants.grey - } -} diff --git a/resources/qml/provider/+android/SearchBar.qml b/resources/qml/provider/+android/SearchBar.qml deleted file mode 100644 index 99683d2..0000000 --- a/resources/qml/provider/+android/SearchBar.qml +++ /dev/null @@ -1,67 +0,0 @@ -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/AdditionalResultsItem.qml b/resources/qml/provider/AdditionalResultsItem.qml deleted file mode 100644 index 9e38859..0000000 --- a/resources/qml/provider/AdditionalResultsItem.qml +++ /dev/null @@ -1,58 +0,0 @@ -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/DimmableTextButton.qml b/resources/qml/provider/DimmableTextButton.qml deleted file mode 100644 index 70296d8..0000000 --- a/resources/qml/provider/DimmableTextButton.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "../global" - -Label { - id: label - signal clicked - - color: white - - MouseArea { - id: buttonArea - anchors.fill: parent - onClicked: { - parent.clicked() - } - } - - states: [ - State { - name: "pressed" - when: buttonArea.pressed - - PropertyChanges { - target: label - color: Constants.grey - } - } - ] - transitions: [ - ] -} diff --git a/resources/qml/provider/ProviderContactInfo.qml b/resources/qml/provider/ProviderContactInfo.qml deleted file mode 100644 index d7b6165..0000000 --- a/resources/qml/provider/ProviderContactInfo.qml +++ /dev/null @@ -1,3 +0,0 @@ -// Dummy component implemented only in +android/+tablet -Item { -} diff --git a/resources/qml/provider/ProviderContactInfoItem.qml b/resources/qml/provider/ProviderContactInfoItem.qml deleted file mode 100644 index d7b6165..0000000 --- a/resources/qml/provider/ProviderContactInfoItem.qml +++ /dev/null @@ -1,3 +0,0 @@ -// Dummy component implemented only in +android/+tablet -Item { -} diff --git a/resources/qml/provider/ProviderDetailButtonBar.qml b/resources/qml/provider/ProviderDetailButtonBar.qml deleted file mode 100644 index 0940753..0000000 --- a/resources/qml/provider/ProviderDetailButtonBar.qml +++ /dev/null @@ -1,2 +0,0 @@ -Item { -} diff --git a/resources/qml/provider/ProviderDetailDescription.qml b/resources/qml/provider/ProviderDetailDescription.qml deleted file mode 100644 index 0940753..0000000 --- a/resources/qml/provider/ProviderDetailDescription.qml +++ /dev/null @@ -1,2 +0,0 @@ -Item { -} diff --git a/resources/qml/provider/ProviderDetailHistory.qml b/resources/qml/provider/ProviderDetailHistory.qml deleted file mode 100644 index 0940753..0000000 --- a/resources/qml/provider/ProviderDetailHistory.qml +++ /dev/null @@ -1,2 +0,0 @@ -Item { -} diff --git a/resources/qml/provider/ProviderDetailHistoryInfo.qml b/resources/qml/provider/ProviderDetailHistoryInfo.qml deleted file mode 100644 index 0940753..0000000 --- a/resources/qml/provider/ProviderDetailHistoryInfo.qml +++ /dev/null @@ -1,2 +0,0 @@ -Item { -} diff --git a/resources/qml/provider/ProviderDetailHistoryItem.qml b/resources/qml/provider/ProviderDetailHistoryItem.qml deleted file mode 100644 index 0940753..0000000 --- a/resources/qml/provider/ProviderDetailHistoryItem.qml +++ /dev/null @@ -1,2 +0,0 @@ -Item { -} diff --git a/resources/qml/provider/ProviderDetailView.qml b/resources/qml/provider/ProviderDetailView.qml deleted file mode 100644 index fc6ca20..0000000 --- a/resources/qml/provider/ProviderDetailView.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.0 as QtControls - -import "../" -import "../global" - -SectionPage -{ - id: baseItem - leftTitleBarAction: TitleBarMenuAction { state: "back"; onClicked: pop() } - headerTitleBarAction: TitleBarAction { text: provider.shortName } - titleBarColor: Category.displayColor(provider.category) - - property alias providerModelItem: provider.modelItem - ProviderModelItem { - id: provider - } - - - ProviderHeader { - id: header - width: baseItem.width - selectedProvider: provider - } - - - Rectangle { - id: swipeBar - anchors.top: header.bottom - anchors.topMargin: Utils.dp(20) - anchors.horizontalCenter: parent.horizontalCenter - - width: descriptionTab.width + contactTab.width + 2 * border.width - height: descriptionTab.height + 2 * border.width - - border.color: Constants.blue - border.width: Utils.dp(1) - radius: Utils.dp(3) - clip: true - - Row { - id: row - readonly property int maxContentWidth: Math.max(descriptionText.contentWidth, contactText.contentWidth) - - anchors.centerIn: parent - Rectangle { - id: descriptionTab - width: row.maxContentWidth + Utils.dp(6) - height: descriptionText.contentHeight + Utils.dp(6) - color: swipeView.currentIndex === 0 ? Constants.blue : descriptiontMouseArea.pressed ? Constants.blue_light : "transparent" - Text { - id: descriptionText - anchors.centerIn: parent - color: swipeView.currentIndex === 0 ? "white" : Constants.blue - text: qsTr("Description") - } - MouseArea { - id: descriptiontMouseArea - anchors.fill: parent - onClicked: swipeView.currentIndex = 0 - } - } - Rectangle { - id: contactTab - width: row.maxContentWidth + Utils.dp(6) - height: contactText.contentHeight + Utils.dp(6) - color: swipeView.currentIndex === 1 ? Constants.blue : contactMouseArea.pressed ? Constants.blue_light : "transparent" - Text { - id: contactText - anchors.centerIn: parent - color: swipeView.currentIndex === 1 ? "white" : Constants.blue - text: qsTr("Contact") - } - MouseArea { - id: contactMouseArea - anchors.fill: parent - onClicked: swipeView.currentIndex = 1 - } - } - } - } - - - Rectangle { - anchors.fill: flickable - } - - Flickable { - id: flickable - anchors.topMargin: Utils.dp(10) - anchors.top: swipeBar.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - flickableDirection: Flickable.VerticalFlick - clip: true - - QtControls.SwipeView { - id: swipeView - anchors.fill: parent - anchors.margins: Utils.dp(20) - clip: true - - Text { - text: !!provider.longDescription ? provider.longDescription : qsTr("Description not avaible") - - wrapMode: Text.WordWrap - font.pixelSize: Utils.dp(16) - } - - ProviderContactTab { - contactModel: provider.contactModel - } - } - } -} diff --git a/resources/qml/provider/ProviderSectionDelegate.qml b/resources/qml/provider/ProviderSectionDelegate.qml deleted file mode 100644 index f8007c6..0000000 --- a/resources/qml/provider/ProviderSectionDelegate.qml +++ /dev/null @@ -1,68 +0,0 @@ -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/ProviderStyle.qml b/resources/qml/provider/ProviderStyle.qml deleted file mode 100644 index cb3dd13..0000000 --- a/resources/qml/provider/ProviderStyle.qml +++ /dev/null @@ -1,38 +0,0 @@ -import QtQuick 2.5 - -import "../global" - -Item { - // ProviderViewHeader properties for ProviderView - readonly property bool showSearchBar: true - readonly property bool showHeaderButtonsInProviderView: false - readonly property string headerBackgroundInProviderView: "" - - // Provider category list properties - 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) - readonly property int leftProviderListMargin: Utils.dp(0) - readonly property bool showCategoryRightArrow: true - - // Provider list item properties - readonly property int itemLeftMargin: Utils.dp(5) - readonly property color subjectTextColor: "#000000" // default color, which is? - readonly property bool subjectTextFontBold: false - readonly property int addressTextFontSize: Utils.dp(11) - readonly property color addressTextColor: Constants.blue_dark - readonly property double infoItemWidthFactor: 2.0 - - readonly property int providerListItemTopMargin: Utils.dp(2) - readonly property int providerListItemRightMargin: Utils.dp(5) - readonly property int providerListItemBottomMargin: Utils.dp(5) - - readonly property bool providerListItemsHaveBorder: true - - readonly property bool providerListDetailsLinkBold: false - readonly property color providerListDetailsLinkBorder: Constants.blue_dark - readonly property color providerListDetailsLinkColor: Constants.blue_dark - readonly property color providerListDetailsLinkBackground: "#ffffff" - readonly property string providerListDetailsLinkPosition: "middle" -} diff --git a/resources/qml/provider/ProviderView.qml b/resources/qml/provider/ProviderView.qml deleted file mode 100644 index fae5176..0000000 --- a/resources/qml/provider/ProviderView.qml +++ /dev/null @@ -1,107 +0,0 @@ -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 } - - titleBarColor: Category.displayColor(category) - - ProviderDetailView { - id: providerDetailView - visible: false - } - - header: SearchBar { - width: baseItem.width - color: Category.displayColor(category) - onSearchTextChanged: providerModel.searchString = searchText - } - - 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/ProviderViewDelegate.qml b/resources/qml/provider/ProviderViewDelegate.qml deleted file mode 100644 index d957c20..0000000 --- a/resources/qml/provider/ProviderViewDelegate.qml +++ /dev/null @@ -1,86 +0,0 @@ -import QtQml.Models 2.2 -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.2 - -import "../" -import "../global" - -Rectangle { - id: baseItem - width: parent.width - height: Constants.provider_section_height - color: Constants.background_color - clip: true - - Rectangle { - id: background - color: "white" - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: Utils.dp(5) - anchors.top: parent.top - anchors.topMargin: Utils.dp(2) - anchors.bottom: parent.bottom - anchors.bottomMargin: Utils.dp(5) - - Item { - height: subjectText.height + addressText.height - anchors.verticalCenter: parent.verticalCenter - - anchors.left: parent.left - anchors.leftMargin: Utils.dp(5) - anchors.right: detailsLink.left - anchors.rightMargin: Utils.dp(15) - - Text { - id: subjectText - width: parent.width - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.normal_font_size - elide: Text.ElideRight - text: display - } - Text { - id: addressText - anchors.top: subjectText.bottom - width: parent.width - - verticalAlignment: Text.AlignVCenter - font.pixelSize: Constants.small_font_size - color: Constants.blue_dark - elide: Text.ElideRight - text: providerAddressDomain - } - } - Item { - id: detailsLink - anchors.right: parent.right - anchors.margins: Utils.dp(5) - height: parent.height - width: parent.height / 2 - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - height: width - - border.color: Constants.blue_dark - border.width: 1 - radius: width - - Text { - anchors.centerIn: parent - text: qsTr("i") - color: parent.border.color - } - } - } - } - - MouseArea { - anchors.fill: parent - onClicked: push(providerDetailView, {providerModelItem: model}) - } -} diff --git a/resources/qml/provider/SearchBar.qml b/resources/qml/provider/SearchBar.qml deleted file mode 100644 index 7115613..0000000 --- a/resources/qml/provider/SearchBar.qml +++ /dev/null @@ -1,159 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../global" - - -Rectangle { - id: baseItem - height: Constants.titlebar_height + Constants.searchbar_height - - readonly property alias searchText: searchField.text - - MouseArea { - id: pageArea - onClicked: pageArea.focus = true - - height: Constants.searchbar_height - width: parent.width - anchors.bottom: parent.bottom - - Rectangle { - anchors.left: parent.left - anchors.right: cancelButton.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.leftMargin: Utils.dp(8) - anchors.rightMargin: Utils.dp(10) - anchors.topMargin: Utils.dp(6) - anchors.bottomMargin: Utils.dp(8) - radius: Utils.dp(6) - color: "white" - - TextField { - id: searchField - anchors.fill: parent - anchors.leftMargin: Utils.dp(24) - - horizontalAlignment: Text.AlignLeft - - style: TextFieldStyle { - background: Rectangle { - radius: Utils.dp(6) - } - } - - Image { - id: textEditX - anchors.right: parent.right - anchors.rightMargin: Utils.dp(8) - anchors.verticalCenter: parent.verticalCenter - width: Utils.dp(64) - height: Utils.dp(64) - source: "qrc:///images/iOS/search_cancel.svg" - visible: searchField.text.length > 0 - - MouseArea { - anchors.fill: parent - onClicked: { - searchField.text = "" - } - } - } - } - - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - anchors.leftMargin: Utils.dp(8) - anchors.topMargin: Utils.dp(4) - - width: childrenRect.width - height: glassIcon.height - - Image { - id: glassIcon - height: textEditX.height - width: textEditX.width - fillMode: Image.PreserveAspectFit - source: "qrc:///images/iOS/search_icon.svg" - visible: searchField.text.trim().length === 0 - } - - Label { - id: searchLabel - anchors.left: glassIcon.right - anchors.leftMargin: Utils.dp(8) - anchors.verticalCenter: glassIcon.verticalCenter - text: qsTr("Search") - color: Constants.grey - font.pixelSize: Constants.normal_font_size - visible: searchField.text.trim().length === 0 - } - } - } - - DimmableTextButton { - id: cancelButton - - anchors.left: parent.right - anchors.right: parent.right - anchors.rightMargin: Utils.dp(8) - anchors.verticalCenter: parent.verticalCenter - clip: true - font.family: "Helvetica" - font.pixelSize: Constants.normal_font_size - color: "white" - text: qsTr("Cancel") - onClicked: { - pageArea.clicked(null) - } - } - } - - states: [ - State { - name: "searchBarActive" - when: searchField.activeFocus - AnchorChanges { - target: cancelButton - anchors.left: undefined - } - - PropertyChanges { - target: cancelButton - width: cancelButton.implicitWidth - } - }, - State { - name: "" - StateChangeScript { - script: { - Qt.inputMethod.hide() - } - } - - PropertyChanges { - target: searchField - text: "" - } - - AnchorChanges { - target: cancelButton - anchors.left: parent.right - } - } - ] - - transitions: [ - Transition { - from: "*" - to: "*" - AnchorAnimation { - duration: 200; - easing.type: Easing.InOutQuad - } - } - ] -} diff --git a/resources/qml_stationary/AusweisApp2/Global/Category.js b/resources/qml_stationary/AusweisApp2/Global/Category.js index 1fc8189..db0071c 100644 --- a/resources/qml_stationary/AusweisApp2/Global/Category.js +++ b/resources/qml_stationary/AusweisApp2/Global/Category.js @@ -6,18 +6,18 @@ var CATEGORY_COLOR_OTHER = "#00868e" function displayString(cat) { if (cat === "all") { - return qsTr("Provider") + return qsTr("Provider") + settingsModel.translationTrigger } if (cat === "citizen") { - return qsTr("Citizen services") + return qsTr("Citizen services") + settingsModel.translationTrigger } if (cat === "insurance") { - return qsTr("Insurances") + return qsTr("Insurances") + settingsModel.translationTrigger } if (cat === "finance") { - return qsTr("Financials") + return qsTr("Financials") + settingsModel.translationTrigger } - return qsTr("Other services") + return qsTr("Other services") + settingsModel.translationTrigger } function displayColor(cat) { @@ -38,10 +38,10 @@ function displayColor(cat) { var CATEGORY_TO_IMAGE_NAME = { - "all": "General", - "citizen": "CitizenServices", - "insurance": "Insurances", - "finance": "Financials" + "all": "general", + "citizen": "citizen", + "insurance": "insurance", + "finance": "finance" } diff --git a/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml b/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml index 510a6b0..ac8c99a 100644 --- a/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml +++ b/resources/qml_stationary/AusweisApp2/Global/ProviderModelItem.qml @@ -63,28 +63,28 @@ Item { ListElement { iconSource: "qrc:///images/provider/+tablet/url.png" - label: qsTr("Homepage") + label: QT_TR_NOOP("Homepage") text: "" link: "" } ListElement { iconSource: "qrc:///images/provider/+tablet/mail.png" - label: qsTr("E-Mail") + label: QT_TR_NOOP("E-Mail") text: "" link: "" } ListElement { iconSource: "qrc:///images/provider/+tablet/telefon.png" - label: qsTr("Phone") + label: QT_TR_NOOP("Phone") text: "" link: "" } ListElement { iconSource: "qrc:///images/provider/+tablet/adresse.png" - label: qsTr("Contact") + label: QT_TR_NOOP("Contact") text: "" link: "" } diff --git a/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml b/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml index 51e177a..5a22005 100644 --- a/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml +++ b/resources/qml_stationary/AusweisApp2/Views/History/HistoryView.qml @@ -31,7 +31,7 @@ Item { Text { id: searchLabel anchors.verticalCenter: parent.verticalCenter - text: qsTr("Search:") + text: qsTr("Search:") + settingsModel.translationTrigger textFormat: Text.StyledText } TextField { @@ -53,7 +53,7 @@ Item { Text { anchors.centerIn: parent - text: qsTr("No history entry available") + text: qsTr("No history entry available") + settingsModel.translationTrigger wrapMode: Text.WordWrap font.pixelSize: Constants.normal_font_size visible: !scrollView.visible @@ -118,7 +118,7 @@ Item { spacing: Constants.pane_spacing Text { - text: qsTr("History:") + text: qsTr("History:") + settingsModel.translationTrigger } CheckBox { @@ -135,7 +135,7 @@ Item { Text { anchors.left: parent.left anchors.leftMargin: -Constants.pane_spacing - text: qsTr("save") + text: qsTr("save") + settingsModel.translationTrigger } } @@ -144,13 +144,13 @@ Item { } Button { - text: qsTr("Delete History") + text: qsTr("Delete History") + settingsModel.translationTrigger enabled: listView.count > 0 onClicked: deleteConfirmationDialog.open() } Button { - text: qsTr("Save as PDF") + text: qsTr("Save as PDF") + settingsModel.translationTrigger enabled: listView.count > 0 onClicked: fileDialog.open() } @@ -163,17 +163,17 @@ Item { 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?") + title: qsTr("Delete history") + settingsModel.translationTrigger + text: qsTr("Do you really want to delete the history?") + settingsModel.translationTrigger onYes: { historyModel.removeRows(0, historyModel.rowCount()) } } FileDialog { id: fileDialog modality: Qt.ApplicationModal selectExisting: false - title: Qt.application.name + " - " + qsTr("Save history") + title: Qt.application.name + " - " + qsTr("Save history") + settingsModel.translationTrigger folder: shortcuts.home - nameFilters: [qsTr("PDF Documents (*.pdf)")] + nameFilters: [qsTr("PDF Documents (*.pdf)") + settingsModel.translationTrigger] onAccepted: { qmlExtension.exportHistory(fileDialog.fileUrls) } diff --git a/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml index 2235007..274b764 100644 --- a/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml +++ b/resources/qml_stationary/AusweisApp2/Views/History/ListViewDelegateContent.qml @@ -26,15 +26,15 @@ Item { return ""; } else if (Utils.isToday(historyModelItem.dateTime)) { - return qsTr("today") + return qsTr("today") + settingsModel.translationTrigger } else if (Utils.isYesterday(historyModelItem.dateTime)) { - return qsTr("yesterday") + return qsTr("yesterday") + settingsModel.translationTrigger } else if (Utils.isThisWeek(historyModelItem.dateTime)) { - return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dddd")) + settingsModel.translationTrigger } - return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("MM/dd/yyyy")) + return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")) + settingsModel.translationTrigger } } Text { diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml index c4019ba..c9694f1 100644 --- a/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/AdditionalResultsItem.qml @@ -32,7 +32,7 @@ Rectangle { } Text { - text: qsTr("Additional results in other categories: %1").arg(baseItem.totalHits) + text: qsTr("Additional results in other categories: %1").arg(baseItem.totalHits) + settingsModel.translationTrigger anchors.verticalCenter: parent.verticalCenter anchors.left: backgroundImage.right anchors.margins: Utils.dp(15) diff --git a/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml index bbca995..4ec814e 100644 --- a/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml +++ b/resources/qml_stationary/AusweisApp2/Views/Provider/ProviderView.qml @@ -23,9 +23,9 @@ Rectangle { Text { width: parent.width - text: qsTr("

This section lists offers of service providers that support online identification. " + + 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.

") + "the online identification function.") + "

" wrapMode: Text.Wrap } @@ -36,7 +36,7 @@ Rectangle { Text { id: searchLabel anchors.verticalCenter: parent.verticalCenter - text: qsTr("Search:") + text: qsTr("Search:") + settingsModel.translationTrigger textFormat: Text.StyledText } TextField { @@ -57,32 +57,32 @@ Rectangle { readonly property real space: (parent.width - checkBoxCitizen.width - checkBoxInsurance.width - checkBoxFinance.width - checkBoxOther.width) / 5 spacing: space - CategoryCheckbox { + CategoryCheckbox_tablet { id: checkBoxCitizen category: "citizen" imageSource: Category.imageSource("citizen") - text: qsTr("Citizen services") + text: qsTr("Citizen services") + settingsModel.translationTrigger } - CategoryCheckbox { + CategoryCheckbox_tablet { id: checkBoxInsurance category: "insurance" imageSource: Category.imageSource("insurance") - text: qsTr("Insurances") + text: qsTr("Insurances") + settingsModel.translationTrigger } - CategoryCheckbox { + CategoryCheckbox_tablet { id: checkBoxFinance category: "finance" imageSource: Category.imageSource("finance") - text: qsTr("Financials") + text: qsTr("Financials") + settingsModel.translationTrigger } - CategoryCheckbox { + CategoryCheckbox_tablet { id: checkBoxOther category: "other" imageSource: Category.imageSource("other") - text: qsTr("Other services") + text: qsTr("Other services") + settingsModel.translationTrigger } } } @@ -95,7 +95,7 @@ Rectangle { Text { anchors.centerIn: parent - text: qsTr("No match found") + text: qsTr("No match found") + settingsModel.translationTrigger wrapMode: Text.WordWrap font.pixelSize: Constants.normal_font_size visible: !scrollView.visible diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml index 442ffcf..9c61e41 100644 --- a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderContactInfo.qml @@ -24,7 +24,7 @@ Rectangle { } Text { - text: qsTr("Contact") + text: qsTr("Contact") + settingsModel.translationTrigger padding: Constants.component_spacing font.pixelSize: Constants.header_font_size color: "white" @@ -43,7 +43,7 @@ Rectangle { width: contactListView.width color: baseItem.color imageSource: Qt.resolvedUrl(model.iconSource) - itemText: !!model.text ? model.text : qsTr("Unknown") + itemText: (!!model.text ? model.text : qsTr("Unknown")) + settingsModel.translationTrigger link: model.link } } diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml index 55ca344..7e71751 100644 --- a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailButtonBar.qml @@ -30,7 +30,7 @@ Item { Button { id: button - text: qsTr("ONLINE-APPLICATION") + text: qsTr("ONLINE-APPLICATION") + settingsModel.translationTrigger // TODO: Use custom button // buttonColor: baseItem.titleBarColor anchors.left: icon.right diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml index b96b42c..a0913ea 100644 --- a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailDescription.qml @@ -17,7 +17,7 @@ ScrollView { Text { // font.pixelSize: Constants.header_font_size color: PlatformConstants.blue_primary - text: qsTr("Description") + text: qsTr("Description") + settingsModel.translationTrigger } Text { diff --git a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml index 14ed85d..019d258 100644 --- a/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml +++ b/resources/qml_stationary/AusweisApp2/Views/ProviderDetails/ProviderDetailsDialog.qml @@ -7,7 +7,7 @@ import AusweisApp2.Views.Provider 1.0 Window { id: baseItem - title: qsTr("Provider details") + title: qsTr("Provider details") + settingsModel.translationTrigger height: Utils.dp(900) minimumHeight: Utils.dp(700) width: Utils.dp(1200) diff --git a/resources/qtlogging.ini b/resources/qtlogging.ini index 73fae37..980241e 100644 --- a/resources/qtlogging.ini +++ b/resources/qtlogging.ini @@ -41,6 +41,7 @@ gui=true # Logging category for network stuff written on our own. # I. e. unfortunately we do not log network traffic handled by third party libraries network=true +#qt.network.ssl=true # Logging category for systems calls / signals system=true diff --git a/resources/statemachine.sh.in b/resources/statemachine.sh.in new file mode 100755 index 0000000..3567ffa --- /dev/null +++ b/resources/statemachine.sh.in @@ -0,0 +1,24 @@ +#!/bin/sh + +RULE=' +s/([[:alnum:]]+)\.setInitialState\(([[:alnum:]]+)\)\;/[*] --> \2/p +s/setInitialState\(([[:alnum:]]+)\)\;/[*] --> \1/p +s/([[:alnum:]]+)\-.addTransition\(([[:alnum:]]+)\,[[:space:]]+\&([[:alnum:]]+)\:\:fire([[:alnum:]]+)\,[[:space:]]+([[:alnum:]]+)\)\;/\2 --> \5 : \4/p +s/auto[[:space:]]+([[:alnum:]]+)[[:space:]]+=\s+addAndConnectState\(\);/\1 --> [*]/p +' + +function createImage { + echo "@startuml" > $2.uml + sed -E -n -e "$RULE" < $1 >> $2.uml + echo "@enduml" >> $2.uml + cat $2.uml + @JAVA_EXECUTABLE@ -DPLANTUML_LIMIT_SIZE=8192 -jar @PLANTUML@ $2.uml + rm $2.uml +} + +createImage @PROJECT_SOURCE_DIR@/src/core/states/CompositeStateSelectCard.cpp @PROJECT_BINARY_DIR@/uml_SelectCard +createImage @PROJECT_SOURCE_DIR@/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp @PROJECT_BINARY_DIR@/uml_ProcessCvcsAndSetRights +createImage @PROJECT_SOURCE_DIR@/src/core/controller/ChangePinController.cpp @PROJECT_BINARY_DIR@/uml_ChangePinController +createImage @PROJECT_SOURCE_DIR@/src/core/controller/SelfAuthController.cpp @PROJECT_BINARY_DIR@/uml_SelfAuthController +createImage @PROJECT_SOURCE_DIR@/src/core/controller/AuthController.cpp @PROJECT_BINARY_DIR@/uml_AuthController +createImage @PROJECT_SOURCE_DIR@/src/core/controller/RemoteServiceController.cpp @PROJECT_BINARY_DIR@/uml_RemoteServiceController diff --git a/resources/translations/ausweisapp2_de.ts b/resources/translations/ausweisapp2_de.ts index a871f27..1b473e2 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -4,27 +4,22 @@ AboutDialog - - <b>AusweisApp2</b> - <b>AusweisApp2</b> - - - + AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Ministry of the Interior. - Die AusweisApp2 ist ein Produkt der Governikus GmbH &amp; Co. KG - im Auftrag des Bundesministeriums des Innern. + Die AusweisApp2 ist ein Produkt der Governikus GmbH & Co. KG - im Auftrag des Bundesministeriums des Innern. - + Developer mode: Entwicklermodus: - + use verwenden - + OK OK @@ -32,8 +27,7 @@ AdditionalResultsItem - - + Additional results: Weitere Ergebnisse: @@ -43,246 +37,239 @@ Weitere Ergebnisse in anderen Kategorien: %1 + + AdditionalResultsItem_tablet + + + Additional results: + Weitere Ergebnisse: + + AppQtMainWidget - + Actions Hauptaktionen - + Welcome Startseite - + Provider Anbieter - + History Verlauf - + Identify Ausweisen - + Settings Einstellungen - + Minimise Minimieren - + AusweisApp2 AusweisApp2 - + nPA and eAT Logo Logo des nPA und eAT - + AusweisApp2 Logo Logo der AusweisApp2 - + Fi&le &Datei - + &PIN Management &PIN-Verwaltung - + &Exit &Beenden - + &Identify &Ausweisen - + &Settings &Einstellungen - + &Manual &Handbuch - + &Evaluate &Bewerten - + &Report error Fehler &melden - + &About AusweisApp2 &Über AusweisApp2 - + &Provider A&nbieter - + S&how log Protokoll &anzeigen - + Save &log Protokoll &speichern - + &Questions &Fragen - + &History &Verlauf - + &Change PIN &PIN ändern - + &Setup assistant &Einrichtungsassistent - + &Help &Hilfe - + &Diagnosis &Diagnose + + + Switch language to German + Die Sprache auf Deutsch umstellen + + + + DE + DE + + + + Switch language to English + Die Sprache auf Englisch umstellen + + + + EN + EN + BluetoothWorkflow - + Enable Bluetooth Bluetooth aktivieren - + Continue Fortsetzen - - Bluetooth is not supported by your device.<br/>Please try NFC. - Ihr Gerät unterstützt kein Bluetooth.<br/>Bitte versuchen Sie NFC. + + Bluetooth is not supported by your device. + Ihr Gerät unterstützt kein Bluetooth. - - Bluetooth is switched off.<br/>Please enable Bluetooth. - Bluetooth ist deaktiviert.<br/>Bitte aktivieren Sie Bluetooth. + + Please try NFC. + Bitte versuchen Sie NFC. - + + Bluetooth is switched off. + Bluetooth ist deaktiviert. + + + + Please enable Bluetooth. + 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. + Es konnte kein gekoppeltes, eingeschaltetes Bluetooth-Kartenlesegerät 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 wird hergestellt - + Determine card Ermittle Ausweis - - Change PIN - PIN ändern + + Search card reader... + Suche Kartenlesegerät... - - Authenticate - Jetzt ausweisen - - - - 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. - - - - 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... @@ -290,45 +277,45 @@ Category - + Provider Anbieter - + All Alle - + Citizen services Bürgerdienste - + Insurances Versicherungen - + Financials Finanzen - + Other services - Weitere Services + Weitere Dienste CertificateDescriptionPage - + Provider Information Anbieterinformationen @@ -336,7 +323,7 @@ ChangePinController - + You may now remove your ID card from the device. Sie können nun Ihr Ausweisdokument vom Gerät entfernen. @@ -344,32 +331,32 @@ CredentialDialog - + Proxy security Proxy-Sicherheit - + Proxy requires credentials: Es werden Proxy-Anmeldeinformationen benötigt: - + Password: Kennwort: - + Username: Benutzername: - + Proxy credential password Passwort für den Proxy - + Proxy credential username Benutzername für den Proxy @@ -377,22 +364,22 @@ CustomSwipeBar - + Contact Kontakt - + History Verlauf - + CONTACT KONTAKT - + HISTORY VERLAUF @@ -400,7 +387,8 @@ DataGroup - + + No data requested Keine Daten erforderlich @@ -408,12 +396,12 @@ DetailDialog - + Service provider data Angaben zum Diensteanbieter - + close dialog Schließen Dialog @@ -421,20 +409,33 @@ DeveloperModeHistoryWidget - - <html><head/><body><p align="center"><span style=" font-size:12pt; color:#ff0000;">Developer Mode: Enabled!</span></p></body></html> - <html><head/><body><p align="center"><span style=" font-size:12pt; color:#ff0000;">Entwicklermodus: Aktiviert!</span></p></body></html> - - - + Disable Deaktivieren + + + Developer Mode: Enabled! + Entwicklermodus: Aktiviert! + + + + DeveloperSettingsWidget + + + Self authentication test URI: + Test URI für die Selbstauskunft: + + + + use + verwenden + DeveloperView - + Developer options Entwickleroptionen @@ -442,17 +443,17 @@ DiagnosisDialog - + Diagnosis Diagnose - + Save as... - Speichern... + Speichern als... - + Close Schließen @@ -460,105 +461,115 @@ EnterPinView - + 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. - - 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. + + You have entered the wrong PIN twice. Prior to 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 enter a new 6-digit PIN of your choice. + Geben Sie nun bitte eine neue 6-stellige PIN Ihrer Wahl 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 new 6-digit PIN again. + Wiederholen Sie bitte Ihre neue 6-stellige PIN. - + + Please enter your current PIN or your initial transport PIN first. + Geben Sie bitte zunächst Ihre aktuelle PIN bzw. die Transport-PIN ein. + + + 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. - Feedback - - Dialog & Feedback - Dialog & Rückmeldung - - - + Your opinion matters Ihre Meinung zählt - + We are happy about every feedback on our software. Wir freuen uns über Ihre Rückmeldung zu unserem Programm. - + Rate AusweisApp2 Bewerten Sie die AusweisApp2 - - Please rate us on the Google Play Store. - Bitte bewerten Sie uns im Google Play Store. + + Help & Feedback + Hilfe & Feedback - - Share - Teilen + + FAQ + FAQ - - Tell your friends about AusweisApp2. - Erzählen Sie Ihren Freunden und Bekannten von der AusweisApp2. + + Do you have questions how to use AusweisApp2? + Haben Sie Fragen zur Nutzung der AusweisApp2? - - Share with - Teilen mit + + https://www.ausweisapp.bund.de/en/questions-and-answers/frequently-asked-questions/ + https://www.ausweisapp.bund.de/fragen-und-antworten/haeufig-gestellte-fragen/ - - 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 + + Support + Support - + + You need further help? + Benötigen Sie weitere Hilfe? + + + + https://www.ausweisapp.bund.de/en/questions-and-answers/support/ + https://www.ausweisapp.bund.de/fragen-und-antworten/support/ + + + + Please rate us in the Google Play Store. + Bewerten Sie die AusweisApp2. + + + Report error Melden Sie einen Fehler - + 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. - + Android log file Android Protokolle - + <Please describe the error> <Bitte beschreiben Sie den Fehler> @@ -566,103 +577,90 @@ GeneralSettingsWidget - + Software update: Softwareaktualisierungen: - + History: Verlauf: - + check on program start beim Programmstart prüfen - + search for updates nach Aktualisierungen suchen - + On screen password: Bildschirmtastatur: - + use verwenden - + Start AusweisApp2 automatically: AusweisApp2 automatisch starten: - + on system start beim Systemstart - + Close AusweisApp2 window automatically: Fenster der AusweisApp2 automatisch schließen: - + after successful identification nach erfolgreichem Ausweisen - + save speichern - + check software update on program start Beim Start des Programms auf Software-Aktualisierung prüfen - + save history Verlauf speichern - + Start AusweisApp2 automatically on system startup AusweisApp2 automatisch beim Systemstart starten - + Close AusweisApp2 window automatically after successful identification AusweisApp2 automatisch nach erfolgreicher Authentifizierung schließen - + use on screen password Bildschirmtastatur verwenden - - HistoryDetails - - - Delete - Löschen - - - - Go to online application - Gehe zu Online-Anwendung - - HistoryListView - + Delete Löschen @@ -670,53 +668,58 @@ HistoryListViewDelegateContent - + today heute - + yesterday gestern - + dddd dddd - - MM/dd/yyyy + + dd.MM.yyyy dd.MM.yyyy - - Touch for more details + + Tap for more details Berühren Sie hier für mehr Details HistoryView - - + + + + History Verlauf - - - + + + + Currently there are no history entries. Derzeit gibt es keine Einträge im Verlauf. - + + Delete Löschen - + + Delete all Alle löschen @@ -779,37 +782,37 @@ HistoryViewDetails - + Provider Information Anbieterinformationen - + Provider name Anbieter - + Purpose Zweck - + Date Datum - - MM/dd/yyyy + + dd.MM.yyyy dd.MM.yyyy - + Requested data Angeforderte Daten - + Terms of usage Nutzungsbedingungen @@ -817,57 +820,57 @@ HistoryWidget - + 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. Es ist darüber hinaus auch möglich, den Verlauf zu speichern. - + No matching history entries were found. Please modify your search criteria. Es wurden keine Verlaufseinträge gefunden. Bitte ändern Sie Ihr Suchkriterium. - + Delete history... Verlauf löschen... - + Save as PDF... Als PDF speichern... - + History: Verlauf: - + save speichern - + Search: Suche: - + Please enter your search Bitte geben Sie Ihre Suche ein - + save history: Verlauf speichern: - + save history Verlauf speichern - + save history as PDF Verlauf als PDF speichern @@ -875,7 +878,7 @@ IdentifyController - + You may now remove your ID card from the device. Sie können nun Ihr Ausweisdokument vom Gerät entfernen. @@ -883,116 +886,140 @@ IdentifyView - - - - - + + + + + Identify Ausweisen - + + Authenticate + Jetzt ausweisen + + + + Please wait a moment... Bitte warten Sie einen Moment... - + + The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the online identification function. + Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an die Behörde, die Ihr Ausweisdokument ausgegeben hat, um die Online-Ausweisfunktion zu aktivieren. + + + + Please observe the display of your card reader. + Bitte beachten Sie die Anzeige Ihres Kartenlesegeräts. + + + + You have entered the wrong PIN twice. Prior to 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. + + + 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 - IdentifyViewContent - - - + + + + Service provider Diensteanbieter - - - + + + + Purpose for reading out requested data Zweck des Auslesevorgangs - - - + + + + Identify now Jetzt ausweisen - - + + + + Transactional information Transaktionsinformationen - - - + + + + Required Data Erforderliche Daten - - - + + + + Optional Data Optionale Daten + + + + + + You are about to identify yourself towards the following service provider: + Sie möchten sich bei folgendem Diensteanbieter ausweisen: + + + + + + + The following data will be transferred to the service provider when you enter the PIN: + Folgende Daten Ihres Ausweises werden nach Eingabe der PIN ausgelesen und an den Diensteanbieter übermittelt: + 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. - + Hello, "%1" wants to read your data. Hallo, "%1" möchte Ihre Daten auslesen. - - - Hello, here you have the - Hallo, hier haben Sie die - - - - Hello, - Hallo, - - - - opportunity to view the stored data on your identity card. - Möglichkeit, die auf Ihrem Personalausweis hinterlegten Daten einzusehen. - - - - "%1"<br>wants to read your data - "%1"<br>möchte Ihre Daten auslesen - IdentifyWorkflow - + Identify Ausweisen @@ -1000,76 +1027,59 @@ 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 + + Information + Information - - 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 Anwendung. - + https://www.ausweisapp.bund.de/en/download/ https://www.ausweisapp.bund.de/download/ + + KnownDevicesListDelegate + + + (Available) + (Verfügbar) + + + + Last connection: + Letzte Verbindung: + + ListViewDelegateContent @@ -1089,34 +1099,34 @@ - MM/dd/yyyy + dd.MM.yyyy dd.MM.yyyy LogFilesDialog - + Log files Protokolle - + File: Datei: - + Save... Speichern... - + Delete old files... Alte Dateien löschen... - + Close Schließen @@ -1124,47 +1134,62 @@ MoreView - + More Mehr - + Version information Versionsinformationen - + FAQ FAQ - + + https://www.ausweisapp.bund.de/en/questions-and-answers/frequently-asked-questions/ + https://www.ausweisapp.bund.de/fragen-und-antworten/haeufig-gestellte-fragen/ + + + Support Support - + + https://www.ausweisapp.bund.de/en/questions-and-answers/support/ + https://www.ausweisapp.bund.de/fragen-und-antworten/support/ + + + Rate app Bewerten - - Share - Teilen + + https://www.ausweisapp.bund.de/en/questions-and-answers/evaluate-us/ + https://www.ausweisapp.bund.de/fragen-und-antworten/bewerten-sie-uns/ - - 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&hl=de + + Software license + Softwarelizenz - - Share with - Teilen mit + + https://www.ausweisapp.bund.de/en/download/ + https://www.ausweisapp.bund.de/download/ - + + Configure remote service + Fernzugriff konfigurieren + + + Developer options Entwickleroptionen @@ -1172,46 +1197,51 @@ NavigationView - - + + Identify Ausweisen - - + + Provider - Diensteanbieter + Anbieter - - + + History Verlauf - - + + PIN Management PIN-Verwaltung - - Dialog & Feedback - Dialog & Rückmeldung + + Help & Feedback + Hilfe & Feedback - - Info & Help - Information & Hilfe + + Information + Information - + + Smartphone as card reader + Smartphone als Kartenlesegerät + + + Developer options Entwickleroptionen - + More Mehr @@ -1219,60 +1249,65 @@ NfcWorkflow - - Enable NFC - NFC aktivieren + + NFC is not supported by your device. + Ihr Gerät unterstützt kein NFC. - - NFC is not supported by your device.<br/>Please try Bluetooth. - Ihr Gerät unterstützt kein NFC.<br/>Bitte versuchen Sie Bluetooth. + + Please try Bluetooth. + Bitte versuchen Sie Bluetooth. - - NFC is switched off.<br/>Please enable NFC. - NFC ist nicht aktiv.<br/>Bitte aktivieren Sie NFC. + + NFC is switched off. + NFC ist nicht aktiv. - + + Go to NFC settings + Zu den NFC Einstellungen + + + + Please enable NFC in your system settings. + Bitte aktivieren Sie NFC in Ihren Systemeinstellungen. + + + Establish connection Verbindung wird hergestellt - - 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. + + Your device does not meet the technical requirements (Extended Length not supported). You require an additional 'Bluetooth card reader' or an additional 'smartphone as 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 oder mit einem separaten Smartphone als Kartenleser nutzen. - - 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. + + The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the online identification function. + Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an die Behörde, die Ihr Ausweisdokument ausgegeben hat, um die Online-Ausweisfunktion zu aktivieren. - + Please place your device<br/>on your ID card. Bitte platzieren Sie Ihr Gerät<br/>über Ihrem Personalausweis. - - - Use Bluetooth card reader<br/>instead of NFC - Bluetooth Kartenleser<br/>anstatt NFC benutzen - PinSettingsWidget - + Please pay attention to the display of your card reader. Bitte beachten Sie die Anzeige auf Ihrem Kartenlesegerät. - + <h4>PIN successfully changed</h4> <h4>Änderung der PIN erfolgreich</h4> - + Click on "Change PIN" if you want to change your PIN again. If not, you can now remove your ID card form the card reader. @@ -1281,19 +1316,25 @@ If not, you can now remove your ID card form the card reader. Anderenfalls können Sie nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. - + <html> <h4>No card reader detected. Please make sure that a card reader is connected.</h4> <p>If you need help or have problems with your card reader click on the "Diagnosis" button for further information. </p> +<p>Please note: It is currently not possible to change your PIN whilst using your smartphone as a card reader. +However, you can change your PIN on your smartphone directly as long as the remote service is disabled. +</p> </html> <html> <h4>Es wurde kein Kartenlesegerät gefunden. Bitte stellen Sie sicher, dass ein Kartenlesegerät angeschlossen ist.</h4> <p>Wenn Sie Hilfe bei der Einrichtung Ihres Kartenlesegerät benötigen, klicken Sie auf "Diagnose".</p> +<p>Beachten Sie: Es ist zurzeit noch nicht möglich, Ihre PIN mithilfe der "Smartphone als Kartenleser"-Funktionalität zu ändern. +Sie können jedoch Ihre PIN direkt am Smartphone ändern solange der Fernzugriff deaktiviert ist. +</p> </html> - + <html> <h4>Please place your ID card on the card reader.</h4> <p>If you have already placed an ID card on the card reader but it is not displayed here, please click on "Diagnosis".</p> @@ -1304,7 +1345,7 @@ Anderenfalls können Sie nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. </html> - + <html> <h4>Several ID cards detected</h4> <p>Please place just one ID card on the card reader.</p> @@ -1315,23 +1356,23 @@ Anderenfalls können Sie nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. </html> - + Please make sure that only one card reader with an ID card on it is connected to your computer. Bitte stellen Sie sicher, dass an Ihrem Computer nur ein Kartenlesegerät mit aufliegendem Ausweisdokument angeschlossen ist. - + <html> <h4>eID feature deactivated</h4> -<p>The eID function of your ID card is deactivated. Please contact your competent authority to activate the eID function.</p> +<p>The eID function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document 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 Ihre 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 die Behörde, die Ihr Ausweisdokument ausgegeben hat, 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 your competent authority. @@ -1339,101 +1380,100 @@ When you change your PIN for the first time, please enter your five-digit transp 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. -Bei der erstmaligen PIN-Änderung geben Sie bitte in das Feld "Aktuelle PIN / Transport-PIN" Ihre 5-stellige Transport-PIN ein. Sie finden die Transport-PIN in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. - +Bei der erstmaligen PIN-Änderung geben Sie bitte in das Feld "Aktuelle PIN / Transport-PIN" Ihre 5-stellige Transport-PIN ein. Sie finden die Transport-PIN in dem Schreiben, das Sie nach Beantragung Ihres Ausweisdokuments von der für die Ausgabe Ihres Ausweisdokuments zuständigen Behörde erhalten haben. - + You have entered the wrong PIN two times. For a third attempt you first have to enter your six-digit card access number. 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. Sie haben Ihre PIN zweimal falsch eingegeben. Für einen dritten Versuch müssen Sie zunächst Ihre 6-stellige Zugangsnummer eingeben. Die Zugangsnummer finden Sie beim Personalausweis auf der Vorderseite rechts neben dem letzten Tag der Gültigkeitsdauer. Beim elektronischen Aufenthaltstitel finden Sie die Zugangsnummer über Ihrer Unterschrift. - + <h4>PUK entry successful</h4><p>Your ID card is unblocked. You now have three more tries to change your PIN.</p> <h4>Eingabe der PUK erfolgreich</h4><p>Ihr Ausweis ist entsperrt. Sie haben nun erneut drei Versuche, Ihre PIN zu ändern.</p> - + Current PIN / Transport PIN: Aktuelle PIN / Transport-PIN: - + New PIN: Neue PIN: - + Confirm: Bestätigen: - + Card access number (CAN): Zugangsnummer (CAN): - + PUK: PUK: - + Click on "Change PIN" to enter a new PIN. Klicken Sie auf "PIN ändern", um eine neue PIN zu setzen. - + Click on "Enter PUK" to unblock your ID card. Klicken Sie auf "PUK eingeben", um Ihren Ausweis zu entsperren. - + deactivatedReaderImageLabel deactivatedReaderImageLabel - + 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. "Klicken Sie auf "PIN ändern", um zunächst Ihre Zugangsnummer einzugeben und anschließend eine neue PIN zu setzen. Die Zugangsnummer finden Sie beim Personalausweis auf der Vorderseite rechts neben dem letzten Tag der Gültigkeitsdauer. Beim elektronischen Aufenthaltstitel finden Sie die Zugangsnummer über Ihrer Unterschrift. - + CAN on nPA icon Zugangsnummer auf nPA Icon - + card reader icon - Icon des Kartenlesers + Icon des Kartenlesegeräts - + no reader icon - Kein Kartenleser Icon + Kein Kartenlesegerät Icon - + multiple card reader icon - Mehrer Kartenleser Icon + Mehrer Kartenlesegerät Icon - + deactivated card reader icon - Deaktiverter Kartenleser Icon + Deaktiverter Kartenlesegerät 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. @@ -1441,44 +1481,82 @@ Please note that you can only use the PUK to unblock the eID function. If you ha 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. + + + <html> +<h4>Extended Length is not supported.</h4> +<p>Your remote reader does not meet the technical requirements (Extended Length not supported).</p> +</html> + Ihr entferntes Kartenlesegerät erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt).< + + + + <html> +<h4>Extended Length is not supported.</h4> +<p>At least one of your card readers does not meet the technical requirements (Extended Length not supported). Please place the ID card on a different card reader.</p> +</html> + Mindestens eines Ihrer Kartenlesegeräte erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt). Bitte platzieren Sie Ihren Ausweis auf einem anderen Kartenlesegerät.< + PinView - - - + + + PIN Management PIN-Verwaltung - + + Change PIN PIN ändern - - Processing... - In Arbeit... + + + Please wait a moment... + Bitte warten Sie einen Moment... + + + + The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the online identification function. + Die Online-Ausweisfunktion Ihres Ausweisdokumentes ist nicht aktiviert. Bitte wenden Sie sich an die Behörde, die Ihr Ausweisdokument ausgegeben hat, um die Online-Ausweisfunktion zu aktivieren. + + + + Please observe the display of your card reader. + Bitte beachten Sie die Anzeige Ihres Kartenlesegeräts. + + + + You have entered the wrong PIN twice. Prior to 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. PinViewContent - - + + PIN Management PIN-Verwaltung - - + + 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 @@ -1486,7 +1564,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe PinWorkflow - + PIN Management PIN-Verwaltung @@ -1494,144 +1572,161 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderContactInfo - Contact Kontakt - Unknown Unbekannt + + ProviderContactInfo_tablet + + + Contact + Kontakt + + + + Unknown + Unbekannt + + ProviderContactTab - + Unknown Unbekannt ProviderDetailButtonBar - - - ONLINE APPLICATION - Online-Anwendung - ONLINE-APPLICATION ONLINE-ANWENDUNG + + ProviderDetailButtonBar_tablet + + + ONLINE APPLICATION + Online-Anwendung + + ProviderDetailDescription - Description Beschreibung - ProviderDetailHistory + ProviderDetailDescription_tablet - - History - Verlauf - - - - Purpose for reading out requested data - Zweck des Auslesevorgangs + + Description + Beschreibung - ProviderDetailHistoryInfo + ProviderDetailHistoryInfo_tablet - - Purpose for reading out requested data - Zweck des Auslesevorgangs - - - + Service provider Diensteanbieter - + + Purpose for reading out requested data + Zweck des Auslesevorgangs + + + Read data Daten auslesen - + Terms of usage Nutzungsbedingungen - ProviderDetailHistoryItem + ProviderDetailHistoryItem_tablet - + today heute - + yesterday gestern - + dddd dddd - - MM/dd/yyyy + + dd.MM.yyyy dd.MM.yyyy - + Touch for more details Berühren Sie hier für mehr Details + + ProviderDetailHistory_tablet + + + History + Verlauf + + + + Purpose for reading out requested data + Zweck des Auslesevorgangs + + ProviderDetailView - + DESCRIPTION BESCHREIBUNG - + CONTACT KONTAKT - + Description Beschreibung - + Contact Kontakt - + + Description not available Beschreibung nicht verfügbar - - - Description not avaible - Beschreibung nicht verfügbar - ProviderDetailsDialog @@ -1644,17 +1739,15 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderHeader - - - Online Application - Online-Anwendung + + To service provider + Zum Anbieter ProviderInfoSection - - + Touch for more details Berühren Sie hier für mehr Details @@ -1662,25 +1755,25 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderModelItem - + Homepage Homepage - + E-Mail E-Mail - + Phone Telefon - + Contact Kontakt @@ -1689,47 +1782,52 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderView - - + + Provider Anbieter - + + Citizen services Bürgerdienste - + + Insurances Versicherungen - + + Financials Finanzen - + + Other services Weitere Services - - - + + + + No match found Kein Ergebnis gefunden - <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> + 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. + Dieser Bereich enthält eine Liste von Anbietern, die eine Online-Authentisierung anbieten. Diese Liste wird ständig aktualisiert. @@ -1740,7 +1838,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderViewDelegate - + i i @@ -1748,27 +1846,22 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe ProviderWidget - - <html><head/><body><p>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.</p></body></html> - <html><head/><body><p>In diesem Bereich finden Sie Anwendungen, die die Authentisierung mit der Online-Ausweisfunktion unterstützen. Mit einem Klick auf einen Eintrag kommen Sie auf die Webseite des Diensteanbieters. Dieser Bereich wird stetig um weitere Anwendungsmöglichkeiten für den Online-Ausweis ergänzt.</p></body></html> - - - + No matching providers were found. Please modify your search criteria. Es wurden keine Anbieter gefunden. Bitte ändern Sie Ihr Suchkriterium. - + 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. Diese Dialogseite listet die Angebote von Diensteanbietern auf, die die Online-Ausweisfunktion unterstützen. Klicken Sie auf einen Eintrag, um auf die Webseite des Diensteanbieters zu gelangen. Diese Dialogseite wird kontinuierlich mit weiteren Angeboten zur Online-Ausweisfunktion aktualisiert. - + Search: Suche: - + Please enter your search Bitte geben Sie Ihre Suche ein @@ -1776,67 +1869,290 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe RandomPinDialog - - * - * - - - + OK OK - + Cancel Abbrechen - + Clear Löschen - + PIN field PIN-Eingabefeld - + Screen keyboard Bildschirmtastatur - ReaderDriverDialog + ReaderConfigurationInfo - + + Unknown reader + Unbekanntes Kartenlesegerät + + + + ReaderDeviceDialog + + Diagnosis Diagnose - + Close Schließen - ReaderDriverWidget + ReaderDeviceWidget - + + In order to use the online identification function of your ID card you need a separate card reader or a suitable smartphone. The following overview shows the status of a connected card reader or connected smartphone. + Um die Online-Ausweisfunktion des Personalausweises nutzen zu können, benötigen Sie ein separates Kartenlesegerät oder auch ein geeignetes Smartphone. Die nachfolgende Übersicht stellt dar, in welchem Status sich ein angeschlossenes Kartenlesegerät oder verbundenes Smartphone befindet. + + + + Smartphone as card reader + Smartphone als Kartenleser + + + + No smartphone with enabled remote service found. See online help for details of use. + Es wurde kein Smartphone mit aktiviertem Fernzugriff gefunden. Details zur Verwendung finden Sie in der Online-Hilfe. + + + + Pair + Koppeln + + + + Forget + Verwerfen + + + + Card readers + Kartenlesegeräte + + + + No connected card reader found. See online help for installation of card readers. + Es wurde kein angeschlossenes Kartenlesegerät gefunden. Details zur Installation von Kartenlesegeräten finden Sie in der Online-Hilfe. + + + + After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. + Nachdem ein neues Kartenlesegerät angeschlossen worden ist, kann es einige Sekunden dauern bis der Treiber erkannt wird. Unter Umständen kann ein Neustart Ihres Betriebssystems notwendig sein. + + + TextLabel TextLabel + + + RemotePinInputDialog - - After connecting a new card reader it can take some seconds to recognize the driver. - Nachdem ein neues Kartenlesegerät angeschlossen worden ist, kann es einige Sekunden dauern bis der Treiber erkannt wird. + + Pairing code entry + Eingabe des Kopplungscodes + + + + Enter the 4-digit pairing code shown on your other device. + Geben Sie den 4-stelligen Kopplungscode ein, der auf Ihrem anderen Gerät angezeigt wird. + + + + RemoteServicePairingPopup + + + Pairing code + Kopplungscode + + + + Enter the pairing code shown on your other device to use it as a card reader + Geben Sie den Kopplungscode ein, der auf Ihrem anderen Gerät angezeigt wird, um es als Kartenlesegerät zu verwenden + + + + Enter this code on your other device to use this device as a card reader + Geben Sie diesen Code auf Ihrem anderen Gerät ein, um dieses Gerät als Kartenlesegerät zu verwenden + + + + Start pairing + Kopplung starten + + + + RemoteServiceSettings + + + Configure remote service + Fernzugriff konfigurieren + + + + Pairing failed. Please try again to activate pairing on your other device and enter the shown pairing code. + Die Kopplung ist fehlgeschlagen. Bitte starten Sie eine neue Kopplung an Ihrem anderen Gerät und geben den angezeigten Kopplungscode ein. + + + + Device name + Gerätename + + + + Choose a device name here to identify it in the network: + Wählen Sie einen Gerätenamen, unter dem Ihr Smartphone im Netzwerk gefunden werden kann: + + + + PIN pad mode + Tastaturmodus + + + + Enter PIN on smartphone + PIN-Eingabe auf dem Smartphone + + + + Paired devices + Gekoppelte Geräte + + + + No device is paired. + Kein Gerät gekoppelt. + + + + Available devices + Verfügbare Geräte + + + + No new remote reader was found on your network. Make sure that the remote reader functionality in AusweisApp2 on your other device is activated and that your devices are connected to the same network. + Kein entferntes Kartenlesegerät in Ihrem Netzwerk verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem anderen Gerät aktiviert ist. Beide Geräte müssen sich im selben Netzwerk befinden. + + + + Start the pairing mode on the other device if it is not already started. + Aktivieren Sie den Kopplungsmodus auf dem anderen Gerät wenn er noch nicht aktiviert sein sollte. + + + + OK + OK + + + + RemoteServiceView + + + Smartphone as card reader + Smartphone als Kartenlesegerät + + + + Please start the remote service in order to use your smartphone as a card reader with AusweisApp2. Please note: Both your devices have to be connected to the same WiFi. + Bitte starten Sie den Fernzugriff, damit Sie Ihr Smartphone als Kartenlesegerät für die AusweisApp2 nutzen können. Bitte beachten Sie: dies ist nur möglich, wenn beide Geräte mit demselben WLAN verbunden sind. + + + + Enable NFC + NFC aktivieren + + + + Stop remote service + Fernzugriff stoppen + + + + Start remote service + Fernzugriff starten + + + + Start pairing + Kopplung starten + + + + Card access in progress + Kartenzugriff + + + + Please pay attention to the display on your other device. + Bitte beachten Sie die Anzeige auf Ihrem anderen Gerät. + + + + Settings + Einstellungen + + + + RemoteWorkflow + + + Enable Wifi + WLAN aktivieren + + + + Continue + Fortsetzen + + + + Establish connection + Verbindung wird hergestellt + + + + Determine card + Ermittle Ausweis + + + + To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. + Um den Fernzugriff zu nutzen muss WLAN aktiviert werden. Bitte aktivieren Sie WLAN in Ihren Einstellungen. + + + + No paired and activated remote device was detected. Make sure that you have started remote service on you remote device. + Kein gekoppeltes und aktiviertes Gerät gefunden. Stellen Sie sicher, dass der Fernzugriff auf Ihrem Gerät gestartet wurde. + + + + Please insert your ID card. + Bitte legen Sie Ihren Ausweis auf. ResultView - - + + Ok Ok @@ -1844,12 +2160,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe SearchBar - + Search Suchen - + Cancel Abbrechen @@ -1857,17 +2173,17 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe SelfAuthenticationData - + Identify Ausweisen - + Successfull reading data Daten erfolgreich gelesen - + Ok Ok @@ -1875,7 +2191,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe SelfInfoWidget - + The following data has been read out from your ID card: Folgende Daten wurden aus Ihrem Ausweisdokument ausgelesen: @@ -1883,27 +2199,27 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe SelfInformationWidget - + You can use your ID card anywhere you see this logo. Überall wo Sie dieses Logo sehen, können Sie Ihr Ausweisdokument einsetzen. - + See my personal data Meine Daten 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. - + eID Logo eID Logo @@ -1911,154 +2227,134 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe SettingsWidget - + General Allgemein - + PIN Management PIN-Verwaltung - + Diagnosis... Diagnose... - + Cancel Abbrechen - + Apply Übernehmen - - Look for Driver - Treibersuche + + Card Readers + Kartenlesegeräte StepAuthenticationEac1Widget - + AusweisApp2 AusweisApp2 - - <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> - - - + Service provider Diensteanbieter - + Purpose for reading out requested data: Zweck des Auslesevorgangs: - + Name: Name: - + more... mehr... - - <html><head/><body><p align="justify">Here you can select or deselect data fields to be read out. Mandatory data fields required by the service provider cannot be deselected.</p></body></html> - <html><head/><body><p align="justify">Hier können Sie die Datenfelder an/abwählen, die ausgelesen werden sollen. Felder, die Sie nicht abwählen können, sind durch den Diensteanbieter als Pflichtfelder festgelegt worden. Diese Felder sind daher nicht abwählbar.</p></body></html> - - - + Data Daten - + Important transactional information Wichtige Transaktionsinformationen - + The following data is required by the service provider. You can deselect the non-mandatory data fields if you do not want this data to be transmitted. Folgende Daten werden von dem Diensteanbieter benötigt. Bei Datenfeldern, die als "abwählbar" gekennzeichnet sind, können Sie entscheiden, ob Sie diese Daten übermitteln möchten. - + details Details - SupportView + TechnologyInfo - - Support - Support - - - - Via Email - per E-Mail - - - - You can reach our email support at <a href="mailto:support@ausweisapp.de">support@ausweisapp.de</a> - Sie können unseren E-Mail- Support erreichen unter: <a href="mailto:support@ausweisapp.de">support@ausweisapp.de</a> - - - - Via Phone - Per Telefon - - - - You can reach our phone support at <a href="tel:+491805348743">+49 1805 348 743</a> (*14 ct./Minute from German landlines, mobile price may vary) - Sie können unsere E-Mail- Support erreichen unter: <a href="tel:+491805348743">+49 1805 348 743</a> (*14 ct./Minute, Mobilfunk kann abweichen) - - - - Support availability - Erreichbarkeit - - - - Support is available from 9.00 to 17.00 on Monday-Friday, except on national holidays. - Unser Support ist erreichbar von Montag bis Freitag 09:00-17:00, außer an Feiertagen. + + The device %1 was unpaired because it does not react to connection attempts. Retry the pairing process if you want to use this device to authenticate yourself. + Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Versuchen Sie das Gerät erneut zu koppeln wenn sie es zur Selbstauthentifizierung verwenden möchten. - TitleBar + TechnologySwitch - - Identify - Ausweisen + + NFC + NFC + + + + WiFi + WLAN + + + + Bluetooth + Bluetooth + + + + Use WiFi card reader instead<br/>of Bluetooth card reader + WLAN Kartenlesegerät anstelle <br/>vom Bluetooth Kartenlesegerät verwenden + + + + Use Bluetooth card reader instead<br/>of remote card reader + Bluetooth Kartenlesegerät anstelle <br/>vom WLAN Kartenlesegerät verwenden TitleBarAction - + Cancel Abbrechen - + Edit Bearbeiten - + < back < Zurück @@ -2066,57 +2362,52 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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 @@ -2124,7 +2415,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe VersionInformation - + Version Information Versionsinformationen @@ -2132,27 +2423,27 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::AboutDialog - - About %1 - Über %1 + + Further information + Weitere Informationen - - <b>Further information:</b> %1 - <b>Weitere Informationen:</b> %1 + + Version + Version - - The current release notes can be found %1 here. %2 - Die aktuellen Release-Notes finden Sie %1 hier. %2 + + The current release notes can be found %1 here.%2 + Die aktuellen Release-Notes finden Sie %1 hier.%2 - - <b>Version:</b> %1 (%2) - <b>Version:</b> %1 (%2) + + About %1 - %2 + Über %1 - %2 - + The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2. 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. @@ -2160,165 +2451,165 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::AccessRoleAndRightsUtil - + WRITE_DG17 WRITE_DG17 - + WRITE_DG18 WRITE_DG18 - + WRITE_DG19 WRITE_DG19 - + WRITE_DG20 WRITE_DG20 - + WRITE_DG21 WRITE_DG21 - - + + Optional data Optionale Daten - + Residence permit II Nebenbestimmungen II - + Residence permit I Nebenbestimmungen I (nur eAT) - + Pseudonym Pseudonym - + Address Anschrift - + Birth name Geburtsname - + Date of birth Geburtsdatum - + Doctoral degree Doktorgrad - + Religious / artistic name Ordens- / Künstlername - + Given name(s) Vorname(n) - + Valid until Gültig bis - + Issuing country Ausstellender Staat - + Address verification Wohnortbestätigung + - RFU RFU - + Community-ID Wohnort-ID - + Gender Geschlecht - + Nationality Staatsangehörigkeit - + Place of birth Geburtsort - + Family name Familienname - + Document type Dokumentenart - + Installation of qualified signature certificates Installation qualifizierter Signaturzertifikate - + Installation of signature certificates Installation von Signaturzertifikaten - + PIN Management PIN-Verwaltung - + CAN allowed CAN erlaubt - + Privileged terminal Privilegiertes Terminal - + Age verification Altersbestätigung - + Unknown Unbekannt @@ -2326,131 +2617,145 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::AppQtGui - + AusweisApp2 was started. AusweisApp2 wurde gestartet. - - Don't show this dialog again. + + Do not show this dialog again. Diesen Hinweis nicht mehr anzeigen. - + Open Öffnen - + + Updates + Aktualisierungen + + + + + + Information + Information + + + 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. + + + Your software is up to date. + Ihre Software ist auf dem aktuellen Stand. + governikus::AppQtMainWidget - - Save file - Datei speichern - - - + https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/ https://www.ausweisapp.bund.de/service/haeufig-gestellte-fragen/ - + https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/ https://www.ausweisapp.bund.de/feedback/melden-sie-einen-fehler/ - + https://www.ausweisapp.bund.de/en/feedback/bewerten-sie-uns/ https://www.ausweisapp.bund.de/feedback/bewerten-sie-uns/ - governikus::CardReaderPage + governikus::CardInfo - - <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> + + not inserted + Karte + nicht eingelegt - - 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 detected card readers and the status of the corresponding driver. - + + unknown type + Karte + unbekannter Typ - - 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 detected card readers and the status of the corresponding driver. - + + ID card (PA/eAT) + Ausweisdokument (PA/eAT) governikus::CertificateDescriptionModel - + Service provider Diensteanbieter - + Certificate issuer 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 @@ -2458,7 +2763,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::CredentialDialog - + Proxy security Proxy-Sicherheit @@ -2466,37 +2771,37 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DeleteHistoryDialog - + Delete history Verlauf löschen - + Delete history for this period: Verlauf für diesen Zeitraum löschen: - + Past hour Letzte Stunde - + Past day Letzter Tag - + Past week Letzte Woche - + Last four weeks Letzte vier Wochen - + All history Gesamter Zeitraum @@ -2504,7 +2809,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DetailDialog - + Service provider data Angaben zum Diensteanbieter @@ -2512,12 +2817,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DetailWidget - - Details - Details - - - + Service provider details dialog Dialog mit Details des Diensteanbieters @@ -2525,17 +2825,17 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DiagnosisController - + pcsclite %1 pcsclite %1 - + unknown unbekannt - + not available nicht verfügbar @@ -2543,32 +2843,32 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DiagnosisDialog - + Diagnosis Diagnose - + Save diagnosis result Diagnoseergebnis speichern - - /AusweisApp2-diagnosis.txt - /AusweisApp2-Diagnose.txt + + AusweisApp2-diagnosis.txt + AusweisApp2-Diagnose.txt - + Text files (*.txt) Textdateien (*.txt) - + File error Dateifehler - + An error occurred while saving the file. Beim Speichern der Datei ist ein Fehler aufgetreten. @@ -2576,614 +2876,633 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::DiagnosisWidget - - - - + + + + Diagnosis is running... Diagnose läuft... - - + Diagnosis Diagnose - - + + Operating system Betriebssystem - - + + Card reader Kartenlesegerät - - + + PC/SC PC/SC - - + + Time of diagnosis Diagnosezeitpunkt - - - - + + + + Version: %1 Version: %1 - + Components Komponenten - + Components: Komponenten: - + Driver Treiber - + Driver: Treiber: - - + + not recognised keine erkannt - + Basic card reader Basis-Kartenlesegerät - + Standard / deluxe card reader Standard-/Komfort-Kartenlesegerät - - + + Type: %1 Typ: %1 - - not inserted - Karte - keine eingesteckt - - - - unknown type - Karte - unbekannter Typ - - - - ID card (PA/eAT) - Ausweisdokument (PA/eAT) - - - - + + Card: %1 Karte: %1 - - + + Retry counter: %1 Fehlbedienungszähler: %1 - - MMMM dd yyyy, hh:mm:ss AP - d. MMMM yyyy',' hh:mm:ss 'Uhr' + + d. MMMM yyyy, hh:mm:ss AP + d. MMMM yyyy, HH:mm:ss Uhr - - + + Vendor: %1 Hersteller: %1 - - + + File path: %1 Dateipfad: %1 - - governikus::GeneralSettingsWidget - - - General - 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>. - + + Cannot start authentication. An operation is already in progress. + Die Authentisierung kann nicht gestartet werden. Es läuft bereits eine Operation. + + + Using the developer mode is only allowed in a test environment. Der Entwicklermodus darf nur in einer Testumgebung verwendet werden. - + + The service is temporarily not available. Please try again later. + Der Dienst ist vorübergehend nicht verfügbar, bitte versuchen Sie es zu einem späteren Zeitpunkt erneut. + + + 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. + + An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again. + Bei der Kommunikation mit dem Ausweisdokument ist ein Fehler aufgetreten. Bitte überprüfen Sie, dass das Ausweisdokument korrekt aufgelegt ist und versuchen Sie es erneut. - - A protocol error has occurred. - Ein Protokollfehler ist aufgetreten. + + A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at + Ein Protokollfehler ist aufgetreten. Bitte überprüfen Sie, dass das Ausweisdokument korrekt aufgelegt ist und versuchen Sie es erneut. Wenn das Problem wieder auftritt kontaktieren Sie bitte unseren Support unter - + + https://www.ausweisapp.bund.de/en/service/support/ + https://www.ausweisapp.bund.de/service/support/ + + + + AusweisApp2 Support + AusweisApp2 Support + + + 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. + Es ist ein Fehler während des Verbindungsaufbaus zu einem Kartenlesegerät aufgetreten. - + An error occurred while scanning for reader devices. - Es ist ein Fehler während der Suche nach einem Kartenleser aufgetreten. + Es ist ein Fehler während der Suche nach einem Kartenlesegerät aufgetreten. - + The remote reader connection was closed properly. - Die Verbindung zum Remote-Lesegerät wurde ordnungsgemäß geschlossen. + Die Verbindung zum entfernten Kartenlesegerä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. + + + Remote reader connection request contains invalid parameters. + Die Verbindungsanforderung zum entfernten Kartenlesegerät enthält einen ungültigen Parameter. + + + + Empty password in extended encryption of remote reader connection request. + Die Anforderung der erweiterten Verschlüsselung mit dem entfernten Kartenlesegerät enthält ein leeres Kennwort. + + + + Remote reader connection request does not contain any supported API level. + Die Verbindungsanforderung zum entfernten Kartenlesegerät enthält keine unterstützte API-Version. + + + + A timeout occurred while trying to establish a connection to a remote reader. + Bei der Verbindung zum entfernten Kartenlesegerät kam es zu einer Zeitüberschreitung. + + + + An error occurred while trying to establish a connection to a remote reader. + Bei der Verbindung zum entfernten Kartenlesegerät ist ein Fehler aufgetreten. + + + + Remote device has rejected the connection. Please check the pairing code. + Das zu koppelnde Gerät hat die Verbindung verweigert. Überprüfen Sie bitte den Kopplungscode. + + + + File not found. + Datei nicht gefunden. + + + + Cannot save file. + Speichern der Datei nicht möglich. + + + + Received data were corrupted. + Die empfangenen Daten waren beschädigt. + 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 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? - - governikus::HistoryDetailWidget - - - History details - Anbieterinformationen - - governikus::HistoryModelSearchFilter - MM/dd/yyyy + dd.MM.yyyy dd.MM.yyyy governikus::HistoryWidget - - History - Verlauf - - - + Date Datum - + Details Details - - - - MM/dd/yyyy hh:mm AP + + dd.MM.yyyy hh:mm AP dd.MM.yyyy HH:mm - + Date: Datum: - - <b>Provider:</b> - <b>Diensteanbieter:</b> + + Provider + Diensteanbieter - - <b>Purpose:</b> - <b>Zweck:</b> + + Purpose + Zweck - - <b>Data:</b> - <b>Daten:</b> + + Data + Daten - - Save history - Verlauf speichern + + AusweisApp2.History.%1.pdf + AusweisApp2.Verlauf.%1.pdf - - PDF Documents (*.pdf) - PDF Dokumente (*.pdf) + + Save + Speichern + + + + PDF Documents + PDF-Dokumente governikus::LogFilesDialog - + Log Protokoll - + Current log Akuelles Protokoll - - MM/dd/yyyy hh:mm:ss - dd.MM.yyyy hh:mm:ss + + dd.MM.yyyy hh:mm:ss AP + dd.MM.yyyy HH:mm:ss - + File could not be opened: - Datei kann nicht geöffnet werden: + Datei kann nicht geöffnet werden: - + File is larger than 3 MB and can not be displayed: - Die Datei ist größer als 3MB und kann nicht angezeigt werden: + Die Datei ist größer als 3MB und kann nicht angezeigt werden: - + Delete log files Protokolle löschen - + Do you really want to delete all old log files? Wolle Sie wirklich alle alten Protokolle löschen? - - Save log file - Protokoll speichern + + Save + Speichern - - /AusweisApp2-logfile.log - /AusweisApp2-logfile.log - - - - Text files (*.txt) - Textdateien (*.txt) - - - + File error Dateifehler - + An error occurred while saving the file. Beim Speichern der Datei ist ein Fehler aufgetreten. @@ -3191,58 +3510,35 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::LogHandler - + An error occurred in log handling: %1 Es ist ein Fehler bei der Protokollverwaltung aufgetreten: %1 - - governikus::MainPage - - - Identify - Ausweisen - - - - Provider - Anbieter - - - - History - Verlauf - - - - Settings - Einstellungen - - governikus::NumberModel - - You have entered a wrong PIN, please try again. - Sie haben eine falsche PIN eingegeben. Bitte versuchen Sie es erneut. + + The given PIN is not correct. You have 2 tries to enter the correct PIN. + Die eingegebene PIN ist nicht korrekt. Sie haben noch 2 weitere Möglichkeiten die korrekte PIN einzugeben. - - 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. + + You have entered the wrong PIN twice. Prior to 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. - + You have entered a wrong CAN, please try again. 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. @@ -3250,73 +3546,87 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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 + governikus::PdfExporter - - 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 AP dd.MM.yyyy HH:mm - + Provider: Diensteanbieter: - + Purpose: Zweck: - + Data: Daten: - - - governikus::PinSettingsInfoWidget - + + + dd.MM.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: + + + + History + Verlauf + + + + Entry + Eintrag + + + + Content + Inhalt + + + + 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: + + + Information Information @@ -3324,89 +3634,85 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::PinSettingsWidget - - PIN Management - PIN-Verwaltung - - - - - - - + + + + + Only digits (0-9) are allowed. Es sind nur Ziffern (0-9) erlaubt. - + Enter PUK PUK eingeben - + Change PIN PIN ändern - + The PIN in the field "%1" does not match the PIN in the field "%2". Die PIN im Feld "%1" stimmt nicht mit der PIN im Feld "%2" überein. - - The PIN match. + + + PIN correct. Die PIN stimmt überein. - - card reader icon - Icon des Kartenlesers + + Card reader icon + Icon des Kartenlesegeräts - - empty card reader icon - Kein Kartenleser icon + + Empty card reader icon + Kein Kartenlesegerät 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 @@ -3414,17 +3720,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::ProviderWidget - - Provider - Diensteanbieter - - - + Name Name - + Address Adresse @@ -3432,7 +3733,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::QmlExtension - + Send application log per email... Anwendungsprotokoll per E-Mail senden... @@ -3440,273 +3741,355 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::RandomPinDialog - + On screen password Bildschirmtastatur - governikus::ReaderDriverDialog + governikus::ReaderDeviceDialog - + Reader Driver Integration Treiber für Kartenlesegeräte - governikus::ReaderDriverWidget + governikus::ReaderDeviceWidget - - Reader driver integration - Treiber für Kartenlesegeräte + + No card reader detected + Kein Kartenlesegerät erkannt - - Device - Gerät + + Select a device to display more information about it + Wählen Sie ein Kartenlesegerät aus, um mehr Informationen zu erhalten - - Status - Status - - - - - Installed - Installiert - - - - - Searching for driver... - Ein passender Treiber wird gesucht... - - - - <html><body><p>No card reader detected</p></body></html> - <html><body><p>Kein Kartenleser gefunden</p></body></html - - - - <html><body><p>Select a device to display more information about it</p></body></html> - <html><body><p>Bitte wählen Sie ein Gerät aus, um sich mehr Informationen anzeigen zu lassen</p></body></html - - - - <html><body><p>Device is installed correctly</p></body></html> - <html><body><p>Das Gerät ist korrekt installiert</p></body></html - - - - <html><body><p>Device is not configured, please download and install the driver you can find at url: <a href="%1">%1</a></p></body></html> - <html><body><p>Der Treiber für das Gerät ist nicht installiert, bitte installieren Sie den Treiber, den Sie über diese Adresse herunterladen können: <a href="%1">%1</a></p></body></html> - - - - The list of card readers was last updated at %1. - Die Liste der Kartenlesegeräte wurde zuletzt am %1 aktualisiert. - - - + hh:mm:ss AP HH:mm:ss - - Not installed - Nicht installiert + + The list of card readers was last updated at %1. + Die Liste der Kartenlesegeräte wurde zuletzt um %1 aktualisiert. + + + + Start the pairing mode on the other device if it is not already started. + Aktivieren Sie den Kopplungsmodus auf dem anderen Gerät wenn er noch nicht aktiviert sein sollte. + + + + Pairing + Kopplung + + + + governikus::ReaderDriverModel + + + Connected w/ driver + Angeschlossen mit Treiber + + + + Connected w/o driver + Angeschlossen ohne Treiber + + + + Not connected + Nicht angeschlossen + + + + Device + Gerät + + + + Status + Status + + + + Device is installed correctly. + Das Kartenlesegerät ist korrekt installiert. + + + + Device is not configured, please download and install the driver you can find at url: %1 + Für das Kartenlesegerät wurden keine Treiber erkannt, bitte installieren Sie den Treiber: %1 + + + + governikus::RemoteDeviceModel + + + Not connected + Nicht verbunden + + + + Paired and available + Gekoppelt und verfügbar + + + + Paired and not available + Gekoppelt aber nicht verfügbar + + + + Not paired + Nicht gekoppelt + + + + Device + Gerät + + + + Status + Status + + + + dd.MM.YYYY hh:mm AP + dd.MM.yyyy HH:mm + + + + governikus::RemotePinInputDialog + + + Only digits (0-9) are allowed. + Es sind nur Ziffern (0-9) erlaubt. + + + + A pairing code has to be 4 digits long. + Ein Kopplungscode besteht aus 4 Ziffern. + + + + governikus::RemoteServiceModel + + + NFC is not available on your device. + NFC ist auf Ihrem Gerät nicht verfügbar. + + + + Please enable NFC to use the remote service. + Bitte aktivieren Sie NFC, um den Fernzugriff zu benutzen. + + + + Please connect your WiFi to use the remote service. + Bitte verbinden Sie sich mit Ihrem WLAN, um den Fernzugriff zu benutzen. + + + + governikus::RemoteServiceSettings + + + Remote Reader + Entferntes Kartenlesegeräte 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. - + 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. + + The process was cancelled by the 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 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. + + This action cannot be performed. The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document 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 Behörde, die Ihr Ausweisdokument ausgegeben hat, 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::SelfAuthenticationData + governikus::SelfData - + This data has not been stored in this chip generation. Diese Datengruppe wurde in dieser Chip-Generation nicht gespeichert. - - - governikus::SelfAuthenticationModel - + + dd.MM.yyyy + dd.MM.yyyy + + + Family name Familienname - + Birth name Geburtsname - + Given name(s) Vorname(n) - + Doctoral degree Doktorgrad - - MM/dd/yyyy - dd.MM.yyyy - - - + Date of birth Geburtsdatum - + Place of birth Geburtsort - + + + Address - Anschrift + Adresse - + Document type Dokumentenart - + Nationality Staatsangehörigkeit - + Religious / artistic name Ordens- / Künstlername - + Issuing country Ausstellender Staat - + Residence permit I Nebenbestimmungen I (nur eAT) @@ -3714,114 +4097,27 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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... - - 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 - + + AusweisApp2.Information.%1.pdf + AusweisApp2.Selbstauskunft.%1.pdf + + + Save Speichern - + PDF Documents PDF-Dokumente @@ -3829,167 +4125,127 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::SelfInformationWidget - - Identify - Ausweisen + + Test environment + Testumgebung governikus::SettingsWidget - - Settings - Einstellungen - - - + Apply Übernehmen - + + Developer Settings + Entwicklereinstellungen + + + Apply settings? Einstellungen übernehmen? - + Do you want to apply the changes? Möchten Sie die Änderungen übernehmen? + + + OK + OK + governikus::SetupAssistantWizard - - - setup assistant - - 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> - - - - 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 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 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 - - - + 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">Schritt %1 von %2</div><div align="left">Fast fertig!</div> + + setup assistant + Einrichtungsassistent - - History: - Verlauf: + + + Step %1 of %2 + Schritt %1 von %2 - + + Introduction + Einleitung + + + + History + Verlauf + + + + AusweisApp2 offers saving the course of your authentications in a history. Subsequently you can activate this option. + 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. + + + save speichern - + save history Verlauf speichern + + + Card Readers + Kartenlesegeräte + + + + Firefox extension NoScript + Firefox-Erweiterung NoScript + + + + Almost done! + Fast fertig! + + + + Personal 6 - digit PIN + Persönliche 6-stellige 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. + 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. + + + + 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. + 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". + governikus::StateChangePin - + You have successfully changed your PIN. Sie haben Ihre PIN erfolgreich geändert. @@ -3997,7 +4253,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StateEstablishPacePuk - + PIN successfully unblocked PIN erfolgreich entsperrt @@ -4005,7 +4261,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StateWriteHistory - + Validity: %1 - %2 Gültigkeit: @@ -4015,7 +4271,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StepAdviseUserToRemoveCardGui - + + Information + Information + + + You may now remove your ID card from the card reader. Sie können nun Ihr Ausweisdokument vom Kartenlesegerät entfernen. @@ -4023,12 +4284,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StepAuthenticationEac1Gui - + Information Information - + Please observe the display of your card reader. Bitte beachten Sie die Anzeige Ihres Kartenlesegeräts. @@ -4036,121 +4297,130 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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: - + + Information on the service provider who wants to read out data from your ID card is given here. For further information press the button "more...". + 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 "mehr...". + + + + Here you can select or deselect data fields to be read out. Mandatory data fields required by the service provider cannot be deselected. + Hier können Sie die Datenfelder an/abwählen, die ausgelesen werden sollen. Felder, die Sie nicht abwählen können, sind durch den Diensteanbieter als Pflichtfelder festgelegt worden. Diese Felder sind daher nicht abwählbar. + + + Card access number (CAN): Zugangsnummer (CAN): - - - open on screen password dialog + + + Open on screen password dialog Öffnen Sie den Bildschirmtastatur-Passwortdialog - + More information with TAB Weitere Informationen mit dem Tabulator - + PIN: PIN: @@ -4158,65 +4428,101 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StepChooseCardGui - + + Information + Information + + + Cancel Abbrechen - + Diagnosis Diagnose - + + Settings + Einstellungen + + + 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 would like to set up a local or remote card reader, click on the "Settings" button to cancel the current operation and open the reader settings. + Wenn Sie ein lokales oder entferntes Kartenlesegerät einrichten wollen, klicken Sie auf die Schaltfläche "Einstellungen", um den laufenden Vorgang abzubrechen und die Einstellungen für das Kartenlesegerät zu öffnen. + + + 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. - + + + Extended Length is not supported. + Extended Length wird nicht überstützt. + + + + Your remote reader does not meet the technical requirements (Extended Length not supported). + Ihr entferntes Kartenlesegerät erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt). + + + + At least one of your card readers does not meet the technical requirements (Extended Length not supported). Please place the ID card on a different card reader. + Mindestens eines Ihrer Kartenlesegeräte erfüllt leider nicht die technischen Voraussetzungen (Extended Length wird nicht unterstützt). Bitte platzieren Sie Ihren Ausweis auf einem anderen Kartenlesegerät. + + + 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. - + Online identification function is disabled. Die Online-Ausweisfunktion ist deaktiviert. - - 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. + + This action cannot be performed. The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document 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 Behörde, die Ihr Ausweisdokument ausgegeben hat, um die Online-Ausweisfunktion zu aktivieren. + + + + The device %1 was unpaired because it does not react to connection attempts. Retry the pairing process if you want to use this device to authenticate yourself. + Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Versuchen Sie das Gerät erneut zu koppeln wenn sie es zur Selbstauthentifizierung verwenden möchten. 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 @@ -4224,7 +4530,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::StepShowSelfAuthenticationDataGui - + Close Schließen @@ -4232,22 +4538,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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> @@ -4255,67 +4551,67 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::VersionInformationModel - + Application Name Anwendungsname - + Application Version Anwendungsversion - + Organization Organisation - + Organization domain Organisation Homepage - + Build date 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 @@ -4323,75 +4619,75 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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> @@ -4399,63 +4695,62 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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)! @@ -4463,22 +4758,22 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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. @@ -4486,12 +4781,12 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::WorkflowQtWidget - + Cancel Abbrechen - + Next Weiter @@ -4499,7 +4794,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe governikus::WorkflowSelfInfoQtGui - + Identify Ausweisen @@ -4507,7 +4802,7 @@ Bitte beachten Sie, dass Sie mit Ihrer PUK lediglich Ihren Online-Ausweis entspe 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/resources/updatable-files/reader/img_ACS_ACR122U.png b/resources/updatable-files/reader/img_ACS_ACR122U.png new file mode 100644 index 0000000..1db843b Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR122U.png differ diff --git a/resources/updatable-files/reader/img_ACS_ACR122U_mit_ausweis.png b/resources/updatable-files/reader/img_ACS_ACR122U_mit_ausweis.png new file mode 100644 index 0000000..b76259f Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR122U_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_ACS_ACR1252U.png b/resources/updatable-files/reader/img_ACS_ACR1252U.png new file mode 100644 index 0000000..d16198c Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR1252U.png differ diff --git a/resources/updatable-files/reader/img_ACS_ACR1252U_mit_ausweis.png b/resources/updatable-files/reader/img_ACS_ACR1252U_mit_ausweis.png new file mode 100644 index 0000000..82645a9 Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR1252U_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_ACS_ACR1281U.png b/resources/updatable-files/reader/img_ACS_ACR1281U.png new file mode 100644 index 0000000..a4a6a2c Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR1281U.png differ diff --git a/resources/updatable-files/reader/img_ACS_ACR1281U_mit_ausweis.png b/resources/updatable-files/reader/img_ACS_ACR1281U_mit_ausweis.png new file mode 100644 index 0000000..ff2e55b Binary files /dev/null and b/resources/updatable-files/reader/img_ACS_ACR1281U_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Cherry_TC_1200.png b/resources/updatable-files/reader/img_Cherry_TC_1200.png new file mode 100644 index 0000000..f17e897 Binary files /dev/null and b/resources/updatable-files/reader/img_Cherry_TC_1200.png differ diff --git a/resources/updatable-files/reader/img_Cherry_TC_1200_mit_ausweis.png b/resources/updatable-files/reader/img_Cherry_TC_1200_mit_ausweis.png new file mode 100644 index 0000000..67736d2 Binary files /dev/null and b/resources/updatable-files/reader/img_Cherry_TC_1200_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Cherry_TC_1300.png b/resources/updatable-files/reader/img_Cherry_TC_1300.png new file mode 100644 index 0000000..2b8479e Binary files /dev/null and b/resources/updatable-files/reader/img_Cherry_TC_1300.png differ diff --git a/resources/updatable-files/reader/img_Cherry_TC_1300_mit_ausweis.png b/resources/updatable-files/reader/img_Cherry_TC_1300_mit_ausweis.png new file mode 100644 index 0000000..dec65ec Binary files /dev/null and b/resources/updatable-files/reader/img_Cherry_TC_1300_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_FEIG_myAXXES_basic.png b/resources/updatable-files/reader/img_FEIG_myAXXES_basic.png new file mode 100644 index 0000000..ddebb47 Binary files /dev/null and b/resources/updatable-files/reader/img_FEIG_myAXXES_basic.png differ diff --git a/resources/updatable-files/reader/img_FEIG_myAXXES_basic_mit_ausweis.png b/resources/updatable-files/reader/img_FEIG_myAXXES_basic_mit_ausweis.png new file mode 100644 index 0000000..b7a608c Binary files /dev/null and b/resources/updatable-files/reader/img_FEIG_myAXXES_basic_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Gemalto_Prox_DU.png b/resources/updatable-files/reader/img_Gemalto_Prox_DU.png new file mode 100644 index 0000000..40da58d Binary files /dev/null and b/resources/updatable-files/reader/img_Gemalto_Prox_DU.png differ diff --git a/resources/updatable-files/reader/img_Gemalto_Prox_DU_mit_ausweis.png b/resources/updatable-files/reader/img_Gemalto_Prox_DU_mit_ausweis.png new file mode 100644 index 0000000..cdcbc09 Binary files /dev/null and b/resources/updatable-files/reader/img_Gemalto_Prox_DU_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Gemalto_Prox_SU.png b/resources/updatable-files/reader/img_Gemalto_Prox_SU.png new file mode 100644 index 0000000..eb6ab50 Binary files /dev/null and b/resources/updatable-files/reader/img_Gemalto_Prox_SU.png differ diff --git a/resources/updatable-files/reader/img_Gemalto_Prox_SU_mit_ausweis.png b/resources/updatable-files/reader/img_Gemalto_Prox_SU_mit_ausweis.png new file mode 100644 index 0000000..9d13a00 Binary files /dev/null and b/resources/updatable-files/reader/img_Gemalto_Prox_SU_mit_ausweis.png differ diff --git a/resources/images/reader/img_HID_Global_OMNIKEY_5321_V2.png b/resources/updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2.png similarity index 100% rename from resources/images/reader/img_HID_Global_OMNIKEY_5321_V2.png rename to resources/updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2.png diff --git a/resources/images/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png b/resources/updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png similarity index 100% rename from resources/images/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png rename to resources/updatable-files/reader/img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png diff --git a/resources/updatable-files/reader/img_HID_Omnikey_5421.png b/resources/updatable-files/reader/img_HID_Omnikey_5421.png new file mode 100644 index 0000000..b1d2882 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_5421.png differ diff --git a/resources/updatable-files/reader/img_HID_Omnikey_5421_mit_ausweis.png b/resources/updatable-files/reader/img_HID_Omnikey_5421_mit_ausweis.png new file mode 100644 index 0000000..651f061 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_5421_mit_ausweis.png differ diff --git a/resources/images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png similarity index 100% rename from resources/images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png rename to resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL.png diff --git a/resources/images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png similarity index 100% rename from resources/images/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png rename to resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png diff --git a/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL.png new file mode 100644 index 0000000..0bf6c98 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL.png differ diff --git a/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL_mit_ausweis.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL_mit_ausweis.png new file mode 100644 index 0000000..9ea5929 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5021_CL_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL.png new file mode 100644 index 0000000..0bf6c98 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL.png differ diff --git a/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL_mit_ausweis.png b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL_mit_ausweis.png new file mode 100644 index 0000000..9ea5929 Binary files /dev/null and b/resources/updatable-files/reader/img_HID_Omnikey_Mobile_Reader_5022_CL_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_3700_F.png b/resources/updatable-files/reader/img_Identive_Cloud_3700_F.png new file mode 100644 index 0000000..65f15e7 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_3700_F.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_3700_F_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_Cloud_3700_F_mit_ausweis.png new file mode 100644 index 0000000..6d21fda Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_3700_F_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_4700_F.png b/resources/updatable-files/reader/img_Identive_Cloud_4700_F.png new file mode 100644 index 0000000..fa36feb Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_4700_F.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_4700_F_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_Cloud_4700_F_mit_ausweis.png new file mode 100644 index 0000000..6fd89fd Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_4700_F_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_4701_F.png b/resources/updatable-files/reader/img_Identive_Cloud_4701_F.png new file mode 100644 index 0000000..fa36feb Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_4701_F.png differ diff --git a/resources/updatable-files/reader/img_Identive_Cloud_4701_F_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_Cloud_4701_F_mit_ausweis.png new file mode 100644 index 0000000..6fd89fd Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_Cloud_4701_F_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_SCL011.png b/resources/updatable-files/reader/img_Identive_SCL011.png new file mode 100644 index 0000000..bd66fab Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SCL011.png differ diff --git a/resources/updatable-files/reader/img_Identive_SCL011_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_SCL011_mit_ausweis.png new file mode 100644 index 0000000..55c4911 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SCL011_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_SCL3711.png b/resources/updatable-files/reader/img_Identive_SCL3711.png new file mode 100644 index 0000000..9ca7631 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SCL3711.png differ diff --git a/resources/updatable-files/reader/img_Identive_SCL3711_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_SCL3711_mit_ausweis.png new file mode 100644 index 0000000..d083386 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SCL3711_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_SDI010.png b/resources/updatable-files/reader/img_Identive_SDI010.png new file mode 100644 index 0000000..f8a35e7 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SDI010.png differ diff --git a/resources/updatable-files/reader/img_Identive_SDI010_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_SDI010_mit_ausweis.png new file mode 100644 index 0000000..03f28ab Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SDI010_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Identive_SDI011.png b/resources/updatable-files/reader/img_Identive_SDI011.png new file mode 100644 index 0000000..f8a35e7 Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SDI011.png differ diff --git a/resources/updatable-files/reader/img_Identive_SDI011_mit_ausweis.png b/resources/updatable-files/reader/img_Identive_SDI011_mit_ausweis.png new file mode 100644 index 0000000..03f28ab Binary files /dev/null and b/resources/updatable-files/reader/img_Identive_SDI011_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_KOBIL_ID_Token.png b/resources/updatable-files/reader/img_KOBIL_ID_Token.png new file mode 100644 index 0000000..2fa9471 Binary files /dev/null and b/resources/updatable-files/reader/img_KOBIL_ID_Token.png differ diff --git a/resources/updatable-files/reader/img_KOBIL_ID_Token_mit_ausweis.png b/resources/updatable-files/reader/img_KOBIL_ID_Token_mit_ausweis.png new file mode 100644 index 0000000..55110d6 Binary files /dev/null and b/resources/updatable-files/reader/img_KOBIL_ID_Token_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis.png new file mode 100644 index 0000000..c0922bd Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png new file mode 100644 index 0000000..abb5554 Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png new file mode 100644 index 0000000..4b25072 Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png new file mode 100644 index 0000000..7c6949a Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard.png new file mode 100644 index 0000000..b380c7b Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard.png differ diff --git a/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png new file mode 100644 index 0000000..19d690d Binary files /dev/null and b/resources/updatable-files/reader/img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_RemoteReader.png b/resources/updatable-files/reader/img_RemoteReader.png new file mode 100644 index 0000000..dcbed16 Binary files /dev/null and b/resources/updatable-files/reader/img_RemoteReader.png differ diff --git a/resources/updatable-files/reader/img_RemoteReader_mit_ausweis.png b/resources/updatable-files/reader/img_RemoteReader_mit_ausweis.png new file mode 100644 index 0000000..8300272 Binary files /dev/null and b/resources/updatable-files/reader/img_RemoteReader_mit_ausweis.png differ diff --git a/resources/updatable-files/reader/img_cyberjack_wave.png b/resources/updatable-files/reader/img_cyberjack_wave.png new file mode 100644 index 0000000..a1aca61 Binary files /dev/null and b/resources/updatable-files/reader/img_cyberjack_wave.png differ diff --git a/resources/updatable-files/reader/img_cyberjack_wave_mit_ausweis.png b/resources/updatable-files/reader/img_cyberjack_wave_mit_ausweis.png new file mode 100644 index 0000000..12f6c74 Binary files /dev/null and b/resources/updatable-files/reader/img_cyberjack_wave_mit_ausweis.png differ diff --git a/resources/updatable-files/supported-providers.json b/resources/updatable-files/supported-providers.json new file mode 100644 index 0000000..f904c88 --- /dev/null +++ b/resources/updatable-files/supported-providers.json @@ -0,0 +1,952 @@ +{ + "issueDate": "2017-12-14T12: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/", + "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", + "subjectUrls": ["https://www.bitkasten.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Akteneinsicht in Stasi-Unterlagen"}, + "longName": {"" : "Akteneinsicht in Stasi-Unterlagen"}, + "shortDescription": {"": "Antragstellung auf Einsicht in Stasi-Unterlagen für Privatpersonen."}, + "longDescription": {"": "Privatpersonen können online mittels neuem Personalausweis ohne weitere Wege die Einsichtnahme in die von der Stasi angelegten Akten zur eigenen Person oder zu verstorbenen/vermissten nahen Angehörigen beantragen."}, + "address": "https://www.bstu.bund.de/DE/Akteneinsicht/Privatpersonen/Online-Antrag/online-antrag_node.html", + "homepage": "https://www.bstu.bund.de", + "phone": "+49 30 23 24-7000", + "email": "post@bstu.bund.de", + "postalAddress": "Der Bundesbeauftragte für die Unterlagen des Staatssicherheitsdienstes der ehemaligen Deutschen Demokratischen Republik (BStU)
Karl-Liebknecht-Straße 31/33
10178 Berlin", + "image": "stasi_image.jpg", + "icon": "stasi_icon.png", + "category": "citizen", + "subjectUrls": ["https://www.bstu-formulare.de/lip"] + }, + { + "exclude": ["ios", "android"], + "shortName": {"" : "Allianz Maklerportal"}, + "address": "https://makler.allianz.de", + "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.", + "subjectUrls": ["https://npa.allianz.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Ausweis Auskunft des Bundes"}, + "address": "https://www.buergerserviceportal.de/bund/ausweisapp/bspx_selbstauskunft", + "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", + "subjectUrls": ["https://www.buergerserviceportal.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG 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", + "homepage": "https://www.berlin-bafoeg.de", + "phone": "+49 30 939 39 - 70", + "email": "info@stw.berlin", + "postalAddress": "studierendenWERK BERLIN
BAföG-Amt
Behrenstraße 40/41
10117 Berlin", + "image": "BafoegBerlin_image.jpg", + "icon": "BafoegBerlin_icon.png", + "category": "citizen", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG Hessen"}, + "longName": {"" : "BAföG/AFBG hessenweit"}, + "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", + "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"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG Online"}, + "address": "https://www.bafoegonline.bva.bund.de/", + "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": "Bundesverwaltungsamt
BT-BAföG
50728 Köln", + "category": "citizen", + "tcTokenUrl" : "", + "clientUrl" : "https://www.bafoegonline.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeldenMitNpaPreFlow", + "subjectUrls": ["https://e-id.bva.bund.de"] + }, + { + "exclude": ["ios"], + "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", + "homepage": "https://afoegfofa.osrz-akdb.de", + "phone": "+49 89 / 5903 - 0", + "email": "", + "postalAddress": "Anstalt für Kommunale Datenverarbeitung in Bayern (AKDB)
Hansastraße 12-16
80686 München", + "category": "citizen", + "subjectUrls": ["https://www.buergerserviceportal.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG Online Bayern (Studentenwerk)"}, + "address": "https://www.bafoeg-bayern.de", + "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": [] + }, + { + "exclude": ["ios"], + "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", + "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"] + }, + { + "exclude": ["ios"], + "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", + "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"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG Online Mecklenburg-Vorpommern"}, + "address": "http://www.bm.regierung-mv.de/bafoeg", + "homepage": "http://www.regierung-mv.de/", + "phone": "", + "email": "", + "postalAddress": "Ministerium für Bildung, Wissenschaft und Kultur Mecklenburg-Vorpommern
Werderstraße 124
19055 Schwerin", + "category": "citizen", + "subjectUrls": ["https://fms.mv-regierung.de"] + }, + { + "exclude": ["ios"], + "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", + "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": [] + }, + { + "exclude": ["ios"], + "shortName": {"" : "BAföG Online Sachsen"}, + "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"] + }, + { + "exclude": ["ios"], + "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/", + "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" + }, + { + "exclude": ["ios", "android"], + "shortName": {"" : "bahn.de"}, + "address": "https://www.bahn.de/p/view/meinebahn/login.shtml", + "homepage": "https://www.bahn.de", + "phone": "+49 1806 - 996633", + "email": "reiseportal@bahn.de", + "postalAddress": "DB Vertrieb GmbH
Stephensonstraße 1
60326 Frankfurt am Main", + "category": "other", + "subjectUrls": ["https://www.bahn.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", + "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", + "homepage": "http://www.saarland.de/index.htm", + "phone": "+49 681/9978-2181", + "email": "", + "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.", + "subjectUrls": ["https://tbklas.saarland.de"] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": ["https://formular.arbeitsagentur.de"] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://epetitionen.bundestag.de"] + }, + { + "exclude": ["ios"], + "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": "webmaster@buergerschaft.bremen.de", + "postalAddress": "", + "category": "citizen", + "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": "https://www.stadt-muenster.de/rathaus/online-dienste.html", + "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.", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "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": "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", + "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", + "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", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] + }, + { + "exclude": ["ios"], + "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", + "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"] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.de"] + }, + { + "exclude": ["ios"], + "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/", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.de"] + }, + { + "exclude": ["ios", "android"], + "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", + "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", + "subjectUrls": ["https://www.cosmosdirekt.de"] + }, + { + "exclude": ["ios"], + "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/", + "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", + "subjectUrls": ["https://mein.foxdox.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Datev - Arbeitnehmer online / Lohn- und Gehaltsabrechnung"}, + "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/ano/", + "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", + "subjectUrls": ["https://secure6.datev.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Deutsche Post AG - POSTIDENT Verfahren"}, + "longName": {"" : "Deutsche Post AG - POSTIDENT Verfahren"}, + "shortDescription": {"": "Durch das Onlineverfahren POSTIDENT mit dem neuem Personalausweis, können Sie sich schnell und einfach online mit Ihrem neuen Personalausweis identifizieren."}, + "longDescription": {"": "Durch das Onlineverfahren POSTIDENT mit dem neuem Personalausweis, können Sie sich schnell und einfach online mit Ihrem neuen Personalausweis z.B. zur Eröffnung eines Tagesgeldkontos identifizieren: Sie werden hierzu von Ihrer Bank automatisch auf das POSTIDENT Portal geleitet und können sich mithilfe Ihres neuen Personalausweises mit freigeschalteter Online-Ausweisfunktion, einem Kartenlesegerät sowie der AusweisApp2 in wenigen Minuten sicher identifizieren."}, + "address": "https://www.deutschepost.de/de/p/postident/identifizierungsverfahren/postident-npa.html", + "homepage": "https://www.deutschepost.de/de/p/postident.html", + "email": "info@deutschepost.de", + "postalAddress": "Deutsche Post AG
Charles-de-Gaulle-Str. 20
53113 Bonn", + "image": "DeutschePost_image.jpg", + "icon": "DeutschePost_icon.png", + "category": "other" + }, + { + "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", + "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.", + "subjectUrls": ["https://www.eservice-drv.de"] + }, + { + "exclude": ["ios", "android"], + "shortName": {"" : "eAntrag der Investitionsbank Berlin (IBB)"}, + "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://www.ibb.de/de/service/eantrag/eantrag.html", + "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.", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "shortName": {"" : "easy Login - Der Zugang für Finanz- & Versicherungsvermittler"}, + "address": "http://www.easy-login.de", + "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.", + "subjectUrls": ["https://easy-login.vdg-portal.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "ELSTER"}, + "longName": {"" : "ELSTER - Die elektronische Steuererklärung"}, + "shortDescription": {"": "Abwicklung der Steuererklärungen und -anmeldungen über das Internet."}, + "longDescription": {"": "ELSTER bietet im Rahmen der Registrierung, welche Voraussetzung für die Abwicklung der Steuererklärungen und Steueranmeldungen über das Internet ist, die Möglichkeit der Nutzung der Online-Ausweisfunktion."}, + "address": "https://www.elster.de", + "homepage": "https://www.elster.de", + "phone": "+49 89 9991 - 0", + "email": "info@elster.de", + "postalAddress": "Bayerisches Landesamt für Steuern - Dienststelle München
80284 München", + "image": "elster_image.png", + "icon": "elster_icon.png", + "category": "citizen", + "tcTokenUrlInfo" : "Registration required.", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "shortName": {"" : "ERGO Direkt Lebensversicherung AG"}, + "address": "https://ergodirekt.de/de/persoenlicherbereich.html#login", + "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", + "homepage": "https://www.berlin.de", + "phone": "+49 30 90269 – 0", + "email": "", + "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", + "category": "citizen", + "tcTokenUrlInfo" : "Car lizence number required", + "subjectUrls": [] + }, + { + "exclude": ["ios", "android"], + "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/", + "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.", + "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", + "homepage": "https://www.berlin.de", + "phone": "+49 30 90269 – 0", + "email": "", + "postalAddress": "Direktorin Landesamt für Bürger- und Ordnungsangelegenheiten
Friedrichstr. 219
10958 Berlin", + "category": "citizen", + "tcTokenUrlInfo" : "Car lizence number required.", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "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": "dataporthamburggateway-service@dataport.de", + "postalAddress": "Bürgermeister Olaf Scholz
Rathausmarkt 1
20095 Hamburg", + "category": "citizen", + "tcTokenUrlInfo" : "TcToken URL requires valid dynamic request id.", + "subjectUrls": ["https://gateway.hamburg.de"] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": ["https://www.buergerservice.org"] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": ["https://www.sixform.com"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "ID-Safe des Landkreis Würzburg"}, + "address": "https://www.buergerservice.org/ID-Safe-Wuerzburg", + "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", + "subjectUrls": ["https://www.buergerservice.org"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Kraftfahrt-Bundesamt - Registerauskunft"}, + "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. Die erforderlichen Daten werden dann von Ihrem Personalausweis ausgelesen. Die Auskunft erhalten Sie innerhalb weniger Tage per Post."}, + "address": "https://www.kba-online.de/registerauskunft/app/registeranfrage.html", + "homepage": "http://www.kba.de/", + "phone": "+49 461 316-0", + "email": "poststelle@kba.de", + "postalAddress": "Kraftfahrt-Bundesamt
Fördestraße 16
24944 Flensburg", + "category": "citizen", + "tcTokenUrl" : "https://www.kba-online.de:443/registerauskunft/app/eidstart.html;jsessionid=HZFFDC4E848A794D83A1D3032252F3F905?ref=HZFFDC4E848A794D83A1D3032252F3F905", + "tcTokenUrlInfo" : "TcToken URL contains dynamic request id but is accepted anyway.", + "subjectUrls": ["https://www.kba-online.de/registerauskunft"] + }, + { + "shortName": {"" : "Kreis Borken"}, + "longName": {"" : "Kreis Borken - Kfz-Abmeldung Internet"}, + "shortDescription": {"": "Authentisierung für internetbasierte Kfz-Abmeldung."}, + "longDescription": {"": "Für die internetbasierte Kfz-Abmeldung wird die eID-Funktionalität des neuen Personalausweises benötigt."}, + "address": "https://formulare-extern.de/administrationCenter/Form-Solutions/05554004-0001/eID/eIDMandatory?directlink=https%3A%2F%2Fformulare-extern.de%2Fmetaform%2FForm-Solutions%2Fsid%2Fassistant%2F55dc839be4b054042fb93dba%3FeIDComplete%3Dtrue", + "homepage": "https://www.kreis-borken.de", + "phone": "+49 2861 / 82 - 2059", + "email": "zulassungsstelle@kreis-borken.de", + "postalAddress": "Kfz-Zulassungsstelle Borken
Burloer Str. 93
46325 Borken", + "image": "KreisBorken_image.png", + "icon": "KreisBorken_icon.svg", + "category": "citizen", + "tcTokenUrlInfo" : "", + "subjectUrls": [] + }, + { + "exclude": ["ios"], + "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://www.vbl.de/de/meine_vbl", + "homepage": "https://www.vbl.de/", + "phone": "+49 721 93 98 93 1", + "email": "info@vbl.de", + "postalAddress": "VBL. Kundenservice
76240 Karlsruhe", + "category": "other", + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.vbl.de"] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": ["https://www.lvm.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Mentana-Claimsoft AG - Registrierung beim De-Mail Dienst"}, + "address": "https://www.fp-demail.de/", + "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.", + "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/", + "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", + "subjectUrls": ["https://pgp.governikus-eid.de"] + }, + { + "exclude": ["ios", "android"], + "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", + "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", + "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/ausweisapp2/ausprobieren-meine-daten-einsehen/", + "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"] + }, + { + "exclude": ["ios"], + "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", + "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.", + "subjectUrls": ["https://www.buergerserviceportal.nrw"] + }, + { + "shortName": {"" : "SkIDentity Service"}, + "longName": {"" : "SkIDentity Service"}, + "longDescription": {"": "SkIDentity unterstützt die Umsetzung der Cyber-Sicherheitsstrategie der Bundesregierung und macht den elektronischen Personalausweis im Internet sehr leicht und mobil nutzbar. Der SkIDentity-Dienst bietet „Mobile eID as a Service“ und leitet bei Bedarf aus elektronischen Ausweisdokumenten kryptographisch geschützte „Cloud Identitäten“ ab, die auf beliebige Smartphones übertragen und dort sicher mobil genutzt werden können. Darüber hinaus kann auch die bislang aufwändige eID-Integration in einem komfortablen Portal erfolgen und die vertrauenswürdigen Identitäten kommen nun selbst aus einer vom Bundesamt für Sicherheit in der Informationstechnik (BSI) zertifizierten „Secure Cloud Infrastructure“."}, + "address": "https://skidentity.de/service", + "homepage": "https://www.skidentity.de", + "phone": "+49 9571 604 8014", + "email": "detlef.huehnlein@ecsec.de", + "postalAddress": "ecsec GmbH
Sudetenstraße 16
96247 Michelau", + "category": "other", + "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", + "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", + "subjectUrls": ["https://meinkonto.nuernberg.de"] + }, + { + "exclude": ["ios"], + "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/", + "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.", + "subjectUrls": ["https://tbk.ego-mv.de/BuergerKontoWeb"] + }, + { + "shortName": {"" : "Techniker Krankenkasse"}, + "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/118032", + "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": "insurance", + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.tk.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Telekom DeMail"}, + "longName": {"" : "Telekom DeMail für Privat- und Geschäftskunden"}, + "address": "https://www.telekom.de/de-mail", + "homepage": "https://www.telekom.de/", + "phone": "+49 800 33 01000", + "email": "", + "postalAddress": "Telekom Deutschland GmbH
Landgrabenweg 151
53227 Bonn", + "category": "other", + "tcTokenUrlInfo" : "Registration required", + "subjectUrls": ["https://www.de-mail.t-online.de"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "T-Systems DeMail für Großkunden"}, + "address": "https://www.t-systems.de/de-mail", + "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", + "subjectUrls": ["https://www.de-mail.t-systems.de"] + }, + { + "exclude": ["ios"], + "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", + "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", + "subjectUrls": ["https://ea.stadt-koeln.de"] + }, + { + "exclude": ["ios"], + "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://rathaus.dortmund.de/", + "homepage": "https://rathaus.dortmund.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"] + }, + { + "exclude": ["ios"], + "shortName": {"" : "Vollstreckungsportal"}, + "longDescription": {"": "Herzlich willkommen auf dem Gemeinsamen Vollstreckungsportal der Länder."}, + "address": "https://www.vollstreckungsportal.de/auskunft/priv/anmelden.jsf?type=npa", + "homepage": "https://www.vollstreckungsportal.de/", + "phone": "", + "email": "bundesportal@ag-hagen.nrw.de", + "postalAddress": "Land Nordrhein-Westfalen
vertreten durch das Justizministerium
Martin-Luther-Platz 40
40212 Düsseldorf", + "category": "citizen", + "tcTokenUrlInfo" : "Registration required.", + "subjectUrls": ["https://www.vollstreckungsportal.de"] + } + ] +} diff --git a/resources/updatable-files/supported-readers.json b/resources/updatable-files/supported-readers.json new file mode 100644 index 0000000..f38fe84 --- /dev/null +++ b/resources/updatable-files/supported-readers.json @@ -0,0 +1,488 @@ +{ + "SupportedDevices": + [ + { + "VendorId": "0x0000", + "ProductId": "0x0000", + "Name": "Smartphone als Kartenlesegerät", + "Pattern": "^NFC.*", + "Icon": "img_RemoteReader.png", + "IconWithNPA": "img_RemoteReader_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}, {"os": "mac"}, {"os": "unknown"}], + "URL": "https://play.google.com/store/apps/details?id=com.governikus.ausweisapp2" + } + ] + }, + + { + "VendorId": "0x0C4B", + "ProductId": "0x0501", + "Name": "REINER SCT cyberJack RFID komfort", + "Pattern": "REINER SCT cyberJack RFID komfort", + "Icon": "img_Reiner_SCT_cyberjack_RFID_komfort.png", + "IconWithNPA": "img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304822&q=driver#choice5" + } + ] + }, + + { + "VendorId": "0x0C4B", + "ProductId": "0x0500", + "Name": "REINER SCT cyberJack RFID standard", + "Pattern": "REINER SCT cyberJack RFID standard", + "Icon": "img_Reiner_SCT_cyberjack_RFID_standard.png", + "IconWithNPA": "img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304820&q=driver#choice5" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304820&q=driver#choice5" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304820&q=driver#choice5" + } + ] + }, + + { + "VendorId": "0x0C4B", + "ProductId": "0x9102", + "Name": "REINER SCT cyberJack RFID basis", + "Pattern": "REINER SCT cyberJack RFID basis", + "Icon": "img_Reiner_SCT_cyberjack_RFID_basis.png", + "IconWithNPA": "img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304856&q=driver#choice5" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304856&q=driver#choice5" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304856&q=driver#choice5" + } + ] + }, + + { + "VendorId": "0x0C4B", + "ProductId": "0x0505", + "Name": "REINER SCT cyberJack wave", + "Pattern": "REINER SCT cyberJack wave", + "Icon": "img_cyberjack_wave.png", + "IconWithNPA": "img_cyberjack_wave_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304828&q=driver#choice5" + }, + { + "Platforms": [{"os": "mac", "min": "10.11"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304828&q=driver#choice5" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304828&q=driver#choice5" + } + ] + }, + + { + "VendorId": "0x0D46", + "ProductId": "0x301D", + "Name": "KOBIL IDToken", + "Pattern": "KOBIL (Systems )?IDToken", + "Icon": "img_KOBIL_ID_Token.png", + "IconWithNPA": "img_KOBIL_ID_Token_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.kobil.com/de/support_de/#drivers_de" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://www.kobil.com/de/support_de/#drivers_de" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.kobil.com/de/support_de/#drivers_de" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x512B", + "Name": "SDI011 Contactless Reader", + "Pattern": "SDI011 (USB )?(Smart Card|Contactless) Reader", + "Icon": "img_Identive_SDI011.png", + "IconWithNPA": "img_Identive_SDI011_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}], + "URL": "https://support.identiv.com/sdi010-011/" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://support.identiv.com/sdi010-011/" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x5292", + "Name": "SCL01x Contactless Reader", + "Pattern": "(SCM Microsystems Inc. )?SCL011 Contactless Reader", + "Icon": "img_Identive_SCL011.png", + "IconWithNPA": "img_Identive_SCL011_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win", "min": "10.0"}], + "URL": "https://support.identiv.com/scl010-scl011/" + }, + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}], + "URL": "https://support.identiv.com/scl010-scl011/" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://support.identiv.com/scl010-scl011/" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x5790", + "Name": "Identiv Cloud 3700 F", + "Pattern": "(CLOUD 3700 F Contactless Reader|Identiv uTrust 3700 F CL Reader)", + "Icon": "img_Identive_Cloud_3700_F.png", + "IconWithNPA": "img_Identive_Cloud_3700_F_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://support.identiv.com/3700f/" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://support.identiv.com/3700f/" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://support.identiv.com/3700f/" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x5591", + "Name": "Identiv SCL3711", + "Pattern": "SCL3711", + "Icon": "img_Identive_SCL3711.png", + "IconWithNPA": "img_Identive_SCL3711_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://support.identiv.com/scl3711/" + }, + { + "Platforms": [{"os": "mac", "max": "10.11"}], + "URL": "https://support.identiv.com/scl3711/" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://support.identiv.com/scl3711/" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x5720", + "Name": "Identiv Cloud 4700 F", + "Pattern": "(CLOUD 4700 F Contactless Reader|Identiv uTrust 4700 F Dual Interface Reader)", + "Icon": "img_Identive_Cloud_4700_F.png", + "IconWithNPA": "img_Identive_Cloud_4700_F_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.scm-pc-card.de/index.php?lang=en&page=download&function=show_downloads&product_id=832" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "http://www.scm-pc-card.de/index.php?lang=en&page=download&function=show_downloads&product_id=832" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "http://www.scm-pc-card.de/index.php?lang=en&page=download&function=show_downloads&product_id=832" + } + ] + }, + + { + "VendorId": "0x04E6", + "ProductId": "0x5724", + "Name": "Identiv Cloud 4701 F", + "Pattern": "(CLOUD 4701 F Contactless Reader|Identiv uTrust 4701 F Dual Interface Reader)", + "Icon": "img_Identive_Cloud_4701_F.png", + "IconWithNPA": "img_Identive_Cloud_4701_F_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://support.identiv.com/4701f/" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "https://support.identiv.com/4701f/" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://support.identiv.com/4701f/" + } + ] + }, + + { + "VendorId": "0x072F", + "ProductId": "0x2200", + "Name": "ACS ACR122U", + "Pattern": "ACS ACR122U", + "Icon": "img_ACS_ACR122U.png", + "IconWithNPA": "img_ACS_ACR122U_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}, {"os": "mac"}], + "URL": "https://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/" + } + ] + }, + + { + "VendorId": "0x072F", + "ProductId": "0x0901", + "Name": "ACS ACR1281U", + "Pattern": "ACS ACR1281 PICC Reader", + "Icon": "img_ACS_ACR1281U.png", + "IconWithNPA": "img_ACS_ACR1281U_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.acs.com.hk/en/driver/151/acr1281u-npa-contactless-reader/" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "http://www.acs.com.hk/en/driver/151/acr1281u-npa-contactless-reader/" + } + ] + }, + + { + "VendorId": "0x072F", + "ProductId": "0x223B", + "Name": "ACS ACR1252U", + "Pattern": "ACS ACR1252 Dual Reader|ACS ACR1252 1S CL Reader", + "Icon": "img_ACS_ACR1252U.png", + "IconWithNPA": "img_ACS_ACR1252U_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.acs.com.hk/en/products/342/acr1252u-usb-nfc-reader-iii-nfc-forum-certified-reader/#tab_downloads" + }, + { + "Platforms": [{"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "http://www.acs.com.hk/en/products/342/acr1252u-usb-nfc-reader-iii-nfc-forum-certified-reader/#tab_downloads" + } + ] + }, + + { + "VendorId": "0x076B", + "ProductId": "0x5340", + "Name": "OMNIKEY 5021-CL", + "Pattern": "OMNIKEY CardMan 5x21-CL|OMNIKEY CardMan \\(076B:5340\\) 5021 CL", + "Icon": "img_HID_Omnikey_Mobile_Reader_5021_CL.png", + "IconWithNPA": "img_HID_Omnikey_Mobile_Reader_5021_CL_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + }, + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}, {"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + } + ] + }, + + { + "VendorId": "0x076B", + "ProductId": "0x5421", + "Name": "OMNIKEY 5421", + "Pattern": "OMNIKEY CardMan \\(076B:5421\\) 5421|OMNIKEY Smart Card Reader USB", + "Icon": "img_HID_Omnikey_5421.png", + "IconWithNPA": "img_HID_Omnikey_5421_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + }, + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}, {"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All" + } + ] + }, + + { + "VendorId": "0x0AB1", + "ProductId": "0x0003", + "Name": "OBID RFID-Reader", + "Pattern": "FEIG ELECTRONIC GmbH OBID myAXXESS basic", + "Icon": "img_FEIG_myAXXES_basic.png", + "IconWithNPA": "img_FEIG_myAXXES_basic_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.feig.de/downloads/" + } + ] + }, + + { + "VendorId": "0x08E6", + "ProductId": "0x5504", + "Name": "Gemalto Prox-SU Contactless", + "Pattern": "Gemalto Prox( |-)SU", + "Icon": "img_Gemalto_Prox_SU.png", + "IconWithNPA": "img_Gemalto_Prox_SU_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win", "max": "6.1"}, {"os": "win", "min": "10.0"}], + "URL": "http://support.gemalto.com/index.php?id=prox-du_prox-su#msdrivers" + }, + { + "Platforms": [{"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "http://support.gemalto.com/index.php?id=prox-du_prox-su#macosxdrivers" + } + ] + }, + + { + "VendorId": "0x08E6", + "ProductId": "0x5503", + "Name": "Prox-DU HID", + "Pattern": "Gemalto Prox(-DU| Dual)($| USB| Contactless_)", + "Icon": "img_Gemalto_Prox_DU.png", + "IconWithNPA": "img_Gemalto_Prox_DU_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win", "max": "6.1"}, {"os": "win", "min": "10.0"}], + "URL": "http://support.gemalto.com/index.php?id=prox-du_prox-su#.WOIQijvyjyQ" + }, + { + "Platforms": [{"os": "mac"}], + "URL": "http://support.gemalto.com/index.php?id=prox-du_prox-su#.WOIQijvyjyQ" + } + ] + }, + + { + "VendorId": "0x046A", + "ProductId": "0x0091", + "Name": "Cherry TC-1200", + "Pattern": "(Cherry TC 1200($|[^-])|TC 12xx-CL 0|Cherry SC Reader \\(046A:0091\\))", + "Icon": "img_Cherry_TC_1200.png", + "IconWithNPA": "img_Cherry_TC_1200_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.cherry.de/cid/download.php" + }, + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}, {"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "http://www.cherry.de/cid/download.php" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "http://www.cherry.de/cid/download.php" + } + ] + }, + + { + "VendorId": "0x046A", + "ProductId": "0x0092", + "Name": "Cherry TC-1300", + "Pattern": "(Cherry TC 1300|Cherry Smartcard Terminal TC 13xx-CL 0|Cherry SC Reader \\(046A:0092\\))", + "Icon": "img_Cherry_TC_1300.png", + "IconWithNPA": "img_Cherry_TC_1300_mit_ausweis.png", + "Drivers": + [ + { + "Platforms": [{"os": "win"}], + "URL": "http://www.cherry.de/cid/download.php" + }, + { + "Platforms": [{"os": "mac", "min": "10.11", "max": "10.11"}, {"os": "mac", "min": "10.13", "max": "10.13"}], + "URL": "http://www.cherry.de/cid/download.php" + }, + { + "Platforms": [{"os": "unknown"}], + "URL": "http://www.cherry.de/cid/download.php" + } + ] + } + ] +} diff --git a/resources/windows.rc b/resources/windows.rc deleted file mode 100644 index 3b8ebf4..0000000 --- a/resources/windows.rc +++ /dev/null @@ -1,55 +0,0 @@ -// http://msdn.microsoft.com/en-us/library/aa381058(VS.85).aspx -#include - -IDR_MAINFRAME ICON "images\\npa.ico" - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -#define COMPANY "Governikus GmbH & Co. KG" -#define PRODUCT "AusweisApp2" -#define EXECUTABLE "AusweisApp2.exe" -#define COPYRIGHT "\251 2014 " COMPANY -#define VERSION_STR STR(VERSION) - - -1 VERSIONINFO -FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_TWEAK -PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_TWEAK -FILEOS VOS_NT_WINDOWS32 -FILETYPE VFT_APP - -BEGIN - BLOCK "StringFileInfo" - - BEGIN - BLOCK "040704B0" // LANG_GERMAN/SUBLANG_DEFAULT, Unicode CP - BEGIN - VALUE "CompanyName", COMPANY - VALUE "FileDescription", PRODUCT - VALUE "FileVersion", VERSION_STR - VALUE "InternalName", PRODUCT - VALUE "LegalCopyright", COPYRIGHT - VALUE "OriginalFilename", EXECUTABLE - VALUE "ProductName", PRODUCT - VALUE "ProductVersion", VERSION_STR - END - - BLOCK "040904B0" // LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP - BEGIN - VALUE "CompanyName", COMPANY - VALUE "FileDescription", PRODUCT - VALUE "FileVersion", VERSION_STR - VALUE "InternalName", PRODUCT - VALUE "LegalCopyright", COPYRIGHT - VALUE "OriginalFilename", EXECUTABLE - VALUE "ProductName", PRODUCT - VALUE "ProductVersion", VERSION_STR - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0407, 0x04B0 - END -END diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63ab7c3..2b63ed3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,27 +1,54 @@ ADD_SUBDIRECTORY(external) ADD_SUBDIRECTORY(global) +ADD_SUBDIRECTORY(secure_storage) +ADD_SUBDIRECTORY(configuration) +ADD_SUBDIRECTORY(settings) ADD_SUBDIRECTORY(card) ADD_SUBDIRECTORY(network) -ADD_SUBDIRECTORY(settings) ADD_SUBDIRECTORY(services) ADD_SUBDIRECTORY(activation) ADD_SUBDIRECTORY(core) ADD_SUBDIRECTORY(jsonapi) ADD_SUBDIRECTORY(websocket) ADD_SUBDIRECTORY(aidl) +ADD_SUBDIRECTORY(remote_device) +ADD_SUBDIRECTORY(file_provider) +ADD_SUBDIRECTORY(export) IF(DESKTOP) ADD_SUBDIRECTORY(cli) - ADD_SUBDIRECTORY(export) ENDIF() -ADD_SUBDIRECTORY(qml) + +IF(TARGET Qt5::Qml) + ADD_SUBDIRECTORY(qml) +ENDIF() # Use this if we can use QSvgPlugin without Widgets # IF(TARGET Qt5::Widgets) # https://bugreports.qt.io/browse/QTBUG-41884 IF(DESKTOP) - ADD_SUBDIRECTORY(gui) + ADD_SUBDIRECTORY(widget) + IF(TARGET Qt5::UiPlugin) + ADD_SUBDIRECTORY(widgetDesignerPlugin) + ENDIF() ENDIF() +FUNCTION(CONFIGURE_CONFIG_H) + IF(VENDOR_GOVERNIKUS) + SET(VENDOR_DOMAIN governikus.com) + ELSE() + SET(VENDOR_DOMAIN) + ENDIF() + + IF(VERSION_DVCS) + SET(VERSION ${VERSION_DVCS}) + ELSE() + SET(VERSION ${PROJECT_VERSION}) + ENDIF() + + SET(PRODUCT ${EXECUTABLE_BASE_NAME}) + + CONFIGURE_FILE(config.h.in config.h @ONLY) +ENDFUNCTION() FILE(GLOB TRANSLATION_FILES ${RESOURCES_DIR}/translations/*.ts) @@ -61,67 +88,65 @@ IF(IOS) SET(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) SET(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}) - FOREACH(entry QtQuick QtQuick.2 QtQml QtGraphicalEffects Qt) - FILE(COPY ${QT_HOST_PREFIX}/qml/${entry} DESTINATION ${CMAKE_BINARY_DIR}/qml PATTERN "lib*" EXCLUDE) - LIST(APPEND IOS_RESOURCES ${CMAKE_BINARY_DIR}/qml/${entry}) - ENDFOREACH() - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/qml) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/packaging/ios/de.lproj) LIST(APPEND IOS_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/translations) LIST(APPEND IOS_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/config.json) - LIST(APPEND IOS_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/default-providers.json) LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/qtlogging.ini) # Attention: the file names correspond to values in the Info.plist - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon29x29@2x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon29x29@2x~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon29x29@3x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon29x29~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon40x40@2x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon40x40@2x~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon40x40@3x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon40x40~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon60x60@2x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon60x60@3x.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon76x76@2x~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/icon76x76~ipad.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchIcons/launchIcon.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchIcons/launchIcon6.png) - LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchIcons/launchIcon6p.png) + IF(BUILD_PREVIEW) + MESSAGE(FATAL_ERROR "iOS preview not implemented") + ELSEIF(IS_DEVELOPER_VERSION) + SET(IOS_APPICON_PATH "beta/") + ELSE() + SET(IOS_APPICON_PATH "") + ENDIF() + + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall40.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall40@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}iconSmall40@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}icon60@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}icon60@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}icon76.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}icon76@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/appIcons/${IOS_APPICON_PATH}icon83.5@2x.png) + + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/Default-568h@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage568@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage568@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage667@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage667@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage736@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage736@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1024@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1024@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1112@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1112@3x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1366@2x.png) + LIST(APPEND IOS_RESOURCES ${RESOURCES_DIR}/images/iOS/launchImages/launchImage1366@3x.png) LIST(APPEND IOS_RESOURCES ${RCC}) SET_SOURCE_FILES_PROPERTIES(${RCC} PROPERTIES GENERATED TRUE) ENDIF() -SET(MAIN_CPP "main.cpp") FILE(GLOB MAIN_FILES *.cpp) IF(ANDROID) ADD_LIBRARY(AusweisApp SHARED ${MAIN_FILES} ${QM_FILES}) ELSEIF(IOS) ADD_EXECUTABLE(AusweisApp MACOSX_BUNDLE ${MAIN_FILES} ${IOS_RESOURCES} ${QM_FILES}) ELSE() - ADD_EXECUTABLE(AusweisApp WIN32 ${MAIN_FILES} ${WINDOWS_RC} ${QM_FILES}) - IF(WIN32) - SET_PROPERTY(SOURCE ${WINDOWS_RC} APPEND_STRING PROPERTY COMPILE_FLAGS " -DVERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DVERSION_MINOR=${PROJECT_VERSION_MINOR} -DVERSION_PATCH=${PROJECT_VERSION_PATCH} -DVERSION_TWEAK=${PROJECT_VERSION_TWEAK}") - ENDIF() + ADD_EXECUTABLE(AusweisApp WIN32 ${MAIN_FILES} windows.rc ${QM_FILES}) ENDIF() ADD_DEPENDENCIES(AusweisApp AusweisAppRcc) +CONFIGURE_CONFIG_H() -ADD_STRING_DEFINITION("${VENDOR}" "VENDOR" ${MAIN_CPP}) -IF(VENDOR_GOVERNIKUS) - ADD_STRING_DEFINITION("governikus.com" "VENDOR_DOMAIN" ${MAIN_CPP}) -ENDIF() - - -IF(VERSION_DVCS) - ADD_STRING_DEFINITION(${VERSION_DVCS} "VERSION" ${MAIN_CPP} ${WINDOWS_RC}) -ELSE() - ADD_STRING_DEFINITION(${PROJECT_VERSION} "VERSION" ${MAIN_CPP} ${WINDOWS_RC}) -ENDIF() - -TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCard AusweisAppCore AusweisAppGlobal AusweisAppExternalHttpParser AusweisAppNetwork AusweisAppActivation AusweisAppActivationInternal) +TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCard AusweisAppCore AusweisAppGlobal 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) @@ -129,43 +154,56 @@ SET_TARGET_PROPERTIES(AusweisApp PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER com.gov IF(IOS) + TARGET_LINK_LIBRARIES(AusweisApp OpenSSL::SSL) # remove this if iOS uses shared libraries TARGET_LINK_LIBRARIES(AusweisApp -L${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/plugins/platforms) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/plugins/imageformats) TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/lib) - TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick.2) - TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Dialogs) - TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Layouts) - 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 -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 -lQt5Network -lQt5Gui -lQt5Core -lQt5Bluetooth -lQt5Svg -lQt5Quick -lQt5Qml -lQt5QuickTemplates2 -lQt5QuickControls2) + TARGET_LINK_LIBRARIES(AusweisApp -lqtpcre2 -lqtlibpng -lQt5GraphicsSupport -lQt5FontDatabaseSupport -lQt5ClipboardSupport -lqios -lqsvg -lqjpeg -lqtfreetype) 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}) TARGET_LINK_LIBRARIES(AusweisApp -Wl,-e,_qt_main_wrapper) - TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtGraphicalEffects/private) - TARGET_LINK_LIBRARIES(AusweisApp -lqtgraphicaleffectsprivate) - TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtGraphicalEffects) - TARGET_LINK_LIBRARIES(AusweisApp -lqtgraphicaleffectsplugin) + # Do not delete the comments to avoid searching for the path/filename - #TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Templates.2) - #TARGET_LINK_LIBRARIES(AusweisApp -lqtquicktemplates2plugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQml/Models.2 -lmodelsplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQml/StateMachine -lqtqmlstatemachine) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtGraphicalEffects/private -lqtgraphicaleffectsprivate) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtGraphicalEffects -lqtgraphicaleffectsplugin) - #TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls.2) - #TARGET_LINK_LIBRARIES(AusweisApp -lqtquickcontrols2plugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls -lqtquickcontrolsplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls/Styles/Flat -lqtquickextrasflatplugin) - #TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls/Styles/Flat) - #TARGET_LINK_LIBRARIES(AusweisApp -lqtquickextrasflatplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls.2 -lqtquickcontrols2plugin) +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls.2/Material -lqtquickcontrols2materialstyleplugin) +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Controls.2/Universal -lqtquickcontrols2universalstyleplugin) + + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Dialogs -ldialogplugin) +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Dialogs/Private -ldialogsprivateplugin) + +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Extras -lqtquickextrasplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Layouts -lqquicklayoutsplugin) +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/LocalStorage -lqmllocalstorageplugin) +# TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Particles.2 -lparticlesplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Templates.2 -lqtquicktemplates2plugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick/Window.2 -lwindowplugin) + TARGET_LINK_LIBRARIES(AusweisApp -L${QT_HOST_PREFIX}/qml/QtQuick.2 -lqtquick2plugin) SET_TARGET_PROPERTIES(AusweisApp PROPERTIES RESOURCE "${IOS_RESOURCES}") + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_ARCHS "arm64") SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") - SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "8.0") + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "10.0") SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") + IF(USE_DISTRIBUTION_PROFILE) + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "iOS Release (Distribution)") + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Distribution: Governikus GmbH & Co. KG (G7EQCJU4BR)") + ELSE() + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "iOS Development") + SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: Marco von der Puetten (46ZK7WV8QR)") + ENDIF() # prevent xcode to convert multiple png files to tiff SET_TARGET_PROPERTIES(AusweisApp PROPERTIES XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES "NO") @@ -181,27 +219,34 @@ IF(ANDROID) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardNfc AusweisAppActivationIntent) ENDIF() -IF(ANDROID OR IOS OR (LINUX AND CMAKE_BUILD_TYPE STREQUAL "DEBUG")) +IF(ANDROID OR IOS) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardBluetooth) +ELSEIF(LINUX) + TARGET_LINK_LIBRARIES(AusweisApp debug AusweisAppCardBluetooth) ENDIF() IF(WIN32) TARGET_LINK_LIBRARIES(AusweisApp ${WIN_DEFAULT_LIBS}) ENDIF() -IF(IOS OR ANDROID OR WINDOWS_STORE OR ${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") +IF(IOS OR ANDROID OR WINDOWS_STORE) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppQml) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppAidl) +ELSE() + TARGET_LINK_LIBRARIES(AusweisApp debug AusweisAppQml) + TARGET_LINK_LIBRARIES(AusweisApp debug AusweisAppAidl) ENDIF() + IF(DESKTOP) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardPcsc AusweisAppCardDrivers AusweisAppActivationWebservice) TARGET_LINK_LIBRARIES(AusweisApp AusweisAppWidget AusweisAppCli) ENDIF() -IF(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") - TARGET_LINK_LIBRARIES(AusweisApp AusweisAppWebSocket) -ENDIF() +TARGET_LINK_LIBRARIES(AusweisApp debug AusweisAppWebSocket) +IF(NOT WINDOWS_STORE) + TARGET_LINK_LIBRARIES(AusweisApp AusweisAppCardRemote) +ENDIF() INCLUDE(Install) diff --git a/src/CommandLineParser.cpp b/src/CommandLineParser.cpp index cc97dae..ea2de87 100644 --- a/src/CommandLineParser.cpp +++ b/src/CommandLineParser.cpp @@ -1,10 +1,9 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CommandLineParser.h" -#include "LanguageLoader.h" #include "LogHandler.h" #include "NetworkManager.h" #include "SingletonHelper.h" @@ -35,16 +34,20 @@ Q_DECLARE_LOGGING_CATEGORY(cmdline) namespace { -static QString prefixUi = QStringLiteral("UIPlugIn"); +QString getPrefixUi() +{ + return QStringLiteral("UIPlugIn"); +} + QString defaultUi(const QVector& pPlugins) { QStringList list; for (auto entry : pPlugins) { - list << QString(getEnumName(entry)).remove(prefixUi); + list << QString(getEnumName(entry)).remove(getPrefixUi()); } - return list.join(','); + return list.join(QLatin1Char(',')); } @@ -52,14 +55,13 @@ QString defaultUi(const QVector& pPlugins) CommandLineParser::CommandLineParser() : mParser() - , mOptionKeepLog("keep", "Keep log file.") - , mOptionShowWindow("show", "Show window on startup.") - , mOptionProxy("no-proxy", "Disable system proxy.") - , mOptionLanguage("language", "Force UI language.", LanguageLoader::getDefaultLanguage().uiLanguages().join(',')) - , mOptionUi("ui", "Use given UI plugin.", defaultUi(UILoader::getInstance().getDefault())) - , mOptionPort("port", "Use listening port.", "24727") + , mOptionKeepLog(QStringLiteral("keep"), QStringLiteral("Keep log file.")) + , mOptionShowWindow(QStringLiteral("show"), QStringLiteral("Show window on startup.")) + , mOptionProxy(QStringLiteral("no-proxy"), QStringLiteral("Disable system proxy.")) + , mOptionUi(QStringLiteral("ui"), QStringLiteral("Use given UI plugin."), defaultUi(UILoader::getInstance().getDefault())) + , mOptionPort(QStringLiteral("port"), QStringLiteral("Use listening port."), QStringLiteral("24727")) #ifndef QT_NO_DEBUG - , mOptionPortWebSocket("port-websocket", "Use listening port for websocket.", QString::number(UIPlugInWebSocket::WEBSOCKET_DEFAULT_PORT)) + , mOptionPortWebSocket(QStringLiteral("port-websocket"), QStringLiteral("Use listening port for websocket."), QString::number(UIPlugInWebSocket::WEBSOCKET_DEFAULT_PORT)) #endif { addOptions(); @@ -89,7 +91,6 @@ void CommandLineParser::addOptions() #endif mParser.addOption(mOptionProxy); - mParser.addOption(mOptionLanguage); mParser.addOption(mOptionUi); mParser.addOption(mOptionPort); @@ -127,20 +128,6 @@ void CommandLineParser::parse(QCoreApplication* pApp) NetworkManager::lockProxy(true); } - if (mParser.isSet(mOptionLanguage)) - { - const auto& language = mParser.value(mOptionLanguage); - const auto& locale = QLocale(language); - if (locale == QLocale::C) - { - qCWarning(cmdline) << "Cannot detect language:" << language; - } - else - { - LanguageLoader::setDefaultLanguage(locale); - } - } - #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) if (mParser.isSet(mOptionPort)) { @@ -187,7 +174,7 @@ void CommandLineParser::parseUiPlugin() { for (auto availablePluginEntry : availablePlugins) { - if (parsedUiOption.compare(QString(getEnumName(availablePluginEntry)).remove(prefixUi), Qt::CaseInsensitive) == 0) + if (parsedUiOption.compare(QString(getEnumName(availablePluginEntry)).remove(getPrefixUi()), Qt::CaseInsensitive) == 0) { selectedPlugins << availablePluginEntry; } diff --git a/src/CommandLineParser.h b/src/CommandLineParser.h index 3801d91..70d2420 100644 --- a/src/CommandLineParser.h +++ b/src/CommandLineParser.h @@ -1,7 +1,7 @@ /* * \brief Provides and parses command line options. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -19,7 +19,6 @@ class CommandLineParser const QCommandLineOption mOptionKeepLog; const QCommandLineOption mOptionShowWindow; const QCommandLineOption mOptionProxy; - const QCommandLineOption mOptionLanguage; const QCommandLineOption mOptionUi; const QCommandLineOption mOptionPort; #ifndef QT_NO_DEBUG diff --git a/src/MetaTypeRegister.cpp b/src/MetaTypeRegister.cpp deleted file mode 100644 index a3fd421..0000000 --- a/src/MetaTypeRegister.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * \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(QT_NO_DEBUG)) || 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(QT_NO_DEBUG)) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - BluetoothMessage::registerMetaTypes(); -#endif -} - - -} -} diff --git a/src/MetaTypeRegister.h b/src/MetaTypeRegister.h deleted file mode 100644 index edea70e..0000000 --- a/src/MetaTypeRegister.h +++ /dev/null @@ -1,16 +0,0 @@ -/*! - * \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/base/ActivationContext.cpp b/src/activation/base/ActivationContext.cpp index fa26be4..97ddcb2 100644 --- a/src/activation/base/ActivationContext.cpp +++ b/src/activation/base/ActivationContext.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ActivationContext.h" diff --git a/src/activation/base/ActivationContext.h b/src/activation/base/ActivationContext.h index 4a80f7f..840cd8f 100644 --- a/src/activation/base/ActivationContext.h +++ b/src/activation/base/ActivationContext.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/activation/base/ActivationHandler.cpp b/src/activation/base/ActivationHandler.cpp index 81d2493..c27db25 100644 --- a/src/activation/base/ActivationHandler.cpp +++ b/src/activation/base/ActivationHandler.cpp @@ -1,26 +1,26 @@ /*! - * ActivationHandler.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ActivationHandler.h" -#include "MetaTypeHelper.h" +#include "ActivationContext.h" +#include "Initializer.h" #include #include #include #include -REGISTER_META_TYPE(StatusFormat) -REGISTER_META_TYPE(UiModule) - - using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(activation) +static Initializer::Entry X([] { + qRegisterMetaType("UiModule"); + qRegisterMetaType >("QSharedPointer"); + }); + ActivationHandler::ActivationHandler() { diff --git a/src/activation/base/ActivationHandler.h b/src/activation/base/ActivationHandler.h index 5774069..4d6f537 100644 --- a/src/activation/base/ActivationHandler.h +++ b/src/activation/base/ActivationHandler.h @@ -1,12 +1,9 @@ /*! - * ActivationHandler.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "ActivationContext.h" #include "EnumHelper.h" #include @@ -15,12 +12,15 @@ namespace governikus { +class ActivationContext; + /*! * UI modules that can be requested to show. */ defineEnumType(UiModule, CURRENT, DEFAULT, + IDENTIFY, SETTINGS, PINMANAGEMENT ) @@ -83,7 +83,7 @@ class ActivationHandler Q_SIGNALS: void fireShowUserInformation(const QString& pErrorMessage = QString()); void fireShowUiRequest(UiModule pModule); - void fireAuthenticationRequest(ActivationContext* pActivationContext); + void fireAuthenticationRequest(const QSharedPointer& pActivationContext); }; } /* namespace governikus */ diff --git a/src/activation/customscheme/CustomSchemeActivationContext.cpp b/src/activation/customscheme/CustomSchemeActivationContext.cpp index 3e2b343..db3ea5b 100644 --- a/src/activation/customscheme/CustomSchemeActivationContext.cpp +++ b/src/activation/customscheme/CustomSchemeActivationContext.cpp @@ -1,7 +1,5 @@ /*! - * CustomSchemeActivationContext.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CustomSchemeActivationContext.h" @@ -55,18 +53,15 @@ bool CustomSchemeActivationContext::sendProcessing() bool CustomSchemeActivationContext::sendOperationAlreadyActive() { - // probably we emit a signal, that will be caught by the AppController - // so that then UI can display some message or so? + Q_EMIT fireShowUserInformation(GlobalStatus(GlobalStatus::Code::Workflow_AlreadyInProgress_Error).toErrorDescription()); return true; } -bool CustomSchemeActivationContext::sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) +bool CustomSchemeActivationContext::sendErrorPage(HttpStatusCode, const GlobalStatus&) { - Q_UNUSED(pStatusCode); - 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? + // The error is displayed in the application, + // so here is nothing to be done in this case. return true; } diff --git a/src/activation/customscheme/CustomSchemeActivationContext.h b/src/activation/customscheme/CustomSchemeActivationContext.h index 5f4a57d..eb3ff00 100644 --- a/src/activation/customscheme/CustomSchemeActivationContext.h +++ b/src/activation/customscheme/CustomSchemeActivationContext.h @@ -1,7 +1,5 @@ /*! - * CustomSchemeActivationContext.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -30,6 +28,9 @@ class CustomSchemeActivationContext bool sendOperationAlreadyActive() override; bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pResult) override; + + Q_SIGNALS: + void fireShowUserInformation(const QString& pMessage); }; } /* namespace governikus */ diff --git a/src/activation/customscheme/CustomSchemeActivationHandler.cpp b/src/activation/customscheme/CustomSchemeActivationHandler.cpp index 4474f51..8e4a803 100644 --- a/src/activation/customscheme/CustomSchemeActivationHandler.cpp +++ b/src/activation/customscheme/CustomSchemeActivationHandler.cpp @@ -1,7 +1,5 @@ /*! - * CustomSchemeActivationHandler.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CustomSchemeActivationHandler.h" @@ -43,30 +41,16 @@ void CustomSchemeActivationHandler::onCustomUrl(const QUrl& pUrl) qCDebug(activation) << "Got new request"; qCDebug(activation) << "Request URL:" << pUrl; - if (pUrl.port() != 24727 || (pUrl.host() != QLatin1String("127.0.0.1") && pUrl.host() != QLatin1String("localhost"))) + if (pUrl.port() != 24727 || + (pUrl.host() != QLatin1String("127.0.0.1") && pUrl.host() != QLatin1String("localhost")) || + (pUrl.path() != QLatin1String("/eID-Client"))) { qCWarning(activation) << "Request type: unknown"; return; } - if (pUrl.path() == QLatin1String("/eID-Client")) - { - const auto urlParameter = getQueryParameter(pUrl); - - if (urlParameter.contains(QStringLiteral("showui"))) - { - qCDebug(activation) << "Request type: showui"; - UiModule module = Enum::fromString(urlParameter.value(QStringLiteral("showui")).toUpper(), UiModule::DEFAULT); - Q_EMIT fireShowUiRequest(module); - return; - } - else if (urlParameter.contains(QStringLiteral("tctokenurl"))) - { - qCDebug(activation) << "Request type: authentication"; - Q_EMIT fireAuthenticationRequest(new CustomSchemeActivationContext(pUrl)); - return; - } - } - - qCWarning(activation) << "Request type: unknown"; + qCDebug(activation) << "Request type: authentication"; + QSharedPointer context(new CustomSchemeActivationContext(pUrl)); + connect(context.data(), &CustomSchemeActivationContext::fireShowUserInformation, this, &ActivationHandler::fireShowUserInformation); + Q_EMIT fireAuthenticationRequest(context); } diff --git a/src/activation/customscheme/CustomSchemeActivationHandler.h b/src/activation/customscheme/CustomSchemeActivationHandler.h index b1b22f1..10e35dd 100644 --- a/src/activation/customscheme/CustomSchemeActivationHandler.h +++ b/src/activation/customscheme/CustomSchemeActivationHandler.h @@ -1,7 +1,5 @@ /*! - * CustomSchemeActivationHandler.h - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,7 +21,7 @@ class CustomSchemeActivationHandler Q_PLUGIN_METADATA(IID "governikus.ActivationHandler" FILE "metadata.json") Q_INTERFACES(governikus::ActivationHandler) - private: + private Q_SLOTS: void onCustomUrl(const QUrl& pUrl); public: diff --git a/src/activation/intent/AusweisApp2Service.java b/src/activation/intent/AusweisApp2Service.java index fa85509..7c0f890 100644 --- a/src/activation/intent/AusweisApp2Service.java +++ b/src/activation/intent/AusweisApp2Service.java @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + package com.governikus.ausweisapp2; import android.content.Intent; @@ -26,12 +30,6 @@ public class AusweisApp2Service } - public NFCConnector getNfcConnector() - { - return NFCConnector.getInstance(this); - } - - @Override public IBinder onBind(Intent intent) { @@ -56,7 +54,6 @@ public class AusweisApp2Service // register the broadcast receiver after loading the C++ library in super.onCreate() AndroidBluetoothReceiver.register(this); - NfcAdapterStateChangeReceiver.register(this); } @@ -67,7 +64,6 @@ public class AusweisApp2Service // unregister the broadcast receiver before unloading the C++ library in super.onDestroy() AndroidBluetoothReceiver.unregister(this); - NfcAdapterStateChangeReceiver.unregister(this); super.onDestroy(); diff --git a/src/activation/intent/IntentActivationContext.cpp b/src/activation/intent/IntentActivationContext.cpp index 3b058df..2d76325 100644 --- a/src/activation/intent/IntentActivationContext.cpp +++ b/src/activation/intent/IntentActivationContext.cpp @@ -1,9 +1,10 @@ /*! - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #include "IntentActivationContext.h" +#include "GlobalStatus.h" #include "UrlUtil.h" #include @@ -52,9 +53,7 @@ bool IntentActivationContext::sendProcessing() 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? + Q_EMIT fireShowUserInformation(GlobalStatus(GlobalStatus::Code::Workflow_AlreadyInProgress_Error).toErrorDescription()); return true; } diff --git a/src/activation/intent/IntentActivationContext.h b/src/activation/intent/IntentActivationContext.h index a7aca5d..a5c4108 100644 --- a/src/activation/intent/IntentActivationContext.h +++ b/src/activation/intent/IntentActivationContext.h @@ -2,7 +2,7 @@ * \brief Implementation of ActivationContext for Intent * based activation on Android systems. * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -16,12 +16,14 @@ namespace governikus class IntentActivationContext : public ActivationContext { + Q_OBJECT + const QUrl mActivationUrl; QUrl mRedirectAddress; public: IntentActivationContext(const QUrl& pActivationUrl); - virtual ~IntentActivationContext(); + virtual ~IntentActivationContext() override; QUrl getActivationURL() const override; @@ -29,6 +31,9 @@ class IntentActivationContext bool sendOperationAlreadyActive() override; bool sendErrorPage(HttpStatusCode pStatusCode, const GlobalStatus& pStatus) override; bool sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pResult) override; + + Q_SIGNALS: + void fireShowUserInformation(const QString& pMessage); }; } /* namespace governikus */ diff --git a/src/activation/intent/IntentActivationHandler.cpp b/src/activation/intent/IntentActivationHandler.cpp index e043ee5..b63feb8 100644 --- a/src/activation/intent/IntentActivationHandler.cpp +++ b/src/activation/intent/IntentActivationHandler.cpp @@ -1,7 +1,5 @@ /*! - * IntentActivationHandler.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "IntentActivationHandler.h" @@ -45,7 +43,9 @@ void IntentActivationHandler::onIntent(const QUrl& pUrl) { qCDebug(activation) << "Got new authentication request"; qCDebug(activation) << "Request URL:" << pUrl; - Q_EMIT fireAuthenticationRequest(new IntentActivationContext(pUrl)); + QSharedPointer context(new IntentActivationContext(pUrl)); + connect(context.data(), &IntentActivationContext::fireShowUserInformation, this, &ActivationHandler::fireShowUserInformation); + Q_EMIT fireAuthenticationRequest(context); } diff --git a/src/activation/intent/IntentActivationHandler.h b/src/activation/intent/IntentActivationHandler.h index 4c9f8e0..9d38f4f 100644 --- a/src/activation/intent/IntentActivationHandler.h +++ b/src/activation/intent/IntentActivationHandler.h @@ -1,7 +1,5 @@ /*! - * IntentActivationHandler.h - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/activation/intent/MainActivity.java b/src/activation/intent/MainActivity.java index 94c06fb..5f629b4 100644 --- a/src/activation/intent/MainActivity.java +++ b/src/activation/intent/MainActivity.java @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + package com.governikus.ausweisapp2; import android.app.Activity; @@ -12,6 +16,10 @@ import android.nfc.tech.IsoDep; import android.nfc.Tag; import android.os.Bundle; import android.util.Log; +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; + import org.qtproject.qt5.android.bindings.QtActivity; @@ -84,12 +92,6 @@ public class MainActivity extends QtActivity } - public NFCConnector getNfcConnector() - { - return NFCConnector.getInstance(this); - } - - @Override public void onCreate(Bundle savedInstanceState) { @@ -99,11 +101,8 @@ public class MainActivity extends QtActivity // register the broadcast receiver after loading the C++ library in super.onCreate() AndroidBluetoothReceiver.register(this); - NfcAdapterStateChangeReceiver.register(this); mNfcForegroundDispatcher = new NfcForegroundDispatcher(this); - Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG); - getNfcConnector().updateNfcTag(tag); setRequestedOrientation(isTablet() ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } @@ -115,9 +114,6 @@ public class MainActivity extends QtActivity Log.d(TAG, "onNewIntent (subsequent invocation of application): " + newIntent); super.onNewIntent(newIntent); - Tag tag = newIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - getNfcConnector().updateNfcTag(tag); - triggerActivation(newIntent.getDataString()); } @@ -145,12 +141,25 @@ public class MainActivity extends QtActivity // unregister the broadcast receiver before unloading the C++ library in super.onDestroy() AndroidBluetoothReceiver.unregister(this); - NfcAdapterStateChangeReceiver.unregister(this); super.onDestroy(); } + public void keepScreenOn(boolean pActivate) + { + Log.d(TAG, "Keep screen on: " + pActivate); + if (pActivate) + { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + else + { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } + + // required by UIPlugInQml::getPlatformSelectors() public boolean isTablet() { diff --git a/src/activation/internal/InternalActivationContext.cpp b/src/activation/internal/InternalActivationContext.cpp index 8f14792..7afbd05 100644 --- a/src/activation/internal/InternalActivationContext.cpp +++ b/src/activation/internal/InternalActivationContext.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "InternalActivationContext.h" diff --git a/src/activation/internal/InternalActivationContext.h b/src/activation/internal/InternalActivationContext.h index ba313e8..f8c3864 100644 --- a/src/activation/internal/InternalActivationContext.h +++ b/src/activation/internal/InternalActivationContext.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -19,7 +19,7 @@ class InternalActivationContext public: InternalActivationContext(const QUrl& pUrl); - virtual ~InternalActivationContext(); + virtual ~InternalActivationContext() override; QUrl getActivationURL() const override; bool sendProcessing() override; diff --git a/src/activation/internal/InternalActivationHandler.cpp b/src/activation/internal/InternalActivationHandler.cpp index ba15254..728d9bf 100644 --- a/src/activation/internal/InternalActivationHandler.cpp +++ b/src/activation/internal/InternalActivationHandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "InternalActivationHandler.h" @@ -26,7 +26,7 @@ void InternalActivationHandler::stop() } -void InternalActivationHandler::runAuthentication(InternalActivationContext* pContext) +void InternalActivationHandler::runAuthentication(const QSharedPointer& pContext) { Q_EMIT fireAuthenticationRequest(pContext); } diff --git a/src/activation/internal/InternalActivationHandler.h b/src/activation/internal/InternalActivationHandler.h index cf36227..6eef314 100644 --- a/src/activation/internal/InternalActivationHandler.h +++ b/src/activation/internal/InternalActivationHandler.h @@ -1,7 +1,7 @@ /*! * \brief ActivationHandler for Internal usage like JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,12 +21,12 @@ class InternalActivationHandler public: InternalActivationHandler(); - virtual ~InternalActivationHandler(); + virtual ~InternalActivationHandler() override; virtual bool start() override; virtual void stop() override; - void runAuthentication(InternalActivationContext* pContext); + void runAuthentication(const QSharedPointer& pContext); }; } /* namespace governikus */ diff --git a/src/activation/webservice/Template.cpp b/src/activation/webservice/Template.cpp index e22c746..c683b91 100644 --- a/src/activation/webservice/Template.cpp +++ b/src/activation/webservice/Template.cpp @@ -1,7 +1,5 @@ /*! - * Template.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "Template.h" diff --git a/src/activation/webservice/Template.h b/src/activation/webservice/Template.h index 61e7daa..ccc5f27 100644 --- a/src/activation/webservice/Template.h +++ b/src/activation/webservice/Template.h @@ -1,9 +1,7 @@ /*! - * Template.h - * * A simple template renderer. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/activation/webservice/WebserviceActivationContext.cpp b/src/activation/webservice/WebserviceActivationContext.cpp index 2cb5760..54abad9 100644 --- a/src/activation/webservice/WebserviceActivationContext.cpp +++ b/src/activation/webservice/WebserviceActivationContext.cpp @@ -1,7 +1,5 @@ /*! - * WebserviceActivationContext.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "WebserviceActivationContext.h" diff --git a/src/activation/webservice/WebserviceActivationContext.h b/src/activation/webservice/WebserviceActivationContext.h index ca5a264..1378cde 100644 --- a/src/activation/webservice/WebserviceActivationContext.h +++ b/src/activation/webservice/WebserviceActivationContext.h @@ -1,7 +1,5 @@ /*! - * WebserviceActivationContext.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,7 +24,7 @@ class WebserviceActivationContext public: WebserviceActivationContext(const QSharedPointer& pRequest); - virtual ~WebserviceActivationContext(); + virtual ~WebserviceActivationContext() override; QUrl getActivationURL() const override; diff --git a/src/activation/webservice/WebserviceActivationHandler.cpp b/src/activation/webservice/WebserviceActivationHandler.cpp index ce0f304..77639ce 100644 --- a/src/activation/webservice/WebserviceActivationHandler.cpp +++ b/src/activation/webservice/WebserviceActivationHandler.cpp @@ -1,12 +1,10 @@ /*! - * WebserviceActivationHandler.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "WebserviceActivationHandler.h" -#include "EnvHolder.h" +#include "Env.h" #include "HttpServerStatusParser.h" #include "Template.h" #include "VersionInfo.h" @@ -42,7 +40,7 @@ void WebserviceActivationHandler::stop() bool WebserviceActivationHandler::start() { - mServer = EnvHolder::shared(); + mServer = Env::getShared(); if (mServer->isListening()) { @@ -58,7 +56,7 @@ bool WebserviceActivationHandler::start() { 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(QStringLiteral("ShowUI=") + UiModule::CURRENT, port)).isNull()) { qCWarning(activation) << "ShowUI request timed out"; } @@ -101,7 +99,7 @@ void WebserviceActivationHandler::onNewRequest(const QSharedPointer else if (urlParameter.contains(QLatin1String("tctokenurl"))) { qCDebug(activation) << "Request type: authentication"; - Q_EMIT fireAuthenticationRequest(new WebserviceActivationContext(pRequest)); + Q_EMIT fireAuthenticationRequest(QSharedPointer::create(pRequest)); return; } } @@ -143,7 +141,7 @@ void WebserviceActivationHandler::handleShowUiRequest(UiModule pUiModule, const QString userAgent = QString::fromLatin1(pRequest->getHeader(QByteArrayLiteral("user-agent"))); if (userAgent.startsWith(QCoreApplication::applicationName())) { - QString version = userAgent.remove(QCoreApplication::applicationName() + '/').split(' ').at(0); + QString version = userAgent.remove(QCoreApplication::applicationName() + QLatin1Char('/')).split(QLatin1Char(' ')).at(0); VersionNumber callerVersion(version); if (callerVersion > VersionNumber::getApplicationVersion()) diff --git a/src/activation/webservice/WebserviceActivationHandler.h b/src/activation/webservice/WebserviceActivationHandler.h index 1f47dc5..e60fc02 100644 --- a/src/activation/webservice/WebserviceActivationHandler.h +++ b/src/activation/webservice/WebserviceActivationHandler.h @@ -1,7 +1,5 @@ /*! - * WebserviceActivationHandler.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -41,7 +39,7 @@ class WebserviceActivationHandler public: WebserviceActivationHandler(); - virtual ~WebserviceActivationHandler(); + virtual ~WebserviceActivationHandler() override; virtual bool start() override; virtual void stop() override; diff --git a/src/aidl/AidlBinder.java b/src/aidl/AidlBinder.java index cb29d26..4fc0c03 100644 --- a/src/aidl/AidlBinder.java +++ b/src/aidl/AidlBinder.java @@ -1,5 +1,11 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + package com.governikus.ausweisapp2; +import android.content.Intent; +import android.nfc.NfcAdapter; import android.nfc.Tag; import android.os.DeadObjectException; import android.os.IBinder; @@ -9,6 +15,8 @@ import java.lang.Throwable; import java.util.HashMap; import java.util.Map; +import org.qtproject.qt5.android.QtNative; + class AidlBinder extends IAusweisApp2Sdk.Stub { public final static String LOG_TAG = AusweisApp2Service.LOG_TAG; @@ -124,12 +132,17 @@ class AidlBinder extends IAusweisApp2Sdk.Stub public synchronized boolean updateNfcTag(String pSessionId, Tag pTag) { + Log.d(LOG_TAG, "Android service: Received nfc tag from client"); + if (!isValidSessionId(mCallbackSessionId)) { return false; } - mService.getNfcConnector().updateNfcTag(pTag); + Intent newIntent = new Intent(); + newIntent.putExtra(NfcAdapter.EXTRA_TAG, pTag); + QtNative.onNewIntent(newIntent); + return true; } diff --git a/src/aidl/PskManager.cpp b/src/aidl/PskManager.cpp index d694fb2..3a79b4e 100644 --- a/src/aidl/PskManager.cpp +++ b/src/aidl/PskManager.cpp @@ -1,7 +1,5 @@ /*! - * PskManager.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "PskManager.h" diff --git a/src/aidl/PskManager.h b/src/aidl/PskManager.h index 59b389a..fa41296 100644 --- a/src/aidl/PskManager.h +++ b/src/aidl/PskManager.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/aidl/UIPlugInAidl.cpp b/src/aidl/UIPlugInAidl.cpp index dc78f93..3f6eaf6 100644 --- a/src/aidl/UIPlugInAidl.cpp +++ b/src/aidl/UIPlugInAidl.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInAidl.h" diff --git a/src/aidl/UIPlugInAidl.h b/src/aidl/UIPlugInAidl.h index 137246b..2139b0f 100644 --- a/src/aidl/UIPlugInAidl.h +++ b/src/aidl/UIPlugInAidl.h @@ -1,7 +1,7 @@ /*! * \brief UIPlugIn implementation of the AIDL UI. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -32,7 +32,7 @@ class UIPlugInAidl public: UIPlugInAidl(); - virtual ~UIPlugInAidl(); + virtual ~UIPlugInAidl() override; static UIPlugInAidl* getInstance(bool pBlock = true); bool isSuccessfullInitialized(); diff --git a/src/card/CMakeLists.txt b/src/card/CMakeLists.txt index d8ffa35..2719ab3 100644 --- a/src/card/CMakeLists.txt +++ b/src/card/CMakeLists.txt @@ -2,10 +2,9 @@ ADD_SUBDIRECTORY(base) IF(DESKTOP) ADD_SUBDIRECTORY(pcsc) - ADD_SUBDIRECTORY(drivers) ENDIF() -IF(ANDROID) +IF(TARGET Qt5::Nfc) ADD_SUBDIRECTORY(nfc) ENDIF() @@ -13,4 +12,5 @@ IF(LINUX OR ANDROID OR IOS) ADD_SUBDIRECTORY(bluetooth) ENDIF() +ADD_SUBDIRECTORY(drivers) ADD_SUBDIRECTORY(remote) diff --git a/src/card/base/Apdu.cpp b/src/card/base/Apdu.cpp index a94b869..6c4ae43 100644 --- a/src/card/base/Apdu.cpp +++ b/src/card/base/Apdu.cpp @@ -1,12 +1,14 @@ /*! - * Apdu.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Apdu.h" + +#include "Commands.h" + #include + using namespace governikus; @@ -36,8 +38,9 @@ const QByteArray& Apdu::getBuffer() const } -CommandApdu::CommandApdu(const QByteArray& pBuffer) +CommandApdu::CommandApdu(const QByteArray& pBuffer, bool pUpdateRetryCounter) : Apdu(pBuffer) + , mUpdateRetryCounter(pUpdateRetryCounter) { } @@ -48,7 +51,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 length() > 5 && mBuffer.at(4) == char(0x00); + return length() > 5 && mBuffer.at(4) == '\0'; } @@ -72,6 +75,7 @@ CommandApdu::CommandApdu(const QByteArray& pHeader, const QByteArray& pData, int CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteArray& pData, int pLe) : Apdu(QByteArray()) + , mUpdateRetryCounter(false) { if (pData.size() > EXTENDED_MAX_LC) { @@ -96,7 +100,7 @@ CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteAr { if (CommandApdu::isExtendedLength(pData, pLe)) { - mBuffer += char(0x00); + mBuffer += '\0'; mBuffer += static_cast(pData.size() >> 8 & 0xff); mBuffer += static_cast(pData.size() & 0xff); } @@ -114,7 +118,7 @@ CommandApdu::CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteAr { if (pData.isEmpty()) { - mBuffer += char(0x00); + mBuffer += '\0'; } mBuffer += static_cast(pLe >> 8 & 0xff); } @@ -130,25 +134,25 @@ CommandApdu::~CommandApdu() char CommandApdu::getCLA() const { - return length() > 0 ? mBuffer.at(0) : 0; + return length() > 0 ? mBuffer.at(0) : '\0'; } char CommandApdu::getINS() const { - return length() > 1 ? mBuffer.at(1) : 0; + return length() > 1 ? mBuffer.at(1) : '\0'; } char CommandApdu::getP1() const { - return length() > 2 ? mBuffer.at(2) : 0; + return length() > 2 ? mBuffer.at(2) : '\0'; } char CommandApdu::getP2() const { - return mBuffer.size() > 3 ? mBuffer.at(3) : 0; + return mBuffer.size() > 3 ? mBuffer.at(3) : '\0'; } @@ -223,6 +227,12 @@ QByteArray CommandApdu::getData() const } +bool CommandApdu::isUpdateRetryCounter() const +{ + return mUpdateRetryCounter; +} + + ResponseApdu::ResponseApdu(const QByteArray& pBuffer) : Apdu(pBuffer) { @@ -242,7 +252,7 @@ void ResponseApdu::setBuffer(const QByteArray& pBuffer) QByteArray ResponseApdu::getData() const { - if (length() < 2) + if (length() < RETURN_CODE_LENGTH) { return QByteArray(); } @@ -253,27 +263,59 @@ QByteArray ResponseApdu::getData() const int ResponseApdu::getDataLength() const { - return length() - 2; + return length() - RETURN_CODE_LENGTH; } StatusCode ResponseApdu::getReturnCode() const { - // avoid "undefined-behavior" with explicit "uint" variable - const uint sw1 = static_cast(getSW1()); - const uchar sw2 = static_cast(getSW2()); - return StatusCode((sw1 << 8) + sw2); + if (mBuffer.isEmpty()) + { + return StatusCode::EMPTY; + } + + const int returnCodeAsInt = getReturnCodeAsHex().toInt(nullptr, 16); + return Enum::isValue(returnCodeAsInt) ? StatusCode(returnCodeAsInt) : StatusCode::INVALID; } -char ResponseApdu::getSW1() const +QByteArray ResponseApdu::getReturnCodeAsHex() const { - if (length() < 2) + return mBuffer.right(RETURN_CODE_LENGTH).toHex(); +} + + +int ResponseApdu::getRetryCounter() const +{ + StatusCode statusCode = getReturnCode(); + if (statusCode == StatusCode::SUCCESS) + { + return 3; + } + if (statusCode == StatusCode::PIN_RETRY_COUNT_2) + { + return 2; + } + if (statusCode == StatusCode::PIN_SUSPENDED) + { + return 1; + } + if (statusCode == StatusCode::PIN_BLOCKED || statusCode == StatusCode::PIN_DEACTIVATED) { - qCCritical(card) << "Buffer too short, returning 0"; return 0; } - return mBuffer.at(length() - 2); + return -1; +} + + +SW1 ResponseApdu::getSW1() const +{ + if (length() < RETURN_CODE_LENGTH) + { + qCCritical(card) << "Buffer too short, returning 0"; + return SW1::INVALID; + } + return SW1(mBuffer.at(length() - RETURN_CODE_LENGTH)); } diff --git a/src/card/base/Apdu.h b/src/card/base/Apdu.h index ee7885f..f78bbc9 100644 --- a/src/card/base/Apdu.h +++ b/src/card/base/Apdu.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -10,7 +10,9 @@ namespace governikus { -defineEnumType(StatusCode, +defineTypedEnumType(StatusCode, quint16, + EMPTY = 0x0000, + INVALID = 0x0001, SUCCESS = 0x9000, NO_PKCS15_APP = 0x6200, END_OF_FILE = 0x6282, @@ -57,7 +59,10 @@ defineEnumType(StatusCode, * As defined in ISO-7816-4 Table-5 */ defineEnumType(SW1, + INVALID = 0x00, + MORE_DATA_AVAILABLE = 0x61, ERROR_COMMAND_NOT_ALLOWED = 0x69, + WRONG_LE_FIELD = 0x6c, ) class Apdu @@ -85,10 +90,12 @@ class CommandApdu : public Apdu { private: + bool mUpdateRetryCounter; + inline bool isExtendedLength() const; public: - CommandApdu(const QByteArray& pBuffer); + CommandApdu(const QByteArray& pBuffer, bool pUpdateRetryCounter = false); CommandApdu(const QByteArray& pHeader, const QByteArray& pData, int pLe); CommandApdu(char pCla, char pIns, char pP1, char pP2, const QByteArray& pData = QByteArray(), int pLe = NO_LE); virtual ~CommandApdu(); @@ -100,6 +107,7 @@ class CommandApdu int getLc() const; int getLe() const; QByteArray getData() const; + bool isUpdateRetryCounter() const; static bool isExtendedLength(const QByteArray& pData, int pLe); static bool isSecureMessaging(const QByteArray& pCommandBuffer); @@ -109,6 +117,9 @@ class ResponseApdu : public Apdu { + private: + static const int RETURN_CODE_LENGTH = 2; + public: ResponseApdu(const QByteArray& pBuffer = QByteArray()); virtual ~ResponseApdu(); @@ -117,7 +128,9 @@ class ResponseApdu QByteArray getData() const; int getDataLength() const; StatusCode getReturnCode() const; - char getSW1() const; + QByteArray getReturnCodeAsHex() const; + int getRetryCounter() const; + SW1 getSW1() const; char getSW2() const; }; diff --git a/src/card/base/CMakeLists.txt b/src/card/base/CMakeLists.txt index 5213ab6..018eec7 100644 --- a/src/card/base/CMakeLists.txt +++ b/src/card/base/CMakeLists.txt @@ -1,4 +1,3 @@ ADD_PLATFORM_LIBRARY(AusweisAppCard) -TARGET_INCLUDE_DIRECTORIES(AusweisAppCard SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(AusweisAppCard Qt5::Core AusweisAppGlobal ${OPENSSL_LIBRARIES}) +TARGET_LINK_LIBRARIES(AusweisAppCard Qt5::Core OpenSSL::Crypto AusweisAppGlobal AusweisAppConfiguration AusweisAppCardDrivers) diff --git a/src/card/base/Card.cpp b/src/card/base/Card.cpp index b8ef63e..51abf04 100644 --- a/src/card/base/Card.cpp +++ b/src/card/base/Card.cpp @@ -1,8 +1,7 @@ /*! - * Card.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ + #include "Card.h" #include @@ -22,9 +21,9 @@ Card::~Card() } -CardReturnCode Card::establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) +CardReturnCode Card::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) { - Q_UNUSED(pPinId); + Q_UNUSED(pPasswordId); Q_UNUSED(pChat); Q_UNUSED(pCertificateDescription); Q_UNUSED(pChannelOutput); diff --git a/src/card/base/Card.h b/src/card/base/Card.h index 479fa24..352c5be 100644 --- a/src/card/base/Card.h +++ b/src/card/base/Card.h @@ -1,9 +1,7 @@ /*! - * Card.h - * * \brief Class representing a smart card * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -55,7 +53,7 @@ class Card /*! * Establishes a PACE channel, i.e. the corresponding reader is no basic reader. */ - virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds = 60); + virtual CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, 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. diff --git a/src/card/base/CardConnection.cpp b/src/card/base/CardConnection.cpp index 092cd65..13b4ac1 100644 --- a/src/card/base/CardConnection.cpp +++ b/src/card/base/CardConnection.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -29,6 +29,14 @@ const ReaderInfo& CardConnection::getReaderInfo() } +bool CardConnection::stopSecureMessaging() +{ + bool result; + QMetaObject::invokeMethod(mCardConnectionWorker.data(), "stopSecureMessaging", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); + return result; +} + + UpdateRetryCounterCommand* CardConnection::createUpdateRetryCounterCommand() { return new UpdateRetryCounterCommand(mCardConnectionWorker); @@ -41,9 +49,9 @@ UnblockPinCommand* CardConnection::createUnblockPinCommand(const QString& pPuk) } -EstablishPaceChannelCommand* CardConnection::createEstablishPaceChannelCommand(PACE_PIN_ID pPacePinId, const QString& pPacePin, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription) +EstablishPaceChannelCommand* CardConnection::createEstablishPaceChannelCommand(PACE_PASSWORD_ID pPacePasswordId, const QString& pPacePassword, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription) { - return new EstablishPaceChannelCommand(mCardConnectionWorker, pPacePinId, pPacePin, pEffectiveChat, pCertificateDescription); + return new EstablishPaceChannelCommand(mCardConnectionWorker, pPacePasswordId, pPacePassword, pEffectiveChat, pCertificateDescription); } @@ -77,7 +85,7 @@ DidAuthenticateEAC2Command* CardConnection::createDidAuthenticateEAC2Command( void CardConnection::onReaderInfoChanged(const ReaderInfo& pReaderInfo) { mReaderInfo = pReaderInfo; - Q_EMIT fireReaderInfoChanged(); + Q_EMIT fireReaderInfoChanged(mReaderInfo); } diff --git a/src/card/base/CardConnection.h b/src/card/base/CardConnection.h index e3d8ef5..73c3ea5 100644 --- a/src/card/base/CardConnection.h +++ b/src/card/base/CardConnection.h @@ -1,9 +1,7 @@ /*! - * CardConnection.h - * * \brief Contains a card connection object * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -52,7 +50,7 @@ class CardConnection UpdateRetryCounterCommand* createUpdateRetryCounterCommand(); UnblockPinCommand* createUnblockPinCommand(const QString& pPuk); - EstablishPaceChannelCommand* createEstablishPaceChannelCommand(PACE_PIN_ID pPacePinId, const QString& pPacePin, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription); + EstablishPaceChannelCommand* createEstablishPaceChannelCommand(PACE_PASSWORD_ID pPacePasswordId, const QString& pPacePassword, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription); SetEidPinCommand* createSetEidPinCommand(const QString& pNewPin, quint8 pTimeoutSeconds); DestroyPaceChannelCommand* createDestroyPaceChannelCommand(); @@ -102,6 +100,7 @@ class CardConnection */ const ReaderInfo& getReaderInfo(); + bool stopSecureMessaging(); template QMetaObject::Connection callDidAuthenticateEAC1Command(const typename QtPrivate::FunctionPointer::Object* pReceiver, T pFunc) @@ -134,9 +133,9 @@ class CardConnection template QMetaObject::Connection callEstablishPaceChannelCommand(const typename QtPrivate::FunctionPointer::Object* pReceiver, T pFunc, - PACE_PIN_ID pPacePinId, const QString& pPacePin, const QByteArray& pEffectiveChat = QByteArray(), const QByteArray& pCertificateDescription = QByteArray()) + PACE_PASSWORD_ID pPacePasswordId, const QString& pPacePassword, const QByteArray& pEffectiveChat = QByteArray(), const QByteArray& pCertificateDescription = QByteArray()) { - auto command = createEstablishPaceChannelCommand(pPacePinId, pPacePin, pEffectiveChat, pCertificateDescription); + EstablishPaceChannelCommand* command = createEstablishPaceChannelCommand(pPacePasswordId, pPacePassword, pEffectiveChat, pCertificateDescription); return call(command, pReceiver, pFunc); } @@ -177,7 +176,7 @@ class CardConnection Q_SIGNALS: - void fireReaderInfoChanged(); + void fireReaderInfoChanged(const ReaderInfo& pReaderInfo); }; } /* namespace governikus */ diff --git a/src/card/base/CardConnectionWorker.cpp b/src/card/base/CardConnectionWorker.cpp index 3a06905..a5c3f82 100644 --- a/src/card/base/CardConnectionWorker.cpp +++ b/src/card/base/CardConnectionWorker.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnectionWorker.h" @@ -18,7 +18,6 @@ CardConnectionWorker::CardConnectionWorker(Reader* pReader) , mReader(pReader) , mSecureMessaging() { - connect(this, &CardConnectionWorker::fireRetryCounterPotentiallyChanged, mReader.data(), &Reader::onRetryCounterPotentiallyChanged); connect(mReader, &Reader::fireCardInserted, this, &CardConnectionWorker::onReaderInfoChanged); connect(mReader, &Reader::fireCardRemoved, this, &CardConnectionWorker::onReaderInfoChanged); connect(mReader, &Reader::fireCardRetryCounterChanged, this, &CardConnectionWorker::onReaderInfoChanged); @@ -78,18 +77,30 @@ CardReturnCode CardConnectionWorker::transmit(const CommandApdu& pCommandApdu, R return CardReturnCode::CARD_NOT_FOUND; } + CardReturnCode returnCode; + if (mSecureMessaging) { CommandApdu securedCommandApdu = mSecureMessaging->encrypt(pCommandApdu); ResponseApdu securedResponseApdu; - CardReturnCode returnCode = mReader->getCard()->transmit(securedCommandApdu, securedResponseApdu); + returnCode = mReader->getCard()->transmit(securedCommandApdu, securedResponseApdu); if (!mSecureMessaging->decrypt(securedResponseApdu, pResponseApdu)) { return CardReturnCode::COMMAND_FAILED; } - return returnCode; } - return mReader->getCard()->transmit(pCommandApdu, pResponseApdu); + else + { + returnCode = mReader->getCard()->transmit(pCommandApdu, pResponseApdu); + } + + if (pCommandApdu.isUpdateRetryCounter()) + { + int retryCounter = pResponseApdu.getRetryCounter(); + mReader->setRetryCounter(retryCounter); + } + + return returnCode; } @@ -145,16 +156,16 @@ bool CardConnectionWorker::stopSecureMessaging() } -CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, - const QString& pPinValue, +CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, + const QString& pPasswordValue, EstablishPACEChannelOutput& pChannelOutput) { - return establishPaceChannel(pPinId, pPinValue, nullptr, nullptr, pChannelOutput); + return establishPaceChannel(pPasswordId, pPasswordValue, nullptr, nullptr, pChannelOutput); } -CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, - const QString& pPinValue, +CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, + const QString& pPasswordValue, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput) @@ -165,13 +176,15 @@ CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, } CardReturnCode returnCode; - qCInfo(support) << "Starting PACE for" << pPinId; + qCInfo(support) << "Starting PACE for" << pPasswordId; if (mReader->getReaderInfo().isBasicReader()) { - Q_ASSERT(!pPinValue.isEmpty()); + Q_ASSERT(!pPasswordValue.isEmpty()); PaceHandler paceHandler(sharedFromThis()); paceHandler.setChat(pChat); - returnCode = paceHandler.establishPaceChannel(pPinId, pPinValue); + returnCode = paceHandler.establishPaceChannel(pPasswordId, pPasswordValue); + pChannelOutput.setPaceReturnCode(returnCode); + pChannelOutput.setStatusMseSetAt(paceHandler.getStatusMseSetAt()); if (returnCode == CardReturnCode::OK) { @@ -185,12 +198,12 @@ CardReturnCode CardConnectionWorker::establishPaceChannel(PACE_PIN_ID pPinId, } else { - Q_ASSERT(pPinValue.isNull()); - returnCode = mReader->getCard()->establishPaceChannel(pPinId, pChat, pCertificateDescription, pChannelOutput); + Q_ASSERT(pPasswordValue.isNull()); + returnCode = mReader->getCard()->establishPaceChannel(pPasswordId, pChat, pCertificateDescription, pChannelOutput); + pChannelOutput.setPaceReturnCode(returnCode); } - Q_EMIT fireRetryCounterPotentiallyChanged(); - qCInfo(support) << "Finished PACE for" << pPinId << "with result" << returnCode; + qCInfo(support) << "Finished PACE for" << pPasswordId << "with result" << returnCode; return returnCode; } @@ -208,7 +221,9 @@ CardReturnCode CardConnectionWorker::destroyPaceChannel() stopSecureMessaging(); MSEBuilder builder(MSEBuilder::P1::ERASE, MSEBuilder::P2::DEFAULT_CHANNEL); ResponseApdu response; - return mReader->getCard()->transmit(builder.build(), response); + CardReturnCode cardReturnCode = mReader->getCard()->transmit(builder.build(), response); + qCDebug(card) << "Destroying PACE channel with invalid command causing 6700 as return code"; + return cardReturnCode; } else { diff --git a/src/card/base/CardConnectionWorker.h b/src/card/base/CardConnectionWorker.h index 06f9cc3..21eeeb3 100644 --- a/src/card/base/CardConnectionWorker.h +++ b/src/card/base/CardConnectionWorker.h @@ -1,7 +1,7 @@ /*! * \brief Worker for \ref CardConnection that will do the job in \ref ReaderManagerWorker * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -77,8 +77,8 @@ 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 CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, - const QString& pPinValue, + virtual CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, + const QString& pPasswordValue, EstablishPACEChannelOutput& pChannelOutput); /*! @@ -86,8 +86,8 @@ 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 CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, - const QString& pPinValue, + virtual CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, + const QString& pPasswordValue, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput); @@ -100,12 +100,11 @@ class CardConnectionWorker /*! * Destroys an established secure messaging channel, if there is one. */ - virtual bool stopSecureMessaging(); + Q_INVOKABLE virtual bool stopSecureMessaging(); virtual CardReturnCode setEidPin(const QString& pNewPin, quint8 pTimeoutSeconds); Q_SIGNALS: - void fireRetryCounterPotentiallyChanged(); void fireReaderInfoChanged(const ReaderInfo& pReaderInfo); }; diff --git a/src/card/base/CardInfo.cpp b/src/card/base/CardInfo.cpp index dd76db6..211ed94 100644 --- a/src/card/base/CardInfo.cpp +++ b/src/card/base/CardInfo.cpp @@ -1,15 +1,14 @@ /*! - * CardInfo.cpp - * * \brief CardInfo holds smart card information, such as the type and some contained data structure (currently only the EF.CardAccess). * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "CardInfo.h" + #include "asn1/PACEInfo.h" #include "asn1/SecurityInfos.h" #include "CardConnectionWorker.h" -#include "CardInfo.h" #include #include @@ -21,7 +20,11 @@ Q_DECLARE_LOGGING_CATEGORY(card) using namespace governikus; -CardInfo::CardInfo(CardType pCardType, QSharedPointer pEfCardAccess, int pRetryCounter, bool pPinDeactivated, bool pPukInoperative) + +const int CardInfo::UNDEFINED_RETRY_COUNTER = -1; + + +CardInfo::CardInfo(CardType pCardType, const QSharedPointer& pEfCardAccess, int pRetryCounter, bool pPinDeactivated, bool pPukInoperative) : mCardType(pCardType) , mEfCardAccess(pEfCardAccess) , mRetryCounter(pRetryCounter) @@ -31,9 +34,33 @@ CardInfo::CardInfo(CardType pCardType, QSharedPointer pEfCar } -CardType CardInfo::getCardType() const +QString CardInfo::getCardTypeString() const { - return mCardType; + switch (mCardType) + { + case CardType::NONE: + return tr("not inserted", "Karte"); + + case CardType::UNKNOWN: + return tr("unknown type", "Karte"); + + case CardType::EID_CARD: + return tr("ID card (PA/eAT)"); + } + + Q_UNREACHABLE(); +} + + +bool CardInfo::isAvailable() const +{ + return mCardType != CardType::NONE; +} + + +bool CardInfo::isEid() const +{ + return mCardType == CardType::EID_CARD; } @@ -55,6 +82,12 @@ int CardInfo::getRetryCounter() const } +bool CardInfo::isRetryCounterDetermined() const +{ + return mRetryCounter != UNDEFINED_RETRY_COUNTER; +} + + bool CardInfo::isPinDeactivated() const { return mPinDeactivated; @@ -194,3 +227,22 @@ bool CardInfoFactory::checkEfCardAccess(const QSharedPointer& pEfC return true; } + + +namespace governikus +{ + + +QDebug operator<<(QDebug pDbg, const CardInfo& pCardInfo) +{ + QDebugStateSaver saver(pDbg); + pDbg.nospace() << "{Type: " << pCardInfo.mCardType + << ", Retry counter: " << pCardInfo.mRetryCounter + << ", Pin deactivated: " << pCardInfo.mPinDeactivated << "}"; + // Skipping mEfCardAccess since there is no pretty formating available. + + return pDbg; +} + + +} diff --git a/src/card/base/CardInfo.h b/src/card/base/CardInfo.h index 30fbbb3..16a7439 100644 --- a/src/card/base/CardInfo.h +++ b/src/card/base/CardInfo.h @@ -1,9 +1,7 @@ /*! - * CardInfo.h - * * \brief Contains the CardInfo and the CardInfoFactory * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -11,6 +9,7 @@ #include "asn1/SecurityInfos.h" #include "SmartCardDefinitions.h" +#include #include namespace governikus @@ -27,17 +26,25 @@ class ReaderInfo; */ class CardInfo { - CardType mCardType; - QSharedPointer mEfCardAccess; - int mRetryCounter; - bool mPinDeactivated; - bool mPukInoperative; + Q_DECLARE_TR_FUNCTIONS(governikus::CardInfo) + + private: + CardType mCardType; + QSharedPointer mEfCardAccess; + int mRetryCounter; + bool mPinDeactivated; + bool mPukInoperative; + static const int UNDEFINED_RETRY_COUNTER; + + friend QDebug operator<<(QDebug, const CardInfo&); public: - CardInfo(CardType pCardType, QSharedPointer = QSharedPointer(), - int pRetryCounter = -1, bool pPinDeactivated = false, bool pPukInoperative = false); + CardInfo(CardType pCardType, const QSharedPointer& = QSharedPointer(), + int pRetryCounter = UNDEFINED_RETRY_COUNTER, bool pPinDeactivated = false, bool pPukInoperative = false); - CardType getCardType() const; + QString getCardTypeString() const; + bool isAvailable() const; + bool isEid() const; QSharedPointer getEfCardAccess() const; @@ -45,6 +52,8 @@ class CardInfo int getRetryCounter() const; + bool isRetryCounterDetermined() const; + /*! * The online identification function has not been activated by the competent authority. */ @@ -90,4 +99,7 @@ class CardInfoFactory }; +QDebug operator<<(QDebug pDbg, const CardInfo& pCardInfo); + + } /* namespace governikus */ diff --git a/src/card/base/CardOperationResult.h b/src/card/base/CardOperationResult.h new file mode 100644 index 0000000..0077572 --- /dev/null +++ b/src/card/base/CardOperationResult.h @@ -0,0 +1,42 @@ +/*! + * \brief Generic class representing the result of a card operation, or an error. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "CardReturnCode.h" + +namespace governikus +{ +template +class CardOperationResult +{ + private: + const CardReturnCode mReturnCode; + const T mPayload; + + public: + CardOperationResult(const CardReturnCode& pReturnCode, const T& pPayload) + : mReturnCode(pReturnCode) + , mPayload(pPayload) + { + } + + + const CardReturnCode& getReturnCode() const + { + return mReturnCode; + } + + + const T& getPayload() const + { + return mPayload; + } + + +}; + +} /* namespace governikus */ diff --git a/src/card/base/Commands.cpp b/src/card/base/Commands.cpp index fc083be..a5a900e 100644 --- a/src/card/base/Commands.cpp +++ b/src/card/base/Commands.cpp @@ -1,7 +1,5 @@ /*! - * Commands.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Commands.h" @@ -92,6 +90,33 @@ QByteArray GetChallengeResponse::getChallenge() const /* * MSEBuilder */ +bool MSEBuilder::isUpdateRetryCounterCommand(const QByteArray& cmd) +{ + if (cmd.size() < 4) + { + return false; + } + + if (cmd.at(0) != CommandApdu::CLA) + { + return false; + } + if (cmd.at(1) != static_cast(MSEBuilder::INS::MANAGE_SECURITY_ENVIRONMENT)) + { + return false; + } + if (cmd.at(2) != static_cast(MSEBuilder::P1::PERFORM_SECURITY_OPERATION)) + { + return false; + } + if (cmd.at(3) != static_cast(MSEBuilder::P2::SET_AT)) + { + return false; + } + + return true; +} + MSEBuilder::MSEBuilder(P1 p1, P2 p2) : CommandApduBuilder() @@ -127,11 +152,11 @@ void MSEBuilder::setPublicKey(const QByteArray& pData) } -void MSEBuilder::setPublicKey(PACE_PIN_ID pPin) +void MSEBuilder::setPublicKey(PACE_PASSWORD_ID pPasswordId) { static const char TAG_PUBLIC_KEY = char(0x83); QByteArray data; - data += Enum::getValue(pPin); + data += Enum::getValue(pPasswordId); mPublicKey = Asn1Util::encode(TAG_PUBLIC_KEY, data); } @@ -158,8 +183,6 @@ void MSEBuilder::setChat(const QByteArray& pData) CommandApdu MSEBuilder::build() { - static const char INS = 0x22; - QByteArray data; data += mOid; data += mPublicKey; @@ -168,7 +191,7 @@ CommandApdu MSEBuilder::build() data += mEphemeralPublicKey; data += mChat; - return CommandApdu(CommandApdu::CLA, INS, static_cast(mP1), static_cast(mP2), data); + return CommandApdu(CommandApdu::CLA, static_cast(MSEBuilder::INS::MANAGE_SECURITY_ENVIRONMENT), static_cast(mP1), static_cast(mP2), data); } @@ -328,7 +351,7 @@ CommandApdu ResetRetryCounterBuilder::build() { static const char INS = 0x2c; // P1: 2 (change), 3 (unblock) - char p1 = mPin.isNull() ? 3 : 2; + const char p1 = mPin.isNull() ? char(3) : char(2); // P2: 3 (PIN) (2 (CAN) -- not used) // data: new PIN, when changing return CommandApdu(CommandApdu::CLA, INS, p1, 3, mPin); @@ -355,13 +378,13 @@ QByteArray PinModifyBuilder::createCommandData(quint8 pTimeoutSeconds, char pMsg // bmFormatString (PIN format): system unit is bytes (0x80), ASCII format (0x02) command += char(0x82); // bmPINBlockString (PIN block size and length info): PIN not in APDU command - command += char(0x00); + command += '\0'; // bmPINLengthFormat (format of PIN length field in APDU command): PIN not in APDU command - command += char(0x00); + command += '\0'; // bInsertionOffsetOld (insertion position offset for old PIN) - command += char(0x00); + command += '\0'; // bInsertionOffsetNew BYTE (insertion position offset for new PIN) - command += char(0x00); + command += '\0'; // wPINMaxExtraDigit USHORT (0xXXYY, min (XX) and max (length) of new PIN) command += 0x06; command += 0x06; @@ -381,9 +404,9 @@ QByteArray PinModifyBuilder::createCommandData(quint8 pTimeoutSeconds, char pMsg // bMsgIndex3 (index (into reader table) of third message to display) command += pMsgIndex3; // bTeoPrologue (T1 only: I-block prologue field to use): fill with 0 - command += char(0x00); - command += char(0x00); - command += char(0x00); + command += '\0'; + command += '\0'; + command += '\0'; if (pAbData.size() > 0xFF) { @@ -393,9 +416,9 @@ QByteArray PinModifyBuilder::createCommandData(quint8 pTimeoutSeconds, char pMsg } // ulDataLength (length of the APDU to be sent to ICC) command += static_cast(pAbData.size()); - command += char(0x00); - command += char(0x00); - command += char(0x00); + command += '\0'; + command += '\0'; + command += '\0'; command += pAbData; return command; @@ -416,13 +439,13 @@ CommandApdu PinModifyBuilder::createCommandDataCcid(quint8 pTimeoutSeconds) cons // bmFormatString (PIN format): system unit is bytes (0x80), ASCII format (0x02) abPINDataStructure += char(0x82); // bmPINBlockString (PIN block size and length info): PIN not in APDU command - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; // bmPINLengthFormat (format of PIN length field in APDU command): PIN not in APDU command - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; // bInsertionOffsetOld (insertion position offset for old PIN) - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; // bInsertionOffsetNew BYTE (insertion position offset for new PIN) - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; // wPINMaxExtraDigit USHORT (0xXXYY, min (XX) and max (length) of new PIN) abPINDataStructure += char(0x06); abPINDataStructure += char(0x06); @@ -440,13 +463,13 @@ CommandApdu PinModifyBuilder::createCommandDataCcid(quint8 pTimeoutSeconds) cons // bMsgIndex2 (index (into reader table) of second message to display) abPINDataStructure += char(0x02); // bMsgIndex3 (index (into reader table) of third message to display) - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; // bTeoPrologue (T1 only: I-block prologue field to use): fill with 0 - abPINDataStructure += char(0x00); - abPINDataStructure += char(0x00); - abPINDataStructure += char(0x00); + abPINDataStructure += '\0'; + abPINDataStructure += '\0'; + abPINDataStructure += '\0'; // abData (APDU to be sent to ICC) - abPINDataStructure += char(0x00); // CLA: command + abPINDataStructure += '\0'; // CLA: command abPINDataStructure += char(0x2c); // INS: Reset Retry Counter abPINDataStructure += char(0x02); // P1: new PIN/CAN abPINDataStructure += char(0x03); // P2: PIN diff --git a/src/card/base/Commands.h b/src/card/base/Commands.h index 4a339bd..d02d425 100644 --- a/src/card/base/Commands.h +++ b/src/card/base/Commands.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -10,31 +10,10 @@ #include "FileRef.h" #include "SmartCardDefinitions.h" -#include - namespace governikus { -// TODO: brauchen wir das wirklich? -template QByteArray toBigEndian(T pDataToConvert) -{ - uchar converted[sizeof(T)]; - qToBigEndian(pDataToConvert, converted); - - unsigned long position; - for (position = 0; position < sizeof(T) - 1; ++position) - { - if (converted[position] != 0) - { - break; - } - } - - return QByteArray(reinterpret_cast(&converted[position]), static_cast(sizeof(T) - position)); -} - - class CommandApduBuilder { private: @@ -88,21 +67,28 @@ class MSEBuilder : public CommandApduBuilder { public: - enum class P1 : int + enum class INS : char { - COMPUTE_DIGITAL_SIGNATURE = 0x41, PUT_HASH = 0xa0, PERFORM_SECURITY_OPERATION = 0xc1, SET_DST = 0x81, ERASE = 0xF3, + MANAGE_SECURITY_ENVIRONMENT = 0x22, }; - enum class P2 : int + enum class P1 : char { - SET_AT = 0xa4, HASH_ALGORITHM = 0xaa, COMPUTE_DIGITAL_SIGNATURE = 0xb6, ENCRYPTION_OPERATION = 0xb8, DEFAULT_CHANNEL = 0x00, + COMPUTE_DIGITAL_SIGNATURE = 0x41, PUT_HASH = char(0xa0), PERFORM_SECURITY_OPERATION = char(0xc1), SET_DST = char(0x81), ERASE = char(0xF4), }; + enum class P2 : char + { + SET_AT = char(0xa4), HASH_ALGORITHM = char(0xaa), COMPUTE_DIGITAL_SIGNATURE = char(0xb6), ENCRYPTION_OPERATION = char(0xb8), DEFAULT_CHANNEL = 0x01, + }; + + static bool isUpdateRetryCounterCommand(const QByteArray& cmd); + MSEBuilder(P1 p1, P2 p2); void setAuxiliaryData(const QByteArray& pData); void setOid(const QByteArray& pData); void setPublicKey(const QByteArray& pData); - void setPublicKey(PACE_PIN_ID pPin); + void setPublicKey(PACE_PASSWORD_ID pPassword); void setPrivateKey(const QByteArray& pData); void setEphemeralPublicKey(const QByteArray& pData); void setChat(const QByteArray& pData); diff --git a/src/card/base/DestroyPACEChannel.cpp b/src/card/base/DestroyPACEChannel.cpp index e9ebdc8..ad0e936 100644 --- a/src/card/base/DestroyPACEChannel.cpp +++ b/src/card/base/DestroyPACEChannel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "DestroyPACEChannel.h" @@ -15,8 +15,8 @@ QByteArray DestroyPACEChannelBuilder::createCommandData() QByteArray commandData; commandData += INDEX_DESTROY_PACE_CHANNEL; - commandData += char(0x00); - commandData += char(0x00); + commandData += '\0'; + commandData += '\0'; return commandData; } diff --git a/src/card/base/DestroyPACEChannel.h b/src/card/base/DestroyPACEChannel.h index 4859b7d..45b4aa6 100644 --- a/src/card/base/DestroyPACEChannel.h +++ b/src/card/base/DestroyPACEChannel.h @@ -1,7 +1,7 @@ /*! * \brief Data object for creation of card command DestroyPACEChannel * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/EstablishPACEChannel.cpp b/src/card/base/EstablishPACEChannel.cpp index 789e160..4007490 100644 --- a/src/card/base/EstablishPACEChannel.cpp +++ b/src/card/base/EstablishPACEChannel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -9,6 +9,7 @@ #include #include #include +#include using namespace governikus; @@ -17,6 +18,23 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) +namespace +{ +template QByteArray readByteArray(const QByteArray& pInput, int& pOffset) +{ + Q_ASSERT(sizeof(T) < INT_MAX); + + T length = qFromLittleEndian(pInput.data() + pOffset); + pOffset += static_cast(sizeof(T)); + QByteArray result = pInput.mid(pOffset, length); + pOffset += length; + return result; +} + + +} + + namespace governikus { @@ -63,7 +81,7 @@ IMPLEMENT_ASN1_OBJECT(ESTABLISHPACECHANNELINPUT) EstablishPACEChannelBuilder::EstablishPACEChannelBuilder() - : mPinId(PACE_PIN_ID::PACE_MRZ) + : mPasswordId(PACE_PASSWORD_ID::PACE_MRZ) , mChat(nullptr) , mCertificateDescription() { @@ -82,9 +100,9 @@ void EstablishPACEChannelBuilder::setChat(const QByteArray& pChat) } -void EstablishPACEChannelBuilder::setPinId(PACE_PIN_ID pPinId) +void EstablishPACEChannelBuilder::setPasswordId(PACE_PASSWORD_ID pPasswordId) { - mPinId = pPinId; + mPasswordId = pPasswordId; } @@ -94,7 +112,7 @@ QByteArray EstablishPACEChannelBuilder::createCommandData() static const char INDEX_ESTABLISH_PACE_CHANNEL = 0x02; QByteArray inputData; - inputData += static_cast(mPinId); + inputData += static_cast(mPasswordId); if (mChat.size() > 0xFF) { @@ -105,7 +123,7 @@ QByteArray EstablishPACEChannelBuilder::createCommandData() inputData += static_cast(mChat.size()); inputData += mChat; - inputData += char(0x00); // length of PIN + inputData += '\0'; // length of PIN if (mCertificateDescription.size() > 0xFFFF) { @@ -137,7 +155,7 @@ CommandApdu EstablishPACEChannelBuilder::createCommandDataCcid() { auto channelInput = newObject(); - ASN1_INTEGER_set(channelInput->mPasswordID, static_cast(mPinId)); + ASN1_INTEGER_set(channelInput->mPasswordID, static_cast(mPasswordId)); if (!mChat.isNull()) { channelInput->mCHAT = ASN1_OCTET_STRING_new(); @@ -162,6 +180,7 @@ EstablishPACEChannelOutput::EstablishPACEChannelOutput() , mCarCurr() , mCarPrev() , mIdIcc() + , mStatusMseSetAt() { } @@ -210,6 +229,18 @@ void EstablishPACEChannelOutput::setCarPrev(const QByteArray& pCarPrev) } +QByteArray EstablishPACEChannelOutput::getMseStatusSetAt() const +{ + return mStatusMseSetAt; +} + + +void EstablishPACEChannelOutput::setStatusMseSetAt(const QByteArray& pStatusMseSetAt) +{ + mStatusMseSetAt = pStatusMseSetAt; +} + + void EstablishPACEChannelOutput::setEfCardAccess(const QByteArray& pEfCardAccess) { Q_ASSERT(mEfCardAccess.isNull()); @@ -230,41 +261,21 @@ void EstablishPACEChannelOutput::setPaceReturnCode(CardReturnCode pPaceReturnCod } -int EstablishPACEChannelOutput::parseUSHORT(const QByteArray& pData, int pOffset) -{ - int len = static_cast(pData.at(pOffset)); - len += (static_cast(pData.at(pOffset + 1)) << 8); - return len; -} - - -QByteArray EstablishPACEChannelOutput::reverse(const QByteArray& pArrayToReverse) -{ - QByteArray reversed; - for (int i = pArrayToReverse.size() - 1; i >= 0; i--) - { - reversed += (pArrayToReverse.at(i)); - } - return reversed; -} - - -void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PIN_ID pPinId) +void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PASSWORD_ID pPasswordId) { if (pControlOutput.size() < 6) { qCWarning(card) << "Output of EstablishPACEChannel has wrong size"; return; } - quint32 paceReturnCode; - QDataStream(reverse(pControlOutput.mid(0, 4))) >> paceReturnCode; - mPaceReturnCode = parseReturnCode(paceReturnCode, pPinId); + quint32 paceReturnCode = qFromLittleEndian(pControlOutput.data()); + mPaceReturnCode = parseReturnCode(paceReturnCode, pPasswordId); if (mPaceReturnCode == CardReturnCode::UNKNOWN) { - mPaceReturnCode = PersoSimWorkaround::parsingEstablishPACEChannelOutput(pControlOutput, pPinId); + mPaceReturnCode = PersoSimWorkaround::parsingEstablishPACEChannelOutput(pControlOutput, pPasswordId); } - int dataLength = parseUSHORT(pControlOutput.mid(4, 2), 0); + quint16 dataLength = qFromLittleEndian(pControlOutput.data() + 4); if (pControlOutput.size() < 6 + dataLength) { qCWarning(card) << "Output of EstablishPACEChannel has wrong size"; @@ -277,17 +288,14 @@ void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PI } // Response data according to PC/SC Part 10 amendment 1.1 - int it = 6; - //uint status = (static_cast(pControlOutput.at(it)) << 8); - ++it; - //status += static_cast(pControlOutput.at(it)); - ++it; + quint16 status = qFromBigEndian(pControlOutput.data() + 6); + if (status != StatusCode::SUCCESS) + { + qCWarning(card) << "PACE failed. Status code:" << status; + } - int lengthCardAccess = parseUSHORT(pControlOutput, it); - it += 2; - - mEfCardAccess = (pControlOutput.mid(it, lengthCardAccess)); - it += lengthCardAccess; + int it = 8; + mEfCardAccess = readByteArray(pControlOutput, it); if (it >= pControlOutput.size()) { @@ -296,26 +304,64 @@ void EstablishPACEChannelOutput::parse(const QByteArray& pControlOutput, PACE_PI return; } - int length_CARcurr = pControlOutput.at(it); - ++it; - mCarCurr = (pControlOutput.mid(it, length_CARcurr)); - it += length_CARcurr; - qCDebug(card) << "mCarCurr" << mCarCurr; - - int length_CARprev = pControlOutput.at(it); - ++it; - mCarPrev = (pControlOutput.mid(it, length_CARprev)); - it += length_CARprev; - qCDebug(card) << "mCarPrev" << mCarPrev; - - int length_IDicc = parseUSHORT(pControlOutput, it); - it += 2; - mIdIcc = (pControlOutput.mid(it, length_IDicc)); + mCarCurr = readByteArray(pControlOutput, it); + qCDebug(card) << "mCarCurr:" << mCarCurr; + mCarPrev = readByteArray(pControlOutput, it); + qCDebug(card) << "mCarPrev:" << mCarPrev; + mIdIcc = readByteArray(pControlOutput, it); + qCDebug(card) << "mIdIcc:" << mIdIcc.toHex(); } -void EstablishPACEChannelOutput::parseFromCcid(const QByteArray& pOutput, PACE_PIN_ID pPinId) +QByteArray EstablishPACEChannelOutput::toCcid() const { + auto establishPaceChannelOutput = newObject(); + + QByteArray paceReturnCodeBytes; + QDataStream(&paceReturnCodeBytes, QIODevice::WriteOnly) << Enum::getValue(generateReturnCode(mPaceReturnCode)); + establishPaceChannelOutput->mErrorCode = ASN1_OCTET_STRING_new(); + Asn1OctetStringUtil::setValue(paceReturnCodeBytes, establishPaceChannelOutput->mErrorCode); + + establishPaceChannelOutput->mStatusMSESetAt = ASN1_OCTET_STRING_new(); + if (mStatusMseSetAt.isEmpty()) + { + qCWarning(card) << "mStatusMseSetAt is empty! Using 0000 as dummy..."; + Asn1OctetStringUtil::setValue(QByteArray::fromHex(QByteArrayLiteral("0000")), establishPaceChannelOutput->mStatusMSESetAt); + } + else + { + Asn1OctetStringUtil::setValue(mStatusMseSetAt, establishPaceChannelOutput->mStatusMSESetAt); + } + + const uchar* unsignedCharPointer = reinterpret_cast(mEfCardAccess.constData()); + decodeAsn1Object(&establishPaceChannelOutput->mEfCardAccess, &unsignedCharPointer, mEfCardAccess.size()); + + establishPaceChannelOutput->mIdPICC = ASN1_OCTET_STRING_new(); + Asn1OctetStringUtil::setValue(mIdIcc, establishPaceChannelOutput->mIdPICC); + establishPaceChannelOutput->mCurCAR = ASN1_OCTET_STRING_new(); + Asn1OctetStringUtil::setValue(mCarCurr, establishPaceChannelOutput->mCurCAR); + establishPaceChannelOutput->mPrevCAR = ASN1_OCTET_STRING_new(); + Asn1OctetStringUtil::setValue(mCarPrev, establishPaceChannelOutput->mPrevCAR); + + QByteArray ccidOutput = encodeObject(establishPaceChannelOutput.data()); + + QByteArray ccidErrorCode; + QDataStream(&ccidErrorCode, QIODevice::WriteOnly) << Enum::getValue(StatusCode::SUCCESS); + ccidOutput += ccidErrorCode; + + return ccidOutput; +} + + +void EstablishPACEChannelOutput::parseFromCcid(const QByteArray& pOutput, PACE_PASSWORD_ID pPasswordId) +{ + mPaceReturnCode = CardReturnCode::UNKNOWN; + mEfCardAccess.clear(); + mCarCurr.clear(); + mCarPrev.clear(); + mIdIcc.clear(); + mStatusMseSetAt.clear(); + if (pOutput.size() < 2) { qCCritical(card) << "EstablishPACEChannelOutput too short"; @@ -338,11 +384,11 @@ void EstablishPACEChannelOutput::parseFromCcid(const QByteArray& pOutput, PACE_P if (match.hasMatch()) { qCWarning(card) << "Determine at least PACE return code by regular expression"; - QByteArray paceReturnCodeBytes = QByteArray::fromHex(match.captured("a1").toUtf8()); + QByteArray paceReturnCodeBytes = QByteArray::fromHex(match.captured(QStringLiteral("a1")).toUtf8()); quint32 paceReturnCode; QDataStream(paceReturnCodeBytes) >> paceReturnCode; - mPaceReturnCode = parseReturnCode(paceReturnCode, pPinId); - qCDebug(card) << "mPaceReturnCode: " << mPaceReturnCode << paceReturnCodeBytes.toHex(); + mPaceReturnCode = parseReturnCode(paceReturnCode, pPasswordId); + qCDebug(card) << "mPaceReturnCode:" << mPaceReturnCode << paceReturnCodeBytes.toHex(); } return; } @@ -350,63 +396,72 @@ void EstablishPACEChannelOutput::parseFromCcid(const QByteArray& pOutput, PACE_P QByteArray paceReturnCodeBytes = Asn1OctetStringUtil::getValue(channelOutput->mErrorCode); quint32 paceReturnCode; QDataStream(paceReturnCodeBytes) >> paceReturnCode; - mPaceReturnCode = parseReturnCode(paceReturnCode, pPinId); - qDebug() << "mPaceReturnCode: " << mPaceReturnCode << paceReturnCodeBytes.toHex(); + mPaceReturnCode = parseReturnCode(paceReturnCode, pPasswordId); + qDebug() << "mPaceReturnCode:" << mPaceReturnCode << paceReturnCodeBytes.toHex(); - auto statusMseSetAT = Asn1OctetStringUtil::getValue(channelOutput->mStatusMSESetAt); - qDebug() << "statusMSESetAT: " << statusMseSetAT.toHex(); + if (channelOutput->mStatusMSESetAt) + { + mStatusMseSetAt = Asn1OctetStringUtil::getValue(channelOutput->mStatusMSESetAt); + qDebug() << "mStatusMseSetAt:" << mStatusMseSetAt.toHex(); + } - mEfCardAccess = encodeObject(channelOutput->mEfCardAccess); - qDebug() << "mEfCardAccess" << mEfCardAccess.toHex(); + if (channelOutput->mEfCardAccess) + { + mEfCardAccess = encodeObject(channelOutput->mEfCardAccess); + qDebug() << "mEfCardAccess:" << mEfCardAccess.toHex(); + } if (channelOutput->mIdPICC != nullptr) { mIdIcc = Asn1OctetStringUtil::getValue(channelOutput->mIdPICC); - qDebug() << "idicc: " << mIdIcc.toHex(); + qDebug() << "mIdIcc:" << mIdIcc.toHex(); } if (channelOutput->mCurCAR != nullptr) { mCarCurr = Asn1OctetStringUtil::getValue(channelOutput->mCurCAR); - qDebug() << "mCarCurr" << mCarCurr; + qDebug() << "mCarCurr:" << mCarCurr; } if (channelOutput->mPrevCAR != nullptr) { mCarPrev = Asn1OctetStringUtil::getValue(channelOutput->mPrevCAR); - qDebug() << "mCarPrev" << mCarPrev; + qDebug() << "mCarPrev:" << mCarPrev; } } -CardReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId) +CardReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCode, PACE_PASSWORD_ID pPasswordId) { // error codes from the reader - switch (pPaceReturnCode) + switch (EstablishPACEChannelErrorCode(pPaceReturnCode)) { - case 0: + case EstablishPACEChannelErrorCode::NoError: // no error return CardReturnCode::OK; - case 0xd0000001: // Inconsistent lengths in input - case 0xd0000002: // Unexpected data in input - case 0xd0000003: // Unexpected combination of data in input - case 0xe0000001: // Syntax error in TLV response - case 0xe0000002: // Unexpected or missing object in TLV response - case 0xe0000003: // Unknown PIN-ID - case 0xe0000006: // Wrong Authentication Token + case EstablishPACEChannelErrorCode::InconsistentLengthsInInput: + case EstablishPACEChannelErrorCode::UnexpectedDataInInput: + case EstablishPACEChannelErrorCode::UnexpectedCombinationOfDataInInput: + case EstablishPACEChannelErrorCode::SyntaxErrorInTLVResponse: + case EstablishPACEChannelErrorCode::UnexpectedOrMissingObjectInTLVResponse: + case EstablishPACEChannelErrorCode::UnknownPasswordID: + case EstablishPACEChannelErrorCode::WrongAuthenticationToken: return CardReturnCode::COMMAND_FAILED; // 0xf00663c2 -- invalid PIN? - case 0xf0100001: // Communication abort (e.g. card removed during protocol) - case 0xf0100002: // No card + case EstablishPACEChannelErrorCode::CommunicationAbort: + case EstablishPACEChannelErrorCode::NoCard: return CardReturnCode::COMMAND_FAILED; - case 0xf0200001: // Abort + case EstablishPACEChannelErrorCode::Abort: return CardReturnCode::CANCELLATION_BY_USER; - case 0xf0200002: // Timeout + case EstablishPACEChannelErrorCode::Timeout: return CardReturnCode::INPUT_TIME_OUT; + + default: + break; } // Error codes wrapping error codes from the card. The format is 0xXXXXYYZZ, where XXXX identifies @@ -426,17 +481,17 @@ CardReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCo { // SW1 == 0x63 is a warning, which includes incorrectly entered CAN/PIN. For the PIN // we get SW2 == 0xcX, with X being the number of remaining retries. - switch (pPinId) + switch (pPasswordId) { - case PACE_PIN_ID::PACE_MRZ: + case PACE_PASSWORD_ID::PACE_MRZ: // No separate error code (yet). - case PACE_PIN_ID::PACE_CAN: + case PACE_PASSWORD_ID::PACE_CAN: return CardReturnCode::INVALID_CAN; - case PACE_PIN_ID::PACE_PIN: + case PACE_PASSWORD_ID::PACE_PIN: return CardReturnCode::INVALID_PIN; - case PACE_PIN_ID::PACE_PUK: + case PACE_PASSWORD_ID::PACE_PUK: return CardReturnCode::INVALID_PUK; } } @@ -445,3 +500,45 @@ CardReturnCode EstablishPACEChannelOutput::parseReturnCode(quint32 pPaceReturnCo return CardReturnCode::UNKNOWN; } + + +EstablishPACEChannelErrorCode EstablishPACEChannelOutput::generateReturnCode(CardReturnCode pReturnCode) +{ + switch (pReturnCode) + { + case CardReturnCode::UNKNOWN: + case CardReturnCode::UNDEFINED: + case CardReturnCode::NEW_PIN_MISMATCH: + case CardReturnCode::NEW_PIN_INVALID_LENGTH: + case CardReturnCode::PIN_BLOCKED: + case CardReturnCode::PIN_NOT_BLOCKED: + case CardReturnCode::PUK_INOPERATIVE: + case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: + case CardReturnCode::PROTOCOL_ERROR: + return EstablishPACEChannelErrorCode::UnexpectedDataInInput; + + case CardReturnCode::INVALID_CAN: + case CardReturnCode::INVALID_PIN: + case CardReturnCode::INVALID_PUK: + return EstablishPACEChannelErrorCode::GeneralAuthenticateStep1_4_Warning; + + case CardReturnCode::OK: + return EstablishPACEChannelErrorCode::NoError; + + case CardReturnCode::CARD_NOT_FOUND: + return EstablishPACEChannelErrorCode::NoCard; + + case CardReturnCode::INPUT_TIME_OUT: + return EstablishPACEChannelErrorCode::Timeout; + + + case CardReturnCode::COMMAND_FAILED: + return EstablishPACEChannelErrorCode::CommunicationAbort; + + case CardReturnCode::CANCELLATION_BY_USER: + return EstablishPACEChannelErrorCode::Abort; + } + + Q_UNREACHABLE(); + return EstablishPACEChannelErrorCode::UnexpectedDataInInput; +} diff --git a/src/card/base/EstablishPACEChannel.h b/src/card/base/EstablishPACEChannel.h index c6355e9..95d0403 100644 --- a/src/card/base/EstablishPACEChannel.h +++ b/src/card/base/EstablishPACEChannel.h @@ -1,7 +1,7 @@ /*! * \brief Data object for output of card command EstablishPACEChannel * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -11,6 +11,7 @@ #include "asn1/SecurityInfos.h" #include "Apdu.h" #include "CardReturnCode.h" +#include "pace/EstablishPACEChannelCode.h" #include "SmartCardDefinitions.h" #include @@ -46,7 +47,7 @@ DECLARE_ASN1_OBJECT(ESTABLISHPACECHANNELINPUT) class EstablishPACEChannelBuilder { private: - PACE_PIN_ID mPinId; + PACE_PASSWORD_ID mPasswordId; QByteArray mChat; QByteArray mCertificateDescription; @@ -65,7 +66,7 @@ class EstablishPACEChannelBuilder void setCertificateDescription(const QByteArray& pCertificateDescription); void setChat(const QByteArray& pChat); - void setPinId(PACE_PIN_ID pPinId); + void setPasswordId(PACE_PASSWORD_ID pPasswordId); }; @@ -102,11 +103,7 @@ class EstablishPACEChannelOutput QByteArray mCarCurr; QByteArray mCarPrev; QByteArray mIdIcc; - - - static int parseUSHORT(const QByteArray& pData, int pOffset); - - static QByteArray reverse(const QByteArray& pArrayToReverse); + QByteArray mStatusMseSetAt; public: EstablishPACEChannelOutput(); @@ -114,12 +111,13 @@ class EstablishPACEChannelOutput /** * Defined in pcsc10_v2.02.08_amd1.1 */ - void parse(const QByteArray& pControlOutput, PACE_PIN_ID pPinId); + void parse(const QByteArray& pControlOutput, PACE_PASSWORD_ID pPasswordId); /** * Defined in TR-03119 */ - void parseFromCcid(const QByteArray& pOutput, PACE_PIN_ID pPinId); + QByteArray toCcid() const; + void parseFromCcid(const QByteArray& pOutput, PACE_PASSWORD_ID pPasswordId); CardReturnCode getPaceReturnCode() const; void setPaceReturnCode(CardReturnCode); @@ -136,7 +134,11 @@ class EstablishPACEChannelOutput QByteArray getCARprev() const; void setCarPrev(const QByteArray&); - static CardReturnCode parseReturnCode(quint32 pPaceReturnCode, PACE_PIN_ID pPinId); + QByteArray getMseStatusSetAt() const; + void setStatusMseSetAt(const QByteArray& pStatusMseSetAt); + + static CardReturnCode parseReturnCode(quint32 pPaceReturnCode, PACE_PASSWORD_ID pPasswordId); + static EstablishPACEChannelErrorCode generateReturnCode(CardReturnCode pReturnCode); }; diff --git a/src/card/base/EstablishPACEChannelParser.cpp b/src/card/base/EstablishPACEChannelParser.cpp new file mode 100644 index 0000000..7f2871a --- /dev/null +++ b/src/card/base/EstablishPACEChannelParser.cpp @@ -0,0 +1,121 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "EstablishPACEChannelParser.h" + +#include "asn1/ASN1TemplateUtil.h" +#include "Apdu.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(card) + + +using namespace governikus; + + +EstablishPACEChannelParser::EstablishPACEChannelParser(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, const QByteArray& pCommandData) + : mPasswordId(pPasswordId) + , mChat(pChat) + , mCertificateDescription(pCertificateDescription) + , mCommandData(pCommandData) +{ + +} + + +EstablishPACEChannelParser EstablishPACEChannelParser::fromCcid(const QByteArray& pInput) +{ + CommandApdu command(pInput); + + if (command.getCLA() != char(0xFF) + || command.getINS() != char(0x9A) + || command.getP1() != 0x04 + || command.getP2() != 0x02) + { + qCDebug(card) << "Decapsulation of command failed. Unexpected header."; + return EstablishPACEChannelParser(); + } + + QByteArray commandData = command.getData(); + auto channelInput = decodeObject(commandData); + + Q_ASSERT(channelInput); + if (!channelInput) + { + qCDebug(card) << "Decapsulation of command failed. Bad command data."; + return EstablishPACEChannelParser(); + } + + PACE_PASSWORD_ID passwordId = PACE_PASSWORD_ID::PACE_PIN; + Q_ASSERT(channelInput->mPasswordID); + if (channelInput->mPasswordID) + { + char asn1_char = static_cast(ASN1_INTEGER_get(channelInput->mPasswordID)); + if (Enum::isValue(asn1_char)) + { + passwordId = PACE_PASSWORD_ID(asn1_char); + } + else + { + qCDebug(card) << "Decapsulation: Bad PIN ID!"; + Q_ASSERT(false); + } + } + else + { + qCDebug(card) << "Decapsulation: No PIN ID!"; + Q_ASSERT(false); + } + + // With CAN and PUK mode there is no certificate description. + QByteArray certificateDescription; + Q_ASSERT(passwordId != PACE_PASSWORD_ID::PACE_PIN || channelInput->mCertificateDescription); + if (channelInput->mCertificateDescription) + { + certificateDescription = channelInput->mCertificateDescription->encode(); + } + else if (passwordId == PACE_PASSWORD_ID::PACE_PIN) + { + qCDebug(card) << "Decapsulation: No certificate description!"; + } + + // With CAN and PUK mode there is no chat. + QByteArray chat; + Q_ASSERT(passwordId != PACE_PASSWORD_ID::PACE_PIN || channelInput->mCHAT); + if (channelInput->mCHAT) + { + chat = Asn1OctetStringUtil::getValue(channelInput->mCHAT); + } + else if (passwordId == PACE_PASSWORD_ID::PACE_PIN) + { + qCDebug(card) << "Decapsulation: No CHAT!"; + } + + return EstablishPACEChannelParser(passwordId, chat, certificateDescription, commandData); +} + + +PACE_PASSWORD_ID EstablishPACEChannelParser::getPasswordId() const +{ + return mPasswordId; +} + + +const QByteArray& EstablishPACEChannelParser::getChat() const +{ + return mChat; +} + + +const QByteArray& EstablishPACEChannelParser::getCertificateDescription() const +{ + return mCertificateDescription; +} + + +const QByteArray& EstablishPACEChannelParser::getCommandData() const +{ + return mCommandData; +} diff --git a/src/card/base/EstablishPACEChannelParser.h b/src/card/base/EstablishPACEChannelParser.h new file mode 100644 index 0000000..e09b15e --- /dev/null +++ b/src/card/base/EstablishPACEChannelParser.h @@ -0,0 +1,38 @@ +/*! + * \brief Parser to decapsulation EstablishPACEChannel + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EstablishPACEChannel.h" + + +namespace governikus +{ + +class EstablishPACEChannelParser +{ + private: + PACE_PASSWORD_ID mPasswordId; + QByteArray mChat; + QByteArray mCertificateDescription; + QByteArray mCommandData; + + EstablishPACEChannelParser(PACE_PASSWORD_ID pPasswordId = PACE_PASSWORD_ID::PACE_PIN, + const QByteArray& pChat = QByteArray(), + const QByteArray& pCertificateDescription = QByteArray(), + const QByteArray& pCommandData = QByteArray()); + + public: + static EstablishPACEChannelParser fromCcid(const QByteArray& pInput); + + PACE_PASSWORD_ID getPasswordId() const; + const QByteArray& getChat() const; + const QByteArray& getCertificateDescription() const; + const QByteArray& getCommandData() const; + +}; + +} diff --git a/src/card/base/ExtendedLengthApduSupportCode.cpp b/src/card/base/ExtendedLengthApduSupportCode.cpp deleted file mode 100644 index 3cde9c7..0000000 --- a/src/card/base/ExtendedLengthApduSupportCode.cpp +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * \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 deleted file mode 100644 index aa6422d..0000000 --- a/src/card/base/ExtendedLengthApduSupportCode.h +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * 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 421761e..a4524dc 100644 --- a/src/card/base/FileRef.cpp +++ b/src/card/base/FileRef.cpp @@ -1,7 +1,5 @@ /*! - * FileRef.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Commands.h" diff --git a/src/card/base/FileRef.h b/src/card/base/FileRef.h index 73c05fd..c58a31b 100644 --- a/src/card/base/FileRef.h +++ b/src/card/base/FileRef.h @@ -1,7 +1,7 @@ /*! * \brief Reference information for files on smart cards. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/GeneralAuthenticateResponse.cpp b/src/card/base/GeneralAuthenticateResponse.cpp index b13f62e..421eb46 100644 --- a/src/card/base/GeneralAuthenticateResponse.cpp +++ b/src/card/base/GeneralAuthenticateResponse.cpp @@ -1,7 +1,5 @@ /*! - * GeneralAuthenticateResponse.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/src/card/base/GeneralAuthenticateResponse.h b/src/card/base/GeneralAuthenticateResponse.h index 3b64d7a..2c5c539 100644 --- a/src/card/base/GeneralAuthenticateResponse.h +++ b/src/card/base/GeneralAuthenticateResponse.h @@ -1,9 +1,7 @@ /*! - * GeneralAuthenticateResponse.h - * * \brief Implementation of GeneralAuthenticate response APDUs. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -24,7 +22,7 @@ class GAResponseApdu public: GAResponseApdu(); - virtual ~GAResponseApdu(); + virtual ~GAResponseApdu() override; virtual void setBuffer(const QByteArray& pBuffer) override; }; @@ -52,7 +50,7 @@ class GAEncryptedNonceResponse public: GAEncryptedNonceResponse(); - virtual ~GAEncryptedNonceResponse(); + virtual ~GAEncryptedNonceResponse() override; const QByteArray& getEncryptedNonce(); }; @@ -80,7 +78,7 @@ class GAMapNonceResponse public: GAMapNonceResponse(); - virtual ~GAMapNonceResponse(); + virtual ~GAMapNonceResponse() override; const QByteArray& getMappingData(); }; @@ -108,7 +106,7 @@ class GAPerformKeyAgreementResponse public: GAPerformKeyAgreementResponse(); - virtual ~GAPerformKeyAgreementResponse(); + virtual ~GAPerformKeyAgreementResponse() override; const QByteArray& getEphemeralPublicKey(); }; @@ -140,7 +138,7 @@ class GAMutualAuthenticationResponse public: GAMutualAuthenticationResponse(); - virtual ~GAMutualAuthenticationResponse(); + virtual ~GAMutualAuthenticationResponse() override; const QByteArray& getAuthenticationToken(); const QByteArray& getCarCurr(); const QByteArray& getCarPrev(); @@ -172,7 +170,7 @@ class GAChipAuthenticationResponse public: GAChipAuthenticationResponse(); - virtual ~GAChipAuthenticationResponse(); + virtual ~GAChipAuthenticationResponse() override; const QByteArray& getNonce(); const QByteArray& getAuthenticationToken(); diff --git a/src/card/base/InputAPDUInfo.cpp b/src/card/base/InputAPDUInfo.cpp index 81009d6..bb3c366 100644 --- a/src/card/base/InputAPDUInfo.cpp +++ b/src/card/base/InputAPDUInfo.cpp @@ -1,7 +1,5 @@ /*! - * InputAPDUInfo.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "InputAPDUInfo.h" @@ -11,18 +9,14 @@ using namespace governikus; InputAPDUInfo::InputAPDUInfo() : mInputApdu() , mAcceptableStatusCodes() + , mUpdateRetryCounter(false) { } -InputAPDUInfo::InputAPDUInfo(const QByteArray& pInputApdu, const QByteArrayList& pAcceptableStatusCodes) +InputAPDUInfo::InputAPDUInfo(const QByteArray& pInputApdu, bool pUpdateRetryCounter) : mInputApdu(pInputApdu) - , mAcceptableStatusCodes(pAcceptableStatusCodes) + , mAcceptableStatusCodes() + , mUpdateRetryCounter(pUpdateRetryCounter) { } - - -bool InputAPDUInfo::isValid() const -{ - return !mInputApdu.isEmpty(); -} diff --git a/src/card/base/InputAPDUInfo.h b/src/card/base/InputAPDUInfo.h index 354b259..9ab862a 100644 --- a/src/card/base/InputAPDUInfo.h +++ b/src/card/base/InputAPDUInfo.h @@ -1,11 +1,11 @@ /*! - * InputAPDUInfo.h - * * \brief Holds the data of an InputAPDUInfo element. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "Apdu.h" + #include #include @@ -18,13 +18,18 @@ class InputAPDUInfo { public: InputAPDUInfo(); - InputAPDUInfo(const QByteArray& pInputApdu, const QByteArrayList& pAcceptableStatusCodes); + InputAPDUInfo(const QByteArray& pInputApdu, bool pUpdateRetryCounter = false); - bool isValid() const; - const QByteArray& getInputApdu() const + bool isValid() const { - return mInputApdu; + return !mInputApdu.isEmpty(); + } + + + const CommandApdu getInputApdu() const + { + return CommandApdu(mInputApdu, mUpdateRetryCounter); } @@ -40,15 +45,19 @@ class InputAPDUInfo } - void addAcceptableStatusCode(const QByteArray& pStatusCode) + void addAcceptableStatusCode(const QByteArray& pStatusCodeAsHex) { - mAcceptableStatusCodes += pStatusCode; + mAcceptableStatusCodes += pStatusCodeAsHex; } private: QByteArray mInputApdu; QByteArrayList mAcceptableStatusCodes; + // mUpdateRetryCounter is not part of the xml data. + // We use it internally to update the retry counter on a + // low level especially when we act as a remote card reader + bool mUpdateRetryCounter; }; } diff --git a/src/card/base/PersoSimWorkaround.h b/src/card/base/PersoSimWorkaround.h index 66b1618..1ae3b00 100644 --- a/src/card/base/PersoSimWorkaround.h +++ b/src/card/base/PersoSimWorkaround.h @@ -1,9 +1,7 @@ /*! - * PersoSim.h - * * \brief This class is only to mark it as a workaround for working with the PersoSim. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -33,10 +31,11 @@ class PersoSimWorkaround * * As soon as PersoSim is fixed in that point, we will remove the workaround. */ - static void sendingMseSetAt(const QSharedPointer& pCardConnectionWorker) + static CardReturnCode sendingMseSetAt(const QSharedPointer& pCardConnectionWorker) { ResponseApdu response; - pCardConnectionWorker->transmit(SelectBuilder(FileRef::efCardAccess()).build(), response); + const CardReturnCode returnCode = pCardConnectionWorker->transmit(SelectBuilder(FileRef::efCardAccess()).build(), response); + return (returnCode == CardReturnCode::COMMAND_FAILED && response.getReturnCode() != StatusCode::EMPTY) ? CardReturnCode::OK : returnCode; } @@ -46,11 +45,11 @@ class PersoSimWorkaround * * As soon as PersoSim is fixed in that point, we will remove the workaround. */ - static CardReturnCode parsingEstablishPACEChannelOutput(const QByteArray& pControlOutput, PACE_PIN_ID pPinId) + static CardReturnCode parsingEstablishPACEChannelOutput(const QByteArray& pControlOutput, PACE_PASSWORD_ID pPasswordId) { quint32 paceReturnCode; QDataStream(pControlOutput.mid(0, 4)) >> paceReturnCode; - return EstablishPACEChannelOutput::parseReturnCode(paceReturnCode, pPinId); + return EstablishPACEChannelOutput::parseReturnCode(paceReturnCode, pPasswordId); } diff --git a/src/card/base/Reader.cpp b/src/card/base/Reader.cpp index 43c00be..f80c02a 100644 --- a/src/card/base/Reader.cpp +++ b/src/card/base/Reader.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ @@ -18,11 +18,10 @@ Q_DECLARE_LOGGING_CATEGORY(card) Q_DECLARE_LOGGING_CATEGORY(support) -Reader::Reader(ReaderManagerPlugInType pPlugInType, const QString& pReaderName, ReaderType pType) +Reader::Reader(ReaderManagerPlugInType pPlugInType, const QString& pReaderName) : QObject() - , mReaderInfo(pPlugInType, pReaderName, pType) + , mReaderInfo(pReaderName, pPlugInType) , mTimerId(0) - , mUpdateRetryCounter(true) { } @@ -38,6 +37,18 @@ void Reader::setPukInoperative() } +void Reader::setRetryCounter(int pRetryCounter) +{ + if (mReaderInfo.getRetryCounter() != pRetryCounter) + { + qCInfo(support) << "retry counter updated:" << pRetryCounter << ", was:" << mReaderInfo.getRetryCounter(); + + mReaderInfo.mCardInfo.mRetryCounter = pRetryCounter; + Q_EMIT fireCardRetryCounterChanged(mReaderInfo.getName()); + } +} + + QSharedPointer Reader::createCardConnectionWorker() { Card* currentCard = getCard(); @@ -76,22 +87,6 @@ void Reader::update() { CardEvent cardEvent = updateCard(); fireUpdateSignal(cardEvent); - updateRetryCounterIfNecessary(); -} - - -void Reader::updateRetryCounterIfNecessary() -{ - if (!mUpdateRetryCounter || mReaderInfo.getCardInfo().getCardType() != CardType::EID_CARD) - { - return; - } - - auto cardConnection = createCardConnectionWorker(); - if (cardConnection) - { - updateRetryCounter(cardConnection); - } } @@ -103,13 +98,13 @@ CardReturnCode Reader::updateRetryCounter(QSharedPointer p CardReturnCode returnCode = getRetryCounter(pCardConnectionWorker, newRetryCounter, newPinDeactivated); if (returnCode == CardReturnCode::OK) { - bool changed = (newRetryCounter != mReaderInfo.getRetryCounter()) || (newPinDeactivated != mReaderInfo.isPinDeactivated()); + bool emitSignal = mReaderInfo.isRetryCounterDetermined() && ((newRetryCounter != mReaderInfo.getRetryCounter()) || (newPinDeactivated != mReaderInfo.isPinDeactivated())); + qCInfo(support) << "retrieved retry counter:" << newRetryCounter << ", was:" << mReaderInfo.getRetryCounter() << ", PIN deactivated:" << newPinDeactivated; - mUpdateRetryCounter = false; mReaderInfo.mCardInfo.mRetryCounter = newRetryCounter; mReaderInfo.mCardInfo.mPinDeactivated = newPinDeactivated; - if (changed) + if (emitSignal) { qCDebug(card) << "fireCardRetryCounterChanged"; Q_EMIT fireCardRetryCounterChanged(mReaderInfo.getName()); @@ -132,16 +127,21 @@ CardReturnCode Reader::getRetryCounter(QSharedPointer pCar QByteArray cryptographicMechanismReference = paceInfo->getProtocolValueBytes(); QByteArray referencePrivateKey = paceInfo->getParameterId(); - PersoSimWorkaround::sendingMseSetAt(pCardConnectionWorker); + CardReturnCode returnCode = PersoSimWorkaround::sendingMseSetAt(pCardConnectionWorker); + if (returnCode != CardReturnCode::OK) + { + qCCritical(card) << "Error on MSE:Set AT"; + return returnCode; + } // MSE:Set AT MSEBuilder mseBuilder(MSEBuilder::P1::PERFORM_SECURITY_OPERATION, MSEBuilder::P2::SET_AT); mseBuilder.setOid(cryptographicMechanismReference); - mseBuilder.setPublicKey(PACE_PIN_ID::PACE_PIN); + mseBuilder.setPublicKey(PACE_PASSWORD_ID::PACE_PIN); mseBuilder.setPrivateKey(referencePrivateKey); ResponseApdu mseSetAtResponse; - CardReturnCode returnCode = pCardConnectionWorker->transmit(mseBuilder.build(), mseSetAtResponse); + returnCode = pCardConnectionWorker->transmit(mseBuilder.build(), mseSetAtResponse); if (returnCode != CardReturnCode::OK) { return returnCode; @@ -149,23 +149,7 @@ CardReturnCode Reader::getRetryCounter(QSharedPointer pCar StatusCode statusCode = mseSetAtResponse.getReturnCode(); qCDebug(card) << "StatusCode: " << statusCode; - if (statusCode == StatusCode::SUCCESS) - { - pRetryCounter = 3; - } - else if (statusCode == StatusCode::PIN_RETRY_COUNT_2) - { - pRetryCounter = 2; - } - else if (statusCode == StatusCode::PIN_SUSPENDED) - { - pRetryCounter = 1; - } - else if (statusCode == StatusCode::PIN_BLOCKED || statusCode == StatusCode::PIN_DEACTIVATED) - { - pRetryCounter = 0; - } - + pRetryCounter = mseSetAtResponse.getRetryCounter(); pPinDeactivated = statusCode == StatusCode::PIN_DEACTIVATED; return CardReturnCode::OK; @@ -180,7 +164,7 @@ void Reader::fireUpdateSignal(CardEvent pCardEvent) break; case CardEvent::CARD_INSERTED: - qCInfo(support) << "Card inserted of type" << mReaderInfo.getCardType(); + qCInfo(support) << "Card inserted:" << mReaderInfo.getCardInfo(); Q_EMIT fireCardInserted(mReaderInfo.getName()); break; @@ -192,12 +176,6 @@ void Reader::fireUpdateSignal(CardEvent pCardEvent) } -void Reader::onRetryCounterPotentiallyChanged() -{ - mUpdateRetryCounter = true; -} - - ConnectableReader::~ConnectableReader() { } diff --git a/src/card/base/Reader.h b/src/card/base/Reader.h index 8dda6a5..19d7b0c 100644 --- a/src/card/base/Reader.h +++ b/src/card/base/Reader.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -31,7 +31,6 @@ class Reader ReaderInfo mReaderInfo; int mTimerId; - bool mUpdateRetryCounter; void timerEvent(QTimerEvent* pEvent) override; @@ -43,15 +42,13 @@ class Reader private: virtual CardEvent updateCard() = 0; - void updateRetryCounterIfNecessary(); - CardReturnCode getRetryCounter(QSharedPointer pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated); void fireUpdateSignal(CardEvent pCardEvent); public: - Reader(ReaderManagerPlugInType pPlugInType, const QString& pReaderName, ReaderType pType); - virtual ~Reader(); + Reader(ReaderManagerPlugInType pPlugInType, const QString& pReaderName); + virtual ~Reader() override; const QString& getName() const { @@ -59,18 +56,15 @@ class Reader } - ReaderType getReaderType() const - { - return mReaderInfo.getReaderType(); - } - - const ReaderInfo& getReaderInfo() const { return mReaderInfo; } + void setRetryCounter(int pRetryCounter); + + virtual Card* getCard() const = 0; void setPukInoperative(); @@ -90,9 +84,6 @@ class Reader void fireReaderPropertiesUpdated(const QString& pReaderName); void fireReaderDeviceError(DeviceError pDeviceError); - public Q_SLOTS: - void onRetryCounterPotentiallyChanged(); - }; diff --git a/src/card/base/ReaderFilter.cpp b/src/card/base/ReaderFilter.cpp new file mode 100644 index 0000000..b25e2a2 --- /dev/null +++ b/src/card/base/ReaderFilter.cpp @@ -0,0 +1,77 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderFilter.h" + +#include "EnumHelper.h" +#include "ReaderConfiguration.h" +#include "ReaderManagerPlugIn.h" + +using namespace governikus; + +ReaderFilter::ReaderFilter() + : mFilterType(NoFilter) + , mPluginTypes() +{ + +} + + +ReaderFilter::ReaderFilter(const QVector& pPluginTypes) + : mFilterType(PluginTypeFilter) + , mPluginTypes(pPluginTypes) +{ + +} + + +ReaderFilter::ReaderFilter(const ReaderFilter::FilterType pFilterType) + : mFilterType(pFilterType) + , mPluginTypes() +{ + +} + + +QVector ReaderFilter::apply(const QVector& pPluginType) const +{ + if (mFilterType & PluginTypeFilter) + { + QVector filtered; + for (const auto& pluginType : pPluginType) + { + if (mPluginTypes.contains(pluginType->getInfo().getPlugInType())) + { + filtered += pluginType; + } + } + return filtered; + } + + return pPluginType; +} + + +QVector ReaderFilter::apply(const QVector& pInputList) const +{ + if (mFilterType & UniqueReaderTypes) + { + QVector filtered; + QVector alreadyContained; + for (const auto& readerInfo : pInputList) + { + const ReaderConfigurationInfo configurationInfo = readerInfo.getReaderConfigurationInfo(); + if (alreadyContained.contains(configurationInfo)) + { + continue; + } + + filtered += readerInfo; + alreadyContained += configurationInfo; + } + return filtered; + } + + return pInputList; +} diff --git a/src/card/base/ReaderFilter.h b/src/card/base/ReaderFilter.h new file mode 100644 index 0000000..102cca8 --- /dev/null +++ b/src/card/base/ReaderFilter.h @@ -0,0 +1,47 @@ +/*! + * \brief A configured filter used to retrieve readers + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ReaderInfo.h" +#include "ReaderManagerPlugInInfo.h" + +#include +#include + +namespace governikus +{ + +class ReaderManagerPlugIn; + +class ReaderFilter +{ + public: + enum FilterType + { + NoFilter = 0, + PluginTypeFilter = 1, + UniqueReaderTypes = 2 + }; + Q_DECLARE_FLAGS(FilterTypes, FilterType) + + private: + ReaderFilter::FilterTypes mFilterType; + const QVector mPluginTypes; + + public: + ReaderFilter(); + ReaderFilter(const QVector& pPluginTypes); + ReaderFilter(const ReaderFilter::FilterType pFilterType); + + QVector apply(const QVector& pPluginType) const; + QVector apply(const QVector& pInputList) const; +}; + + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(governikus::ReaderFilter::FilterTypes) diff --git a/src/card/base/ReaderInfo.cpp b/src/card/base/ReaderInfo.cpp index dae4571..9e1baae 100644 --- a/src/card/base/ReaderInfo.cpp +++ b/src/card/base/ReaderInfo.cpp @@ -1,22 +1,28 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderInfo.h" +#include "Env.h" +#include "Initializer.h" +#include "ReaderDetector.h" + using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType("ReaderInfo"); + }); -ReaderInfo::ReaderInfo(ReaderManagerPlugInType pPlugInType, - const QString& pName, - ReaderType pReaderType, +ReaderInfo::ReaderInfo(const QString& pName, + ReaderManagerPlugInType pPlugInType, const CardInfo& pCardInfo) : mPlugInType(pPlugInType) , mName(pName) - , mReaderType(pReaderType) + , mReaderConfigurationInfo(Env::getSingleton()->getReaderConfigurationInfo(pName)) , mBasicReader(true) , mCardInfo(pCardInfo) , mConnected(false) - , mExtendedLengthApduSupportCode(pPlugInType == ReaderManagerPlugInType::NFC ? ExtendedLengthApduSupportCode::UNKNOWN : ExtendedLengthApduSupportCode::SUPPORTED) + , mMaxApduLength(pPlugInType == ReaderManagerPlugInType::NFC ? 0 : 500) { } diff --git a/src/card/base/ReaderInfo.h b/src/card/base/ReaderInfo.h index 357a480..3fe3dd1 100644 --- a/src/card/base/ReaderInfo.h +++ b/src/card/base/ReaderInfo.h @@ -1,12 +1,12 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "CardInfo.h" #include "EnumHelper.h" -#include "MetaTypeHelper.h" +#include "ReaderConfigurationInfo.h" #include "ReaderManagerPlugInInfo.h" #include "SmartCardDefinitions.h" @@ -14,35 +14,23 @@ namespace governikus { - -defineEnumType(ExtendedLengthApduSupportCode, - UNKNOWN = -1, - NOT_SUPPORTED = 0, - SUPPORTED = 1) - class ReaderInfo { friend class Reader; ReaderManagerPlugInType mPlugInType; QString mName; - ReaderType mReaderType; + ReaderConfigurationInfo mReaderConfigurationInfo; bool mBasicReader; CardInfo mCardInfo; bool mConnected; - ExtendedLengthApduSupportCode mExtendedLengthApduSupportCode; + int mMaxApduLength; public: - ReaderInfo(ReaderManagerPlugInType pPlugInType = ReaderManagerPlugInType::UNKNOWN, - const QString& pName = QString(), - ReaderType pReaderType = ReaderType::UNKNOWN, + ReaderInfo(const QString& pName = QString(), + ReaderManagerPlugInType pPlugInType = ReaderManagerPlugInType::UNKNOWN, const CardInfo& pCardInfo = CardInfo(CardType::NONE)); - bool isValid() const - { - return !mName.isNull(); - } - ReaderManagerPlugInType getPlugInType() const { @@ -50,15 +38,33 @@ class ReaderInfo } + const ReaderConfigurationInfo& getReaderConfigurationInfo() const + { + return mReaderConfigurationInfo; + } + + const CardInfo& getCardInfo() const { return mCardInfo; } - CardType getCardType() const + QString getCardTypeString() const { - return mCardInfo.getCardType(); + return mCardInfo.getCardTypeString(); + } + + + bool hasCard() const + { + return mCardInfo.isAvailable(); + } + + + bool hasEidCard() const + { + return mCardInfo.isEid(); } @@ -68,6 +74,12 @@ class ReaderInfo } + bool isRetryCounterDetermined() const + { + return mCardInfo.isRetryCounterDetermined(); + } + + bool isPinDeactivated() const { return mCardInfo.isPinDeactivated(); @@ -92,12 +104,6 @@ class ReaderInfo } - ReaderType getReaderType() const - { - return mReaderType; - } - - void setBasicReader(bool pIsBasicReader) { mBasicReader = pIsBasicReader; @@ -122,20 +128,24 @@ class ReaderInfo } - void setExtendedLengthApduSupportCode(ExtendedLengthApduSupportCode pExtendedLengthApduSupportCode) + void setMaxApduLength(int pMaxApduLength) { - mExtendedLengthApduSupportCode = pExtendedLengthApduSupportCode; + mMaxApduLength = pMaxApduLength; } - ExtendedLengthApduSupportCode getExtendedLengthApduSupportCode() const + int getMaxApduLength() const { - return mExtendedLengthApduSupportCode; + return mMaxApduLength; + } + + + bool sufficientApduLength() const + { + return mMaxApduLength == 0 || mMaxApduLength >= 500; } }; } /* namespace governikus */ - -REGISTER_META_TYPE(ReaderInfo) diff --git a/src/card/base/ReaderManager.cpp b/src/card/base/ReaderManager.cpp index 060e48d..db90627 100644 --- a/src/card/base/ReaderManager.cpp +++ b/src/card/base/ReaderManager.cpp @@ -1,7 +1,5 @@ /*! - * ReaderManager.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderManager.h" @@ -22,6 +20,7 @@ ReaderManager::ReaderManager() : QObject() , mThread() , mWorker() + , mRemoteClient() { mThread.setObjectName(QStringLiteral("ReaderManagerThread")); } @@ -43,7 +42,7 @@ ReaderManager& ReaderManager::getInstance() } -void ReaderManager::init() +void ReaderManager::init(const QSharedPointer& pRemoteClient) { if (mThread.isRunning()) { @@ -53,27 +52,29 @@ void ReaderManager::init() if (mWorker.isNull()) { - mWorker = new ReaderManagerWorker(); + mRemoteClient = pRemoteClient; + mWorker = new ReaderManagerWorker(pRemoteClient); mWorker->moveToThread(&mThread); 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::firePluginAdded, this, &ReaderManager::firePluginAdded); connect(mWorker.data(), &ReaderManagerWorker::fireStatusChanged, this, &ReaderManager::fireStatusChanged); + connect(mWorker.data(), &ReaderManagerWorker::fireReaderAdded, this, &ReaderManager::fireReaderAdded); + connect(mWorker.data(), &ReaderManagerWorker::fireReaderRemoved, this, &ReaderManager::fireReaderRemoved); + connect(mWorker.data(), &ReaderManagerWorker::fireReaderDeviceError, this, &ReaderManager::fireReaderDeviceError); + connect(mWorker.data(), &ReaderManagerWorker::fireReaderPropertiesUpdated, this, &ReaderManager::fireReaderPropertiesUpdated); connect(mWorker.data(), &ReaderManagerWorker::fireCardInserted, this, &ReaderManager::fireCardInserted); connect(mWorker.data(), &ReaderManagerWorker::fireCardRemoved, this, &ReaderManager::fireCardRemoved); 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); connect(this, &ReaderManager::fireReaderAdded, this, &ReaderManager::fireReaderEvent); connect(this, &ReaderManager::fireReaderRemoved, this, &ReaderManager::fireReaderEvent); connect(this, &ReaderManager::fireCardInserted, this, &ReaderManager::fireReaderEvent); connect(this, &ReaderManager::fireCardRemoved, this, &ReaderManager::fireReaderEvent); + connect(this, &ReaderManager::fireReaderPropertiesUpdated, this, &ReaderManager::fireReaderEvent); } mThread.start(); @@ -87,12 +88,13 @@ void ReaderManager::shutdown() qCDebug(card) << "Shutdown ReaderManager..."; mThread.requestInterruption(); // do not try to stop AGAIN from dtor mThread.quit(); - qCDebug(card) << "Stopping..." << mThread.wait(2500); + mThread.wait(2500); + qCDebug(card) << "Stopping..." << mThread.isRunning(); } } -void ReaderManager::startScan() +void ReaderManager::startScan(ReaderManagerPlugInType pType) { if (!mThread.isRunning()) { @@ -100,11 +102,20 @@ void ReaderManager::startScan() return; } - QMetaObject::invokeMethod(mWorker.data(), "startScan", Qt::QueuedConnection); + QMetaObject::invokeMethod(mWorker.data(), "startScan", Qt::QueuedConnection, Q_ARG(ReaderManagerPlugInType, pType)); } -void ReaderManager::stopScan() +void ReaderManager::startScanAll() +{ + for (const auto& plugInType : Enum::getList()) + { + startScan(plugInType); + } +} + + +void ReaderManager::stopScan(ReaderManagerPlugInType pType) { if (!mThread.isRunning()) { @@ -112,7 +123,16 @@ void ReaderManager::stopScan() return; } - QMetaObject::invokeMethod(mWorker.data(), "stopScan", Qt::QueuedConnection); + QMetaObject::invokeMethod(mWorker.data(), "stopScan", Qt::QueuedConnection, Q_ARG(ReaderManagerPlugInType, pType)); +} + + +void ReaderManager::stopScanAll() +{ + for (const auto& plugInType : Enum::getList()) + { + stopScan(plugInType); + } } @@ -130,17 +150,17 @@ QVector ReaderManager::getReaderInfos(ReaderManagerPlugInType pType) } -QVector ReaderManager::getReaderInfos(const QVector& pTypes) const +QVector ReaderManager::getReaderInfos(const ReaderFilter& pFilter) const { QVector list; - QMetaObject::invokeMethod(mWorker.data(), "getReaderInfos", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, list), Q_ARG(const QVector &, pTypes)); + QMetaObject::invokeMethod(mWorker.data(), "getReaderInfos", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, list), Q_ARG(ReaderFilter, pFilter)); return list; } ReaderInfo ReaderManager::getReaderInfo(const QString& pReaderName) const { - ReaderInfo info; + ReaderInfo info(pReaderName); QMetaObject::invokeMethod(mWorker.data(), "getReaderInfo", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ReaderInfo, info), Q_ARG(QString, pReaderName)); return info; } @@ -162,3 +182,9 @@ void ReaderManager::disconnectAllReaders() { QMetaObject::invokeMethod(mWorker.data(), "disconnectAllReaders", Qt::QueuedConnection); } + + +QSharedPointer ReaderManager::getRemoteClient() +{ + return mRemoteClient; +} diff --git a/src/card/base/ReaderManager.h b/src/card/base/ReaderManager.h index c77c5f1..ce2bd78 100644 --- a/src/card/base/ReaderManager.h +++ b/src/card/base/ReaderManager.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -8,6 +8,7 @@ #include "DeviceError.h" #include "Reader.h" #include "ReaderManagerWorker.h" +#include "RemoteClient.h" #include #include @@ -23,6 +24,7 @@ class ReaderManager private: QThread mThread; QPointer mWorker; + QSharedPointer mRemoteClient; protected: ReaderManager(); @@ -35,23 +37,33 @@ class ReaderManager * Initialize the reader manager service. * The thread is started and the plug-ins are initialized, too. */ - void init(); + void init(const QSharedPointer& pRemoteClient = QSharedPointer()); + + /*! + * Starts a scan for all device types. + */ + void startScanAll(); /*! * Starts a scan for devices if registered plugin don't scan anytime. */ - void startScan(); + void startScan(ReaderManagerPlugInType pType); + + /*! + * Stops scan for all device types. + */ + void stopScanAll(); /*! * Stops started scan for devices. * Be aware that some plugins don't finish the whole scan if you * abort it with stopScan! */ - void stopScan(); + void stopScan(ReaderManagerPlugInType pType); QVector getPlugInInfos() const; QVector getReaderInfos(ReaderManagerPlugInType pType) const; - QVector getReaderInfos(const QVector& pTypes = Enum::getList()) const; + virtual QVector getReaderInfos(const ReaderFilter& pFilter = ReaderFilter()) const; ReaderInfo getReaderInfo(const QString& pReaderName) const; /*! @@ -83,12 +95,14 @@ class ReaderManager void disconnectReader(const QString& pReaderName); void disconnectAllReaders(); + QSharedPointer getRemoteClient(); + Q_SIGNALS: + void firePluginAdded(const ReaderManagerPlugInInfo& pInfo); 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 fireReaderDeviceError(DeviceError pDeviceError); void fireReaderPropertiesUpdated(const QString& pReaderName); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); diff --git a/src/card/base/ReaderManagerPlugIn.cpp b/src/card/base/ReaderManagerPlugIn.cpp index 87eb9ee..a114e2b 100644 --- a/src/card/base/ReaderManagerPlugIn.cpp +++ b/src/card/base/ReaderManagerPlugIn.cpp @@ -1,16 +1,44 @@ /*! - * ReaderManagerPlugIn.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderManagerPlugIn.h" using namespace governikus; + +void ReaderManagerPlugIn::onConnectToKnownReadersChanged() +{ +} + + ReaderManagerPlugIn::ReaderManagerPlugIn(ReaderManagerPlugInType pPlugInType, bool pAvailable, bool pPlugInEnabled) : mInfo(pPlugInType, pPlugInEnabled, pAvailable) + , mScanInProgress(false) + , mConnectToKnownReaders(false) { } + + +void ReaderManagerPlugIn::startScan() +{ + mScanInProgress = true; +} + + +void ReaderManagerPlugIn::stopScan() +{ + mScanInProgress = false; +} + + +void ReaderManagerPlugIn::setConnectToKnownReaders(bool pConnectToKnownReaders) +{ + if (mConnectToKnownReaders != pConnectToKnownReaders) + { + mConnectToKnownReaders = pConnectToKnownReaders; + onConnectToKnownReadersChanged(); + } +} diff --git a/src/card/base/ReaderManagerPlugIn.h b/src/card/base/ReaderManagerPlugIn.h index 8dbc262..d547877 100644 --- a/src/card/base/ReaderManagerPlugIn.h +++ b/src/card/base/ReaderManagerPlugIn.h @@ -1,16 +1,15 @@ /*! - * ReaderManagerPlugIn.h - * * \brief PlugIn to control different kinds of reader managers that will be used in \ref ReaderManager. * If you implement a class of this PlugIn you need to register it in \ref ReaderManager, otherwise it won't be used. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "DeviceError.h" #include "ReaderManagerPlugInInfo.h" +#include "RemoteDispatcher.h" #include #include @@ -19,6 +18,7 @@ namespace governikus { class Reader; +class RemoteClient; class ReaderManagerPlugIn : public QObject @@ -27,6 +27,11 @@ class ReaderManagerPlugIn ReaderManagerPlugInInfo mInfo; protected: + bool mScanInProgress; + bool mConnectToKnownReaders; + + virtual void onConnectToKnownReadersChanged(); + void setReaderInfoEnabled(bool pEnabled) { if (mInfo.isEnabled() != pEnabled) @@ -61,7 +66,7 @@ class ReaderManagerPlugIn } - virtual QList getReader() const = 0; + virtual QList getReaders() const = 0; virtual void init() @@ -75,22 +80,22 @@ class ReaderManagerPlugIn } - virtual void startScan() - { - } + virtual void startScan(); + virtual void stopScan(); + void setConnectToKnownReaders(bool pConnectToKnownReaders); - virtual void stopScan() + virtual void setRemoteClient(const QSharedPointer& pRemoteClient) { + Q_UNUSED(pRemoteClient); } 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 fireReaderDeviceError(DeviceError pDeviceError); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); void fireCardRetryCounterChanged(const QString& pReaderName); diff --git a/src/card/base/ReaderManagerPlugInInfo.cpp b/src/card/base/ReaderManagerPlugInInfo.cpp index af71a77..b3027b7 100644 --- a/src/card/base/ReaderManagerPlugInInfo.cpp +++ b/src/card/base/ReaderManagerPlugInInfo.cpp @@ -1,13 +1,18 @@ /*! - * ReaderManagerPlugInInfo.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderManagerPlugInInfo.h" +#include "Initializer.h" + using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType("ReaderManagerPlugInInfo"); + qRegisterMetaType("ReaderManagerPlugInType"); + }); + ReaderManagerPlugInInfo::ReaderManagerPlugInInfo(ReaderManagerPlugInType pType, bool pEnabled, bool pAvailable) : mType(pType) diff --git a/src/card/base/ReaderManagerPlugInInfo.h b/src/card/base/ReaderManagerPlugInInfo.h index 6a07f01..c5ba276 100644 --- a/src/card/base/ReaderManagerPlugInInfo.h +++ b/src/card/base/ReaderManagerPlugInInfo.h @@ -1,26 +1,22 @@ /*! - * ReaderManagerPlugInInfo.h - * * \brief Data object providing information about a reader manager plug-in. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "EnumHelper.h" -#include "MetaTypeHelper.h" #include #include #include - namespace governikus { -defineEnumType(ReaderManagerPlugInType, UNKNOWN, PCSC, BLUETOOTH, NFC) +defineEnumType(ReaderManagerPlugInType, UNKNOWN, PCSC, BLUETOOTH, NFC, REMOTE) class ReaderManagerPlugInInfo @@ -98,5 +94,3 @@ class ReaderManagerPlugInInfo }; } /* namespace governikus */ - -REGISTER_META_TYPE(ReaderManagerPlugInInfo) diff --git a/src/card/base/ReaderManagerWorker.cpp b/src/card/base/ReaderManagerWorker.cpp index f01db76..cd86060 100644 --- a/src/card/base/ReaderManagerWorker.cpp +++ b/src/card/base/ReaderManagerWorker.cpp @@ -1,10 +1,13 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "Reader.h" #include "ReaderManagerWorker.h" +#include "Initializer.h" +#include "Reader.h" +#include "RemoteClient.h" + #include #include #include @@ -13,10 +16,15 @@ Q_DECLARE_LOGGING_CATEGORY(card) using namespace governikus; -ReaderManagerWorker::ReaderManagerWorker() +static Initializer::Entry X([] { + qRegisterMetaType >("QSharedPointer"); + }); + + +ReaderManagerWorker::ReaderManagerWorker(const QSharedPointer& pRemoteClient) : QObject() + , mRemoteClient(pRemoteClient) , mPlugIns() - , mScanStarted(false) { } @@ -25,7 +33,7 @@ ReaderManagerWorker::~ReaderManagerWorker() { Q_ASSERT(thread() == QThread::currentThread()); - for (auto plugin : qAsConst(mPlugIns)) + for (auto& plugin : qAsConst(mPlugIns)) { qCDebug(card) << "Shutdown plugin:" << plugin->metaObject()->className(); plugin->shutdown(); @@ -62,6 +70,9 @@ void ReaderManagerWorker::registerPlugIns() { registerPlugIn(pluginInstance); pluginInstance->init(); + pluginInstance->setRemoteClient(mRemoteClient); + + Q_EMIT firePluginAdded(pluginInstance->getInfo()); } } } @@ -81,52 +92,45 @@ void ReaderManagerWorker::registerPlugIn(ReaderManagerPlugIn* pPlugIn) mPlugIns.push_back(pPlugIn); + connect(pPlugIn, &ReaderManagerPlugIn::fireReaderAdded, this, &ReaderManagerWorker::fireReaderAdded); + connect(pPlugIn, &ReaderManagerPlugIn::fireReaderRemoved, this, &ReaderManagerWorker::fireReaderRemoved); + connect(pPlugIn, &ReaderManagerPlugIn::fireReaderDeviceError, this, &ReaderManagerWorker::fireReaderDeviceError); + connect(pPlugIn, &ReaderManagerPlugIn::fireReaderPropertiesUpdated, this, &ReaderManagerWorker::fireReaderPropertiesUpdated); connect(pPlugIn, &ReaderManagerPlugIn::fireStatusChanged, this, &ReaderManagerWorker::fireStatusChanged); connect(pPlugIn, &ReaderManagerPlugIn::fireCardInserted, this, &ReaderManagerWorker::fireCardInserted); connect(pPlugIn, &ReaderManagerPlugIn::fireCardRemoved, this, &ReaderManagerWorker::fireCardRemoved); 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); } -void ReaderManagerWorker::startScan() +void ReaderManagerWorker::startScan(ReaderManagerPlugInType pType) { Q_ASSERT(thread() == QThread::currentThread()); - if (mScanStarted) + for (auto& plugin : qAsConst(mPlugIns)) { - qCWarning(card) << "Scan is already started, skip starting"; - return; - } - - mScanStarted = true; - for (auto plugin : qAsConst(mPlugIns)) - { - qCDebug(card) << "Start scan on plugin:" << plugin->metaObject()->className(); - plugin->startScan(); + if (plugin->getInfo().getPlugInType() == pType) + { + qCDebug(card) << "Start scan on plugin:" << plugin->metaObject()->className(); + plugin->setConnectToKnownReaders(true); + plugin->startScan(); + } } } -void ReaderManagerWorker::stopScan() +void ReaderManagerWorker::stopScan(ReaderManagerPlugInType pType) { Q_ASSERT(thread() == QThread::currentThread()); - if (!mScanStarted) + for (auto& plugin : qAsConst(mPlugIns)) { - qCWarning(card) << "Scan is not started, skip stopping"; - return; - } - - mScanStarted = false; - for (auto plugin : qAsConst(mPlugIns)) - { - qCDebug(card) << "Stop scan on plugin:" << plugin->metaObject()->className(); - plugin->stopScan(); + if (plugin->getInfo().getPlugInType() == pType) + { + qCDebug(card) << "Stop scan on plugin:" << plugin->metaObject()->className(); + plugin->setConnectToKnownReaders(false); + plugin->stopScan(); + } } } @@ -146,23 +150,21 @@ QVector ReaderManagerWorker::getPlugInInfos() const } -QVector ReaderManagerWorker::getReaderInfos(const QVector& pTypes) const +QVector ReaderManagerWorker::getReaderInfos(const ReaderFilter& pFilter) const { Q_ASSERT(thread() == QThread::currentThread()); QVector list; - for (const auto plugIn : qAsConst(mPlugIns)) + const QVector& plugIns = pFilter.apply(mPlugIns); + for (const auto& plugIn : plugIns) { - if (pTypes.contains(plugIn->getInfo().getPlugInType())) + const auto& readerList = plugIn->getReaders(); + for (const Reader* reader : readerList) { - const auto& readerList = plugIn->getReader(); - for (const Reader* reader : readerList) - { - list += reader->getReaderInfo(); - } + list += reader->getReaderInfo(); } } - return list; + return pFilter.apply(list); } @@ -171,7 +173,7 @@ ReaderInfo ReaderManagerWorker::getReaderInfo(const QString& pReaderName) const Q_ASSERT(thread() == QThread::currentThread()); const Reader* reader = getReader(pReaderName); - return reader ? reader->getReaderInfo() : ReaderInfo(); + return reader ? reader->getReaderInfo() : ReaderInfo(pReaderName); } @@ -179,9 +181,9 @@ Reader* ReaderManagerWorker::getReader(const QString& pReaderName) const { Q_ASSERT(thread() == QThread::currentThread()); - for (auto plugin : qAsConst(mPlugIns)) + for (auto& plugin : qAsConst(mPlugIns)) { - const auto& readerList = plugin->getReader(); + const auto& readerList = plugin->getReaders(); for (Reader* reader : readerList) { if (reader->getName() == pReaderName) @@ -235,19 +237,8 @@ void ReaderManagerWorker::disconnectAllReaders() { Q_ASSERT(thread() == QThread::currentThread()); - for (auto& info : getReaderInfos(Enum::getList())) + for (auto& info : getReaderInfos()) { 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 7459a76..7378e2b 100644 --- a/src/card/base/ReaderManagerWorker.h +++ b/src/card/base/ReaderManagerWorker.h @@ -1,13 +1,14 @@ /*! * \brief Worker implementation of ReaderManger thread * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "CardConnectionWorker.h" #include "DeviceError.h" +#include "ReaderFilter.h" #include "ReaderInfo.h" #include "ReaderManagerPlugIn.h" #include "ReaderManagerPlugInInfo.h" @@ -16,6 +17,7 @@ namespace governikus { +class RemoteClient; class ReaderManagerWorker : public QObject @@ -23,8 +25,8 @@ class ReaderManagerWorker Q_OBJECT private: + const QSharedPointer mRemoteClient; QVector mPlugIns; - bool mScanStarted; void registerPlugIns(); bool isPlugIn(const QJsonObject& pJson); @@ -32,27 +34,26 @@ class ReaderManagerWorker Reader* getReader(const QString& pReaderName) const; public: - ReaderManagerWorker(); + ReaderManagerWorker(const QSharedPointer& pRemoteClient); ~ReaderManagerWorker(); - Q_INVOKABLE void startScan(); - Q_INVOKABLE void stopScan(); + Q_INVOKABLE void startScan(ReaderManagerPlugInType pType); + Q_INVOKABLE void stopScan(ReaderManagerPlugInType pType); Q_INVOKABLE QVector getPlugInInfos() const; - Q_INVOKABLE QVector getReaderInfos(const QVector& pTypes) const; + Q_INVOKABLE QVector getReaderInfos(const ReaderFilter& pFilter = ReaderFilter()) const; Q_INVOKABLE ReaderInfo getReaderInfo(const QString& pReaderName) const; Q_INVOKABLE void createCardConnectionWorker(const QString& pReaderName); Q_INVOKABLE void connectReader(const QString& pReaderName); Q_INVOKABLE void disconnectReader(const QString& pReaderName); Q_INVOKABLE void disconnectAllReaders(); - static void registerMetaTypes(); Q_SIGNALS: + void firePluginAdded(const ReaderManagerPlugInInfo& pInfo); 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 fireReaderDeviceError(DeviceError pDeviceError); void fireReaderPropertiesUpdated(const QString& pReaderName); void fireCardInserted(const QString& pReaderName); void fireCardRemoved(const QString& pReaderName); diff --git a/src/card/base/RemoteClient.cpp b/src/card/base/RemoteClient.cpp new file mode 100644 index 0000000..03dd12c --- /dev/null +++ b/src/card/base/RemoteClient.cpp @@ -0,0 +1,25 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteClient.h" + + +using namespace governikus; + + +RemoteClient::~RemoteClient() +{ +} + + +QVector > RemoteClient::getRemoteDevices() const +{ + return QVector >(); +} + + +void RemoteClient::requestRemoteDevices() +{ + Q_EMIT fireRemoteDevicesInfo(QVector >()); +} diff --git a/src/card/base/RemoteClient.h b/src/card/base/RemoteClient.h new file mode 100644 index 0000000..1540391 --- /dev/null +++ b/src/card/base/RemoteClient.h @@ -0,0 +1,54 @@ +/*! + * \brief An interface for RemoteClientImpl, meant to omit the + * dependency between card_base and remote_device. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" +#include "RemoteServiceSettings.h" + +#include +#include + +namespace governikus +{ + +class RemoteDispatcher; +class RemoteDeviceListEntry; + +class RemoteClient + : public QObject +{ + Q_OBJECT + + Q_SIGNALS: + void fireDeviceAppeared(const QSharedPointer& pEntry); + void fireDeviceVanished(const QSharedPointer& pEntry); + void fireEstablishConnectionDone(const QSharedPointer& pEntry, GlobalStatus pStatus); + + void fireNewRemoteDispatcher(const QSharedPointer& pRemoteDispatcher); + void fireRemoteDevicesInfo(const QVector >& pRemoteDevices); + void fireDispatcherDestroyed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); + void fireDetectionChanged(); + void fireCertificateRemoved(QString pDeviceName); + + public: + RemoteClient() = default; + virtual ~RemoteClient(); + + Q_INVOKABLE virtual void startDetection() = 0; + Q_INVOKABLE virtual void stopDetection() = 0; + Q_INVOKABLE virtual bool isDetecting() = 0; + + Q_INVOKABLE virtual void establishConnection(const QSharedPointer& pEntry, const QString& pPsk) = 0; + + virtual QVector > getRemoteDevices() const; + Q_INVOKABLE virtual void requestRemoteDevices(); + virtual QVector getConnectedDeviceInfos() = 0; +}; + + +} /* namespace governikus */ diff --git a/src/card/base/RemoteDispatcher.cpp b/src/card/base/RemoteDispatcher.cpp new file mode 100644 index 0000000..6cae95b --- /dev/null +++ b/src/card/base/RemoteDispatcher.cpp @@ -0,0 +1,32 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDispatcher.h" + +#include "Initializer.h" + +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +static Initializer::Entry E([] { + qRegisterMetaType >("QSharedPointer"); + }); + + +RemoteDispatcher::RemoteDispatcher() + : QObject() + , QEnableSharedFromThis() +{ +} + + +RemoteDispatcher::~RemoteDispatcher() +{ +} diff --git a/src/card/base/RemoteDispatcher.h b/src/card/base/RemoteDispatcher.h new file mode 100644 index 0000000..0c01d1c --- /dev/null +++ b/src/card/base/RemoteDispatcher.h @@ -0,0 +1,44 @@ +/*! + * + * \brief An interface for RemoteHandleImpl, meant to omit the + * dependency between card_base and remote_device. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" + +#include +#include + + +namespace governikus +{ + +class DataChannel; +class RemoteMessage; + +class RemoteDispatcher + : public QObject + , public QEnableSharedFromThis +{ + Q_OBJECT + + protected: + RemoteDispatcher(); + + public: + virtual ~RemoteDispatcher(); + + virtual const QString& getId() const = 0; + virtual const QString& getContextHandle() const = 0; + Q_INVOKABLE virtual void send(const QSharedPointer& pMessage) = 0; + + Q_SIGNALS: + void fireReceived(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher); + void fireClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); +}; + +} /* namespace governikus */ diff --git a/src/card/base/SecureMessagingResponse.cpp b/src/card/base/SecureMessagingResponse.cpp index 86473f0..3331576 100644 --- a/src/card/base/SecureMessagingResponse.cpp +++ b/src/card/base/SecureMessagingResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/src/card/base/SecureMessagingResponse.h b/src/card/base/SecureMessagingResponse.h index 17a21ed..bea1431 100644 --- a/src/card/base/SecureMessagingResponse.h +++ b/src/card/base/SecureMessagingResponse.h @@ -1,7 +1,7 @@ /*! * \brief Response APDU for SecureMessaging * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/SmartCardDefinitions.cpp b/src/card/base/SmartCardDefinitions.cpp index d00d461..62a129d 100644 --- a/src/card/base/SmartCardDefinitions.cpp +++ b/src/card/base/SmartCardDefinitions.cpp @@ -1,7 +1,5 @@ /*! - * SmartCardDefinitions.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "SmartCardDefinitions.h" diff --git a/src/card/base/SmartCardDefinitions.h b/src/card/base/SmartCardDefinitions.h index 96a334c..55737f6 100644 --- a/src/card/base/SmartCardDefinitions.h +++ b/src/card/base/SmartCardDefinitions.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -8,29 +8,12 @@ namespace governikus { -defineEnumType(ReaderType, - UNKNOWN, - REINER_cyberJack_RFID_komfort, - REINER_cyberJack_RFID_standard, - REINER_cyberJack_RFID_basis, - REINER_cyberJack_wave, - KOBIL_IDToken, - SCM_SDI010, - SCM_SDI011, - SCM_SCL011_Contactless_Reader, - ACS_ACR1281_PICC_Reader, - OMNIKEY_4121_CL, - OMNIKEY_CardMan_5x21_CL, - FEIG_OBID_myAXXESS_basic, - Gemalto_Prox_SU, - Gemalto_Prox_DU) - defineEnumType(CardType, NONE, UNKNOWN, EID_CARD) -defineTypedEnumType(PACE_PIN_ID, char, +defineTypedEnumType(PACE_PASSWORD_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 deleted file mode 100644 index b87cf40..0000000 --- a/src/card/base/SupportedReaders.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*! - * SupportedReaders.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "SupportedReaders.h" - -#include "SingletonHelper.h" - -#define regex(X) QRegularExpression(QStringLiteral(X)) - -using namespace governikus; - -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)")} - }) -{ -} - - -SupportedReaders::~SupportedReaders() -{ -} - - -SupportedReaders& SupportedReaders::getInstance() -{ - return *Instance; -} - - -SupportedReaders::WhiteListMap::const_iterator SupportedReaders::getMapEntry(const QString& pReaderName) const -{ - for (auto iter = mWhiteList.constBegin(); iter != mWhiteList.constEnd(); ++iter) - { - if (pReaderName.contains(*iter)) - { - return iter; - } - } - - return mWhiteList.constEnd(); -} - - -ReaderType SupportedReaders::getReader(const QString& pReaderName) const -{ - auto iter = getMapEntry(pReaderName); - if (iter == mWhiteList.constEnd()) - { - return ReaderType::UNKNOWN; - } - - return iter.key(); -} - - -bool SupportedReaders::isOnWhiteList(const QString& pReaderName) const -{ - return getMapEntry(pReaderName) != mWhiteList.constEnd(); -} - - -QString SupportedReaders::getPattern(ReaderType pReader) const -{ - if (mWhiteList.contains(pReader)) - { - return mWhiteList.find(pReader)->pattern(); - } - - return QString(); -} diff --git a/src/card/base/SupportedReaders.h b/src/card/base/SupportedReaders.h deleted file mode 100644 index e72b536..0000000 --- a/src/card/base/SupportedReaders.h +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * SupportedReaders.h - * - * \brief Implements whitelist of readers and provides some more useful information of them. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "SmartCardDefinitions.h" - -#include -#include -#include - -namespace governikus -{ - - -class SupportedReaders -{ - private: - typedef QMap WhiteListMap; - const WhiteListMap mWhiteList; - - Q_DISABLE_COPY(SupportedReaders) - - WhiteListMap::const_iterator getMapEntry(const QString& pReaderName) const; - - protected: - SupportedReaders(); - ~SupportedReaders(); - - public: - static SupportedReaders& getInstance(); - - /*! - * Returns the corresponding \ref Reader object of given reader name. If reader name is unknown it will return \ref Reader::UNKNOWN. - */ - ReaderType getReader(const QString& pReaderName) const; - - /*! - * Check if the given reader name is on whitelist - */ - bool isOnWhiteList(const QString& pReaderName) const; - - /*! - * Returns the base name of given \ref Reader, otherwise QString() - */ - QString getPattern(ReaderType pReader) const; -}; - -} /* namespace governikus */ diff --git a/src/card/base/asn1/ASN1TemplateUtil.h b/src/card/base/asn1/ASN1TemplateUtil.h index 1222b36..9ee49f4 100644 --- a/src/card/base/asn1/ASN1TemplateUtil.h +++ b/src/card/base/asn1/ASN1TemplateUtil.h @@ -1,7 +1,7 @@ /*! * \brief Utility template functions for encoding and decoding of ASN.1 types * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/ASN1Util.cpp b/src/card/base/asn1/ASN1Util.cpp index f983307..24d0d7e 100644 --- a/src/card/base/asn1/ASN1Util.cpp +++ b/src/card/base/asn1/ASN1Util.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + #include "asn1/ASN1Util.h" #include "SecureMessagingResponse.h" @@ -9,10 +13,7 @@ using namespace governikus; -IMPLEMENT_STACK_OF(ASN1_OCTET_STRING) - - -ASN1_OBJECT * Asn1ObjectUtil::parseFrom(const QByteArray &pOidAsText) +ASN1_OBJECT* Asn1ObjectUtil::parseFrom(const QByteArray& pOidAsText) { return OBJ_txt2obj(pOidAsText.constData(), 1); } @@ -39,6 +40,20 @@ QByteArray Asn1ObjectUtil::convertTo(const ASN1_OBJECT* pAsn1Object) } +QByteArray Asn1ObjectUtil::getValue(const ASN1_OBJECT* pAsn1Object) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return QByteArray(reinterpret_cast(pAsn1Object->data), pAsn1Object->length); + +#else + const size_t len = OBJ_length(pAsn1Object); + const unsigned char* data = OBJ_get0_data(pAsn1Object); + return QByteArray(reinterpret_cast(data), static_cast(len)); + +#endif +} + + void Asn1OctetStringUtil::setValue(const QByteArray& pValue, ASN1_OCTET_STRING* pAsn1OctetString) { ASN1_OCTET_STRING_set(pAsn1OctetString, reinterpret_cast(pValue.data()), pValue.length()); diff --git a/src/card/base/asn1/ASN1Util.h b/src/card/base/asn1/ASN1Util.h index c6f0706..900728d 100644 --- a/src/card/base/asn1/ASN1Util.h +++ b/src/card/base/asn1/ASN1Util.h @@ -1,7 +1,7 @@ /*! * \brief Utility functions, templates and other ASN.1 related helper stuff * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -16,8 +16,11 @@ /*! * OpenSSL type declarations */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L DECLARE_STACK_OF(ASN1_OCTET_STRING) - +#else +DEFINE_STACK_OF(ASN1_OCTET_STRING) +#endif namespace governikus { @@ -47,6 +50,7 @@ class Asn1ObjectUtil public: static ASN1_OBJECT* parseFrom(const QByteArray& pOidAsText); static QByteArray convertTo(const ASN1_OBJECT* pAsn1Object); + static QByteArray getValue(const ASN1_OBJECT* pAsn1Object); }; diff --git a/src/card/base/asn1/AccessRoleAndRight.cpp b/src/card/base/asn1/AccessRoleAndRight.cpp index 2427280..47a5383 100644 --- a/src/card/base/asn1/AccessRoleAndRight.cpp +++ b/src/card/base/asn1/AccessRoleAndRight.cpp @@ -1,7 +1,5 @@ /*! - * AccessRoleAndRight.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "AccessRoleAndRight.h" @@ -15,12 +13,7 @@ QList AccessRoleAndRightsUtil::mAllRights; QList AccessRoleAndRightsUtil::mAllDisplayedOrderedRights; -AccessRoleAndRightsUtil::AccessRoleAndRightsUtil() - : QObject() -{ -} - - +// TR-03124, 3.8: Access rights for data groups or functions not defined in [TR-03127] SHALL NOT be available. const QList& AccessRoleAndRightsUtil::allDisplayedOrderedRights() { if (mAllDisplayedOrderedRights.isEmpty()) @@ -48,6 +41,7 @@ const QList& AccessRoleAndRightsUtil::allDisplayedOrderedRights() } +// TR 03127 - 3.2.2 const QList& AccessRoleAndRightsUtil::allRights() { if (mAllRights.isEmpty()) @@ -99,6 +93,7 @@ const QList& AccessRoleAndRightsUtil::allRights() } +// TR-03127, Annex C QString AccessRoleAndRightsUtil::toDisplayText(AccessRight pRight) { switch (pRight) @@ -126,6 +121,7 @@ QString AccessRoleAndRightsUtil::toDisplayText(AccessRight pRight) return tr("Residence permit II"); case AccessRight::READ_DG19: + // "Auxiliary conditions" are replaced with "Residence permit I" in agreement with the BMI return tr("Residence permit I"); case AccessRight::READ_DG18: @@ -236,3 +232,6 @@ bool AccessRoleAndRightsUtil::fromTechnicalName(const char* pStr, const std::fun } return false; } + + +#include "moc_AccessRoleAndRight.cpp" diff --git a/src/card/base/asn1/AccessRoleAndRight.h b/src/card/base/asn1/AccessRoleAndRight.h index d68e90a..510c438 100644 --- a/src/card/base/asn1/AccessRoleAndRight.h +++ b/src/card/base/asn1/AccessRoleAndRight.h @@ -1,6 +1,4 @@ /*! - * AccessRoleAndRight.h - * * \brief Defines the AccessRight and AccessRole enum. * * Note: When using a QHash directly or indirectly (e.g. via QSet), @@ -8,7 +6,7 @@ * or otherwise the complain about the qHash() function for AccessRight not being * found. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -16,6 +14,7 @@ #include "EnumHelper.h" #include +#include #include #include @@ -102,14 +101,13 @@ defineEnumType(AccessRole, class AccessRoleAndRightsUtil - : public QObject { - Q_OBJECT + Q_DECLARE_TR_FUNCTIONS(governikus::AccessRoleAndRightsUtil) private: static QList mAllRights; static QList mAllDisplayedOrderedRights; - AccessRoleAndRightsUtil(); + AccessRoleAndRightsUtil() = delete; public: static const QList& allDisplayedOrderedRights(); diff --git a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp index b0b6925..675cf1c 100644 --- a/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp +++ b/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp @@ -1,13 +1,11 @@ /*! - * AuthenticatedAuxiliaryData.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "AuthenticatedAuxiliaryData.h" + #include "ASN1TemplateUtil.h" #include "ASN1Util.h" -#include "AuthenticatedAuxiliaryData.h" -#include "KnownOIDs.h" #include @@ -53,15 +51,15 @@ ASN1_ITEM_TEMPLATE_END(AuxDataTemplate) /*! - * This defines the AuthenticatedAuxiliaryData object with the special tag 0x07. + * This defines the AuthenticatedAuxiliaryDataInternal object with the special tag 0x07. */ -ASN1_ITEM_TEMPLATE(AuthenticatedAuxiliaryData) = - ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x07, AuthenticatedAuxiliaryData, AuxDataTemplate) -ASN1_ITEM_TEMPLATE_END(AuthenticatedAuxiliaryData) +ASN1_ITEM_TEMPLATE(AuthenticatedAuxiliaryDataInternal) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x07, AuthenticatedAuxiliaryDataInternal, AuxDataTemplate) +ASN1_ITEM_TEMPLATE_END(AuthenticatedAuxiliaryDataInternal) -IMPLEMENT_ASN1_FUNCTIONS(AuthenticatedAuxiliaryData) -IMPLEMENT_ASN1_OBJECT(AuthenticatedAuxiliaryData) +IMPLEMENT_ASN1_FUNCTIONS(AuthenticatedAuxiliaryDataInternal) +IMPLEMENT_ASN1_OBJECT(AuthenticatedAuxiliaryDataInternal) /*! @@ -97,8 +95,23 @@ ASN1_ITEM_TEMPLATE_END(AgeVerificationDate) IMPLEMENT_ASN1_FUNCTIONS(AgeVerificationDate) +DECLARE_ASN1_FUNCTIONS(AuthenticatedAuxiliaryDataInternal) +DECLARE_ASN1_OBJECT(AuthenticatedAuxiliaryDataInternal) -} // namespace governikus + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define sk_AuxDataTemplate_num(data) SKM_sk_num(AuxDataTemplate, data) + #define sk_AuxDataTemplate_value(data, i) SKM_sk_value(AuxDataTemplate, data, i) +#endif + +} /* namespace governikus */ + + +AuthenticatedAuxiliaryData::AuthenticatedAuxiliaryData(const QSharedPointer& pData) + : mData(pData) +{ + Q_ASSERT(mData); +} QSharedPointer AuthenticatedAuxiliaryData::fromHex(const QByteArray& pHexValue) @@ -109,49 +122,55 @@ QSharedPointer AuthenticatedAuxiliaryData::fromHex(c QSharedPointer AuthenticatedAuxiliaryData::decode(const QByteArray& pBytes) { - auto auxDate = decodeObject(pBytes); + auto auxDate = decodeObject(pBytes); + + if (!auxDate) + { + return nullptr; + } QByteArrayList oids; - for (int i = 0; i < SKM_sk_num(AuxDataTemplate, auxDate.data()); i++) + for (int i = 0; i < sk_AuxDataTemplate_num(auxDate.data()); i++) { - AuxDataTemplate* auxDataTemplate = SKM_sk_value(AuxDataTemplate, auxDate.data(), i); + AuxDataTemplate* auxDataTemplate = sk_AuxDataTemplate_value(auxDate.data(), i); const auto oid = Asn1ObjectUtil::convertTo(auxDataTemplate->mAuxId); if (oids.contains(oid)) { - qCritical(card) << "More than one AuxDataTemplate with OID" << oid; - auxDate.clear(); - break; + qCCritical(card) << "More than one AuxDataTemplate with OID" << oid; + return nullptr; } oids += oid; } - oids.removeOne(KnownOIDs::AuxilaryData::id_CommunityID); - oids.removeOne(KnownOIDs::AuxilaryData::id_DateOfBirth); - oids.removeOne(KnownOIDs::AuxilaryData::id_DateOfExpiry); + + oids.removeOne(toByteArray(KnownOIDs::AuxilaryData::ID_COMMUNITY_ID)); + oids.removeOne(toByteArray(KnownOIDs::AuxilaryData::ID_DATE_OF_BIRTH)); + oids.removeOne(toByteArray(KnownOIDs::AuxilaryData::ID_DATE_OF_EXPIRY)); if (!oids.isEmpty()) { - qCritical() << "Unknown AuxDataTemplate with oid" << oids.first(); - auxDate.clear(); + qCCritical(card) << "Unknown AuxDataTemplate with OID" << oids.first(); + return nullptr; } - return auxDate; + return QSharedPointer(new AuthenticatedAuxiliaryData(auxDate)); } -QByteArray AuthenticatedAuxiliaryData::encode() +QByteArray AuthenticatedAuxiliaryData::encode() const { - return encodeObject(this); + Q_ASSERT(mData); + return encodeObject(mData.data()); } bool AuthenticatedAuxiliaryData::hasValidityDate() const { - return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfExpiry) != nullptr; + return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_DATE_OF_EXPIRY) != nullptr; } QDate AuthenticatedAuxiliaryData::getValidityDate() const { - if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfExpiry)) + if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_DATE_OF_EXPIRY)) { QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo); @@ -168,13 +187,13 @@ QDate AuthenticatedAuxiliaryData::getValidityDate() const bool AuthenticatedAuxiliaryData::hasAgeVerificationDate() const { - return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfBirth) != nullptr; + return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_DATE_OF_BIRTH) != nullptr; } QDate AuthenticatedAuxiliaryData::getAgeVerificationDate() const { - if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfBirth)) + if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_DATE_OF_BIRTH)) { QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo); @@ -189,32 +208,40 @@ QDate AuthenticatedAuxiliaryData::getAgeVerificationDate() const } +QString AuthenticatedAuxiliaryData::getRequiredAge(const QDate& pEffectiveDate) const +{ + const QDate ageVerificationDate = getAgeVerificationDate(); + if (!pEffectiveDate.isValid() || !ageVerificationDate.isValid()) + { + return QString(); + } + + int age = pEffectiveDate.year() - ageVerificationDate.year(); + + if (pEffectiveDate.month() <= ageVerificationDate.month() && (pEffectiveDate.month() != ageVerificationDate.month() || pEffectiveDate.day() < ageVerificationDate.day())) + { + --age; + } + + return QString::number(age); +} + + QString AuthenticatedAuxiliaryData::getRequiredAge() const { - QDateTime now = QDateTime::currentDateTime(); - QDate nowDateGMT = now.toUTC().date(); - QDate ageVerificationDate = getAgeVerificationDate(); - - if (nowDateGMT.month() > ageVerificationDate.month() || (nowDateGMT.month() == ageVerificationDate.month() && nowDateGMT.day() >= ageVerificationDate.day())) - { - return QString::number(nowDateGMT.year() - ageVerificationDate.year()); - } - else - { - return QString::number(nowDateGMT.year() - ageVerificationDate.year() - 1); - } + return getRequiredAge(QDateTime::currentDateTimeUtc().date()); } bool AuthenticatedAuxiliaryData::hasCommunityID() const { - return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_CommunityID) != nullptr; + return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_COMMUNITY_ID) != nullptr; } QByteArray AuthenticatedAuxiliaryData::getCommunityID() const { - if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_CommunityID)) + if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::ID_COMMUNITY_ID)) { QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo); auto communityId = decodeObject(extBytes); @@ -227,15 +254,14 @@ QByteArray AuthenticatedAuxiliaryData::getCommunityID() const } -AuxDataTemplate* AuthenticatedAuxiliaryData::getAuxDataTemplateFor(const QByteArray& pOid) const +AuxDataTemplate* AuthenticatedAuxiliaryData::getAuxDataTemplateFor(KnownOIDs::AuxilaryData pData) const { - // unfortunately OpenSSL cannot handle const pointers, so we cast it away - AuthenticatedAuxiliaryData* notConstThis = const_cast(this); + const auto& oid = toByteArray(pData); - for (int i = 0; i < SKM_sk_num(AuxDataTemplate, notConstThis); i++) + for (int i = 0; i < sk_AuxDataTemplate_num(mData.data()); i++) { - AuxDataTemplate* auxDataTemplate = SKM_sk_value(AuxDataTemplate, notConstThis, i); - if (Asn1ObjectUtil::convertTo(auxDataTemplate->mAuxId) == pOid) + AuxDataTemplate* auxDataTemplate = sk_AuxDataTemplate_value(mData.data(), i); + if (Asn1ObjectUtil::convertTo(auxDataTemplate->mAuxId) == oid) { return auxDataTemplate; } diff --git a/src/card/base/asn1/AuthenticatedAuxiliaryData.h b/src/card/base/asn1/AuthenticatedAuxiliaryData.h index e60a912..2b93222 100644 --- a/src/card/base/asn1/AuthenticatedAuxiliaryData.h +++ b/src/card/base/asn1/AuthenticatedAuxiliaryData.h @@ -1,21 +1,22 @@ /*! - * AuthenticatedAuxiliaryData.h - * * \brief Implementation of AuthenticatedAuxiliaryData. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "ASN1TemplateUtil.h" +#include "KnownOIDs.h" + #include #include #include #include +class test_AuxiliaryAuthenticatedData; namespace governikus { @@ -48,34 +49,39 @@ typedef struct auxdatatemplate_st } AuxDataTemplate; - +#if OPENSSL_VERSION_NUMBER < 0x10100000L DECLARE_STACK_OF(AuxDataTemplate) +using AuthenticatedAuxiliaryDataInternal = stack_st_AuxDataTemplate; +#else +DEFINE_STACK_OF(AuxDataTemplate) +using AuthenticatedAuxiliaryDataInternal = STACK_OF(AuxDataTemplate); +#endif - -struct AuthenticatedAuxiliaryData - : stack_st_AuxDataTemplate +class AuthenticatedAuxiliaryData { - static QSharedPointer fromHex(const QByteArray& pHexValue); - static QSharedPointer decode(const QByteArray& pBytes); - QByteArray encode(); - - bool hasValidityDate() const; - QDate getValidityDate() const; - - bool hasAgeVerificationDate() const; - QDate getAgeVerificationDate() const; - QString getRequiredAge() const; - - bool hasCommunityID() const; - QByteArray getCommunityID() const; - private: - AuxDataTemplate* getAuxDataTemplateFor(const QByteArray& pOid) const; + friend class ::test_AuxiliaryAuthenticatedData; + QSharedPointer mData; + AuthenticatedAuxiliaryData(const QSharedPointer& pData); + AuxDataTemplate* getAuxDataTemplateFor(KnownOIDs::AuxilaryData pData) const; + + QString getRequiredAge(const QDate& pEffectiveDate) const; + + public: + static QSharedPointer fromHex(const QByteArray& pHexValue); + static QSharedPointer decode(const QByteArray& pBytes); + QByteArray encode() const; + + bool hasValidityDate() const; + QDate getValidityDate() const; + + bool hasAgeVerificationDate() const; + QDate getAgeVerificationDate() const; + QString getRequiredAge() const; + + bool hasCommunityID() const; + QByteArray getCommunityID() const; }; - -DECLARE_ASN1_FUNCTIONS(AuthenticatedAuxiliaryData) -DECLARE_ASN1_OBJECT(AuthenticatedAuxiliaryData) - } /* namespace governikus */ diff --git a/src/card/base/asn1/CVCertificate.cpp b/src/card/base/asn1/CVCertificate.cpp index 93c5c68..80d6bc8 100644 --- a/src/card/base/asn1/CVCertificate.cpp +++ b/src/card/base/asn1/CVCertificate.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -60,17 +60,26 @@ int CVCertificate::decodeCallback(int pOperation, ASN1_VALUE** pVal, const ASN1_ const unsigned char* sig = reinterpret_cast(sigValue.data()); int siglen = sigValue.size(); - BN_bin2bn(sig, siglen / 2, cvc->mEcdsaSignature.data()->r); - BN_bin2bn(sig + (siglen / 2), siglen / 2, cvc->mEcdsaSignature.data()->s); + + BIGNUM* r = BN_bin2bn(sig, siglen / 2, 0); + BIGNUM* s = BN_bin2bn(sig + (siglen / 2), siglen / 2, 0); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + cvc->mEcdsaSignature.data()->r = r; + cvc->mEcdsaSignature.data()->s = s; +#else + ECDSA_SIG_set0(cvc->mEcdsaSignature.data(), r, s); +#endif + } } return CB_SUCCESS; } -QVector > CVCertificate::fromHex(const QByteArrayList& pHexByteList) +QVector > CVCertificate::fromHex(const QByteArrayList& pHexByteList) { - QVector > cvcs; + QVector > cvcs; for (const QByteArray& hexBytes : pHexByteList) { if (auto cvc = CVCertificate::fromHex(hexBytes)) @@ -82,7 +91,7 @@ QVector > CVCertificate::fromHex(const QByteArrayL } -QSharedPointer CVCertificate::fromHex(const QByteArray& pHexBytes) +QSharedPointer CVCertificate::fromHex(const QByteArray& pHexBytes) { return decodeObject(QByteArray::fromHex(pHexBytes)); @@ -95,12 +104,6 @@ QByteArray CVCertificate::encode() const } -bool CVCertificate::operator ==(const cvcertificate_st& other) const -{ - return this->getRawBody() == other.getRawBody() && this->getRawSignature() == other.getRawSignature(); -} - - const CVCertificateBody& CVCertificate::getBody() const { Q_ASSERT(mBody != nullptr); @@ -136,39 +139,7 @@ bool CVCertificate::isValidOn(const QDateTime& pValidationDate) const bool CVCertificate::isIssuedBy(const CVCertificate& pIssuer) const { - return this->getBody().getCertificationAuthorityReference() == pIssuer.getBody().getCertificateHolderReference(); -} - - -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())) - { - return false; - } - if (pCvc1.isNull() && pCvc2.isNull()) - { - return true; - } - return *pCvc1 == *pCvc2; + return getBody().getCertificationAuthorityReference() == pIssuer.getBody().getCertificateHolderReference(); } diff --git a/src/card/base/asn1/CVCertificate.h b/src/card/base/asn1/CVCertificate.h index 1801158..e70e6d9 100644 --- a/src/card/base/asn1/CVCertificate.h +++ b/src/card/base/asn1/CVCertificate.h @@ -1,7 +1,7 @@ /*! * \brief Implementation of Card Verifiable Certificate, CVC. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -50,18 +50,15 @@ typedef struct cvcertificate_st SIGNATURE* mSignature; QSharedPointer mEcdsaSignature; - static QVector > fromHex(const QByteArrayList& pHexByteList); - static QSharedPointer fromHex(const QByteArray& pHexBytes); + static QVector > fromHex(const QByteArrayList& pHexByteList); + static QSharedPointer fromHex(const QByteArray& pHexBytes); QByteArray encode() const; - bool operator==(const cvcertificate_st& other) const; - const CVCertificateBody& getBody() const; QByteArray getRawBody() const; QSharedPointer getEcdsaSignature() const; QByteArray getRawSignature() const; - bool isValidOn(const QDateTime& pValidationDate) const; bool isIssuedBy(const cvcertificate_st& pIssuer) const; @@ -74,15 +71,20 @@ DECLARE_ASN1_FUNCTIONS(CVCertificate) DECLARE_ASN1_OBJECT(CVCertificate) +inline bool operator==(const CVCertificate& pLeft, const CVCertificate& pRight) +{ + return pLeft.getRawBody() == pRight.getRawBody() && pLeft.getRawSignature() == pRight.getRawSignature(); +} + + +inline bool operator!=(const CVCertificate& pLeft, const CVCertificate& pRight) +{ + return !(pLeft == pRight); +} + + } /* namespace governikus */ - -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); diff --git a/src/card/base/asn1/CVCertificateBody.cpp b/src/card/base/asn1/CVCertificateBody.cpp index e435392..ab6a153 100644 --- a/src/card/base/asn1/CVCertificateBody.cpp +++ b/src/card/base/asn1/CVCertificateBody.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + #include "CVCertificateBody.h" #include "ASN1TemplateUtil.h" @@ -92,7 +96,13 @@ ASN1_ITEM_TEMPLATE_END(CVCertificateBody) IMPLEMENT_ASN1_FUNCTIONS(CVCertificateBody) IMPLEMENT_ASN1_OBJECT(CVCertificateBody) -} + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define sk_CERTIFICATEEXTENSION_num(data) SKM_sk_num(CERTIFICATEEXTENSION, data) + #define sk_CERTIFICATEEXTENSION_value(data, i) SKM_sk_value(CERTIFICATEEXTENSION, data, i) +#endif + +} /* namespace governikus */ QSharedPointer CVCertificateBody::fromHex(const QString& pHexValue) @@ -174,23 +184,23 @@ QByteArray CVCertificateBody::getCertificateHolderReference() const QCryptographicHash::Algorithm CVCertificateBody::getHashAlgorithm() const { const auto oid = getPublicKey().getPublicKeyOid(); - if (oid == KnownOIDs::id_TA::ECDSA_SHA_1) + if (oid == KnownOIDs::id_ta::ECDSA_SHA_1) { return QCryptographicHash::Sha1; } - if (oid == KnownOIDs::id_TA::ECDSA_SHA_224) + if (oid == KnownOIDs::id_ta::ECDSA_SHA_224) { return QCryptographicHash::Sha224; } - if (oid == KnownOIDs::id_TA::ECDSA_SHA_256) + if (oid == KnownOIDs::id_ta::ECDSA_SHA_256) { return QCryptographicHash::Sha256; } - if (oid == KnownOIDs::id_TA::ECDSA_SHA_384) + if (oid == KnownOIDs::id_ta::ECDSA_SHA_384) { return QCryptographicHash::Sha384; } - if (oid == KnownOIDs::id_TA::ECDSA_SHA_512) + if (oid == KnownOIDs::id_ta::ECDSA_SHA_512) { return QCryptographicHash::Sha512; } @@ -206,9 +216,9 @@ QMap CVCertificateBody::getExtensions() const if (mExtensions != nullptr) { - for (int i = 0; i < SKM_sk_num(CERTIFICATEEXTENSION, mExtensions); i++) + for (int i = 0; i < sk_CERTIFICATEEXTENSION_num(mExtensions); i++) { - CERTIFICATEEXTENSION* extension = SKM_sk_value(CERTIFICATEEXTENSION, mExtensions, i); + CERTIFICATEEXTENSION* extension = sk_CERTIFICATEEXTENSION_value(mExtensions, i); ext.insert(Asn1ObjectUtil::convertTo(extension->mOid), Asn1OctetStringUtil::getValue(extension->mObject1)); } } diff --git a/src/card/base/asn1/CVCertificateBody.h b/src/card/base/asn1/CVCertificateBody.h index 9c33ec5..57c726a 100644 --- a/src/card/base/asn1/CVCertificateBody.h +++ b/src/card/base/asn1/CVCertificateBody.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -35,6 +35,12 @@ typedef struct CERTIFICATEEXTENSION_st } CERTIFICATEEXTENSION; DECLARE_ASN1_FUNCTIONS(CERTIFICATEEXTENSION) +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DECLARE_STACK_OF(CERTIFICATEEXTENSION) +#else +DEFINE_STACK_OF(CERTIFICATEEXTENSION) +#endif + typedef struct certificateprofilebody_st { ASN1_OCTET_STRING* mCertificateProfileIdentifier; diff --git a/src/card/base/asn1/CVCertificateChain.cpp b/src/card/base/asn1/CVCertificateChain.cpp index 0cb8dcd..9132706 100644 --- a/src/card/base/asn1/CVCertificateChain.cpp +++ b/src/card/base/asn1/CVCertificateChain.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CVCertificateChain.h" @@ -9,13 +9,13 @@ using namespace governikus; CVCertificateChain::CVCertificateChain(bool pProductive) - : CVCertificateChain(QVector >(), pProductive) + : CVCertificateChain(QVector >(), pProductive) { } -CVCertificateChain::CVCertificateChain(const QVector >& pCvcs, bool pProductive) - : QVector >(pCvcs) +CVCertificateChain::CVCertificateChain(const QVector >& pCvcs, bool pProductive) + : QVector >(pCvcs) , mProductive(pProductive) { if (!isValid()) @@ -25,14 +25,14 @@ CVCertificateChain::CVCertificateChain(const QVector CVCertificateChain::getTerminalCvc() const +QSharedPointer CVCertificateChain::getTerminalCvc() const { Q_ASSERT(length() > 0); return at(length() - 1); } -QSharedPointer CVCertificateChain::getDvCvc() const +QSharedPointer CVCertificateChain::getDvCvc() const { Q_ASSERT(length() > 1); return at(length() - 2); diff --git a/src/card/base/asn1/CVCertificateChain.h b/src/card/base/asn1/CVCertificateChain.h index 03c343f..7d01cbe 100644 --- a/src/card/base/asn1/CVCertificateChain.h +++ b/src/card/base/asn1/CVCertificateChain.h @@ -5,7 +5,7 @@ * (The holder is equivalent to the Subject-DN, the authority reference * is equivalent to the Issuer-DN.) * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -19,7 +19,7 @@ namespace governikus { class CVCertificateChain - : public QVector > + : public QVector > { private: bool mProductive; @@ -27,17 +27,17 @@ class CVCertificateChain public: CVCertificateChain(bool pProductive = true); - CVCertificateChain(const QVector >& pCvcs, bool pProductive); + CVCertificateChain(const QVector >& pCvcs, bool pProductive); /*! * Return the document verifier certificate. */ - QSharedPointer getDvCvc() const; + QSharedPointer getDvCvc() const; /*! * Return the terminal certificate. */ - QSharedPointer getTerminalCvc() const; + QSharedPointer getTerminalCvc() const; /*! * Is this a valid CVC chain, i.e. do DV and terminal CVCs exist? diff --git a/src/card/base/asn1/CVCertificateChainBuilder.cpp b/src/card/base/asn1/CVCertificateChainBuilder.cpp index b29b9ea..574546b 100644 --- a/src/card/base/asn1/CVCertificateChainBuilder.cpp +++ b/src/card/base/asn1/CVCertificateChainBuilder.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CVCertificateChainBuilder.h" @@ -20,19 +20,19 @@ bool CVCertificateChainBuilder::isChild(const QSharedPointer >(), pProductive) + : CVCertificateChainBuilder(QVector >(), pProductive) { } -CVCertificateChainBuilder::CVCertificateChainBuilder(const QVector >& pCvcPool, bool pProductive) +CVCertificateChainBuilder::CVCertificateChainBuilder(const QVector >& pCvcPool, bool pProductive) : ChainBuilder(pCvcPool, &CVCertificateChainBuilder::isChild) , mProductive(pProductive) { removeInvalidChains(); - for (auto cvc : pCvcPool) + for (const auto& cvc : pCvcPool) { qCDebug(card) << "CVC in pool" << cvc; } @@ -53,7 +53,7 @@ CVCertificateChainBuilder::CVCertificateChainBuilder(const QVector > > chainIter(mChains); + QMutableVectorIterator > > chainIter(mChains); while (chainIter.hasNext()) { if (!CVCertificateChain(chainIter.next(), mProductive).isValid()) @@ -111,7 +111,7 @@ CVCertificateChain CVCertificateChainBuilder::getChainStartingWith(const QShared { for (int i = 0; i < chain.length(); ++i) { - if (chain.at(i) == pChainRoot) + if (*chain.at(i) == *pChainRoot) { CVCertificateChain subChain(chain.mid(i), mProductive); if (subChain.isValid()) diff --git a/src/card/base/asn1/CVCertificateChainBuilder.h b/src/card/base/asn1/CVCertificateChainBuilder.h index 0b169c5..ec9729e 100644 --- a/src/card/base/asn1/CVCertificateChainBuilder.h +++ b/src/card/base/asn1/CVCertificateChainBuilder.h @@ -1,7 +1,7 @@ /*! * \brief Builder for CVC chains. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -17,7 +17,7 @@ namespace governikus class CVCertificateChainBuilder - : private ChainBuilder > + : private ChainBuilder > { private: bool mProductive; @@ -34,7 +34,7 @@ class CVCertificateChainBuilder /*! * Creates a new instance. All chains are build using the CVCs passed in as parameter. */ - CVCertificateChainBuilder(const QVector >& pCvcPool, bool pProductive); + CVCertificateChainBuilder(const QVector >& pCvcPool, bool pProductive); /*! diff --git a/src/card/base/asn1/CertificateDescription.cpp b/src/card/base/asn1/CertificateDescription.cpp index 5acd955..62a7a23 100644 --- a/src/card/base/asn1/CertificateDescription.cpp +++ b/src/card/base/asn1/CertificateDescription.cpp @@ -1,7 +1,5 @@ /*! - * CertificateDescription.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CertificateDescription.h" @@ -84,15 +82,16 @@ ASN1_SEQUENCE_END(CertificateDescription) IMPLEMENT_ASN1_FUNCTIONS(CertificateDescription) IMPLEMENT_ASN1_OBJECT(CertificateDescription) -} // namespace governikus +} /* namespace governikus */ -QSharedPointer CertificateDescription::fromHex(const QByteArray& pHexValue) + +QSharedPointer CertificateDescription::fromHex(const QByteArray& pHexValue) { return decode(QByteArray::fromHex(pHexValue)); } -QSharedPointer CertificateDescription::decode(const QByteArray& pBytes) +QSharedPointer CertificateDescription::decode(const QByteArray& pBytes) { return decodeObject(pBytes); } @@ -175,11 +174,11 @@ QString CertificateDescription::getSubjectUrl() const CertificateDescription::TermsOfUsageType CertificateDescription::getTermsOfUsageType() const { - if (getDescriptionType() == KnownOIDs::TermsOfUsageType::id_plainFormat) + if (getDescriptionType() == KnownOIDs::TermsOfUsageType::ID_PLAIN_FORMAT) { return TermsOfUsageType::PLAIN_TEXT; } - if (getDescriptionType() == KnownOIDs::TermsOfUsageType::id_htmlFormat) + if (getDescriptionType() == KnownOIDs::TermsOfUsageType::ID_HTML_FORMAT) { return TermsOfUsageType::HTML; } @@ -228,10 +227,11 @@ QSet CertificateDescription::getCommCertificates() const QSet commCerts; if (mCommCertificates != nullptr) { - commCerts.reserve(mCommCertificates->stack.num); - for (int i = 0; i < mCommCertificates->stack.num; i++) + const auto size = sk_ASN1_OCTET_STRING_num(mCommCertificates); + commCerts.reserve(size); + for (int i = 0; i < size; i++) { - ASN1_OCTET_STRING* octetString = SKM_sk_value(ASN1_OCTET_STRING, mCommCertificates, i); + ASN1_OCTET_STRING* octetString = sk_ASN1_OCTET_STRING_value(mCommCertificates, i); QByteArray byteBuf(reinterpret_cast(octetString->data), octetString->length); commCerts += QString::fromLatin1(byteBuf.toHex().toUpper()); } diff --git a/src/card/base/asn1/CertificateDescription.h b/src/card/base/asn1/CertificateDescription.h index 6a5fce3..6b93ac6 100644 --- a/src/card/base/asn1/CertificateDescription.h +++ b/src/card/base/asn1/CertificateDescription.h @@ -1,9 +1,7 @@ /*! - * CertificateDescription.h - * * \brief Implementation of ASN.1 type CertificateDescription with OpenSSL * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -14,8 +12,6 @@ #include #include -#include - #include #include #include @@ -43,77 +39,76 @@ namespace governikus */ struct CertificateDescription { - Q_DECLARE_TR_FUNCTIONS(CertificateDescription) + enum class TermsOfUsageType + { + PLAIN_TEXT, HTML, PDF + }; - // public is necessary here, because Q_DECLARE_TR_FUNCTIONS leaves - // the visibility set to private. - - public: - enum class TermsOfUsageType - { - PLAIN_TEXT, HTML, PDF - }; - - ASN1_OBJECT* mDescriptionType; - ASN1_UTF8STRING* mIssuerName; - ASN1_PRINTABLESTRING* mIssuerURL; - ASN1_UTF8STRING* mSubjectName; - ASN1_PRINTABLESTRING* mSubjectURL; - ASN1_TYPE* mTermsOfUsage; - ASN1_PRINTABLESTRING* mRedirectURL; - STACK_OF(ASN1_OCTET_STRING) * mCommCertificates; + ASN1_OBJECT* mDescriptionType; + ASN1_UTF8STRING* mIssuerName; + ASN1_PRINTABLESTRING* mIssuerURL; + ASN1_UTF8STRING* mSubjectName; + ASN1_PRINTABLESTRING* mSubjectURL; + ASN1_TYPE* mTermsOfUsage; + ASN1_PRINTABLESTRING* mRedirectURL; + STACK_OF(ASN1_OCTET_STRING) * mCommCertificates; - static QSharedPointer fromHex(const QByteArray& pHexValue); - static QSharedPointer decode(const QByteArray& pBytes); - QByteArray encode(); + static QSharedPointer fromHex(const QByteArray& pHexValue); + static QSharedPointer decode(const QByteArray& pBytes); + QByteArray encode(); - void setDescriptionType(const QByteArray& pOidAsText); - QByteArray getDescriptionType() const; + void setDescriptionType(const QByteArray& pOidAsText); + QByteArray getDescriptionType() const; - void setIssuerName(const QString& pIssuerName); - QString getIssuerName() const; + void setIssuerName(const QString& pIssuerName); + QString getIssuerName() const; - void setIssuerUrl(const QString& pIssuerUrl); - QString getIssuerUrl() const; + void setIssuerUrl(const QString& pIssuerUrl); + QString getIssuerUrl() const; - void setSubjectName(const QString& pSubjectName); - QString getSubjectName() const; + void setSubjectName(const QString& pSubjectName); + QString getSubjectName() const; - void setSubjectUrl(const QString& pSubjectUrl); - QString getSubjectUrl() const; + void setSubjectUrl(const QString& pSubjectUrl); + QString getSubjectUrl() const; - TermsOfUsageType getTermsOfUsageType() const; - QString getTermsOfUsage() const; + TermsOfUsageType getTermsOfUsageType() const; + QString getTermsOfUsage() const; - void setRedirectUrl(const QString& pRedirectUrl); - QString getRedirectUrl() const; + void setRedirectUrl(const QString& pRedirectUrl); + QString getRedirectUrl() const; - QSet getCommCertificates() const; + QSet getCommCertificates() const; - /*! - * \brief Returns the address of service provider. - * - * \return The address. - */ - QString getServiceProviderAddress() const; + /*! + * \brief Returns the address of service provider. + * + * \return The address. + */ + QString getServiceProviderAddress() const; - /*! - * \brief Returns the purpose of the certificate description. - * - * \return The purpose. - */ - QString getPurpose() const; + /*! + * \brief Returns the purpose of the certificate description. + * + * \return The purpose. + */ + QString getPurpose() const; - /*! - * \brief Returns the data security officer of the certificate description. - * - * \return The data security officer. - */ - QString getDataSecurityOfficer() const; + /*! + * \brief Returns the data security officer of the certificate description. + * + * \return The data security officer. + */ + QString getDataSecurityOfficer() const; }; DECLARE_ASN1_FUNCTIONS(CertificateDescription) DECLARE_ASN1_OBJECT(CertificateDescription) -} // namespace governikus +#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define sk_ASN1_OCTET_STRING_num(data) data->stack.num + #define sk_ASN1_OCTET_STRING_value(data, i) SKM_sk_value(ASN1_OCTET_STRING, data, i) +#endif + +} /* namespace governikus */ diff --git a/src/card/base/asn1/ChainBuilder.h b/src/card/base/asn1/ChainBuilder.h index c359964..d4609f4 100644 --- a/src/card/base/asn1/ChainBuilder.h +++ b/src/card/base/asn1/ChainBuilder.h @@ -1,13 +1,11 @@ /*! - * ChainBuilder.h - * * \brief Generic implementation for chain building, i.e. building ordered lists. * The ChainBuilder is initialized with a pool of objects and a (pointer to a) function * that decides if two objects have a parent child relation. Duplicates are filtered out. * * All found chains are returned by the function /ref ChainBuilder::getChains(). * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/Chat.cpp b/src/card/base/asn1/Chat.cpp index 42590e6..041d31c 100644 --- a/src/card/base/asn1/Chat.cpp +++ b/src/card/base/asn1/Chat.cpp @@ -1,7 +1,5 @@ /*! - * CHAT.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -61,7 +59,7 @@ int CHAT::decodeCallback(int pOperation, ASN1_VALUE** pVal, const ASN1_ITEM* pIt *pVal = nullptr; return CB_ERROR; } - else if (chat->getType() != KnownOIDs::CHATType::id_AT) + else if (chat->getType() != KnownOIDs::CHATType::ID_AT) { // currently we only support Authentication Terminals qDebug() << "CHAT type is unsupported" << chat->getType(); diff --git a/src/card/base/asn1/Chat.h b/src/card/base/asn1/Chat.h index 3a2174f..7cbfeee 100644 --- a/src/card/base/asn1/Chat.h +++ b/src/card/base/asn1/Chat.h @@ -1,9 +1,7 @@ /*! - * Chat.h - * * \brief Implementation of Certificate Holder Authorization Template, CHAT. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/ChipAuthenticationInfo.cpp b/src/card/base/asn1/ChipAuthenticationInfo.cpp index a4166af..df47a9a 100644 --- a/src/card/base/asn1/ChipAuthenticationInfo.cpp +++ b/src/card/base/asn1/ChipAuthenticationInfo.cpp @@ -1,7 +1,5 @@ /*! - * ChipAuthenticationInfo.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -49,15 +47,17 @@ void freeAsn1Object(chipauthenticationinfo_st* pObjec bool ChipAuthenticationInfo::acceptsProtocol(const ASN1_OBJECT* pObjectIdentifier) { + using namespace KnownOIDs; + const auto protocol = Asn1ObjectUtil::convertTo(pObjectIdentifier); - return protocol == id_CA::DH_3DES_CBC_CBC - || protocol == id_CA::DH_AES_CBC_CMAC_128 - || protocol == id_CA::DH_AES_CBC_CMAC_192 - || protocol == id_CA::DH_AES_CBC_CMAC_256 - || protocol == id_CA::ECDH_3DES_CBC_CBC - || protocol == id_CA::ECDH_AES_CBC_CMAC_128 - || protocol == id_CA::ECDH_AES_CBC_CMAC_192 - || protocol == id_CA::ECDH_AES_CBC_CMAC_256; + return protocol == id_ca::DH_3DES_CBC_CBC + || protocol == id_ca::DH_AES_CBC_CMAC_128 + || protocol == id_ca::DH_AES_CBC_CMAC_192 + || protocol == id_ca::DH_AES_CBC_CMAC_256 + || protocol == id_ca::ECDH_3DES_CBC_CBC + || protocol == id_ca::ECDH_AES_CBC_CMAC_128 + || protocol == id_ca::ECDH_AES_CBC_CMAC_192 + || protocol == id_ca::ECDH_AES_CBC_CMAC_256; } diff --git a/src/card/base/asn1/ChipAuthenticationInfo.h b/src/card/base/asn1/ChipAuthenticationInfo.h index 06851e2..30f9fa7 100644 --- a/src/card/base/asn1/ChipAuthenticationInfo.h +++ b/src/card/base/asn1/ChipAuthenticationInfo.h @@ -1,9 +1,7 @@ /*! - * ChipAuthenticationInfo.h - * * \brief Implementation of ChipAuthenticationInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/EFCardSecurity.cpp b/src/card/base/asn1/EFCardSecurity.cpp index 1845a43..34e7b8a 100644 --- a/src/card/base/asn1/EFCardSecurity.cpp +++ b/src/card/base/asn1/EFCardSecurity.cpp @@ -1,7 +1,5 @@ /*! - * EFCardSecurity.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -54,14 +52,14 @@ QSharedPointer EFCardSecurity::decode(const QByteArray& pBytes) } const auto type = Asn1ObjectUtil::convertTo(CMS_get0_type(contentInfo.data())); - if (type != KnownOIDs::signedData) + if (type != KnownOIDs::Base::SIGNED_DATA) { qCCritical(card) << "Got unexpected ContentInfo type" << type; return QSharedPointer(); } const auto eContentType = Asn1ObjectUtil::convertTo(CMS_get0_eContentType(contentInfo.data())); - if (eContentType != KnownOIDs::id_SecurityObject) + if (eContentType != KnownOIDs::Base::ID_SECURITY_OBJECT) { qCCritical(card) << "Got unexpected eContentType" << eContentType; return QSharedPointer(); diff --git a/src/card/base/asn1/EFCardSecurity.h b/src/card/base/asn1/EFCardSecurity.h index 238a314..b7f9193 100644 --- a/src/card/base/asn1/EFCardSecurity.h +++ b/src/card/base/asn1/EFCardSecurity.h @@ -1,9 +1,7 @@ /*! - * EFCardSecurity.h - * * \brief Implementation of EFCardSecurity * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/src/card/base/asn1/EcdsaPublicKey.cpp b/src/card/base/asn1/EcdsaPublicKey.cpp index fab4d07..a91d5d6 100644 --- a/src/card/base/asn1/EcdsaPublicKey.cpp +++ b/src/card/base/asn1/EcdsaPublicKey.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -103,13 +103,13 @@ QByteArray EcdsaPublicKey::getPublicKeyOid() const QByteArray EcdsaPublicKey::getPublicKeyOidValueBytes() const { - return QByteArray(reinterpret_cast(mObjectIdentifier->data), mObjectIdentifier->length); + return Asn1ObjectUtil::getValue(mObjectIdentifier); } QByteArray EcdsaPublicKey::getUncompressedPublicPoint() const { - return QByteArray(reinterpret_cast(mPublicPoint->data), mPublicPoint->length); + return Asn1OctetStringUtil::getValue(mPublicPoint); } diff --git a/src/card/base/asn1/EcdsaPublicKey.h b/src/card/base/asn1/EcdsaPublicKey.h index 4afe5b2..9a10a58 100644 --- a/src/card/base/asn1/EcdsaPublicKey.h +++ b/src/card/base/asn1/EcdsaPublicKey.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/KnownOIDs.cpp b/src/card/base/asn1/KnownOIDs.cpp new file mode 100644 index 0000000..27c15d3 --- /dev/null +++ b/src/card/base/asn1/KnownOIDs.cpp @@ -0,0 +1,280 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + */ + +#include "KnownOIDs.h" + +using namespace governikus::KnownOIDs; + + +QByteArray governikus::toByteArray(Base pValue) +{ + switch (pValue) + { + case Base::BSI_DE: + return QByteArrayLiteral("0.4.0.127.0.7"); + + case Base::SIGNED_DATA: + return QByteArrayLiteral("1.2.840.113549.1.7.2"); + + case Base::ID_SECURITY_OBJECT: + return QByteArrayLiteral("0.4.0.127.0.7.3.2.1"); + + case Base::ID_EXTENSIONS: + return Base::BSI_DE + QByteArrayLiteral(".3.1.3"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(CertificateExtensions pValue) +{ + switch (pValue) + { + case CertificateExtensions::ID_DESCRIPTION: + return Base::ID_EXTENSIONS + QByteArrayLiteral(".1"); + + case CertificateExtensions::ID_SECTOR: + return Base::ID_EXTENSIONS + QByteArrayLiteral(".2"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(TermsOfUsageType pValue) +{ + switch (pValue) + { + case TermsOfUsageType::ID_PLAIN_FORMAT: + return CertificateExtensions::ID_DESCRIPTION + QByteArrayLiteral(".1"); + + case TermsOfUsageType::ID_HTML_FORMAT: + return CertificateExtensions::ID_DESCRIPTION + QByteArrayLiteral(".2"); + + case TermsOfUsageType::ID_PDF_FORMAT: + return CertificateExtensions::ID_DESCRIPTION + QByteArrayLiteral(".3"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(CHATType pValue) +{ + switch (pValue) + { + case CHATType::ID_IS: + // OID for the CHAT type inspection systems. + return Base::BSI_DE + QByteArrayLiteral(".3.1.2.1"); + + case CHATType::ID_AT: + // OID for the CHAT type authentication terminals. + return Base::BSI_DE + QByteArrayLiteral(".3.1.2.2"); + + case CHATType::ID_ST: + // OID for the CHAT type signature terminals. + return Base::BSI_DE + QByteArrayLiteral(".3.1.2.3"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(AuxilaryData pValue) +{ + switch (pValue) + { + case AuxilaryData::ID_DATE_OF_BIRTH: + return Base::BSI_DE + QByteArrayLiteral(".3.1.4.1"); + + case AuxilaryData::ID_DATE_OF_EXPIRY: + return Base::BSI_DE + QByteArrayLiteral(".3.1.4.2"); + + case AuxilaryData::ID_COMMUNITY_ID: + return Base::BSI_DE + QByteArrayLiteral(".3.1.4.3"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(SecurityProtocol pValue) +{ + switch (pValue) + { + case SecurityProtocol::ID_PK: + return Base::BSI_DE + QByteArrayLiteral(".2.2.1"); + + case SecurityProtocol::ID_TA: + return Base::BSI_DE + QByteArrayLiteral(".2.2.2"); + + case SecurityProtocol::ID_CA: + return Base::BSI_DE + QByteArrayLiteral(".2.2.3"); + + case SecurityProtocol::ID_PACE: + return Base::BSI_DE + QByteArrayLiteral(".2.2.4"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(id_ca pValue) +{ + switch (pValue) + { + case id_ca::DH: + return SecurityProtocol::ID_CA + QByteArrayLiteral(".1"); + + case id_ca::DH_3DES_CBC_CBC: + return id_ca::DH + QByteArrayLiteral(".1"); + + case id_ca::DH_AES_CBC_CMAC_128: + return id_ca::DH + QByteArrayLiteral(".2"); + + case id_ca::DH_AES_CBC_CMAC_192: + return id_ca::DH + QByteArrayLiteral(".3"); + + case id_ca::DH_AES_CBC_CMAC_256: + return id_ca::DH + QByteArrayLiteral(".4"); + + + case id_ca::ECDH: + return SecurityProtocol::ID_CA + QByteArrayLiteral(".2"); + + case id_ca::ECDH_3DES_CBC_CBC: + return id_ca::ECDH + QByteArrayLiteral(".1"); + + case id_ca::ECDH_AES_CBC_CMAC_128: + return id_ca::ECDH + QByteArrayLiteral(".2"); + + case id_ca::ECDH_AES_CBC_CMAC_192: + return id_ca::ECDH + QByteArrayLiteral(".3"); + + case id_ca::ECDH_AES_CBC_CMAC_256: + return id_ca::ECDH + QByteArrayLiteral(".4"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(id_ta pValue) +{ + switch (pValue) + { + case id_ta::ECDSA_SHA_1: + return SecurityProtocol::ID_TA + QByteArrayLiteral(".2.1"); + + case id_ta::ECDSA_SHA_224: + return SecurityProtocol::ID_TA + QByteArrayLiteral(".2.2"); + + case id_ta::ECDSA_SHA_256: + return SecurityProtocol::ID_TA + QByteArrayLiteral(".2.3"); + + case id_ta::ECDSA_SHA_384: + return SecurityProtocol::ID_TA + QByteArrayLiteral(".2.4"); + + case id_ta::ECDSA_SHA_512: + return SecurityProtocol::ID_TA + QByteArrayLiteral(".2.5"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(id_pk pValue) +{ + switch (pValue) + { + case id_pk::DH: + return SecurityProtocol::ID_PK + QByteArrayLiteral(".1"); + + case id_pk::ECDH: + return SecurityProtocol::ID_PK + QByteArrayLiteral(".2"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(id_PACE::DH pValue) +{ + switch (pValue) + { + case id_PACE::DH::GM: + return SecurityProtocol::ID_PACE + QByteArrayLiteral(".1"); + + case id_PACE::DH::GM_3DES_CBC_CBC: + return id_PACE::DH::GM + QByteArrayLiteral(".1"); + + case id_PACE::DH::GM_AES_CBC_CMAC_128: + return id_PACE::DH::GM + QByteArrayLiteral(".2"); + + case id_PACE::DH::GM_AES_CBC_CMAC_192: + return id_PACE::DH::GM + QByteArrayLiteral(".3"); + + case id_PACE::DH::GM_AES_CBC_CMAC_256: + return id_PACE::DH::GM + QByteArrayLiteral(".4"); + + + case id_PACE::DH::IM: + return SecurityProtocol::ID_PACE + QByteArrayLiteral(".3"); + + case id_PACE::DH::IM_3DES_CBC_CBC: + return id_PACE::DH::IM + QByteArrayLiteral(".1"); + + case id_PACE::DH::IM_AES_CBC_CMAC_128: + return id_PACE::DH::IM + QByteArrayLiteral(".2"); + + case id_PACE::DH::IM_AES_CBC_CMAC_192: + return id_PACE::DH::IM + QByteArrayLiteral(".3"); + + case id_PACE::DH::IM_AES_CBC_CMAC_256: + return id_PACE::DH::IM + QByteArrayLiteral(".4"); + } + + Q_UNREACHABLE(); +} + + +QByteArray governikus::toByteArray(id_PACE::ECDH pValue) +{ + switch (pValue) + { + case id_PACE::ECDH::GM: + return SecurityProtocol::ID_PACE + QByteArrayLiteral(".2"); + + case id_PACE::ECDH::GM_3DES_CBC_CBC: + return id_PACE::ECDH::GM + QByteArrayLiteral(".1"); + + case id_PACE::ECDH::GM_AES_CBC_CMAC_128: + return id_PACE::ECDH::GM + QByteArrayLiteral(".2"); + + case id_PACE::ECDH::GM_AES_CBC_CMAC_192: + return id_PACE::ECDH::GM + QByteArrayLiteral(".3"); + + case id_PACE::ECDH::GM_AES_CBC_CMAC_256: + return id_PACE::ECDH::GM + QByteArrayLiteral(".4"); + + + case id_PACE::ECDH::IM: + return SecurityProtocol::ID_PACE + QByteArrayLiteral(".4"); + + case id_PACE::ECDH::IM_3DES_CBC_CBC: + return id_PACE::ECDH::IM + QByteArrayLiteral(".1"); + + case id_PACE::ECDH::IM_AES_CBC_CMAC_128: + return id_PACE::ECDH::IM + QByteArrayLiteral(".2"); + + case id_PACE::ECDH::IM_AES_CBC_CMAC_192: + return id_PACE::ECDH::IM + QByteArrayLiteral(".3"); + + case id_PACE::ECDH::IM_AES_CBC_CMAC_256: + return id_PACE::ECDH::IM + QByteArrayLiteral(".4"); + } + + Q_UNREACHABLE(); +} diff --git a/src/card/base/asn1/KnownOIDs.h b/src/card/base/asn1/KnownOIDs.h index 689914a..d7af500 100644 --- a/src/card/base/asn1/KnownOIDs.h +++ b/src/card/base/asn1/KnownOIDs.h @@ -1,152 +1,154 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include -// -// Note: It may be a good idea to keep the namespace indentation here. -// - namespace governikus { + namespace KnownOIDs { - -const QByteArray bsi_de(QByteArrayLiteral("0.4.0.127.0.7")); - -const QByteArray signedData(QByteArrayLiteral("1.2.840.113549.1.7.2")); - -const QByteArray id_SecurityObject(QByteArrayLiteral("0.4.0.127.0.7.3.2.1")); - -const QByteArray id_extensions = bsi_de + QByteArrayLiteral(".3.1.3"); - - -namespace CertificateExtensions +enum class Base { -const QByteArray id_description = id_extensions + ".1"; + BSI_DE, + SIGNED_DATA, + ID_SECURITY_OBJECT, + ID_EXTENSIONS +}; -const QByteArray id_sector = id_extensions + ".2"; -} - -namespace TermsOfUsageType +enum class CertificateExtensions { + ID_DESCRIPTION, + ID_SECTOR +}; -/** - * OID for the terms of usage type plain text. - */ -const QByteArray id_plainFormat = CertificateExtensions::id_description + ".1"; - -/** - * OID for the terms of usage type html. - */ -const QByteArray id_htmlFormat = CertificateExtensions::id_description + ".2"; - -/** - * OID for the terms of usage type pdf. - */ -const QByteArray id_pdfFormat = CertificateExtensions::id_description + ".3"; -} - -namespace CHATType +enum class TermsOfUsageType { -/** - * OID for the CHAT type inspection systems. - */ -const QByteArray id_IS = bsi_de + ".3.1.2.1"; + ID_PLAIN_FORMAT, + ID_HTML_FORMAT, + ID_PDF_FORMAT +}; -/** - * OID for the CHAT type authentication terminals. - */ -const QByteArray id_AT = bsi_de + ".3.1.2.2"; - -/** - * OID for the CHAT type signature terminals. - */ -const QByteArray id_ST = bsi_de + ".3.1.2.3"; -} - -namespace AuxilaryData +enum class CHATType { + ID_IS, + ID_AT, + ID_ST +}; -const QByteArray id_DateOfBirth = bsi_de + ".3.1.4.1"; - -const QByteArray id_DateOfExpiry = bsi_de + ".3.1.4.2"; - -const QByteArray id_CommunityID = bsi_de + ".3.1.4.3"; - -} - -namespace SecurityProtocol +enum class AuxilaryData { -const QByteArray id_CA = bsi_de + ".2.2.3"; -const QByteArray id_PACE = bsi_de + ".2.2.4"; -const QByteArray id_TA = bsi_de + ".2.2.2"; -const QByteArray id_PK = bsi_de + ".2.2.1"; -} + ID_DATE_OF_BIRTH, + ID_DATE_OF_EXPIRY, + ID_COMMUNITY_ID +}; -namespace id_CA +enum class SecurityProtocol { -const QByteArray DH = SecurityProtocol::id_CA + ".1"; -const QByteArray DH_3DES_CBC_CBC = SecurityProtocol::id_CA + ".1.1"; -const QByteArray DH_AES_CBC_CMAC_128 = SecurityProtocol::id_CA + ".1.2"; -const QByteArray DH_AES_CBC_CMAC_192 = SecurityProtocol::id_CA + ".1.3"; -const QByteArray DH_AES_CBC_CMAC_256 = SecurityProtocol::id_CA + ".1.4"; -const QByteArray ECDH = SecurityProtocol::id_CA + ".2"; -const QByteArray ECDH_3DES_CBC_CBC = SecurityProtocol::id_CA + ".2.1"; -const QByteArray ECDH_AES_CBC_CMAC_128 = SecurityProtocol::id_CA + ".2.2"; -const QByteArray ECDH_AES_CBC_CMAC_192 = SecurityProtocol::id_CA + ".2.3"; -const QByteArray ECDH_AES_CBC_CMAC_256 = SecurityProtocol::id_CA + ".2.4"; -} + ID_PK, + ID_TA, + ID_CA, + ID_PACE +}; -namespace id_TA +enum class id_ca { -const QByteArray ECDSA_SHA_1 = SecurityProtocol::id_TA + ".2.1"; -const QByteArray ECDSA_SHA_224 = SecurityProtocol::id_TA + ".2.2"; -const QByteArray ECDSA_SHA_256 = SecurityProtocol::id_TA + ".2.3"; -const QByteArray ECDSA_SHA_384 = SecurityProtocol::id_TA + ".2.4"; -const QByteArray ECDSA_SHA_512 = SecurityProtocol::id_TA + ".2.5"; -} + DH, + DH_3DES_CBC_CBC, + DH_AES_CBC_CMAC_128, + DH_AES_CBC_CMAC_192, + DH_AES_CBC_CMAC_256, + ECDH, + ECDH_3DES_CBC_CBC, + ECDH_AES_CBC_CMAC_128, + ECDH_AES_CBC_CMAC_192, + ECDH_AES_CBC_CMAC_256 +}; -namespace id_PK +enum class id_ta { -const QByteArray DH = SecurityProtocol::id_PK + ".1"; -const QByteArray ECDH = SecurityProtocol::id_PK + ".2"; -} + ECDSA_SHA_1, + ECDSA_SHA_224, + ECDSA_SHA_256, + ECDSA_SHA_384, + ECDSA_SHA_512 +}; + +enum class id_pk +{ + DH, + ECDH +}; namespace id_PACE { -namespace DH +enum class DH { -const QByteArray GM = SecurityProtocol::id_PACE + ".1"; -const QByteArray GM_3DES_CBC_CBC = GM + ".1"; -const QByteArray GM_AES_CBC_CMAC_128 = GM + ".2"; -const QByteArray GM_AES_CBC_CMAC_192 = GM + ".3"; -const QByteArray GM_AES_CBC_CMAC_256 = GM + ".4"; + GM, + GM_3DES_CBC_CBC, + GM_AES_CBC_CMAC_128, + GM_AES_CBC_CMAC_192, + GM_AES_CBC_CMAC_256, + IM, + IM_3DES_CBC_CBC, + IM_AES_CBC_CMAC_128, + IM_AES_CBC_CMAC_192, + IM_AES_CBC_CMAC_256, -const QByteArray IM = SecurityProtocol::id_PACE + ".3"; -const QByteArray IM_3DES_CBC_CBC = IM + ".1"; -const QByteArray IM_AES_CBC_CMAC_128 = IM + ".2"; -const QByteArray IM_AES_CBC_CMAC_192 = IM + ".3"; -const QByteArray IM_AES_CBC_CMAC_256 = IM + ".4"; -} +}; -namespace ECDH +enum class ECDH { -const QByteArray GM = SecurityProtocol::id_PACE + ".2"; -const QByteArray GM_3DES_CBC_CBC = GM + ".1"; -const QByteArray GM_AES_CBC_CMAC_128 = GM + ".2"; -const QByteArray GM_AES_CBC_CMAC_192 = GM + ".3"; -const QByteArray GM_AES_CBC_CMAC_256 = GM + ".4"; + GM, + GM_3DES_CBC_CBC, + GM_AES_CBC_CMAC_128, + GM_AES_CBC_CMAC_192, + GM_AES_CBC_CMAC_256, + IM, + IM_3DES_CBC_CBC, + IM_AES_CBC_CMAC_128, + IM_AES_CBC_CMAC_192, + IM_AES_CBC_CMAC_256 +}; -const QByteArray IM = SecurityProtocol::id_PACE + ".4"; -const QByteArray IM_3DES_CBC_CBC = IM + ".1"; -const QByteArray IM_AES_CBC_CMAC_128 = IM + ".2"; -const QByteArray IM_AES_CBC_CMAC_192 = IM + ".3"; -const QByteArray IM_AES_CBC_CMAC_256 = IM + ".4"; -} -} -} -} +} // namespace KnownOIDs::id_PACE + +} // namespace KnownOIDs + +#define DEFINE_TO_BYTE_ARRAY(type)\ + QByteArray toByteArray(type pValue);\ +\ + inline QByteArray operator+(type pEnum, const QByteArray& pValue)\ + {\ + return toByteArray(pEnum) + pValue;\ + }\ +\ + inline bool operator==(const QByteArray& pValue, type pEnum)\ + {\ + return toByteArray(pEnum) == pValue;\ + }\ +\ + inline bool operator!=(const QByteArray& pValue, type pEnum)\ + {\ + return !(pValue == pEnum);\ + } + + +DEFINE_TO_BYTE_ARRAY(KnownOIDs::Base) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::CertificateExtensions) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::TermsOfUsageType) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::CHATType) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::AuxilaryData) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::SecurityProtocol) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::id_ca) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::id_ta) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::id_pk) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::id_PACE::DH) +DEFINE_TO_BYTE_ARRAY(KnownOIDs::id_PACE::ECDH) + +#undef DEFINE_TO_BYTE_ARRAY + +} // namespace governikus diff --git a/src/card/base/asn1/PACEInfo.cpp b/src/card/base/asn1/PACEInfo.cpp index e9e30be..910df51 100644 --- a/src/card/base/asn1/PACEInfo.cpp +++ b/src/card/base/asn1/PACEInfo.cpp @@ -1,7 +1,5 @@ /*! - * PACEInfo.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ @@ -78,9 +76,9 @@ PACEInfo::PACEInfo(const QSharedPointer& pDelegate) : SecurityInfo() , mDelegate(pDelegate) { - if (getVersion() != QByteArray::fromHex("02")) + if (getVersion() != 2) { - qCWarning(card) << "Expect version=2, got: " << getVersion().toHex(); + qCWarning(card) << "Expect version=2, got: " << getVersion(); } } @@ -101,15 +99,18 @@ QByteArray PACEInfo::getParameterId() const } -QByteArray PACEInfo::getVersion() const +int PACEInfo::getVersion() const { - return Asn1IntegerUtil::getValue(mDelegate->mVersion); + const auto& version = Asn1IntegerUtil::getValue(mDelegate->mVersion); + return version.isEmpty() || version.size() > 1 ? -1 : version[0]; } KeyAgreementType PACEInfo::getKeyAgreementType() const { - if (getProtocol().startsWith(KnownOIDs::id_PACE::DH::GM) || getProtocol().startsWith(KnownOIDs::id_PACE::DH::IM)) + const auto& protocol = getProtocol(); + if (protocol.startsWith(toByteArray(KnownOIDs::id_PACE::DH::GM)) + || protocol.startsWith(toByteArray(KnownOIDs::id_PACE::DH::IM))) { return KeyAgreementType::DH; } @@ -122,7 +123,9 @@ KeyAgreementType PACEInfo::getKeyAgreementType() const MappingType PACEInfo::getMappingType() const { - if (getProtocol().startsWith(KnownOIDs::id_PACE::DH::GM) || getProtocol().startsWith(KnownOIDs::id_PACE::ECDH::GM)) + const auto& protocol = getProtocol(); + if (protocol.startsWith(toByteArray(KnownOIDs::id_PACE::DH::GM)) + || protocol.startsWith(toByteArray((KnownOIDs::id_PACE::ECDH::GM)))) { return MappingType::GM; } diff --git a/src/card/base/asn1/PACEInfo.h b/src/card/base/asn1/PACEInfo.h index e39e9b4..a231db5 100644 --- a/src/card/base/asn1/PACEInfo.h +++ b/src/card/base/asn1/PACEInfo.h @@ -1,9 +1,7 @@ /*! - * PACEInfo.h - * * \brief Implementation of PACEInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -87,7 +85,7 @@ class PACEInfo QByteArray getParameterId() const; int getParameterIdAsInt() const; - QByteArray getVersion() const; + int getVersion() const; KeyAgreementType getKeyAgreementType() const; MappingType getMappingType() const; bool isStandardizedDomainParameters() const; diff --git a/src/card/base/asn1/SecurityInfo.cpp b/src/card/base/asn1/SecurityInfo.cpp index d5ba44c..91938ef 100644 --- a/src/card/base/asn1/SecurityInfo.cpp +++ b/src/card/base/asn1/SecurityInfo.cpp @@ -1,7 +1,5 @@ /*! - * SecurityInfo.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -62,7 +60,7 @@ ASN1_OBJECT* SecurityInfo::getProtocolObjectIdentifier() const QByteArray SecurityInfo::getProtocolValueBytes() const { - return QByteArray(reinterpret_cast(getProtocolObjectIdentifier()->data), getProtocolObjectIdentifier()->length); + return Asn1ObjectUtil::getValue(getProtocolObjectIdentifier()); } diff --git a/src/card/base/asn1/SecurityInfo.h b/src/card/base/asn1/SecurityInfo.h index c5e2da5..d033a94 100644 --- a/src/card/base/asn1/SecurityInfo.h +++ b/src/card/base/asn1/SecurityInfo.h @@ -1,9 +1,7 @@ /*! - * SecurityInfo.h - * * \brief Implementation of SecurityInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -35,8 +33,11 @@ struct securityinfo_st }; DECLARE_ASN1_FUNCTIONS(securityinfo_st) +#if OPENSSL_VERSION_NUMBER < 0x10100000L DECLARE_STACK_OF(securityinfo_st) - +#else +DEFINE_STACK_OF(securityinfo_st) +#endif /* * Because OpenSSL's template macro system does not support inheritance, diff --git a/src/card/base/asn1/SecurityInfos.cpp b/src/card/base/asn1/SecurityInfos.cpp index 483e666..aecdb8f 100644 --- a/src/card/base/asn1/SecurityInfos.cpp +++ b/src/card/base/asn1/SecurityInfos.cpp @@ -1,7 +1,5 @@ /*! - * SecurityInfos.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ASN1TemplateUtil.h" @@ -27,7 +25,12 @@ IMPLEMENT_ASN1_FUNCTIONS(securityinfos_st) IMPLEMENT_ASN1_OBJECT(securityinfos_st) -} // namespace governikus +#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define sk_securityinfo_st_num(data) SKM_sk_num(securityinfo_st, data) + #define sk_securityinfo_st_value(data, i) SKM_sk_value(securityinfo_st, data, i) +#endif + +} /* namespace governikus */ QSharedPointer SecurityInfos::fromHex(const QByteArray& pHexString) @@ -48,9 +51,9 @@ QSharedPointer SecurityInfos::decode(const QByteArray& pBytes) QVector > paceInfos; QVector > chipAuthenticationInfos; - for (int i = 0; i < SKM_sk_num(securityinfo_st, securityInfosStruct.data()); ++i) + for (int i = 0; i < sk_securityinfo_st_num(securityInfosStruct.data()); ++i) { - securityinfo_st* secInfoStruct = SKM_sk_value(securityinfo_st, securityInfosStruct.data(), i); + securityinfo_st* secInfoStruct = sk_securityinfo_st_value(securityInfosStruct.data(), i); QByteArray bytes = encodeObject(secInfoStruct); if (auto pi = PACEInfo::decode(bytes)) diff --git a/src/card/base/asn1/SecurityInfos.h b/src/card/base/asn1/SecurityInfos.h index a5c0b92..80be318 100644 --- a/src/card/base/asn1/SecurityInfos.h +++ b/src/card/base/asn1/SecurityInfos.h @@ -1,9 +1,7 @@ /*! - * SecurityInfos.h - * * \brief Implementation of SecurityInfos * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/asn1/SignatureChecker.cpp b/src/card/base/asn1/SignatureChecker.cpp index 4507424..6456a7a 100644 --- a/src/card/base/asn1/SignatureChecker.cpp +++ b/src/card/base/asn1/SignatureChecker.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/SignatureChecker.h" @@ -15,7 +15,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -SignatureChecker::SignatureChecker(const QVector >& pCertificateChain) +SignatureChecker::SignatureChecker(const QVector >& pCertificateChain) : mCertificateChain(pCertificateChain) { } @@ -68,7 +68,7 @@ bool SignatureChecker::checkSignature(const QSharedPointer& EC_POINT* publicPoint = EC_POINT_new(EC_KEY_get0_group(signingKey.data())); const EC_GROUP* ecGroup = EC_KEY_get0_group(signingKey.data()); - if (!EC_POINT_oct2point(ecGroup, publicPoint, uncompPublicPointData, uncompPublicPointLen, (BN_CTX*) nullptr)) + if (!EC_POINT_oct2point(ecGroup, publicPoint, uncompPublicPointData, uncompPublicPointLen, nullptr)) { qCCritical(card) << "Cannot decode uncompressed public point"; return false; diff --git a/src/card/base/asn1/SignatureChecker.h b/src/card/base/asn1/SignatureChecker.h index b142375..94fe6fb 100644 --- a/src/card/base/asn1/SignatureChecker.h +++ b/src/card/base/asn1/SignatureChecker.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -15,12 +15,12 @@ namespace governikus class SignatureChecker { private: - const QVector > mCertificateChain; + const QVector > mCertificateChain; bool checkSignature(const QSharedPointer& pCert, const QSharedPointer& pSigningCert, const EC_KEY* pKey); public: - SignatureChecker(const QVector >& pCertificateChain); + SignatureChecker(const QVector >& pCertificateChain); ~SignatureChecker() = default; bool check(); diff --git a/src/card/base/command/BaseCardCommand.cpp b/src/card/base/command/BaseCardCommand.cpp index 4b62d8d..d43f50a 100644 --- a/src/card/base/command/BaseCardCommand.cpp +++ b/src/card/base/command/BaseCardCommand.cpp @@ -1,10 +1,12 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "asn1/SecurityInfos.h" #include "BaseCardCommand.h" + +#include "asn1/SecurityInfos.h" #include "CardConnection.h" +#include "Initializer.h" #include #include @@ -14,6 +16,11 @@ Q_DECLARE_LOGGING_CATEGORY(card) using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType >("QSharedPointer"); + }); + + BaseCardCommand::BaseCardCommand(QSharedPointer pCardConnectionWorker) : mCardConnectionWorker(pCardConnectionWorker) , mReturnCode(CardReturnCode::UNKNOWN) @@ -52,7 +59,7 @@ CardReturnCode BaseCardCommand::checkRetryCounterAndPrepareForPace(const QString case 1: // CAN required { EstablishPACEChannelOutput output; - return mCardConnectionWorker->establishPaceChannel(PACE_PIN_ID::PACE_CAN, pCan, output); + return mCardConnectionWorker->establishPaceChannel(PACE_PASSWORD_ID::PACE_CAN, pCan, output); } case 2: @@ -64,14 +71,3 @@ CardReturnCode BaseCardCommand::checkRetryCounterAndPrepareForPace(const QString 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 468ca82..627267c 100644 --- a/src/card/base/command/BaseCardCommand.h +++ b/src/card/base/command/BaseCardCommand.h @@ -1,7 +1,7 @@ /*! * \brief Holds some basic card control commands * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -46,8 +46,6 @@ class BaseCardCommand } - 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 c2f90b7..ca6bbcc 100644 --- a/src/card/base/command/CreateCardConnectionCommand.cpp +++ b/src/card/base/command/CreateCardConnectionCommand.cpp @@ -1,15 +1,20 @@ /*! - * CreateCardConnectionCommand.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ + #include "CreateCardConnectionCommand.h" + +#include "Initializer.h" #include "ReaderManagerWorker.h" #include using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType >("QSharedPointer"); + }); + CreateCardConnectionCommand::CreateCardConnectionCommand(const QString& pReaderName, const QPointer& pReaderManagerWorker) : QObject() @@ -55,12 +60,7 @@ QSharedPointer CreateCardConnectionCommand::getCardConnection() } -void CreateCardConnectionCommand::registerMetaTypes() +const QString& CreateCardConnectionCommand::getReaderName() const { - static bool registered = false; - if (!registered) - { - qRegisterMetaType >("QSharedPointer"); - registered = true; - } + return mReaderName; } diff --git a/src/card/base/command/CreateCardConnectionCommand.h b/src/card/base/command/CreateCardConnectionCommand.h index 58f5230..b946eb9 100644 --- a/src/card/base/command/CreateCardConnectionCommand.h +++ b/src/card/base/command/CreateCardConnectionCommand.h @@ -1,9 +1,7 @@ /*! - * CreateCardConnectionCommand.h - * * \brief Command implementation for asynchronous CardConnection creation * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -28,7 +26,7 @@ class CreateCardConnectionCommand Q_OBJECT private: - QString mReaderName; + const QString mReaderName; QPointer mReaderManagerWorker; QSharedPointer mCardConnection; @@ -36,7 +34,7 @@ class CreateCardConnectionCommand CreateCardConnectionCommand(const QString& pReaderName, const QPointer& pReaderManagerWorker); Q_INVOKABLE void execute(); QSharedPointer getCardConnection() const; - static void registerMetaTypes(); + const QString& getReaderName() const; private Q_SLOTS: void onCardConnectionWorkerCreated(QSharedPointer pCardConnectionWorker); diff --git a/src/card/base/command/DestroyPaceChannelCommand.cpp b/src/card/base/command/DestroyPaceChannelCommand.cpp index e68cae4..aff3de9 100644 --- a/src/card/base/command/DestroyPaceChannelCommand.cpp +++ b/src/card/base/command/DestroyPaceChannelCommand.cpp @@ -1,7 +1,5 @@ /*! - * DestroyPaceChannelCommand.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" diff --git a/src/card/base/command/DestroyPaceChannelCommand.h b/src/card/base/command/DestroyPaceChannelCommand.h index d38e755..6df3744 100644 --- a/src/card/base/command/DestroyPaceChannelCommand.h +++ b/src/card/base/command/DestroyPaceChannelCommand.h @@ -1,9 +1,7 @@ /*! - * DestroyPaceChannelCommand.h - * * \brief Command to destroy a Pace channel. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +20,7 @@ class DestroyPaceChannelCommand protected: virtual void internalExecute() override; - virtual ~DestroyPaceChannelCommand(); + virtual ~DestroyPaceChannelCommand() override; public: DestroyPaceChannelCommand(QSharedPointer pCardConnectionWorker); diff --git a/src/card/base/command/DidAuthenticateEAC1Command.cpp b/src/card/base/command/DidAuthenticateEAC1Command.cpp index 8d4bc14..20760d9 100644 --- a/src/card/base/command/DidAuthenticateEAC1Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC1Command.cpp @@ -1,7 +1,5 @@ /*! - * DidAuthenticateEAC1Command.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "BaseCardCommand.h" @@ -36,7 +34,6 @@ void DidAuthenticateEAC1Command::internalExecute() if (mReturnCode != CardReturnCode::OK || response.getReturnCode() != StatusCode::SUCCESS) { qCWarning(card) << "GetChallenge failed"; - mReturnCode = CardReturnCode::GET_CHALLENGE_FAILED; return; } mChallenge = response.getChallenge(); diff --git a/src/card/base/command/DidAuthenticateEAC1Command.h b/src/card/base/command/DidAuthenticateEAC1Command.h index 0522882..d7497ba 100644 --- a/src/card/base/command/DidAuthenticateEAC1Command.h +++ b/src/card/base/command/DidAuthenticateEAC1Command.h @@ -1,9 +1,7 @@ /*! - * DidAuthenticateEAC1Command.h - * * \brief Command to perform the DID Authenticate EAC1 process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -27,7 +25,7 @@ class DidAuthenticateEAC1Command protected: virtual void internalExecute() override; - virtual ~DidAuthenticateEAC1Command(); + virtual ~DidAuthenticateEAC1Command() override; public: DidAuthenticateEAC1Command(QSharedPointer pCardConnectionWorker); diff --git a/src/card/base/command/DidAuthenticateEAC2Command.cpp b/src/card/base/command/DidAuthenticateEAC2Command.cpp index e3e3981..e0f85e7 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC2Command.cpp @@ -1,18 +1,18 @@ /*! - * DidAuthenticateEAC2Command.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "DidAuthenticateEAC2Command.h" + #include "asn1/ChipAuthenticationInfo.h" #include "asn1/EFCardSecurity.h" #include "CardConnection.h" -#include "DidAuthenticateEAC2Command.h" #include "GeneralAuthenticateResponse.h" - +#include "GlobalStatus.h" #include + Q_DECLARE_LOGGING_CATEGORY(card) @@ -57,7 +57,7 @@ void DidAuthenticateEAC2Command::internalExecute() /* * According to TR-03111, chapter 3.2.1 the uncompressed encoding of an elliptic curve point is: * 0x04 | xCoordinate | yCoordinate - * In contrast the AGETO server just sends xCoordinate | yCoordinate. + * In contrast the AGETO and mtG server just sends xCoordinate | yCoordinate. * * We fix this by prepending 0x04 */ diff --git a/src/card/base/command/DidAuthenticateEAC2Command.h b/src/card/base/command/DidAuthenticateEAC2Command.h index 3f50c16..873c0e4 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.h +++ b/src/card/base/command/DidAuthenticateEAC2Command.h @@ -1,9 +1,7 @@ /*! - * DidAuthenticateEAC2Command.h - * * \brief Command to perform the DID Authenticate EAC2 process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -44,7 +42,7 @@ class DidAuthenticateEAC2Command protected: virtual void internalExecute() override; - virtual ~DidAuthenticateEAC2Command(); + virtual ~DidAuthenticateEAC2Command() override; public: DidAuthenticateEAC2Command(QSharedPointer pCardConnectionWorker, diff --git a/src/card/base/command/EstablishPaceChannelCommand.cpp b/src/card/base/command/EstablishPaceChannelCommand.cpp index a5970b3..accb166 100644 --- a/src/card/base/command/EstablishPaceChannelCommand.cpp +++ b/src/card/base/command/EstablishPaceChannelCommand.cpp @@ -1,7 +1,5 @@ /*! - * EstablishPaceChannelCommand.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -12,16 +10,17 @@ using namespace governikus; EstablishPaceChannelCommand::EstablishPaceChannelCommand(QSharedPointer pCardConnectionWorker, - PACE_PIN_ID pPacePinId, - const QString& pPacePin, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription) + PACE_PASSWORD_ID pPacePasswordId, + const QString& pPacePassword, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription) : BaseCardCommand(pCardConnectionWorker) - , mPacePinId(pPacePinId) - , mPacePin(pPacePin) + , mPacePasswordId(pPacePasswordId) + , mPacePassword(pPacePassword) , mEffectiveChat(pEffectiveChat) , mCertificateDescription(pCertificateDescription) + , mPaceOutput() { // This command only supports PIN and CAN. - Q_ASSERT(mPacePinId == PACE_PIN_ID::PACE_PIN || mPacePinId == PACE_PIN_ID::PACE_CAN); + Q_ASSERT(mPacePasswordId == PACE_PASSWORD_ID::PACE_PIN || mPacePasswordId == PACE_PASSWORD_ID::PACE_CAN); } @@ -38,5 +37,5 @@ const EstablishPACEChannelOutput& EstablishPaceChannelCommand::getPaceOutput() c void EstablishPaceChannelCommand::internalExecute() { - mReturnCode = mCardConnectionWorker->establishPaceChannel(mPacePinId, mPacePin, mEffectiveChat, mCertificateDescription, mPaceOutput); + mReturnCode = mCardConnectionWorker->establishPaceChannel(mPacePasswordId, mPacePassword, mEffectiveChat, mCertificateDescription, mPaceOutput); } diff --git a/src/card/base/command/EstablishPaceChannelCommand.h b/src/card/base/command/EstablishPaceChannelCommand.h index 990697e..36b8ccd 100644 --- a/src/card/base/command/EstablishPaceChannelCommand.h +++ b/src/card/base/command/EstablishPaceChannelCommand.h @@ -1,9 +1,7 @@ /*! - * EstablishPaceChannelCommand.h - * * \brief Command to change the PIN of a card. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,19 +19,19 @@ class EstablishPaceChannelCommand Q_OBJECT private: - const PACE_PIN_ID mPacePinId; - const QString mPacePin; + const PACE_PASSWORD_ID mPacePasswordId; + const QString mPacePassword; const QByteArray mEffectiveChat; const QByteArray mCertificateDescription; EstablishPACEChannelOutput mPaceOutput; protected: virtual void internalExecute() override; - virtual ~EstablishPaceChannelCommand(); + virtual ~EstablishPaceChannelCommand() override; public: EstablishPaceChannelCommand(QSharedPointer pCardConnectionWorker, - PACE_PIN_ID pPacePinId, const QString& pPacePin, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription); + PACE_PASSWORD_ID pPacePasswordId, const QString& pPacePassword, const QByteArray& pEffectiveChat, const QByteArray& pCertificateDescription); const EstablishPACEChannelOutput& getPaceOutput() const; }; diff --git a/src/card/base/command/SetEidPinCommand.cpp b/src/card/base/command/SetEidPinCommand.cpp index 5cf6d8f..afbab77 100644 --- a/src/card/base/command/SetEidPinCommand.cpp +++ b/src/card/base/command/SetEidPinCommand.cpp @@ -1,7 +1,5 @@ /*! - * SetEidPinCommand.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" diff --git a/src/card/base/command/SetEidPinCommand.h b/src/card/base/command/SetEidPinCommand.h index 7873b46..b46fedd 100644 --- a/src/card/base/command/SetEidPinCommand.h +++ b/src/card/base/command/SetEidPinCommand.h @@ -1,9 +1,7 @@ /*! - * SetEidPinCommand.h - * * \brief Command to set the Eid PIN of a card. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,7 +24,7 @@ class SetEidPinCommand protected: virtual void internalExecute() override; - virtual ~SetEidPinCommand(); + virtual ~SetEidPinCommand() override; public: SetEidPinCommand(QSharedPointer pCardConnectionWorker, diff --git a/src/card/base/command/TransmitCommand.cpp b/src/card/base/command/TransmitCommand.cpp index eb3b755..5d0b55e 100644 --- a/src/card/base/command/TransmitCommand.cpp +++ b/src/card/base/command/TransmitCommand.cpp @@ -1,13 +1,13 @@ /*! - * TransmitCommand.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "TransmitCommand.h" + #include "CardConnection.h" #include "CardReturnCode.h" +#include "GlobalStatus.h" #include "InputAPDUInfo.h" -#include "TransmitCommand.h" #include @@ -20,6 +20,7 @@ TransmitCommand::TransmitCommand(QSharedPointer pCardConne const QVector& pInputApduInfos) : BaseCardCommand(pCardConnectionWorker) , mInputApduInfos(pInputApduInfos) + , mReaderName(pCardConnectionWorker->getReaderInfo().getName()) , mOutputApduAsHex() { } @@ -39,9 +40,7 @@ void TransmitCommand::internalExecute() for (const auto& inputApduInfo : mInputApduInfos) { ResponseApdu response; - CommandApdu request(QByteArray::fromHex(inputApduInfo.getInputApdu())); - - mReturnCode = mCardConnectionWorker->transmit(request, response); + mReturnCode = mCardConnectionWorker->transmit(inputApduInfo.getInputApdu(), response); if (mReturnCode != CardReturnCode::OK) { qCWarning(card) << "Transmit unsuccessful. Return code:" << CardReturnCodeUtil::toGlobalStatus(mReturnCode); @@ -57,12 +56,7 @@ void TransmitCommand::internalExecute() for (const QByteArray& acceptableStatusCodeAsHex : inputApduInfo.getAcceptableStatusCodes()) { // according to TR-03112-6 chapter 3.2.5 - QByteArray acceptableStatusCode = QByteArray::fromHex(acceptableStatusCodeAsHex); - QByteArray actualStatusCode(2, 0x00); - actualStatusCode[0] = response.getSW1(); - actualStatusCode[1] = response.getSW2(); - - if (actualStatusCode.startsWith(acceptableStatusCode)) + if (response.getReturnCodeAsHex() == acceptableStatusCodeAsHex) { isAcceptable = true; break; diff --git a/src/card/base/command/TransmitCommand.h b/src/card/base/command/TransmitCommand.h index 6d786cf..854a006 100644 --- a/src/card/base/command/TransmitCommand.h +++ b/src/card/base/command/TransmitCommand.h @@ -1,9 +1,7 @@ /*! - * TransmitCommand.h - * * \brief Command to transmit data to/from the card. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,11 +21,12 @@ class TransmitCommand private: const QVector mInputApduInfos; + const QString mReaderName; QByteArrayList mOutputApduAsHex; protected: virtual void internalExecute() override; - virtual ~TransmitCommand(); + virtual ~TransmitCommand() override; public: TransmitCommand(QSharedPointer pCardConnectionWorker, @@ -39,6 +38,12 @@ class TransmitCommand } + const QString& getReaderName() const + { + return mReaderName; + } + + }; } /* namespace governikus */ diff --git a/src/card/base/command/UnblockPinCommand.cpp b/src/card/base/command/UnblockPinCommand.cpp index e07beda..bdbd558 100644 --- a/src/card/base/command/UnblockPinCommand.cpp +++ b/src/card/base/command/UnblockPinCommand.cpp @@ -1,7 +1,5 @@ /*! - * UnblockPinCommand.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -39,7 +37,7 @@ void UnblockPinCommand::internalExecute() } EstablishPACEChannelOutput output; - mReturnCode = mCardConnectionWorker->establishPaceChannel(PACE_PIN_ID::PACE_PUK, mPuk, output); + mReturnCode = mCardConnectionWorker->establishPaceChannel(PACE_PASSWORD_ID::PACE_PUK, mPuk, output); if (mReturnCode != CardReturnCode::OK) { return; @@ -48,7 +46,7 @@ void UnblockPinCommand::internalExecute() // unblock PIN (reset retry counter) ResponseApdu response; mReturnCode = mCardConnectionWorker->transmit(ResetRetryCounterBuilder().build(), response); - if (mReturnCode == CardReturnCode::OK && response.getSW1() == Enum::getValue(SW1::ERROR_COMMAND_NOT_ALLOWED)) + if (mReturnCode == CardReturnCode::OK && response.getSW1() == SW1::ERROR_COMMAND_NOT_ALLOWED) { mCardConnectionWorker->setPukInoperative(); mReturnCode = CardReturnCode::PUK_INOPERATIVE; diff --git a/src/card/base/command/UnblockPinCommand.h b/src/card/base/command/UnblockPinCommand.h index 6a1b88a..ad1f808 100644 --- a/src/card/base/command/UnblockPinCommand.h +++ b/src/card/base/command/UnblockPinCommand.h @@ -1,9 +1,7 @@ /*! - * UnblockPinCommand.h - * * \brief Command to unblock the PIN of a card. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,7 +23,7 @@ class UnblockPinCommand protected: virtual void internalExecute() override; - virtual ~UnblockPinCommand(); + virtual ~UnblockPinCommand() override; public: UnblockPinCommand(QSharedPointer pCardConnectionWorker, const QString& pPuk); diff --git a/src/card/base/command/UpdateRetryCounterCommand.cpp b/src/card/base/command/UpdateRetryCounterCommand.cpp index 557bc80..8e7c92f 100644 --- a/src/card/base/command/UpdateRetryCounterCommand.cpp +++ b/src/card/base/command/UpdateRetryCounterCommand.cpp @@ -1,7 +1,5 @@ /*! - * UpdateRetryCounterCommand.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" diff --git a/src/card/base/command/UpdateRetryCounterCommand.h b/src/card/base/command/UpdateRetryCounterCommand.h index bc1a74d..1eaa326 100644 --- a/src/card/base/command/UpdateRetryCounterCommand.h +++ b/src/card/base/command/UpdateRetryCounterCommand.h @@ -1,9 +1,7 @@ /*! - * UpdateRetryCounterCommand.h - * * \brief Command to update the retry counter of a card. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +20,7 @@ class UpdateRetryCounterCommand protected: virtual void internalExecute() override; - virtual ~UpdateRetryCounterCommand(); + virtual ~UpdateRetryCounterCommand() override; public: UpdateRetryCounterCommand(QSharedPointer pCardConnectionWorker); diff --git a/src/card/base/pace/CipherMac.cpp b/src/card/base/pace/CipherMac.cpp index c5d47fb..a0889ae 100644 --- a/src/card/base/pace/CipherMac.cpp +++ b/src/card/base/pace/CipherMac.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" @@ -7,6 +7,7 @@ #include #include +#include using namespace governikus; @@ -104,26 +105,29 @@ QByteArray CipherMac::generate(const QByteArray& pMessage) return QByteArray(); } - 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)); + + const int mac_int_len = static_cast(mac_len); + if (mac_int_len <= 0) + { + qCCritical(card) << "Got negative mac_len" << mac_int_len; + Q_ASSERT(mac_int_len > 0); + return QByteArray(); + } + + QVarLengthArray mac(mac_int_len); if (!CMAC_Final(mCtx, mac.data(), &mac_len)) { qCCritical(card) << "Error on CMAC_Final"; return QByteArray(); } - QByteArray value(reinterpret_cast(mac.data()), static_cast(mac_len)); + QByteArray value(reinterpret_cast(mac.data()), mac_int_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/CipherMac.h b/src/card/base/pace/CipherMac.h index 920d39d..e328387 100644 --- a/src/card/base/pace/CipherMac.h +++ b/src/card/base/pace/CipherMac.h @@ -1,9 +1,7 @@ /*! - * CipherMac.h - * * \brief CMAC implementation to be used in PACE protocol. See TR 03110. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/pace/DomainParameterMapping.h b/src/card/base/pace/DomainParameterMapping.h index eb4c543..e7e77fa 100644 --- a/src/card/base/pace/DomainParameterMapping.h +++ b/src/card/base/pace/DomainParameterMapping.h @@ -1,9 +1,7 @@ /*! - * DomainParameterMapping.h - * * \brief Mapping protocol for PACE domain parameters. For details see TR 03110. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/pace/EstablishPACEChannelCode.h b/src/card/base/pace/EstablishPACEChannelCode.h new file mode 100644 index 0000000..953a64d --- /dev/null +++ b/src/card/base/pace/EstablishPACEChannelCode.h @@ -0,0 +1,102 @@ +/*! + * \brief EstablishPACEChannel error code definitions + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" + +namespace governikus +{ + + +// +// EstablishPACEChannel error codes according to TR-03119, D.1.2 +// +defineTypedEnumType(EstablishPACEChannelErrorCode, quint32, + NoError + = 0x00000000, + + // Error in input data + InconsistentLengthsInInput + = 0xD0000001, + UnexpectedDataInInput + = 0xD0000002, + UnexpectedCombinationOfDataInInput + = 0xD0000003, + + // Errors during protocol execution + SyntaxErrorInTLVResponse + = 0xE0000001, + UnexpectedOrMissingObjectInTLVResponse + = 0xE0000002, + UnknownPasswordID + = 0xE0000003, + WrongAuthenticationToken + = 0xE0000006, + CertificateChainForTerminalAuthenticationCannotBeBuilt + = 0xE0000007, + UnexpectedDataStructureInResponseToChipAuthentication + = 0xE0000008, + PassiveAuthenticationFailed + = 0xE0000009, + IncorrectTokenForChipAuthentication + = 0xE000000A, + + // Response APDU of the card reports error (status code SW1SW2) + // Select EF.CardAccess + // 0xF000SW1SW2 + // Read Binary EF.CardAccess + // 0xF001SW1SW2 + // MSE: Set AT für PACE + // 0xF002SW1SW2 + // General Authenticate Step 1 - 4 + // 0xF003SW1SW2 – 0xF006SW1SW2 + + // A specific case with "SW1 == 0x63 == warning" and a "dummy SW2". + GeneralAuthenticateStep1_4_Warning + = 0xf0066300, + + // APDU created by PCD for terminal/chip authentication reports error (status code SW1SW2) + // MSE: Set DST (first certificate) + // 0xF800SW1SW2 + // PSO: Verify Certificate (first certificate) + // 0xF801SW1SW2 + // MSE: Set DST (second certificate) + // 0xF802SW1SW2 + // PSO: Verify Certificate (second certificate) + // 0xF803SW1SW2 + // MSE: Set DST (third certificate) + // 0xF804SW1SW2 + // PSO: Verify Certificate (third certificate) + // 0xF805SW1SW2 + // MSE: Set AT for terminal authentication + // 0xF806SW1SW2 + // Get Challenge + // 0xF807SW1SW2 + // External Authenticate + // 0xF808SW1SW2 + // Select EF.CardSecurity + // 0xF809SW1SW2 + // Read Binary EF.CardSecurity + // 0xF80ASW1SW2 + // MSE: Set AT for chip authentication + // 0xF80BSW1SW2 + // General Authenticate + // 0xF80CSW1SW2 + + // Others + CommunicationAbort + = 0xF0100001, + NoCard + = 0xF0100002, + Abort + = 0xF0200001, + Timeout + = 0xF0200002 + ) + + +} diff --git a/src/card/base/pace/KeyAgreement.cpp b/src/card/base/pace/KeyAgreement.cpp index 856ea82..e42db44 100644 --- a/src/card/base/pace/KeyAgreement.cpp +++ b/src/card/base/pace/KeyAgreement.cpp @@ -1,12 +1,15 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ + +#include "KeyAgreement.h" + #include "asn1/PACEInfo.h" #include "Commands.h" +#include "GlobalStatus.h" #include "pace/CipherMac.h" #include "pace/ec/EcdhKeyAgreement.h" -#include "pace/KeyAgreement.h" #include "pace/KeyDerivationFunction.h" #include "pace/SymmetricCipher.h" #include "PersoSimWorkaround.h" @@ -20,18 +23,33 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -template -static QString getResponseErrorString(CardReturnCode pReturnCode, const ResponseType& pResponse) +static QString getResponseErrorString(CardReturnCode pReturnCode, StatusCode pResponseReturnCode) { QString errorString = CardReturnCodeUtil::toGlobalStatus(pReturnCode).toErrorDescription(); if (pReturnCode == CardReturnCode::OK) { - errorString += QStringLiteral(" | ") + pResponse.getReturnCode(); + errorString += QStringLiteral(" | ") + pResponseReturnCode; } return errorString; } +static CardOperationResult makeTransmitResult(CardReturnCode pReturnCode, + StatusCode pResponseReturnCode, + const QByteArray& pResultData, + const QString& pLogMessage) +{ + if (pReturnCode == CardReturnCode::OK && pResponseReturnCode == StatusCode::SUCCESS) + { + return CardOperationResult(pReturnCode, pResultData); + } + + const CardReturnCode newReturnCode = pReturnCode == CardReturnCode::OK ? CardReturnCode::PROTOCOL_ERROR : CardReturnCode::COMMAND_FAILED; + qCCritical(card).noquote() << pLogMessage << getResponseErrorString(pReturnCode, pResponseReturnCode); + return CardOperationResult(newReturnCode, QByteArray()); +} + + QSharedPointer KeyAgreement::create(const QSharedPointer& pPaceInfo, QSharedPointer pCardConnectionWorker) { @@ -66,18 +84,34 @@ KeyAgreement::~KeyAgreement() KeyAgreementStatus KeyAgreement::perform(const QString& pPin) { - QByteArray nonce = determineNonce(pPin); - if (nonce.isNull()) + CardOperationResult nonceResult = determineNonce(pPin); + switch (nonceResult.getReturnCode()) { - return KeyAgreementStatus::PROTOCOLL_ERROR; + case CardReturnCode::PROTOCOL_ERROR: + return KeyAgreementStatus::PROTOCOL_ERROR; + + case CardReturnCode::COMMAND_FAILED: + return KeyAgreementStatus::COMMUNICATION_ERROR; + + default: + ; } - QByteArray sharedSecret = determineSharedSecret(nonce); - if (sharedSecret.isNull()) + QByteArray nonce = nonceResult.getPayload(); + CardOperationResult sharedSecretResult = determineSharedSecret(nonce); + switch (sharedSecretResult.getReturnCode()) { - return KeyAgreementStatus::PROTOCOLL_ERROR; + case CardReturnCode::COMMAND_FAILED: + return KeyAgreementStatus::COMMUNICATION_ERROR; + + case CardReturnCode::PROTOCOL_ERROR: + return KeyAgreementStatus::PROTOCOL_ERROR; + + default: + ; } + QByteArray sharedSecret = sharedSecretResult.getPayload(); mEncryptionKey = mKeyDerivationFunction.enc(sharedSecret); mMacKey = mKeyDerivationFunction.mac(sharedSecret); @@ -85,18 +119,19 @@ KeyAgreementStatus KeyAgreement::perform(const QString& pPin) } -QByteArray KeyAgreement::determineNonce(const QString& pPin) +CardOperationResult KeyAgreement::determineNonce(const QString& pPin) { - QByteArray encryptedNonce = transmitGAEncryptedNonce(); - if (encryptedNonce.isNull()) + CardOperationResult result = transmitGAEncryptedNonce(); + if (result.getReturnCode() != CardReturnCode::OK) { - return QByteArray(); + return result; } + QByteArray encryptedNonce = result.getPayload(); QByteArray symmetricKey = mKeyDerivationFunction.pi(pPin); SymmetricCipher nonceDecrypter(mPaceInfo->getProtocol(), symmetricKey); - return nonceDecrypter.decrypt(encryptedNonce); + return CardOperationResult(CardReturnCode::OK, nonceDecrypter.decrypt(encryptedNonce)); } @@ -118,7 +153,7 @@ KeyAgreementStatus KeyAgreement::performMutualAuthenticate() } else if (response->getReturnCode() != StatusCode::SUCCESS) { - return KeyAgreementStatus::PROTOCOLL_ERROR; + return KeyAgreementStatus::PROTOCOL_ERROR; } QByteArray uncompressedTerminalPublicKey = getUncompressedTerminalPublicKey(); @@ -127,7 +162,7 @@ KeyAgreementStatus KeyAgreement::performMutualAuthenticate() if (mutualAuthenticationTerminalData != response->getAuthenticationToken()) { qCCritical(card) << "Error on mutual authentication "; - return KeyAgreementStatus::PROTOCOLL_ERROR; + return KeyAgreementStatus::PROTOCOL_ERROR; } mCarCurr = response->getCarCurr(); @@ -137,51 +172,36 @@ KeyAgreementStatus KeyAgreement::performMutualAuthenticate() } -QByteArray KeyAgreement::transmitGAEncryptedNonce() +CardOperationResult KeyAgreement::transmitGAEncryptedNonce() { GABuilder builder(CommandApdu::CLA_COMMAND_CHAINING); GAEncryptedNonceResponse response; - 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(); - } - return response.getEncryptedNonce(); + const CardReturnCode returnCode = mCardConnectionWorker->transmit(builder.build(), response); + return makeTransmitResult(returnCode, response.getReturnCode(), response.getEncryptedNonce(), QStringLiteral("Error on GA (Encrypted Nonce):")); } -QByteArray KeyAgreement::transmitGAEphemeralPublicKey(const QByteArray& pEphemeralPublicKey) +CardOperationResult KeyAgreement::transmitGAEphemeralPublicKey(const QByteArray& pEphemeralPublicKey) { GABuilder commandBuilder(CommandApdu::CLA_COMMAND_CHAINING); commandBuilder.setPaceEphemeralPublicKey(pEphemeralPublicKey); GAPerformKeyAgreementResponse response; - 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(); - } - return response.getEphemeralPublicKey(); + const CardReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); + return makeTransmitResult(returnCode, response.getReturnCode(), response.getEphemeralPublicKey(), QStringLiteral("Error on GA(Perform Key Agreement):")); } -QByteArray KeyAgreement::transmitGAMappingData(const QByteArray& pMappingData) +CardOperationResult KeyAgreement::transmitGAMappingData(const QByteArray& pMappingData) { // sende den PublicKey (D.3.4.) GABuilder commandBuilder(CommandApdu::CLA_COMMAND_CHAINING); commandBuilder.setPaceMappingData(pMappingData); GAMapNonceResponse response; - 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(); - } - return response.getMappingData(); + const CardReturnCode returnCode = mCardConnectionWorker->transmit(commandBuilder.build(), response); + return makeTransmitResult(returnCode, response.getReturnCode(), response.getMappingData(), QStringLiteral("Error on GA(Mapping Data):")); } @@ -194,7 +214,7 @@ QSharedPointer KeyAgreement::transmitGAMutualAut 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); + qCCritical(card) << "Error on GA(Mutual Authentication):" << getResponseErrorString(returnCode, response->getReturnCode()); } return response; } diff --git a/src/card/base/pace/KeyAgreement.h b/src/card/base/pace/KeyAgreement.h index 299bdfb..9882619 100644 --- a/src/card/base/pace/KeyAgreement.h +++ b/src/card/base/pace/KeyAgreement.h @@ -1,15 +1,14 @@ /*! - * KeyAgreement.h - * * \brief the key agreement protocol use in PACE. For details see TR 03110. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "asn1/SecurityInfo.h" #include "CardConnectionWorker.h" +#include "CardOperationResult.h" #include "GeneralAuthenticateResponse.h" #include "pace/KeyDerivationFunction.h" @@ -25,8 +24,9 @@ class PACEInfo; enum class KeyAgreementStatus { SUCCESS, + COMMUNICATION_ERROR, FAILED, - PROTOCOLL_ERROR + PROTOCOL_ERROR }; class KeyAgreement @@ -43,7 +43,7 @@ class KeyAgreement * \param pPin PIN for decryption of the nonce * \return the decrypted nonce */ - QByteArray determineNonce(const QString& pPin); + CardOperationResult determineNonce(const QString& pPin); /*! * \brief Determines the shared secret by performing the key agreement. @@ -51,7 +51,7 @@ class KeyAgreement * \param pNonce the nonce needed for key agreement. * \return the shared secret between terminal and card */ - virtual QByteArray determineSharedSecret(const QByteArray& pNonce) = 0; + virtual CardOperationResult determineSharedSecret(const QByteArray& pNonce) = 0; /*! * \brief Returns the uncompressed terminal's ephemeral public key calculated during key agreement. @@ -64,11 +64,11 @@ class KeyAgreement * \brief Transmit the General Authenticate (Encrypted Nonce) command to the card. * \return the encrypted nonce */ - QByteArray transmitGAEncryptedNonce(); + CardOperationResult transmitGAEncryptedNonce(); /*! * \brief Performs the mutual authentication of terminal and card using the determined shared secret. - * This represents the forth step "General Authenticate" of TR-03110 Part 3, page 47. + * This represents the fourth step "General Authenticate" of TR-03110 Part 3, page 47. * \return result of authentication */ KeyAgreementStatus performMutualAuthenticate(); @@ -84,14 +84,14 @@ class KeyAgreement * \param pMappingData the terminal's mapping data. * \return the card's mapping data */ - QByteArray transmitGAMappingData(const QByteArray& pMappingData); + CardOperationResult transmitGAMappingData(const QByteArray& pMappingData); /*! * \brief Transmit the General Authenticate (Ephemeral Public Key) command to the card. * \param pEphemeralPublicKey the terminal's ephemeral public key * \return the card's ephemeral public key */ - QByteArray transmitGAEphemeralPublicKey(const QByteArray& pEphemeralPublicKey); + CardOperationResult transmitGAEphemeralPublicKey(const QByteArray& pEphemeralPublicKey); /*! * \brief Transmit the General Authenticate (Mutual Authentication) command to the card. @@ -118,7 +118,7 @@ class KeyAgreement /*! * \brief Factory method to create an instance of KeyAgreement. * \param pPaceInfo the PACEInfo containing the protocol parameters - * \param pReader the reader to transmit card commands + * \param pCardConnectionWorker the reader connection to transmit card commands * \return new instance */ static QSharedPointer create(const QSharedPointer& pPaceInfo, diff --git a/src/card/base/pace/KeyDerivationFunction.cpp b/src/card/base/pace/KeyDerivationFunction.cpp index 6150c3b..3ff1eeb 100644 --- a/src/card/base/pace/KeyDerivationFunction.cpp +++ b/src/card/base/pace/KeyDerivationFunction.cpp @@ -1,13 +1,12 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" #include "pace/KeyDerivationFunction.h" -#include #include - +#include using namespace governikus; @@ -24,8 +23,7 @@ KeyDerivationFunction::KeyDerivationFunction(const QByteArray& pPaceAlgorithm) if (pPaceAlgorithm == id_PACE::DH::GM_3DES_CBC_CBC || pPaceAlgorithm == id_PACE::DH::IM_3DES_CBC_CBC || pPaceAlgorithm == id_PACE::ECDH::GM_3DES_CBC_CBC || pPaceAlgorithm == id_PACE::ECDH::IM_3DES_CBC_CBC) { - mHashAlgorithm = QCryptographicHash::Sha1; - mKeySize = 8; + qCCritical(card) << "3DES not supported"; } else if (pPaceAlgorithm == id_PACE::DH::GM_AES_CBC_CMAC_128 || pPaceAlgorithm == id_PACE::DH::IM_AES_CBC_CMAC_128 || pPaceAlgorithm == id_PACE::ECDH::GM_AES_CBC_CMAC_128 || pPaceAlgorithm == id_PACE::ECDH::IM_AES_CBC_CMAC_128) @@ -89,25 +87,8 @@ QByteArray KeyDerivationFunction::deriveKey(const QByteArray& pK, const QByteArr return QByteArray(); } - QByteArray dataBytes(pK); - 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); + char counterBigEndian[4]; + qToBigEndian(pC, counterBigEndian); - QByteArray hashBytes; - if (mHashAlgorithm == QCryptographicHash::Sha1) - { - char md[SHA_DIGEST_LENGTH]; - 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()), static_cast(dataBytes.size()), reinterpret_cast(md)); - hashBytes.append(md, mKeySize); - } - return hashBytes; + return QCryptographicHash::hash(pK + pNonce + QByteArray(counterBigEndian, 4), mHashAlgorithm).left(mKeySize); } diff --git a/src/card/base/pace/KeyDerivationFunction.h b/src/card/base/pace/KeyDerivationFunction.h index 37a9735..bf06592 100644 --- a/src/card/base/pace/KeyDerivationFunction.h +++ b/src/card/base/pace/KeyDerivationFunction.h @@ -1,9 +1,7 @@ /*! - * KeyDerivationFunction.h - * * \brief Creates key according to TR 03110 Part 3 chapters A.2.3 ff. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -27,7 +25,6 @@ class KeyDerivationFunction * \brief Creates a new instance with derivation function algorithm determined by parameter. * \param pPaceAlgorithm algorithm of PACE protocol. This will determine the key derivation algorithm to use. E.g. a * PACE protocol of id_PACE::DH::GM_AES_CBC_CMAC_128 will result in SHA256 to be used internally to derive keys. - * \param pKeyBytes the bytes of the key */ KeyDerivationFunction(const QByteArray& pPaceAlgorithm); virtual ~KeyDerivationFunction(); diff --git a/src/card/base/pace/PaceHandler.cpp b/src/card/base/pace/PaceHandler.cpp index 7ba4071..ce35367 100644 --- a/src/card/base/pace/PaceHandler.cpp +++ b/src/card/base/pace/PaceHandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "pace/PaceHandler.h" @@ -23,6 +23,7 @@ PaceHandler::PaceHandler(const QSharedPointer& pCardConnec : mCardConnectionWorker(pCardConnectionWorker) , mKeyAgreement() , mPaceInfo() + , mStatusMseSetAt() , mIdIcc() , mEncryptionKey() , mMacKey() @@ -43,40 +44,44 @@ QByteArray PaceHandler::getPaceProtocol() const } -CardReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin) +CardReturnCode PaceHandler::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QString& pPassword) { auto efCardAccess = mCardConnectionWorker->getReaderInfo().getCardInfo().getEfCardAccess(); - if (!efCardAccess) - { - return CardReturnCode::PROTOCOL_ERROR; - } if (!initialize(efCardAccess)) { return CardReturnCode::PROTOCOL_ERROR; } - if (!transmitMSESetAT(pPinId)) + + switch (transmitMSESetAT(pPasswordId)) { - return CardReturnCode::PROTOCOL_ERROR; + case CardReturnCode::PROTOCOL_ERROR: + return CardReturnCode::PROTOCOL_ERROR; + + case CardReturnCode::COMMAND_FAILED: + return CardReturnCode::COMMAND_FAILED; + + default: + ; } - KeyAgreementStatus keyAgreementStatus = mKeyAgreement->perform(pPin); - if (keyAgreementStatus == KeyAgreementStatus::PROTOCOLL_ERROR) + KeyAgreementStatus keyAgreementStatus = mKeyAgreement->perform(pPassword); + if (keyAgreementStatus == KeyAgreementStatus::PROTOCOL_ERROR) { return CardReturnCode::PROTOCOL_ERROR; } else if (keyAgreementStatus == KeyAgreementStatus::FAILED) { - switch (pPinId) + switch (pPasswordId) { - case PACE_PIN_ID::PACE_MRZ: + case PACE_PASSWORD_ID::PACE_MRZ: // No separate error code (yet). - case PACE_PIN_ID::PACE_CAN: + case PACE_PASSWORD_ID::PACE_CAN: return CardReturnCode::INVALID_CAN; - case PACE_PIN_ID::PACE_PIN: + case PACE_PASSWORD_ID::PACE_PIN: return CardReturnCode::INVALID_PIN; - case PACE_PIN_ID::PACE_PUK: + case PACE_PASSWORD_ID::PACE_PUK: return CardReturnCode::INVALID_PUK; } } @@ -119,6 +124,12 @@ bool PaceHandler::initialize(const QSharedPointer& pEfCardAc bool PaceHandler::isSupportedProtocol(const QSharedPointer& pPaceInfo) const { + if (pPaceInfo->getVersion() != 2) + { + qCWarning(card) << "Unsupported pace version:" << pPaceInfo->getVersion(); + return false; + } + const auto protocol = pPaceInfo->getProtocol(); if (protocol == KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128 || @@ -131,18 +142,24 @@ bool PaceHandler::isSupportedProtocol(const QSharedPointer& pPac return true; } } + qCWarning(card) << "Unsupported domain parameters: " << pPaceInfo->getProtocol(); return false; } -bool PaceHandler::transmitMSESetAT(PACE_PIN_ID pPinId) +CardReturnCode PaceHandler::transmitMSESetAT(PACE_PASSWORD_ID pPasswordId) { - PersoSimWorkaround::sendingMseSetAt(mCardConnectionWorker); + CardReturnCode cardReturnCode = PersoSimWorkaround::sendingMseSetAt(mCardConnectionWorker); + if (cardReturnCode != CardReturnCode::OK) + { + qCCritical(card) << "Error on MSE:Set AT"; + return CardReturnCode::COMMAND_FAILED; + } MSEBuilder mseBuilder(MSEBuilder::P1::PERFORM_SECURITY_OPERATION, MSEBuilder::P2::SET_AT); mseBuilder.setOid(mPaceInfo->getProtocolValueBytes()); - mseBuilder.setPublicKey(pPinId); + mseBuilder.setPublicKey(pPasswordId); mseBuilder.setPrivateKey(mPaceInfo->getParameterId()); if (!mChat.isNull()) { @@ -150,18 +167,23 @@ bool PaceHandler::transmitMSESetAT(PACE_PIN_ID pPinId) } ResponseApdu response; - CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), response); - if (returnCode != CardReturnCode::OK) + cardReturnCode = mCardConnectionWorker->transmit(mseBuilder.build(), response); + + Q_ASSERT(response.getBuffer().length() == 2); + mStatusMseSetAt = response.getBuffer().left(2); + + const StatusCode responseReturnCode = response.getReturnCode(); + if (cardReturnCode != CardReturnCode::OK) { qCCritical(card) << "Error on MSE:Set AT"; - return false; + return responseReturnCode == StatusCode::EMPTY ? CardReturnCode::COMMAND_FAILED : CardReturnCode::PROTOCOL_ERROR; } - if (response.getReturnCode() != StatusCode::SUCCESS && response.getReturnCode() != StatusCode::PIN_RETRY_COUNT_2 && response.getReturnCode() != StatusCode::PIN_SUSPENDED) + if (responseReturnCode != StatusCode::SUCCESS && responseReturnCode != StatusCode::PIN_RETRY_COUNT_2 && responseReturnCode != StatusCode::PIN_SUSPENDED) { qCCritical(card) << "Error on MSE:Set AT"; - return false; + return CardReturnCode::PROTOCOL_ERROR; } - return true; + return CardReturnCode::OK; } @@ -199,3 +221,9 @@ const QByteArray& PaceHandler::getIdIcc() const { return mIdIcc; } + + +const QByteArray& PaceHandler::getStatusMseSetAt() const +{ + return mStatusMseSetAt; +} diff --git a/src/card/base/pace/PaceHandler.h b/src/card/base/pace/PaceHandler.h index 6b46776..be1b8f5 100644 --- a/src/card/base/pace/PaceHandler.h +++ b/src/card/base/pace/PaceHandler.h @@ -1,9 +1,7 @@ /*! - * PaceHandler.h - * * \brief Handler for the PACE protocol. See TR-03110. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -11,9 +9,9 @@ #include "asn1/PACEInfo.h" #include "asn1/SecurityInfos.h" #include "CardConnectionWorker.h" +#include "CardOperationResult.h" #include "EnumHelper.h" #include "pace/KeyAgreement.h" -#include "pace/KeyDerivationFunction.h" #include #include @@ -31,6 +29,7 @@ class PaceHandler const QSharedPointer mCardConnectionWorker; QSharedPointer mKeyAgreement; QSharedPointer mPaceInfo; + QByteArray mStatusMseSetAt; QByteArray mIdIcc; QByteArray mEncryptionKey; QByteArray mMacKey; @@ -51,10 +50,10 @@ class PaceHandler /*! * \brief Transmit the MSE:Set AT command to the card. - * \param pPinId the PIN id to use, e.g. PIN, CAN or PUK + * \param pPasswordId the PACE password id to use, e.g. PIN, CAN or PUK * \return false on any card errors */ - bool transmitMSESetAT(PACE_PIN_ID pPinId); + CardReturnCode transmitMSESetAT(PACE_PASSWORD_ID pPasswordId); Q_DISABLE_COPY(PaceHandler) @@ -63,11 +62,11 @@ class PaceHandler /*! * \brief Performs the PACE protocol and establishes a PACE channel. - * \param pPinId the PIN id to use, e.g. PIN, CAN or PUK - * \param pPin the PIN value, e.g. "123456" + * \param pPasswordId the PACE password id to use, e.g. PIN, CAN or PUK + * \param pPassword the password value, e.g. "123456" * \return false on any errors during establishment */ - CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin); + CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QString& pPassword); /*! * \brief The certificate holder authorization template to be supplied to the card. May be empty @@ -108,6 +107,8 @@ class PaceHandler */ const QByteArray& getIdIcc() const; + const QByteArray& getStatusMseSetAt() const; + /*! * The used PACE protocol. * \return the PACE protocol OID as string. diff --git a/src/card/base/pace/SecureMessaging.cpp b/src/card/base/pace/SecureMessaging.cpp index 4ddd025..f00580c 100644 --- a/src/card/base/pace/SecureMessaging.cpp +++ b/src/card/base/pace/SecureMessaging.cpp @@ -1,13 +1,13 @@ /*! - * SecureMessaging.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ + #include "asn1/ASN1Util.h" #include "pace/SecureMessaging.h" #include "SecureMessagingResponse.h" #include +#include using namespace governikus; @@ -190,8 +190,10 @@ int SecureMessaging::createNewLe(const QByteArray& pSecuredData, int pOldLe) con QByteArray SecureMessaging::getSendSequenceCounter() const { - QByteArray ssc = toBigEndian(mSendSequenceCounter); - return QByteArray(mCipher.getBlockSize() - ssc.size(), 0x00) + ssc; + static const int COUNTER_SIZE = sizeof(mSendSequenceCounter); + char converted[COUNTER_SIZE]; + qToBigEndian(mSendSequenceCounter, converted); + return QByteArray(mCipher.getBlockSize() - COUNTER_SIZE, 0x00) + QByteArray(converted, COUNTER_SIZE); } diff --git a/src/card/base/pace/SecureMessaging.h b/src/card/base/pace/SecureMessaging.h index 3bdd644..dfb1626 100644 --- a/src/card/base/pace/SecureMessaging.h +++ b/src/card/base/pace/SecureMessaging.h @@ -1,9 +1,7 @@ /*! - * SecureMessaging.h - * * \brief Implements TR-03110 v2 part3 --> Secure Messaging. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/pace/SymmetricCipher.cpp b/src/card/base/pace/SymmetricCipher.cpp index 24b8a0d..ac90305 100644 --- a/src/card/base/pace/SymmetricCipher.cpp +++ b/src/card/base/pace/SymmetricCipher.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" diff --git a/src/card/base/pace/SymmetricCipher.h b/src/card/base/pace/SymmetricCipher.h index 3eeb6cd..89403e4 100644 --- a/src/card/base/pace/SymmetricCipher.h +++ b/src/card/base/pace/SymmetricCipher.h @@ -1,9 +1,7 @@ /*! - * SymmetricCipher.h - * * \brief Symmetric decryption method used for PACE. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/base/pace/ec/EcUtil.h b/src/card/base/pace/ec/EcUtil.h index 4aca7f4..c3392ff 100644 --- a/src/card/base/pace/ec/EcUtil.h +++ b/src/card/base/pace/ec/EcUtil.h @@ -1,9 +1,7 @@ /*! - * EcUtil.h - * * \brief Elliptic curve utility. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -44,6 +42,12 @@ class EcUtil inline QByteArray EcUtil::point2oct(const QSharedPointer& pCurve, const EC_POINT* pPoint) { + if (pCurve.isNull() || pPoint == nullptr) + { + qCCritical(card) << "Invalid input data, cannot encode elliptic curve point"; + return QByteArray(); + } + size_t buf_size = EC_POINT_point2oct(pCurve.data(), pPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); if (buf_size == 0) diff --git a/src/card/base/pace/ec/EcdhGenericMapping.cpp b/src/card/base/pace/ec/EcdhGenericMapping.cpp index 0e72067..5bc484b 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.cpp +++ b/src/card/base/pace/ec/EcdhGenericMapping.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/src/card/base/pace/ec/EcdhGenericMapping.h b/src/card/base/pace/ec/EcdhGenericMapping.h index 47a36b3..5e67edf 100644 --- a/src/card/base/pace/ec/EcdhGenericMapping.h +++ b/src/card/base/pace/ec/EcdhGenericMapping.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -29,7 +29,7 @@ class EcdhGenericMapping public: EcdhGenericMapping(const QSharedPointer& pCurve); - virtual ~EcdhGenericMapping(); + virtual ~EcdhGenericMapping() override; QByteArray generateTerminalMappingData() override; diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.cpp b/src/card/base/pace/ec/EcdhKeyAgreement.cpp index a4452f1..f970578 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.cpp +++ b/src/card/base/pace/ec/EcdhKeyAgreement.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" @@ -23,39 +23,13 @@ Q_DECLARE_LOGGING_CATEGORY(secure) QByteArray EcdhKeyAgreement::encodeUncompressedPublicKey(const QSharedPointer& pPaceInfo, const QSharedPointer& pCurve, const QSharedPointer& pPoint) { - QByteArray pointBytes = EcUtil::point2oct(pCurve, pPoint.data()); + const QByteArray& publicKeyData = + Asn1Util::encode(char(0x06), pPaceInfo->getProtocolValueBytes()) + + Asn1Util::encode(char(0x86), EcUtil::point2oct(pCurve, pPoint.data())); - QByteArray publicKeyData; - 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 += 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; + const QByteArray& publicKey = + QByteArray(1, char(0x7f)) + + Asn1Util::encode(char(0x49), publicKeyData); return publicKey; } @@ -106,84 +80,93 @@ EcdhKeyAgreement::~EcdhKeyAgreement() } -QByteArray EcdhKeyAgreement::determineSharedSecret(const QByteArray& pNonce) +CardOperationResult EcdhKeyAgreement::determineSharedSecret(const QByteArray& pNonce) { - mEphemeralCurve = determineEphemeralDomainParameters(pNonce); - if (!mEphemeralCurve) + CardOperationResult > ephemeralCurveResult = determineEphemeralDomainParameters(pNonce); + CardReturnCode ephemeralCurveResultCode = ephemeralCurveResult.getReturnCode(); + mEphemeralCurve = ephemeralCurveResult.getPayload(); + if (ephemeralCurveResultCode != CardReturnCode::OK) { - return QByteArray(); + return CardOperationResult(ephemeralCurveResultCode, QByteArray()); } - QSharedPointer mutualPoint = performKeyExchange(mEphemeralCurve); - if (!mutualPoint) + CardOperationResult > mutualPointResult = performKeyExchange(mEphemeralCurve); + CardReturnCode mutualPointResultCode = mutualPointResult.getReturnCode(); + QSharedPointer mutualPoint = mutualPointResult.getPayload(); + if (mutualPointResultCode != CardReturnCode::OK) { - return QByteArray(); + return CardOperationResult(mutualPointResultCode, QByteArray()); } QByteArray sharedSecret = EcUtil::point2oct(mEphemeralCurve, mutualPoint.data()); sharedSecret = sharedSecret.mid(1, (sharedSecret.size() - 1) / 2); - return sharedSecret; + return CardOperationResult(CardReturnCode::OK, sharedSecret); } -QSharedPointer EcdhKeyAgreement::determineEphemeralDomainParameters(const QByteArray& pNonce) +CardOperationResult > EcdhKeyAgreement::determineEphemeralDomainParameters(const QByteArray& pNonce) { QByteArray terminalMappingData = mMapping->generateTerminalMappingData(); - QByteArray cardMappingData = transmitGAMappingData(terminalMappingData); - if (cardMappingData.isNull()) + CardOperationResult result = transmitGAMappingData(terminalMappingData); + CardReturnCode resultCode = result.getReturnCode(); + if (resultCode != CardReturnCode::OK) { - return QSharedPointer(); + return CardOperationResult >(resultCode, QSharedPointer()); } - return mMapping->generateEphemeralDomainParameters(cardMappingData, pNonce); + + QByteArray cardMappingData = result.getPayload(); + return CardOperationResult >(CardReturnCode::OK, mMapping->generateEphemeralDomainParameters(cardMappingData, pNonce)); } -QSharedPointer EcdhKeyAgreement::performKeyExchange(const QSharedPointer& pCurve) +CardOperationResult > EcdhKeyAgreement::performKeyExchange(const QSharedPointer& pCurve) { QSharedPointer terminalEphemeralKey = EcUtil::create(EC_KEY_new()); if (!EC_KEY_set_group(terminalEphemeralKey.data(), pCurve.data())) { qCCritical(card) << "Error EC_KEY_set_group"; - return QSharedPointer(); + return CardOperationResult >(CardReturnCode::PROTOCOL_ERROR, QSharedPointer()); } if (!EC_KEY_generate_key(terminalEphemeralKey.data())) { qCCritical(card) << "Error EC_KEY_generate_key"; - return QSharedPointer(); + return CardOperationResult >(CardReturnCode::PROTOCOL_ERROR, QSharedPointer()); } // Make a copy of the terminal public key for later mutual authentication. mTerminalPublicKey = EcUtil::create(EC_POINT_dup(EC_KEY_get0_public_key(terminalEphemeralKey.data()), pCurve.data())); QByteArray terminalEphemeralPublicKeyBytes = EcUtil::point2oct(pCurve, mTerminalPublicKey.data()); const BIGNUM* terminalPrivateKey = EC_KEY_get0_private_key(terminalEphemeralKey.data()); - QByteArray cardEphemeralPublicKeyBytes = transmitGAEphemeralPublicKey(terminalEphemeralPublicKeyBytes); - if (cardEphemeralPublicKeyBytes.isNull()) + CardOperationResult result = transmitGAEphemeralPublicKey(terminalEphemeralPublicKeyBytes); + CardReturnCode resultCode = result.getReturnCode(); + if (resultCode != CardReturnCode::OK) { - return QSharedPointer(); + return CardOperationResult >(resultCode, QSharedPointer()); } + QByteArray cardEphemeralPublicKeyBytes = result.getPayload(); qCDebug(secure) << "uncompressedCardEphemeralPublicKey: " << cardEphemeralPublicKeyBytes.toHex(); mCardPublicKey = EcUtil::oct2point(pCurve, cardEphemeralPublicKeyBytes); if (!mCardPublicKey) { qCCritical(card) << "Cannot encode card ephemeral public key"; - return QSharedPointer(); + return CardOperationResult >(CardReturnCode::PROTOCOL_ERROR, QSharedPointer()); } if (!EC_POINT_cmp(pCurve.data(), mTerminalPublicKey.data(), mCardPublicKey.data(), nullptr)) { qCCritical(card) << "The exchanged public keys are equal"; - return QSharedPointer(); + return CardOperationResult >(CardReturnCode::PROTOCOL_ERROR, QSharedPointer()); } QSharedPointer mutualPoint = EcUtil::create(EC_POINT_new(pCurve.data())); if (!EC_POINT_mul(pCurve.data(), mutualPoint.data(), nullptr, mCardPublicKey.data(), terminalPrivateKey, nullptr)) { qCCritical(card) << "Calculation of elliptic curve point H failed"; - return QSharedPointer(); + return CardOperationResult >(CardReturnCode::PROTOCOL_ERROR, QSharedPointer()); } - return mutualPoint; + return CardOperationResult >(CardReturnCode::OK, mutualPoint); } diff --git a/src/card/base/pace/ec/EcdhKeyAgreement.h b/src/card/base/pace/ec/EcdhKeyAgreement.h index d4ec844..7f0add6 100644 --- a/src/card/base/pace/ec/EcdhKeyAgreement.h +++ b/src/card/base/pace/ec/EcdhKeyAgreement.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -28,13 +28,13 @@ class EcdhKeyAgreement QSharedPointer mTerminalPublicKey; QSharedPointer mCardPublicKey; - QSharedPointer determineEphemeralDomainParameters(const QByteArray& pNonce); - QSharedPointer performKeyExchange(const QSharedPointer& pCurve); + CardOperationResult > determineEphemeralDomainParameters(const QByteArray& pNonce); + CardOperationResult > performKeyExchange(const QSharedPointer& pCurve); 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; + CardOperationResult determineSharedSecret(const QByteArray& pNonce) override; QByteArray getUncompressedTerminalPublicKey() override; QByteArray getUncompressedCardPublicKey() override; QByteArray getCompressedCardPublicKey() override; @@ -45,7 +45,7 @@ class EcdhKeyAgreement static QSharedPointer create(const QSharedPointer& pPaceInfo, const QSharedPointer& pCardConnectionWorker); - virtual ~EcdhKeyAgreement(); + virtual ~EcdhKeyAgreement() override; }; } /* namespace governikus */ diff --git a/src/card/base/pace/ec/EllipticCurveFactory.cpp b/src/card/base/pace/ec/EllipticCurveFactory.cpp index cb4b899..aa381c8 100644 --- a/src/card/base/pace/ec/EllipticCurveFactory.cpp +++ b/src/card/base/pace/ec/EllipticCurveFactory.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/src/card/base/pace/ec/EllipticCurveFactory.h b/src/card/base/pace/ec/EllipticCurveFactory.h index 71acefb..80e0ac6 100644 --- a/src/card/base/pace/ec/EllipticCurveFactory.h +++ b/src/card/base/pace/ec/EllipticCurveFactory.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/AndroidBluetoothAdapter.cpp b/src/card/bluetooth/AndroidBluetoothAdapter.cpp index e172566..5c371fa 100644 --- a/src/card/bluetooth/AndroidBluetoothAdapter.cpp +++ b/src/card/bluetooth/AndroidBluetoothAdapter.cpp @@ -1,7 +1,5 @@ /*! - * AndroidBluetoothAdapter.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "AndroidBluetoothAdapter.h" @@ -27,7 +25,7 @@ const int DEVICE_TYPE_LE = 2; */ const int STATE_ON = 12; -QBluetoothDeviceInfo::CoreConfiguration AndroidBluetoothAdapter::fromAndroidDeviceType(quint32 pAndroidDeviceTypeConstant) +QBluetoothDeviceInfo::CoreConfiguration AndroidBluetoothAdapter::fromAndroidDeviceType(int pAndroidDeviceTypeConstant) { switch (pAndroidDeviceTypeConstant) { @@ -74,17 +72,19 @@ AndroidBluetoothAdapter AndroidBluetoothAdapter::getDefaultAdapter() stateOn = (adapter.callMethod("getState") == STATE_ON); QAndroidJniObject deviceSet = adapter.callObjectMethod("getBondedDevices", "()Ljava/util/Set;"); - for (QAndroidJniObject iter = deviceSet.callObjectMethod("iterator", "()Ljava/util/Iterator;"); (bool) iter.callMethod("hasNext", "()Z"); ) + for (QAndroidJniObject iter = deviceSet.callObjectMethod("iterator", "()Ljava/util/Iterator;") + ; static_cast(iter.callMethod("hasNext", "()Z")) + ;) { QAndroidJniObject device = iter.callObjectMethod("next", "()Ljava/lang/Object;"); QString name = device.callObjectMethod("getName").toString(); QString address = device.callObjectMethod("getAddress").toString(); QAndroidJniObject bluetoothClass = device.callObjectMethod("getBluetoothClass", "()Landroid/bluetooth/BluetoothClass;"); - quint32 deviceClass = bluetoothClass.callMethod("getDeviceClass"); - quint32 type = device.callMethod("getType"); + int deviceClass = bluetoothClass.callMethod("getDeviceClass"); + int type = device.callMethod("getType"); - QBluetoothDeviceInfo deviceInfo(QBluetoothAddress(address), name, deviceClass); + QBluetoothDeviceInfo deviceInfo(QBluetoothAddress(address), name, static_cast(deviceClass)); deviceInfo.setCoreConfigurations(fromAndroidDeviceType(type)); deviceInfo.setCached(true); bondedDevices += deviceInfo; diff --git a/src/card/bluetooth/AndroidBluetoothAdapter.h b/src/card/bluetooth/AndroidBluetoothAdapter.h index e9df1a8..7f1c8b9 100644 --- a/src/card/bluetooth/AndroidBluetoothAdapter.h +++ b/src/card/bluetooth/AndroidBluetoothAdapter.h @@ -1,9 +1,7 @@ /*! - * AndroidBluetoothAdapter.h - * * \brief This class accesses the java class android.bluetooth.BluetoothAdapter * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -19,7 +17,7 @@ namespace governikus class AndroidBluetoothAdapter { private: - static QBluetoothDeviceInfo::CoreConfiguration fromAndroidDeviceType(quint32 pAndroidDeviceTypeConstant); + static QBluetoothDeviceInfo::CoreConfiguration fromAndroidDeviceType(int pAndroidDeviceTypeConstant); bool mAvailable; bool mStateOn; diff --git a/src/card/bluetooth/AndroidBluetoothReceiver.java b/src/card/bluetooth/AndroidBluetoothReceiver.java index fc5ab92..50930b5 100644 --- a/src/card/bluetooth/AndroidBluetoothReceiver.java +++ b/src/card/bluetooth/AndroidBluetoothReceiver.java @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + package com.governikus.ausweisapp2; import android.bluetooth.BluetoothAdapter; @@ -90,4 +94,4 @@ public class AndroidBluetoothReceiver extends BroadcastReceiver private native void bluetoothAdapterStateChanged(int previous, int current); -} \ No newline at end of file +} diff --git a/src/card/bluetooth/BluetoothCard.cpp b/src/card/bluetooth/BluetoothCard.cpp index 19b9248..dfa99fc 100644 --- a/src/card/bluetooth/BluetoothCard.cpp +++ b/src/card/bluetooth/BluetoothCard.cpp @@ -1,8 +1,7 @@ /*! - * BluetoothCard.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ + #include "BluetoothCard.h" #include "DestroyPACEChannel.h" #include "messages/BluetoothMessageCreator.h" @@ -119,14 +118,14 @@ CardReturnCode BluetoothCard::transmit(const CommandApdu& pCmd, ResponseApdu& pR } -CardReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode BluetoothCard::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) { EstablishPACEChannelBuilder builder; - builder.setPinId(pPinId); + builder.setPasswordId(pPasswordId); builder.setChat(pChat); builder.setCertificateDescription(pCertificateDescription); @@ -138,7 +137,7 @@ CardReturnCode BluetoothCard::establishPaceChannel(PACE_PIN_ID pPinId, return returnCode; } - pChannelOutput.parseFromCcid(response.getBuffer(), pPinId); + pChannelOutput.parseFromCcid(response.getBuffer(), pPasswordId); return pChannelOutput.getPaceReturnCode(); } diff --git a/src/card/bluetooth/BluetoothCard.h b/src/card/bluetooth/BluetoothCard.h index cb0bd7a..ebefc5f 100644 --- a/src/card/bluetooth/BluetoothCard.h +++ b/src/card/bluetooth/BluetoothCard.h @@ -1,9 +1,7 @@ /*! - * BluetoothCard.h - * * \brief Implementation of Card object for Bluetooth * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -36,7 +34,7 @@ class BluetoothCard CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; + CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; CardReturnCode destroyPaceChannel() override; diff --git a/src/card/bluetooth/BluetoothDebug.cpp b/src/card/bluetooth/BluetoothDebug.cpp index 2c445be..e677722 100644 --- a/src/card/bluetooth/BluetoothDebug.cpp +++ b/src/card/bluetooth/BluetoothDebug.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothDebug.h" diff --git a/src/card/bluetooth/BluetoothDebug.h b/src/card/bluetooth/BluetoothDebug.h index b9a560b..7a40497 100644 --- a/src/card/bluetooth/BluetoothDebug.h +++ b/src/card/bluetooth/BluetoothDebug.h @@ -1,7 +1,7 @@ /*! * \brief Implementation of debug output for various Qt Bluetooth classes. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/BluetoothDeviceUtil.h b/src/card/bluetooth/BluetoothDeviceUtil.h index f2d4411..e23f2dd 100644 --- a/src/card/bluetooth/BluetoothDeviceUtil.h +++ b/src/card/bluetooth/BluetoothDeviceUtil.h @@ -1,9 +1,7 @@ /*! - * BluetoothDeviceUtil.h - * * \brief Utility function for determination of unique Bluetooth device ids. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/BluetoothReader.cpp b/src/card/bluetooth/BluetoothReader.cpp index 906525d..c03e1f9 100644 --- a/src/card/bluetooth/BluetoothReader.cpp +++ b/src/card/bluetooth/BluetoothReader.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothReader.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothCard.h" @@ -25,17 +23,18 @@ using namespace governikus; BluetoothReader::BluetoothReader(const QSharedPointer& pDevice) - : ConnectableReader(ReaderManagerPlugInType::BLUETOOTH, pDevice->getName(), ReaderType::REINER_cyberJack_wave) + : ConnectableReader(ReaderManagerPlugInType::BLUETOOTH, pDevice->getName()) , mDevice(pDevice) , mLastCardEvent(CardEvent::NONE) , mCard() { mReaderInfo.setBasicReader(false); - 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); + mReaderInfo.setConnected(mDevice->isValid()); + qCDebug(bluetooth) << "Created reader" << getName() << "with connected status:" << mReaderInfo.isConnected(); } @@ -138,8 +137,6 @@ void BluetoothReader::onStatusCharacteristicChanged(const QByteArray& pValue) mCard.reset(new BluetoothCard(mDevice)); QSharedPointer cardConnection = createCardConnectionWorker(); CardInfoFactory::create(cardConnection, mReaderInfo); - const QSignalBlocker blocker(this); - updateRetryCounter(cardConnection); mLastCardEvent = CardEvent::CARD_INSERTED; } else if (!mCard.isNull() && statusChange == BluetoothStatusChange::CardRemoved) @@ -157,7 +154,6 @@ void BluetoothReader::onCardRemoved() { qCDebug(card) << "Card removed" << getName(); mLastCardEvent = CardEvent::CARD_REMOVED; - mUpdateRetryCounter = false; mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); mCard.reset(); } diff --git a/src/card/bluetooth/BluetoothReader.h b/src/card/bluetooth/BluetoothReader.h index 656777a..6327fde 100644 --- a/src/card/bluetooth/BluetoothReader.h +++ b/src/card/bluetooth/BluetoothReader.h @@ -1,9 +1,7 @@ /*! - * BluetoothReader.h - * * \brief Implementation of Reader object for Bluetooth based card reader. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp b/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp index 0bcf44a..e456c85 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn.cpp @@ -1,23 +1,23 @@ /*! - * BluetoothReaderManagerPlugIn.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ +#include "BluetoothReaderManagerPlugIn.h" + #include "AndroidBluetoothAdapter.h" #include "BluetoothDebug.h" #include "BluetoothDeviceUtil.h" #include "BluetoothReader.h" -#include "BluetoothReaderManagerPlugIn.h" #include "BluetoothReaderManagerPlugIn_p.h" #include "DeviceError.h" +#include "Initializer.h" +#include "ScopeGuard.h" #include - +#include Q_DECLARE_LOGGING_CATEGORY(bluetooth) - using namespace governikus; @@ -25,10 +25,9 @@ BluetoothReaderManagerPlugIn::BluetoothReaderManagerPlugIn() : ReaderManagerPlugIn(ReaderManagerPlugInType::BLUETOOTH) , d_ptr(new BluetoothReaderManagerPlugInPrivate(this)) , mDeviceDiscoveryAgent() - , mDiscoveredReadersInCurrentScan() , mInitializingDevices() , mReaders() - , mScanInProgress(false) + , mReadersDiscoveredInCurrentScan() , mTimerIdDiscoverPairedDevices(0) { connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothReaderManagerPlugIn::onDeviceDiscovered); @@ -50,7 +49,7 @@ void BluetoothReaderManagerPlugIn::init() } -QList BluetoothReaderManagerPlugIn::getReader() const +QList BluetoothReaderManagerPlugIn::getReaders() const { QList readers; readers.reserve(mReaders.size()); @@ -76,9 +75,12 @@ void BluetoothReaderManagerPlugIn::startScan() qCDebug(bluetooth) << "Handle already paired devices"; d->handlePairedDevices(); - qCDebug(bluetooth) << "Starting Bluetooth device discovery"; - mScanInProgress = true; - mDeviceDiscoveryAgent.start(); + if (mReaders.size() < 1) + { + qCDebug(bluetooth) << "Starting Bluetooth device discovery"; + mScanInProgress = true; + mDeviceDiscoveryAgent.start(); + } } @@ -97,36 +99,72 @@ void BluetoothReaderManagerPlugIn::setBluetoothStatus(bool pEnabled) void BluetoothReaderManagerPlugIn::stopScan() { - if (!mDeviceDiscoveryAgent.isActive()) + if (mDeviceDiscoveryAgent.isActive()) + { + qCDebug(bluetooth) << "Stopping Bluetooth device discovery"; + mDeviceDiscoveryAgent.stop(); + } + else { qCWarning(bluetooth) << "Bluetooth device discovery not running"; - return; } - qCDebug(bluetooth) << "Stopping Bluetooth device discovery"; mScanInProgress = false; - mDeviceDiscoveryAgent.stop(); +} + + +void BluetoothReaderManagerPlugIn::onConnectToKnownReadersChanged() +{ + const auto& values = mReaders.values(); + for (BluetoothReader* const reader : values) + { + const bool connected = reader->getReaderInfo().isConnected(); + if (mConnectToKnownReaders && !connected) + { + /* + * Workaround for pairing problem on Android: + * + * The reader detection process performs a BT connect, determines the services and characteristics + * and disconnects afterwards. When selecting a reader we connect again. + * This causes some timing issue. Other developers have similar problems, e.g. see + * https://github.com/NordicSemiconductor/Android-DFU-Library/issues/1#issuecomment-156790789 + * + * This led to setting a delay of 1000 msecs. + */ + QTimer::singleShot(1000, [ = ] { + reader->connectReader(); + }); + } + else if (connected && !mConnectToKnownReaders) + { + reader->disconnectReader(); + } + } } void BluetoothReaderManagerPlugIn::onDeviceDiscovered(const QBluetoothDeviceInfo& pInfo) { - qCDebug(bluetooth) << "Bluetooth device discovered" << pInfo; - QString deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); if (mReaders.contains(deviceId)) { - mDiscoveredReadersInCurrentScan += deviceId; + if (!mReadersDiscoveredInCurrentScan.contains(deviceId)) + { + qCDebug(bluetooth) << "Bluetooth device re-discovered" << pInfo; + mReadersDiscoveredInCurrentScan += deviceId; + } return; } + if (mInitializingDevices.contains(deviceId)) { - qCDebug(bluetooth) << "Device is already determined, just update the device info"; auto knownDevice = mInitializingDevices.value(deviceId); knownDevice->setDeviceInfo(pInfo); return; } + qCDebug(bluetooth) << "Bluetooth device discovered" << pInfo; + QSharedPointer newDevice(new CyberJackWaveDevice(pInfo)); mInitializingDevices.insert(deviceId, newDevice); connect(newDevice.data(), &CyberJackWaveDevice::fireInitialized, this, &BluetoothReaderManagerPlugIn::onDeviceInitialized); @@ -136,49 +174,71 @@ void BluetoothReaderManagerPlugIn::onDeviceDiscovered(const QBluetoothDeviceInfo void BluetoothReaderManagerPlugIn::onDeviceInitialized(const QBluetoothDeviceInfo& pInfo) { - QString deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); - if (auto device = mInitializingDevices.value(deviceId)) + const QString& deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); + auto device = mInitializingDevices.value(deviceId); + if (!device) { - if (device->isValid()) - { - if (mReaders.contains(deviceId)) - { - qCDebug(bluetooth) << "Device is already determined as reader, skip further processing"; - mDiscoveredReadersInCurrentScan += deviceId; - } - else - { - BluetoothReader* reader = new BluetoothReader(device); - qCDebug(bluetooth) << "Device is successfully initialized, create reader" << reader->getName(); + return; + } + disconnect(device.data(), &CyberJackWaveDevice::fireInitialized, this, &BluetoothReaderManagerPlugIn::onDeviceInitialized); - connect(reader, &BluetoothReader::fireReaderConnected, this, &ReaderManagerPlugIn::fireReaderConnected); - 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); + const ScopeGuard disconnector([device] { + device->disconnectFromDevice(); + }); - mDiscoveredReadersInCurrentScan += deviceId; - mReaders.insert(deviceId, reader); - connect(device.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReaderManagerPlugIn::onDeviceDisconnected); - } - } - disconnect(device.data(), &CyberJackWaveDevice::fireInitialized, this, &BluetoothReaderManagerPlugIn::onDeviceInitialized); - device->disconnectFromDevice(); + if (!device->isValid()) + { + return; + } + + Q_ASSERT_X(!mReaders.contains(deviceId), "BluetoothReaderManagerPlugIn", "Device is already determined as reader"); + + BluetoothReader* reader = new BluetoothReader(device); + qCDebug(bluetooth) << "Device is successfully initialized, create reader" << reader->getName(); + + connect(reader, &BluetoothReader::fireReaderConnected, this, &ReaderManagerPlugIn::fireReaderAdded); + 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); + + mReadersDiscoveredInCurrentScan += deviceId; + mReaders.insert(deviceId, reader); + connect(device.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReaderManagerPlugIn::onDeviceDisconnected); + + if (mConnectToKnownReaders) + { + /* + * Workaround for pairing problem on Android: + * + * The reader detection process performs a BT connect, determines the services and characteristics + * and disconnects afterwards. When selecting a reader we connect again. + * This causes some timing issue. Other developers have similar problems, e.g. see + * https://github.com/NordicSemiconductor/Android-DFU-Library/issues/1#issuecomment-156790789 + * + * This led to setting a delay of 1000 msecs. + */ + QTimer::singleShot(1000, [ = ] { + reader->connectReader(); + }); } } void BluetoothReaderManagerPlugIn::onDeviceDisconnected(const QBluetoothDeviceInfo& pInfo) { - QString deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); - if (auto device = mInitializingDevices.value(deviceId)) + const QString& deviceId = BluetoothDeviceUtil::getDeviceId(pInfo); + auto device = mInitializingDevices.value(deviceId); + if (!device) { - disconnect(device.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReaderManagerPlugIn::onDeviceDisconnected); - if (auto reader = mReaders.value(deviceId)) - { - qCDebug(bluetooth) << "Device is disconnected, publish reader" << reader->getName(); - Q_EMIT fireReaderAdded(reader->getName()); - } + return; + } + disconnect(device.data(), &CyberJackWaveDevice::fireDisconnected, this, &BluetoothReaderManagerPlugIn::onDeviceDisconnected); + + if (auto reader = mReaders.value(deviceId)) + { + qCDebug(bluetooth) << "Device is disconnected" << reader->getName(); + Q_EMIT fireReaderRemoved(reader->getName()); } } @@ -210,7 +270,7 @@ void BluetoothReaderManagerPlugIn::onDeviceDiscoveryCanceled() d->onDeviceDiscoveryCanceled(); mInitializingDevices.clear(); - mDiscoveredReadersInCurrentScan.clear(); + mReadersDiscoveredInCurrentScan.clear(); } diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn.h b/src/card/bluetooth/BluetoothReaderManagerPlugIn.h index c8c895d..f69adf7 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn.h +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn.h @@ -1,9 +1,7 @@ /*! - * BluetoothReaderManagerPlugIn.h - * * \brief Implements the ReaderManagerPlugIn with Qt'S Bluetooth API. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -35,32 +33,33 @@ class BluetoothReaderManagerPlugIn BluetoothReaderManagerPlugInPrivate* const d_ptr; QBluetoothDeviceDiscoveryAgent mDeviceDiscoveryAgent; - QStringList mDiscoveredReadersInCurrentScan; QMap > mInitializingDevices; QMap mReaders; - bool mScanInProgress; + QStringList mReadersDiscoveredInCurrentScan; int mTimerIdDiscoverPairedDevices; void onRemoveReader(const QString& pDeviceId); void timerEvent(QTimerEvent* event) override; private Q_SLOTS: + void onDeviceInitialized(const QBluetoothDeviceInfo& pInfo); void onDeviceDisconnected(const QBluetoothDeviceInfo& pInfo); void onDeviceDiscovered(const QBluetoothDeviceInfo& pInfo); void onDeviceDiscoveryFinished(); void onDeviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error pError); void onDeviceDiscoveryCanceled(); - void onDeviceInitialized(const QBluetoothDeviceInfo& pInfo); void setBluetoothStatus(bool pEnabled); + protected: + virtual void onConnectToKnownReadersChanged() override; + public: BluetoothReaderManagerPlugIn(); void init() override; - QList getReader() const override; + QList getReaders() const override; - public Q_SLOTS: - void startScan() override; - void stopScan() override; + virtual void startScan() override; + virtual void stopScan() override; }; } /* namespace governikus */ diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p.h b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p.h index 6c2d541..12b9221 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p.h +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p.h @@ -1,9 +1,7 @@ /*! - * BluetoothReaderManagerPlugIn_p.h - * * \brief Private implementation part of the ReaderManagerPlugIn with Qt'S Bluetooth API. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp index 4971e55..cbb8b3e 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_android.cpp @@ -1,8 +1,7 @@ /*! - * BluetoothReaderManagerPlugInPrivate_p_android.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ + #include "AndroidBluetoothAdapter.h" #include "BluetoothReaderManagerPlugIn_p.h" @@ -88,29 +87,12 @@ void BluetoothReaderManagerPlugInPrivate::onScanStart() void BluetoothReaderManagerPlugInPrivate::handlePairedDevices() { - static QVector knownPairedDevices; - const QVector& currentlyPairedDevices = AndroidBluetoothAdapter::getDefaultAdapter().getBondedDevices(); - QVector newlyPairedDevices; - - for (const QBluetoothDeviceInfo& device : qAsConst(currentlyPairedDevices)) + const QVector& pairedDevices = AndroidBluetoothAdapter::getDefaultAdapter().getBondedDevices(); + for (const QBluetoothDeviceInfo& device : pairedDevices) { - if (!knownPairedDevices.contains(device)) - { - 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); - } + q->onDeviceDiscovered(device); } - - knownPairedDevices = currentlyPairedDevices; } @@ -119,7 +101,7 @@ void BluetoothReaderManagerPlugInPrivate::onDeviceDiscoveryCanceled() Q_Q(BluetoothReaderManagerPlugIn); for (auto deviceId : q->mReaders.keys()) { - if (!q->mDiscoveredReadersInCurrentScan.contains(deviceId)) + if (!q->mReadersDiscoveredInCurrentScan.contains(deviceId)) { q->onRemoveReader(deviceId); } diff --git a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_generic.cpp b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_generic.cpp index 9570f24..d03137e 100644 --- a/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_generic.cpp +++ b/src/card/bluetooth/BluetoothReaderManagerPlugIn_p_generic.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothReaderManagerPlugInPrivate_p_generic.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothReaderManagerPlugIn_p.h" diff --git a/src/card/bluetooth/CyberJackWaveDevice.cpp b/src/card/bluetooth/CyberJackWaveDevice.cpp index d91a389..fac59f7 100644 --- a/src/card/bluetooth/CyberJackWaveDevice.cpp +++ b/src/card/bluetooth/CyberJackWaveDevice.cpp @@ -1,7 +1,5 @@ /*! - * CyberJackWaveDevice.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothDebug.h" @@ -110,15 +108,18 @@ void CyberJackWaveDevice::onConnectedDevice() void CyberJackWaveDevice::onServiceDiscoveryFinished() { qCDebug(bluetooth) << "Services discovered for device" << mDeviceInfo; - for (const auto& serviceUuid : mLeController.services()) + const auto& services = mLeController.services(); + for (const auto& serviceUuid : services) { qCDebug(bluetooth) << "Found service" << serviceUuid; - if (const auto service = QSharedPointer(mLeController.createServiceObject(serviceUuid))) + if (const auto& service = QSharedPointer(mLeController.createServiceObject(serviceUuid))) { - for (const auto& characteristic : service->characteristics()) + const auto& serviceCharacteristis = service->characteristics(); + for (const auto& characteristic : serviceCharacteristis) { qCDebug(bluetooth) << "Found service characteristic" << characteristic.uuid(); - for (const auto& descriptor : characteristic.descriptors()) + const auto& characteristicDescriptors = characteristic.descriptors(); + for (const auto& descriptor : characteristicDescriptors) { qCDebug(bluetooth) << "Found service characteristic descriptor" << descriptor.uuid(); } @@ -246,7 +247,7 @@ QLowEnergyService::WriteMode CyberJackWaveDevice::determineWriteMode(int pBlockI * confirmation response. */ static int IOS_CONFIRMATION_BLOCK_NUMBER = 6; - return pBlockIndex % IOS_CONFIRMATION_BLOCK_NUMBER ? QLowEnergyService::WriteWithoutResponse : QLowEnergyService::WriteWithResponse; + return (pBlockIndex % IOS_CONFIRMATION_BLOCK_NUMBER) ? QLowEnergyService::WriteWithoutResponse : QLowEnergyService::WriteWithResponse; #else Q_UNUSED(pBlockIndex); diff --git a/src/card/bluetooth/CyberJackWaveDevice.h b/src/card/bluetooth/CyberJackWaveDevice.h index 34a033a..5cae105 100644 --- a/src/card/bluetooth/CyberJackWaveDevice.h +++ b/src/card/bluetooth/CyberJackWaveDevice.h @@ -1,9 +1,7 @@ /*! - * CyberJackWaveDevice.h - * * \brief Implementation of a Reiner SCT cyberJack wave device. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/NotificationEnabler.cpp b/src/card/bluetooth/NotificationEnabler.cpp index 336245b..a02678e 100644 --- a/src/card/bluetooth/NotificationEnabler.cpp +++ b/src/card/bluetooth/NotificationEnabler.cpp @@ -1,8 +1,7 @@ /*! - * NotificationEnabler.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ + #include "NotificationEnabler.h" #include diff --git a/src/card/bluetooth/NotificationEnabler.h b/src/card/bluetooth/NotificationEnabler.h index d23d372..50acd71 100644 --- a/src/card/bluetooth/NotificationEnabler.h +++ b/src/card/bluetooth/NotificationEnabler.h @@ -1,6 +1,4 @@ /*! - * NotificationEnabler.h - * * \brief If a QLowEnergyCharacteristic is able to notify about changes, i.e. * it has property QLowEnergyCharacteristic::PropertyType::Notify, * one needs to enable notification explicitly. @@ -8,7 +6,7 @@ * * For details see the Qt documentation on QLowEnergyService and topic "Service Interaction". * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -45,7 +43,8 @@ class NotificationEnabler public: /*! - * \param QLowEnergyService the service corresponding to the characteristic to be enabled/disabled. + * \param pService the service corresponding to the characteristic to be enabled/disabled. + * \param pTimeoutSeconds time out in seconds. */ NotificationEnabler(QLowEnergyService* pService, int pTimeoutSeconds = 5); virtual ~NotificationEnabler(); diff --git a/src/card/bluetooth/SynchronousBtCall.cpp b/src/card/bluetooth/SynchronousBtCall.cpp index 7268325..632d8f7 100644 --- a/src/card/bluetooth/SynchronousBtCall.cpp +++ b/src/card/bluetooth/SynchronousBtCall.cpp @@ -1,7 +1,5 @@ /*! - * SynchronousBtCall.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "SynchronousBtCall.h" diff --git a/src/card/bluetooth/SynchronousBtCall.h b/src/card/bluetooth/SynchronousBtCall.h index 4ce3efa..23ee24d 100644 --- a/src/card/bluetooth/SynchronousBtCall.h +++ b/src/card/bluetooth/SynchronousBtCall.h @@ -1,10 +1,8 @@ /*! - * SynchronousBtCall.h - * * \brief Helper class to make a synchronous call to a Bluetooth device, i.e. * send the request data and wait for the response data to arrive. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothIDs.cpp b/src/card/bluetooth/messages/BluetoothIDs.cpp index cdf2708..3cee50c 100644 --- a/src/card/bluetooth/messages/BluetoothIDs.cpp +++ b/src/card/bluetooth/messages/BluetoothIDs.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothIDs.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothIDs.h" diff --git a/src/card/bluetooth/messages/BluetoothIDs.h b/src/card/bluetooth/messages/BluetoothIDs.h index caf7778..d4ef589 100644 --- a/src/card/bluetooth/messages/BluetoothIDs.h +++ b/src/card/bluetooth/messages/BluetoothIDs.h @@ -1,9 +1,7 @@ /*! - * BluetoothIDs.h - * * \brief Add message and parameter types of bluetooth SIM ACCESS spec * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessage.cpp b/src/card/bluetooth/messages/BluetoothMessage.cpp index 173d50f..f280249 100644 --- a/src/card/bluetooth/messages/BluetoothMessage.cpp +++ b/src/card/bluetooth/messages/BluetoothMessage.cpp @@ -1,17 +1,21 @@ /*! - * BluetoothMessage.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessage.h" +#include "Initializer.h" + #include Q_DECLARE_LOGGING_CATEGORY(bluetooth) using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType("BluetoothMessage::Ptr"); + }); + QDebug operator<<(QDebug pDbg, const governikus::BluetoothMessage& pMsg) { @@ -68,8 +72,8 @@ QByteArray BluetoothMessage::toData() const return QByteArray(); } data += static_cast(mMessageParameter.size()); - data += char(0x00); - data += char(0x00); + data += '\0'; + data += '\0'; for (const auto& parameter : qAsConst(mMessageParameter)) { @@ -91,14 +95,3 @@ QString BluetoothMessage::toString() const } 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 dcb99f8..8ff7642 100644 --- a/src/card/bluetooth/messages/BluetoothMessage.h +++ b/src/card/bluetooth/messages/BluetoothMessage.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessage.h - * * \brief Implements a message of SIM ACCESS profile. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,7 +19,7 @@ namespace governikus class BluetoothMessage { public: - typedef QSharedPointer Ptr; + using Ptr = QSharedPointer; private: friend class ::test_BluetoothMessageParser; @@ -45,8 +43,6 @@ class BluetoothMessage BluetoothMsgId getBluetoothMsgId() const; QByteArray toData() const; QString toString() const; - - static void registerMetaTypes(); }; } /* namespace governikus */ diff --git a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp index 4ab2cb7..64c55ea 100644 --- a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/BluetoothMessageConnectResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.h b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.h index 2b1837c..b138291 100644 --- a/src/card/bluetooth/messages/BluetoothMessageConnectResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageConnectResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageCreator.cpp b/src/card/bluetooth/messages/BluetoothMessageCreator.cpp index ba53b43..4e526d6 100644 --- a/src/card/bluetooth/messages/BluetoothMessageCreator.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageCreator.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageCreator.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/src/card/bluetooth/messages/BluetoothMessageCreator.h b/src/card/bluetooth/messages/BluetoothMessageCreator.h index 881d896..83effa5 100644 --- a/src/card/bluetooth/messages/BluetoothMessageCreator.h +++ b/src/card/bluetooth/messages/BluetoothMessageCreator.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageCreator.h - * * \brief Provides an easy to use API to create requests. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.cpp index 3ed216d..aee2d92 100644 --- a/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/BluetoothMessageDisconnectResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.h b/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.h index f02525e..dcd6775 100644 --- a/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageDisconnectResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageParser.cpp b/src/card/bluetooth/messages/BluetoothMessageParser.cpp index 091eec3..47ebb78 100644 --- a/src/card/bluetooth/messages/BluetoothMessageParser.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageParser.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParser.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageConnectResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageParser.h b/src/card/bluetooth/messages/BluetoothMessageParser.h index 38c182f..cdf7aa7 100644 --- a/src/card/bluetooth/messages/BluetoothMessageParser.h +++ b/src/card/bluetooth/messages/BluetoothMessageParser.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParser.h - * * \brief Parses messages of bluetooth SIM ACCESS protocol. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp index c8f8547..f8e1207 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/BluetoothMessagePowerSimOffResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.h b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.h index 9b411ed..1b2a963 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOffResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp index a62ed23..f0c03d3 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothIDs.h" diff --git a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.h b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.h index 38c0e8a..01da060 100644 --- a/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessagePowerSimOnResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp index 319d9c4..ffe2cc6 100644 --- a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/BluetoothMessageResetSimResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.h b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.h index 3657077..09582aa 100644 --- a/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageResetSimResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp index 79de393..56f158f 100644 --- a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageSetTransportProtocolResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.h b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.h index 6863031..0657d58 100644 --- a/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageSetTransportProtocolResponse.h @@ -1,7 +1,7 @@ /*! * \brief Store information of SetTransportProtocolResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp b/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp index b045e63..6f04299 100644 --- a/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageStatusInd.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageStatusInd.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageStatusInd.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageStatusInd.h b/src/card/bluetooth/messages/BluetoothMessageStatusInd.h index 817f96f..f13b39b 100644 --- a/src/card/bluetooth/messages/BluetoothMessageStatusInd.h +++ b/src/card/bluetooth/messages/BluetoothMessageStatusInd.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageStatusInd.h - * * \brief Implements special BluetoothMessage for StatusInd. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp index dfce8a4..dd3f790 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/BluetoothMessageTransferApduResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.h b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.h index 24da08a..e96275d 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageTransferApduResponse.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp index 90667f7..542a4b3 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp +++ b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageTransferCardReaderStatusResponse.h" diff --git a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.h b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.h index 08557bc..bbe050e 100644 --- a/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.h +++ b/src/card/bluetooth/messages/BluetoothMessageTransferCardReaderStatusResponse.h @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/BluetoothUtils.cpp b/src/card/bluetooth/messages/BluetoothUtils.cpp index c5ad031..87d24b4 100644 --- a/src/card/bluetooth/messages/BluetoothUtils.cpp +++ b/src/card/bluetooth/messages/BluetoothUtils.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothUtils.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothUtils.h" @@ -32,6 +30,6 @@ void BluetoothUtils::addPadding(QByteArray& pData, const QByteArray& pContent, u ushort paddingLength = getPaddingLength(static_cast(pContent.size()), pPaddingLen); for (ushort i = 0; i < paddingLength; ++i) { - pData += char(0x00); + pData += '\0'; } } diff --git a/src/card/bluetooth/messages/BluetoothUtils.h b/src/card/bluetooth/messages/BluetoothUtils.h index 844ec4b..3d76522 100644 --- a/src/card/bluetooth/messages/BluetoothUtils.h +++ b/src/card/bluetooth/messages/BluetoothUtils.h @@ -1,9 +1,7 @@ /*! - * BluetoothUtils.h - * * \brief Some helper utils for bluetooth messages. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp index 3419559..e34a336 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameter.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameter.h" @@ -67,7 +65,7 @@ QByteArray BluetoothMessageParameter::toData() const { QByteArray data; data += Enum::getValue(mParamId); - data += char(0x00); + data += '\0'; if (mValue.size() > 0xFFFF) { qCCritical(bluetooth) << "Value of BluetoothMessageParameter of size > 0xFFFF not supported"; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h index db27c27..582a0a4 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameter.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameter.h - * * \brief Implements message parameter of SIM ACCESS spec. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -52,7 +50,7 @@ class BluetoothMessageParameter public: - typedef QSharedPointer Ptr; + using Ptr = QSharedPointer; BluetoothMessageParameter(BluetoothParamId pParamId, const QByteArray& pValue); virtual ~BluetoothMessageParameter(); diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.cpp index 25212f2..1e0ff2c 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameterApduResponse.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameterApduResponse.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.h index a2c92ef..f45194d 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterApduResponse.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameterApduResponse.h - * * \brief Implements special BluetoothMessageParameter for TransferApduResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -18,7 +16,7 @@ class BluetoothMessageParameterApduResponse { public: BluetoothMessageParameterApduResponse(const QByteArray& pApdu); - virtual ~BluetoothMessageParameterApduResponse(); + virtual ~BluetoothMessageParameterApduResponse() override; const QByteArray& getResponseApdu() const; virtual QString toStringValue() const override; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.cpp index f7130e0..6261649 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/parameter/BluetoothMessageParameterCardReaderStatus.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.h index 76aabab..fcb4799 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterCardReaderStatus.h @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -16,10 +16,10 @@ class BluetoothMessageParameterCardReaderStatus BluetoothCardReaderStatus mCardReaderStatus; public: - typedef QSharedPointer Ptr; + using Ptr = QSharedPointer; BluetoothMessageParameterCardReaderStatus(const QByteArray& pValue); - virtual ~BluetoothMessageParameterCardReaderStatus(); + virtual ~BluetoothMessageParameterCardReaderStatus() override; BluetoothStatusChange getStatusChange() const; BluetoothCardReaderStatus getCardReaderStatus() const; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.cpp index 7894692..f5f3ac3 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameterConnectionStatus.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameterConnectionStatus.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.h index 28cf59d..fdf9b5c 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterConnectionStatus.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameterConnectionStatus.h - * * \brief Implements special BluetoothMessageParameter for ConnectionStatus. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,7 +19,7 @@ class BluetoothMessageParameterConnectionStatus public: BluetoothMessageParameterConnectionStatus(const QByteArray& pValue); - virtual ~BluetoothMessageParameterConnectionStatus(); + virtual ~BluetoothMessageParameterConnectionStatus() override; BluetoothConnectionStatus getResultCode() const; virtual QString toStringValue() const override; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp index 419e6ea..c0de551 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameterMaxMsgSize.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameterMaxMsgSize.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h index ca13e52..ec791a7 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterMaxMsgSize.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameterMaxMsgSize.h - * * \brief Implements special BluetoothMessageParameter for MaxMsgSize. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +20,7 @@ class BluetoothMessageParameterMaxMsgSize public: BluetoothMessageParameterMaxMsgSize(const QByteArray& pValue); BluetoothMessageParameterMaxMsgSize(uint pMaxMsgSize); - virtual ~BluetoothMessageParameterMaxMsgSize(); + virtual ~BluetoothMessageParameterMaxMsgSize() override; unsigned int getMaxMsgSize() const; virtual QString toStringValue() const override; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.cpp index 6f7b5b8..7bcc222 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameterResultCode.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameterResultCode.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.h index 76e88f2..4b511a3 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterResultCode.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameterResultCode.h - * * \brief Implements special BluetoothMessageParameter for ResultCode. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,7 +19,7 @@ class BluetoothMessageParameterResultCode public: BluetoothMessageParameterResultCode(const QByteArray& pValue); - virtual ~BluetoothMessageParameterResultCode(); + virtual ~BluetoothMessageParameterResultCode() override; BluetoothResultCode getResultCode() const; virtual QString toStringValue() const override; diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.cpp b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.cpp index d3b81a7..cb8ae11 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.cpp +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.cpp @@ -1,7 +1,5 @@ /*! - * BluetoothMessageParameterStatusChange.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "BluetoothMessageParameterStatusChange.h" diff --git a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.h b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.h index e180a6d..7ef2f80 100644 --- a/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.h +++ b/src/card/bluetooth/messages/parameter/BluetoothMessageParameterStatusChange.h @@ -1,9 +1,7 @@ /*! - * BluetoothMessageParameterStatusChange.h - * * \brief Implements special BluetoothMessageParameter for StatusChange. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -20,10 +18,10 @@ class BluetoothMessageParameterStatusChange BluetoothStatusChange mStatusChange; public: - typedef QSharedPointer Ptr; + using Ptr = QSharedPointer; BluetoothMessageParameterStatusChange(const QByteArray& pValue); - virtual ~BluetoothMessageParameterStatusChange(); + virtual ~BluetoothMessageParameterStatusChange() override; BluetoothStatusChange getStatusChange() const; virtual QString toStringValue() const override; diff --git a/src/card/drivers/CMakeLists.txt b/src/card/drivers/CMakeLists.txt index 92f700c..b279e62 100644 --- a/src/card/drivers/CMakeLists.txt +++ b/src/card/drivers/CMakeLists.txt @@ -1,6 +1,6 @@ ADD_PLATFORM_LIBRARY(AusweisAppCardDrivers) -TARGET_LINK_LIBRARIES(AusweisAppCardDrivers Qt5::Core AusweisAppGlobal AusweisAppCard AusweisAppSettings) +TARGET_LINK_LIBRARIES(AusweisAppCardDrivers Qt5::Core AusweisAppGlobal AusweisAppConfiguration) IF(WIN32) TARGET_LINK_LIBRARIES(AusweisAppCardDrivers ${WIN_DEFAULT_LIBS}) @@ -13,7 +13,7 @@ ENDIF() IF(LINUX) IF(LIBUDEV) TARGET_LINK_LIBRARIES(AusweisAppCardDrivers ${LIBUDEV}) - ADD_DEFINITION("HAVE_LIBUDEV" "ReaderDetector_linux.cpp") + SET_PROPERTY(SOURCE "ReaderDetector_linux.cpp" APPEND_STRING PROPERTY COMPILE_FLAGS " -DHAVE_LIBUDEV") ELSE() MESSAGE(STATUS "Hardware detection disabled - Missing libudev") ENDIF() diff --git a/src/card/drivers/DeviceDescriptor.cpp b/src/card/drivers/DeviceDescriptor.cpp deleted file mode 100644 index 9a18e68..0000000 --- a/src/card/drivers/DeviceDescriptor.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "DeviceDescriptor.h" - -using namespace governikus; - - -DeviceDescriptor::DeviceDescriptor(const QSharedPointer& pDriver) - : mDriver(pDriver) - , mReaderType(pDriver.isNull() ? - ReaderType::UNKNOWN : - Enum::fromString(pDriver->getReaderType(), ReaderType::UNKNOWN)) - , mHasDriver(false) -{ -} - - -DeviceDescriptor::~DeviceDescriptor() -{ -} - - -void DeviceDescriptor::checkDriver(const QVector& pReaderTypes) -{ - mHasDriver = pReaderTypes.contains(mReaderType); -} - - -ReaderType DeviceDescriptor::getReaderType() const -{ - return mReaderType; -} - - -uint DeviceDescriptor::getVendorId() const -{ - return mReaderType == ReaderType::UNKNOWN ? 0 : mDriver->getVendorId(); -} - - -uint DeviceDescriptor::getProductId() const -{ - return mReaderType == ReaderType::UNKNOWN ? 0 : mDriver->getProductId(); -} - - -QString DeviceDescriptor::getName() const -{ - return mReaderType == ReaderType::UNKNOWN ? QString() : mDriver->getName(); -} - - -QString DeviceDescriptor::getDriverUrl() const -{ - return mReaderType == ReaderType::UNKNOWN ? QString() : mDriver->getUrl(); -} - - -bool DeviceDescriptor::hasDriver() const -{ - return mHasDriver; -} diff --git a/src/card/drivers/DeviceDescriptor.h b/src/card/drivers/DeviceDescriptor.h deleted file mode 100644 index 248243d..0000000 --- a/src/card/drivers/DeviceDescriptor.h +++ /dev/null @@ -1,56 +0,0 @@ -/*! - * \brief Information about reader drivers containing general information such - * as issue date, and detailed information (vendor id, product id, driver - * URL, etc) about each known card reader device. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "DriverSettings.h" -#include "SmartCardDefinitions.h" - -#include -#include -#include - -namespace governikus -{ -/*! - * \brief Class that stores detailed information (vendor id, product id, driver - * URL, etc) about a single card reader device. - */ -class DeviceDescriptor -{ - private: - const QSharedPointer mDriver; - - const ReaderType mReaderType; - - bool mHasDriver; - - Q_DISABLE_COPY(DeviceDescriptor) - - public: - DeviceDescriptor(const QSharedPointer& pDriver); - - ~DeviceDescriptor(); - - void checkDriver(const QVector& pReaderTypes); - - ReaderType getReaderType() const; - - uint getVendorId() const; - - uint getProductId() const; - - QString getName() const; - - QString getDriverUrl() const; - - bool hasDriver() const; -}; - - -} /* namespace governikus */ diff --git a/src/card/drivers/ReaderDetector.cpp b/src/card/drivers/ReaderDetector.cpp index 5dbbfeb..7e4af67 100644 --- a/src/card/drivers/ReaderDetector.cpp +++ b/src/card/drivers/ReaderDetector.cpp @@ -1,78 +1,38 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "FileDestination.h" #include "ReaderDetector.h" +#include "Env.h" +#include "FuncUtils.h" +#include "ReaderConfiguration.h" +#include "SingletonHelper.h" + #include #include +#include +#include using namespace governikus; +defineSingleton(ReaderDetector) + + Q_DECLARE_LOGGING_CATEGORY(card_drivers) -static QVector readerTypesForReaderInfos(const QVector& pReaderInfos) +ReaderDetector & ReaderDetector::getInstance() { - QVector readerTypes; - readerTypes.reserve(pReaderInfos.size()); - for (const auto& readerInfo : pReaderInfos) - { - readerTypes += readerInfo.getReaderType(); - } - - return readerTypes; + return *Instance; } -QVector > ReaderDetector::convertSettings(const QSharedPointer& pSettings) -{ - if (pSettings.isNull()) - { - qCWarning(card_drivers) << "invalid input settings"; - - return QVector >(); - } - - QVector > devices; - for (const auto& driver : pSettings->getDrivers()) - { - const QSharedPointer device(new DeviceDescriptor(driver)); - if (device->getReaderType() == ReaderType::UNKNOWN) - { - qCWarning(card_drivers) << "invalid reader type in input settings, bailing out"; - - return QVector >(); - } - - devices += device; - } - - return devices; -} - - -QSharedPointer ReaderDetector::lookupDevice(uint pVendorId, uint pProductId) const -{ - for (const auto& descriptor : mSupportedDevices) - { - if (pVendorId == descriptor->getVendorId() && pProductId == descriptor->getProductId()) - { - return descriptor; - } - } - - return QSharedPointer(); -} - - -ReaderDetector::ReaderDetector(const QSharedPointer& pDriverSettings) - : mSupportedDevices(convertSettings(pDriverSettings)) +ReaderDetector::ReaderDetector() #ifdef Q_OS_LINUX - , mDeviceListener(nullptr) + : mDeviceListener(nullptr) #endif { qCDebug(card_drivers) << "initNativeEvents() =" << initNativeEvents(); @@ -85,21 +45,39 @@ ReaderDetector::~ReaderDetector() } -QVector > ReaderDetector::getAttachedDevices(const QVector& pReaderInfos) const +QVector ReaderDetector::getAttachedSupportedDevices() const { - const auto readerTypes = readerTypesForReaderInfos(pReaderInfos); + const auto& readerConfiguration = Env::getSingleton(); + QVector attachedSupportedDevices; - QVector > result; - for (const auto& devId : attachedDevIds()) + const auto& devIds = attachedDevIds(); + for (const auto& devId : devIds) { - const uint vendorId = devId.first; - const uint productId = devId.second; - const QSharedPointer device = lookupDevice(vendorId, productId); - if (device) + const auto& readerConfigurationInfo = readerConfiguration->getReaderConfigurationInfoById(devId); + if (readerConfigurationInfo.isKnownReader() && !readerConfigurationInfo.getUrl().isEmpty()) { - device->checkDriver(readerTypes); - result += device; + qCDebug(card_drivers) << "Found known reader:" << devId; + attachedSupportedDevices += readerConfigurationInfo; } } - return result; + return attachedSupportedDevices; +} + + +ReaderConfigurationInfo ReaderDetector::getReaderConfigurationInfo(const QString& pReaderName) +{ + QVector attachedSupportedDevices = getAttachedSupportedDevices(); + attachedSupportedDevices += Env::getSingleton()->getRemoteReaderConfigurationInfo(); + + for (const auto& info : qAsConst(attachedSupportedDevices)) + { + const QString& pattern = info.getPattern(); + const QRegularExpression expression(pattern.isEmpty() ? info.getName() : pattern); + if (pReaderName.contains(expression)) + { + return info; + } + } + + return ReaderConfigurationInfo(pReaderName); } diff --git a/src/card/drivers/ReaderDetector.h b/src/card/drivers/ReaderDetector.h index 1e31d07..7ce69a8 100644 --- a/src/card/drivers/ReaderDetector.h +++ b/src/card/drivers/ReaderDetector.h @@ -2,16 +2,15 @@ * \brief Interface specifying classes that can detect the attached card reader * devices on a specific platform. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "DeviceDescriptor.h" -#include "DriverSettings.h" -#include "ReaderInfo.h" +#include "ReaderConfiguration.h" +#include "UsbId.h" -#ifdef Q_OS_OSX +#ifdef Q_OS_MACOS #include #endif @@ -29,6 +28,7 @@ class DeviceListener; namespace governikus { + class ReaderDetector : public QObject #ifdef Q_OS_WIN @@ -38,34 +38,29 @@ class ReaderDetector Q_OBJECT private: - const QVector > mSupportedDevices; - - #ifdef Q_OS_OSX + #ifdef Q_OS_MACOS io_iterator_t mIteratorPublish; io_iterator_t mIteratorTerminated; #endif #ifdef Q_OS_LINUX - DeviceListener* mDeviceListener; + DeviceListener * mDeviceListener; #endif bool initNativeEvents(); bool terminateNativeEvents(); - protected: - static QVector > convertSettings(const QSharedPointer& pSettings); - - QSharedPointer lookupDevice(uint pVendorId, uint pProductId) const; - - virtual QVector > attachedDevIds() const; - public: - ReaderDetector(const QSharedPointer& pDriverSettings); + static ReaderDetector& getInstance(); + + ReaderDetector(); virtual ~ReaderDetector(); + virtual QVector attachedDevIds() const; + #ifdef Q_OS_WIN bool nativeEventFilter(const QByteArray& pEventType, void* pMessage, long* pResult) override; #endif @@ -74,7 +69,9 @@ class ReaderDetector * \brief getAttachedDevices produce a list of supported devices that are * attached to the system */ - QVector > getAttachedDevices(const QVector& pReaderInfos) const; + QVector getAttachedSupportedDevices() const; + + ReaderConfigurationInfo getReaderConfigurationInfo(const QString& pReaderName); Q_SIGNALS: void fireReaderChangeDetected(); diff --git a/src/card/drivers/ReaderDetector_generic.cpp b/src/card/drivers/ReaderDetector_generic.cpp index 9e5d65d..649fa91 100644 --- a/src/card/drivers/ReaderDetector_generic.cpp +++ b/src/card/drivers/ReaderDetector_generic.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderDetector.h" @@ -20,7 +20,7 @@ bool ReaderDetector::terminateNativeEvents() } -QVector > ReaderDetector::attachedDevIds() const +QVector ReaderDetector::attachedDevIds() const { - return QVector >(); + return QVector(); } diff --git a/src/card/drivers/ReaderDetector_linux.cpp b/src/card/drivers/ReaderDetector_linux.cpp index c9fc973..dc71c3a 100644 --- a/src/card/drivers/ReaderDetector_linux.cpp +++ b/src/card/drivers/ReaderDetector_linux.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderDetector.h" @@ -24,17 +24,16 @@ class DeviceListener { Q_OBJECT - private: #ifdef HAVE_LIBUDEV + + private: struct udev* mUserDevices; struct udev_monitor* mDeviceMonitor; int mFileDescriptor; -#endif - void run() override + virtual void run() override { -#ifdef HAVE_LIBUDEV - for (;; ) + for (;;) { fd_set fds; FD_ZERO(&fds); @@ -53,14 +52,12 @@ class DeviceListener Q_EMIT fireDeviceChangeDetected(); } } -#endif } public: DeviceListener() { -#ifdef HAVE_LIBUDEV mUserDevices = udev_new(); // Set up a monitor to monitor usb devices @@ -70,19 +67,19 @@ class DeviceListener /// Get the file descriptor (fd) for the monitor mFileDescriptor = udev_monitor_get_fd(mDeviceMonitor); -#endif } - ~DeviceListener() + virtual ~DeviceListener() override { -#ifdef HAVE_LIBUDEV udev_monitor_unref(mDeviceMonitor); udev_unref(mUserDevices); -#endif } +#endif + + public: Q_SIGNALS: void fireDeviceChangeDetected(); }; @@ -109,9 +106,9 @@ bool ReaderDetector::terminateNativeEvents() } -QVector > ReaderDetector::attachedDevIds() const +QVector ReaderDetector::attachedDevIds() const { - QVector > result; + QVector result; #ifdef HAVE_LIBUDEV // http://www.signal11.us/oss/udev/ @@ -146,10 +143,6 @@ QVector > ReaderDetector::attachedDevIds() const const char* path = udev_list_entry_get_name(dev_list_entry); struct udev_device* dev = udev_device_new_from_syspath(udev, path); - /* usb_device_get_devnode() returns the path to the device node - itself in /dev. */ - qCDebug(card_drivers) << "Device Node Path:" << udev_device_get_devnode(dev); - /* The device pointed to by dev contains information about the hidraw device. In order to get information about the USB device, get the parent device with the @@ -159,7 +152,6 @@ QVector > ReaderDetector::attachedDevIds() const dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); if (!dev) { - qCDebug(card_drivers) << "Unable to find parent usb device."; continue; } @@ -172,10 +164,8 @@ QVector > ReaderDetector::attachedDevIds() const udev_device_get_sysattr_value() are UTF-8 encoded. */ QByteArray vid(udev_device_get_sysattr_value(dev, "idVendor")); QByteArray pid(udev_device_get_sysattr_value(dev, "idProduct")); - result += QPair(vid.toUInt(nullptr, 16), pid.toUInt(nullptr, 16)); - qCDebug(card_drivers) << "VID / PID:" << vid << "/" << pid; - qCDebug(card_drivers) << "Manufacturer:" << udev_device_get_sysattr_value(dev, "manufacturer"); - qCDebug(card_drivers) << "Product:" << udev_device_get_sysattr_value(dev, "product"); + const UsbId usbId(vid.toUInt(nullptr, 16), pid.toUInt(nullptr, 16)); + result += usbId; udev_device_unref(dev); } diff --git a/src/card/drivers/ReaderDetector_osx.cpp b/src/card/drivers/ReaderDetector_osx.cpp index e06ea8d..c9cc779 100644 --- a/src/card/drivers/ReaderDetector_osx.cpp +++ b/src/card/drivers/ReaderDetector_osx.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderDetector.h" @@ -125,7 +125,7 @@ static bool getUintValueFromDeviceRegistryEntry(io_object_t pDevice, CFStringRef } -static QPair getDeviceIds(io_object_t pDevice) +static UsbId getDeviceIds(io_object_t pDevice) { uint vendorId = 0x0; uint productId = 0x0; @@ -134,23 +134,23 @@ static QPair getDeviceIds(io_object_t pDevice) { qCDebug(card_drivers) << "missing or invalid vendor id"; - return QPair(0x0, 0x0); + return UsbId(0x0, 0x0); } if (!getUintValueFromDeviceRegistryEntry(pDevice, CFSTR(PRODUCT_ID), &productId)) { qCDebug(card_drivers) << "missing or invalid product id"; - return QPair(0x0, 0x0); + return UsbId(0x0, 0x0); } - return QPair(vendorId, productId); + return UsbId(vendorId, productId); } -QVector > ReaderDetector::attachedDevIds() const +QVector ReaderDetector::attachedDevIds() const { - QVector > result; + QVector result; mach_port_t myMasterPort = kIOMasterPortDefault; io_iterator_t deviceIterator = 0; io_object_t currentDevice = 0; @@ -160,19 +160,15 @@ QVector > ReaderDetector::attachedDevIds() const { qCWarning(card_drivers) << "creation of device iterator failed, exiting"; - return QVector >(); + return QVector(); } currentDevice = IOIteratorNext(deviceIterator); while (currentDevice != 0) { - QPair ids = getDeviceIds(currentDevice); - if (ids.first != 0 && ids.second != 0) + UsbId ids = getDeviceIds(currentDevice); + if (ids.getVendorId() != 0 && ids.getProductId() != 0) { - const QString vendorId = QString::number(ids.first, 16); - const QString productId = QString::number(ids.second, 16); - qCDebug(card_drivers) << "found device with vendor id =" << vendorId << "product id =" << productId; - result += ids; } diff --git a/src/card/drivers/ReaderDetector_win.cpp b/src/card/drivers/ReaderDetector_win.cpp index d21445d..a7810ae 100644 --- a/src/card/drivers/ReaderDetector_win.cpp +++ b/src/card/drivers/ReaderDetector_win.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderDetector.h" @@ -111,9 +111,9 @@ static uint getProductId(const QString& pDevId) } -QVector > ReaderDetector::attachedDevIds() const +QVector ReaderDetector::attachedDevIds() const { - QVector > result; + QVector result; for (auto stringDevId : attachedDevStringIds()) { @@ -121,7 +121,7 @@ QVector > ReaderDetector::attachedDevIds() const const uint productId = getProductId(stringDevId); if (vendorId != 0 && productId != 0) { - result += QPair(vendorId, productId); + result += UsbId(vendorId, productId); } } diff --git a/src/card/nfc/CMakeLists.txt b/src/card/nfc/CMakeLists.txt index 4112805..858670e 100644 --- a/src/card/nfc/CMakeLists.txt +++ b/src/card/nfc/CMakeLists.txt @@ -1,6 +1,6 @@ ADD_PLATFORM_LIBRARY(AusweisAppCardNfc) -TARGET_LINK_LIBRARIES(AusweisAppCardNfc Qt5::Core AusweisAppGlobal AusweisAppCard) +TARGET_LINK_LIBRARIES(AusweisAppCardNfc Qt5::Core Qt5::Nfc AusweisAppGlobal AusweisAppCard) TARGET_COMPILE_DEFINITIONS(AusweisAppCardNfc PRIVATE QT_STATICPLUGIN) IF(ANDROID) diff --git a/src/card/nfc/NFCConnector.java b/src/card/nfc/NFCConnector.java deleted file mode 100644 index eeee441..0000000 --- a/src/card/nfc/NFCConnector.java +++ /dev/null @@ -1,349 +0,0 @@ -package com.governikus.ausweisapp2; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Arrays; - - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.nfc.tech.IsoDep; -import android.nfc.Tag; -import android.nfc.TagLostException; -import android.util.Log; - - -public class NFCConnector -{ - - public static enum NfcCardCode - { - NO_CARD(0), - SAME_CARD(1), - NEW_CARD(2); - - private byte mVal; - NfcCardCode(int pVal) - { - mVal = (byte) pVal; - } - public byte toByte() - { - return mVal; - } - - - } - - - public static enum NfcConnectorCode - { - SUCCESS(0), - ERROR_NO_NFC(-1), - ERROR_NO_TAG(-2), - ERROR_CONNECT(-3), - ERROR_TAG_LOST(-4), - ERROR_TRANSMIT(-5), - ERROR_UNKNOWN(-16); - - - private byte mVal; - NfcConnectorCode(int pVal) - { - mVal = (byte) pVal; - } - public byte toByte() - { - return mVal; - } - - - } - - private static final byte[] SUCCESS_BYTE = { - NfcConnectorCode.SUCCESS.toByte() - }; - private static final byte[] ERROR_NO_NFC_BYTE = { - NfcConnectorCode.ERROR_NO_NFC.toByte() - }; - private static final byte[] ERROR_NO_TAG_BYTE = { - NfcConnectorCode.ERROR_NO_TAG.toByte() - }; - private static final byte[] ERROR_CONNECT_BYTE = { - NfcConnectorCode.ERROR_CONNECT.toByte() - }; - private static final byte[] ERROR_TAG_LOST_BYTE = { - NfcConnectorCode.ERROR_TAG_LOST.toByte() - }; - private static final byte[] ERROR_TRANSMIT_BYTE = { - NfcConnectorCode.ERROR_TRANSMIT.toByte() - }; - private static final byte[] ERROR_UNKNOWN_BYTE = { - NfcConnectorCode.ERROR_UNKNOWN.toByte() - }; - - - public static enum ExtendedLengthApduSupportCode - { - UNKNOWN(-1), - NOT_SUPPORTED(0), - SUPPORTED(1); - - - private byte mVal; - ExtendedLengthApduSupportCode(int pVal) - { - mVal = (byte) pVal; - } - public byte toByte() - { - return mVal; - } - - - } - - 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); - 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; - } - } - } - - - public synchronized byte start() - { - if (mNfcAdapter == null) - { - return NfcConnectorCode.ERROR_NO_NFC.toByte(); - } - - return NfcConnectorCode.SUCCESS.toByte(); - } - - - public synchronized byte stop() - { - if (mTag != null) - { - if (mTag.isConnected()) - { - try - { - mTag.close(); - } - catch (IOException e) - { - // nothing - } - } - 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 (mNfcAdapter == null) - { - return ERROR_NO_NFC_BYTE; - } - - if (mTag == null) - { - return ERROR_NO_TAG_BYTE; - } - if (!mTag.isConnected()) - { - Log.e(LOG_TAG, "Card is not connected"); - return ERROR_CONNECT_BYTE; - } - - try - { - byte[] cardAnswer; - try - { - cardAnswer = mTag.transceive(data); - } - catch (TagLostException e) - { - mTag = null; - return ERROR_TAG_LOST_BYTE; - } - catch (IOException e) - { - return ERROR_TRANSMIT_BYTE; - } - - ByteBuffer buffer = ByteBuffer.allocate(1 + cardAnswer.length); - buffer.put(SUCCESS_BYTE); - buffer.put(cardAnswer); - return buffer.array(); - } - catch (Throwable t) - { - Log.e(LOG_TAG, "Cannot send data ", t); - return ERROR_UNKNOWN_BYTE; - } - } - - - public synchronized byte getExtendedLengthApduSupportStatus() - { - return mExtendedLengthApduSupportStatus.toByte(); - } - - - public synchronized byte isCardPresent() - { - if (mNfcAdapter == null) - { - return NfcConnectorCode.ERROR_NO_NFC.toByte(); - } - - if (mTag == null) - { - return NfcCardCode.NO_CARD.toByte(); - } - - if (!mTag.isConnected()) - { - try - { - mTag.connect(); - if (!mTag.isConnected()) - { - return NfcCardCode.NO_CARD.toByte(); - } - mTag.close(); - } - catch (IOException e) - { - return NfcCardCode.NO_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/NfcAdapterStateChangeReceiver.java b/src/card/nfc/NfcAdapterStateChangeReceiver.java deleted file mode 100644 index 56f406e..0000000 --- a/src/card/nfc/NfcAdapterStateChangeReceiver.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.governikus.ausweisapp2; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.util.Log; - - -enum NfcAdapterState -{ - STATE_UNKNOWN(-1), - STATE_OFF(NfcAdapter.STATE_OFF), - STATE_TURNING_ON(NfcAdapter.STATE_TURNING_ON), - STATE_ON(NfcAdapter.STATE_ON), - STATE_TURNING_OFF(NfcAdapter.STATE_TURNING_OFF); - - - public int value; - - private NfcAdapterState(int value) - { - this.value = value; - } - - public static NfcAdapterState forInt(int value) - { - for (NfcAdapterState state : NfcAdapterState.values()) - { - if (state.value == value) - { - return state; - } - } - Log.e(NfcAdapterStateChangeReceiver.LOG_TAG, "Unknown state " + value); - return STATE_UNKNOWN; - } - - -} - - -public class NfcAdapterStateChangeReceiver extends BroadcastReceiver -{ - static final String LOG_TAG = "AusweisApp2"; - - private static NfcAdapterStateChangeReceiver singleInstance = new NfcAdapterStateChangeReceiver(); - - - private NfcAdapterStateChangeReceiver() - { - super(); - } - - - @Override - public void onReceive(Context context, Intent intent) - { - NfcAdapterState state = NfcAdapterState.forInt(intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1)); - Log.d(LOG_TAG, "nfc state changed to " + state); - nfcAdapterStateChanged(state.value); - } - - - private native void nfcAdapterStateChanged(int newState); - - - public static void register(Context context) - { - try - { - context.registerReceiver(NfcAdapterStateChangeReceiver.singleInstance, new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)); - } - catch (Throwable t) - { - Log.e(LOG_TAG, "Cannot register", t); - } - } - - - public static void unregister(Context context) - { - try - { - context.unregisterReceiver(NfcAdapterStateChangeReceiver.singleInstance); - } - catch (Throwable t) - { - Log.e(LOG_TAG, "Cannot unregister", t); - } - } - - -} diff --git a/src/card/nfc/NfcBridge.cpp b/src/card/nfc/NfcBridge.cpp deleted file mode 100644 index 2497611..0000000 --- a/src/card/nfc/NfcBridge.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "NfcBridge.h" - -#include "SingletonHelper.h" - -#include - -using namespace governikus; - -defineSingleton(NfcBridge) - -Q_DECLARE_LOGGING_CATEGORY(card_nfc) - -#ifdef Q_OS_ANDROID -#include -#include -#endif - - -NfcBridge::NfcBridge() -#ifdef Q_OS_ANDROID - : mJavaConnector(QtAndroid::androidContext().callObjectMethod("getNfcConnector", "()Lcom/governikus/ausweisapp2/NFCConnector;")) -#endif -{ -} - - -NfcBridge::~NfcBridge() -{ -} - - -NfcBridge& NfcBridge::getInstance() -{ - return *Instance; -} - - -#ifdef Q_OS_ANDROID -QAndroidJniObject NfcBridge::getApplicationContext() -{ - QAndroidJniObject application = QtAndroid::androidContext().callObjectMethod("getApplication", "()Landroid/app/Application;"); - if (application == nullptr) - { - qCCritical(card_nfc) << "Cannot get application"; - return nullptr; - } - - return application.callObjectMethod("getApplicationContext", "()Landroid/content/Context;"); -} - - -jbyteArray NfcBridge::convert(const QByteArray& pData) -{ - QAndroidJniEnvironment env; - const int size = pData.size(); - const char* buffer = pData.constData(); - - jbyteArray target = env->NewByteArray(size); - jbyte* bytes = env->GetByteArrayElements(target, 0); - for (int i = 0; i < size; ++i) - { - bytes[i] = buffer[i]; - } - env->SetByteArrayRegion(target, 0, size, bytes); - - return target; -} - - -QByteArray NfcBridge::convert(const jbyteArray& pData) -{ - QAndroidJniEnvironment env; - - jsize size = env->GetArrayLength(pData); - QVector buffer(size); - env->GetByteArrayRegion(pData, 0, size, buffer.data()); - - return QByteArray(reinterpret_cast(buffer.data()), buffer.size()); -} - - -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() const -{ -#ifdef Q_OS_ANDROID - if (isValid()) - { - return static_cast(mJavaConnector.callMethod("isCardPresent")); - } - -#endif - - return NfcCardCode::NO_CARD; -} - - -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()) - { - return static_cast(mJavaConnector.callMethod("getExtendedLengthApduSupportStatus")); - } - -#endif - - return ExtendedLengthApduSupportCode::UNKNOWN; -} - - -bool NfcBridge::isNfcEnabled() const -{ -#ifdef Q_OS_ANDROID - auto nfcAdapter = getNfcAdapter(); - - if (nfcAdapter == nullptr) - { - qCWarning(card_nfc) << "Cannot get default NfcAdapter"; - return false; - } - - return static_cast(nfcAdapter.callMethod("isEnabled")); - -#else - return false; - -#endif -} - - -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; - -#else - return false; - -#endif -} - - -bool NfcBridge::start() -{ -#ifdef Q_OS_ANDROID - if (isValid()) - { - return NfcConnectorCode::SUCCESS == static_cast(mJavaConnector.callMethod("start")); - } -#endif - - return false; -} - - -bool NfcBridge::stop() -{ -#ifdef Q_OS_ANDROID - if (isValid()) - { - return NfcConnectorCode::SUCCESS == static_cast(mJavaConnector.callMethod("stop")); - } -#endif - - return false; -} - - -QByteArray NfcBridge::sendData(const QByteArray& pData) -{ - QByteArray ret; -#ifdef Q_OS_ANDROID - if (isValid()) - { - QAndroidJniEnvironment env; - jbyteArray cmd = convert(pData); - - QAndroidJniObject arrayObj = mJavaConnector.callObjectMethod("sendData", "([B)[B", cmd); - if (arrayObj == nullptr) - { - qCCritical(card_nfc) << "JavaConnector: sendData failed"; - } - else - { - ret = convert(static_cast(arrayObj.object())); - } - - env->DeleteLocalRef(cmd); - } -#else - Q_UNUSED(pData) -#endif - - return ret; -} - - -#include "moc_NfcBridge.cpp" diff --git a/src/card/nfc/NfcBridge.h b/src/card/nfc/NfcBridge.h deleted file mode 100644 index 758e513..0000000 --- a/src/card/nfc/NfcBridge.h +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * \brief Helper for bridge between C++ and Java or something else. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "EnumHelper.h" -#include "ReaderInfo.h" - -#ifdef Q_OS_ANDROID -#include -#endif - -namespace governikus -{ -defineEnumType(NfcCardCode, - NO_CARD = 0, - SAME_CARD = 1, - NEW_CARD = 2) - -defineTypedEnumType(NfcConnectorCode, signed char, - SUCCESS = 0, - ERROR_NO_NFC = -1, - ERROR_NO_TAG = -2, - ERROR_CONNECT = -3, - ERROR_TAG_LOST = -4, - ERROR_TRANSMIT = -5, - ERROR_UNKNOWN = -16) - -class NfcBridge -{ - private: -#ifdef Q_OS_ANDROID - QAndroidJniObject mJavaConnector; - - static QAndroidJniObject getApplicationContext(); - static QAndroidJniObject getNfcAdapter(); - static QByteArray convert(const jbyteArray& pData); - static jbyteArray convert(const QByteArray& pData); -#endif - - Q_DISABLE_COPY(NfcBridge) - - protected: - NfcBridge(); - ~NfcBridge(); - - public: - static NfcBridge& getInstance(); - - 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); -}; - -} /* namespace governikus */ diff --git a/src/card/nfc/NfcCard.cpp b/src/card/nfc/NfcCard.cpp index fad92cb..ce15071 100644 --- a/src/card/nfc/NfcCard.cpp +++ b/src/card/nfc/NfcCard.cpp @@ -1,94 +1,144 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "NfcBridge.h" #include "NfcCard.h" #include +#include + using namespace governikus; + Q_DECLARE_LOGGING_CATEGORY(card_nfc) -NfcCard::NfcCard() - : Card() + +void NfcCard::onError(QNearFieldTarget::Error pError, const QNearFieldTarget::RequestId& pId) { + Q_UNUSED(pId); + qCWarning(card_nfc) << "Error:" << pError; +} + + +NfcCard::NfcCard(QNearFieldTarget* pNearFieldTarget) + : Card() + , mConnected(false) + , mIsValid(true) + , mNearFieldTarget(pNearFieldTarget) +{ + qCDebug(card_nfc) << "Card created"; + + QObject::connect(pNearFieldTarget, &QNearFieldTarget::error, this, &NfcCard::onError); + + pNearFieldTarget->setKeepConnection(true); } NfcCard::~NfcCard() { + // Memory is managed by QNearFieldManager + // delete mNearFieldTarget; +} + + +bool NfcCard::isValid() const +{ + return mIsValid; +} + + +bool NfcCard::invalidateTarget(QNearFieldTarget* pNearFieldTarget) +{ + if (pNearFieldTarget == mNearFieldTarget) + { + mIsValid = false; + return true; + } + + return false; } CardReturnCode NfcCard::connect() { -#ifdef Q_OS_ANDROID - if (NfcBridge::getInstance().connectCard()) + if (isConnected()) { - return CardReturnCode::OK; + qCCritical(card_nfc) << "Card is already connected"; + return CardReturnCode::COMMAND_FAILED; } -#endif - return CardReturnCode::COMMAND_FAILED; + + mConnected = true; + return CardReturnCode::OK; } CardReturnCode NfcCard::disconnect() { -#ifdef Q_OS_ANDROID - if (NfcBridge::getInstance().disconnectCard()) + if (!mIsValid || !mNearFieldTarget) { - return CardReturnCode::OK; + qCWarning(card_nfc) << "NearFieldTarget is no longer valid"; + return CardReturnCode::COMMAND_FAILED; } -#endif - return CardReturnCode::COMMAND_FAILED; + + if (!isConnected()) + { + qCCritical(card_nfc) << "Card is already disconnected"; + return CardReturnCode::COMMAND_FAILED; + } + + mConnected = false; + mNearFieldTarget->disconnect(); + return CardReturnCode::OK; } bool NfcCard::isConnected() { -#ifdef Q_OS_ANDROID - return NfcBridge::getInstance().isCardConnected(); - -#endif - return false; + return mConnected; } CardReturnCode NfcCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) { -#ifdef Q_OS_ANDROID + if (!mIsValid || !mNearFieldTarget) + { + qCWarning(card_nfc) << "NearFieldTarget is no longer valid"; + return CardReturnCode::COMMAND_FAILED; + } + qCDebug(card_nfc) << "Transmit command APDU: " << pCmd.getBuffer().toHex(); - QByteArray recvBuffer = NfcBridge::getInstance().sendData(pCmd.getBuffer()); - if (recvBuffer.isEmpty()) + if (!mNearFieldTarget->accessMethods().testFlag(QNearFieldTarget::AccessMethod::TagTypeSpecificAccess)) { - qCWarning(card_nfc) << "No response received"; + qCWarning(card_nfc) << "No TagTypeSpecificAccess supported"; return CardReturnCode::COMMAND_FAILED; } - NfcConnectorCode status = static_cast(recvBuffer.at(0)); - if (status == NfcConnectorCode::SUCCESS) + QNearFieldTarget::RequestId id = mNearFieldTarget->sendCommand(pCmd.getBuffer()); + if (!id.isValid()) { - pRes.setBuffer(recvBuffer.mid(1)); - qCDebug(card_nfc) << "Transmit response APDU: " << pRes.getBuffer().toHex(); - return CardReturnCode::OK; + qCWarning(card_nfc) << "Cannot write messages"; + return CardReturnCode::COMMAND_FAILED; } - else if (status == NfcConnectorCode::ERROR_TAG_LOST || status == NfcConnectorCode::ERROR_NO_TAG) + + if (!mNearFieldTarget->waitForRequestCompleted(id, 750)) { - qCWarning(card_nfc) << "Transmit error: " << status; Q_EMIT fireCardRemoved(); - return CardReturnCode::COMMAND_FAILED; - } - else - { - qCWarning(card_nfc) << "Transmit error: " << status; - return CardReturnCode::COMMAND_FAILED; - } -#endif - Q_UNUSED(pCmd); - Q_UNUSED(pRes); - return CardReturnCode::UNDEFINED; + qCWarning(card_nfc) << "Transmit timeout reached"; + return CardReturnCode::COMMAND_FAILED; + } + + QVariant response = mNearFieldTarget->requestResponse(id); + if (!response.isValid()) + { + qCWarning(card_nfc) << "Invalid response received"; + return CardReturnCode::COMMAND_FAILED; + } + + QByteArray recvBuffer = response.toByteArray(); + qCDebug(card_nfc) << "Transmit response APDU: " << recvBuffer.toHex(); + pRes.setBuffer(recvBuffer); + return CardReturnCode::OK; } diff --git a/src/card/nfc/NfcCard.h b/src/card/nfc/NfcCard.h index 4b436c9..830aa91 100644 --- a/src/card/nfc/NfcCard.h +++ b/src/card/nfc/NfcCard.h @@ -1,13 +1,16 @@ /*! * \brief Implementation of \ref Card for NFC. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "Card.h" +#include + + namespace governikus { class NfcCard @@ -15,12 +18,23 @@ class NfcCard { Q_OBJECT + private: + bool mConnected; + bool mIsValid; + QNearFieldTarget* mNearFieldTarget; + + private Q_SLOTS: + void onError(QNearFieldTarget::Error pError, const QNearFieldTarget::RequestId& pId); + Q_SIGNALS: void fireCardRemoved(); public: - NfcCard(); - virtual ~NfcCard(); + NfcCard(QNearFieldTarget* pNearFieldTarget); + virtual ~NfcCard() override; + + bool isValid() const; + bool invalidateTarget(QNearFieldTarget* pNearFieldTarget); virtual CardReturnCode connect() override; virtual CardReturnCode disconnect() override; diff --git a/src/card/nfc/NfcReader.cpp b/src/card/nfc/NfcReader.cpp index 0c53b2a..22ee700 100644 --- a/src/card/nfc/NfcReader.cpp +++ b/src/card/nfc/NfcReader.cpp @@ -1,79 +1,96 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "NfcReader.h" - #include "CardConnectionWorker.h" -#include "NfcBridge.h" +#include "NfcReader.h" #include #include -Q_DECLARE_LOGGING_CATEGORY(card_nfc) using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(card_nfc) + + +Reader::CardEvent NfcReader::updateCard() +{ + Q_EMIT fireNfcAdapterStateChanged(mNfManager.isAvailable()); + + return CardEvent::NONE; +} + + +void NfcReader::targetDetected(QNearFieldTarget* pTarget) +{ + if (!pTarget) + { + return; + } + qCDebug(card_nfc) << "targetDetected, type:" << pTarget->type(); + + if (!(pTarget->accessMethods() & QNearFieldTarget::TagTypeSpecificAccess)) + { + qCDebug(card_nfc) << "The target does not provide commands"; + return; + } + + int length = pTarget->maxCommandLength(); + mReaderInfo.setMaxApduLength(length); + if (!mReaderInfo.sufficientApduLength()) + { + Q_EMIT fireReaderPropertiesUpdated(getName()); + qCDebug(card_nfc) << "ExtendedLengthApduSupport missing. MaxTransceiveLength:" << length; + return; + } + + mCard.reset(new NfcCard(pTarget)); + QSharedPointer cardConnection = createCardConnectionWorker(); + CardInfoFactory::create(cardConnection, mReaderInfo); + Q_EMIT fireCardInserted(getName()); +} + + +void NfcReader::targetLost(QNearFieldTarget* pTarget) +{ + qCDebug(card_nfc) << "targetLost"; + if (pTarget && mCard && mCard->invalidateTarget(pTarget)) + { + mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); + Q_EMIT fireCardRemoved(getName()); + } +} + + NfcReader::NfcReader() - : Reader(ReaderManagerPlugInType::NFC, QStringLiteral("NFC"), ReaderType::UNKNOWN) + : Reader(ReaderManagerPlugInType::NFC, QStringLiteral("NFC")) + , mNfManager() { mReaderInfo.setBasicReader(true); mReaderInfo.setConnected(true); + connect(&mNfManager, &QNearFieldManager::targetDetected, this, &NfcReader::targetDetected); + connect(&mNfManager, &QNearFieldManager::targetLost, this, &NfcReader::targetLost); + mNfManager.startTargetDetection(); + mTimerId = startTimer(500); } NfcReader::~NfcReader() { + mNfManager.stopTargetDetection(); } Card* NfcReader::getCard() const { - return mCard.data(); -} - - -Reader::CardEvent NfcReader::updateCard() -{ -#ifdef Q_OS_ANDROID - - const ExtendedLengthApduSupportCode& code = NfcBridge::getInstance().getExtendedLengthApduSupportStatus(); - if (mReaderInfo.getExtendedLengthApduSupportCode() != code) + if (mCard->isValid()) { - mReaderInfo.setExtendedLengthApduSupportCode(code); - Q_EMIT fireReaderPropertiesUpdated(getName()); + return mCard.data(); } - if (mCard.isNull() && NfcBridge::getInstance().getCardStatus() == NfcCardCode::NEW_CARD) - { - mCard.reset(new NfcCard()); - connect(mCard.data(), &NfcCard::fireCardRemoved, this, &NfcReader::onCardRemoved); - QSharedPointer cardConnection = createCardConnectionWorker(); - CardInfoFactory::create(cardConnection, mReaderInfo); - const QSignalBlocker blocker(this); - updateRetryCounter(cardConnection); - return CardEvent::CARD_INSERTED; - } - - if (!mCard.isNull() && NfcBridge::getInstance().getCardStatus() == NfcCardCode::NO_CARD) - { - mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); - mCard.reset(); - return CardEvent::CARD_REMOVED; - } - -#endif - - return CardEvent::NONE; -} - - -void NfcReader::onCardRemoved() -{ - qCDebug(card_nfc) << "Card removed"; - mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); - mCard.reset(); - Q_EMIT fireCardRemoved(getName()); + return nullptr; } diff --git a/src/card/nfc/NfcReader.h b/src/card/nfc/NfcReader.h index b7f1a38..dc8e007 100644 --- a/src/card/nfc/NfcReader.h +++ b/src/card/nfc/NfcReader.h @@ -1,7 +1,7 @@ /*! * \brief Implementation of \ref Reader for NFC. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -9,6 +9,9 @@ #include "NfcCard.h" #include "Reader.h" +#include + + namespace governikus { @@ -18,16 +21,21 @@ class NfcReader Q_OBJECT private: + QNearFieldManager mNfManager; QScopedPointer mCard; virtual CardEvent updateCard() override; + Q_SIGNALS: + void fireNfcAdapterStateChanged(bool pEnabled); + private Q_SLOTS: - void onCardRemoved(); + void targetDetected(QNearFieldTarget* pTarget); + void targetLost(QNearFieldTarget* pTarget); public: NfcReader(); - virtual ~NfcReader(); + virtual ~NfcReader() override; virtual Card* getCard() const override; }; diff --git a/src/card/nfc/NfcReaderManagerPlugIn.cpp b/src/card/nfc/NfcReaderManagerPlugIn.cpp index 339ecd2..df73705 100644 --- a/src/card/nfc/NfcReaderManagerPlugIn.cpp +++ b/src/card/nfc/NfcReaderManagerPlugIn.cpp @@ -1,13 +1,16 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "NfcBridge.h" #include "NfcReader.h" #include "NfcReaderManagerPlugIn.h" #include +#ifdef Q_OS_ANDROID +#include +#include +#endif using namespace governikus; @@ -15,43 +18,57 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_nfc) -NfcReaderManagerPlugIn * NfcReaderManagerPlugIn::mInstance = nullptr; - - -#ifdef Q_OS_ANDROID -JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_NfcAdapterStateChangeReceiver_nfcAdapterStateChanged(JNIEnv* env, jobject obj, jint newState) +namespace { - Q_UNUSED(env) - Q_UNUSED(obj) - if (NfcReaderManagerPlugIn::mInstance == nullptr) +bool isAvailable() +{ +#ifdef Q_OS_ANDROID + QAndroidJniObject context = QtAndroid::androidContext(); + if (context == nullptr) + { + qCCritical(card_nfc) << "Cannot get context"; + return false; + } + + return QAndroidJniObject::callStaticObjectMethod("android/nfc/NfcAdapter", "getDefaultAdapter", "(Landroid/content/Context;)Landroid/nfc/NfcAdapter;", context.object()) != nullptr; + +#else + QNearFieldManager manager; + return manager.isAvailable(); + +#endif +} + + +} + + +void NfcReaderManagerPlugIn::onNfcAdapterStateChanged(bool pEnabled) +{ + if (mEnabled == pEnabled) { - qCWarning(card_nfc) << "NfcReaderManagerPlugIn not yet instantiated, skip processing"; return; } - if (newState == 1) // STATE_OFF (class android.nfc.NfcAdapter) + + qCDebug(card_nfc) << "NfcAdapterStateChanged:" << pEnabled; + mEnabled = pEnabled; + setReaderInfoEnabled(pEnabled); + if (pEnabled) { - qCDebug(card_nfc) << "Nfc was powered off"; - // jump from Android thread into Qt thread by invoking per BlockingQueuedConnection - QMetaObject::invokeMethod(NfcReaderManagerPlugIn::mInstance, "setNfcStatus", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); + Q_EMIT fireReaderAdded(mNfcReader->getName()); } - else if (newState == 3) // STATE_ON (class android.nfc.NfcAdapter) + else { - qCDebug(card_nfc) << "Nfc was powered on"; - // jump from Android thread into Qt thread by invoking per BlockingQueuedConnection - QMetaObject::invokeMethod(NfcReaderManagerPlugIn::mInstance, "setNfcStatus", Qt::BlockingQueuedConnection, Q_ARG(bool, true)); + Q_EMIT fireReaderRemoved(mNfcReader->getName()); } } -#endif - - NfcReaderManagerPlugIn::NfcReaderManagerPlugIn() - : ReaderManagerPlugIn(ReaderManagerPlugInType::NFC, NfcBridge::getInstance().isNfcAvailable()) - , mInitialized(false) - , mReaderList() + : ReaderManagerPlugIn(ReaderManagerPlugInType::NFC, isAvailable()) + , mEnabled(false) + , mNfcReader(nullptr) { - NfcReaderManagerPlugIn::mInstance = this; } @@ -60,74 +77,42 @@ NfcReaderManagerPlugIn::~NfcReaderManagerPlugIn() } -QList NfcReaderManagerPlugIn::getReader() const +QList NfcReaderManagerPlugIn::getReaders() const { - return mReaderList; -} + if (mEnabled) + { + return QList({mNfcReader.data()}); + } - -void NfcReaderManagerPlugIn::addNfcReader() -{ - NfcReader* reader = new NfcReader(); - - connect(reader, &NfcReader::fireCardInserted, this, &NfcReaderManagerPlugIn::fireCardInserted); - connect(reader, &NfcReader::fireCardRemoved, this, &NfcReaderManagerPlugIn::fireCardRemoved); - connect(reader, &NfcReader::fireCardRetryCounterChanged, this, &NfcReaderManagerPlugIn::fireCardRetryCounterChanged); - connect(reader, &NfcReader::fireReaderPropertiesUpdated, this, &NfcReaderManagerPlugIn::fireReaderPropertiesUpdated); - - mReaderList << reader; - qCDebug(card_nfc) << "Add reader" << reader->getName(); - Q_EMIT fireReaderAdded(reader->getName()); + return QList(); } void NfcReaderManagerPlugIn::init() { ReaderManagerPlugIn::init(); -#ifdef Q_OS_ANDROID - if (!mInitialized && NfcBridge::getInstance().start()) + + if (mNfcReader) { - mInitialized = true; - setNfcStatus(NfcBridge::getInstance().isNfcEnabled()); + return; + } + + mNfcReader.reset(new NfcReader()); + connect(mNfcReader.data(), &NfcReader::fireCardInserted, this, &NfcReaderManagerPlugIn::fireCardInserted); + connect(mNfcReader.data(), &NfcReader::fireCardRemoved, this, &NfcReaderManagerPlugIn::fireCardRemoved); + connect(mNfcReader.data(), &NfcReader::fireCardRetryCounterChanged, this, &NfcReaderManagerPlugIn::fireCardRetryCounterChanged); + connect(mNfcReader.data(), &NfcReader::fireReaderPropertiesUpdated, this, &NfcReaderManagerPlugIn::fireReaderPropertiesUpdated); + connect(mNfcReader.data(), &NfcReader::fireNfcAdapterStateChanged, this, &NfcReaderManagerPlugIn::onNfcAdapterStateChanged); + qCDebug(card_nfc) << "Add reader" << mNfcReader->getName(); + + if (mEnabled) + { + Q_EMIT fireReaderAdded(mNfcReader->getName()); } -#endif } void NfcReaderManagerPlugIn::shutdown() { -#ifdef Q_OS_ANDROID - if (mInitialized && NfcBridge::getInstance().stop()) - { - mInitialized = false; - } -#endif -} - - -void NfcReaderManagerPlugIn::setNfcStatus(bool pEnabled) -{ - if (!mInitialized) - { - return; - } - - setReaderInfoEnabled(pEnabled); - if (pEnabled) - { - if (mReaderList.isEmpty()) - { - addNfcReader(); - } - } - else - { - while (!mReaderList.isEmpty()) - { - Reader* reader = mReaderList.takeFirst(); - qCDebug(card_nfc) << "Remove reader" << reader->getName(); - Q_EMIT fireReaderRemoved(reader->getName()); - delete reader; - } - } + mNfcReader.reset(); } diff --git a/src/card/nfc/NfcReaderManagerPlugIn.h b/src/card/nfc/NfcReaderManagerPlugIn.h index 9f17e43..1132496 100644 --- a/src/card/nfc/NfcReaderManagerPlugIn.h +++ b/src/card/nfc/NfcReaderManagerPlugIn.h @@ -1,7 +1,7 @@ /*! * \brief Implementation of \ref ReaderManagerPlugIn for NFC on Android. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -9,16 +9,8 @@ #include "Reader.h" #include "ReaderManagerPlugIn.h" - -#ifdef Q_OS_ANDROID -#include - - -extern "C" -{ -JNIEXPORT void JNICALL Java_com_governikus_ausweisapp2_NfcAdapterStateChangeReceiver_nfcAdapterStateChanged(JNIEnv* env, jobject obj, jint newState); -} -#endif +#include +#include namespace governikus @@ -31,25 +23,18 @@ class NfcReaderManagerPlugIn Q_PLUGIN_METADATA(IID "governikus.ReaderManagerPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::ReaderManagerPlugIn) -#ifdef Q_OS_ANDROID - friend void ::Java_com_governikus_ausweisapp2_NfcAdapterStateChangeReceiver_nfcAdapterStateChanged(JNIEnv * env, jobject obj, jint newState); -#endif - private: - static NfcReaderManagerPlugIn* mInstance; - bool mInitialized; - QList mReaderList; - - void addNfcReader(); + bool mEnabled; + QScopedPointer mNfcReader; private Q_SLOTS: - void setNfcStatus(bool pEnabled); + void onNfcAdapterStateChanged(bool pEnabled); public: NfcReaderManagerPlugIn(); - virtual ~NfcReaderManagerPlugIn(); + virtual ~NfcReaderManagerPlugIn() override; - virtual QList getReader() const override; + virtual QList getReaders() const override; virtual void init() override; virtual void shutdown() override; diff --git a/src/card/pcsc/PcscCard.cpp b/src/card/pcsc/PcscCard.cpp index c1c3157..53f95b6 100644 --- a/src/card/pcsc/PcscCard.cpp +++ b/src/card/pcsc/PcscCard.cpp @@ -1,28 +1,62 @@ /*! - * PcscCard.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DestroyPACEChannel.h" #include "PcscCard.h" +#include #include +#include Q_DECLARE_LOGGING_CATEGORY(card_pcsc) using namespace governikus; +namespace +{ +QLatin1String protocolToString(PCSC_INT pProtocol) +{ + switch (pProtocol) + { + case SCARD_PROTOCOL_UNDEFINED: + return QLatin1String("SCARD_PROTOCOL_UNDEFINED"); + + case SCARD_PROTOCOL_T0: + return QLatin1String("SCARD_PROTOCOL_T0"); + + case SCARD_PROTOCOL_T1: + return QLatin1String("SCARD_PROTOCOL_T1"); + + case SCARD_PROTOCOL_RAW: + return QLatin1String("SCARD_PROTOCOL_RAW"); + +#ifdef SCARD_PROTOCOL_T15 + case SCARD_PROTOCOL_T15: + return QLatin1String("SCARD_PROTOCOL_T15"); + +#endif + + default: + qCWarning(card_pcsc) << "Unknown value of SCARD_PROTOCOL:" << pProtocol; + return QLatin1String(); + } +} + + +} + + PcscCard::PcscCard(PcscReader* pPcscReader) : Card() , mReader(pPcscReader) - , mProtocol(0) + , mProtocol(SCARD_PROTOCOL_UNDEFINED) , mContextHandle(0) , mCardHandle(0) , mTimer() { PCSC_RETURNCODE returnCode = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &mContextHandle); - qCDebug(card_pcsc) << "SCardEstablishContext for " << mReader->getName() << ": " << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardEstablishContext for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); mTimer.setInterval(4000); QObject::connect(&mTimer, &QTimer::timeout, this, &PcscCard::sendSCardStatus); @@ -38,7 +72,7 @@ PcscCard::~PcscCard() } PCSC_RETURNCODE returnCode = SCardReleaseContext(mContextHandle); - qCDebug(card_pcsc) << "SCardReleaseContext for " << mReader->getName() << ": " << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardReleaseContext for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); mContextHandle = 0; } @@ -74,21 +108,21 @@ CardReturnCode PcscCard::connect() PCSC_INT preferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; 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); + qCDebug(card_pcsc) << "SCardConnect for" << mReader->getName() << ':' << PcscUtils::toString(returnCode) << "| cardHandle:" << mCardHandle << "| protocol:" << protocolToString(mProtocol); if (returnCode != PcscUtils::Scard_S_Success) { return CardReturnCode::COMMAND_FAILED; } returnCode = SCardBeginTransaction(mCardHandle); - qCDebug(card_pcsc) << "SCardBeginTransaction for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardBeginTransaction for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); if (returnCode != PcscUtils::Scard_S_Success) { SCardDisconnect(mCardHandle, SCARD_LEAVE_CARD); return CardReturnCode::COMMAND_FAILED; } - if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) { mTimer.start(); } @@ -106,12 +140,12 @@ CardReturnCode PcscCard::disconnect() mTimer.stop(); PCSC_RETURNCODE returnCode = SCardEndTransaction(mCardHandle, SCARD_LEAVE_CARD); - qCDebug(card_pcsc) << "SCardEndTransaction for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); + qCDebug(card_pcsc) << "SCardEndTransaction for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); returnCode = SCardDisconnect(mCardHandle, SCARD_RESET_CARD); mCardHandle = 0; - mProtocol = 0; - qCDebug(card_pcsc) << "SCardDisconnect for " << mReader->getName() << " : " << PcscUtils::toString(returnCode); + mProtocol = SCARD_PROTOCOL_UNDEFINED; + qCDebug(card_pcsc) << "SCardDisconnect for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); return returnCode == PcscUtils::Scard_S_Success ? CardReturnCode::OK : CardReturnCode::COMMAND_FAILED; } @@ -141,7 +175,7 @@ CardReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) ResponseApdu tempResponse; tempResponse.setBuffer(receiveBuffer); - if (tempResponse.getSW1() == 0x6c) + if (tempResponse.getSW1() == SW1::WRONG_LE_FIELD) { 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()); @@ -152,7 +186,7 @@ CardReturnCode PcscCard::transmit(const CommandApdu& pCmd, ResponseApdu& pRes) } } - while (tempResponse.getSW1() == 0x61) + while (tempResponse.getSW1() == SW1::MORE_DATA_AVAILABLE) { QByteArray tempReceiveBuffer; qCDebug(card_pcsc) << "got SW1 == 0x61, getting response with Le:" << tempResponse.getSW2(); @@ -236,7 +270,7 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, QByteArray& pR return PcscUtils::Scard_F_Unknown_Error; } pReceiveBuffer.resize(static_cast(bytesReceived)); - qCDebug(card_pcsc) << "SCardTransmit resBuffer " << pReceiveBuffer.toHex(); + qCDebug(card_pcsc) << "SCardTransmit resBuffer:" << pReceiveBuffer.toHex(); if (pReceiveBuffer.size() < 2) { qCCritical(card_pcsc) << "Response buffer smaller than 2"; @@ -252,15 +286,15 @@ PCSC_RETURNCODE PcscCard::transmit(const QByteArray& pSendBuffer, SCARD_IO_REQUEST& pRecvPci, PCSC_INT& pBytesReceived) { - qCDebug(card_pcsc) << "SCardTransmit cmdBuffer " << pSendBuffer.toHex(); + qCDebug(card_pcsc) << "SCardTransmit cmdBuffer:" << pSendBuffer.toHex(); 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); + qCDebug(card_pcsc) << "SCardTransmit for" << mReader->getName() << ':' << PcscUtils::toString(returnCode); return returnCode; } -CardReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, +CardReturnCode PcscCard::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) @@ -273,7 +307,7 @@ CardReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::EXECUTE_PACE); EstablishPACEChannelBuilder builder; - builder.setPinId(pPinId); + builder.setPasswordId(pPasswordId); builder.setChat(pChat); builder.setCertificateDescription(pCertificateDescription); @@ -285,7 +319,7 @@ CardReturnCode PcscCard::establishPaceChannel(PACE_PIN_ID pPinId, return CardReturnCode::COMMAND_FAILED; } - pChannelOutput.parse(controlRes, pPinId); + pChannelOutput.parse(controlRes, pPasswordId); return pChannelOutput.getPaceReturnCode(); } @@ -314,7 +348,7 @@ PCSC_RETURNCODE PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCntrInp { char buffer[2048]; PCSC_INT len = 0; - qCDebug(card_pcsc) << "SCardControl cmdBuffer " << pCntrInput.toHex(); + qCDebug(card_pcsc) << "SCardControl cmdBuffer:" << pCntrInput.toHex(); PCSC_RETURNCODE returnCode = SCardControl(mCardHandle, pCntrCode, pCntrInput.constData(), @@ -342,7 +376,7 @@ PCSC_RETURNCODE PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCntrInp } pCntrOutput.append(buffer, static_cast(len)); - qCDebug(card_pcsc) << "SCardControl for " << mReader->getName() << " : " << PcscUtils::toString(returnCode) << " " << pCntrOutput.toHex(); + qCDebug(card_pcsc) << "SCardControl for" << mReader->getName() << ':' << PcscUtils::toString(returnCode) << pCntrOutput.toHex(); return returnCode; } diff --git a/src/card/pcsc/PcscCard.h b/src/card/pcsc/PcscCard.h index 353d6d1..ec57db5 100644 --- a/src/card/pcsc/PcscCard.h +++ b/src/card/pcsc/PcscCard.h @@ -1,9 +1,7 @@ /*! - * PcscCard.h - * * \brief Implementation of card object for PC/SC * * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -30,7 +28,7 @@ class PcscCard QPointer mReader; PCSC_INT mProtocol; SCARDCONTEXT mContextHandle; - PCSC_CARDHANDLE mCardHandle; + SCARDHANDLE mCardHandle; QTimer mTimer; PCSC_RETURNCODE transmit(const QByteArray& pSendBuffer, QByteArray& pReceiveBuffer); @@ -48,7 +46,7 @@ class PcscCard public: PcscCard(PcscReader* pPcscReader); - virtual ~PcscCard(); + virtual ~PcscCard() override; virtual CardReturnCode connect() override; virtual CardReturnCode disconnect() override; @@ -56,7 +54,7 @@ class PcscCard virtual CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; - virtual CardReturnCode establishPaceChannel(PACE_PIN_ID pPinId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; + virtual CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) override; virtual CardReturnCode destroyPaceChannel() override; diff --git a/src/card/pcsc/PcscReader.cpp b/src/card/pcsc/PcscReader.cpp index 75507ac..165bb08 100644 --- a/src/card/pcsc/PcscReader.cpp +++ b/src/card/pcsc/PcscReader.cpp @@ -1,22 +1,19 @@ /*! - * PcscReader.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PcscCard.h" #include "PcscReader.h" -#include "PcscReaderFeature.h" -#include "SupportedReaders.h" #include +#include using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_pcsc) PcscReader::PcscReader(const QString& pReaderName) - : Reader(ReaderManagerPlugInType::PCSC, pReaderName, SupportedReaders::getInstance().getReader(pReaderName)) + : Reader(ReaderManagerPlugInType::PCSC, pReaderName) , mReaderState() , mReaderFeatures(nullptr) , mPaceCapabilities(nullptr) @@ -51,6 +48,10 @@ PcscReader::PcscReader(const QString& pReaderName) return; } + // For PersoSim we need to check for FeatureID::EXECUTE_PACE + // The correct check would be for PaceCapabilityId::EID + // https://github.com/PersoSim/de.persosim.simulator/issues/89 + // mReaderInfo.setBasicReader(!mPaceCapabilities.contains(PaceCapabilityId::EID)); mReaderInfo.setBasicReader(!hasFeature(FeatureID::EXECUTE_PACE)); mReaderInfo.setConnected(true); @@ -62,10 +63,8 @@ PcscReader::PcscReader(const QString& pReaderName) PcscReader::~PcscReader() { qCDebug(card_pcsc) << mReaderInfo.getName(); - - qCDebug(card_pcsc) << "SCardCancel for " << mReaderInfo.getName() << ": " << PcscUtils::toString(SCardCancel(mContextHandle)); - - qCDebug(card_pcsc) << "SCardReleaseContext: " << PcscUtils::toString(SCardReleaseContext(mContextHandle)); + qCDebug(card_pcsc) << "SCardCancel: " << PcscUtils::toString(SCardCancel(mContextHandle)); + qCDebug(card_pcsc) << "SCardReleaseContext:" << PcscUtils::toString(SCardReleaseContext(mContextHandle)); mContextHandle = 0; delete[] mReaderState.szReader; @@ -80,69 +79,73 @@ SCARD_READERSTATE PcscReader::getState() bool PcscReader::hasFeature(FeatureID pFeatureID) const { - return mReaderFeatures.getFeatures().contains(pFeatureID); + return mReaderFeatures.contains(pFeatureID); } PCSC_INT PcscReader::getFeatureValue(FeatureID pFeatureID) { - return mReaderFeatures.getFeatures().find(pFeatureID).value(); + return mReaderFeatures.getValue(pFeatureID); } -template static QString SCARD_STATE_toString(T i) +static QString SCARD_STATE_toString(DWORD i) { - QString sb = QString().sprintf("(%#lx)", static_cast(i)); + QStringList sb(QString().sprintf("(%#lx)", static_cast(i))); - if ((i & SCARD_STATE_UNAWARE) != 0) + if (i == SCARD_STATE_UNAWARE) { - sb += QStringLiteral(" UNAWARE"); + sb += QStringLiteral("UNAWARE"); } - if ((i & SCARD_STATE_IGNORE) != 0) + else { - sb += QStringLiteral(" IGNORE"); + if ((i & SCARD_STATE_IGNORE) != 0) + { + sb += QStringLiteral("IGNORE"); + } + if ((i & SCARD_STATE_CHANGED) != 0) + { + sb += QStringLiteral("CHANGED"); + } + if ((i & SCARD_STATE_UNKNOWN) != 0) + { + sb += QStringLiteral("UNKNOWN"); + } + if ((i & SCARD_STATE_UNAVAILABLE) != 0) + { + sb += QStringLiteral("UNAVAILABLE"); + } + if ((i & SCARD_STATE_EMPTY) != 0) + { + sb += QStringLiteral("EMPTY"); + } + if ((i & SCARD_STATE_PRESENT) != 0) + { + sb += QStringLiteral("PRESENT"); + } + if ((i & SCARD_STATE_ATRMATCH) != 0) + { + sb += QStringLiteral("ATRMATCH"); + } + if ((i & SCARD_STATE_EXCLUSIVE) != 0) + { + sb += QStringLiteral("EXCLUSIVE"); + } + if ((i & SCARD_STATE_INUSE) != 0) + { + sb += QStringLiteral("INUSE"); + } + if ((i & SCARD_STATE_MUTE) != 0) + { + sb += QStringLiteral("MUTE"); + } + if ((i & SCARD_STATE_UNPOWERED) != 0) + { + sb += QStringLiteral("UNPOWERED"); + } } - if ((i & SCARD_STATE_CHANGED) != 0) - { - sb += QStringLiteral(" CHANGED"); - } - if ((i & SCARD_STATE_UNKNOWN) != 0) - { - sb += QStringLiteral(" UNKNOWN"); - } - if ((i & SCARD_STATE_UNAVAILABLE) != 0) - { - sb += QStringLiteral(" UNAVAILABLE"); - } - if ((i & SCARD_STATE_EMPTY) != 0) - { - sb += QStringLiteral(" EMPTY"); - } - if ((i & SCARD_STATE_PRESENT) != 0) - { - sb += QStringLiteral(" PRESENT"); - } - if ((i & SCARD_STATE_ATRMATCH) != 0) - { - sb += QStringLiteral(" ATRMATCH"); - } - if ((i & SCARD_STATE_EXCLUSIVE) != 0) - { - sb += QStringLiteral(" EXCLUSIVE"); - } - if ((i & SCARD_STATE_INUSE) != 0) - { - sb += QStringLiteral(" INUSE"); - } - if ((i & SCARD_STATE_MUTE) != 0) - { - sb += QStringLiteral(" MUTE"); - } - if ((i & SCARD_STATE_UNPOWERED) != 0) - { - sb += QStringLiteral(" UNPOWERED"); - } - return sb; + + return sb.join(QLatin1Char(' ')); } @@ -151,7 +154,7 @@ template static QString SCARD_STATE_toString(T i) */ bool PcscReader::hasPaceCapability(PaceCapabilityId pPaceCapability) { - return mPaceCapabilities.getPaceCapabilities().contains(pPaceCapability); + return mPaceCapabilities.contains(pPaceCapability); } @@ -164,7 +167,7 @@ Reader::CardEvent PcscReader::updateCard() } else if (returnCode == PcscUtils::Scard_E_Unknown_Reader) { - qCWarning(card_pcsc) << "SCardGetStatusChange: " << PcscUtils::toString(returnCode); + qCWarning(card_pcsc) << "SCardGetStatusChange:" << PcscUtils::toString(returnCode); qCWarning(card_pcsc) << "Reader unknown, stop updating reader information"; if (mTimerId != 0) { @@ -175,7 +178,7 @@ Reader::CardEvent PcscReader::updateCard() } else if (returnCode != PcscUtils::Scard_S_Success) { - qCWarning(card_pcsc) << "SCardGetStatusChange: " << PcscUtils::toString(returnCode); + qCWarning(card_pcsc) << "SCardGetStatusChange:" << PcscUtils::toString(returnCode); qCWarning(card_pcsc) << "Cannot update reader"; return Reader::CardEvent::NONE; } @@ -188,8 +191,8 @@ Reader::CardEvent PcscReader::updateCard() return Reader::CardEvent::NONE; } - qCDebug(card_pcsc) << "\n old state: " << SCARD_STATE_toString(mReaderState.dwCurrentState) << "\n new state: " - << SCARD_STATE_toString(mReaderState.dwEventState); + qCDebug(card_pcsc) << "old state:" << SCARD_STATE_toString(mReaderState.dwCurrentState) + << "| new state:" << SCARD_STATE_toString(mReaderState.dwEventState); bool newPresent = (mReaderState.dwEventState & SCARD_STATE_PRESENT) == SCARD_STATE_PRESENT; bool newExclusive = (mReaderState.dwEventState & SCARD_STATE_EXCLUSIVE) == SCARD_STATE_EXCLUSIVE; @@ -206,9 +209,9 @@ Reader::CardEvent PcscReader::updateCard() mPcscCard.reset(new PcscCard(this)); QSharedPointer cardConnection = createCardConnectionWorker(); CardInfoFactory::create(cardConnection, mReaderInfo); - qCDebug(card_pcsc) << "Card detected, type:" << mReaderInfo.getCardType(); + qCDebug(card_pcsc) << "Card detected:" << mReaderInfo.getCardInfo(); - if (mReaderInfo.getCardType() == CardType::UNKNOWN) + if (mReaderInfo.hasCard() && !mReaderInfo.hasEidCard()) { qCDebug(card_pcsc) << "Unknown card detected, retrying."; } @@ -218,7 +221,6 @@ Reader::CardEvent PcscReader::updateCard() } } - mUpdateRetryCounter = true; return CardEvent::CARD_INSERTED; } } @@ -226,7 +228,6 @@ Reader::CardEvent PcscReader::updateCard() { mPcscCard.reset(); mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); - mUpdateRetryCounter = false; return CardEvent::CARD_REMOVED; } @@ -241,7 +242,7 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() #else PCSC_INT PROTOCOL = 0; #endif - PCSC_CARDHANDLE cardHandle = 0; + SCARDHANDLE cardHandle = 0; PCSC_INT protocol = 0; QString str = QStringLiteral("SCardConnect(%1, %2, %3, %4, %5, %6)").arg(mContextHandle, 0, 16).arg(mReaderInfo.getName()).arg(SCARD_SHARE_DIRECT) @@ -290,11 +291,11 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() qCDebug(card_pcsc) << "FEATURES:" << QByteArray(buffer, static_cast(clen)).toHex(); mReaderFeatures = PcscReaderFeature(buffer, clen); - qCDebug(card_pcsc) << "FEATURES:" << mReaderFeatures.toString(); + qCDebug(card_pcsc) << "FEATURES:" << mReaderFeatures; - if (mReaderFeatures.getFeatures().contains(FeatureID::EXECUTE_PACE)) + if (mReaderFeatures.contains(FeatureID::EXECUTE_PACE)) { - PCSC_INT cmdID = mReaderFeatures.getFeatures().find(FeatureID::EXECUTE_PACE).value(); + PCSC_INT cmdID = mReaderFeatures.getValue(FeatureID::EXECUTE_PACE); clen = 0; @@ -324,7 +325,7 @@ PCSC_RETURNCODE PcscReader::readReaderFeaturesAndPACECapabilities() qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << QByteArray(buffer, static_cast(clen)).toHex(); mPaceCapabilities = PcscReaderPaceCapability(buffer, clen); - qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << mPaceCapabilities.toString(); + qCDebug(card_pcsc) << "PACE_CAPABILITIES:" << mPaceCapabilities; } else { diff --git a/src/card/pcsc/PcscReader.h b/src/card/pcsc/PcscReader.h index 6fbe2f8..e33ff08 100644 --- a/src/card/pcsc/PcscReader.h +++ b/src/card/pcsc/PcscReader.h @@ -1,11 +1,14 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \brief Implementation of \ref Reader for PCSC. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "CardConnectionWorker.h" #include "PcscReaderFeature.h" +#include "PcscReaderPaceCapability.h" #include "PcscUtils.h" #include "Reader.h" @@ -40,7 +43,7 @@ class PcscReader public: PcscReader(const QString& pReaderName); - ~PcscReader(); + virtual ~PcscReader() override; Card* getCard() const override; diff --git a/src/card/pcsc/PcscReaderFeature.cpp b/src/card/pcsc/PcscReaderFeature.cpp index 78a8886..e56cad1 100644 --- a/src/card/pcsc/PcscReaderFeature.cpp +++ b/src/card/pcsc/PcscReaderFeature.cpp @@ -1,7 +1,5 @@ /*! - * PcscReaderFeature.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PcscReaderFeature.h" @@ -15,29 +13,6 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card_pcsc) -namespace -{ -template static QString toStringListing(const T& pList) -{ - QStringList list; - list.reserve(pList.size()); - for (auto entry : pList) - { - list += getEnumName(entry); - } - - return QLatin1Char('[') % list.join(' ') % QLatin1Char(']'); -} - - -} - - -const QMap& PcscReaderFeature::getFeatures() const -{ - return mFeatures; -} - PcscReaderFeature::PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength) : mFeatures() @@ -50,7 +25,7 @@ PcscReaderFeature::PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength) const uchar* runner = reinterpret_cast(pFeaturesTLV); const uchar* end = reinterpret_cast(pFeaturesTLV + pLength); - for (; runner + 6 <= end; ) + for (; runner + 6 <= end;) { if (!Enum::isValue(*runner)) { @@ -75,46 +50,15 @@ PcscReaderFeature::PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength) } -QString PcscReaderFeature::toString() const +bool PcscReaderFeature::contains(FeatureID pFeatureID) const { - return toStringListing(mFeatures.keys()); + return mFeatures.contains(pFeatureID); } -QVector PcscReaderPaceCapability::getPaceCapabilities() const +PCSC_INT PcscReaderFeature::getValue(FeatureID pFeatureID) const { - return mPaceCapabilities; -} - - -PcscReaderPaceCapability::PcscReaderPaceCapability(const char* pCapabilitiesTLV, PCSC_INT pLength) - : mPaceCapabilities() -{ - if (pCapabilitiesTLV == nullptr || pLength != 7) - { - qCDebug(card_pcsc) << "capabilities: null"; - return; - } - else if (pCapabilitiesTLV[0] != 0x00 || pCapabilitiesTLV[1] != 0x00 || pCapabilitiesTLV[2] != 0x00 || pCapabilitiesTLV[3] != 0x00) - { - qCWarning(card_pcsc) << "Error on determination of pace capabilities"; - return; - } - - // in contrast to PCSC 10 Amendment 1: the output data of GetReaderPACECapabilities on Reiner SCT Konfort is of size 1! - for (PaceCapabilityId capability : Enum::getList()) - { - if (pCapabilitiesTLV[6] & static_cast(capability)) - { - mPaceCapabilities += capability; - } - } -} - - -QString PcscReaderPaceCapability::toString() const -{ - return toStringListing(mPaceCapabilities); + return mFeatures.find(pFeatureID).value(); } diff --git a/src/card/pcsc/PcscReaderFeature.h b/src/card/pcsc/PcscReaderFeature.h index 541e4ef..768d9eb 100644 --- a/src/card/pcsc/PcscReaderFeature.h +++ b/src/card/pcsc/PcscReaderFeature.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -38,25 +38,27 @@ class PcscReaderFeature private: QMap mFeatures; + friend QDebug operator<<(QDebug, const PcscReaderFeature&); + public: PcscReaderFeature(const char* pFeaturesTLV, PCSC_INT pLength = 0); - QString toString() const; - const QMap& getFeatures() const; + bool contains(FeatureID pFeatureID) const; + + /*! + * Check with contains first for existence of the + * feature, otherwise this will cause an exception. + */ + PCSC_INT getValue(FeatureID pFeatureID) const; }; -defineEnumType(PaceCapabilityId, ESIGN = 0x10, EID = 0x20, GENERIC = 0x40, DESTROY_CHANNEL = 0x80) -class PcscReaderPaceCapability +inline QDebug operator<<(QDebug pDbg, const governikus::PcscReaderFeature& pPcscReaderFeature) { - private: - QVector mPaceCapabilities; + QDebugStateSaver saver(pDbg); + pDbg << pPcscReaderFeature.mFeatures.keys(); + return pDbg; +} - public: - PcscReaderPaceCapability(const char* pCapabilitiesTLV, PCSC_INT pLength = 0); - - QString toString() const; - QVector getPaceCapabilities() const; -}; } /* namespace governikus */ diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.cpp b/src/card/pcsc/PcscReaderManagerPlugIn.cpp index 478e712..12de0bf 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.cpp +++ b/src/card/pcsc/PcscReaderManagerPlugIn.cpp @@ -1,7 +1,5 @@ /*! - * PcscReaderManagerPlugIn.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PcscReaderManagerPlugIn.h" @@ -45,7 +43,7 @@ PcscReaderManagerPlugIn::~PcscReaderManagerPlugIn() } -QList PcscReaderManagerPlugIn::getReader() const +QList PcscReaderManagerPlugIn::getReaders() const { return mReaders.values(); } @@ -157,7 +155,7 @@ void PcscReaderManagerPlugIn::updateReaders() } - for (QMutableListIterator it(readersToAdd); it.hasNext(); ) + for (QMutableListIterator it(readersToAdd); it.hasNext();) { QString readerName = it.next(); if (readersToRemove.contains(readerName)) @@ -172,7 +170,7 @@ void PcscReaderManagerPlugIn::updateReaders() removeReader(readerName); } - for (QMutableListIterator iterator(readersToAdd); iterator.hasNext(); ) + for (QMutableListIterator iterator(readersToAdd); iterator.hasNext();) { QString readerName = iterator.next(); Reader* reader = new PcscReader(readerName); diff --git a/src/card/pcsc/PcscReaderManagerPlugIn.h b/src/card/pcsc/PcscReaderManagerPlugIn.h index 4ac4f77..48ad852 100644 --- a/src/card/pcsc/PcscReaderManagerPlugIn.h +++ b/src/card/pcsc/PcscReaderManagerPlugIn.h @@ -1,9 +1,7 @@ /*! - * PcscReaderManagerPlugIn.h - * * \brief Implementation of \ref ReaderManagerPlugIn for PCSC. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -43,9 +41,9 @@ class PcscReaderManagerPlugIn public: PcscReaderManagerPlugIn(); - virtual ~PcscReaderManagerPlugIn(); + virtual ~PcscReaderManagerPlugIn() override; - QList getReader() const override; + QList getReaders() const override; void init() override; void shutdown() override; diff --git a/src/card/pcsc/PcscReaderPaceCapability.cpp b/src/card/pcsc/PcscReaderPaceCapability.cpp new file mode 100644 index 0000000..5be740c --- /dev/null +++ b/src/card/pcsc/PcscReaderPaceCapability.cpp @@ -0,0 +1,48 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PcscReaderPaceCapability.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_pcsc) + + +PcscReaderPaceCapability::PcscReaderPaceCapability(const char* pCapabilitiesTLV, PCSC_INT pLength) + : mPaceCapabilities() +{ + if (pCapabilitiesTLV == nullptr || pLength != 7) + { + qCDebug(card_pcsc) << "capabilities: null"; + return; + } + else if (pCapabilitiesTLV[0] != 0x00 || pCapabilitiesTLV[1] != 0x00 || pCapabilitiesTLV[2] != 0x00 || pCapabilitiesTLV[3] != 0x00) + { + qCWarning(card_pcsc) << "Error on determination of pace capabilities"; + return; + } + + // in contrast to PCSC 10 Amendment 1: the output data of GetReaderPACECapabilities on Reiner SCT Konfort is of size 1! + for (PaceCapabilityId capability : Enum::getList()) + { + if (pCapabilitiesTLV[6] & static_cast(capability)) + { + mPaceCapabilities += capability; + } + } +} + + +bool PcscReaderPaceCapability::contains(PaceCapabilityId pPaceCapabilityId) const +{ + return mPaceCapabilities.contains(pPaceCapabilityId); +} + + +#include "moc_PcscReaderPaceCapability.cpp" diff --git a/src/card/pcsc/PcscReaderPaceCapability.h b/src/card/pcsc/PcscReaderPaceCapability.h new file mode 100644 index 0000000..12885a2 --- /dev/null +++ b/src/card/pcsc/PcscReaderPaceCapability.h @@ -0,0 +1,42 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" +#include "PcscUtils.h" + +#include + +namespace governikus +{ +defineEnumType(PaceCapabilityId, + ESIGN = 0x10, + EID = 0x20, + GENERIC = 0x40, + DESTROY_CHANNEL = 0x80) + +class PcscReaderPaceCapability +{ + private: + QVector mPaceCapabilities; + + friend QDebug operator<<(QDebug, const PcscReaderPaceCapability&); + + public: + PcscReaderPaceCapability(const char* pCapabilitiesTLV, PCSC_INT pLength = 0); + + bool contains(PaceCapabilityId pPaceCapabilityId) const; +}; + + +inline QDebug operator<<(QDebug pDbg, const governikus::PcscReaderPaceCapability& pPcscReaderPaceCapability) +{ + QDebugStateSaver saver(pDbg); + pDbg << pPcscReaderPaceCapability.mPaceCapabilities.toList(); + return pDbg; +} + + +} /* namespace governikus */ diff --git a/src/card/pcsc/PcscUtils.cpp b/src/card/pcsc/PcscUtils.cpp index 09067f2..ea7f4c0 100644 --- a/src/card/pcsc/PcscUtils.cpp +++ b/src/card/pcsc/PcscUtils.cpp @@ -1,7 +1,5 @@ /*! - * PcscUtils.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PcscUtils.h" @@ -11,191 +9,12 @@ using namespace governikus; QString PcscUtils::toString(PCSC_RETURNCODE pCode) { - switch (pCode) + const auto& metaEnum = QMetaEnum::fromType(); + const char* name = metaEnum.valueToKey(static_cast(pCode)); + if (Q_UNLIKELY(name == nullptr)) { - case Scard_S_Success: - return QStringLiteral("SCARD_S_SUCCESS"); - - case Scard_F_Internal_Error: - return QStringLiteral("SCARD_F_INTERNAL_ERROR"); - - case Scard_E_Cancelled: - return QStringLiteral("SCARD_E_CANCELLED"); - - case Scard_E_Invalid_Handle: - return QStringLiteral("SCARD_E_INVALID_HANDLE"); - - case Scard_E_Invalid_Parameter: - return QStringLiteral("SCARD_E_INVALID_PARAMETER"); - - case Scard_E_Invalid_Target: - return QStringLiteral("SCARD_E_INVALID_TARGET"); - - case Scard_E_No_Memory: - return QStringLiteral("SCARD_E_NO_MEMORY"); - - case Scard_F_Waited_Too_Long: - return QStringLiteral("SCARD_F_WAITED_TOO_LONG"); - - case Scard_E_Insufficient_Buffer: - return QStringLiteral("SCARD_E_INSUFFICIENT_BUFFER"); - - case Scard_E_Unknown_Reader: - return QStringLiteral("SCARD_E_UNKNOWN_READER"); - - case Scard_E_Timeout: - return QStringLiteral("SCARD_E_TIMEOUT"); - - case Scard_E_Sharing_Violation: - return QStringLiteral("SCARD_E_SHARING_VIOLATION"); - - case Scard_E_No_Smartcard: - return QStringLiteral("SCARD_E_NO_SMARTCARD"); - - case Scard_E_Unknown_Card: - return QStringLiteral("SCARD_E_UNKNOWN_CARD"); - - case Scard_E_Cant_Dispose: - return QStringLiteral("SCARD_E_CANT_DISPOSE"); - - case Scard_E_Proto_Mismatch: - return QStringLiteral("SCARD_E_PROTO_MISMATCH"); - - case Scard_E_Not_Ready: - return QStringLiteral("SCARD_E_NOT_READY"); - - case Scard_E_Invalid_Value: - return QStringLiteral("SCARD_E_INVALID_VALUE"); - - case Scard_E_System_Cancelled: - return QStringLiteral("SCARD_E_SYSTEM_CANCELLED"); - - case Scard_F_Comm_Error: - return QStringLiteral("SCARD_F_COMM_ERROR"); - - case Scard_F_Unknown_Error: - return QStringLiteral("SCARD_F_UNKNOWN_ERROR"); - - case Scard_E_Invalid_Atr: - return QStringLiteral("SCARD_E_INVALID_ATR"); - - case Scard_E_Not_Transacted: - return QStringLiteral("SCARD_E_NOT_TRANSACTED"); - - case Scard_E_Reader_Unavailable: - return QStringLiteral("SCARD_E_READER_UNAVAILABLE"); - - case Scard_P_Shutdown: - return QStringLiteral("SCARD_P_SHUTDOWN"); - - case Scard_E_Pci_Too_Small: - return QStringLiteral("SCARD_E_PCI_TOO_SMALL"); - - case Scard_E_Reader_Unsupported: - return QStringLiteral("SCARD_E_READER_UNSUPPORTED"); - - case Scard_E_Duplicate_Reader: - return QStringLiteral("SCARD_E_DUPLICATE_READER"); - - case Scard_E_Card_Unsupported: - return QStringLiteral("SCARD_E_CARD_UNSUPPORTED"); - - case Scard_E_No_Service: - return QStringLiteral("SCARD_E_NO_SERVICE"); - - case Scard_E_Service_Stopped: - return QStringLiteral("SCARD_E_SERVICE_STOPPED"); - - case Scard_E_Icc_Installation: - return QStringLiteral("SCARD_E_ICC_INSTALLATION"); - - case Scard_E_Icc_Createorder: - return QStringLiteral("SCARD_E_ICC_CREATEORDER"); - - // 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: - return QStringLiteral("SCARD_E_FILE_NOT_FOUND"); - - case Scard_E_No_Dir: - return QStringLiteral("SCARD_E_NO_DIR"); - - case Scard_E_No_File: - return QStringLiteral("SCARD_E_NO_FILE"); - - case Scard_E_No_Access: - return QStringLiteral("SCARD_E_NO_ACCESS"); - - case Scard_E_Write_Too_Many: - return QStringLiteral("SCARD_E_WRITE_TOO_MANY"); - - case Scard_E_Bad_Seek: - return QStringLiteral("SCARD_E_BAD_SEEK"); - - case Scard_E_Invalid_Chv: - return QStringLiteral("SCARD_E_INVALID_CHV"); - - case Scard_E_Unknown_Res_Mng: - return QStringLiteral("SCARD_E_UNKNOWN_RES_MNG"); - - case Scard_E_No_Such_Certificate: - return QStringLiteral("SCARD_E_NO_SUCH_CERTIFICATE"); - - case Scard_E_Certificate_Unavailable: - return QStringLiteral("SCARD_E_CERTIFICATE_UNAVAILABLE"); - - case Scard_E_No_Readers_Available: - return QStringLiteral("SCARD_E_NO_READERS_AVAILABLE"); - - case Scard_E_Comm_Data_Lost: - return QStringLiteral("SCARD_E_COMM_DATA_LOST"); - - case Scard_E_No_Key_Container: - return QStringLiteral("SCARD_E_NO_KEY_CONTAINER"); - - case Scard_E_Server_Too_Busy: - return QStringLiteral("SCARD_E_SERVER_TOO_BUSY"); - - case Scard_W_Unsupported_Card: - return QStringLiteral("SCARD_W_UNSUPPORTED_CARD"); - - case Scard_W_Unresponsive_Card: - return QStringLiteral("SCARD_W_UNRESPONSIVE_CARD"); - - case Scard_W_Unpowered_Card: - return QStringLiteral("SCARD_W_UNPOWERED_CARD"); - - case Scard_W_Reset_Card: - return QStringLiteral("SCARD_W_RESET_CARD"); - - case Scard_W_Removed_Card: - return QStringLiteral("SCARD_W_REMOVED_CARD"); - - case Scard_W_Security_Violation: - return QStringLiteral("SCARD_W_SECURITY_VIOLATION"); - - case Scard_W_Wrong_Chv: - return QStringLiteral("SCARD_W_WRONG_CHV"); - - case Scard_W_Chv_Blocked: - return QStringLiteral("SCARD_W_CHV_BLOCKED"); - - case Scard_W_Eof: - return QStringLiteral("SCARD_W_EOF"); - - case Scard_W_Cancelled_By_User: - return QStringLiteral("SCARD_W_CANCELLED_BY_USER"); - - case Scard_W_Card_Not_Authenticated: - return QStringLiteral("SCARD_W_CARD_NOT_AUTHENTICATED"); - - default: - return QStringLiteral("UNKNOWN_STATE (%1)").arg(pCode, 8, 16, QChar('0')); + return QStringLiteral("UNKNOWN_STATE (%1)").arg(pCode, 8, 16, QLatin1Char('0')); } + + return QString::fromLatin1(name); } diff --git a/src/card/pcsc/PcscUtils.h b/src/card/pcsc/PcscUtils.h index 5aac998..b29a465 100644 --- a/src/card/pcsc/PcscUtils.h +++ b/src/card/pcsc/PcscUtils.h @@ -1,73 +1,63 @@ /*! - * PcscUtils.h - * * \brief toString method for PCSC_RETURNCODE and platform dependent * typedefs for PCSC types. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include #include #include -// TODO: Check these codes -#ifdef Q_OS_WIN #include -typedef LONG PCSC_RETURNCODE; -typedef SCARDHANDLE PCSC_CARDHANDLE; -typedef DWORD PCSC_UINT; -typedef DWORD PCSC_INT; -typedef DWORD* PCSC_INT_PTR; -#ifdef UNICODE -typedef WCHAR PCSC_CHAR; -#else -typedef CHAR PCSC_CHAR; + +#ifndef Q_OS_WIN +#include #endif -typedef LPTSTR PCSC_CHAR_PTR; -typedef BYTE PCSC_UCHAR; + +/* + * Because the three PC/SC implementations on Windows, + * MacOS and Linux have sligtly different types, we typedef + * an abstraction layer for those data types. + */ +#ifdef Q_OS_WIN +typedef LONG PCSC_RETURNCODE; +typedef DWORD PCSC_INT; +typedef TCHAR PCSC_CHAR; +typedef TCHAR* PCSC_CHAR_PTR; typedef LPBYTE PCSC_UCHAR_PTR; typedef LPCBYTE PCSC_CUCHAR_PTR; -#elif defined Q_OS_OSX -#include -// 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 int64_t PCSC_RETURNCODE; -typedef SCARDHANDLE PCSC_CARDHANDLE; +#elif defined Q_OS_MACOS +typedef int32_t PCSC_RETURNCODE; typedef uint32_t PCSC_INT; -typedef PCSC_INT* PCSC_INT_PTR; typedef char PCSC_CHAR; typedef char* PCSC_CHAR_PTR; -typedef uchar PCSC_UCHAR; typedef uchar* PCSC_UCHAR_PTR; typedef const uchar* PCSC_CUCHAR_PTR; #elif defined Q_OS_UNIX -#include typedef LONG PCSC_RETURNCODE; -typedef SCARDHANDLE PCSC_CARDHANDLE; typedef DWORD PCSC_INT; -typedef PCSC_INT* PCSC_INT_PTR; typedef char PCSC_CHAR; typedef char* PCSC_CHAR_PTR; -typedef uchar PCSC_UCHAR; typedef uchar* PCSC_UCHAR_PTR; typedef const uchar* PCSC_CUCHAR_PTR; #endif + namespace governikus { class PcscUtils { + Q_GADGET + private: PcscUtils() = delete; ~PcscUtils() = delete; public: - static QString toString(PCSC_RETURNCODE pCode); - /** * Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx */ @@ -104,8 +94,8 @@ class PcscUtils 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_Unexpected = static_cast(SCARD_E_UNEXPECTED), /**< An unexpected card error has occurred. */ 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. */ @@ -138,13 +128,16 @@ class PcscUtils 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. */ }; + Q_ENUM(PcscReturnCode); + static QString toString(PCSC_RETURNCODE pCode); }; /** * Make sure we do not use these macros directly in our code. */ +#ifdef QT_NO_DEBUG #undef SCARD_S_SUCCESS #undef SCARD_F_INTERNAL_ERROR #undef SCARD_E_CANCELLED @@ -209,6 +202,6 @@ class PcscUtils #undef SCARD_W_EOF #undef SCARD_W_CANCELLED_BY_USER #undef SCARD_W_CARD_NOT_AUTHENTICATED - +#endif } /* namespace governikus */ diff --git a/src/card/remote/CMakeLists.txt b/src/card/remote/CMakeLists.txt index 40241f4..03f4a5f 100644 --- a/src/card/remote/CMakeLists.txt +++ b/src/card/remote/CMakeLists.txt @@ -1,5 +1,4 @@ ADD_PLATFORM_LIBRARY(AusweisAppCardRemote) -TARGET_INCLUDE_DIRECTORIES(AusweisAppCardRemote SYSTEM PUBLIC) -TARGET_LINK_LIBRARIES(AusweisAppCardRemote Qt5::Core Qt5::WebSockets AusweisAppGlobal AusweisAppCard) +TARGET_LINK_LIBRARIES(AusweisAppCardRemote Qt5::Core AusweisAppGlobal AusweisAppCard AusweisAppRemoteDevice) TARGET_COMPILE_DEFINITIONS(AusweisAppCardRemote PRIVATE QT_STATICPLUGIN) diff --git a/src/card/remote/DataChannel.cpp b/src/card/remote/DataChannel.cpp deleted file mode 100644 index c8f331d..0000000 --- a/src/card/remote/DataChannel.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 2998ace..0000000 --- a/src/card/remote/DataChannel.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * 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 deleted file mode 100644 index d5d2364..0000000 --- a/src/card/remote/NotificationHandler.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * \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 deleted file mode 100644 index cfa99d4..0000000 --- a/src/card/remote/NotificationHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * 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 deleted file mode 100644 index e416e58..0000000 --- a/src/card/remote/NotificationParser.cpp +++ /dev/null @@ -1,663 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 1c15231..0000000 --- a/src/card/remote/NotificationParser.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * 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/RemoteCard.cpp b/src/card/remote/RemoteCard.cpp new file mode 100644 index 0000000..3e6d28e --- /dev/null +++ b/src/card/remote/RemoteCard.cpp @@ -0,0 +1,199 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteCard.h" + +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdEstablishPaceChannel.h" +#include "messages/IfdEstablishPaceChannelResponse.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + + +bool RemoteCard::sendMessage(const QSharedPointer& pMessage, RemoteCardMessageType pExpectedAnswer, unsigned long pTimeout) +{ + // mResponseAvailable is locked by the constructor, to revert the mutex behavior. + // Locking this is a requirement for QWaitCondition. + + mWaitingForAnswer = true; + mExpectedAnswerType = pExpectedAnswer; + + const auto& connection = QObject::connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteCard::onMessageReceived, Qt::DirectConnection); + QMetaObject::invokeMethod(mRemoteDispatcher.data(), "send", Qt::QueuedConnection, Q_ARG(QSharedPointer, pMessage)); + + mWaitCondition.wait(&mResponseAvailable, pTimeout); + QObject::disconnect(connection); + + QMutexLocker locker(&mProcessResponse); + + if (mWaitingForAnswer) + { + mWaitingForAnswer = false; + return false; + } + + return true; +} + + +void RemoteCard::onMessageReceived(const QSharedPointer& pMessage) +{ + QMutexLocker locker(&mProcessResponse); + + if (!mWaitingForAnswer) + { + return; + } + + if (pMessage->getType() == mExpectedAnswerType) + { + mResponse = pMessage; + mWaitingForAnswer = false; + mWaitCondition.wakeOne(); + } +} + + +void RemoteCard::onDispatcherClosed(GlobalStatus::Code pCloseCode, const QSharedPointer&) +{ + QMutexLocker locker(&mProcessResponse); + + if (mWaitingForAnswer) + { + qCWarning(card_remote) << "RemoteDispatcher was closed while waiting for an answer:" << pCloseCode; + + mResponse.reset(); + mWaitingForAnswer = false; + mWaitCondition.wakeOne(); + } +} + + +RemoteCard::RemoteCard(const QSharedPointer& pRemoteDispatcher, const QString& pReaderName) + : Card() + , mWaitingForAnswer(false) + , mWaitCondition() + , mResponseAvailable() + , mProcessResponse() + , mExpectedAnswerType() + , mResponse() + , mRemoteDispatcher(pRemoteDispatcher) + , mReaderName(pReaderName) + , mConnected(false) +{ + Q_ASSERT(mRemoteDispatcher); + + mResponseAvailable.lock(); + const QString& contextHandle = mRemoteDispatcher->getContextHandle(); + mReaderName.remove(contextHandle); + + QObject::connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteCard::onDispatcherClosed, Qt::DirectConnection); +} + + +RemoteCard::~RemoteCard() +{ + mResponseAvailable.unlock(); +} + + +CardReturnCode RemoteCard::connect() +{ + const QSharedPointer connectMsg(new IfdConnect(mReaderName)); + if (sendMessage(connectMsg, RemoteCardMessageType::IFDConnectResponse, 5000)) + { + const QSharedPointer response = mResponse.dynamicCast(); + if (response) + { + if (!response->resultHasError()) + { + mConnected = true; + return CardReturnCode::OK; + } + qCWarning(card_remote) << response->getResultMinor(); + } + } + return CardReturnCode::COMMAND_FAILED; +} + + +CardReturnCode RemoteCard::disconnect() +{ + const QSharedPointer disconnectCmd(new IfdDisconnect(mReaderName)); + if (sendMessage(disconnectCmd, RemoteCardMessageType::IFDDisconnectResponse, 5000)) + { + const QSharedPointer response = mResponse.dynamicCast(); + if (response) + { + if (!response->resultHasError()) + { + mConnected = false; + return CardReturnCode::OK; + } + qCWarning(card_remote) << response->getResultMinor(); + } + } + return CardReturnCode::COMMAND_FAILED; +} + + +bool RemoteCard::isConnected() +{ + return mConnected; +} + + +CardReturnCode RemoteCard::transmit(const CommandApdu& pCommand, ResponseApdu& pResponse) +{ + QSharedPointer transmitCmd(new IfdTransmit(mReaderName, pCommand.getBuffer())); + if (sendMessage(transmitCmd, RemoteCardMessageType::IFDTransmitResponse, 5000)) + { + const QSharedPointer response = mResponse.dynamicCast(); + if (response) + { + if (!response->resultHasError()) + { + pResponse.setBuffer(response->getResponseApdu()); + return CardReturnCode::OK; + } + qCWarning(card_remote) << response->getResultMinor(); + } + } + return CardReturnCode::COMMAND_FAILED; +} + + +CardReturnCode RemoteCard::establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds) +{ + EstablishPACEChannelBuilder builder; + builder.setPasswordId(pPasswordId); + builder.setChat(pChat); + builder.setCertificateDescription(pCertificateDescription); + const QByteArray inputData = builder.createCommandDataCcid().getBuffer(); + + QSharedPointer message(new IfdEstablishPaceChannel(mReaderName, inputData)); + if (sendMessage(message, RemoteCardMessageType::IFDEstablishPACEChannelResponse, pTimeoutSeconds * 1000)) + { + const QSharedPointer response = mResponse.dynamicCast(); + if (response) + { + pChannelOutput.parseFromCcid(response->getOutputData(), pPasswordId); + return pChannelOutput.getPaceReturnCode(); + } + } + + return CardReturnCode::COMMAND_FAILED; +} diff --git a/src/card/remote/RemoteCard.h b/src/card/remote/RemoteCard.h new file mode 100644 index 0000000..9a59ae9 --- /dev/null +++ b/src/card/remote/RemoteCard.h @@ -0,0 +1,61 @@ +/*! + * \brief Implementation of \ref Card for remote reader. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "Card.h" +#include "messages/RemoteMessage.h" +#include "RemoteDispatcher.h" + +#include +#include +#include +#include + + +namespace governikus +{ + +class RemoteCard + : public Card +{ + Q_OBJECT + + private: + bool mWaitingForAnswer; + QWaitCondition mWaitCondition; + QMutex mResponseAvailable, mProcessResponse; + + RemoteCardMessageType mExpectedAnswerType; + QSharedPointer mResponse; + const QSharedPointer mRemoteDispatcher; + QString mReaderName; + bool mConnected; + + bool sendMessage(const QSharedPointer& pMessage, RemoteCardMessageType pExpectedAnswer, unsigned long pTimeout); + + private Q_SLOTS: + void onMessageReceived(const QSharedPointer& pMessage); + void onDispatcherClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); + + Q_SIGNALS: + void fireCardRemoved(); + + public: + RemoteCard(const QSharedPointer& pRemoteDispatcher, const QString& pReaderName); + virtual ~RemoteCard() override; + + virtual CardReturnCode connect() override; + virtual CardReturnCode disconnect() override; + virtual bool isConnected() override; + + virtual CardReturnCode transmit(const CommandApdu& pCmd, ResponseApdu& pRes) override; + + virtual CardReturnCode establishPaceChannel(PACE_PASSWORD_ID pPasswordId, const QByteArray& pChat, const QByteArray& pCertificateDescription, EstablishPACEChannelOutput& pChannelOutput, quint8 pTimeoutSeconds = 60) override; + +}; + +} /* namespace governikus */ diff --git a/src/card/remote/RemoteCardNotifications.cpp b/src/card/remote/RemoteCardNotifications.cpp deleted file mode 100644 index a2d87d5..0000000 --- a/src/card/remote/RemoteCardNotifications.cpp +++ /dev/null @@ -1,860 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 89f78e8..0000000 --- a/src/card/remote/RemoteCardNotifications.h +++ /dev/null @@ -1,475 +0,0 @@ -/*! - * 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/RemoteReader.cpp b/src/card/remote/RemoteReader.cpp new file mode 100644 index 0000000..da8242c --- /dev/null +++ b/src/card/remote/RemoteReader.cpp @@ -0,0 +1,83 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteReader.h" + +#include "CardConnectionWorker.h" + +#include +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + + +RemoteReader::RemoteReader(const QString& pReaderName, const QSharedPointer& pRemoteDispatcher, const IfdStatus& pIfdStatus) + : Reader(ReaderManagerPlugInType::REMOTE, pReaderName) + , mRemoteDispatcher(pRemoteDispatcher) +{ + mReaderInfo.setBasicReader(!pIfdStatus.getPaceCapabilities().getPace()); + mReaderInfo.setConnected(true); + + update(pIfdStatus); +} + + +RemoteReader::~RemoteReader() +{ + mCard.reset(); +} + + +Card* RemoteReader::getCard() const +{ + return mCard.data(); +} + + +Reader::CardEvent RemoteReader::updateCard() +{ + return CardEvent::NONE; +} + + +void RemoteReader::update(const IfdStatus& pIfdStatus) +{ + if (mReaderInfo.getMaxApduLength() != pIfdStatus.getMaxApduLength()) + { + mReaderInfo.setMaxApduLength(pIfdStatus.getMaxApduLength()); + Q_EMIT fireReaderPropertiesUpdated(getName()); + + if (!mReaderInfo.sufficientApduLength()) + { + qCDebug(card_remote) << "ExtendedLengthApduSupport missing. maxAPDULength:" << mReaderInfo.getMaxApduLength(); + if (!mCard) + { + return; + } + } + } + + if (mCard) + { + if (!pIfdStatus.getCardAvailable()) + { + qCDebug(card_remote) << "Card removed"; + mReaderInfo.setCardInfo(CardInfo(CardType::NONE)); + mCard.reset(); + Q_EMIT fireCardRemoved(getName()); + } + return; + } + + if (pIfdStatus.getCardAvailable()) + { + qCDebug(card_remote) << "Card inserted"; + mCard.reset(new RemoteCard(mRemoteDispatcher, getName())); + QSharedPointer cardConnection = createCardConnectionWorker(); + CardInfoFactory::create(cardConnection, mReaderInfo); + Q_EMIT fireCardInserted(getName()); + } +} diff --git a/src/card/remote/RemoteReader.h b/src/card/remote/RemoteReader.h new file mode 100644 index 0000000..0938249 --- /dev/null +++ b/src/card/remote/RemoteReader.h @@ -0,0 +1,41 @@ +/*! + * \brief Implementation of \ref Reader for remote reader. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "messages/IfdStatus.h" +#include "Reader.h" +#include "RemoteCard.h" +#include "RemoteDispatcher.h" + +#include +#include + + +namespace governikus +{ + +class RemoteReader + : public Reader +{ + Q_OBJECT + + private: + QScopedPointer mCard; + const QSharedPointer mRemoteDispatcher; + + virtual CardEvent updateCard() override; + + public: + RemoteReader(const QString& pReaderName, const QSharedPointer& pRemoteDispatcher, const IfdStatus& pIfdStatus); + virtual ~RemoteReader() override; + + virtual Card* getCard() const override; + + void update(const IfdStatus& pIfdStatus); +}; + +} /* namespace governikus */ diff --git a/src/card/remote/RemoteReaderManagerPlugIn.cpp b/src/card/remote/RemoteReaderManagerPlugIn.cpp new file mode 100644 index 0000000..373c885 --- /dev/null +++ b/src/card/remote/RemoteReaderManagerPlugIn.cpp @@ -0,0 +1,326 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteReaderManagerPlugIn.h" + +#include "AppSettings.h" +#include "FuncUtils.h" +#include "messages/GetIfdStatus.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/IfdStatus.h" +#include "RemoteClient.h" +#include "RemoteDeviceList.h" +#include "RemoteReader.h" + +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(card_remote) + + +void RemoteReaderManagerPlugIn::updateReader(const IfdStatus& pIfdStatus) +{ + const QSharedPointer remoteToUpdate = mRemoteToUpdate.toStrongRef(); + const QString& contextHandle = remoteToUpdate->getContextHandle(); + const QString& readerName = pIfdStatus.getSlotName() + contextHandle; + + if (mReaderList.contains(readerName)) + { + if (pIfdStatus.getConnectedReader()) + { + static_cast(mReaderList[readerName])->update(pIfdStatus); + } + else + { + qCDebug(card_remote) << "Removed reader" << readerName; + Q_EMIT fireReaderRemoved(readerName); + delete mReaderList.take(readerName); + mRemoteDispatchers.remove(remoteToUpdate, readerName); + } + return; + } + + if (pIfdStatus.getConnectedReader()) + { + RemoteReader* reader = new RemoteReader(readerName, remoteToUpdate, pIfdStatus); + + connect(reader, &RemoteReader::fireCardInserted, this, &RemoteReaderManagerPlugIn::fireCardInserted); + connect(reader, &RemoteReader::fireCardRemoved, this, &RemoteReaderManagerPlugIn::fireCardRemoved); + connect(reader, &RemoteReader::fireCardRetryCounterChanged, this, &RemoteReaderManagerPlugIn::fireCardRetryCounterChanged); + connect(reader, &RemoteReader::fireReaderPropertiesUpdated, this, &RemoteReaderManagerPlugIn::fireReaderPropertiesUpdated); + + mReaderList.insert(readerName, reader); + mRemoteDispatchers.insert(remoteToUpdate, readerName); + qCDebug(card_remote) << "Add reader" << readerName; + Q_EMIT fireReaderAdded(readerName); + + // Also update card + reader->update(pIfdStatus); + } +} + + +void RemoteReaderManagerPlugIn::removeDispatcher(const QSharedPointer& pRemoteDispatcher) +{ + const auto& remoteReader = mRemoteDispatchers.values(pRemoteDispatcher); + for (const auto& readerName : remoteReader) + { + if (readerName.isEmpty()) + { + continue; + } + Q_EMIT fireReaderRemoved(readerName); + delete mReaderList.take(readerName); + } + disconnect(pRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteReaderManagerPlugIn::onRemoteMessage); + disconnect(pRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteReaderManagerPlugIn::onDispatcherClosed); + + mRemoteDispatchers.remove(pRemoteDispatcher); +} + + +void RemoteReaderManagerPlugIn::removeAllDispatchers() +{ + const auto& keys = mRemoteDispatchers.keys(); + for (const auto& dispatcher : keys) + { + removeDispatcher(dispatcher); + } +} + + +void RemoteReaderManagerPlugIn::connectToPairedReaders() +{ + if (!mRemoteClient.isNull()) + { + connect(mRemoteClient.data(), &RemoteClient::fireRemoteDevicesInfo, this, &RemoteReaderManagerPlugIn::continueConnectToPairedReaders); + QMetaObject::invokeMethod(mRemoteClient.data(), "requestRemoteDevices", Qt::QueuedConnection); + } +} + + +void RemoteReaderManagerPlugIn::unexpectedMessage(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher, bool pSendMessage) +{ + qCWarning(card_remote) << "Received an unexpected message of type:" << pMessage->getType(); + + if (pSendMessage) + { + const QSharedPointer errorMessage(new IfdError(QString(), QStringLiteral("/al/common#unknownAPIFunction"))); + QMetaObject::invokeMethod(pRemoteDispatcher.data(), "send", Qt::QueuedConnection, Q_ARG(QSharedPointer, errorMessage)); + } +} + + +void RemoteReaderManagerPlugIn::continueConnectToPairedReaders(const QVector >& pRemoteDevices) +{ + disconnect(mRemoteClient.data(), &RemoteClient::fireRemoteDevicesInfo, this, &RemoteReaderManagerPlugIn::continueConnectToPairedReaders); + + const QList > remoteDispatchers = mRemoteDispatchers.keys(); + const QStringList connectionIds = map, QString>([](const QSharedPointer& d){ + return d->getId(); + }, + remoteDispatchers); + + const RemoteServiceSettings& remoteServiceSettings = AppSettings::getInstance().getRemoteServiceSettings(); + for (const QSharedPointer& remoteDevice : pRemoteDevices) + { + const QString ifdId = remoteDevice->getRemoteDeviceDescriptor().getIfdId(); + + // If already connected: skip. + if (connectionIds.contains(ifdId)) + { + continue; + } + + const RemoteServiceSettings::RemoteInfo remoteInfo = remoteServiceSettings.getRemoteInfo(ifdId); + // If we find a remote info for this fingerprint (IfdId), then the remote device is paired. + if (remoteInfo.getFingerprint() == ifdId) + { + QMetaObject::invokeMethod(mRemoteClient.data(), "establishConnection", Qt::QueuedConnection, Q_ARG(QSharedPointer, remoteDevice), Q_ARG(QString, QString())); + } + } +} + + +void RemoteReaderManagerPlugIn::onRemoteMessage(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher) +{ + const QVector clientMessageTypes({ + RemoteCardMessageType::IFDEstablishContext, + RemoteCardMessageType::IFDGetStatus, + RemoteCardMessageType::IFDConnect, + RemoteCardMessageType::IFDDisconnect, + RemoteCardMessageType::IFDTransmit, + RemoteCardMessageType::IFDEstablishPACEChannel + }); + + if (clientMessageTypes.contains(pMessage->getType())) + { + unexpectedMessage(pMessage, pRemoteDispatcher, true); + return; + } + + mRemoteToUpdate = pRemoteDispatcher; + receive(pMessage, pRemoteDispatcher); +} + + +void RemoteReaderManagerPlugIn::onDispatcherClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher) +{ + qCDebug(card_remote) << "RemoteDispatcher was closed with:" << pCloseCode; + removeDispatcher(pRemoteDispatcher); +} + + +void RemoteReaderManagerPlugIn::checkRemoteDevices() +{ + if (mConnectToKnownReaders) + { + connectToPairedReaders(); + } +} + + +void RemoteReaderManagerPlugIn::onConnectToKnownReadersChanged() +{ + if (mConnectToKnownReaders) + { + connectToPairedReaders(); + } + else + { + removeAllDispatchers(); + } +} + + +RemoteReaderManagerPlugIn::RemoteReaderManagerPlugIn() + : ReaderManagerPlugIn(ReaderManagerPlugInType::REMOTE, true) + , MessageReceiver() + , mScanTimer() + , mRemoteClient() + , mReaderList() +{ + mScanTimer.setInterval(1000); + connect(&mScanTimer, &QTimer::timeout, this, &RemoteReaderManagerPlugIn::checkRemoteDevices); +} + + +RemoteReaderManagerPlugIn::~RemoteReaderManagerPlugIn() +{ + mScanTimer.stop(); + removeAllDispatchers(); +} + + +void RemoteReaderManagerPlugIn::setRemoteClient(const QSharedPointer& pRemoteClient) +{ + mRemoteClient = pRemoteClient; + if (!mRemoteClient.isNull()) + { + connect(mRemoteClient.data(), &RemoteClient::fireNewRemoteDispatcher, this, &RemoteReaderManagerPlugIn::addRemoteDispatcher); + } +} + + +QList RemoteReaderManagerPlugIn::getReaders() const +{ + return mReaderList.values(); +} + + +void RemoteReaderManagerPlugIn::addRemoteDispatcher(const QSharedPointer& pRemoteDispatcher) +{ + Q_ASSERT(pRemoteDispatcher); + + mRemoteDispatchers.insert(pRemoteDispatcher, QString()); + + connect(pRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteReaderManagerPlugIn::onRemoteMessage); + connect(pRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteReaderManagerPlugIn::onDispatcherClosed); + + const QSharedPointer establishContext(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName())); + QMetaObject::invokeMethod(pRemoteDispatcher.data(), "send", Qt::QueuedConnection, Q_ARG(QSharedPointer, establishContext)); +} + + +void RemoteReaderManagerPlugIn::process(const QSharedPointer& pMessage) +{ + if (pMessage->resultHasError()) + { + qCDebug(card_remote) << "EstablishContext failed:" << pMessage->getResultMinor(); + return; + } + + bool initialPairing = false; + + //update IFD name + if (mRemoteToUpdate) + { + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + auto info = settings.getRemoteInfo(mRemoteToUpdate.data()->getId()); + if (info.getName().isEmpty()) + { + initialPairing = true; + } + info.setName(pMessage->getIfdName()); + settings.updateRemoteInfo(info); + } + + if (initialPairing) + { + removeDispatcher(mRemoteToUpdate); + } + else + { + const QSharedPointer getIfdStatus(new GetIfdStatus()); + QMetaObject::invokeMethod(mRemoteToUpdate.data(), "send", Qt::QueuedConnection, Q_ARG(QSharedPointer, getIfdStatus)); + } +} + + +void RemoteReaderManagerPlugIn::process(const QSharedPointer& pMessage) +{ + updateReader(*pMessage); +} + + +void RemoteReaderManagerPlugIn::unprocessed(const QSharedPointer& pMessage) +{ + unexpectedMessage(pMessage); +} + + +void RemoteReaderManagerPlugIn::startScan() +{ + if (mRemoteClient.isNull()) + { + qCWarning(card_remote) << "Cannot start remote device discovery: no remote client found"; + return; + } + + connect(mRemoteClient.data(), &RemoteClient::fireDeviceAppeared, this, &RemoteReaderManagerPlugIn::checkRemoteDevices); + + mScanTimer.start(); + QMetaObject::invokeMethod(mRemoteClient.data(), "startDetection", Qt::QueuedConnection); + mScanInProgress = true; +} + + +void RemoteReaderManagerPlugIn::stopScan() +{ + if (mRemoteClient.isNull()) + { + qCWarning(card_remote) << "Cannot stop remote device discovery: no remote client found"; + return; + } + + disconnect(mRemoteClient.data(), &RemoteClient::fireDeviceAppeared, this, &RemoteReaderManagerPlugIn::checkRemoteDevices); + mScanTimer.stop(); + QMetaObject::invokeMethod(mRemoteClient.data(), "stopDetection", Qt::QueuedConnection); + mScanInProgress = false; +} diff --git a/src/card/remote/RemoteReaderManagerPlugIn.h b/src/card/remote/RemoteReaderManagerPlugIn.h new file mode 100644 index 0000000..d3f3acb --- /dev/null +++ b/src/card/remote/RemoteReaderManagerPlugIn.h @@ -0,0 +1,74 @@ +/*! + * \brief Implementation of \ref ReaderManagerPlugIn for remote reader. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "Env.h" +#include "messages/MessageReceiver.h" +#include "Reader.h" +#include "ReaderManagerPlugIn.h" + +#include +#include +#include +#include + +namespace governikus +{ +class IfdStatus; +class RemoteClient; +class ReaderDescription; +class RemoteDeviceListEntry; + +class RemoteReaderManagerPlugIn + : public ReaderManagerPlugIn + , public MessageReceiver +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "governikus.ReaderManagerPlugIn" FILE "metadata.json") + Q_INTERFACES(governikus::ReaderManagerPlugIn) + + private: + QTimer mScanTimer; + QSharedPointer mRemoteClient; + QWeakPointer mRemoteToUpdate; + QMultiMap, QString> mRemoteDispatchers; + QMap mReaderList; + + void updateReader(const IfdStatus& pIfdStatus); + void removeDispatcher(const QSharedPointer& pRemoteDispatcher); + void removeAllDispatchers(); + void connectToPairedReaders(); + void unexpectedMessage(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher = QSharedPointer(), bool pSendMessage = false); + + private Q_SLOTS: + void onRemoteMessage(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher); + void onDispatcherClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); + void addRemoteDispatcher(const QSharedPointer& pRemoteDispatcher); + void checkRemoteDevices(); + void continueConnectToPairedReaders(const QVector >& pRemoteDevices); + + protected: + virtual void onConnectToKnownReadersChanged() override; + + public: + RemoteReaderManagerPlugIn(); + virtual ~RemoteReaderManagerPlugIn() override; + + virtual void setRemoteClient(const QSharedPointer& pRemoteClient) override; + virtual QList getReaders() const override; + + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + + virtual void unprocessed(const QSharedPointer& pMessage) override; + + virtual void startScan() override; + virtual void stopScan() override; + +}; + +} /* namespace governikus */ diff --git a/src/card/remote/WebSocketChannel.cpp b/src/card/remote/WebSocketChannel.cpp deleted file mode 100644 index 3db3627..0000000 --- a/src/card/remote/WebSocketChannel.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 02a45a4..0000000 --- a/src/card/remote/WebSocketChannel.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * 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/card/remote/metadata.json b/src/card/remote/metadata.json new file mode 100644 index 0000000..4053cb3 --- /dev/null +++ b/src/card/remote/metadata.json @@ -0,0 +1,4 @@ +{ + "name" : "RemoteReaderManagerPlugIn", + "dependencies" : [] +} diff --git a/src/cli/ConsoleReader.cpp b/src/cli/ConsoleReader.cpp index 3aff089..037d955 100644 --- a/src/cli/ConsoleReader.cpp +++ b/src/cli/ConsoleReader.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "ConsoleReader.h" diff --git a/src/cli/ConsoleReader.h b/src/cli/ConsoleReader.h index 8105f87..fa77e1d 100644 --- a/src/cli/ConsoleReader.h +++ b/src/cli/ConsoleReader.h @@ -1,7 +1,7 @@ /*! * \brief Helper to read stdin in non-blocking mode. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/cli/UIPlugInCli.cpp b/src/cli/UIPlugInCli.cpp index 68e4213..d3dec7f 100644 --- a/src/cli/UIPlugInCli.cpp +++ b/src/cli/UIPlugInCli.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInCli.h" @@ -7,7 +7,7 @@ #include "states/StateEstablishPacePin.h" #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -#include "EnvHolder.h" +#include "Env.h" #include "HttpServer.h" #endif @@ -58,9 +58,9 @@ void UIPlugInCli::onWorkflowStarted(QSharedPointer pContext) mContext = pContext; if (!mContext.isNull()) { - connect(mContext.data(), &WorkflowContext::fireCurrentStateChanged, - this, &UIPlugInCli::onCurrentStateChanged); - mContext->setReaderType(ReaderManagerPlugInType::PCSC); + connect(mContext.data(), &WorkflowContext::fireStateChanged, + this, &UIPlugInCli::onStateChanged); + mContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC}); } } @@ -76,7 +76,7 @@ void UIPlugInCli::onWorkflowFinished(QSharedPointer pContext) } -void UIPlugInCli::onCurrentStateChanged(const QString& pState) +void UIPlugInCli::onStateChanged(const QString& pState) { Q_UNUSED(pState); @@ -96,7 +96,7 @@ void UIPlugInCli::doInput(const QString& pData) { qCInfo(stdinput) << pData; - const QStringList chunks = pData.split(QChar(' ')); + const QStringList chunks = pData.split(QLatin1Char(' ')); auto func = mAvailableCommands.value(chunks.at(0).toLower()); if (func) { @@ -220,7 +220,7 @@ void UIPlugInCli::handlePing() void UIPlugInCli::handlePort() { #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - qCInfo(cli) << "Port:" << EnvHolder::shared()->getServerPort(); + qCInfo(cli) << "Port:" << Env::getShared()->getServerPort(); #else qCInfo(cli) << "Port is undefined"; #endif diff --git a/src/cli/UIPlugInCli.h b/src/cli/UIPlugInCli.h index 18eae5f..ba358ce 100644 --- a/src/cli/UIPlugInCli.h +++ b/src/cli/UIPlugInCli.h @@ -1,7 +1,7 @@ /*! * \brief UIPlugIn implementation of CLI. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,7 +25,7 @@ class UIPlugInCli Q_PLUGIN_METADATA(IID "governikus.UIPlugIn" FILE "metadata.json") Q_INTERFACES(governikus::UIPlugIn) - typedef void (UIPlugInCli::* MemberFunc)(); + using MemberFunc = void (UIPlugInCli::*)(); private: QString mOldPin; @@ -51,7 +51,7 @@ class UIPlugInCli public: UIPlugInCli(); - virtual ~UIPlugInCli(); + virtual ~UIPlugInCli() override; public Q_SLOTS: virtual void onApplicationStarted() override; @@ -62,7 +62,7 @@ class UIPlugInCli void doInput(const QString& pData); virtual void onWorkflowStarted(QSharedPointer pContext) override; virtual void onWorkflowFinished(QSharedPointer pContext) override; - void onCurrentStateChanged(const QString& pState); + void onStateChanged(const QString& pState); void handleOldPinEntered(const QString& pLine); void handleNewPinEntered(const QString& pLine); diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..12bc281 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,29 @@ +/* DO NOT TOUCH THIS MANUALLY */ + +#define PRODUCT "@PRODUCT@" +#define VENDOR "@VENDOR@" +#define VENDOR_DOMAIN "@VENDOR_DOMAIN@" + +#define VERSION "@VERSION@" +#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define VERSION_TWEAK @PROJECT_VERSION_TWEAK@ + +#ifdef __BASE_FILE__ + constexpr inline bool isComparableSep(char pFirst, char pSecond) + { + return (pFirst == '\\' && pSecond == '/') || (pFirst == '/' && pSecond == '\\'); + } + + constexpr inline bool isEqual(const char* pFirst, const char* pSecond) + { + return (*pFirst && *pSecond) ? ((*pFirst == *pSecond || isComparableSep(*pFirst, *pSecond)) && isEqual(pFirst + 1, pSecond + 1)) : (!*pFirst && !*pSecond); + } + + static_assert(isEqual("@CMAKE_CURRENT_SOURCE_DIR@/main.cpp", __BASE_FILE__), "config.h include is allowed in main.cpp only! Provided: " __BASE_FILE__); +#endif + +/* DO NOT INCLUDE THIS + Use QCoreApplication or VersionNumber! +*/ diff --git a/src/configuration/CMakeLists.txt b/src/configuration/CMakeLists.txt new file mode 100644 index 0000000..d7f0b81 --- /dev/null +++ b/src/configuration/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppConfiguration) + +TARGET_LINK_LIBRARIES(AusweisAppConfiguration Qt5::Core AusweisAppGlobal AusweisAppFileProvider) diff --git a/src/configuration/CallCost.cpp b/src/configuration/CallCost.cpp new file mode 100644 index 0000000..1d0c872 --- /dev/null +++ b/src/configuration/CallCost.cpp @@ -0,0 +1,95 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "CallCost.h" + +#include +#include + + +using namespace governikus; + +namespace +{ +inline double getValue(const QJsonValue& pJson, const char* pSection, const char* pSubSection) +{ + return pJson.toObject()[QLatin1String(pSection)].toObject()[QLatin1String(pSubSection)].toDouble(); +} + + +} + +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()[QLatin1String("free-seconds")].toInt()) + , mLandlineCentsPerMinute(getValue(pJson, "landline", "per-minute")) + , mLandlineCentsPerCall(getValue(pJson, "landline", "per-call")) + , mMobileCentsPerMinute(getValue(pJson, "mobile", "per-minute")) + , mMobileCentsPerCall(getValue(pJson, "mobile", "per-call")) +{ +} + + +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/configuration/CallCost.h b/src/configuration/CallCost.h new file mode 100644 index 0000000..c7229d5 --- /dev/null +++ b/src/configuration/CallCost.h @@ -0,0 +1,54 @@ +/*! + * \brief Phone call cost representation + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#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/configuration/LanguageString.cpp b/src/configuration/LanguageString.cpp new file mode 100644 index 0000000..94620ff --- /dev/null +++ b/src/configuration/LanguageString.cpp @@ -0,0 +1,98 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "LanguageString.h" + +#include +#include + +using namespace governikus; + + +LanguageString::LanguageString(const QJsonValue& pJson) +{ + if (!pJson.isObject()) + { + return; + } + + const QJsonObject& object = pJson.toObject(); + const auto& iterEnd = object.constEnd(); + for (auto iter = object.constBegin(); iter != iterEnd; ++iter) + { + mStrings[iter.key()] = iter.value().toString(); + } +} + + +LanguageString::LanguageString(const QMap& pInput) + : mStrings(pInput) +{ +} + + +LanguageString::LanguageString(const QString& pString, const QLocale& pLocale) +{ + mStrings[pLocale.name()] = pString; +} + + +QString LanguageString::toString() const +{ + QString result = toString(LanguageLoader::getInstance().getUsedLocale()); + if (!result.isEmpty()) + { + return result; + } + + result = toString(LanguageLoader::getInstance().getFallbackLanguage()); + if (!result.isEmpty()) + { + return result; + } + + return mStrings[QString()]; +} + + +QString LanguageString::toString(const QLocale& pLocale) const +{ + QString result = mStrings[pLocale.name()]; + if (!result.isEmpty()) + { + return result; + } + + result = mStrings[pLocale.bcp47Name()]; + if (!result.isEmpty()) + { + return result; + } + + return QString(); +} + + +bool LanguageString::isEmpty() const +{ + return mStrings.isEmpty(); +} + + +QMap::const_iterator LanguageString::begin() const +{ + return mStrings.begin(); +} + + +QMap::const_iterator LanguageString::end() const +{ + return mStrings.end(); +} + + +LanguageString::operator QString() const +{ + return toString(); +} diff --git a/src/configuration/LanguageString.h b/src/configuration/LanguageString.h new file mode 100644 index 0000000..2eabac7 --- /dev/null +++ b/src/configuration/LanguageString.h @@ -0,0 +1,46 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "LanguageLoader.h" + +#include +#include +#include + + +namespace governikus +{ + +class LanguageString +{ + friend inline bool operator==(const LanguageString& pLeft, const LanguageString& pRight); + + private: + QMap mStrings; + + QString toString(const QLocale& pLocale) const; + + public: + LanguageString(const QJsonValue& pJson); + LanguageString(const QMap& pInput); + LanguageString(const QString& pString, const QLocale& pLocale = LanguageLoader::getInstance().getUsedLocale()); + + + bool isEmpty() const; + QString toString() const; + operator QString() const; + + QMap::const_iterator begin() const; + QMap::const_iterator end() const; +}; + +inline bool operator==(const LanguageString& pLeft, const LanguageString& pRight) +{ + return pLeft.mStrings == pRight.mStrings; +} + + +} /* namespace governikus */ diff --git a/src/configuration/ProviderConfiguration.cpp b/src/configuration/ProviderConfiguration.cpp new file mode 100644 index 0000000..27e7e4a --- /dev/null +++ b/src/configuration/ProviderConfiguration.cpp @@ -0,0 +1,124 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderConfiguration.h" + +#include "Env.h" +#include "FileProvider.h" +#include "ProviderConfigurationParser.h" +#include "SingletonHelper.h" + +#include +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(configuration) + + +defineSingleton(ProviderConfiguration) + + +bool ProviderConfiguration::parseProviderConfiguration() +{ + const QString& path = mUpdatableFile->lookupPath(); + if (!QFile::exists(path)) + { + qCCritical(configuration) << "ProviderConfiguration file not found"; + return false; + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qCCritical(configuration) << "Wasn't able to open ProviderConfiguration file"; + return false; + } + QByteArray configFileContent = configFile.readAll(); + + const auto& callCosts = ProviderConfigurationParser::parseCallCosts(configFileContent); + if (callCosts.isEmpty()) + { + qCCritical(configuration) << "Parse error while reading ProviderConfiguration"; + return false; + } + + const auto& providerConfigurationInfos = ProviderConfigurationParser::parseProvider(configFileContent); + if (providerConfigurationInfos.isEmpty()) + { + qCCritical(configuration) << "Parse error while reading ProviderConfiguration"; + return false; + } + + mCallCosts = callCosts; + mProviderConfigurationInfos = providerConfigurationInfos; + return true; +} + + +void ProviderConfiguration::onFileUpdated() +{ + if (parseProviderConfiguration()) + { + for (const ProviderConfigurationInfo& info : qAsConst(mProviderConfigurationInfos)) + { + info.getIcon()->markDirty(); + info.getImage()->markDirty(); + } + + Q_EMIT fireUpdated(); + } +} + + +ProviderConfiguration::ProviderConfiguration() + : mUpdatableFile(Env::getSingleton()->getFile(QString(), QStringLiteral("supported-providers.json"))) + , mProviderConfigurationInfos() + , mCallCosts() +{ + connect(mUpdatableFile.data(), &UpdatableFile::fireUpdated, this, &ProviderConfiguration::onFileUpdated); + parseProviderConfiguration(); +} + + +ProviderConfiguration& ProviderConfiguration::getInstance() +{ + return *Instance; +} + + +void ProviderConfiguration::update() +{ + mUpdatableFile->update(); +} + + +const QVector& ProviderConfiguration::getProviderConfigurationInfos() const +{ + return mProviderConfigurationInfos; +} + + +const CallCost ProviderConfiguration::getCallCost(const ProviderConfigurationInfo& pProvider) const +{ + QString standardisedPhoneNumber = pProvider.getPhone(); + standardisedPhoneNumber = standardisedPhoneNumber.remove(QStringLiteral("+49")); + standardisedPhoneNumber = standardisedPhoneNumber.remove(QRegularExpression(QStringLiteral("[^\\d]"))); + + if (!standardisedPhoneNumber.isEmpty()) + { + const auto& prefixes = mCallCosts.keys(); + for (const auto& prefix : prefixes) + { + if (standardisedPhoneNumber.startsWith(prefix)) + { + return mCallCosts[prefix]; + } + } + } + return CallCost(); +} diff --git a/src/configuration/ProviderConfiguration.h b/src/configuration/ProviderConfiguration.h new file mode 100644 index 0000000..6b22d43 --- /dev/null +++ b/src/configuration/ProviderConfiguration.h @@ -0,0 +1,54 @@ +/*! + * \brief Provides information of provider json. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "CallCost.h" +#include "ProviderConfigurationInfo.h" +#include "UpdatableFile.h" + +#include +#include +#include +#include + + +namespace governikus +{ + + +class ProviderConfiguration + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mUpdatableFile; + QVector mProviderConfigurationInfos; + QMap mCallCosts; + + bool parseProviderConfiguration(); + + private Q_SLOTS: + void onFileUpdated(); + + protected: + ProviderConfiguration(); + virtual ~ProviderConfiguration() = default; + + public: + static ProviderConfiguration& getInstance(); + + void update(); + const QVector& getProviderConfigurationInfos() const; + const CallCost getCallCost(const ProviderConfigurationInfo& pProvider) const; + + Q_SIGNALS: + void fireUpdated(); +}; + + +} /* namespace governikus */ diff --git a/src/configuration/ProviderConfigurationInfo.cpp b/src/configuration/ProviderConfigurationInfo.cpp new file mode 100644 index 0000000..5cc44db --- /dev/null +++ b/src/configuration/ProviderConfigurationInfo.cpp @@ -0,0 +1,168 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderConfigurationInfo.h" + +#include "Env.h" +#include "FileProvider.h" + +#include + + +using namespace governikus; + + +QString ProviderConfigurationInfo::getDefaultFile(const QString& pSuffix) const +{ +#ifdef Q_OS_IOS + const QString platform; +#else + const QString platform = QStringLiteral("+android/"); +#endif + const QString category = d->mCategory.isEmpty() ? QStringLiteral("general") : d->mCategory; + return QStringLiteral(":/images/provider/categoryIcons/%1%2%3.svg").arg(platform, category, pSuffix); +} + + +ProviderConfigurationInfo::ProviderConfigurationInfo(const LanguageString& pShortName, + const LanguageString& pLongName, + const LanguageString& pShortDescription, + const LanguageString& pLongDescription, + const QString& pAddress, + const QString& pHomepage, + const QString& pCategory, + const QString& pPhone, + const QString& pEmail, + const QString& pPostalAddress, + const QString& pIcon, + const QString& pImage, + const QString& pTcTokenUrl, + const QString& pClientUrl, + const QStringList& pSubjectUrls) + : d(new InternalInfo(pShortName, pLongName, pShortDescription, pLongDescription, pAddress, pHomepage, + pCategory, pPhone, pEmail, pPostalAddress, pIcon, pImage, pTcTokenUrl, pClientUrl, pSubjectUrls)) +{ +} + + +ProviderConfigurationInfo::~ProviderConfigurationInfo() +{ +} + + +void ProviderConfigurationInfo::setTcTokenUrl(const QString& pTcTokenUrl) +{ + d = new InternalInfo(d->mShortName, d->mLongName, d->mShortDescription, d->mLongDescription, d->mAddress, d->mHomepage, + d->mCategory, d->mPhone, d->mEmail, d->mPostalAddress, d->mIcon, d->mImage, pTcTokenUrl, d->mClientUrl, d->mSubjectUrls); +} + + +bool ProviderConfigurationInfo::operator ==(const ProviderConfigurationInfo& pOther) const +{ + return *d == *pOther.d; +} + + +const LanguageString& ProviderConfigurationInfo::getShortName() const +{ + return d->mShortName; +} + + +const LanguageString& ProviderConfigurationInfo::getLongName() const +{ + return d->mLongName; +} + + +const LanguageString& ProviderConfigurationInfo::getShortDescription() const +{ + return d->mShortDescription; +} + + +const LanguageString& ProviderConfigurationInfo::getLongDescription() const +{ + return d->mLongDescription; +} + + +const QString& ProviderConfigurationInfo::getAddress() const +{ + return d->mAddress; +} + + +QString ProviderConfigurationInfo::getAddressDomain() const +{ + return QUrl::fromUserInput(d->mAddress).host(); +} + + +const QString& ProviderConfigurationInfo::getHomepage() const +{ + return d->mHomepage; +} + + +QString ProviderConfigurationInfo::getHomepageBase() const +{ + return QUrl::fromUserInput(d->mHomepage).host(); +} + + +const QString& ProviderConfigurationInfo::getCategory() const +{ + return d->mCategory; +} + + +const QString& ProviderConfigurationInfo::getPhone() const +{ + return d->mPhone; +} + + +const QString& ProviderConfigurationInfo::getEMail() const +{ + return d->mEmail; +} + + +const QString& ProviderConfigurationInfo::getPostalAddress() const +{ + return d->mPostalAddress; +} + + +QSharedPointer ProviderConfigurationInfo::getIcon() const +{ + const QString defaultFile = getDefaultFile(QStringLiteral("_button")); + return Env::getSingleton()->getFile(QStringLiteral("provider"), d->mIcon, defaultFile); +} + + +QSharedPointer ProviderConfigurationInfo::getImage() const +{ + const QString defaultFile = getDefaultFile(QStringLiteral("_bg")); + return Env::getSingleton()->getFile(QStringLiteral("provider"), d->mImage, defaultFile); +} + + +QUrl ProviderConfigurationInfo::getTcTokenUrl() const +{ + return QUrl::fromUserInput(d->mTcTokenUrl); +} + + +QUrl ProviderConfigurationInfo::getClientUrl() const +{ + return QUrl::fromUserInput(d->mClientUrl); +} + + +const QStringList& ProviderConfigurationInfo::getSubjectUrls() const +{ + return d->mSubjectUrls; +} diff --git a/src/configuration/ProviderConfigurationInfo.h b/src/configuration/ProviderConfigurationInfo.h new file mode 100644 index 0000000..41e5fa2 --- /dev/null +++ b/src/configuration/ProviderConfigurationInfo.h @@ -0,0 +1,147 @@ +/*! + * \brief Class to provide information about providers. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "LanguageString.h" +#include "UpdatableFile.h" + +#include +#include +#include +#include +#include + + +namespace governikus +{ + + +class ProviderConfigurationInfo +{ + private: + class InternalInfo + : public QSharedData + { + public: + const LanguageString mShortName; + const LanguageString mLongName; + const LanguageString mShortDescription; + const LanguageString mLongDescription; + const QString mAddress; + const QString mHomepage; + const QString mCategory; + const QString mPhone; + const QString mEmail; + const QString mPostalAddress; + const QString mIcon; + const QString mImage; + const QString mTcTokenUrl; + const QString mClientUrl; + const QStringList mSubjectUrls; + + InternalInfo(const LanguageString& pShortName, + const LanguageString& pLongName, + const LanguageString& pShortDescription, + const LanguageString& pLongDescription, + const QString& pAddress, + const QString& pHomepage, + const QString& pCategory, + const QString& pPhone, + const QString& pEmail, + const QString& pPostalAddress, + const QString& pIcon, + const QString& pImage, + const QString& pTcTokenUrl, + const QString& pClientUrl, + const QStringList& pSubjectUrls = QStringList()) + : mShortName(pShortName) + , mLongName(pLongName) + , mShortDescription(pShortDescription) + , mLongDescription(pLongDescription) + , mAddress(pAddress) + , mHomepage(pHomepage) + , mCategory(pCategory) + , mPhone(pPhone) + , mEmail(pEmail) + , mPostalAddress(pPostalAddress) + , mIcon(pIcon) + , mImage(pImage) + , mTcTokenUrl(pTcTokenUrl) + , mClientUrl(pClientUrl) + , mSubjectUrls(pSubjectUrls) + { + } + + + bool operator ==(const InternalInfo& pOther) const + { + return mShortName == pOther.mShortName || + mLongName == pOther.mLongName || + mShortDescription == pOther.mShortDescription || + mLongDescription == pOther.mLongDescription || + mAddress == pOther.mAddress || + mHomepage == pOther.mHomepage || + mCategory == pOther.mCategory || + mPhone == pOther.mPhone || + mEmail == pOther.mEmail || + mPostalAddress == pOther.mPostalAddress || + mIcon == pOther.mIcon || + mImage == pOther.mImage || + mTcTokenUrl == pOther.mTcTokenUrl || + mClientUrl == pOther.mClientUrl; + } + + + }; + + QSharedDataPointer d; + + QString getDefaultFile(const QString& pSuffix) const; + + public: + ProviderConfigurationInfo(const LanguageString& pShortName = QString(), + const LanguageString& pLongName = QString(), + const LanguageString& pShortDescription = QString(), + const LanguageString& pLongDescription = QString(), + const QString& pAddress = QString(), + const QString& pHomepage = QString(), + const QString& pCategory = QString(), + const QString& pPhone = QString(), + const QString& pEmail = QString(), + const QString& pPostalAddress = QString(), + const QString& pIcon = QString(), + const QString& pImage = QString(), + const QString& pTcTokenUrl = QString(), + const QString& pClientUrl = QString(), + const QStringList& pSubjectUrls = QStringList()); + virtual ~ProviderConfigurationInfo(); + + void setTcTokenUrl(const QString& pTcTokenUrl); + + bool operator ==(const ProviderConfigurationInfo& pOther) const; + + const LanguageString& getShortName() const; + const LanguageString& getLongName() const; + const LanguageString& getShortDescription() const; + const LanguageString& getLongDescription() const; + const QString& getAddress() const; + QString getAddressDomain() const; + const QString& getHomepage() const; + QString getHomepageBase() const; + const QString& getCategory() const; + const QString& getPhone() const; + const QString& getEMail() const; + const QString& getPostalAddress() const; + QSharedPointer getIcon() const; + QSharedPointer getImage() const; + QUrl getTcTokenUrl() const; + QUrl getClientUrl() const; + const QStringList& getSubjectUrls() const; +}; + + +} /* namespace governikus */ diff --git a/src/configuration/ProviderConfigurationParser.cpp b/src/configuration/ProviderConfigurationParser.cpp new file mode 100644 index 0000000..2a4fcd0 --- /dev/null +++ b/src/configuration/ProviderConfigurationParser.cpp @@ -0,0 +1,146 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderConfigurationParser.h" + +#include "LanguageString.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(update) + + +using namespace governikus; + +namespace +{ + +inline QLatin1String getCurrentOS() +{ +#if defined(Q_OS_WIN) + return QLatin1String("win"); + +#elif defined(Q_OS_MACOS) + return QLatin1String("mac"); + +#elif defined(Q_OS_IOS) + return QLatin1String("ios"); + +#elif defined(Q_OS_ANDROID) + return QLatin1String("android"); + +#elif defined(Q_OS_LINUX) + return QLatin1String("linux"); + +#elif defined(Q_OS_BSD4) + return QLatin1String("bsd"); + +#else +#error OS not implemented +#endif +} + + +} + +bool ProviderConfigurationParser::isExcludedPlatform(const QJsonArray& pExcludedArray, QLatin1String pCurrentOS) +{ + const QLatin1String osType = pCurrentOS == QLatin1String("ios") || pCurrentOS == QLatin1String("android") + ? QLatin1String("mobile") + : QLatin1String("desktop"); + + for (const auto& entry : pExcludedArray) + { + const QString& value = entry.toString().toLower(); + if (value == pCurrentOS || value == osType) + { + return true; + } + } + return false; +} + + +QVector ProviderConfigurationParser::parseProvider(const QByteArray& pData, QLatin1String pCurrentOS) +{ + QJsonParseError jsonError; + const auto& json = QJsonDocument::fromJson(pData, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + qCCritical(update) << "Cannot parse providers:" << jsonError.errorString(); + return QVector(); + } + QJsonObject doc = json.object(); + + const QJsonArray& array = doc[QLatin1String("provider")].toArray(); + QVector providers; + providers.reserve(array.size()); + for (const auto& entry : array) + { + const QJsonObject prov = entry.toObject(); + + if (isExcludedPlatform(prov[QLatin1String("exclude")].toArray(), pCurrentOS)) + { + continue; + } + + const QString postalAddressCamel = prov[QLatin1String("postalAddress")].toString(); + const QString postalAddressLower = prov[QLatin1String("postaladdress")].toString(); + providers << ProviderConfigurationInfo( + LanguageString(prov[QLatin1String("shortName")]), + LanguageString(prov[QLatin1String("longName")]), + LanguageString(prov[QLatin1String("shortDescription")]), + LanguageString(prov[QLatin1String("longDescription")]), + prov[QLatin1String("address")].toString(), + prov[QLatin1String("homepage")].toString(), + prov[QLatin1String("category")].toString(), + prov[QLatin1String("phone")].toString(), + prov[QLatin1String("email")].toString(), + postalAddressCamel.isEmpty() ? postalAddressLower : postalAddressCamel, // Accept old format + prov[QLatin1String("icon")].toString(), + prov[QLatin1String("image")].toString(), + prov[QLatin1String("tcTokenUrl")].toString(), + prov[QLatin1String("clientUrl")].toString(), + prov[QLatin1String("subjectUrls")].toVariant().toStringList()); + } + + return providers; +} + + +QMap ProviderConfigurationParser::parseCallCosts(const QByteArray& pData) +{ + QJsonParseError jsonError; + const auto& json = QJsonDocument::fromJson(pData, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + qCCritical(update) << "Cannot parse call costs:" << jsonError.errorString(); + return QMap(); + } + QJsonObject doc = json.object(); + + QMap callCosts; + const auto& callCostArray = doc[QLatin1String("callcosts")].toArray(); + for (const auto& callCostElem : callCostArray) + { + const auto cost = CallCost(callCostElem); + const auto& prefixArray = callCostElem.toObject()[QLatin1String("prefixes")].toArray(); + for (const auto& prefixElem : prefixArray) + { + const auto& prefix = prefixElem.toString(); + callCosts.insert(prefix, cost); + } + } + + return callCosts; +} + + +QVector ProviderConfigurationParser::parseProvider(const QByteArray& pData) +{ + return parseProvider(pData, getCurrentOS()); +} diff --git a/src/configuration/ProviderConfigurationParser.h b/src/configuration/ProviderConfigurationParser.h new file mode 100644 index 0000000..fa16a31 --- /dev/null +++ b/src/configuration/ProviderConfigurationParser.h @@ -0,0 +1,36 @@ +/*! + * \brief Parser for provider configuration files + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "CallCost.h" +#include "ProviderConfigurationInfo.h" + +#include +#include +#include + +class test_ProviderConfigurationParser; + +namespace governikus +{ +class ProviderConfigurationParser +{ + private: + friend class ::test_ProviderConfigurationParser; + static bool isExcludedPlatform(const QJsonArray& pExcludedArray, QLatin1String pCurrentOS); + static QVector parseProvider(const QByteArray& pData, QLatin1String pCurrentOS); + + ProviderConfigurationParser() = delete; + ~ProviderConfigurationParser() = delete; + + public: + static QMap parseCallCosts(const QByteArray& pData); + static QVector parseProvider(const QByteArray& pData); +}; + + +} /* namespace governikus */ diff --git a/src/configuration/ReaderConfiguration.cpp b/src/configuration/ReaderConfiguration.cpp new file mode 100644 index 0000000..9f5ff80 --- /dev/null +++ b/src/configuration/ReaderConfiguration.cpp @@ -0,0 +1,154 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfiguration.h" + +#include "Env.h" +#include "FileDestination.h" +#include "FileProvider.h" +#include "FuncUtils.h" +#include "ReaderConfigurationParser.h" +#include "SingletonHelper.h" + +#include +#include +#include + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(configuration) + + +defineSingleton(ReaderConfiguration) + + +bool ReaderConfiguration::parseReaderConfiguration() +{ + const QString& path = mUpdatableFile->lookupPath(); + if (!QFile::exists(path)) + { + qCCritical(configuration) << "ReaderConfiguration file not found"; + return false; + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qCCritical(configuration) << "Wasn't able to open ReaderConfiguration file"; + return false; + } + + const auto& readerConfigurationInfos = ReaderConfigurationParser::parse(configFile.readAll()); + if (readerConfigurationInfos.isEmpty()) + { + qCCritical(configuration) << "Parse error while reading ReaderConfiguration"; + return false; + } + + mReaderConfigurationInfos = readerConfigurationInfos; + return true; +} + + +void ReaderConfiguration::onFileUpdated() +{ + if (parseReaderConfiguration()) + { + for (const ReaderConfigurationInfo& info : qAsConst(mReaderConfigurationInfos)) + { + info.getIcon()->markDirty(); + info.getIconWithNPA()->markDirty(); + } + + Q_EMIT fireUpdated(); + } +} + + +ReaderConfiguration::ReaderConfiguration() + : mUpdatableFile(Env::getSingleton()->getFile(QString(), QStringLiteral("supported-readers.json"))) + , mReaderConfigurationInfos() +{ + connect(mUpdatableFile.data(), &UpdatableFile::fireUpdated, this, &ReaderConfiguration::onFileUpdated); + parseReaderConfiguration(); +} + + +ReaderConfiguration& ReaderConfiguration::getInstance() +{ + return *Instance; +} + + +QString ReaderConfiguration::getNoReaderFoundIconPath() +{ + return QStringLiteral(":/images/reader/default_no_reader.png"); +} + + +QString ReaderConfiguration::getMultipleReaderIconPath() +{ + return QStringLiteral(":/images/reader/default_more_reader.png"); +} + + +void ReaderConfiguration::update() +{ + mUpdatableFile->update(); +} + + +const ReaderConfigurationInfo ReaderConfiguration::getRemoteReaderConfigurationInfo() const +{ + return getReaderConfigurationInfoById(UsbId()); +} + + +const QVector& ReaderConfiguration::getReaderConfigurationInfos() const +{ + return mReaderConfigurationInfos; +} + + +const QVector ReaderConfiguration::getSupportedReaderConfigurationInfos() const +{ + return filter([](const ReaderConfigurationInfo& i){ + return !i.getUrl().isEmpty(); + }, qAsConst(mReaderConfigurationInfos)); +} + + +#ifndef QT_NO_DEBUG +ReaderConfigurationInfo ReaderConfiguration::getReaderConfigurationInfo(const QString& pReaderName) const +{ + for (const auto& info : qAsConst(mReaderConfigurationInfos)) + { + const QString& pattern = info.getPattern(); + const QRegularExpression expression(pattern.isEmpty() ? info.getName() : pattern); + if (pReaderName.contains(expression)) + { + return info; + } + } + + return ReaderConfigurationInfo(pReaderName); +} + + +#endif + + +ReaderConfigurationInfo ReaderConfiguration::getReaderConfigurationInfoById(const UsbId& pId) const +{ + for (const auto& info : qAsConst(mReaderConfigurationInfos)) + { + if (pId.getVendorId() == info.getVendorId() && pId.getProductId() == info.getProductId()) + { + return info; + } + } + + return ReaderConfigurationInfo(); +} diff --git a/src/configuration/ReaderConfiguration.h b/src/configuration/ReaderConfiguration.h new file mode 100644 index 0000000..8546ba6 --- /dev/null +++ b/src/configuration/ReaderConfiguration.h @@ -0,0 +1,64 @@ +/*! + * \brief Class to store configuration data about available card readers. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "ReaderConfigurationInfo.h" +#include "UpdatableFile.h" +#include "UsbId.h" + +#include +#include +#include +#include + + +namespace governikus +{ +class MockReaderConfiguration; + +class ReaderConfiguration + : public QObject +{ + Q_OBJECT + + private: + friend class MockReaderConfiguration; + + const QSharedPointer mUpdatableFile; + QVector mReaderConfigurationInfos; + + bool parseReaderConfiguration(); + + private Q_SLOTS: + void onFileUpdated(); + + protected: + ReaderConfiguration(); + virtual ~ReaderConfiguration() = default; + + public: + static ReaderConfiguration& getInstance(); + static QString getNoReaderFoundIconPath(); + static QString getMultipleReaderIconPath(); + + void update(); + const ReaderConfigurationInfo getRemoteReaderConfigurationInfo() const; + const QVector& getReaderConfigurationInfos() const; + const QVector getSupportedReaderConfigurationInfos() const; + +#ifndef QT_NO_DEBUG + // This function is only for use in testcases + ReaderConfigurationInfo getReaderConfigurationInfo(const QString& pReaderName) const; +#endif + ReaderConfigurationInfo getReaderConfigurationInfoById(const UsbId& pId) const; + + Q_SIGNALS: + void fireUpdated(); +}; + +} /* namespace governikus */ diff --git a/src/configuration/ReaderConfigurationInfo.cpp b/src/configuration/ReaderConfigurationInfo.cpp new file mode 100644 index 0000000..f1caa0f --- /dev/null +++ b/src/configuration/ReaderConfigurationInfo.cpp @@ -0,0 +1,88 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfigurationInfo.h" + +#include "Env.h" +#include "FileProvider.h" + +using namespace governikus; + + +ReaderConfigurationInfo::ReaderConfigurationInfo() + : ReaderConfigurationInfo(tr("Unknown reader")) +{ +} + + +ReaderConfigurationInfo::ReaderConfigurationInfo(const QString& pReaderName) + : d(new InternalInfo(false, 0, 0, pReaderName, QString(), QString(), QStringLiteral("default_reader.png"), QStringLiteral("default_reader_mit_ausweis.png"))) +{ +} + + +ReaderConfigurationInfo::ReaderConfigurationInfo(uint pVendorId, uint pProductId, + const QString& pName, const QString& pUrl, const QString& pPattern, const QString& pIcon, const QString& pIconWithNPA) + : d(new InternalInfo(true, pVendorId, pProductId, pName, pUrl, pPattern, pIcon, pIconWithNPA)) +{ +} + + +ReaderConfigurationInfo::~ReaderConfigurationInfo() +{ +} + + +bool ReaderConfigurationInfo::operator ==(const ReaderConfigurationInfo& pOther) const +{ + return *d == *pOther.d; +} + + +bool ReaderConfigurationInfo::isKnownReader() const +{ + return d->mKnown; +} + + +uint ReaderConfigurationInfo::getVendorId() const +{ + return d->mVendorId; +} + + +uint ReaderConfigurationInfo::getProductId() const +{ + return d->mProductId; +} + + +const QString& ReaderConfigurationInfo::getName() const +{ + return d->mName; +} + + +const QString& ReaderConfigurationInfo::getUrl() const +{ + return d->mUrl; +} + + +const QString& ReaderConfigurationInfo::getPattern() const +{ + return d->mPattern; +} + + +QSharedPointer ReaderConfigurationInfo::getIcon() const +{ + return Env::getSingleton()->getFile(QStringLiteral("reader"), d->mIcon, QStringLiteral(":/images/reader/default_reader.png")); +} + + +QSharedPointer ReaderConfigurationInfo::getIconWithNPA() const +{ + return Env::getSingleton()->getFile(QStringLiteral("reader"), d->mIconWithNPA, QStringLiteral(":/images/reader/default_reader_mit_ausweis.png")); +} diff --git a/src/configuration/ReaderConfigurationInfo.h b/src/configuration/ReaderConfigurationInfo.h new file mode 100644 index 0000000..4d5147b --- /dev/null +++ b/src/configuration/ReaderConfigurationInfo.h @@ -0,0 +1,97 @@ +/*! + * \brief Class to provide information about available card readers. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "UpdatableFile.h" + +#include +#include +#include + + +namespace governikus +{ +class ReaderConfigurationInfo +{ + Q_DECLARE_TR_FUNCTIONS(ReaderConfigurationInfo) + + private: + class InternalInfo + : public QSharedData + { + public: + const bool mKnown; + const uint mVendorId; + const uint mProductId; + const QString mName; + const QString mUrl; + const QString mPattern; + const QString mIcon; + const QString mIconWithNPA; + + + InternalInfo(bool pKnown, uint pVendorId, uint pProductId, const QString& pName, const QString& pUrl, + const QString& pPattern, const QString& pIcon, const QString& pIconWithNPA) + : mKnown(pKnown) + , mVendorId(pVendorId) + , mProductId(pProductId) + , mName(pName) + , mUrl(pUrl) + , mPattern(pPattern) + , mIcon(pIcon) + , mIconWithNPA(pIconWithNPA) + { + + } + + + bool operator ==(const InternalInfo& pOther) const + { + return !(mKnown != pOther.mKnown || + mVendorId != pOther.mVendorId || + mProductId != pOther.mProductId || + mName != pOther.mName || + mUrl != pOther.mUrl || + mPattern != pOther.mPattern || + mIcon != pOther.mIcon || + mIconWithNPA != pOther.mIconWithNPA); + } + + + }; + + QSharedDataPointer d; + + public: + ReaderConfigurationInfo(); + ReaderConfigurationInfo(const QString& pReaderName); + ReaderConfigurationInfo(uint pVendorId, uint pProductId, + const QString& pName, const QString& pUrl, const QString& pPattern, + const QString& pIcon, const QString& pIconWithNPA); + + virtual ~ReaderConfigurationInfo(); + + bool operator ==(const ReaderConfigurationInfo& pOther) const; + + bool isKnownReader() const; + uint getVendorId() const; + uint getProductId() const; + const QString& getName() const; + const QString& getUrl() const; + const QString& getPattern() const; + QSharedPointer getIcon() const; + QSharedPointer getIconWithNPA() const; +}; + + +inline uint qHash(const ReaderConfigurationInfo& info) +{ + return qHash(info.getName()); +} + + +} /* namespace governikus */ diff --git a/src/configuration/ReaderConfigurationParser.cpp b/src/configuration/ReaderConfigurationParser.cpp new file mode 100644 index 0000000..3cc766d --- /dev/null +++ b/src/configuration/ReaderConfigurationParser.cpp @@ -0,0 +1,262 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfigurationParser.h" + +#include +#include +#include +#include +#include + + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(card_drivers) + + +ReaderConfigurationParser::EntryParser::EntryParser(const QJsonValue& pJsonValue) + : mJsonValue(pJsonValue) +{ +} + + +ReaderConfigurationParser::EntryParser::~EntryParser() +{ +} + + +QString ReaderConfigurationParser::EntryParser::getDriverUrl(const QJsonObject& pObject) const +{ + const QJsonValue driversValue = pObject.value(QLatin1String("Drivers")); + if (!driversValue.isArray()) + { + qCWarning(card_drivers) << "The value of 'Drivers' must be an array"; + return QString(); + } + + const QJsonArray& driversArray = driversValue.toArray(); + for (const auto& entry : driversArray) + { + const QJsonObject& obj = entry.toObject(); + if (obj.isEmpty()) + { + qCWarning(card_drivers) << "Drivers entry must be a valid object"; + return QString(); + } + + const QJsonValue& platforms = obj.value(QLatin1String("Platforms")); + if (!platforms.isArray()) + { + qCWarning(card_drivers) << "Invalid or missing Platforms tag"; + return QString(); + } + + const QString& url = obj.value(QLatin1String("URL")).toString(); + if (url.isEmpty()) + { + qCWarning(card_drivers) << "Invalid or missing URL tag"; + return QString(); + } + + if (matchPlatform(platforms.toArray())) + { + return url; + } + } + + // No URL for this platform found, but entry is syntactically correct: + // return empty non-null string. + return QStringLiteral(""); +} + + +bool ReaderConfigurationParser::EntryParser::matchPlatform(const QJsonArray& pPlatforms, const QOperatingSystemVersion& pCurrentVersion) const +{ + QString currentOS; + switch (pCurrentVersion.type()) + { + case QOperatingSystemVersion::Windows: + currentOS = QStringLiteral("win"); + break; + + case QOperatingSystemVersion::MacOS: + currentOS = QStringLiteral("mac"); + break; + + default: + currentOS = QStringLiteral("unknown"); + } + + const auto& parseSystemVersion = [&pCurrentVersion](const QString& pVersion) -> QOperatingSystemVersion { + if (pVersion.isEmpty()) + { + return pCurrentVersion; + } + + const auto& number = QVersionNumber::fromString(pVersion); + const auto minor = number.segmentCount() > 1 ? number.minorVersion() : -1; + const auto micro = number.segmentCount() > 2 ? number.microVersion() : -1; + return QOperatingSystemVersion(pCurrentVersion.type(), number.majorVersion(), minor, micro); + }; + + for (const auto& entry : pPlatforms) + { + const auto& obj = entry.toObject(); + if (obj.value(QLatin1String("os")).toString() == currentOS) + { + const auto& min = obj.value(QLatin1String("min")).toString(); + const auto& max = obj.value(QLatin1String("max")).toString(); + + if (pCurrentVersion >= parseSystemVersion(min) && pCurrentVersion <= parseSystemVersion(max)) + { + return true; + } + } + } + + return false; +} + + +ReaderConfigurationInfo ReaderConfigurationParser::EntryParser::parse() const +{ + if (!mJsonValue.isObject()) + { + return fail(QStringLiteral("Cannot parse Json value: object expected")); + } + + const QJsonObject& object = mJsonValue.toObject(); + + bool parseOk = false; + const uint vendorId = object.value(QLatin1String("VendorId")).toString().toUInt(&parseOk, 16); + if (!parseOk) + { + return fail(QStringLiteral("Invalid or missing vendor id")); + } + + const uint productId = object.value(QLatin1String("ProductId")).toString().toUInt(&parseOk, 16); + if (!parseOk) + { + return fail(QStringLiteral("Invalid or missing product id")); + } + + const QString& name = object.value(QLatin1String("Name")).toString(); + if (name.isEmpty()) + { + return fail(QStringLiteral("Invalid or missing name")); + } + + const QString& url = getDriverUrl(object); + if (url.isNull()) + { + return fail(QStringLiteral("Invalid driver URL entry")); + } + + // If Pattern is missing or empty => use name (exact match). + const QString& pattern = object.value(QLatin1String("Pattern")).toString(); + + const QString& icon = object.value(QLatin1String("Icon")).toString(); + const QString& iconWithNPA = object.value(QLatin1String("IconWithNPA")).toString(); + + return ReaderConfigurationInfo(vendorId, productId, name, url, pattern, icon, iconWithNPA); +} + + +ReaderConfigurationInfo ReaderConfigurationParser::EntryParser::fail(const QString& pLogMessage) const +{ + qCWarning(card_drivers) << pLogMessage; + + return ReaderConfigurationInfo(); +} + + +QVector ReaderConfigurationParser::parse(const QByteArray& pData) +{ + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(pData, &error); + if (error.error != QJsonParseError::NoError) + { + return fail(QStringLiteral("Json parsing failed. Error at offset %1: %2").arg(error.offset).arg(error.errorString())); + } + + const QJsonObject& rootObject = doc.object(); + if (rootObject.isEmpty()) + { + return fail(QStringLiteral("Expected object at top level")); + } + + if (!rootObject.contains(QStringLiteral("SupportedDevices"))) + { + return fail(QStringLiteral("Root object does not contain a property named 'SupportedDevices'")); + } + + // Root object OK. Look at child list. + const QJsonValue& devicesValue = rootObject.value(QStringLiteral("SupportedDevices")); + if (!devicesValue.isArray()) + { + return fail(QStringLiteral("The value of 'SupportedDevices' must be an array")); + } + + const QJsonArray& devicesArray = devicesValue.toArray(); + QVector infos; + for (const auto& entry : devicesArray) + { + auto info = EntryParser(entry).parse(); + if (info.isKnownReader()) + { + if (hasUniqueId(info, infos)) + { + infos += info; + } + else + { + const auto& json = QString::fromUtf8(QJsonDocument(entry.toObject()).toJson()); + return fail(QStringLiteral("Invalid reader configuration entry: '%1' duplicate reader information").arg(json)); + } + } + else + { + return fail(QStringLiteral("Invalid reader configuration entry: ") + QString::fromUtf8(QJsonDocument(entry.toObject()).toJson())); + } + } + + return infos; +} + + +QVector ReaderConfigurationParser::fail(const QString& pLogMessage) +{ + qCWarning(card_drivers) << pLogMessage; + return QVector(); +} + + +bool ReaderConfigurationParser::hasUniqueId(const ReaderConfigurationInfo& pInfo, const QVector& pInfos) +{ + const uint vendorId = pInfo.getVendorId(); + const uint productId = pInfo.getProductId(); + const QString& name = pInfo.getName(); + const QString& pattern = pInfo.getPattern(); + + for (const ReaderConfigurationInfo& info : pInfos) + { + if (vendorId > 0 && productId > 0 && vendorId == info.getVendorId() && productId == info.getProductId()) + { + return false; + } + + if (name == info.getName()) + { + return false; + } + + if (!pattern.isEmpty() && pattern == info.getPattern()) + { + return false; + } + } + + return true; +} diff --git a/src/configuration/ReaderConfigurationParser.h b/src/configuration/ReaderConfigurationParser.h new file mode 100644 index 0000000..14951de --- /dev/null +++ b/src/configuration/ReaderConfigurationParser.h @@ -0,0 +1,58 @@ +/*! + * \brief Parser for reader configuration files + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ReaderConfiguration.h" + +#include +#include + +class test_ReaderConfigurationEntryParser; + +namespace governikus +{ +class ReaderConfigurationParser +{ + private: + friend class ::test_ReaderConfigurationEntryParser; + + /** + * Parse a single entry of a reader configuration info list. + */ + class EntryParser + { + private: + friend class ::test_ReaderConfigurationEntryParser; + const QJsonValue mJsonValue; + + QString getDriverUrl(const QJsonObject& pObject) const; + bool matchPlatform(const QJsonArray& pPlatforms, const QOperatingSystemVersion& pCurrentVersion = QOperatingSystemVersion::current()) const; + ReaderConfigurationInfo fail(const QString& logMessage) const; + + public: + EntryParser(const QJsonValue& pJsonValue); + virtual ~EntryParser(); + + ReaderConfigurationInfo parse() const; + }; + + static QVector fail(const QString& logMessage); + static bool hasUniqueId(const ReaderConfigurationInfo& pInfo, const QVector& pInfos); + + ReaderConfigurationParser() = delete; + ~ReaderConfigurationParser() = delete; + + public: + /*! + * Parses the configuration data and returns ReaderConfiguration. + * In case of any errors, the QSharedPointer is empty. + */ + static QVector parse(const QByteArray& pData); +}; + + +} /* namespace governikus */ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7a80b4e..bb37cc2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,6 @@ ADD_PLATFORM_LIBRARY(AusweisAppCore) -TARGET_LINK_LIBRARIES(AusweisAppCore Qt5::Network Qt5::Xml AusweisAppCard AusweisAppGlobal AusweisAppActivation AusweisAppSettings AusweisAppNetwork AusweisAppServices) +TARGET_LINK_LIBRARIES(AusweisAppCore Qt5::Network Qt5::Xml AusweisAppCard AusweisAppGlobal AusweisAppActivation AusweisAppSettings AusweisAppNetwork AusweisAppRemoteDevice AusweisAppServices) IF(WIN32) TARGET_LINK_LIBRARIES(AusweisAppCore ${WIN_DEFAULT_LIBS}) diff --git a/src/core/CertificateChecker.cpp b/src/core/CertificateChecker.cpp index ea39e91..00034e8 100644 --- a/src/core/CertificateChecker.cpp +++ b/src/core/CertificateChecker.cpp @@ -1,110 +1,41 @@ /*! - * CertificateChecker.cpp - * - * \brief Contains the definition of the CertificateChecker methods. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CertificateChecker.h" -#include -#include +#include "AppSettings.h" +#include "paos/retrieve/DidAuthenticateEac1.h" +#include "TlsChecker.h" -#include -#include -#include -#include -#include +#include +#include +#include using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(developermode) -bool CertificateChecker::checkCertificate(const QSslCertificate& pCertificate, - QCryptographicHash::Algorithm pAlgorithm, - const QSet& pAcceptedCertificateHashes) + +CertificateChecker::CertificateStatus CertificateChecker::checkAndSaveCertificate(const QSslCertificate& pCertificate, + const QUrl& pUrl, + const QSharedPointer& pEAC1, + const QSharedPointer& pDvCvc, + const std::function& pSaveCertificateFunc) { - qDebug() << "Check certificate CN=" << pCertificate.subjectInfo(QSslCertificate::CommonName) << "SN=" << pCertificate.serialNumber(); - QString hash = QString::fromLatin1(pCertificate.digest(pAlgorithm).toHex()); - qDebug() << "Certificate hash(" << pAlgorithm << ")" << hash; - qDebug() << "Accepted certificate hashes" << pAcceptedCertificateHashes; - for (const auto& acceptedHash : pAcceptedCertificateHashes) - { - if (hash.compare(acceptedHash, Qt::CaseInsensitive) == 0) - { - return true; - } - } - - return false; -} - - -bool CertificateChecker::hasValidCertificateKeyLength(const QSslCertificate& pCertificate) -{ - auto keyLength = pCertificate.publicKey().length(); - auto keyAlgorithm = pCertificate.publicKey().algorithm(); - qDebug() << "Check certificate key of type" << CertificateChecker::toString(keyAlgorithm) << "and key size" << keyLength; - return isValidKeyLength(keyLength, keyAlgorithm, false); -} - - -bool CertificateChecker::hasValidEphemeralKeyLength(const QSslKey& pEphemeralServerKey) -{ - int keyLength = pEphemeralServerKey.length(); - QSsl::KeyAlgorithm keyAlgorithm = pEphemeralServerKey.algorithm(); - - if (keyAlgorithm == QSsl::Opaque) - { - // try do determine key algorithm and length - if (auto key = static_cast(pEphemeralServerKey.handle())) - { - keyLength = EVP_PKEY_bits(key); - switch (EVP_PKEY_type(key->type)) - { - case EVP_PKEY_RSA: - keyAlgorithm = QSsl::Rsa; - break; - - case EVP_PKEY_DSA: - /* fall through */ - case EVP_PKEY_DH: - keyAlgorithm = QSsl::Dsa; - break; - - case EVP_PKEY_EC: - keyAlgorithm = QSsl::Ec; - break; - } - } - } - - qDebug() << "Check ephemeral key of type" << CertificateChecker::toString(keyAlgorithm) << "and key size" << keyLength; - return isValidKeyLength(keyLength, keyAlgorithm, true); -} - - -CertificateChecker::CertificateStatus CertificateChecker::checkAndSaveCertificate(const QSslCertificate& pCertificate, const QUrl& pUrl, QSharedPointer pContext) -{ - Q_ASSERT(!pContext.isNull()); - - if (!hasValidCertificateKeyLength(pCertificate)) + if (!TlsChecker::hasValidCertificateKeyLength(pCertificate)) { return CertificateStatus::Unsupported_Algorithm_Or_Length; } - // 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 (pEAC1 && pDvCvc) { - if (auto certificateDescription = eac1->getCertificateDescription()) + if (auto certificateDescription = pEAC1->getCertificateDescription()) { const QSet certHashes = certificateDescription->getCommCertificates(); - QCryptographicHash::Algorithm hashAlgo = pContext->getDvCvc()->getBody().getHashAlgorithm(); - if (!checkCertificate(pCertificate, hashAlgo, certHashes)) + QCryptographicHash::Algorithm hashAlgo = pDvCvc->getBody().getHashAlgorithm(); + if (!TlsChecker::checkCertificate(pCertificate, hashAlgo, certHashes)) { auto hashError = QStringLiteral("hash of certificate not in certificate description"); @@ -121,50 +52,6 @@ CertificateChecker::CertificateStatus CertificateChecker::checkAndSaveCertificat } } - pContext->addCertificateData(pUrl, pCertificate); + pSaveCertificateFunc(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; -} - - -QString CertificateChecker::toString(QSsl::KeyAlgorithm pKeyAlgorithm) -{ - switch (pKeyAlgorithm) - { - case QSsl::KeyAlgorithm::Dsa: - return QStringLiteral("Dsa"); - - case QSsl::KeyAlgorithm::Rsa: - return QStringLiteral("Rsa"); - - case QSsl::KeyAlgorithm::Ec: - return QStringLiteral("Ec"); - - default: - return QStringLiteral("Unknown (%1)").arg(pKeyAlgorithm); - } -} diff --git a/src/core/CertificateChecker.h b/src/core/CertificateChecker.h index 4f2e3ea..876eec7 100644 --- a/src/core/CertificateChecker.h +++ b/src/core/CertificateChecker.h @@ -1,27 +1,22 @@ /*! - * CertificateChecker.h - * * \brief Contains the definition of the CertificateChecker class. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "AppSettings.h" -#include "context/AuthContext.h" +#include "asn1/CVCertificate.h" -#include -#include -#include #include #include #include -Q_DECLARE_LOGGING_CATEGORY(developermode) +#include namespace governikus { +class DIDAuthenticateEAC1; /*! * \brief Utility class for checking various constraints on certificates @@ -32,8 +27,6 @@ class CertificateChecker { Q_GADGET - static bool isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral); - public: enum class CertificateStatus { @@ -43,30 +36,17 @@ class CertificateChecker }; Q_ENUM(CertificateStatus) - static QString toString(QSsl::KeyAlgorithm pKeyAlgorithm); /*! - * Checks, whether the certificate's hash is contained in a set of accepted certificate hashes. - */ - static bool checkCertificate(const QSslCertificate& pCertificate, - QCryptographicHash::Algorithm pAlgorithm, - const QSet& pAcceptedCertificateHashes); - - /*! - * Checks, whether the key length of the SSL certificate is of sufficient length. - */ - static bool hasValidCertificateKeyLength(const QSslCertificate& pCertificate); - - /*! - * Checks, whether the length of the ephemeral key is of sufficient length. - */ - static bool hasValidEphemeralKeyLength(const QSslKey& pEphemeralServerKey); - - /*! - * Checks and save certificate into given WorkflowContext + * Checks certificate and, if OK, save it using a callback function. + * * \return Returns a translated error string if an error happened, otherwise QString() */ - static CertificateStatus checkAndSaveCertificate(const QSslCertificate& pCertificate, const QUrl& pUrl, QSharedPointer pContext); + static CertificateStatus checkAndSaveCertificate(const QSslCertificate& pCertificate, + const QUrl& pUrl, + const QSharedPointer& pEAC1, + const QSharedPointer& pDvCvc, + const std::function& pSaveCertificateFunc); }; } // namespace governikus diff --git a/src/core/DeviceInfo.cpp b/src/core/DeviceInfo.cpp deleted file mode 100644 index dcd6d49..0000000 --- a/src/core/DeviceInfo.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "DeviceInfo.h" - -#ifdef Q_OS_ANDROID -#include -#endif - -#include - -using namespace governikus; - -DeviceInfo::DeviceInfo() -{ -} - - -DeviceInfo::~DeviceInfo() -{ -} - - -#ifdef Q_OS_ANDROID -QString DeviceInfo::getField(const char* pField) -{ - QAndroidJniObject field = QAndroidJniObject::getStaticObjectField("android/os/Build", pField, "Ljava/lang/String;"); - if (field == nullptr || !field.isValid()) - { - qCritical() << "Cannot get field:" << pField; - return QString(); - } - - return field.toString(); -} - - -#endif - -QString DeviceInfo::getPrettyInfo() -{ -#ifdef Q_OS_ANDROID - return QStringLiteral("%1 (%2)").arg(getModel(), getFingerprint()); - -#endif - - return QString(); -} - - -QString DeviceInfo::getModel() -{ -#ifdef Q_OS_ANDROID - return getField("MODEL"); - -#endif - - return QString(); -} - - -QString DeviceInfo::getFingerprint() -{ -#ifdef Q_OS_ANDROID - return getField("FINGERPRINT"); - -#endif - - return QString(); -} diff --git a/src/core/DeviceInfo.h b/src/core/DeviceInfo.h deleted file mode 100644 index dfddb35..0000000 --- a/src/core/DeviceInfo.h +++ /dev/null @@ -1,33 +0,0 @@ -/*! - * \brief Implements a wrapper for different APIs to get - * device information like android device name. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -namespace governikus -{ - -class DeviceInfo -{ - private: - DeviceInfo(); - ~DeviceInfo(); - Q_DISABLE_COPY(DeviceInfo) - -#ifdef Q_OS_ANDROID - static QString getField(const char* pField); -#endif - - public: - static QString getPrettyInfo(); - - static QString getModel(); - static QString getFingerprint(); -}; - -} /* namespace governikus */ diff --git a/src/core/NoScriptFinder.cpp b/src/core/NoScriptFinder.cpp index 0f75966..30ac1b9 100644 --- a/src/core/NoScriptFinder.cpp +++ b/src/core/NoScriptFinder.cpp @@ -1,7 +1,5 @@ /*! - * NoScriptFinder.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "NoScriptFinder.h" @@ -33,9 +31,9 @@ class NoScriptFinderPrivate QStringList profileIniFiles; #if defined(Q_OS_LINUX) profileIniFiles += QDir::homePath() + QStringLiteral("/.mozilla/firefox/profiles.ini"); -#elif defined(Q_OS_WIN32) +#elif defined(Q_OS_WIN) profileIniFiles += QDir::homePath() + QStringLiteral("/AppData/Roaming/Mozilla/Firefox/profiles.ini"); -#elif defined(Q_OS_MAC) +#elif defined(Q_OS_MACOS) profileIniFiles += QDir::homePath() + QStringLiteral("/Library/Application Support/Firefox/profiles.ini"); profileIniFiles += QDir::homePath() + QStringLiteral("/Library/Mozilla/Firefox/profiles.ini"); #endif @@ -55,7 +53,8 @@ class NoScriptFinderPrivate } QSettings profileSettings(profileFileInfo.canonicalFilePath(), QSettings::Format::IniFormat); - for (const auto& profileGroup : profileSettings.childGroups().filter(QRegularExpression(QStringLiteral("Profile[0-9]*")))) + const auto& filtered = profileSettings.childGroups().filter(QRegularExpression(QStringLiteral("Profile[0-9]*"))); + for (const auto& profileGroup : filtered) { profileSettings.beginGroup(profileGroup); bool isRelative = profileSettings.value(QStringLiteral("IsRelative")).toBool(); @@ -63,7 +62,7 @@ class NoScriptFinderPrivate if (!path.isEmpty()) { - QString extensionFile = isRelative ? profileFileInfo.canonicalPath() + '/' + path : path; + QString extensionFile = isRelative ? profileFileInfo.canonicalPath() + QLatin1Char('/') + path : path; extensionFile += QStringLiteral("/extensions.json"); if ((mExtensionFound = isNoScriptConfigured(extensionFile))) diff --git a/src/core/NoScriptFinder.h b/src/core/NoScriptFinder.h index f4bffd5..4f1145e 100644 --- a/src/core/NoScriptFinder.h +++ b/src/core/NoScriptFinder.h @@ -1,9 +1,7 @@ /*! - * NoScriptFinder.h - * * \brief Determines, if a Firefox browser with NoScript extension is installed * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/SelfAuthenticationData.cpp b/src/core/SelfAuthenticationData.cpp index 038aad0..a88f3c2 100644 --- a/src/core/SelfAuthenticationData.cpp +++ b/src/core/SelfAuthenticationData.cpp @@ -1,11 +1,11 @@ /*! - * SelfAuthenticationData.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "SelfAuthenticationData.h" +#include "LanguageLoader.h" + #include #include @@ -15,23 +15,45 @@ using namespace governikus; SelfAuthenticationData::SelfAuthenticationData(const QByteArray& pData) - : QObject() - , mValid(false) + : d(new SelfData(pData)) +{ +} + + +bool SelfAuthenticationData::isValid() const +{ + return d->mValid; +} + + +QString SelfAuthenticationData::getValue(SelfAuthData pData) const +{ + return d->getValue(pData); +} + + +const QDateTime& SelfAuthenticationData::getDateTime() const +{ + return d->mDateTime; +} + + +SelfAuthenticationData::OrderedSelfData SelfAuthenticationData::getOrderedSelfData() const +{ + return d->getOrderedSelfInfo(); +} + + +SelfAuthenticationData::SelfData::SelfData(const QByteArray& pData) + : mValid(false) + , mDateTime(QDateTime::currentDateTime()) , mOperationsAllowed() , mSelfAuthData() - , mDateTime(QDateTime::currentDateTime()) -{ - parse(pData); -} - - -SelfAuthenticationData::~SelfAuthenticationData() -{ -} - - -void SelfAuthenticationData::parse(const QByteArray& pData) { + if (pData.isEmpty()) + { + return; + } qCDebug(secure) << "parsing data:" << pData; QDomDocument doc(QStringLiteral("dataXML")); @@ -46,13 +68,33 @@ void SelfAuthenticationData::parse(const QByteArray& pData) return; } - const auto& parseOperations = std::bind(&SelfAuthenticationData::parseOperationsAllowedByUser, this, std::placeholders::_1); - const auto& parsePersonal = std::bind(&SelfAuthenticationData::parsePersonalData, this, std::placeholders::_1); + const auto& parseOperations = std::bind(&SelfAuthenticationData::SelfData::parseOperationsAllowedByUser, this, std::placeholders::_1); + const auto& parsePersonal = std::bind(&SelfAuthenticationData::SelfData::parsePersonalData, this, std::placeholders::_1); mValid = parse(doc, QStringLiteral("OperationsAllowedByUser"), parseOperations) && parse(doc, QStringLiteral("PersonalData"), parsePersonal); } -bool SelfAuthenticationData::parseOperationsAllowedByUser(const QDomElement& pElement) +QString SelfAuthenticationData::SelfData::getValue(SelfAuthData pData) const +{ + if (mOperationsAllowed.value(pData) == SelfAuthDataPermission::ALLOWED) + { + return mSelfAuthData.value(pData); + } + else if (mOperationsAllowed.value(pData) == SelfAuthDataPermission::NOTONCHIP) + { + if (pData == SelfAuthData::Nationality && getValue(SelfAuthData::DocumentType) == QLatin1String("ID")) + { + return QStringLiteral("D"); + } + + return tr("This data has not been stored in this chip generation."); + } + + return QString(); +} + + +bool SelfAuthenticationData::SelfData::parseOperationsAllowedByUser(const QDomElement& pElement) { for (auto elem = pElement; !elem.isNull(); elem = elem.nextSiblingElement()) { @@ -77,7 +119,7 @@ bool SelfAuthenticationData::parseOperationsAllowedByUser(const QDomElement& pEl } -bool SelfAuthenticationData::parsePersonalData(const QDomElement& pElement) +bool SelfAuthenticationData::SelfData::parsePersonalData(const QDomElement& pElement) { for (auto elem = pElement; !elem.isNull(); elem = elem.nextSiblingElement()) { @@ -131,7 +173,7 @@ bool SelfAuthenticationData::parsePersonalData(const QDomElement& pElement) } -bool SelfAuthenticationData::tryToInsertChild(const QDomElement& pElement, SelfAuthData pAuthData) +bool SelfAuthenticationData::SelfData::tryToInsertChild(const QDomElement& pElement, SelfAuthData pAuthData) { if (pElement.isNull() || pElement.text().isNull()) { @@ -143,7 +185,7 @@ bool SelfAuthenticationData::tryToInsertChild(const QDomElement& pElement, SelfA } -bool SelfAuthenticationData::parse(const QDomDocument& pDoc, const QString& pElementName, const std::function& pParserFunc) +bool SelfAuthenticationData::SelfData::parse(const QDomDocument& pDoc, const QString& pElementName, const std::function& pParserFunc) { const QDomNodeList nodeList = pDoc.documentElement().elementsByTagName(pElementName); if (nodeList.size() == 0) @@ -156,33 +198,107 @@ bool SelfAuthenticationData::parse(const QDomDocument& pDoc, const QString& pEle } -bool SelfAuthenticationData::isValid() const +SelfAuthenticationData::OrderedSelfData SelfAuthenticationData::SelfData::getOrderedSelfInfo() const { - return mValid; -} + OrderedSelfData orderedSelfData; - -QString SelfAuthenticationData::getValue(SelfAuthData pData) const -{ - if (mOperationsAllowed.value(pData) == SelfAuthDataPermission::ALLOWED) + if (!mValid) { - return mSelfAuthData.value(pData); - } - else if (mOperationsAllowed.value(pData) == SelfAuthDataPermission::NOTONCHIP) - { - if (pData == SelfAuthData::Nationality && getValue(SelfAuthData::DocumentType) == QLatin1String("ID")) - { - return QStringLiteral("D"); - } - - return tr("This data has not been stored in this chip generation."); + return orderedSelfData; } - return QString(); + const auto& formatDate = [](const QString& pIn){ + QDateTime dateTime = QDateTime::fromString(pIn, QStringLiteral("yyyy-MM-dd+hh:mm")); + return LanguageLoader::getInstance().getUsedLocale().toString(dateTime, tr("dd.MM.yyyy")); + }; + + const auto& add = [&](const QString& pKey, const QString& pValue){ +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + if (!pKey.isEmpty()) + { + orderedSelfData << qMakePair(pKey + QLatin1Char(':'), pValue); + } + else +#endif + { + orderedSelfData << qMakePair(pKey, pValue); + } + }; + + //fill layout with new data, see 18 Personalausweisgesetz (PAuswG) + if (!getValue(SelfAuthData::FamilyNames).isNull()) + { + add(tr("Family name"), getValue(SelfAuthData::FamilyNames)); + } + if (!getValue(SelfAuthData::BirthName).isNull()) + { + add(tr("Birth name"), getValue(SelfAuthData::BirthName)); + } + if (!getValue(SelfAuthData::GivenNames).isNull()) + { + add(tr("Given name(s)"), getValue(SelfAuthData::GivenNames)); + } + if (!getValue(SelfAuthData::AcademicTitle).isNull()) + { + add(tr("Doctoral degree"), getValue(SelfAuthData::AcademicTitle)); + } + if (!getValue(SelfAuthData::DateOfBirth).isNull()) + { + add(tr("Date of birth"), formatDate(getValue(SelfAuthData::DateOfBirth))); + } + if (!getValue(SelfAuthData::PlaceOfBirth).isNull()) + { + add(tr("Place of birth"), getValue(SelfAuthData::PlaceOfBirth)); + } + if (!getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo).isNull()) + { + add(tr("Address"), getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo)); + } + if (!getValue(SelfAuthData::PlaceOfResidenceStreet).isNull()) + { + add(getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo).isNull() ? tr("Address") : QString(), getValue(SelfAuthData::PlaceOfResidenceStreet)); + } + if (!getValue(SelfAuthData::PlaceOfResidenceZipCode).isNull() || !getValue(SelfAuthData::PlaceOfResidenceCity).isNull()) + { + add(getValue(SelfAuthData::PlaceOfResidenceStreet).isNull() ? tr("Address") : QString(), getValue(SelfAuthData::PlaceOfResidenceZipCode) + QLatin1Char(' ') + getValue(SelfAuthData::PlaceOfResidenceCity)); + } + if (!getValue(SelfAuthData::PlaceOfResidenceCountry).isNull()) + { + add(QString(), getValue(SelfAuthData::PlaceOfResidenceCountry)); + } + + const auto& documentType = getValue(SelfAuthData::DocumentType); + if (!documentType.isNull()) + { + add(tr("Document type"), documentType); + } + if (!getValue(SelfAuthData::Nationality).isNull()) + { + add(tr("Nationality"), getValue(SelfAuthData::Nationality)); + } + if (!getValue(SelfAuthData::ArtisticName).isNull()) + { + add(tr("Religious / artistic name"), getValue(SelfAuthData::ArtisticName)); + } + if (!getValue(SelfAuthData::IssuingState).isNull()) + { + add(tr("Issuing country"), getValue(SelfAuthData::IssuingState)); + } + + // Show "Residence Permit" for eAT- and Test-Cards only + // AR, AS, AF --> see TR-03127 (v1.16) chapter 3.2.3 + // TA --> Used by Test-Cards + if (!getValue(SelfAuthData::ResidencePermitI).isNull() && ( + documentType == QLatin1String("AR") || + documentType == QLatin1String("AS") || + documentType == QLatin1String("AF") || + documentType == QLatin1String("TA"))) + { + add(tr("Residence permit I"), getValue(SelfAuthData::ResidencePermitI)); + } + + return orderedSelfData; } -const QDateTime& SelfAuthenticationData::getDateTime() const -{ - return mDateTime; -} +#include "moc_SelfAuthenticationData.cpp" diff --git a/src/core/SelfAuthenticationData.h b/src/core/SelfAuthenticationData.h index 1e36f65..a42bf4f 100644 --- a/src/core/SelfAuthenticationData.h +++ b/src/core/SelfAuthenticationData.h @@ -1,9 +1,7 @@ /*! - * SelfAuthenticationData.h - * * \brief Parses self authentication data from XML data and provides its content. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -12,10 +10,14 @@ #include +#include #include #include #include -#include +#include +#include +#include +#include namespace governikus { @@ -53,27 +55,38 @@ defineEnumType(SelfAuthData, class SelfAuthenticationData - : public QObject { - Q_OBJECT + public: + using OrderedSelfData = QVector >; private: - bool mValid; + class SelfData + : public QSharedData + { + Q_DECLARE_TR_FUNCTIONS(governikus::SelfData) - QMap mOperationsAllowed; - QMap mSelfAuthData; + private: + bool parse(const QDomDocument& pDoc, const QString& pElementName, const std::function& pParserFunc); + bool parseOperationsAllowedByUser(const QDomElement& pElement); + bool parsePersonalData(const QDomElement& pElement); + bool tryToInsertChild(const QDomElement& pElement, SelfAuthData pAuthData); - const QDateTime mDateTime; + public: + bool mValid; + const QDateTime mDateTime; + QMap mOperationsAllowed; + QMap mSelfAuthData; - void parse(const QByteArray& pData); - bool parse(const QDomDocument& pDoc, const QString& pElementName, const std::function& pParserFunc); - bool parseOperationsAllowedByUser(const QDomElement& pElement); - bool parsePersonalData(const QDomElement& pElement); - bool tryToInsertChild(const QDomElement& pElement, SelfAuthData pAuthData); + SelfData(const QByteArray& pData); + QString getValue(SelfAuthData pData) const; + OrderedSelfData getOrderedSelfInfo() const; + }; + + QSharedDataPointer d; public: - SelfAuthenticationData(const QByteArray& pData); - virtual ~SelfAuthenticationData(); + SelfAuthenticationData(const QByteArray& pData = QByteArray()); + ~SelfAuthenticationData() = default; /** * Check if parsing of given data was successful. @@ -81,6 +94,7 @@ class SelfAuthenticationData bool isValid() const; QString getValue(SelfAuthData pData) const; const QDateTime& getDateTime() const; + OrderedSelfData getOrderedSelfData() const; }; } /* namespace governikus */ diff --git a/src/core/SignalHandler.cpp b/src/core/SignalHandler.cpp index 67c0d1a..34880d7 100644 --- a/src/core/SignalHandler.cpp +++ b/src/core/SignalHandler.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "SignalHandler.h" @@ -40,10 +40,10 @@ void SignalHandler::init() { if (!mInit) { -#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_OSX) +#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MACOS) || defined(Q_OS_FREEBSD) initUnix(); -#elif defined(Q_OS_WIN32) - SetConsoleCtrlHandler((PHANDLER_ROUTINE) ctrlHandler, true); +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + SetConsoleCtrlHandler(PHANDLER_ROUTINE(ctrlHandler), true); #endif mInit = true; diff --git a/src/core/SignalHandler.h b/src/core/SignalHandler.h index dbfe5d0..8e09f0b 100644 --- a/src/core/SignalHandler.h +++ b/src/core/SignalHandler.h @@ -1,7 +1,7 @@ /* * \brief Implements signal handler for unix and windows. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/SignalHandler_bsd_linux_osx.cpp b/src/core/SignalHandler_bsd_linux_osx.cpp index 33b7c97..61477a1 100644 --- a/src/core/SignalHandler_bsd_linux_osx.cpp +++ b/src/core/SignalHandler_bsd_linux_osx.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "SignalHandler.h" @@ -23,7 +23,7 @@ void SignalHandler::initUnix() // Signal handling on POSIX systems is some what messed up since there exists // only a limited set of API calls which are usable. Therefore we create a private // socketpair to cross thread borders. - // http://doc.qt.io/qt-5.7/unix-signals.html + // http://doc.qt.io/qt-5/unix-signals.html if (::socketpair(AF_UNIX, SOCK_STREAM, 0, cSignalSocketPair)) { @@ -52,8 +52,13 @@ void SignalHandler::onSignalSocketActivated() { mSignalSocketNotifier->setEnabled(false); - int signal; - ::read(cSignalSocketPair[1], &signal, sizeof(signal)); + int signal = -1; + const auto bytes = ::read(cSignalSocketPair[1], &signal, sizeof(signal)); + if (bytes == 0 || signal == -1) + { + qCWarning(system) << "Cannot read signal:" << signal << "| bytes:" << bytes; + return; + } qCWarning(system) << "Got signal:" << signal; diff --git a/src/core/SignalHandler_win.cpp b/src/core/SignalHandler_win.cpp index 14ee104..757c6b6 100644 --- a/src/core/SignalHandler_win.cpp +++ b/src/core/SignalHandler_win.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "SignalHandler.h" diff --git a/src/core/TcToken.cpp b/src/core/TcToken.cpp index 063892d..b0ebd06 100644 --- a/src/core/TcToken.cpp +++ b/src/core/TcToken.cpp @@ -1,7 +1,5 @@ /*! - * TcToken.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ @@ -251,6 +249,12 @@ const QUrl& TcToken::getCommunicationErrorAddress() const } +bool TcToken::usePsk() const +{ + return !mPsk.isNull(); +} + + const QByteArray& TcToken::getPsk() const { return mPsk; diff --git a/src/core/TcToken.h b/src/core/TcToken.h index 7044f04..60b31dc 100644 --- a/src/core/TcToken.h +++ b/src/core/TcToken.h @@ -1,9 +1,7 @@ /*! - * TcToken.h - * * \brief Parses TCTokens from XML data and provides its content. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -53,6 +51,7 @@ class TcToken const QUrl& getServerAddress() const; const QUrl& getRefreshAddress() const; const QUrl& getCommunicationErrorAddress() const; + bool usePsk() const; const QByteArray& getPsk() const; void clearPsk(); diff --git a/src/core/context/AuthContext.cpp b/src/core/context/AuthContext.cpp index d1fc9c6..a79dbcf 100644 --- a/src/core/context/AuthContext.cpp +++ b/src/core/context/AuthContext.cpp @@ -1,23 +1,24 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AuthContext.h" #include "asn1/Chat.h" #include "AppSettings.h" +#include "Env.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" +#include "SecureStorage.h" #include using namespace governikus; -AuthContext::AuthContext(ActivationContext* pActivationContext) +AuthContext::AuthContext(const QSharedPointer& pActivationContext) : WorkflowContext() , mTcTokenNotFound(true) , mErrorReportedToServer(false) , mActivationContext(pActivationContext) - , mNetworkManager(new NetworkManager()) , mTcTokenUrl() , mTcToken() , mRefreshUrl() @@ -35,6 +36,7 @@ AuthContext::AuthContext(ActivationContext* pActivationContext) , mDIDAuthenticateResponseEAC2() , mTransmits() , mTransmitResponses() + , mTransmitResponseFailed(false) , mDisconnectResponse() , mStartPaosResponse() , mEffectiveAccessRights() @@ -101,7 +103,6 @@ bool AuthContext::removeForbiddenAccessRights(QSet& pAccessRights) } 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; @@ -205,7 +206,7 @@ bool AuthContext::setEffectiveAccessRights(const QSet& pAccessRight } -void AuthContext::setTerminalCvc(const QSharedPointer& pTerminalCvc) +void AuthContext::setTerminalCvc(const QSharedPointer& pTerminalCvc) { mTerminalCvc = pTerminalCvc; initializeChat(); @@ -224,7 +225,7 @@ QByteArray AuthContext::encodeEffectiveChat() } -CVCertificateChain AuthContext::getChainStartingWith(const QSharedPointer& pChainRoot) const +CVCertificateChain AuthContext::getChainStartingWith(const QSharedPointer& pChainRoot) const { const auto& productionChain = mCvcChainBuilderProd.getChainStartingWith(pChainRoot); if (productionChain.isValid()) @@ -254,16 +255,16 @@ CVCertificateChain AuthContext::getChainForCertificationAuthority(const Establis } -void AuthContext::initCvcChainBuilder(const QVector >& pAdditionalCertificates) +void AuthContext::initCvcChainBuilder(const QVector >& pAdditionalCertificates) { Q_ASSERT(mDIDAuthenticateEAC1); - QVector > cvcs; - cvcs += CVCertificate::fromHex(AppSettings::getInstance().getPreVerificationSettings().getLinkCertificates()); + QVector > cvcs; + cvcs += CVCertificate::fromHex(Env::getSingleton()->getPreVerificationSettings().getLinkCertificates()); cvcs += getDidAuthenticateEac1()->getCvCertificates(); cvcs += pAdditionalCertificates; - const auto& secureStorage = AppSettings::getInstance().getSecureStorage(); + const SecureStorage& secureStorage = SecureStorage::getInstance(); mCvcChainBuilderProd = CVCertificateChainBuilder(cvcs + CVCertificate::fromHex(secureStorage.getCVRootCertificates(true)), true); mCvcChainBuilderTest = CVCertificateChainBuilder(cvcs + CVCertificate::fromHex(secureStorage.getCVRootCertificates(false)), false); } diff --git a/src/core/context/AuthContext.h b/src/core/context/AuthContext.h index 30ddf7c..f35e436 100644 --- a/src/core/context/AuthContext.h +++ b/src/core/context/AuthContext.h @@ -1,19 +1,15 @@ /*! - * AuthContext.h - * * \brief Authentication context. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "asn1/CVCertificate.h" #include "asn1/CVCertificateChainBuilder.h" -#include "ActivationHandler.h" +#include "ActivationContext.h" #include "context/WorkflowContext.h" -#include "Commands.h" -#include "EnumHelper.h" #include "NetworkManager.h" #include "paos/invoke/DidAuthenticateResponseEac1.h" #include "paos/invoke/DidAuthenticateResponseEac2.h" @@ -27,11 +23,10 @@ #include "paos/retrieve/DidAuthenticateEac2.h" #include "paos/retrieve/DidAuthenticateEacAdditional.h" #include "paos/retrieve/DidList.h" +#include "paos/retrieve/Disconnect.h" #include "paos/retrieve/InitializeFramework.h" #include "paos/retrieve/StartPaosResponse.h" #include "paos/retrieve/Transmit.h" -#include "Result.h" -#include "SelfAuthenticationData.h" #include "TcToken.h" #include "UrlUtil.h" @@ -41,7 +36,6 @@ #include #include -class test_StatePrepareChat; class test_StateRedirectBrowser; class test_StatePreVerification; class test_StateProcessCertificatesFromEac2; @@ -65,8 +59,7 @@ class AuthContext bool mTcTokenNotFound; bool mErrorReportedToServer; - QScopedPointer mActivationContext; - QScopedPointer mNetworkManager; + QSharedPointer mActivationContext; QUrl mTcTokenUrl; QSharedPointer mTcToken; QUrl mRefreshUrl; @@ -84,13 +77,15 @@ class AuthContext QSharedPointer mDIDAuthenticateResponseEAC2; QVector > mTransmits; QVector > mTransmitResponses; + bool mTransmitResponseFailed; + QSharedPointer mDisconnect; QSharedPointer mDisconnectResponse; QSharedPointer mStartPaosResponse; QSet mEffectiveAccessRights; QSet mRequiredAccessRights; QSet mOptionalAccessRights; QMultiMap mCertificates; - QSharedPointer mTerminalCvc, mDvCvc; + QSharedPointer mTerminalCvc, mDvCvc; CVCertificateChainBuilder mCvcChainBuilderProd, mCvcChainBuilderTest; void initializeChat(); @@ -102,7 +97,7 @@ class AuthContext void fireEffectiveChatChanged(); public: - AuthContext(ActivationContext* pActivationContext); + AuthContext(const QSharedPointer& pActivationContext); virtual ~AuthContext(); @@ -126,26 +121,10 @@ class AuthContext void setTcTokenNotFound(bool pTcTokenNotFound) { - this->mTcTokenNotFound = pTcTokenNotFound; + mTcTokenNotFound = pTcTokenNotFound; } - NetworkManager& getNetworkManager() - { - return *mNetworkManager; - } - - -#ifndef Q_NO_DEBUG - // for testing purposes only! - void setNetworkManager(NetworkManager* pNetworkManager) - { - mNetworkManager.reset(pNetworkManager); - } - - -#endif - QList getCertificateList() const { return mCertificates.values(); @@ -233,9 +212,9 @@ class AuthContext } - void setDidAuthenticateEac2(const QSharedPointer& didAuthenticateEac2) + void setDidAuthenticateEac2(const QSharedPointer& pDidAuthenticateEac2) { - mDIDAuthenticateEAC2 = didAuthenticateEac2; + mDIDAuthenticateEAC2 = pDidAuthenticateEac2; } @@ -245,9 +224,9 @@ class AuthContext } - void setDidAuthenticateResponseEac1(const QSharedPointer& didAuthenticateResponseEac1) + void setDidAuthenticateResponseEac1(const QSharedPointer& pDidAuthenticateResponseEac1) { - mDIDAuthenticateResponseEAC1 = didAuthenticateResponseEac1; + mDIDAuthenticateResponseEAC1 = pDidAuthenticateResponseEac1; } @@ -257,9 +236,9 @@ class AuthContext } - void setDidAuthenticateResponseEacAdditionalInputType(const QSharedPointer& didAuthenticateResponseEacAdditionalInputType) + void setDidAuthenticateResponseEacAdditionalInputType(const QSharedPointer& pDidAuthenticateResponseEacAdditionalInputType) { - mDIDAuthenticateResponseEACAdditionalInputType = didAuthenticateResponseEacAdditionalInputType; + mDIDAuthenticateResponseEACAdditionalInputType = pDidAuthenticateResponseEacAdditionalInputType; } @@ -269,9 +248,9 @@ class AuthContext } - void setDidAuthenticateEacAdditional(const QSharedPointer& didAuthenticateEacAdditionalInputType) + void setDidAuthenticateEacAdditional(const QSharedPointer& pDidAuthenticateEacAdditionalInputType) { - mDIDAuthenticateEACAdditionalInputType = didAuthenticateEacAdditionalInputType; + mDIDAuthenticateEACAdditionalInputType = pDidAuthenticateEacAdditionalInputType; } @@ -281,9 +260,9 @@ class AuthContext } - void setDidAuthenticateResponseEac2(const QSharedPointer& didAuthenticateResponseEac2) + void setDidAuthenticateResponseEac2(const QSharedPointer& pDidAuthenticateResponseEac2) { - mDIDAuthenticateResponseEAC2 = didAuthenticateResponseEac2; + mDIDAuthenticateResponseEAC2 = pDidAuthenticateResponseEac2; } @@ -293,9 +272,9 @@ class AuthContext } - void setDidList(const QSharedPointer& didList) + void setDidList(const QSharedPointer& pDidList) { - mDIDList = didList; + mDIDList = pDidList; } @@ -305,9 +284,9 @@ class AuthContext } - void setDidListResponse(const QSharedPointer& didListResponse) + void setDidListResponse(const QSharedPointer& pDidListResponse) { - mDIDListResponse = didListResponse; + mDIDListResponse = pDidListResponse; } @@ -317,9 +296,9 @@ class AuthContext } - void setInitializeFramework(const QSharedPointer& initializeFramework) + void setInitializeFramework(const QSharedPointer& pInitializeFramework) { - mInitializeFramework = initializeFramework; + mInitializeFramework = pInitializeFramework; } @@ -329,9 +308,21 @@ class AuthContext } - void setInitializeFrameworkResponse(const QSharedPointer& initializeFrameworkResponse) + void setInitializeFrameworkResponse(const QSharedPointer& pInitializeFrameworkResponse) { - mInitializeFrameworkResponse = initializeFrameworkResponse; + mInitializeFrameworkResponse = pInitializeFrameworkResponse; + } + + + const QSharedPointer& getDisconnect() const + { + return mDisconnect; + } + + + void setDisconnect(const QSharedPointer& pDisconnect) + { + mDisconnect = pDisconnect; } @@ -353,9 +344,9 @@ class AuthContext } - void setStartPaosResponse(const QSharedPointer& startPaosResponse) + void setStartPaosResponse(const QSharedPointer& pStartPaosResponse) { - mStartPaosResponse = startPaosResponse; + mStartPaosResponse = pStartPaosResponse; } @@ -372,6 +363,18 @@ class AuthContext } + bool getTransmitResponseFailed() const + { + return mTransmitResponseFailed; + } + + + void setTransmitResponseFailed(bool pFailed) + { + mTransmitResponseFailed = pFailed; + } + + const QVector >& getTransmits() { return mTransmits; @@ -439,7 +442,7 @@ class AuthContext } - CVCertificateChain getChainStartingWith(const QSharedPointer& pChainRoot) const; + CVCertificateChain getChainStartingWith(const QSharedPointer& pChainRoot) const; bool hasChainForCertificationAuthority(const EstablishPACEChannelOutput& pPaceOutput) const; @@ -448,28 +451,28 @@ class AuthContext CVCertificateChain getChainForCertificationAuthority(const EstablishPACEChannelOutput& pPaceOutput) const; - void initCvcChainBuilder(const QVector >& pAdditionalCertificates = QVector >()); + void initCvcChainBuilder(const QVector >& pAdditionalCertificates = QVector >()); - const QSharedPointer& getDvCvc() const + const QSharedPointer& getDvCvc() const { return mDvCvc; } - void setDvCvc(const QSharedPointer& dvCvc) + void setDvCvc(const QSharedPointer& dvCvc) { mDvCvc = dvCvc; } - const QSharedPointer& getTerminalCvc() const + const QSharedPointer& getTerminalCvc() const { return mTerminalCvc; } - void setTerminalCvc(const QSharedPointer& pTerminalCvc); + void setTerminalCvc(const QSharedPointer& pTerminalCvc); }; diff --git a/src/core/context/ChangePinContext.cpp b/src/core/context/ChangePinContext.cpp index 8039fe3..ea62749 100644 --- a/src/core/context/ChangePinContext.cpp +++ b/src/core/context/ChangePinContext.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "ChangePinContext.h" diff --git a/src/core/context/ChangePinContext.h b/src/core/context/ChangePinContext.h index f389dbc..0073b19 100644 --- a/src/core/context/ChangePinContext.h +++ b/src/core/context/ChangePinContext.h @@ -1,7 +1,7 @@ /*! * \brief Context for changing the Pin. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/context/DiagnosisContext.cpp b/src/core/context/DiagnosisContext.cpp index 2aa4a11..3d46733 100644 --- a/src/core/context/DiagnosisContext.cpp +++ b/src/core/context/DiagnosisContext.cpp @@ -1,7 +1,5 @@ /*! - * DiagnosisContext.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DiagnosisContext.h" diff --git a/src/core/context/DiagnosisContext.h b/src/core/context/DiagnosisContext.h index 54aae83..c59f660 100644 --- a/src/core/context/DiagnosisContext.h +++ b/src/core/context/DiagnosisContext.h @@ -1,9 +1,7 @@ /*! - * DiagnosisContext.h - * * \brief Contains information collected by the diagnosis functionality. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/context/ReaderDriverContext.cpp b/src/core/context/ReaderDriverContext.cpp deleted file mode 100644 index 133cc5c..0000000 --- a/src/core/context/ReaderDriverContext.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "ReaderDriverContext.h" - -#include "ReaderManager.h" - -using namespace governikus; - -ReaderDriverContext::ReaderDriverContext() - : 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 -} - - -ReaderDriverContext::~ReaderDriverContext() -{ -} - - -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) -QVector > ReaderDriverContext::attachedDevices() -{ - const QVector readerInfos = ReaderManager::getInstance().getReaderInfos(); - return mReaderDetector->getAttachedDevices(readerInfos); -} - - -#endif - - -QSharedPointer ReaderDriverContext::getDriverSettings() const -{ - QSharedPointer settings(new DriverSettings()); - settings->load(); - - return settings; -} diff --git a/src/core/context/ReaderDriverContext.h b/src/core/context/ReaderDriverContext.h deleted file mode 100644 index 2a51e92..0000000 --- a/src/core/context/ReaderDriverContext.h +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * \brief Context for retrieving and presenting information about - * reader devices and their drivers. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "DriverSettings.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 ReaderDriverContext - : public QObject -{ - Q_OBJECT - - public: - 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; - - Q_SIGNALS: - void fireReaderChangeDetected(); -}; - -} /* namespace governikus */ diff --git a/src/core/context/RemoteServiceContext.cpp b/src/core/context/RemoteServiceContext.cpp new file mode 100644 index 0000000..d9c781a --- /dev/null +++ b/src/core/context/RemoteServiceContext.cpp @@ -0,0 +1,58 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteServiceContext.h" + +#include "Env.h" + + +using namespace governikus; + +RemoteServiceContext::RemoteServiceContext() + : mRemoteServer(Env::create()) + , mEstablishPaceChannelMessage() +{ +} + + +RemoteServiceContext::~RemoteServiceContext() +{ +} + + +const QSharedPointer& RemoteServiceContext::getRemoteServer() const +{ + Q_ASSERT(mRemoteServer); + return mRemoteServer; +} + + +bool RemoteServiceContext::isRunning() const +{ + Q_ASSERT(mRemoteServer); + return mRemoteServer ? mRemoteServer->isRunning() : false; +} + + +void RemoteServiceContext::setEstablishPaceChannelMessage(const QSharedPointer& pMessage) +{ + mEstablishPaceChannelMessage = pMessage; +} + + +const QSharedPointer& RemoteServiceContext::getEstablishPaceChannelMessage() const +{ + return mEstablishPaceChannelMessage; +} + + +void RemoteServiceContext::onResetMessageHandler() +{ + setCardConnection(QSharedPointer()); + setCan(QString()); + setPin(QString()); + setPuk(QString()); + resetLastPaceResultAndRetryCounter(); + mEstablishPaceChannelMessage = QSharedPointer(); +} diff --git a/src/core/context/RemoteServiceContext.h b/src/core/context/RemoteServiceContext.h new file mode 100644 index 0000000..3e0384e --- /dev/null +++ b/src/core/context/RemoteServiceContext.h @@ -0,0 +1,46 @@ +/*! + * \brief Remote service context. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "messages/IfdEstablishPaceChannel.h" +#include "RemoteServer.h" +#include "SelfAuthenticationData.h" +#include "WorkflowContext.h" + +#include + +namespace governikus +{ + +class RemoteServiceContext + : public WorkflowContext +{ + Q_OBJECT + + private: + const QSharedPointer mRemoteServer; + + QSharedPointer mEstablishPaceChannelMessage; + + Q_SIGNALS: + void fireCancelEstablishPaceChannel(); + + public: + RemoteServiceContext(); + virtual ~RemoteServiceContext(); + + const QSharedPointer& getRemoteServer() const; + bool isRunning() const; + + void setEstablishPaceChannelMessage(const QSharedPointer& pMessage); + const QSharedPointer& getEstablishPaceChannelMessage() const; + + public Q_SLOTS: + void onResetMessageHandler(); +}; + +} /* namespace governikus */ diff --git a/src/core/context/SelfAuthContext.cpp b/src/core/context/SelfAuthContext.cpp new file mode 100644 index 0000000..2155512 --- /dev/null +++ b/src/core/context/SelfAuthContext.cpp @@ -0,0 +1,18 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SelfAuthContext.h" + +using namespace governikus; + +SelfAuthContext::SelfAuthContext() + : AuthContext(QSharedPointer()) + , mSelfAuthenticationData() +{ +} + + +SelfAuthContext::~SelfAuthContext() +{ +} diff --git a/src/core/context/SelfAuthContext.h b/src/core/context/SelfAuthContext.h new file mode 100644 index 0000000..dbe5472 --- /dev/null +++ b/src/core/context/SelfAuthContext.h @@ -0,0 +1,47 @@ +/*! + * \brief Self authentication context. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AuthContext.h" + +#include "SelfAuthenticationData.h" + +namespace governikus +{ + +class SelfAuthContext + : public AuthContext +{ + Q_OBJECT + + private: + SelfAuthenticationData mSelfAuthenticationData; + + Q_SIGNALS: + void fireSelfAuthenticationDataChanged(); + + public: + SelfAuthContext(); + virtual ~SelfAuthContext(); + + + const SelfAuthenticationData& getSelfAuthenticationData() const + { + return mSelfAuthenticationData; + } + + + void setSelfAuthenticationData(const SelfAuthenticationData& pSelfAuthenticationData) + { + mSelfAuthenticationData = pSelfAuthenticationData; + Q_EMIT fireSelfAuthenticationDataChanged(); + } + + +}; + +} /* namespace governikus */ diff --git a/src/core/context/SelfAuthenticationContext.cpp b/src/core/context/SelfAuthenticationContext.cpp deleted file mode 100644 index a9cba77..0000000 --- a/src/core/context/SelfAuthenticationContext.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/*! - * SelfAuthenticationContext.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "SelfAuthenticationContext.h" - -using namespace governikus; - -SelfAuthenticationContext::SelfAuthenticationContext(ActivationContext* pActivationContext) - : AuthContext(pActivationContext) - , mSelfAuthenticationData() -{ -} - - -SelfAuthenticationContext::~SelfAuthenticationContext() -{ -} diff --git a/src/core/context/SelfAuthenticationContext.h b/src/core/context/SelfAuthenticationContext.h deleted file mode 100644 index c5bc192..0000000 --- a/src/core/context/SelfAuthenticationContext.h +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * SelfAuthenticationContext.h - * - * \brief Self authentication context. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AuthContext.h" - - -namespace governikus -{ - -class SelfAuthenticationContext - : public AuthContext -{ - Q_OBJECT - - private: - QSharedPointer mSelfAuthenticationData; - - Q_SIGNALS: - void fireSelfAuthenticationDataChanged(); - - public: - SelfAuthenticationContext(ActivationContext* pActivationContext); - virtual ~SelfAuthenticationContext(); - - - const QSharedPointer& getSelfAuthenticationData() const - { - return mSelfAuthenticationData; - } - - - void setSelfAuthenticationData(const QSharedPointer& pSelfAuthenticationData) - { - mSelfAuthenticationData = pSelfAuthenticationData; - Q_EMIT fireSelfAuthenticationDataChanged(); - } - - -}; - -} /* namespace governikus */ diff --git a/src/core/context/WorkflowContext.cpp b/src/core/context/WorkflowContext.cpp index aeaecb4..d2330bf 100644 --- a/src/core/context/WorkflowContext.cpp +++ b/src/core/context/WorkflowContext.cpp @@ -1,16 +1,19 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "WorkflowContext.h" +#include "FuncUtils.h" +#include "ReaderManager.h" + using namespace governikus; WorkflowContext::WorkflowContext() : QObject() , mStateApproved(false) , mCurrentState() - , mReaderType(ReaderManagerPlugInType::UNKNOWN) + , mReaderPlugInTypes() , mReaderName() , mCardConnection() , mCan() @@ -62,26 +65,23 @@ const QString& WorkflowContext::getCurrentState() const void WorkflowContext::setCurrentState(const QString& pNewState) { - if (mCurrentState != pNewState) - { - mCurrentState = pNewState; - Q_EMIT fireCurrentStateChanged(pNewState); - } + mCurrentState = pNewState; + Q_EMIT fireStateChanged(pNewState); } -ReaderManagerPlugInType WorkflowContext::getReaderType() const +const QVector& WorkflowContext::getReaderPlugInTypes() const { - return mReaderType; + return mReaderPlugInTypes; } -void WorkflowContext::setReaderType(ReaderManagerPlugInType pReaderType) +void WorkflowContext::setReaderPlugInTypes(const QVector& pReaderPlugInTypes) { - if (mReaderType != pReaderType) + if (mReaderPlugInTypes != pReaderPlugInTypes) { - mReaderType = pReaderType; - Q_EMIT fireReaderTypeChanged(); + mReaderPlugInTypes = pReaderPlugInTypes; + Q_EMIT fireReaderPlugInTypesChanged(); } } @@ -207,17 +207,29 @@ void WorkflowContext::setLastPaceResultAndRetryCounter(CardReturnCode pLastPaceR } +void WorkflowContext::resetLastPaceResultAndRetryCounter() +{ + mOldRetryCounter = -1; + mLastPaceResult = CardReturnCode::OK; +} + + const GlobalStatus& WorkflowContext::getStatus() const { return mStatus; } -void WorkflowContext::setStatus(const GlobalStatus& pStatus) +void WorkflowContext::setStatus(const GlobalStatus& pStatus, bool pReportToUser) { + const bool forceReport = mStatus.isNoError() && pStatus.isError(); + mStatus = pStatus; - mErrorReportedToUser = false; - Q_EMIT fireResultChanged(); + if (pReportToUser || forceReport) + { + mErrorReportedToUser = false; + Q_EMIT fireResultChanged(); + } } diff --git a/src/core/context/WorkflowContext.h b/src/core/context/WorkflowContext.h index 415a7bf..bf8d8b7 100644 --- a/src/core/context/WorkflowContext.h +++ b/src/core/context/WorkflowContext.h @@ -1,7 +1,7 @@ /*! * \brief Workflow context. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,25 +21,29 @@ class WorkflowContext { Q_OBJECT - bool mStateApproved; - QString mCurrentState; - ReaderManagerPlugInType mReaderType; - QString mReaderName; - QSharedPointer mCardConnection; - QString mCan; - QString mPin; - QString mPuk; - QScopedPointer mPaceOutputData; - int mOldRetryCounter; - CardReturnCode mLastPaceResult; - GlobalStatus mStatus; - bool mErrorReportedToUser; - bool mWorkflowFinished; + private: + bool mStateApproved; + QString mCurrentState; + QVector mReaderPlugInTypes; + QString mReaderName; + QSharedPointer mCardConnection; + QString mCan; + QString mPin; + QString mPuk; + QScopedPointer mPaceOutputData; + int mOldRetryCounter; + CardReturnCode mLastPaceResult; + GlobalStatus mStatus; + bool mErrorReportedToUser; + bool mWorkflowFinished; + + protected: + void resetLastPaceResultAndRetryCounter(); Q_SIGNALS: void fireStateApprovedChanged(); - void fireCurrentStateChanged(const QString& pNewState); - void fireReaderTypeChanged(); + void fireStateChanged(const QString& pNewState); + void fireReaderPlugInTypesChanged(); void fireReaderNameChanged(); void fireCardConnectionChanged(); void fireCanChanged(); @@ -63,8 +67,8 @@ class WorkflowContext const QString& getCurrentState() const; void setCurrentState(const QString& pNewState); - ReaderManagerPlugInType getReaderType() const; - void setReaderType(ReaderManagerPlugInType pReaderType); + const QVector& getReaderPlugInTypes() const; + void setReaderPlugInTypes(const QVector& pReaderPlugInTypes); const QString& getReaderName() const; void setReaderName(const QString& pReaderName); @@ -90,7 +94,7 @@ class WorkflowContext void setLastPaceResultAndRetryCounter(CardReturnCode pLastPaceResult, int pOldRetryCounter); const GlobalStatus& getStatus() const; - void setStatus(const GlobalStatus& pResult); + void setStatus(const GlobalStatus& pResult, bool pReportToUser = true); bool isWorkflowFinished() const; void setWorkflowFinished(bool pWorkflowFinished); diff --git a/src/core/controller/AppController.cpp b/src/core/controller/AppController.cpp index 5cb5560..e61a9b1 100644 --- a/src/core/controller/AppController.cpp +++ b/src/core/controller/AppController.cpp @@ -1,55 +1,104 @@ /*! - * AppController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "AppController.h" + +#include "ActivationContext.h" #include "AppSettings.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" -#include "context/SelfAuthenticationContext.h" -#include "controller/AppController.h" +#include "context/RemoteServiceContext.h" +#include "context/SelfAuthContext.h" #include "controller/AuthController.h" #include "controller/ChangePinController.h" +#include "controller/RemoteServiceController.h" #include "controller/SelfAuthController.h" -#include "DriverService.h" +#include "Env.h" #include "HttpServerRequestor.h" #include "HttpServerStatusParser.h" #include "LanguageLoader.h" #include "LogHandler.h" #include "NetworkManager.h" -#include "ProviderService.h" #include "ReaderManager.h" #include "ResourceLoader.h" #include "view/UILoader.h" +#include "view/UIPlugIn.h" #include +#include #include + +namespace governikus +{ +class WorkflowRequest +{ + private: + const Action mAction; + const QSharedPointer mContext; + + public: + WorkflowRequest(Action pAction, const QSharedPointer& pContext); + ~WorkflowRequest() = default; + + inline Action getAction() const; + inline QSharedPointer getContext() const; +}; + +} + + using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(support) +WorkflowRequest::WorkflowRequest(Action pAction, + const QSharedPointer& pContext) + : mAction(pAction) + , mContext(pContext) +{ +} + + +Action WorkflowRequest::getAction() const +{ + return mAction; +} + + +QSharedPointer WorkflowRequest::getContext() const +{ + return mContext; +} + + +bool AppController::canStartNewAction() +{ + return mCurrentAction == Action::NONE && mActiveController.isNull(); +} + + AppController::AppController() : mCurrentAction(Action::NONE) - , mWaitingAction(Action::NONE) + , mWaitingRequest() , mActiveController() { setObjectName(QStringLiteral("AppController")); - // read and apply the settings - AppSettings::getInstance().load(); - LanguageLoader::getInstance().load(); + connect(&AppSettings::getInstance().getGeneralSettings(), &GeneralSettings::fireSettingsChanged, this, &AppController::onSettingsChanged, Qt::DirectConnection); + onSettingsChanged(); + ResourceLoader::getInstance().init(); #ifndef QT_NO_NETWORKPROXY NetworkManager::setApplicationProxyFactory(); - connect(&NetworkManager::getGlobalInstance(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); + connect(Env::getSingleton(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); #endif - connect(this, &AppController::fireShutdown, &NetworkManager::getGlobalInstance(), &NetworkManager::onShutdown, Qt::QueuedConnection); + connect(this, &AppController::fireShutdown, Env::getSingleton(), &NetworkManager::onShutdown, Qt::QueuedConnection); } @@ -60,6 +109,10 @@ AppController::~AppController() bool AppController::start() { + ReaderManager::getInstance().init(QSharedPointer(Env::create())); + connect(this, &AppController::fireShutdown, &ReaderManager::getInstance(), &ReaderManager::shutdown, Qt::DirectConnection); + connect(&ReaderManager::getInstance(), &ReaderManager::fireInitialized, this, &AppController::fireStarted, Qt::QueuedConnection); + connect(&UILoader::getInstance(), &UILoader::fireLoadedPlugin, this, &AppController::onUiPlugin); if (!UILoader::getInstance().load()) { @@ -82,35 +135,14 @@ bool AppController::start() qDebug() << "Successfully started activation handler:" << handler; } - ReaderManager::getInstance().init(); - connect(this, &AppController::fireShutdown, &ReaderManager::getInstance(), &ReaderManager::shutdown, Qt::DirectConnection); - connect(&ReaderManager::getInstance(), &ReaderManager::fireInitialized, this, &AppController::fireStarted, Qt::QueuedConnection); - return true; } -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)) - { - if (!pActivationContext->sendOperationAlreadyActive()) - { - qCritical() << "Cannot send \"Operation already active\" to caller: " << pActivationContext->getSendError(); - } - } -} - - -void AppController::onActiveControllerDone() +void AppController::onWorkflowFinished() { qDebug() << mActiveController->metaObject()->className() << "done"; - disconnect(mActiveController.data(), &WorkflowController::fireComplete, this, &AppController::onActiveControllerDone); + disconnect(mActiveController.data(), &WorkflowController::fireComplete, this, &AppController::onWorkflowFinished); Q_EMIT fireWorkflowFinished(mActiveController->getContext()); @@ -118,22 +150,39 @@ void AppController::onActiveControllerDone() qCInfo(support) << "Finished workflow" << mCurrentAction; mCurrentAction = Action::NONE; - if (mWaitingAction != Action::NONE) + if (!mWaitingRequest.isNull()) { qDebug() << "Running waiting action now."; - switch (mWaitingAction) + switch (mWaitingRequest->getAction()) { case Action::PIN: - startNewWorkflow(Action::PIN, - QSharedPointer(new ChangePinContext)); - break; + { + const QSharedPointer context = mWaitingRequest->getContext().objectCast(); + Q_ASSERT(context); + startNewWorkflow(Action::PIN, context); + } + break; + + case Action::AUTH: + { + const QSharedPointer context = mWaitingRequest->getContext().objectCast(); + Q_ASSERT(context); + startNewWorkflow(Action::AUTH, context); + } + break; + + case Action::READER_SETTINGS: + { + Q_EMIT fireShowReaderSettings(); + } + break; default: qWarning() << "Waiting action is unhandled!"; break; } - mWaitingAction = Action::NONE; + mWaitingRequest.reset(); } } @@ -151,22 +200,133 @@ void AppController::onCloseReminderFinished(bool pDontRemindAgain) void AppController::onChangePinRequested() { qDebug() << "PIN change requested"; - if (!startNewWorkflow(Action::PIN, - QSharedPointer(new ChangePinContext))) + const QSharedPointer context(new ChangePinContext); + if (canStartNewAction()) { - mWaitingAction = Action::PIN; + startNewWorkflow(Action::PIN, context); + + return; } + + if (mWaitingRequest.isNull()) + { + mWaitingRequest.reset(new WorkflowRequest(Action::PIN, context)); + + return; + } + + qWarning() << "Cannot enqueue action" << Action::PIN << ", queue is already full."; +} + + +void AppController::onSwitchToReaderSettingsRequested() +{ + if (canStartNewAction()) + { + Q_EMIT fireShowReaderSettings(); + + return; + } + + if (mWaitingRequest.isNull()) + { + mWaitingRequest.reset(new WorkflowRequest(Action::READER_SETTINGS, QSharedPointer())); + + return; + } + + qWarning() << "Cannot enqueue action" << Action::READER_SETTINGS << ", queue is already full."; } void AppController::onSelfAuthenticationRequested() { qDebug() << "self authentication requested"; - QSharedPointer context(new SelfAuthenticationContext(nullptr)); + if (canStartNewAction()) + { + const QSharedPointer context(new SelfAuthContext()); + #ifndef QT_NO_NETWORKPROXY + connect(Env::getSingleton(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); + #endif + startNewWorkflow(Action::SELF, context); + } +} + + +void AppController::onAuthenticationRequest(const QSharedPointer& pActivationContext) +{ + qDebug() << "authentication requested"; + const QSharedPointer authContext(new AuthContext(pActivationContext)); + if (canStartNewAction()) + { #ifndef QT_NO_NETWORKPROXY - connect(&context->getNetworkManager(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); + connect(Env::getSingleton(), &NetworkManager::fireProxyAuthenticationRequired, this, &AppController::fireProxyAuthenticationRequired); #endif - startNewWorkflow(Action::SELF, context); + startNewWorkflow(Action::AUTH, authContext); + + return; + } + + if (mCurrentAction == Action::SELF) + { + const QSharedPointer activeContext = mActiveController->getContext(); + Q_ASSERT(!activeContext.isNull()); + if (activeContext->isWorkflowFinished()) + { + if (mWaitingRequest.isNull()) + { + mWaitingRequest.reset(new WorkflowRequest(Action::AUTH, authContext)); + activeContext->setStateApproved(true); + + return; + } + + qWarning() << "Cannot enqueue action" << Action::AUTH << ", queue is already full."; + } + } + + if (!pActivationContext->sendOperationAlreadyActive()) + { + qCritical() << "Cannot send \"Operation already active\" to caller: " << pActivationContext->getSendError(); + } +} + + +void AppController::onRemoteServiceRequested() +{ + qDebug() << "remote service requested"; + if (canStartNewAction()) + { + const QSharedPointer context(new RemoteServiceContext()); + startNewWorkflow(Action::REMOTE_SERVICE, context); + } +} + + +void AppController::onSettingsChanged() +{ + LanguageLoader& languageLoader = LanguageLoader::getInstance(); + const QLocale& newLocale = QLocale(AppSettings::getInstance().getGeneralSettings().getLanguage()); + const QLocale& usedLocale = languageLoader.getUsedLocale(); + + if (newLocale == usedLocale) + { + return; + } + + if (languageLoader.isLoaded()) + { + languageLoader.unload(); + } + + if (newLocale == QLocale::C) + { + languageLoader.load(); + } + else + { + languageLoader.load(newLocale); + } } @@ -180,19 +340,19 @@ 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; + // 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 = Env::getSingleton()->getOpenConnectionCount(); if (openConnectionCount > 0) { - if (++timesInvoked % (THREE_SECONDS / TIMER_INTERVAL) == 0) + static int timesInvoked = 0; + const int THREE_SECONDS = 3000; + if (++timesInvoked < THREE_SECONDS / TIMER_INTERVAL) { - qDebug() << "There are still" << openConnectionCount << "pending network connections"; + return; } - return; + qWarning() << "Closing with" << openConnectionCount << "pending network connections."; } timer->deleteLater(); @@ -212,40 +372,35 @@ void AppController::onUiPlugin(UIPlugIn* pPlugin) connect(this, &AppController::fireStarted, pPlugin, &UIPlugIn::onApplicationStarted); connect(this, &AppController::fireShowUi, pPlugin, &UIPlugIn::onShowUi); connect(this, &AppController::fireShowUserInformation, pPlugin, &UIPlugIn::fireShowUserInformation); + connect(this, &AppController::fireShowReaderSettings, pPlugin, &UIPlugIn::onShowReaderSettings); #ifndef QT_NO_NETWORKPROXY connect(this, &AppController::fireProxyAuthenticationRequired, pPlugin, &UIPlugIn::onProxyAuthenticationRequired); #endif connect(pPlugin, &UIPlugIn::fireChangePinRequest, this, &AppController::onChangePinRequested, Qt::QueuedConnection); + connect(pPlugin, &UIPlugIn::fireSwitchToReaderSettingsRequested, this, &AppController::onSwitchToReaderSettingsRequested, Qt::QueuedConnection); connect(pPlugin, &UIPlugIn::fireSelfAuthenticationRequested, this, &AppController::onSelfAuthenticationRequested, Qt::QueuedConnection); + connect(pPlugin, &UIPlugIn::fireRemoteServiceRequested, this, &AppController::onRemoteServiceRequested, Qt::QueuedConnection); connect(pPlugin, &UIPlugIn::fireQuitApplicationRequest, this, &AppController::doShutdown); connect(pPlugin, &UIPlugIn::fireCloseReminderFinished, this, &AppController::onCloseReminderFinished); } template -bool AppController::startNewWorkflow(Action pAction, QSharedPointer pContext) +bool AppController::startNewWorkflow(Action pAction, const QSharedPointer& pContext) { - // If a new authentication is requested and another authentication or self authentication is currently active, but the workflow is already finished - // then the new authentication shall be started. So we deactivate the old workflow here. - if (pAction == Action::AUTH && (mCurrentAction == Action::AUTH || mCurrentAction == Action::SELF) && mActiveController->getContext()->isWorkflowFinished()) - { - onActiveControllerDone(); - } - - if (mCurrentAction != Action::NONE) + if (mCurrentAction != Action::NONE || !mActiveController.isNull()) { qWarning() << "Cannot start" << Controller::staticMetaObject.className() << "| Current action: " << mCurrentAction; return false; } - Q_ASSERT(mActiveController.isNull()); qCInfo(support) << "Starting new workflow" << pAction; mActiveController.reset(new Controller(pContext)); mCurrentAction = pAction; - connect(mActiveController.data(), &WorkflowController::fireComplete, this, &AppController::onActiveControllerDone, Qt::QueuedConnection); + connect(mActiveController.data(), &WorkflowController::fireComplete, this, &AppController::onWorkflowFinished, Qt::QueuedConnection); LogHandler::getInstance().resetBacklog(); qDebug() << "Start" << mActiveController->metaObject()->className(); diff --git a/src/core/controller/AppController.h b/src/core/controller/AppController.h index 67c121b..4d9be43 100644 --- a/src/core/controller/AppController.h +++ b/src/core/controller/AppController.h @@ -1,28 +1,36 @@ /*! - * AppController.h - * * \brief Controller of the whole program. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "ActivationHandler.h" -#include "context/WorkflowContext.h" #include "EnumHelper.h" -#include "view/UIPlugIn.h" #include +class QAuthenticator; +class QNetworkProxy; + namespace governikus { -class WorkflowController; -class ReaderManagerPlugInInfo; - defineEnumType(Action, - NONE, AUTH, SELF, PIN) + NONE, + AUTH, + SELF, + PIN, + READER_SETTINGS, + REMOTE_SERVICE) + + +class UIPlugIn; +class WorkflowContext; +class WorkflowController; +class WorkflowRequest; + class AppController : public QObject @@ -35,16 +43,15 @@ class AppController friend class SignalHandler; Action mCurrentAction; - Action mWaitingAction; + QScopedPointer mWaitingRequest; QScopedPointer mActiveController; + bool canStartNewAction(); + public: AppController(); virtual ~AppController(); - /*! Start the application controller. - * \return Status: true on success, otherwise false - */ bool start(); Q_SIGNALS: @@ -54,6 +61,7 @@ class AppController void fireWorkflowFinished(QSharedPointer pContext); void fireShowUi(UiModule pModule); void fireShowUserInformation(const QString& pInformationMessage); + void fireShowReaderSettings(); #ifndef QT_NO_NETWORKPROXY void fireProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); #endif @@ -61,14 +69,17 @@ class AppController private Q_SLOTS: void doShutdown(); void onUiPlugin(UIPlugIn* pPlugin); - void onActiveControllerDone(); + void onWorkflowFinished(); void onCloseReminderFinished(bool pDontRemindAgain); void onChangePinRequested(); + void onSwitchToReaderSettingsRequested(); void onSelfAuthenticationRequested(); - void onAuthenticationRequest(ActivationContext* pActivationContext); + void onAuthenticationRequest(const QSharedPointer& pActivationContext); + void onRemoteServiceRequested(); + void onSettingsChanged(); private: - template bool startNewWorkflow(Action pAction, QSharedPointer pContext); + template bool startNewWorkflow(Action pAction, const QSharedPointer& pContext); }; diff --git a/src/core/controller/AuthController.cpp b/src/core/controller/AuthController.cpp index 653d080..6be3894 100644 --- a/src/core/controller/AuthController.cpp +++ b/src/core/controller/AuthController.cpp @@ -1,11 +1,10 @@ /*! - * AuthController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "context/AuthContext.h" #include "controller/AuthController.h" + +#include "context/AuthContext.h" #include "states/CompositeStateProcessCvcsAndSetRights.h" #include "states/CompositeStateSelectCard.h" #include "states/FinalState.h" @@ -20,6 +19,7 @@ #include "states/StateEstablishPacePuk.h" #include "states/StateGenericSendReceive.h" #include "states/StateGetTcToken.h" +#include "states/StateHandleRetryCounter.h" #include "states/StateInitializeFramework.h" #include "states/StateParseTcTokenUrl.h" #include "states/StateProcessCertificatesFromEac2.h" @@ -41,182 +41,159 @@ using namespace governikus; AuthController::AuthController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sProcessing = addAndConnectState(); + auto sProcessing = addState(); mStateMachine.setInitialState(sProcessing); - auto sParseTcTokenUrl = addAndConnectState(); - auto sGetTcToken = addAndConnectState(); - auto sStartPaos = addAndConnectState(); - auto sSendStartPaos = addAndConnectState(); - auto sInitializeFramework = addAndConnectState(); - auto sSendInitializeFrameworkResponse = addAndConnectState(); - auto sDidList = addAndConnectState(); - auto sSendDidListResponse = addAndConnectState(); + auto sParseTcTokenUrl = addState(); + auto sGetTcToken = addState(); + auto sStartPaos = addState(); + auto sSendStartPaos = addState(); + auto sInitializeFramework = addState(); + auto sSendInitializeFrameworkResponse = addState(); + auto sDidList = addState(); + auto sSendDidListResponse = addState(); auto sProcessCvcsAndSetRights = new CompositeStateProcessCvcsAndSetRights(pContext); mStateMachine.addState(sProcessCvcsAndSetRights); auto sSelectCard = new CompositeStateSelectCard(pContext); mStateMachine.addState(sSelectCard); - auto sUpdateRetryCounter = addAndConnectState(); - auto sEstablishPaceCan = addAndConnectState(); - auto sEstablishPacePin = addAndConnectState(); - auto sEstablishPacePuk = addAndConnectState(); - auto sDidAuthenticateEac1 = addAndConnectState(); - auto sSendDidAuthenticateResponseEac1 = addAndConnectState(); - auto sEacAdditionalInputType = addAndConnectState(); - auto sSendDidAuthenticatResponseEacAdditionalInput = addAndConnectState(); - auto sProcessCertificatesFromEac2 = addAndConnectState(); - auto sDidAuthenticateEac2 = addAndConnectState(); - auto sSendDidAuthenticateResponseEac2 = addAndConnectState(); - auto sTransmit = addAndConnectState(); - auto sSendTransmitResponse = addAndConnectState(); - auto sSendDisconnectResponse = addAndConnectState(); - auto sStartPaosResponse = addAndConnectState(); - auto sCheckRefreshAddress = addAndConnectState(); - auto sWriteHistory = addAndConnectState(); - auto sRedirectBrowser = addAndConnectState(); - auto sCleanUpReaderManager = addAndConnectState(); - auto sFinal = addAndConnectState(); + auto sUpdateRetryCounter = addState(); + auto sHandleRetryCounter = addState(); + auto sEstablishPaceCan = addState(); + auto sEstablishPacePin = addState(); + auto sEstablishPacePuk = addState(); + auto sDidAuthenticateEac1 = addState(); + auto sSendDidAuthenticateResponseEac1 = addState(); + auto sEacAdditionalInputType = addState(); + auto sSendDidAuthenticatResponseEacAdditionalInput = addState(); + auto sProcessCertificatesFromEac2 = addState(); + auto sDidAuthenticateEac2 = addState(); + auto sSendDidAuthenticateResponseEac2 = addState(); + auto sTransmit = addState(); + auto sSendTransmitResponse = addState(); + auto sSendDisconnectResponse = addState(); + auto sStartPaosResponse = addState(); + auto sCheckRefreshAddress = addState(); + auto sWriteHistory = addState(); + auto sRedirectBrowser = addState(); + auto sUpdateRetryCounterFinal = addState(); + auto sCleanUpReaderManager = addState(); + auto sFinal = addState(); - sProcessing->addTransition(sProcessing, &AbstractState::fireSuccess, sParseTcTokenUrl); - sProcessing->addTransition(sProcessing, &AbstractState::fireError, sCleanUpReaderManager); - sProcessing->addTransition(sProcessing, &AbstractState::fireCancel, sCleanUpReaderManager); + sProcessing->addTransition(sProcessing, &AbstractState::fireContinue, sParseTcTokenUrl); + sProcessing->addTransition(sProcessing, &AbstractState::fireAbort, sCleanUpReaderManager); - sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireSuccess, sGetTcToken); - sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireError, sCleanUpReaderManager); - sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireCancel, sCleanUpReaderManager); + sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireContinue, sGetTcToken); + sParseTcTokenUrl->addTransition(sParseTcTokenUrl, &AbstractState::fireAbort, sCleanUpReaderManager); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireSuccess, sStartPaos); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireError, sCleanUpReaderManager); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireCancel, sCleanUpReaderManager); + sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireContinue, sStartPaos); + sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireAbort, sCleanUpReaderManager); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireSuccess, sSendStartPaos); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireError, sCleanUpReaderManager); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireCancel, sCleanUpReaderManager); + sStartPaos->addTransition(sStartPaos, &AbstractState::fireContinue, sSendStartPaos); + sStartPaos->addTransition(sStartPaos, &AbstractState::fireAbort, sCleanUpReaderManager); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireSuccess, sInitializeFramework); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireError, sCleanUpReaderManager); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireContinue, sInitializeFramework); + sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireAbort, sCleanUpReaderManager); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedDidList, sDidList); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedExtractCvcsFromEac1InputType, sProcessCvcsAndSetRights); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedStartPaosResponse, sStartPaosResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireSuccess, sSendInitializeFrameworkResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireError, sSendInitializeFrameworkResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireCancel, sSendInitializeFrameworkResponse); + sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireContinue, sSendInitializeFrameworkResponse); + sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireAbort, sSendInitializeFrameworkResponse); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireSuccess, sDidList); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireContinue, sDidList); + sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireAbort, sCleanUpReaderManager); sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &StateSendInitializeFrameworkResponse::fireReceivedExtractCvcsFromEac1InputType, sProcessCvcsAndSetRights); sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &StateSendInitializeFrameworkResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sDidList->addTransition(sDidList, &AbstractState::fireSuccess, sSendDidListResponse); - sDidList->addTransition(sDidList, &AbstractState::fireError, sSendDidListResponse); - sDidList->addTransition(sDidList, &AbstractState::fireCancel, sSendDidListResponse); + sDidList->addTransition(sDidList, &AbstractState::fireContinue, sSendDidListResponse); + sDidList->addTransition(sDidList, &AbstractState::fireAbort, sSendDidListResponse); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireSuccess, sProcessCvcsAndSetRights); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireContinue, sProcessCvcsAndSetRights); + sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireAbort, sCleanUpReaderManager); sSendDidListResponse->addTransition(sSendDidListResponse, &StateSendDIDListResponse::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidListResponse->addTransition(sSendDidListResponse, &StateSendDIDListResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireSuccess, sSelectCard); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireError, sSendDidAuthenticateResponseEac1); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireCancel, sSendDidAuthenticateResponseEac1); + sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireContinue, sSelectCard); + sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireAbort, sSendDidAuthenticateResponseEac1); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireSuccess, sUpdateRetryCounter); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireError, sSendDidAuthenticateResponseEac1); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireCancel, sSendDidAuthenticateResponseEac1); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireContinue, sUpdateRetryCounter); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireAbort, sSendDidAuthenticateResponseEac1); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireContinue, sHandleRetryCounter); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireSuccess, sEstablishPacePin); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); + + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireContinue, sEstablishPacePin); sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, sUpdateRetryCounter); sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInoperativePuk, sUpdateRetryCounter); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireSuccess, sEstablishPacePin); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireContinue, sEstablishPacePin); sEstablishPaceCan->addTransition(sEstablishPaceCan, &StateEstablishPaceCan::fireInvalidCan, sUpdateRetryCounter); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireSuccess, sDidAuthenticateEac1); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireContinue, sDidAuthenticateEac1); sEstablishPacePin->addTransition(sEstablishPacePin, &StateEstablishPacePin::fireInvalidPin, sUpdateRetryCounter); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); + sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireContinue, sSendDidAuthenticateResponseEac1); + sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireSuccess, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); - - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireSuccess, sEacAdditionalInputType); - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireContinue, sEacAdditionalInputType); + sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &StateSendDIDAuthenticateResponseEAC1::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &StateSendDIDAuthenticateResponseEAC1::fireReceivedStartPaosResponse, sStartPaosResponse); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireSuccess, sProcessCertificatesFromEac2); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireError, sSendDidAuthenticatResponseEacAdditionalInput); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireCancel, sSendDidAuthenticatResponseEacAdditionalInput); + sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireContinue, sProcessCertificatesFromEac2); + sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireAbort, sSendDidAuthenticatResponseEacAdditionalInput); sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &StateEACAdditionalInputType::fireSendDidAuthenticatResponse, sSendDidAuthenticatResponseEacAdditionalInput); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireSuccess, sProcessCertificatesFromEac2); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireContinue, sProcessCertificatesFromEac2); + sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &StateSendDIDAuthenticateResponseEACAdditionalInputType::fireReceivedStartPaosResponse, sStartPaosResponse); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireSuccess, sDidAuthenticateEac2); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireError, sSendDidAuthenticateResponseEac2); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac2); + sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireContinue, sDidAuthenticateEac2); + sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireSuccess, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireError, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac2); + sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireContinue, sSendDidAuthenticateResponseEac2); + sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac2); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireSuccess, sTransmit); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireContinue, sTransmit); + sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &StateSendDIDAuthenticateResponseEAC2::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &StateSendDIDAuthenticateResponseEAC2::fireReceivedStartPaosResponse, sStartPaosResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireSuccess, sSendTransmitResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireError, sSendTransmitResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireCancel, sSendTransmitResponse); + sTransmit->addTransition(sTransmit, &AbstractState::fireContinue, sSendTransmitResponse); + sTransmit->addTransition(sTransmit, &AbstractState::fireAbort, sSendTransmitResponse); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireSuccess, sTransmit); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireContinue, sTransmit); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedDisconnect, sSendDisconnectResponse); sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireSuccess, sStartPaosResponse); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireContinue, sStartPaosResponse); + sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireSuccess, sCleanUpReaderManager); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireError, sCleanUpReaderManager); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireContinue, sUpdateRetryCounterFinal); + sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireSuccess, sCheckRefreshAddress); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireError, sCheckRefreshAddress); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireCancel, sCheckRefreshAddress); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireContinue, sCleanUpReaderManager); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireAbort, sCleanUpReaderManager); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireSuccess, sWriteHistory); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireError, sRedirectBrowser); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireCancel, sRedirectBrowser); + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireContinue, sCheckRefreshAddress); + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireAbort, sCheckRefreshAddress); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireSuccess, sRedirectBrowser); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireError, sRedirectBrowser); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireCancel, sRedirectBrowser); + sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireContinue, sWriteHistory); + sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireAbort, sRedirectBrowser); - sRedirectBrowser->addTransition(sRedirectBrowser, &AbstractState::fireSuccess, sFinal); - sRedirectBrowser->addTransition(sRedirectBrowser, &AbstractState::fireError, sFinal); - sRedirectBrowser->addTransition(sRedirectBrowser, &AbstractState::fireCancel, sFinal); + sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireContinue, sRedirectBrowser); + sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireAbort, sRedirectBrowser); + + sRedirectBrowser->addTransition(sRedirectBrowser, &AbstractState::fireContinue, sFinal); + sRedirectBrowser->addTransition(sRedirectBrowser, &AbstractState::fireAbort, sFinal); } diff --git a/src/core/controller/AuthController.h b/src/core/controller/AuthController.h index 3bd11e9..f51c850 100644 --- a/src/core/controller/AuthController.h +++ b/src/core/controller/AuthController.h @@ -1,9 +1,7 @@ /*! - * AuthController.h - * * \brief Controller for the authentication process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/controller/ChangePinController.cpp b/src/core/controller/ChangePinController.cpp index 8cc73f6..a63db48 100644 --- a/src/core/controller/ChangePinController.cpp +++ b/src/core/controller/ChangePinController.cpp @@ -1,9 +1,10 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "context/ChangePinContext.h" #include "ChangePinController.h" + +#include "context/ChangePinContext.h" #include "states/CompositeStateSelectCard.h" #include "states/FinalState.h" #include "states/StateChangePin.h" @@ -12,68 +13,70 @@ #include "states/StateEstablishPaceCan.h" #include "states/StateEstablishPacePin.h" #include "states/StateEstablishPacePuk.h" +#include "states/StateHandleRetryCounter.h" #include "states/StateUpdateRetryCounter.h" - #include #include + using namespace governikus; + ChangePinController::ChangePinController(QSharedPointer pContext) : WorkflowController(pContext) { auto sSelectCard = new CompositeStateSelectCard(pContext); mStateMachine.addState(sSelectCard); - auto sUpdateRetryCounter = addAndConnectState(); - auto sEstablishPacePin = addAndConnectState(); - auto sEstablishPaceCan = addAndConnectState(); - auto sEstablishPacePuk = addAndConnectState(); - auto sChangePin = addAndConnectState(); - auto sDestroyPace = addAndConnectState(); - auto sCleanUpReaderManager = addAndConnectState(); + auto sUpdateRetryCounter = addState(); + auto sHandleRetryCounter = addState(); + auto sEstablishPacePin = addState(); + auto sEstablishPaceCan = addState(); + auto sEstablishPacePuk = addState(); + auto sChangePin = addState(); + auto sDestroyPace = addState(); + auto sUpdateRetryCounterFinal = addState(); + auto sCleanUpReaderManager = addState(); - auto sFinal = addAndConnectState(); + auto sFinal = addState(); mStateMachine.setInitialState(sSelectCard); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireSuccess, sUpdateRetryCounter); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireError, sCleanUpReaderManager); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireCancel, sCleanUpReaderManager); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireContinue, sUpdateRetryCounter); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireAbort, sCleanUpReaderManager); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireError, sCleanUpReaderManager); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sCleanUpReaderManager); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireContinue, sHandleRetryCounter); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireAbort, sCleanUpReaderManager); + + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, 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); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInoperativePuk, sUpdateRetryCounterFinal); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireContinue, sUpdateRetryCounterFinal); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sEstablishPaceCan->addTransition(sEstablishPaceCan, &StateEstablishPaceCan::fireInvalidCan, sUpdateRetryCounter); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireSuccess, sEstablishPacePin); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireError, sCleanUpReaderManager); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireCancel, sCleanUpReaderManager); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireContinue, sEstablishPacePin); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sEstablishPacePin->addTransition(sEstablishPacePin, &StateEstablishPacePin::fireInvalidPin, sUpdateRetryCounter); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireSuccess, sChangePin); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireError, sCleanUpReaderManager); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireCancel, sCleanUpReaderManager); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireContinue, sChangePin); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sChangePin->addTransition(sChangePin, &AbstractState::fireSuccess, sDestroyPace); - sChangePin->addTransition(sChangePin, &StateChangePin::fireInvalidPin, sCleanUpReaderManager); - sChangePin->addTransition(sChangePin, &AbstractState::fireError, sCleanUpReaderManager); - sChangePin->addTransition(sChangePin, &AbstractState::fireCancel, sCleanUpReaderManager); + sChangePin->addTransition(sChangePin, &AbstractState::fireContinue, sDestroyPace); + sChangePin->addTransition(sChangePin, &StateChangePin::fireInvalidPin, sUpdateRetryCounterFinal); + sChangePin->addTransition(sChangePin, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireSuccess, sCleanUpReaderManager); - sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireError, sCleanUpReaderManager); - sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireCancel, sCleanUpReaderManager); + sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireContinue, sUpdateRetryCounterFinal); + sDestroyPace->addTransition(sDestroyPace, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireSuccess, sFinal); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireError, sFinal); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireCancel, sFinal); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireContinue, sCleanUpReaderManager); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireAbort, sCleanUpReaderManager); + + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireContinue, sFinal); + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireAbort, sFinal); } diff --git a/src/core/controller/ChangePinController.h b/src/core/controller/ChangePinController.h index b61359d..c00c8de 100644 --- a/src/core/controller/ChangePinController.h +++ b/src/core/controller/ChangePinController.h @@ -1,9 +1,7 @@ /*! - * ChangePinController.h - * * \brief Controller for the PIN changing process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/controller/DiagnosisController.cpp b/src/core/controller/DiagnosisController.cpp index 7eef722..b99dbfd 100644 --- a/src/core/controller/DiagnosisController.cpp +++ b/src/core/controller/DiagnosisController.cpp @@ -1,7 +1,5 @@ /*! - * DiagnosisController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DiagnosisController.h" diff --git a/src/core/controller/DiagnosisController.h b/src/core/controller/DiagnosisController.h index a0e9546..4bd35f1 100644 --- a/src/core/controller/DiagnosisController.h +++ b/src/core/controller/DiagnosisController.h @@ -1,9 +1,7 @@ /*! - * DiagnosisController.h - * * \brief Controller for retrieving and presenting diagnosis info. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/controller/DiagnosisController_generic.cpp b/src/core/controller/DiagnosisController_generic.cpp index a6e4a18..ffccd35 100644 --- a/src/core/controller/DiagnosisController_generic.cpp +++ b/src/core/controller/DiagnosisController_generic.cpp @@ -1,9 +1,7 @@ /*! - * DiagnosisController_generic.cpp - * * \brief Generic implementation of the controller for retrieving and presenting diagnosis info. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/src/core/controller/DiagnosisController_osx.cpp b/src/core/controller/DiagnosisController_osx.cpp index c851cdc..9691faa 100644 --- a/src/core/controller/DiagnosisController_osx.cpp +++ b/src/core/controller/DiagnosisController_osx.cpp @@ -1,9 +1,7 @@ /*! - * DiagnosisController_osx.cpp - * * \brief Mac OS X specific implementation of the controller for retrieving and presenting diagnosis info. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/src/core/controller/DiagnosisController_win.cpp b/src/core/controller/DiagnosisController_win.cpp index 5c6e198..3d96f1c 100644 --- a/src/core/controller/DiagnosisController_win.cpp +++ b/src/core/controller/DiagnosisController_win.cpp @@ -1,9 +1,7 @@ /*! - * DiagnosisController_win.cpp - * * \brief Windows specific implementation of the controller for retrieving and presenting diagnosis info. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ @@ -161,7 +159,7 @@ static QSet getWindowsSmartCardDriverModuleNames() { QVector serviceName((propertySize + 1) / 2); if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_SERVICE, nullptr, - (PBYTE) serviceName.data(), propertySize, &propertySize)) + PBYTE(serviceName.data()), propertySize, &propertySize)) { moduleNames.insert(QString::fromWCharArray(serviceName.data())); } diff --git a/src/core/controller/RemoteServiceController.cpp b/src/core/controller/RemoteServiceController.cpp new file mode 100644 index 0000000..2965da7 --- /dev/null +++ b/src/core/controller/RemoteServiceController.cpp @@ -0,0 +1,47 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "controller/RemoteServiceController.h" + +#include "context/RemoteServiceContext.h" +#include "states/FinalState.h" +#include "states/remote_service/StateEstablishPaceChannel.h" +#include "states/remote_service/StateProcessRemoteMessages.h" +#include "states/remote_service/StateStartRemoteService.h" +#include "states/remote_service/StateStopRemoteService.h" + +#include +#include + + +using namespace governikus; + + +RemoteServiceController::RemoteServiceController(QSharedPointer pContext) + : WorkflowController(pContext) +{ + auto sStartRemoteService = addState(); + mStateMachine.setInitialState(sStartRemoteService); + auto sProcessRemoteMessages = addState(); + auto sEstablishPaceChannel = addState(); + auto sStopRemoteService = addState(); + auto sFinal = addState(); + + sStartRemoteService->addTransition(sStartRemoteService, &AbstractState::fireContinue, sProcessRemoteMessages); + sStartRemoteService->addTransition(sStartRemoteService, &AbstractState::fireAbort, sStopRemoteService); + + sProcessRemoteMessages->addTransition(sProcessRemoteMessages, &AbstractState::fireAbort, sStopRemoteService); + sProcessRemoteMessages->addTransition(sProcessRemoteMessages, &StateProcessRemoteMessages::fireEstablishPaceChannel, sEstablishPaceChannel); + + sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &AbstractState::fireContinue, sProcessRemoteMessages); + sEstablishPaceChannel->addTransition(sEstablishPaceChannel, &AbstractState::fireAbort, sStopRemoteService); + + sStopRemoteService->addTransition(sStopRemoteService, &AbstractState::fireContinue, sFinal); + sStopRemoteService->addTransition(sStopRemoteService, &AbstractState::fireAbort, sFinal); +} + + +RemoteServiceController::~RemoteServiceController() +{ +} diff --git a/src/core/controller/RemoteServiceController.h b/src/core/controller/RemoteServiceController.h new file mode 100644 index 0000000..355bf01 --- /dev/null +++ b/src/core/controller/RemoteServiceController.h @@ -0,0 +1,26 @@ +/*! + * \brief Controller for the remote service process. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "WorkflowController.h" + +namespace governikus +{ + +class RemoteServiceContext; + +class RemoteServiceController + : public WorkflowController +{ + Q_OBJECT + + public: + RemoteServiceController(QSharedPointer pContext); + virtual ~RemoteServiceController(); +}; + +} /* namespace governikus */ diff --git a/src/core/controller/SelfAuthController.cpp b/src/core/controller/SelfAuthController.cpp index b2cb721..57bd1ad 100644 --- a/src/core/controller/SelfAuthController.cpp +++ b/src/core/controller/SelfAuthController.cpp @@ -1,11 +1,10 @@ /*! - * SelfAuthController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "context/SelfAuthenticationContext.h" #include "controller/SelfAuthController.h" + +#include "context/SelfAuthContext.h" #include "states/CompositeStateProcessCvcsAndSetRights.h" #include "states/CompositeStateSelectCard.h" #include "states/FinalState.h" @@ -22,6 +21,7 @@ #include "states/StateGenericSendReceive.h" #include "states/StateGetSelfAuthenticationData.h" #include "states/StateGetTcToken.h" +#include "states/StateHandleRetryCounter.h" #include "states/StateInitializeFramework.h" #include "states/StateLoadTcTokenUrl.h" #include "states/StateProcessCertificatesFromEac2.h" @@ -39,183 +39,161 @@ using namespace governikus; -SelfAuthController::SelfAuthController(QSharedPointer pContext) +SelfAuthController::SelfAuthController(QSharedPointer pContext) : WorkflowController(pContext) { - auto sLoadTcTokenUrl = addAndConnectState(); + auto sLoadTcTokenUrl = addState(); mStateMachine.setInitialState(sLoadTcTokenUrl); - auto sGetTcToken = addAndConnectState(); - auto sStartPaos = addAndConnectState(); - auto sSendStartPaos = addAndConnectState(); - auto sInitializeFramework = addAndConnectState(); - auto sSendInitializeFrameworkResponse = addAndConnectState(); - auto sDidList = addAndConnectState(); - auto sSendDidListResponse = addAndConnectState(); + auto sGetTcToken = addState(); + auto sStartPaos = addState(); + auto sSendStartPaos = addState(); + auto sInitializeFramework = addState(); + auto sSendInitializeFrameworkResponse = addState(); + auto sDidList = addState(); + auto sSendDidListResponse = addState(); auto sProcessCvcsAndSetRights = new CompositeStateProcessCvcsAndSetRights(pContext); mStateMachine.addState(sProcessCvcsAndSetRights); auto sSelectCard = new CompositeStateSelectCard(pContext); mStateMachine.addState(sSelectCard); - auto sUpdateRetryCounter = addAndConnectState(); - auto sEstablishPaceCan = addAndConnectState(); - auto sEstablishPacePin = addAndConnectState(); - auto sEstablishPacePuk = addAndConnectState(); - auto sDidAuthenticateEac1 = addAndConnectState(); - auto sSendDidAuthenticateResponseEac1 = addAndConnectState(); - auto sEacAdditionalInputType = addAndConnectState(); - auto sSendDidAuthenticatResponseEacAdditionalInput = addAndConnectState(); - auto sProcessCertificatesFromEac2 = addAndConnectState(); - auto sDidAuthenticateEac2 = addAndConnectState(); - auto sSendDidAuthenticateResponseEac2 = addAndConnectState(); - auto sTransmit = addAndConnectState(); - auto sSendTransmitResponse = addAndConnectState(); - auto sSendDisconnectResponse = addAndConnectState(); - auto sStartPaosResponse = addAndConnectState(); - auto sCheckErrorEpilogue = addAndConnectState(); - auto sCheckRefreshAddress = addAndConnectState(); - auto sWriteHistory = addAndConnectState(); - auto sGetSelfAuthenticationData = addAndConnectState(); - auto sCleanUpReaderManager = addAndConnectState(); - auto sFinal = addAndConnectState(); + auto sUpdateRetryCounter = addState(); + auto sHandleRetryCounter = addState(); + auto sEstablishPaceCan = addState(); + auto sEstablishPacePin = addState(); + auto sEstablishPacePuk = addState(); + auto sDidAuthenticateEac1 = addState(); + auto sSendDidAuthenticateResponseEac1 = addState(); + auto sEacAdditionalInputType = addState(); + auto sSendDidAuthenticatResponseEacAdditionalInput = addState(); + auto sProcessCertificatesFromEac2 = addState(); + auto sDidAuthenticateEac2 = addState(); + auto sSendDidAuthenticateResponseEac2 = addState(); + auto sTransmit = addState(); + auto sSendTransmitResponse = addState(); + auto sSendDisconnectResponse = addState(); + auto sStartPaosResponse = addState(); + auto sCheckErrorEpilogue = addState(); + auto sCheckRefreshAddress = addState(); + auto sWriteHistory = addState(); + auto sGetSelfAuthenticationData = addState(); + auto sUpdateRetryCounterFinal = addState(); + auto sCleanUpReaderManager = addState(); + auto sFinal = addState(); - sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireSuccess, sGetTcToken); - sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireError, sCleanUpReaderManager); - sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireCancel, sCleanUpReaderManager); + sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireContinue, sGetTcToken); + sLoadTcTokenUrl->addTransition(sLoadTcTokenUrl, &AbstractState::fireAbort, sCleanUpReaderManager); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireSuccess, sStartPaos); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireError, sCleanUpReaderManager); - sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireCancel, sCleanUpReaderManager); + sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireContinue, sStartPaos); + sGetTcToken->addTransition(sGetTcToken, &AbstractState::fireAbort, sCleanUpReaderManager); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireSuccess, sSendStartPaos); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireError, sCleanUpReaderManager); - sStartPaos->addTransition(sStartPaos, &AbstractState::fireCancel, sCleanUpReaderManager); + sStartPaos->addTransition(sStartPaos, &AbstractState::fireContinue, sSendStartPaos); + sStartPaos->addTransition(sStartPaos, &AbstractState::fireAbort, sCleanUpReaderManager); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireSuccess, sInitializeFramework); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireError, sCleanUpReaderManager); - sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireContinue, sInitializeFramework); + sSendStartPaos->addTransition(sSendStartPaos, &AbstractState::fireAbort, sCleanUpReaderManager); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedDidList, sDidList); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedExtractCvcsFromEac1InputType, sProcessCvcsAndSetRights); sSendStartPaos->addTransition(sSendStartPaos, &StateSendStartPaos::fireReceivedStartPaosResponse, sStartPaosResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireSuccess, sSendInitializeFrameworkResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireError, sSendInitializeFrameworkResponse); - sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireCancel, sSendInitializeFrameworkResponse); + sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireContinue, sSendInitializeFrameworkResponse); + sInitializeFramework->addTransition(sInitializeFramework, &AbstractState::fireAbort, sSendInitializeFrameworkResponse); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireSuccess, sDidList); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireContinue, sDidList); + sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &AbstractState::fireAbort, sCleanUpReaderManager); sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &StateSendInitializeFrameworkResponse::fireReceivedExtractCvcsFromEac1InputType, sProcessCvcsAndSetRights); sSendInitializeFrameworkResponse->addTransition(sSendInitializeFrameworkResponse, &StateSendInitializeFrameworkResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sDidList->addTransition(sDidList, &AbstractState::fireSuccess, sSendDidListResponse); - sDidList->addTransition(sDidList, &AbstractState::fireError, sSendDidListResponse); - sDidList->addTransition(sDidList, &AbstractState::fireCancel, sSendDidListResponse); + sDidList->addTransition(sDidList, &AbstractState::fireContinue, sSendDidListResponse); + sDidList->addTransition(sDidList, &AbstractState::fireAbort, sSendDidListResponse); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireSuccess, sProcessCvcsAndSetRights); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireContinue, sProcessCvcsAndSetRights); + sSendDidListResponse->addTransition(sSendDidListResponse, &AbstractState::fireAbort, sCleanUpReaderManager); sSendDidListResponse->addTransition(sSendDidListResponse, &StateSendDIDListResponse::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidListResponse->addTransition(sSendDidListResponse, &StateSendDIDListResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireSuccess, sSelectCard); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireError, sSendDidAuthenticateResponseEac1); - sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireCancel, sSendDidAuthenticateResponseEac1); + sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireContinue, sSelectCard); + sProcessCvcsAndSetRights->addTransition(sProcessCvcsAndSetRights, &CompositeStateProcessCvcsAndSetRights::fireAbort, sSendDidAuthenticateResponseEac1); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireSuccess, sUpdateRetryCounter); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireError, sSendDidAuthenticateResponseEac1); - sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireCancel, sSendDidAuthenticateResponseEac1); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireContinue, sUpdateRetryCounter); + sSelectCard->addTransition(sSelectCard, &CompositeStateSelectCard::fireAbort, sSendDidAuthenticateResponseEac1); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &StateUpdateRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireContinue, sHandleRetryCounter); + sUpdateRetryCounter->addTransition(sUpdateRetryCounter, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireSuccess, sEstablishPacePin); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsGTOne, sEstablishPacePin); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsOne, sEstablishPaceCan); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &StateHandleRetryCounter::fireRetryCounterIsZero, sEstablishPacePuk); + sHandleRetryCounter->addTransition(sHandleRetryCounter, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); + + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireContinue, sEstablishPacePin); sEstablishPacePuk->addTransition(sEstablishPacePuk, &StateEstablishPacePuk::fireInvalidPuk, sUpdateRetryCounter); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePuk->addTransition(sEstablishPacePuk, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireSuccess, sEstablishPacePin); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireContinue, sEstablishPacePin); sEstablishPaceCan->addTransition(sEstablishPaceCan, &StateEstablishPaceCan::fireInvalidCan, sUpdateRetryCounter); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPaceCan->addTransition(sEstablishPaceCan, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireSuccess, sDidAuthenticateEac1); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireContinue, sDidAuthenticateEac1); sEstablishPacePin->addTransition(sEstablishPacePin, &StateEstablishPacePin::fireInvalidPin, sUpdateRetryCounter); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sEstablishPacePin->addTransition(sEstablishPacePin, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireSuccess, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireError, sSendDidAuthenticateResponseEac1); - sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac1); + sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireContinue, sSendDidAuthenticateResponseEac1); + sDidAuthenticateEac1->addTransition(sDidAuthenticateEac1, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac1); - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireSuccess, sEacAdditionalInputType); - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireContinue, sEacAdditionalInputType); + sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &StateSendDIDAuthenticateResponseEAC1::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidAuthenticateResponseEac1->addTransition(sSendDidAuthenticateResponseEac1, &StateSendDIDAuthenticateResponseEAC1::fireReceivedStartPaosResponse, sStartPaosResponse); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireSuccess, sProcessCertificatesFromEac2); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireError, sSendDidAuthenticatResponseEacAdditionalInput); - sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireCancel, sSendDidAuthenticatResponseEacAdditionalInput); + sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireContinue, sProcessCertificatesFromEac2); + sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &AbstractState::fireAbort, sSendDidAuthenticatResponseEacAdditionalInput); sEacAdditionalInputType->addTransition(sEacAdditionalInputType, &StateEACAdditionalInputType::fireSendDidAuthenticatResponse, sSendDidAuthenticatResponseEacAdditionalInput); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireSuccess, sProcessCertificatesFromEac2); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireContinue, sProcessCertificatesFromEac2); + sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticatResponseEacAdditionalInput->addTransition(sSendDidAuthenticatResponseEacAdditionalInput, &StateSendDIDAuthenticateResponseEACAdditionalInputType::fireReceivedStartPaosResponse, sStartPaosResponse); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireSuccess, sDidAuthenticateEac2); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireError, sSendDidAuthenticateResponseEac2); - sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac2); + sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireContinue, sDidAuthenticateEac2); + sProcessCertificatesFromEac2->addTransition(sProcessCertificatesFromEac2, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireSuccess, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireError, sSendDidAuthenticateResponseEac2); - sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireCancel, sSendDidAuthenticateResponseEac2); + sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireContinue, sSendDidAuthenticateResponseEac2); + sDidAuthenticateEac2->addTransition(sDidAuthenticateEac2, &AbstractState::fireAbort, sSendDidAuthenticateResponseEac2); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireSuccess, sTransmit); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireError, sCleanUpReaderManager); - sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireContinue, sTransmit); + sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &StateSendDIDAuthenticateResponseEAC2::fireReceivedDisconnect, sSendDisconnectResponse); sSendDidAuthenticateResponseEac2->addTransition(sSendDidAuthenticateResponseEac2, &StateSendDIDAuthenticateResponseEAC2::fireReceivedStartPaosResponse, sStartPaosResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireSuccess, sSendTransmitResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireError, sSendTransmitResponse); - sTransmit->addTransition(sTransmit, &AbstractState::fireCancel, sSendTransmitResponse); + sTransmit->addTransition(sTransmit, &AbstractState::fireContinue, sSendTransmitResponse); + sTransmit->addTransition(sTransmit, &AbstractState::fireAbort, sSendTransmitResponse); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireSuccess, sTransmit); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireContinue, sTransmit); + sSendTransmitResponse->addTransition(sSendTransmitResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedDisconnect, sSendDisconnectResponse); sSendTransmitResponse->addTransition(sSendTransmitResponse, &StateSendTransmitResponse::fireReceivedStartPaosResponse, sStartPaosResponse); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireSuccess, sStartPaosResponse); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireError, sCleanUpReaderManager); - sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireContinue, sStartPaosResponse); + sSendDisconnectResponse->addTransition(sSendDisconnectResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireSuccess, sCleanUpReaderManager); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireError, sCleanUpReaderManager); - sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireCancel, sCleanUpReaderManager); + sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireContinue, sUpdateRetryCounterFinal); + sStartPaosResponse->addTransition(sStartPaosResponse, &AbstractState::fireAbort, sUpdateRetryCounterFinal); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireSuccess, sCheckErrorEpilogue); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireError, sCheckErrorEpilogue); - sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireCancel, sCheckErrorEpilogue); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireContinue, sCleanUpReaderManager); + sUpdateRetryCounterFinal->addTransition(sUpdateRetryCounterFinal, &AbstractState::fireAbort, sCleanUpReaderManager); - sCheckErrorEpilogue->addTransition(sCheckErrorEpilogue, &AbstractState::fireSuccess, sCheckRefreshAddress); - sCheckErrorEpilogue->addTransition(sCheckErrorEpilogue, &AbstractState::fireError, sFinal); - sCheckErrorEpilogue->addTransition(sCheckErrorEpilogue, &AbstractState::fireCancel, sFinal); + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireContinue, sCheckErrorEpilogue); + sCleanUpReaderManager->addTransition(sCleanUpReaderManager, &AbstractState::fireAbort, sCheckErrorEpilogue); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireSuccess, sWriteHistory); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireError, sFinal); - sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireCancel, sFinal); + sCheckErrorEpilogue->addTransition(sCheckErrorEpilogue, &AbstractState::fireContinue, sCheckRefreshAddress); + sCheckErrorEpilogue->addTransition(sCheckErrorEpilogue, &AbstractState::fireAbort, sFinal); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireSuccess, sGetSelfAuthenticationData); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireError, sGetSelfAuthenticationData); - sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireCancel, sFinal); + sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireContinue, sWriteHistory); + sCheckRefreshAddress->addTransition(sCheckRefreshAddress, &AbstractState::fireAbort, sFinal); - sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireSuccess, sFinal); - sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireError, sFinal); - sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireCancel, sFinal); + sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireContinue, sGetSelfAuthenticationData); + sWriteHistory->addTransition(sWriteHistory, &AbstractState::fireAbort, sGetSelfAuthenticationData); + + sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireContinue, sFinal); + sGetSelfAuthenticationData->addTransition(sGetSelfAuthenticationData, &AbstractState::fireAbort, sFinal); } diff --git a/src/core/controller/SelfAuthController.h b/src/core/controller/SelfAuthController.h index b47f62b..b959e77 100644 --- a/src/core/controller/SelfAuthController.h +++ b/src/core/controller/SelfAuthController.h @@ -1,9 +1,7 @@ /*! - * SelfAuthController.h - * * \brief Controller for the self authentication process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -13,7 +11,7 @@ namespace governikus { -class SelfAuthenticationContext; +class SelfAuthContext; class SelfAuthController : public WorkflowController @@ -21,7 +19,7 @@ class SelfAuthController Q_OBJECT public: - SelfAuthController(QSharedPointer pContext); + SelfAuthController(QSharedPointer pContext); virtual ~SelfAuthController(); }; diff --git a/src/core/controller/WorkflowController.cpp b/src/core/controller/WorkflowController.cpp index 9f06517..d533eec 100644 --- a/src/core/controller/WorkflowController.cpp +++ b/src/core/controller/WorkflowController.cpp @@ -1,7 +1,5 @@ /*! - * WorkflowController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "controller/WorkflowController.h" diff --git a/src/core/controller/WorkflowController.h b/src/core/controller/WorkflowController.h index bdb3972..b475432 100644 --- a/src/core/controller/WorkflowController.h +++ b/src/core/controller/WorkflowController.h @@ -1,14 +1,11 @@ /*! - * WorkflowController.h - * * \brief Base class for controllers controlling a workflow (using a state machine). * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "states/AbstractGenericState.h" #include "states/StateBuilder.h" #include @@ -43,7 +40,7 @@ class WorkflowController template - T* addAndConnectState() + T* addState() { auto state = StateBuilder::createState(mContext); mStateMachine.addState(state); diff --git a/src/core/paos/ElementDetector.cpp b/src/core/paos/ElementDetector.cpp index 2240ae7..f7ec6c7 100644 --- a/src/core/paos/ElementDetector.cpp +++ b/src/core/paos/ElementDetector.cpp @@ -1,7 +1,5 @@ /*! - * ElementDetector.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ElementDetector.h" diff --git a/src/core/paos/ElementDetector.h b/src/core/paos/ElementDetector.h index 25e1922..df0513f 100644 --- a/src/core/paos/ElementDetector.h +++ b/src/core/paos/ElementDetector.h @@ -1,7 +1,7 @@ /** * \brief Example class * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/MessageIdHandler.cpp b/src/core/paos/MessageIdHandler.cpp index cc1cf73..221ac2e 100644 --- a/src/core/paos/MessageIdHandler.cpp +++ b/src/core/paos/MessageIdHandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/MessageIdHandler.h" diff --git a/src/core/paos/MessageIdHandler.h b/src/core/paos/MessageIdHandler.h index c28cea4..3fa82a6 100644 --- a/src/core/paos/MessageIdHandler.h +++ b/src/core/paos/MessageIdHandler.h @@ -1,7 +1,7 @@ /*! * \brief Handle MessageIDs from XML header to use it in next paos message. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/PaosHandler.cpp b/src/core/paos/PaosHandler.cpp index fc97879..2976b9c 100644 --- a/src/core/paos/PaosHandler.cpp +++ b/src/core/paos/PaosHandler.cpp @@ -1,16 +1,17 @@ /*! - * PaosHandler.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "paos/retrieve/DidList.h" +#include "paos/retrieve/Disconnect.h" +#include "paos/retrieve/InitializeFramework.h" +#include "paos/retrieve/StartPaosResponse.h" #include "PaosHandler.h" #include "retrieve/DidAuthenticateEac1Parser.h" #include "retrieve/DidAuthenticateEac2Parser.h" #include "retrieve/DidAuthenticateEacAdditionalParser.h" #include "retrieve/TransmitParser.h" - using namespace governikus; diff --git a/src/core/paos/PaosHandler.h b/src/core/paos/PaosHandler.h index 6128303..e75c475 100644 --- a/src/core/paos/PaosHandler.h +++ b/src/core/paos/PaosHandler.h @@ -1,21 +1,13 @@ /*! * \brief Generic Handler to detect and parse paos types. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "paos/ElementDetector.h" #include "paos/PaosMessage.h" -#include "paos/PaosType.h" -#include "paos/retrieve/DidAuthenticateEac1.h" -#include "paos/retrieve/DidAuthenticateEac2.h" -#include "paos/retrieve/DidList.h" -#include "paos/retrieve/Disconnect.h" -#include "paos/retrieve/InitializeFramework.h" -#include "paos/retrieve/StartPaosResponse.h" -#include "paos/retrieve/Transmit.h" #include #include diff --git a/src/core/paos/PaosMessage.cpp b/src/core/paos/PaosMessage.cpp index 51dc3bf..88c424c 100644 --- a/src/core/paos/PaosMessage.cpp +++ b/src/core/paos/PaosMessage.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PaosMessage.h" diff --git a/src/core/paos/PaosMessage.h b/src/core/paos/PaosMessage.h index 4401252..3641cf1 100644 --- a/src/core/paos/PaosMessage.h +++ b/src/core/paos/PaosMessage.h @@ -1,7 +1,7 @@ /*! * \brief object represents one paos type * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/PaosType.cpp b/src/core/paos/PaosType.cpp index 91c2489..789d023 100644 --- a/src/core/paos/PaosType.cpp +++ b/src/core/paos/PaosType.cpp @@ -1,7 +1,5 @@ /*! - * PaosType.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PaosType.h" diff --git a/src/core/paos/PaosType.h b/src/core/paos/PaosType.h index 013692f..a9b016b 100644 --- a/src/core/paos/PaosType.h +++ b/src/core/paos/PaosType.h @@ -1,9 +1,7 @@ /*! - * PaosType.h - * * \brief All possible paos types * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/RequestType.cpp b/src/core/paos/RequestType.cpp index 2990aa4..df266cc 100644 --- a/src/core/paos/RequestType.cpp +++ b/src/core/paos/RequestType.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "RequestType.h" diff --git a/src/core/paos/RequestType.h b/src/core/paos/RequestType.h index c32ef4c..422da60 100644 --- a/src/core/paos/RequestType.h +++ b/src/core/paos/RequestType.h @@ -1,7 +1,7 @@ /*! * \brief Represents a PAOS request type according to ISOCommon.xsd * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/ResponseType.cpp b/src/core/paos/ResponseType.cpp index 3f4290e..c37b651 100644 --- a/src/core/paos/ResponseType.cpp +++ b/src/core/paos/ResponseType.cpp @@ -1,7 +1,5 @@ /*! - * ResponseType.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ResponseType.h" diff --git a/src/core/paos/ResponseType.h b/src/core/paos/ResponseType.h index f65784f..1655971 100644 --- a/src/core/paos/ResponseType.h +++ b/src/core/paos/ResponseType.h @@ -1,9 +1,7 @@ /*! - * ResponseType.h - * * \brief Represents a PAOS response type according to ISOCommon.xsd * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/src/core/paos/element/ConnectionHandle.cpp b/src/core/paos/element/ConnectionHandle.cpp index d1e77e7..a769f55 100644 --- a/src/core/paos/element/ConnectionHandle.cpp +++ b/src/core/paos/element/ConnectionHandle.cpp @@ -1,7 +1,5 @@ /*! - * ConnectionHandle.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ConnectionHandle.h" diff --git a/src/core/paos/element/ConnectionHandle.h b/src/core/paos/element/ConnectionHandle.h index eaf6aae..1c96b4b 100644 --- a/src/core/paos/element/ConnectionHandle.h +++ b/src/core/paos/element/ConnectionHandle.h @@ -1,9 +1,7 @@ /*! - * ConnectionHandle.h - * * \brief Object hold the paos connection handle. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/element/ConnectionHandleParser.cpp b/src/core/paos/element/ConnectionHandleParser.cpp index 0eb90e7..fbefadb 100644 --- a/src/core/paos/element/ConnectionHandleParser.cpp +++ b/src/core/paos/element/ConnectionHandleParser.cpp @@ -1,9 +1,11 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ConnectionHandleParser.h" +#include "ConnectionHandle.h" + using namespace governikus; ConnectionHandleParser::ConnectionHandleParser(QSharedPointer pXmlReader) @@ -22,7 +24,6 @@ ConnectionHandle ConnectionHandleParser::parse() { ConnectionHandle connectionHandle; - bool hasNoRecognitionInfoDuplicate = true; QString contexthandle, ifdName, slotIndex, cardApplication, slotHandle; while (readNextStartElement()) { @@ -64,8 +65,7 @@ ConnectionHandle ConnectionHandleParser::parse() } else if (mXmlReader->name() == QLatin1String("RecognitionInfo")) { - // not yet interpreted - assertNoDuplicateElement(hasNoRecognitionInfoDuplicate); + qCWarning(paos) << "Unsupported element:" << mXmlReader->name(); mXmlReader->skipCurrentElement(); } else diff --git a/src/core/paos/element/ConnectionHandleParser.h b/src/core/paos/element/ConnectionHandleParser.h index f588716..32a60b2 100644 --- a/src/core/paos/element/ConnectionHandleParser.h +++ b/src/core/paos/element/ConnectionHandleParser.h @@ -1,12 +1,11 @@ /*! * \brief Parse an XML connection handle from given stream. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "ConnectionHandle.h" #include "ElementParser.h" #include @@ -16,6 +15,8 @@ namespace governikus { +class ConnectionHandle; + class ConnectionHandleParser : public ElementParser { diff --git a/src/core/paos/element/Eac1InputType.cpp b/src/core/paos/element/Eac1InputType.cpp index bfde03b..086cb19 100644 --- a/src/core/paos/element/Eac1InputType.cpp +++ b/src/core/paos/element/Eac1InputType.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Eac1InputType.h" diff --git a/src/core/paos/element/Eac1InputType.h b/src/core/paos/element/Eac1InputType.h index 875d1ab..a9a1aaa 100644 --- a/src/core/paos/element/Eac1InputType.h +++ b/src/core/paos/element/Eac1InputType.h @@ -1,7 +1,7 @@ /*! * \brief Store information of Eac1InputType. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -37,59 +37,59 @@ class Eac1InputType friend class ::test_StateProcessCertificatesFromEac2; private: - QVector > mCvCertificates; + QVector > mCvCertificates; QByteArray mCertificateDescriptionAsBinary; - QSharedPointer mCertificateDescription; - QSharedPointer mRequiredChat, mOptionalChat; + QSharedPointer mCertificateDescription; + QSharedPointer mRequiredChat, mOptionalChat; QByteArray mAuthenticatedAuxiliaryDataAsBinary; - QSharedPointer mAuthenticatedAuxiliaryData; + QSharedPointer mAuthenticatedAuxiliaryData; QString mTransactionInfo; - void setAuthenticatedAuxiliaryData(const QSharedPointer& authenticatedAuxiliaryData) + void setAuthenticatedAuxiliaryData(const QSharedPointer& pAuthenticatedAuxiliaryData) { - mAuthenticatedAuxiliaryData = authenticatedAuxiliaryData; + mAuthenticatedAuxiliaryData = pAuthenticatedAuxiliaryData; } - void setAuthenticatedAuxiliaryDataAsBinary(const QByteArray& authenticatedAuxiliaryDataAsBinary) + void setAuthenticatedAuxiliaryDataAsBinary(const QByteArray& pAuthenticatedAuxiliaryDataAsBinary) { - mAuthenticatedAuxiliaryDataAsBinary = authenticatedAuxiliaryDataAsBinary; + mAuthenticatedAuxiliaryDataAsBinary = pAuthenticatedAuxiliaryDataAsBinary; } - void setCertificateDescription(QSharedPointer certificateDescription) + void setCertificateDescription(const QSharedPointer& pCertificateDescription) { - mCertificateDescription = certificateDescription; + mCertificateDescription = pCertificateDescription; } - void setCertificateDescriptionAsBinary(const QByteArray& certificateDescriptionAsBinary) + void setCertificateDescriptionAsBinary(const QByteArray& pCertificateDescriptionAsBinary) { - mCertificateDescriptionAsBinary = certificateDescriptionAsBinary; + mCertificateDescriptionAsBinary = pCertificateDescriptionAsBinary; } - void appendCvcerts(QSharedPointer cvcert) + void appendCvcerts(const QSharedPointer& pCert) { - mCvCertificates += cvcert; + mCvCertificates += pCert; } - void setOptionalChat(const QSharedPointer& optionalChat) + void setOptionalChat(const QSharedPointer& pOptionalChat) { - mOptionalChat = optionalChat; + mOptionalChat = pOptionalChat; } - void setRequiredChat(const QSharedPointer& requiredChat) + void setRequiredChat(const QSharedPointer& pRequiredChat) { - mRequiredChat = requiredChat; + mRequiredChat = pRequiredChat; } - void setTransactionInfo(const QString& transactionInfo) + void setTransactionInfo(const QString& pTransactionInfo) { - mTransactionInfo = transactionInfo; + mTransactionInfo = pTransactionInfo; } @@ -97,7 +97,7 @@ class Eac1InputType Eac1InputType(); ~Eac1InputType(); - QSharedPointer getAuthenticatedAuxiliaryData() const + const QSharedPointer& getAuthenticatedAuxiliaryData() const { return mAuthenticatedAuxiliaryData; } @@ -109,7 +109,7 @@ class Eac1InputType } - QSharedPointer getCertificateDescription() const + const QSharedPointer& getCertificateDescription() const { return mCertificateDescription; } @@ -121,19 +121,19 @@ class Eac1InputType } - const QVector >& getCvCertificates() const + const QVector >& getCvCertificates() const { return mCvCertificates; } - const QSharedPointer& getOptionalChat() const + const QSharedPointer& getOptionalChat() const { return mOptionalChat; } - const QSharedPointer& getRequiredChat() const + const QSharedPointer& getRequiredChat() const { return mRequiredChat; } diff --git a/src/core/paos/element/Eac2InputType.cpp b/src/core/paos/element/Eac2InputType.cpp index 65cd22a..543d95b 100644 --- a/src/core/paos/element/Eac2InputType.cpp +++ b/src/core/paos/element/Eac2InputType.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Eac2InputType.h" @@ -22,7 +22,7 @@ const QString& Eac2InputType::getSignature() const } -const QVector >& Eac2InputType::getCvCertificates() const +const QVector >& Eac2InputType::getCvCertificates() const { return mCvCertificates; } @@ -40,25 +40,25 @@ const QString& Eac2InputType::getEphemeralPublicKey() const } -void Eac2InputType::setEphemeralPublicKey(const QString& ephemeralPublicKey) +void Eac2InputType::setEphemeralPublicKey(const QString& pEphemeralPublicKey) { - mEphemeralPublicKey = ephemeralPublicKey; + mEphemeralPublicKey = pEphemeralPublicKey; } -void Eac2InputType::setSignature(const QString& signature) +void Eac2InputType::setSignature(const QString& pSignature) { - mSignature = signature; + mSignature = pSignature; } -void Eac2InputType::appendCvcert(QSharedPointer cvcert) +void Eac2InputType::appendCvcert(const QSharedPointer& pCert) { - mCvCertificates += cvcert; + mCvCertificates += pCert; } -void Eac2InputType::appendCvcertAsBinary(const QByteArray& cvcertAsBinary) +void Eac2InputType::appendCvcertAsBinary(const QByteArray& pCvcertAsBinary) { - mCvCertificatesAsBinary += cvcertAsBinary; + mCvCertificatesAsBinary += pCvcertAsBinary; } diff --git a/src/core/paos/element/Eac2InputType.h b/src/core/paos/element/Eac2InputType.h index 79f3558..47c41ba 100644 --- a/src/core/paos/element/Eac2InputType.h +++ b/src/core/paos/element/Eac2InputType.h @@ -1,7 +1,7 @@ /*! * \brief Store information of Eac2InputType. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,13 +23,13 @@ class Eac2InputType private: QByteArrayList mCvCertificatesAsBinary; - QVector > mCvCertificates; + QVector > mCvCertificates; QString mSignature; QString mEphemeralPublicKey; - void appendCvcert(QSharedPointer cvcert); - void appendCvcertAsBinary(const QByteArray& cvcertAsBinary); - void setEphemeralPublicKey(const QString& ephemeralPublicKey); - void setSignature(const QString& signature); + void appendCvcert(const QSharedPointer& pCert); + void appendCvcertAsBinary(const QByteArray& pCvcertAsBinary); + void setEphemeralPublicKey(const QString& pEphemeralPublicKey); + void setSignature(const QString& pSignature); public: Eac2InputType(); @@ -37,7 +37,7 @@ class Eac2InputType const QString& getSignature() const; const QString& getEphemeralPublicKey() const; - const QVector >& getCvCertificates() const; + const QVector >& getCvCertificates() const; const QByteArrayList& getCvCertificatesAsBinary() const; }; diff --git a/src/core/paos/element/ElementParser.cpp b/src/core/paos/element/ElementParser.cpp index 55d518e..a2a962d 100644 --- a/src/core/paos/element/ElementParser.cpp +++ b/src/core/paos/element/ElementParser.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ElementParser.h" @@ -59,16 +59,13 @@ bool ElementParser::assertNoDuplicateElement(bool pNotYetSeen) } -bool ElementParser::assertMandatoryElement(const QString& pValue, const char* pElementName) +void ElementParser::assertMandatoryElement(const QString& pValue, const char* pElementName) { if (pValue.isNull()) { qCWarning(paos) << "Mandatory element is null:" << pElementName; mParseError = true; - return false; } - - return true; } diff --git a/src/core/paos/element/ElementParser.h b/src/core/paos/element/ElementParser.h index b5038df..9a5bb05 100644 --- a/src/core/paos/element/ElementParser.h +++ b/src/core/paos/element/ElementParser.h @@ -1,7 +1,7 @@ /*! * \brief Base class for all XML element parser. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -43,9 +43,8 @@ class ElementParser * \brief Issues a log warning and sets the error when the element has not been set, i.e. the element is null. * \param pValue the elements value to check. * \param pElementName the elements name used to generate the log message. - * \return \c true, if the assertion holds, \c false otherwise. */ - bool assertMandatoryElement(const QString& pValue, const char* pElementName); + void assertMandatoryElement(const QString& pValue, const char* pElementName); /*! * \brief Issues a log warning and sets the error when the list is empty. diff --git a/src/core/paos/element/SupportedApi.cpp b/src/core/paos/element/SupportedApi.cpp index 7523eeb..e654aa5 100644 --- a/src/core/paos/element/SupportedApi.cpp +++ b/src/core/paos/element/SupportedApi.cpp @@ -1,12 +1,12 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "SupportedApi.h" #define SUPPORTED_ECARD_MAJOR 1 #define SUPPORTED_ECARD_MINOR 1 -#define SUPPORTED_ECARD_SUBMINOR 4 +#define SUPPORTED_ECARD_SUBMINOR 5 using namespace governikus; diff --git a/src/core/paos/element/SupportedApi.h b/src/core/paos/element/SupportedApi.h index f8f67ed..369ef6d 100644 --- a/src/core/paos/element/SupportedApi.h +++ b/src/core/paos/element/SupportedApi.h @@ -1,7 +1,7 @@ /*! - * \brief XML element for "SupportedAPI". + * \brief XML element for "SupportedAPI". See TR-03112-7. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/element/UserAgent.cpp b/src/core/paos/element/UserAgent.cpp index f7b8297..4cc9ea9 100644 --- a/src/core/paos/element/UserAgent.cpp +++ b/src/core/paos/element/UserAgent.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "UserAgent.h" diff --git a/src/core/paos/element/UserAgent.h b/src/core/paos/element/UserAgent.h index e5746d0..6db3c9f 100644 --- a/src/core/paos/element/UserAgent.h +++ b/src/core/paos/element/UserAgent.h @@ -1,7 +1,7 @@ /* * \brief Provides UserAgent information for PAOS elements. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/invoke/DidAuthenticateResponseEac1.cpp b/src/core/paos/invoke/DidAuthenticateResponseEac1.cpp index 55906ea..0201568 100644 --- a/src/core/paos/invoke/DidAuthenticateResponseEac1.cpp +++ b/src/core/paos/invoke/DidAuthenticateResponseEac1.cpp @@ -1,9 +1,10 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DidAuthenticateResponseEac1.h" +#include "EstablishPACEChannel.h" #include "paos/PaosType.h" using namespace governikus; @@ -96,7 +97,7 @@ QDomElement DIDAuthenticateResponseEAC1::createDIDAuthenticateResponseEAC1Elemen element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::TECHSCHEMA)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); element.appendChild(createAuthenticationProtocolDataElement()); return element; diff --git a/src/core/paos/invoke/DidAuthenticateResponseEac1.h b/src/core/paos/invoke/DidAuthenticateResponseEac1.h index e38aead..46a6322 100644 --- a/src/core/paos/invoke/DidAuthenticateResponseEac1.h +++ b/src/core/paos/invoke/DidAuthenticateResponseEac1.h @@ -1,12 +1,11 @@ /*! * \brief Generate information for DIDAuthenticateResponseEAC1. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "EstablishPACEChannel.h" #include "paos/ResponseType.h" #include "PaosCreator.h" @@ -16,6 +15,9 @@ namespace governikus { +class EstablishPACEChannelOutput; + + class DIDAuthenticateResponseEAC1 : public PaosCreator , public ResponseType @@ -30,14 +32,14 @@ class DIDAuthenticateResponseEAC1 QDomElement createDIDAuthenticateResponseEAC1Element(); QDomElement createAuthenticationProtocolDataElement(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; virtual Result getResult() const; Q_DISABLE_COPY(DIDAuthenticateResponseEAC1) public: DIDAuthenticateResponseEAC1(); - virtual ~DIDAuthenticateResponseEAC1(); + virtual ~DIDAuthenticateResponseEAC1() override; const QByteArray& getCertificateHolderAuthorizationTemplate() const; diff --git a/src/core/paos/invoke/DidAuthenticateResponseEac2.cpp b/src/core/paos/invoke/DidAuthenticateResponseEac2.cpp index e264065..566d171 100644 --- a/src/core/paos/invoke/DidAuthenticateResponseEac2.cpp +++ b/src/core/paos/invoke/DidAuthenticateResponseEac2.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DidAuthenticateResponseEac2.h" @@ -24,7 +24,7 @@ QDomElement DIDAuthenticateResponseEAC2::createDIDAuthenticateResponseEAC2Elemen element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::TECHSCHEMA)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); element.appendChild(createAuthenticationProtocolDataElement()); return element; diff --git a/src/core/paos/invoke/DidAuthenticateResponseEac2.h b/src/core/paos/invoke/DidAuthenticateResponseEac2.h index 9c93b93..2ddf8da 100644 --- a/src/core/paos/invoke/DidAuthenticateResponseEac2.h +++ b/src/core/paos/invoke/DidAuthenticateResponseEac2.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for DIDAuthenticateResponseEAC2. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -27,7 +27,7 @@ class DIDAuthenticateResponseEAC2 QDomElement createDIDAuthenticateResponseEAC2Element(); QDomElement createAuthenticationProtocolDataElement(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; Q_DISABLE_COPY(DIDAuthenticateResponseEAC2) diff --git a/src/core/paos/invoke/DidListResponse.cpp b/src/core/paos/invoke/DidListResponse.cpp index f16b764..9e34337 100644 --- a/src/core/paos/invoke/DidListResponse.cpp +++ b/src/core/paos/invoke/DidListResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DidListResponse.h" @@ -24,7 +24,7 @@ QDomElement DIDListResponse::createDidListResponseElement() element.setAttribute(getNamespacePrefix(Namespace::TECHSCHEMA), getNamespace(Namespace::TECHSCHEMA)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); element.appendChild(createDidListElement()); return element; diff --git a/src/core/paos/invoke/DidListResponse.h b/src/core/paos/invoke/DidListResponse.h index 8508a70..1abfadb 100644 --- a/src/core/paos/invoke/DidListResponse.h +++ b/src/core/paos/invoke/DidListResponse.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for DIDListResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -20,7 +20,7 @@ class DIDListResponse QDomElement createDidListResponseElement(); QDomElement createDidListElement(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; Q_DISABLE_COPY(DIDListResponse) diff --git a/src/core/paos/invoke/DisconnectResponse.cpp b/src/core/paos/invoke/DisconnectResponse.cpp index a3020d9..03b139e 100644 --- a/src/core/paos/invoke/DisconnectResponse.cpp +++ b/src/core/paos/invoke/DisconnectResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DisconnectResponse.h" @@ -25,7 +25,7 @@ QDomElement DisconnectResponse::createDisconnectResponse() element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::TECHSCHEMA)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); if (!mSlotHandle.isNull()) { element.appendChild(createTextElement(QStringLiteral("SlotHandle"), mSlotHandle)); diff --git a/src/core/paos/invoke/DisconnectResponse.h b/src/core/paos/invoke/DisconnectResponse.h index 64f5d18..d7a9b67 100644 --- a/src/core/paos/invoke/DisconnectResponse.h +++ b/src/core/paos/invoke/DisconnectResponse.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for DisconnectResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -27,7 +27,7 @@ class DisconnectResponse QDomElement createDisconnectResponse(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; public: DisconnectResponse(); diff --git a/src/core/paos/invoke/InitializeFrameworkResponse.cpp b/src/core/paos/invoke/InitializeFrameworkResponse.cpp index 94e30f3..278e1b6 100644 --- a/src/core/paos/invoke/InitializeFrameworkResponse.cpp +++ b/src/core/paos/invoke/InitializeFrameworkResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "InitializeFrameworkResponse.h" @@ -24,7 +24,7 @@ QDomElement InitializeFrameworkResponse::createInitializeFrameworkResponse() element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::ECARD)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); element.appendChild(createVersionElement()); return element; diff --git a/src/core/paos/invoke/InitializeFrameworkResponse.h b/src/core/paos/invoke/InitializeFrameworkResponse.h index 644a772..2141857 100644 --- a/src/core/paos/invoke/InitializeFrameworkResponse.h +++ b/src/core/paos/invoke/InitializeFrameworkResponse.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for InitializeFrameworkResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,7 +23,7 @@ class InitializeFrameworkResponse QDomElement createVersionElement(); QDomElement createInitializeFrameworkResponse(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; Q_DISABLE_COPY(InitializeFrameworkResponse) diff --git a/src/core/paos/invoke/PaosCreator.cpp b/src/core/paos/invoke/PaosCreator.cpp index bfd655b..3226636 100644 --- a/src/core/paos/invoke/PaosCreator.cpp +++ b/src/core/paos/invoke/PaosCreator.cpp @@ -1,11 +1,9 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PaosCreator.h" -#include "paos/ResponseType.h" - #include #include @@ -13,26 +11,26 @@ using namespace governikus; const QMap PaosCreator::mNamespacePrefix = { - {PaosCreator::Namespace::DEFAULT, ""}, - {PaosCreator::Namespace::ADDRESSING, "wsa"}, - {PaosCreator::Namespace::DSS, "dss"}, - {PaosCreator::Namespace::ECARD, "ecard"}, - {PaosCreator::Namespace::PAOS, "paos"}, - {PaosCreator::Namespace::TECHSCHEMA, "iso"}, - {PaosCreator::Namespace::XSD, "xsd"}, - {PaosCreator::Namespace::XSI, "xsi"}, - {PaosCreator::Namespace::SOAP, "soap"} + {PaosCreator::Namespace::DEFAULT, QString()}, + {PaosCreator::Namespace::ADDRESSING, QStringLiteral("wsa")}, + {PaosCreator::Namespace::DSS, QStringLiteral("dss")}, + {PaosCreator::Namespace::ECARD, QStringLiteral("ecard")}, + {PaosCreator::Namespace::PAOS, QStringLiteral("paos")}, + {PaosCreator::Namespace::TECHSCHEMA, QStringLiteral("iso")}, + {PaosCreator::Namespace::XSD, QStringLiteral("xsd")}, + {PaosCreator::Namespace::XSI, QStringLiteral("xsi")}, + {PaosCreator::Namespace::SOAP, QStringLiteral("soap")} }; const QMap PaosCreator::mNamespace = { - {PaosCreator::Namespace::ADDRESSING, "http://www.w3.org/2005/03/addressing"}, - {PaosCreator::Namespace::DSS, "urn:oasis:names:tc:dss:1.0:core:schema"}, - {PaosCreator::Namespace::ECARD, "http://www.bsi.bund.de/ecard/api/1.1"}, - {PaosCreator::Namespace::PAOS, "urn:liberty:paos:2006-08"}, - {PaosCreator::Namespace::TECHSCHEMA, "urn:iso:std:iso-iec:24727:tech:schema"}, - {PaosCreator::Namespace::XSD, "http://www.w3.org/2001/XMLSchema"}, - {PaosCreator::Namespace::XSI, "http://www.w3.org/2001/XMLSchema-instance"}, - {PaosCreator::Namespace::SOAP, "http://schemas.xmlsoap.org/soap/envelope/"} + {PaosCreator::Namespace::ADDRESSING, QStringLiteral("http://www.w3.org/2005/03/addressing")}, + {PaosCreator::Namespace::DSS, QStringLiteral("urn:oasis:names:tc:dss:1.0:core:schema")}, + {PaosCreator::Namespace::ECARD, QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1")}, + {PaosCreator::Namespace::PAOS, QStringLiteral("urn:liberty:paos:2006-08")}, + {PaosCreator::Namespace::TECHSCHEMA, QStringLiteral("urn:iso:std:iso-iec:24727:tech:schema")}, + {PaosCreator::Namespace::XSD, QStringLiteral("http://www.w3.org/2001/XMLSchema")}, + {PaosCreator::Namespace::XSI, QStringLiteral("http://www.w3.org/2001/XMLSchema-instance")}, + {PaosCreator::Namespace::SOAP, QStringLiteral("http://schemas.xmlsoap.org/soap/envelope/")} }; PaosCreator::PaosCreator() @@ -58,7 +56,7 @@ QString PaosCreator::getNamespaceType(Namespace pPrefix, const QString& pType) { QString prefix = mNamespacePrefix.value(pPrefix); Q_ASSERT(!prefix.isEmpty()); - return prefix + ":" + pType; + return prefix + QLatin1Char(':') + pType; } @@ -70,15 +68,15 @@ QString PaosCreator::getNamespacePrefix(Namespace pPrefix, const QString& pSuffi Q_ASSERT(pSuffix.isNull()); if (!value.isEmpty()) { - value.prepend(":"); + value.prepend(QLatin1Char(':')); } - value.prepend("xmlns"); + value.prepend(QLatin1String("xmlns")); } else { Q_ASSERT(pPrefix != Namespace::DEFAULT); Q_ASSERT(!value.isEmpty()); - value += ':'; + value += QLatin1Char(':'); value += pSuffix; } return value; @@ -188,33 +186,24 @@ QDomElement PaosCreator::createEnvelopeElement(const QDomElement& pBody, const Q } -QDomElement PaosCreator::createResultElement() +QDomElement PaosCreator::createResultElement(const ResponseType& pResponse) { QDomElement element = mDoc.createElement(QStringLiteral("Result")); element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::DSS)); - if (ResponseType* paosResponse = dynamic_cast(this)) + const Result& result = pResponse.getResult(); + element.appendChild(createTextElement(QStringLiteral("ResultMajor"), result.getMajorString())); + if (result.getMinor() != GlobalStatus::Code::No_Error) { - Result result = paosResponse->getResult(); - - element.appendChild(createTextElement(QStringLiteral("ResultMajor"), result.getMajorString())); - 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()); - resultElement.setAttribute(QStringLiteral("xml:lang"), result.getMessageLang()); - element.appendChild(resultElement); - } - } - else - { - qCritical() << "Cannot set Result, message is not of type ResponseType"; + element.appendChild(createTextElement(QStringLiteral("ResultMinor"), result.getMinorString())); } + if (!result.getMessage().isNull()) + { + QDomElement resultElement = createTextElement(QStringLiteral("ResultMessage"), result.getMessage()); + resultElement.setAttribute(QStringLiteral("xml:lang"), result.getMessageLang()); + element.appendChild(resultElement); + } return element; } diff --git a/src/core/paos/invoke/PaosCreator.h b/src/core/paos/invoke/PaosCreator.h index 88f36d1..d251c54 100644 --- a/src/core/paos/invoke/PaosCreator.h +++ b/src/core/paos/invoke/PaosCreator.h @@ -1,12 +1,12 @@ /*! * \brief Base class to create a PaosMessage. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "Result.h" +#include "paos/ResponseType.h" #include @@ -43,7 +43,7 @@ class PaosCreator QDomElement createHeaderElement(const QString& pRrelatesTo, const QString& pMessageID); QDomElement createEnvelopeElement(const QDomElement& pBody, const QString& pRelatesTo, const QString& pMessageID); - QDomElement createResultElement(); + QDomElement createResultElement(const ResponseType& pResponse); PaosCreator(); virtual ~PaosCreator(); diff --git a/src/core/paos/invoke/StartPaos.cpp b/src/core/paos/invoke/StartPaos.cpp index 3620698..83d8c97 100644 --- a/src/core/paos/invoke/StartPaos.cpp +++ b/src/core/paos/invoke/StartPaos.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StartPaos.h" @@ -12,17 +12,13 @@ StartPaos::StartPaos(const QByteArray& pSessionId) : PaosCreator() , PaosMessage(PaosType::STARTPAOS) , mSessionId(pSessionId) + , mUserAgent() + , mSupportedAPI() { Q_ASSERT(!mSessionId.isEmpty()); } -QDomElement StartPaos::getDocumentStructure() -{ - return createEnvelopeElement(createStartPaosElement(), getRelatesTo(), getMessageId()); -} - - QDomElement StartPaos::createConnectionHandleElement() { QDomElement element = mDoc.createElement(QStringLiteral("ConnectionHandle")); @@ -61,6 +57,12 @@ QDomElement StartPaos::createSupportedAPIVersionsElement() } +QDomElement StartPaos::createSessionIdentifierElement() +{ + return createTextElement(QStringLiteral("SessionIdentifier"), mSessionId); +} + + QDomElement StartPaos::createStartPaosElement() { QDomElement element = mDoc.createElement(QStringLiteral("StartPAOS")); @@ -75,7 +77,7 @@ QDomElement StartPaos::createStartPaosElement() } -QDomElement StartPaos::createSessionIdentifierElement() +QDomElement StartPaos::getDocumentStructure() { - return createTextElement(QStringLiteral("SessionIdentifier"), mSessionId); + return createEnvelopeElement(createStartPaosElement(), getRelatesTo(), getMessageId()); } diff --git a/src/core/paos/invoke/StartPaos.h b/src/core/paos/invoke/StartPaos.h index 681a530..e05feed 100644 --- a/src/core/paos/invoke/StartPaos.h +++ b/src/core/paos/invoke/StartPaos.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for StartPaos. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,9 +25,8 @@ class StartPaos private: const QByteArray mSessionId; - UserAgent mUserAgent; - SupportedAPI mSupportedAPI; - + const UserAgent mUserAgent; + const SupportedAPI mSupportedAPI; QDomElement createStartPaosElement(); QDomElement createSessionIdentifierElement(); @@ -35,7 +34,7 @@ class StartPaos QDomElement createUserAgentElement(); QDomElement createSupportedAPIVersionsElement(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; Q_DISABLE_COPY(StartPaos) diff --git a/src/core/paos/invoke/TransmitResponse.cpp b/src/core/paos/invoke/TransmitResponse.cpp index 7ef2f03..3e81005 100644 --- a/src/core/paos/invoke/TransmitResponse.cpp +++ b/src/core/paos/invoke/TransmitResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "TransmitResponse.h" @@ -25,7 +25,7 @@ QDomElement TransmitResponse::createTransmitResponse() element.setAttribute(getNamespacePrefix(Namespace::DEFAULT), getNamespace(Namespace::TECHSCHEMA)); element.setAttribute(QStringLiteral("Profile"), getNamespace(Namespace::ECARD)); - element.appendChild(createResultElement()); + element.appendChild(createResultElement(*this)); for (const auto& apdu : qAsConst(mOutputApdus)) { diff --git a/src/core/paos/invoke/TransmitResponse.h b/src/core/paos/invoke/TransmitResponse.h index 10dbcdc..d70dcd9 100644 --- a/src/core/paos/invoke/TransmitResponse.h +++ b/src/core/paos/invoke/TransmitResponse.h @@ -1,7 +1,7 @@ /*! * \brief Generate information for TransmitResponse. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,7 +25,7 @@ class TransmitResponse QDomElement createTransmitResponse(); - virtual QDomElement getDocumentStructure(); + virtual QDomElement getDocumentStructure() override; Q_DISABLE_COPY(TransmitResponse) diff --git a/src/core/paos/retrieve/DidAuthenticateEac1.cpp b/src/core/paos/retrieve/DidAuthenticateEac1.cpp index 9ad726f..142df51 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac1.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEac1.cpp @@ -1,7 +1,5 @@ /*! - * DidAuthenticateEac1.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -38,7 +36,7 @@ void DIDAuthenticateEAC1::setEac1InputType(const Eac1InputType& eac1InputType) } -QSharedPointer DIDAuthenticateEAC1::getAuthenticatedAuxiliaryData() const +const QSharedPointer& DIDAuthenticateEAC1::getAuthenticatedAuxiliaryData() const { return mEac1InputType.getAuthenticatedAuxiliaryData(); } @@ -50,7 +48,7 @@ const QByteArray& DIDAuthenticateEAC1::getAuthenticatedAuxiliaryDataAsBinary() c } -QSharedPointer DIDAuthenticateEAC1::getCertificateDescription() const +const QSharedPointer& DIDAuthenticateEAC1::getCertificateDescription() const { return mEac1InputType.getCertificateDescription(); } @@ -68,7 +66,7 @@ const ConnectionHandle& DIDAuthenticateEAC1::getConnectionHandle() const } -const QVector >& DIDAuthenticateEAC1::getCvCertificates() const +const QVector >& DIDAuthenticateEAC1::getCvCertificates() const { return mEac1InputType.getCvCertificates(); } @@ -80,13 +78,13 @@ const QString& DIDAuthenticateEAC1::getDidName() const } -const QSharedPointer& DIDAuthenticateEAC1::getOptionalChat() const +const QSharedPointer& DIDAuthenticateEAC1::getOptionalChat() const { return mEac1InputType.getOptionalChat(); } -const QSharedPointer& DIDAuthenticateEAC1::getRequiredChat() const +const QSharedPointer& DIDAuthenticateEAC1::getRequiredChat() const { return mEac1InputType.getRequiredChat(); } diff --git a/src/core/paos/retrieve/DidAuthenticateEac1.h b/src/core/paos/retrieve/DidAuthenticateEac1.h index cc5f411..c48a204 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac1.h +++ b/src/core/paos/retrieve/DidAuthenticateEac1.h @@ -1,19 +1,16 @@ /*! * \brief Class represents the retrieved PAOS EAC1InputType. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "asn1/AuthenticatedAuxiliaryData.h" -#include "asn1/CertificateDescription.h" #include "asn1/Chat.h" #include "asn1/CVCertificate.h" #include "paos/element/ConnectionHandle.h" #include "paos/element/Eac1InputType.h" -#include "paos/ElementDetector.h" #include "paos/PaosMessage.h" #include @@ -53,15 +50,15 @@ class DIDAuthenticateEAC1 DIDAuthenticateEAC1(); virtual ~DIDAuthenticateEAC1(); - QSharedPointer getAuthenticatedAuxiliaryData() const; + const QSharedPointer& getAuthenticatedAuxiliaryData() const; const QByteArray& getAuthenticatedAuxiliaryDataAsBinary() const; - QSharedPointer getCertificateDescription() const; + const QSharedPointer& getCertificateDescription() const; const QByteArray& getCertificateDescriptionAsBinary() const; const ConnectionHandle& getConnectionHandle() const; - const QVector >& getCvCertificates() const; + const QVector >& getCvCertificates() const; const QString& getDidName() const; - const QSharedPointer& getOptionalChat() const; - const QSharedPointer& getRequiredChat() const; + const QSharedPointer& getOptionalChat() const; + const QSharedPointer& getRequiredChat() const; const QString& getTransactionInfo() const; }; diff --git a/src/core/paos/retrieve/DidAuthenticateEac1Parser.cpp b/src/core/paos/retrieve/DidAuthenticateEac1Parser.cpp index fa10990..6cfc819 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac1Parser.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEac1Parser.cpp @@ -1,9 +1,7 @@ /*! - * DidAuthenticateEac1Parser.cpp - * * \brief Parser for the PAOS DidAuthenticateEac1 element. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -156,7 +154,7 @@ Eac1InputType DidAuthenticateEac1Parser::parseEac1InputType() mXmlReader->skipCurrentElement(); } } - assertMandatoryList >(eac1.getCvCertificates(), "Certificate"); + assertMandatoryList >(eac1.getCvCertificates(), "Certificate"); return eac1; } diff --git a/src/core/paos/retrieve/DidAuthenticateEac1Parser.h b/src/core/paos/retrieve/DidAuthenticateEac1Parser.h index 98b6f12..4df647a 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac1Parser.h +++ b/src/core/paos/retrieve/DidAuthenticateEac1Parser.h @@ -1,9 +1,7 @@ /*! - * DidAuthenticateEac1Parser.h - * * \brief Parser for the PAOS DidAuthenticateEac1 element. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +20,7 @@ class DidAuthenticateEac1Parser { public: DidAuthenticateEac1Parser(); - ~DidAuthenticateEac1Parser(); + virtual ~DidAuthenticateEac1Parser() override; protected: virtual PaosMessage* parseMessage() override; diff --git a/src/core/paos/retrieve/DidAuthenticateEac2.cpp b/src/core/paos/retrieve/DidAuthenticateEac2.cpp index 63b22b5..1fc1457 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac2.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEac2.cpp @@ -1,7 +1,5 @@ /*! - * DidAuthenticateEac2.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEac2.h" @@ -38,7 +36,7 @@ const QString& DIDAuthenticateEAC2::getSignature() const } -const QVector >& DIDAuthenticateEAC2::getCvCertificates() const +const QVector >& DIDAuthenticateEAC2::getCvCertificates() const { return mEac2.getCvCertificates(); } diff --git a/src/core/paos/retrieve/DidAuthenticateEac2.h b/src/core/paos/retrieve/DidAuthenticateEac2.h index 0ba84ae..4b85cf0 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac2.h +++ b/src/core/paos/retrieve/DidAuthenticateEac2.h @@ -1,9 +1,7 @@ /*! - * DidAuthenticateEac2.h - * * \brief Class represents the retrieved PAOS EAC2InputType. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -40,7 +38,7 @@ class DIDAuthenticateEAC2 const QString& getDidName() const; const QString& getSignature() const; const QString& getEphemeralPublicKey() const; - const QVector >& getCvCertificates() const; + const QVector >& getCvCertificates() const; const QByteArrayList& getCvCertificatesAsBinary() const; }; diff --git a/src/core/paos/retrieve/DidAuthenticateEac2Parser.cpp b/src/core/paos/retrieve/DidAuthenticateEac2Parser.cpp index 444d84d..1371d62 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac2Parser.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEac2Parser.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEac2Parser.h" diff --git a/src/core/paos/retrieve/DidAuthenticateEac2Parser.h b/src/core/paos/retrieve/DidAuthenticateEac2Parser.h index 2e1ba3f..ba6ed57 100644 --- a/src/core/paos/retrieve/DidAuthenticateEac2Parser.h +++ b/src/core/paos/retrieve/DidAuthenticateEac2Parser.h @@ -1,7 +1,7 @@ /*! * \brief Parse information for DidAuthenticateEac2. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +22,7 @@ class DidAuthenticateEac2Parser { public: DidAuthenticateEac2Parser(); - ~DidAuthenticateEac2Parser(); + virtual ~DidAuthenticateEac2Parser() override; protected: virtual PaosMessage* parseMessage() override; diff --git a/src/core/paos/retrieve/DidAuthenticateEacAdditional.cpp b/src/core/paos/retrieve/DidAuthenticateEacAdditional.cpp index 8389800..02c8f32 100644 --- a/src/core/paos/retrieve/DidAuthenticateEacAdditional.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEacAdditional.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DidAuthenticateEacAdditional.h" diff --git a/src/core/paos/retrieve/DidAuthenticateEacAdditional.h b/src/core/paos/retrieve/DidAuthenticateEacAdditional.h index 1b721a1..52f20a0 100644 --- a/src/core/paos/retrieve/DidAuthenticateEacAdditional.h +++ b/src/core/paos/retrieve/DidAuthenticateEacAdditional.h @@ -1,7 +1,7 @@ /*! * \brief Class to hold information of DIDAuthenticateEACAdditional. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.cpp b/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.cpp index 7066bb4..569c89b 100644 --- a/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.cpp +++ b/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEacAdditionalParser.h" @@ -72,14 +72,13 @@ PaosMessage* DidAuthenticateEacAdditionalParser::parseMessage() QString DidAuthenticateEacAdditionalParser::parseEacAdditionalInputType() { - QString signature; while (readNextStartElement()) { qCDebug(paos) << mXmlReader->name(); if (mXmlReader->name() == QLatin1String("Signature")) { - readUniqueElementText(signature); + Q_UNUSED(readUniqueElementText(signature)) } else { diff --git a/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.h b/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.h index 3a2b6b5..4bfd0b8 100644 --- a/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.h +++ b/src/core/paos/retrieve/DidAuthenticateEacAdditionalParser.h @@ -1,7 +1,7 @@ /*! * \brief Parse information for DidAuthenticateEacAdditional. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +22,7 @@ class DidAuthenticateEacAdditionalParser { public: DidAuthenticateEacAdditionalParser(); - ~DidAuthenticateEacAdditionalParser(); + virtual ~DidAuthenticateEacAdditionalParser() override; protected: virtual PaosMessage* parseMessage() override; diff --git a/src/core/paos/retrieve/DidList.cpp b/src/core/paos/retrieve/DidList.cpp index bd9c590..13d2337 100644 --- a/src/core/paos/retrieve/DidList.cpp +++ b/src/core/paos/retrieve/DidList.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "DidList.h" diff --git a/src/core/paos/retrieve/DidList.h b/src/core/paos/retrieve/DidList.h index 178bcb6..25d8dd8 100644 --- a/src/core/paos/retrieve/DidList.h +++ b/src/core/paos/retrieve/DidList.h @@ -1,9 +1,7 @@ /*! - * DidList.h - * * \brief Class represents the retrieved PAOS DIDList. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/Disconnect.cpp b/src/core/paos/retrieve/Disconnect.cpp index 85d3016..70de690 100644 --- a/src/core/paos/retrieve/Disconnect.cpp +++ b/src/core/paos/retrieve/Disconnect.cpp @@ -1,7 +1,5 @@ /*! - * Disconnect.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Disconnect.h" diff --git a/src/core/paos/retrieve/Disconnect.h b/src/core/paos/retrieve/Disconnect.h index ce55577..dc08e88 100644 --- a/src/core/paos/retrieve/Disconnect.h +++ b/src/core/paos/retrieve/Disconnect.h @@ -1,9 +1,7 @@ /*! - * Disconnect.h - * * \brief Class represents the retrieved PAOS Disconnect. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -27,7 +25,7 @@ class Disconnect public: Disconnect(const QByteArray& pXmlData); - virtual ~Disconnect(); + virtual ~Disconnect() override; const QString& getSlotHandle() const; }; diff --git a/src/core/paos/retrieve/InitializeFramework.cpp b/src/core/paos/retrieve/InitializeFramework.cpp index 5b608f1..fffa5af 100644 --- a/src/core/paos/retrieve/InitializeFramework.cpp +++ b/src/core/paos/retrieve/InitializeFramework.cpp @@ -1,9 +1,7 @@ /*! - * InitializeFramework.cpp - * * \brief Class represents the retrieved PAOS InitializeFramework * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/PaosType.h" diff --git a/src/core/paos/retrieve/InitializeFramework.h b/src/core/paos/retrieve/InitializeFramework.h index 4a48ded..e73be21 100644 --- a/src/core/paos/retrieve/InitializeFramework.h +++ b/src/core/paos/retrieve/InitializeFramework.h @@ -1,7 +1,7 @@ /*! * \brief Class to parse InitializeFramework from server. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/PaosParser.cpp b/src/core/paos/retrieve/PaosParser.cpp index 774c1d4..08bb7af 100644 --- a/src/core/paos/retrieve/PaosParser.cpp +++ b/src/core/paos/retrieve/PaosParser.cpp @@ -1,7 +1,5 @@ /*! - * PaosParser.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PaosParser.h" diff --git a/src/core/paos/retrieve/PaosParser.h b/src/core/paos/retrieve/PaosParser.h index ede440b..2e5b206 100644 --- a/src/core/paos/retrieve/PaosParser.h +++ b/src/core/paos/retrieve/PaosParser.h @@ -1,7 +1,7 @@ /*! * \brief Base class for PAOS message parsers. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/StartPaosResponse.cpp b/src/core/paos/retrieve/StartPaosResponse.cpp index 4d00586..6a05c1d 100644 --- a/src/core/paos/retrieve/StartPaosResponse.cpp +++ b/src/core/paos/retrieve/StartPaosResponse.cpp @@ -1,8 +1,7 @@ /*! - * StartPaosResponse.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ + #include "StartPaosResponse.h" using namespace governikus; diff --git a/src/core/paos/retrieve/StartPaosResponse.h b/src/core/paos/retrieve/StartPaosResponse.h index 989d0d1..07c9dcc 100644 --- a/src/core/paos/retrieve/StartPaosResponse.h +++ b/src/core/paos/retrieve/StartPaosResponse.h @@ -1,9 +1,7 @@ /*! - * StartPaosResponse.h - * * \brief Class represents the retrieved PAOS StartPaosResponse * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/Transmit.cpp b/src/core/paos/retrieve/Transmit.cpp index 19195ae..402eaea 100644 --- a/src/core/paos/retrieve/Transmit.cpp +++ b/src/core/paos/retrieve/Transmit.cpp @@ -1,7 +1,5 @@ /*! - * Transmit.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Transmit.h" diff --git a/src/core/paos/retrieve/Transmit.h b/src/core/paos/retrieve/Transmit.h index 3258526..5da1e68 100644 --- a/src/core/paos/retrieve/Transmit.h +++ b/src/core/paos/retrieve/Transmit.h @@ -1,9 +1,7 @@ /*! - * Transmit.h - * * \brief Transmit objects hold a transmit request and provide access to the transmitted data via member functions. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/paos/retrieve/TransmitParser.cpp b/src/core/paos/retrieve/TransmitParser.cpp index 8ac7b7e..d449707 100644 --- a/src/core/paos/retrieve/TransmitParser.cpp +++ b/src/core/paos/retrieve/TransmitParser.cpp @@ -1,7 +1,5 @@ /*! - * Transmit.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "TransmitParser.h" @@ -91,7 +89,7 @@ void TransmitParser::parseInputApduInfo() return; } - inputApduInfo.setInputApdu(inputApdu.toUtf8()); + inputApduInfo.setInputApdu(QByteArray::fromHex(inputApdu.toUtf8())); mTransmit->appendInputApduInfo(inputApduInfo); } diff --git a/src/core/paos/retrieve/TransmitParser.h b/src/core/paos/retrieve/TransmitParser.h index 1a304d0..c9878d7 100644 --- a/src/core/paos/retrieve/TransmitParser.h +++ b/src/core/paos/retrieve/TransmitParser.h @@ -1,9 +1,7 @@ /*! - * Transmit.h - * * \brief Parser for the PAOS Transmit element. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -22,7 +20,7 @@ class TransmitParser { public: TransmitParser(); - ~TransmitParser(); + virtual ~TransmitParser() override; protected: virtual PaosMessage* parseMessage() override; diff --git a/src/core/states/AbstractGenericState.h b/src/core/states/AbstractGenericState.h index 1930932..c84e81f 100644 --- a/src/core/states/AbstractGenericState.h +++ b/src/core/states/AbstractGenericState.h @@ -1,12 +1,10 @@ /*! - * AbstractGenericState.h - * * \brief Template base class for all steps taken by the state machine. * It is parameterized over the model type and contains a getter for the model. * We cannot parameterize the super class AbstractState because Qt does not * support template classes. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/AbstractState.cpp b/src/core/states/AbstractState.cpp index 89b507c..501fde5 100644 --- a/src/core/states/AbstractState.cpp +++ b/src/core/states/AbstractState.cpp @@ -1,7 +1,5 @@ /*! - * AbstractState.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AbstractState.h" @@ -22,6 +20,7 @@ AbstractState::AbstractState(const QSharedPointer& pContext, bo , mConnectOnCardRemoved(pConnectOnCardRemoved) , mConnections() { + Q_ASSERT(mContext); } @@ -46,9 +45,9 @@ void AbstractState::setStateName(const QString& pName) QString AbstractState::getClassName(const char* pName) { QString className = QString::fromLatin1(pName); - if (className.contains(':')) + if (className.contains(QLatin1Char(':'))) { - className = className.mid(className.lastIndexOf(':') + 1); + className = className.mid(className.lastIndexOf(QLatin1Char(':')) + 1); } return className; } @@ -67,7 +66,6 @@ void AbstractState::onStateApprovedChanged() void AbstractState::onEntry(QEvent* pEvent) { Q_UNUSED(pEvent); - Q_ASSERT(mConnections.isEmpty()); if (mConnectOnCardRemoved) { mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &AbstractState::onCardRemoved); @@ -84,15 +82,19 @@ void AbstractState::onEntry(QEvent* pEvent) void AbstractState::onExit(QEvent* pEvent) { QState::onExit(pEvent); + clearConnections(); + mContext->setStateApproved(false); + qCDebug(statemachine) << "Leaving state" << getStateName() << "with status:" << mContext->getStatus(); +} + + +void AbstractState::clearConnections() +{ for (const auto& connection : qAsConst(mConnections)) { QObject::disconnect(connection); } mConnections.clear(); - - mContext->setStateApproved(false); - - qCDebug(statemachine) << "Leaving state" << getStateName() << "with status:" << mContext->getStatus(); } @@ -105,8 +107,8 @@ bool AbstractState::isCancellationByUser() void AbstractState::onUserCancelled() { qCInfo(support) << "Cancellation by user"; - setStatus(GlobalStatus::Code::Workflow_Cancellation_By_User); - Q_EMIT fireCancel(); + updateStatus(GlobalStatus::Code::Workflow_Cancellation_By_User); + Q_EMIT fireAbort(); } @@ -114,13 +116,13 @@ void AbstractState::onCardRemoved(const QString& pReaderName) { if (pReaderName == mContext->getReaderName()) { - setStatus(GlobalStatus::Code::Workflow_Card_Removed); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Card_Removed); + Q_EMIT fireAbort(); } } -void AbstractState::setStatus(const GlobalStatus& pStatus) +void AbstractState::updateStatus(const GlobalStatus& pStatus) { if (pStatus.isError() && mContext->getStatus().isNoError()) { diff --git a/src/core/states/AbstractState.h b/src/core/states/AbstractState.h index 4f447f6..1739501 100644 --- a/src/core/states/AbstractState.h +++ b/src/core/states/AbstractState.h @@ -1,9 +1,7 @@ /*! - * AbstractState.h - * * \brief Base class for all states taken by the state machine. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -39,9 +37,9 @@ class AbstractState void onExit(QEvent* pEvent) override; - + void clearConnections(); bool isCancellationByUser(); - void setStatus(const GlobalStatus& pStatus); + void updateStatus(const GlobalStatus& pStatus); public: static QString getClassName(const char* pName); @@ -53,7 +51,7 @@ class AbstractState } - virtual ~AbstractState(); + virtual ~AbstractState() override; void onEntry(QEvent* pEvent) override; @@ -61,9 +59,8 @@ class AbstractState void setStateName(const QString& pName); Q_SIGNALS: - void fireSuccess(); - void fireError(); - void fireCancel(); + void fireContinue(); + void fireAbort(); public Q_SLOTS: void onStateApprovedChanged(); diff --git a/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp b/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp index 3205b71..6e5e53f 100644 --- a/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp +++ b/src/core/states/CompositeStateProcessCvcsAndSetRights.cpp @@ -1,7 +1,5 @@ /*! - * CompositeStateSelectCard.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "CompositeStateProcessCvcsAndSetRights.h" @@ -11,7 +9,7 @@ #include "states/StateCertificateDescriptionCheck.h" #include "states/StateCheckCertificates.h" #include "states/StateEditAccessRights.h" -#include "states/StateExtractCvcsFromEac1IntputType.h" +#include "states/StateExtractCvcsFromEac1InputType.h" #include "states/StatePreVerification.h" @@ -22,7 +20,7 @@ CompositeStateProcessCvcsAndSetRights::CompositeStateProcessCvcsAndSetRights(con : QState() , mContext(pContext) { - auto sExtractCvcsFromEac1InputType = StateBuilder::createState(mContext); + auto sExtractCvcsFromEac1InputType = StateBuilder::createState(mContext); auto sPreVerification = StateBuilder::createState(mContext); auto sCertificateDescriptionCheck = StateBuilder::createState(mContext); auto sCheckCertificates = StateBuilder::createState(mContext); @@ -36,25 +34,20 @@ CompositeStateProcessCvcsAndSetRights::CompositeStateProcessCvcsAndSetRights(con setInitialState(sExtractCvcsFromEac1InputType); - sExtractCvcsFromEac1InputType->addTransition(sExtractCvcsFromEac1InputType, &AbstractState::fireSuccess, sPreVerification); - connect(sExtractCvcsFromEac1InputType, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sExtractCvcsFromEac1InputType, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); + sExtractCvcsFromEac1InputType->addTransition(sExtractCvcsFromEac1InputType, &AbstractState::fireContinue, sPreVerification); + connect(sExtractCvcsFromEac1InputType, &AbstractState::fireAbort, this, &CompositeStateProcessCvcsAndSetRights::fireAbort); - sPreVerification->addTransition(sPreVerification, &AbstractState::fireSuccess, sCertificateDescriptionCheck); - connect(sPreVerification, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sPreVerification, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); + sPreVerification->addTransition(sPreVerification, &AbstractState::fireContinue, sCertificateDescriptionCheck); + connect(sPreVerification, &AbstractState::fireAbort, this, &CompositeStateProcessCvcsAndSetRights::fireAbort); - sCertificateDescriptionCheck->addTransition(sCertificateDescriptionCheck, &AbstractState::fireSuccess, sCheckCertificates); - connect(sCertificateDescriptionCheck, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sCertificateDescriptionCheck, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); + sCertificateDescriptionCheck->addTransition(sCertificateDescriptionCheck, &AbstractState::fireContinue, sCheckCertificates); + connect(sCertificateDescriptionCheck, &AbstractState::fireAbort, this, &CompositeStateProcessCvcsAndSetRights::fireAbort); - sCheckCertificates->addTransition(sCheckCertificates, &AbstractState::fireSuccess, sEditAccessRights); - connect(sCheckCertificates, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sCheckCertificates, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); + sCheckCertificates->addTransition(sCheckCertificates, &AbstractState::fireContinue, sEditAccessRights); + connect(sCheckCertificates, &AbstractState::fireAbort, this, &CompositeStateProcessCvcsAndSetRights::fireAbort); - connect(sEditAccessRights, &AbstractState::fireSuccess, this, &CompositeStateProcessCvcsAndSetRights::fireSuccess); - connect(sEditAccessRights, &AbstractState::fireError, this, &CompositeStateProcessCvcsAndSetRights::fireError); - connect(sEditAccessRights, &AbstractState::fireCancel, this, &CompositeStateProcessCvcsAndSetRights::fireCancel); + connect(sEditAccessRights, &AbstractState::fireContinue, this, &CompositeStateProcessCvcsAndSetRights::fireContinue); + connect(sEditAccessRights, &AbstractState::fireAbort, this, &CompositeStateProcessCvcsAndSetRights::fireAbort); } diff --git a/src/core/states/CompositeStateProcessCvcsAndSetRights.h b/src/core/states/CompositeStateProcessCvcsAndSetRights.h index 1b4e91e..adfc680 100644 --- a/src/core/states/CompositeStateProcessCvcsAndSetRights.h +++ b/src/core/states/CompositeStateProcessCvcsAndSetRights.h @@ -1,9 +1,7 @@ /*! - * CompositeStateSelectCard.h - * * \brief Composite state for selecting a card. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -29,9 +27,8 @@ class CompositeStateProcessCvcsAndSetRights virtual ~CompositeStateProcessCvcsAndSetRights(); Q_SIGNALS: - void fireSuccess(); - void fireCancel(); - void fireError(); + void fireContinue(); + void fireAbort(); }; } /* namespace governikus */ diff --git a/src/core/states/CompositeStateSelectCard.cpp b/src/core/states/CompositeStateSelectCard.cpp index 434a1e9..f87f21b 100644 --- a/src/core/states/CompositeStateSelectCard.cpp +++ b/src/core/states/CompositeStateSelectCard.cpp @@ -1,7 +1,5 @@ /*! - * CompositeStateSelectCard.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "CompositeStateSelectCard.h" @@ -9,11 +7,7 @@ #include "context/WorkflowContext.h" #include "states/StateBuilder.h" #include "states/StateConnectCard.h" -#include "states/StateSelectBluetoothReader.h" -#include "states/StateSelectNfcReader.h" -#include "states/StateSelectPcscReader.h" -#include "states/StateSelectReaderType.h" - +#include "states/StateSelectReader.h" using namespace governikus; @@ -22,46 +16,22 @@ CompositeStateSelectCard::CompositeStateSelectCard(const QSharedPointer(mContext); - auto selectBluetoothReader = StateBuilder::createState(mContext); - auto selectNfcReader = StateBuilder::createState(mContext); - auto selectPcscReader = StateBuilder::createState(mContext); + auto selectReader = StateBuilder::createState(mContext); auto connectCard = StateBuilder::createState(mContext); - selectReaderType->setParent(this); - selectBluetoothReader->setParent(this); - selectNfcReader->setParent(this); - selectPcscReader->setParent(this); + selectReader->setParent(this); connectCard->setParent(this); - setInitialState(selectReaderType); + setInitialState(selectReader); - selectReaderType->addTransition(selectReaderType, &StateSelectReaderType::fireSelectBluetoothReader, selectBluetoothReader); - selectReaderType->addTransition(selectReaderType, &StateSelectReaderType::fireSelectNfcReader, selectNfcReader); - selectReaderType->addTransition(selectReaderType, &StateSelectReaderType::fireSelectPcscReader, selectPcscReader); - connect(selectReaderType, &AbstractState::fireError, this, &CompositeStateSelectCard::fireError); - connect(selectReaderType, &AbstractState::fireCancel, this, &CompositeStateSelectCard::fireCancel); + selectReader->addTransition(selectReader, &StateSelectReader::fireRetry, selectReader); + selectReader->addTransition(selectReader, &AbstractState::fireContinue, connectCard); + connect(selectReader, &AbstractState::fireAbort, this, &CompositeStateSelectCard::fireAbort); - selectBluetoothReader->addTransition(selectBluetoothReader, &AbstractState::fireSuccess, connectCard); - connect(selectBluetoothReader, &AbstractState::fireError, this, &CompositeStateSelectCard::fireError); - connect(selectBluetoothReader, &AbstractState::fireCancel, this, &CompositeStateSelectCard::fireCancel); - selectBluetoothReader->addTransition(selectBluetoothReader, &StateSelectBluetoothReader::fireAbort, selectReaderType); - - selectNfcReader->addTransition(selectNfcReader, &AbstractState::fireSuccess, connectCard); - connect(selectNfcReader, &AbstractState::fireError, this, &CompositeStateSelectCard::fireError); - connect(selectNfcReader, &AbstractState::fireCancel, this, &CompositeStateSelectCard::fireCancel); - selectNfcReader->addTransition(selectNfcReader, &StateSelectNfcReader::fireAbort, selectReaderType); - - selectPcscReader->addTransition(selectPcscReader, &AbstractState::fireSuccess, connectCard); - connect(selectPcscReader, &AbstractState::fireError, this, &CompositeStateSelectCard::fireError); - connect(selectPcscReader, &AbstractState::fireCancel, this, &CompositeStateSelectCard::fireCancel); - selectPcscReader->addTransition(selectPcscReader, &StateSelectPcscReader::fireAbort, selectReaderType); - - connect(connectCard, &AbstractState::fireSuccess, this, &CompositeStateSelectCard::fireSuccess); - connect(connectCard, &AbstractState::fireError, this, &CompositeStateSelectCard::fireError); - connect(connectCard, &AbstractState::fireCancel, this, &CompositeStateSelectCard::fireCancel); - connectCard->addTransition(connectCard, &StateConnectCard::fireAbort, selectReaderType); - connectCard->addTransition(connectCard, &StateConnectCard::fireReaderRemoved, selectReaderType); + connectCard->addTransition(connectCard, &StateConnectCard::fireRetry, selectReader); + connectCard->addTransition(connectCard, &StateConnectCard::fireReaderRemoved, selectReader); + connect(connectCard, &AbstractState::fireContinue, this, &CompositeStateSelectCard::fireContinue); + connect(connectCard, &AbstractState::fireAbort, this, &CompositeStateSelectCard::fireAbort); } diff --git a/src/core/states/CompositeStateSelectCard.h b/src/core/states/CompositeStateSelectCard.h index 850ce31..31d7d69 100644 --- a/src/core/states/CompositeStateSelectCard.h +++ b/src/core/states/CompositeStateSelectCard.h @@ -1,9 +1,7 @@ /*! - * CompositeStateSelectCard.h - * * \brief Composite state for selecting a card. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -29,9 +27,8 @@ class CompositeStateSelectCard virtual ~CompositeStateSelectCard(); Q_SIGNALS: - void fireSuccess(); - void fireCancel(); - void fireError(); + void fireContinue(); + void fireAbort(); }; } /* namespace governikus */ diff --git a/src/core/states/FinalState.cpp b/src/core/states/FinalState.cpp index 1fb6465..939b041 100644 --- a/src/core/states/FinalState.cpp +++ b/src/core/states/FinalState.cpp @@ -1,7 +1,5 @@ /*! - * FinalError.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "states/FinalState.h" @@ -19,9 +17,11 @@ void FinalState::run() // the state machine and since we do not want to alter our ctor pattern. QFinalState* sStopMachine = new QFinalState(); machine()->addState(sStopMachine); - addTransition(this, &AbstractState::fireSuccess, sStopMachine); - addTransition(this, &AbstractState::fireError, sStopMachine); - addTransition(this, &AbstractState::fireCancel, sStopMachine); + addTransition(this, &AbstractState::fireContinue, sStopMachine); + addTransition(this, &AbstractState::fireAbort, sStopMachine); - Q_EMIT fireSuccess(); + // Clear plugin types and disconnect all readers when the workflow has completed. + getContext()->setReaderPlugInTypes({}); + + Q_EMIT fireContinue(); } diff --git a/src/core/states/FinalState.h b/src/core/states/FinalState.h index daab9ed..28f5330 100644 --- a/src/core/states/FinalState.h +++ b/src/core/states/FinalState.h @@ -1,9 +1,7 @@ /*! - * FinalState.h - * * \brief A final state which blocks the state machine before termination. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateBuilder.h b/src/core/states/StateBuilder.h index 6dae5aa..321445f 100644 --- a/src/core/states/StateBuilder.h +++ b/src/core/states/StateBuilder.h @@ -1,9 +1,7 @@ /*! - * StateBuilder.h - * * \brief Builder for states. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateCertificateDescriptionCheck.cpp b/src/core/states/StateCertificateDescriptionCheck.cpp index bca1542..27fb829 100644 --- a/src/core/states/StateCertificateDescriptionCheck.cpp +++ b/src/core/states/StateCertificateDescriptionCheck.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateCertificateDescriptionCheck.h" @@ -26,28 +26,29 @@ void StateCertificateDescriptionCheck::run() { Q_ASSERT(getContext()->getTerminalCvc()); Q_ASSERT(!getContext()->getDidAuthenticateEac1().isNull()); - auto terminalCertificate = getContext()->getTerminalCvc(); + const auto& terminalCertificate = getContext()->getTerminalCvc(); if (getContext()->getDidAuthenticateEac1()->getCertificateDescriptionAsBinary().isNull()) { qCritical() << "No certificate description available"; - setStatus(GlobalStatus::Code::Workflow_Certificate_No_Description); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Certificate_No_Description); + Q_EMIT fireAbort(); return; } if (getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl().isNull()) { qCritical() << "No subject url available in certificate description"; - setStatus(GlobalStatus::Code::Workflow_Certificate_No_Url_In_Description); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Certificate_No_Url_In_Description); + Q_EMIT fireAbort(); return; } QCryptographicHash hashCalculator(terminalCertificate->getBody().getHashAlgorithm()); hashCalculator.addData(getContext()->getDidAuthenticateEac1()->getCertificateDescriptionAsBinary()); - const QByteArray hashOfDescription = terminalCertificate->getBody().getExtensions().value(KnownOIDs::CertificateExtensions::id_description); + const auto& idDescOid = toByteArray(KnownOIDs::CertificateExtensions::ID_DESCRIPTION); + const QByteArray& hashOfDescription = terminalCertificate->getBody().getExtensions().value(idDescOid); if (hashCalculator.result() != hashOfDescription) { auto certificateHashError = QStringLiteral("The certificate description does not match the certificate."); @@ -58,14 +59,14 @@ void StateCertificateDescriptionCheck::run() else { qCritical() << certificateHashError; - setStatus(GlobalStatus::Code::Workflow_Certificate_Hash_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Certificate_Hash_Error); + Q_EMIT fireAbort(); return; } } // check same origin policy for TCToken URL and subject URL - QUrl subjectUrl = getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl(); + const QUrl& subjectUrl = getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getSubjectUrl(); if (!UrlUtil::isMatchingSameOriginPolicy(subjectUrl, getContext()->getTcTokenUrl())) { auto sameOriginPolicyError = QStringLiteral("The subject URL in the certificate description and the TCToken URL don't satisfy the same origin policy."); @@ -76,11 +77,11 @@ void StateCertificateDescriptionCheck::run() else { qCritical() << sameOriginPolicyError; - setStatus(GlobalStatus::Code::Workflow_Certificate_Sop_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Certificate_Sop_Error); + Q_EMIT fireAbort(); return; } } - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateCertificateDescriptionCheck.h b/src/core/states/StateCertificateDescriptionCheck.h index c148e98..29cf41f 100644 --- a/src/core/states/StateCertificateDescriptionCheck.h +++ b/src/core/states/StateCertificateDescriptionCheck.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateChangePin.cpp b/src/core/states/StateChangePin.cpp index 5aa5459..acdedcf 100644 --- a/src/core/states/StateChangePin.cpp +++ b/src/core/states/StateChangePin.cpp @@ -1,7 +1,5 @@ /*! - * StateChangePin.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderManager.h" @@ -34,22 +32,22 @@ void StateChangePin::onSetEidPinDone(QSharedPointer pCommand) { case CardReturnCode::OK: getContext()->setSuccessMessage(tr("You have successfully changed your PIN.")); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); break; case CardReturnCode::CANCELLATION_BY_USER: - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireCancel(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; case CardReturnCode::NEW_PIN_MISMATCH: - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireInvalidPin(); break; default: - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireError(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; } } diff --git a/src/core/states/StateChangePin.h b/src/core/states/StateChangePin.h index 658597d..88f589e 100644 --- a/src/core/states/StateChangePin.h +++ b/src/core/states/StateChangePin.h @@ -1,7 +1,7 @@ /*! * \brief Controller for the state changing the PIN. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateCheckCertificates.cpp b/src/core/states/StateCheckCertificates.cpp index 1589085..99730ca 100644 --- a/src/core/states/StateCheckCertificates.cpp +++ b/src/core/states/StateCheckCertificates.cpp @@ -1,13 +1,11 @@ /*! - * StateCheckCertificates.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateCheckCertificates.h" #include "AppSettings.h" -#include "CertificateChecker.h" +#include "TlsChecker.h" using namespace governikus; @@ -22,14 +20,14 @@ StateCheckCertificates::StateCheckCertificates(const QSharedPointergetDidAuthenticateEac1()->getCertificateDescription()->getCommCertificates(); - auto hashAlgorithm = getContext()->getDvCvc()->getBody().getHashAlgorithm(); + const auto& commCertificates = getContext()->getDidAuthenticateEac1()->getCertificateDescription()->getCommCertificates(); + const auto& hashAlgorithm = getContext()->getDvCvc()->getBody().getHashAlgorithm(); // check the certificates we've encountered so far - const auto certList = getContext()->getCertificateList(); + const auto& certList = getContext()->getCertificateList(); for (const auto& certificate : certList) { - if (!CertificateChecker::checkCertificate(certificate, hashAlgorithm, commCertificates)) + if (!TlsChecker::checkCertificate(certificate, hashAlgorithm, commCertificates)) { auto certificateDescError = QStringLiteral("Hash of certificate not in certificate description"); if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) @@ -39,11 +37,11 @@ void StateCheckCertificates::run() else { qCritical() << certificateDescError; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description); + Q_EMIT fireAbort(); return; } } } - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateCheckCertificates.h b/src/core/states/StateCheckCertificates.h index cb83683..929caa6 100644 --- a/src/core/states/StateCheckCertificates.h +++ b/src/core/states/StateCheckCertificates.h @@ -1,11 +1,9 @@ /*! - * StateCheckCertificates.h - * * \brief Checks whether the hashes of the certificates encountered so far * (i.e. those stored in the AuthContext) are in the CertificateDescription * extension of the eService certificate. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateCheckError.cpp b/src/core/states/StateCheckError.cpp index f3bbbde..df80376 100644 --- a/src/core/states/StateCheckError.cpp +++ b/src/core/states/StateCheckError.cpp @@ -1,7 +1,5 @@ /*! - * StateCheckError.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateCheckError.h" @@ -18,9 +16,9 @@ void StateCheckError::run() { if (getContext()->getStatus().isNoError() || getContext()->isErrorReportedToUser()) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } - Q_EMIT fireError(); + Q_EMIT fireAbort(); } diff --git a/src/core/states/StateCheckError.h b/src/core/states/StateCheckError.h index 48972cc..61fc159 100644 --- a/src/core/states/StateCheckError.h +++ b/src/core/states/StateCheckError.h @@ -1,10 +1,8 @@ /*! - * StateCheckError.h - * * \brief Helper state to decide whether an error has been occurred that should * be reported to the user. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateCheckRefreshAddress.cpp b/src/core/states/StateCheckRefreshAddress.cpp index fe80874..fbb3814 100644 --- a/src/core/states/StateCheckRefreshAddress.cpp +++ b/src/core/states/StateCheckRefreshAddress.cpp @@ -1,16 +1,16 @@ /*! - * StateCheckRefreshAddress.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateCheckRefreshAddress.h" +#include "AppSettings.h" #include "CertificateChecker.h" +#include "Env.h" #include "HttpStatusCode.h" #include "NetworkManager.h" #include "StateRedirectBrowser.h" -#include "TlsConfiguration.h" +#include "TlsChecker.h" #include "UrlUtil.h" #include @@ -23,6 +23,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(developermode) +Q_DECLARE_LOGGING_CATEGORY(network) StateCheckRefreshAddress::StateCheckRefreshAddress(const QSharedPointer& pContext) @@ -30,7 +31,6 @@ StateCheckRefreshAddress::StateCheckRefreshAddress(const QSharedPointergetTcToken()) + const auto tcToken = getContext()->getTcToken(); + + if (!tcToken) { qDebug() << "Invalid TCToken"; - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } - mUrl = getContext()->getTcToken()->getRefreshAddress(); + if (tcToken->usePsk()) + { + // When the tcToken provided a psk, it is necessary to clear + // all connections to force new connections without psk settings + // after we finished the authentication communication. + Env::getSingleton()->clearConnections(); + } + + mUrl = tcToken->getRefreshAddress(); auto refreshAddrError = QStringLiteral("Invalid RefreshAddress: %1").arg(mUrl.toString()); if (!mUrl.isValid()) { qDebug() << refreshAddrError; - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } if (mUrl.scheme() != QLatin1String("https")) @@ -62,7 +72,7 @@ void StateCheckRefreshAddress::run() else { qDebug() << refreshAddrError; - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } } @@ -122,7 +132,7 @@ void StateCheckRefreshAddress::sendGetRequest() qDebug() << "Send GET request to URL: " << mUrl.toString(); QNetworkRequest request(mUrl); - mReply = getContext()->getNetworkManager().get(request); + mReply = Env::getSingleton()->get(request); mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDone); mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateCheckRefreshAddress::onNetworkReply); @@ -131,7 +141,7 @@ void StateCheckRefreshAddress::sendGetRequest() void StateCheckRefreshAddress::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(mReply, pErrors)) + if (TlsChecker::containsFatalError(mReply, pErrors)) { reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Ssl_Establishment_Error)); } @@ -141,14 +151,17 @@ void StateCheckRefreshAddress::onSslErrors(const QList& pErrors) void StateCheckRefreshAddress::reportCommunicationError(const GlobalStatus& pStatus) { qCritical() << pStatus; - setStatus(pStatus); - Q_EMIT fireError(); + updateStatus(pStatus); + Q_EMIT fireAbort(); } void StateCheckRefreshAddress::onSslHandshakeDone() { - if (!checkSslConnectionAndSaveCertificate(mReply->sslConfiguration())) + const auto& cfg = mReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); + + if (!checkSslConnectionAndSaveCertificate(cfg)) { // checkAndSaveCertificate already set the error mReply->abort(); @@ -158,12 +171,17 @@ void StateCheckRefreshAddress::onSslHandshakeDone() bool StateCheckRefreshAddress::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(); + const QSharedPointer& context = getContext(); + Q_ASSERT(!context.isNull()); - switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), mUrl, getContext())) + std::function saveCertificateFunc = [&] + (const QUrl& pUrl, const QSslCertificate& pCertificate) + { + mVerifiedRefreshUrlHosts += pUrl; + context->addCertificateData(pUrl, pCertificate); + }; + + switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), mUrl, context->getDidAuthenticateEac1(), context->getDvCvc(), saveCertificateFunc)) { case CertificateChecker::CertificateStatus::Good: break; @@ -177,9 +195,9 @@ bool StateCheckRefreshAddress::checkSslConnectionAndSaveCertificate(const QSslCo return false; } - if (!CertificateChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) + if (!TlsChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) { - reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length)); + reportCommunicationError(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length); return false; } @@ -192,12 +210,20 @@ void StateCheckRefreshAddress::onNetworkReply() int statusCode = mReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QUrl redirectUrl = mReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); qDebug() << "Status Code: " << statusCode << " | redirect URL: " << redirectUrl; + for (const auto& header : mReply->rawHeaderPairs()) + { + qCDebug(network).nospace() << "Header | " << header.first << ": " << header.second; + } if (mReply->error() != QNetworkReply::NoError) { qCritical() << "An error occured: " << mReply->errorString(); switch (NetworkManager::toNetworkError(mReply.data())) { + case NetworkManager::NetworkError::ServiceUnavailable: + reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_ServiceUnavailable)); + break; + case NetworkManager::NetworkError::TimeOut: reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_TimeOut)); break; @@ -285,22 +311,22 @@ void StateCheckRefreshAddress::fetchServerCertificate() * * But keep attention: ONLY IF THE SERVER CERTIFICATE WAS COLLECTED DURING DETERMINATION OF THE REFRESH URL *NOT* DURING DETERMINATION OF THE TCTOKEN. */ - - // if (getContext()->containsCertificateFor(mUrl)) - // { - // qDebug() << "SSL certificate already collected for" << mUrl; - // doneSuccess(); - // return; - // } + if (mVerifiedRefreshUrlHosts.contains(mUrl)) + { + qDebug() << "SSL certificate already collected for" << mUrl; + doneSuccess(); + return; + } qDebug() << "Fetch TLS certificate for URL" << mUrl; QNetworkRequest request(mUrl); - // use a separate NetworkManager to ensure a fresh connection is established and the encrypted signal is emitted, - // see Qt documentation QNetworkReply::encrypted(): + // Clear all connections to ensure a fresh connection is established and the + // encrypted signal is emitted, see Qt documentation QNetworkReply::encrypted(): // // "...This means that you are only guaranteed to receive this signal for the first connection to a site in the lifespan of the QNetworkAccessManager." - mReply = mNetworkManager.get(request); + Env::getSingleton()->clearConnections(); + mReply = Env::getSingleton()->get(request); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateCheckRefreshAddress::onSslHandshakeDoneFetchingServerCertificate); mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateCheckRefreshAddress::onSslErrors); @@ -310,7 +336,10 @@ void StateCheckRefreshAddress::fetchServerCertificate() void StateCheckRefreshAddress::onSslHandshakeDoneFetchingServerCertificate() { - if (checkSslConnectionAndSaveCertificate(mReply->sslConfiguration())) + const auto& cfg = mReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); + + if (checkSslConnectionAndSaveCertificate(cfg)) { doneSuccess(); } @@ -328,8 +357,7 @@ void StateCheckRefreshAddress::doneSuccess() { getContext()->setRefreshUrl(mUrl); qDebug() << "Determined RefreshUrl: " << mUrl; - - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateCheckRefreshAddress.h b/src/core/states/StateCheckRefreshAddress.h index 5b84b2c..2ceb700 100644 --- a/src/core/states/StateCheckRefreshAddress.h +++ b/src/core/states/StateCheckRefreshAddress.h @@ -1,10 +1,8 @@ /*! - * StateCheckRefreshAddress.h - * * \brief Calls the RefreshAddress of TcToken and checks the certificates. * After that it will set RedirectAddress in WorkflowContext. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -36,8 +34,8 @@ class StateCheckRefreshAddress QPointer mReply; QUrl mUrl; QUrl mSubjectUrl; - NetworkManager mNetworkManager; bool mCertificateFetched; + QVector mVerifiedRefreshUrlHosts; virtual void run() override; diff --git a/src/core/states/StateCleanUpReaderManager.cpp b/src/core/states/StateCleanUpReaderManager.cpp index f7c43af..fabc70b 100644 --- a/src/core/states/StateCleanUpReaderManager.cpp +++ b/src/core/states/StateCleanUpReaderManager.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ReaderManager.h" @@ -17,7 +17,7 @@ StateCleanUpReaderManager::StateCleanUpReaderManager(const QSharedPointergetCardConnection()) { @@ -27,5 +27,5 @@ void StateCleanUpReaderManager::run() qDebug() << "Going to disconnect readers"; ReaderManager::getInstance().disconnectAllReaders(); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateCleanUpReaderManager.h b/src/core/states/StateCleanUpReaderManager.h index a36e5be..c8f3b0f 100644 --- a/src/core/states/StateCleanUpReaderManager.h +++ b/src/core/states/StateCleanUpReaderManager.h @@ -2,7 +2,7 @@ * \brief Performs clean up of the ReaderManager, * e.g. disconnects all readers, clears the card connection, ... * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateConnectCard.cpp b/src/core/states/StateConnectCard.cpp index dd750b6..0568c0d 100644 --- a/src/core/states/StateConnectCard.cpp +++ b/src/core/states/StateConnectCard.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -7,6 +7,10 @@ #include "Result.h" #include "StateConnectCard.h" +#include + +Q_DECLARE_LOGGING_CATEGORY(statemachine) + using namespace governikus; StateConnectCard::StateConnectCard(const QSharedPointer& pContext) @@ -17,10 +21,11 @@ StateConnectCard::StateConnectCard(const QSharedPointer& pConte void StateConnectCard::run() { - qDebug() << "StateConnectCard::run()"; + qCDebug(statemachine) << "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::onAbort); + mConnections += connect(getContext().data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateConnectCard::fireRetry); onCardInserted(); } @@ -28,11 +33,11 @@ void StateConnectCard::run() void StateConnectCard::onCardInserted() { ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); - if (readerInfo.getCardType() == CardType::EID_CARD) + if (readerInfo.hasEidCard()) { if (!readerInfo.isPinDeactivated()) { - qDebug() << "Card has been inserted, trying to connect"; + qCDebug(statemachine) << "Card has been inserted, trying to connect"; mConnections += ReaderManager::getInstance().callCreateCardConnectionCommand(readerInfo.getName(), this, &StateConnectCard::onCommandDone); } } @@ -41,17 +46,17 @@ void StateConnectCard::onCardInserted() void StateConnectCard::onCommandDone(QSharedPointer pCommand) { - qDebug() << "Card connection command completed"; + qCDebug(statemachine) << "Card connection command completed"; if (pCommand->getCardConnection() == nullptr) { - setStatus(GlobalStatus::Code::Workflow_Reader_Communication_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Reader_Communication_Error); + Q_EMIT fireAbort(); return; } - qDebug() << "Card connection was successful"; + qCDebug(statemachine) << "Card connection was successful"; getContext()->setCardConnection(pCommand->getCardConnection()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } @@ -66,10 +71,15 @@ void StateConnectCard::onReaderRemoved(const QString& pReaderName) void StateConnectCard::onAbort() { - ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); - if (readerInfo.isValid() && readerInfo.isConnected()) + const QSharedPointer context = getContext(); + Q_ASSERT(context); + + ReaderManager::getInstance().stopScanAll(); + + ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(context->getReaderName()); + if (readerInfo.isConnected()) { ReaderManager::getInstance().disconnectReader(readerInfo.getName()); } - Q_EMIT fireAbort(); + Q_EMIT fireRetry(); } diff --git a/src/core/states/StateConnectCard.h b/src/core/states/StateConnectCard.h index 1f9189f..4e36232 100644 --- a/src/core/states/StateConnectCard.h +++ b/src/core/states/StateConnectCard.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,7 +26,7 @@ class StateConnectCard void onAbort(); Q_SIGNALS: - void fireAbort(); + void fireRetry(); void fireReaderRemoved(); }; diff --git a/src/core/states/StateDestroyPace.cpp b/src/core/states/StateDestroyPace.cpp index 11e1082..17ea07f 100644 --- a/src/core/states/StateDestroyPace.cpp +++ b/src/core/states/StateDestroyPace.cpp @@ -1,7 +1,5 @@ /*! - * StateDestroyPace.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ @@ -27,5 +25,5 @@ void StateDestroyPace::run() void StateDestroyPace::onDestroyPaceDone(QSharedPointer ) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateDestroyPace.h b/src/core/states/StateDestroyPace.h index 3e9fdd1..eeb823d 100644 --- a/src/core/states/StateDestroyPace.h +++ b/src/core/states/StateDestroyPace.h @@ -1,7 +1,7 @@ /*! * \brief Controller for the step that tries to destroy an existing PACE connection. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateDidAuthenticateEac1.cpp b/src/core/states/StateDidAuthenticateEac1.cpp index ba23e5e..9adf28d 100644 --- a/src/core/states/StateDidAuthenticateEac1.cpp +++ b/src/core/states/StateDidAuthenticateEac1.cpp @@ -1,7 +1,5 @@ /*! - * StateDidAuthenticateEac1.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/CVCertificateChainBuilder.h" @@ -54,11 +52,11 @@ void StateDidAuthenticateEac1::onCardCommandDone(QSharedPointer qDebug() << "No cvc chain determined, request new cvc list"; eac1Response->setCertificationAuthorityReference(*paceOutput); } - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { - setStatus(CardReturnCodeUtil::toGlobalStatus(result)); - Q_EMIT fireError(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(result)); + Q_EMIT fireAbort(); } } diff --git a/src/core/states/StateDidAuthenticateEac1.h b/src/core/states/StateDidAuthenticateEac1.h index d6b8e18..a0fe17c 100644 --- a/src/core/states/StateDidAuthenticateEac1.h +++ b/src/core/states/StateDidAuthenticateEac1.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateDidAuthenticateEac2.cpp b/src/core/states/StateDidAuthenticateEac2.cpp index 48a3676..a9bf8aa 100644 --- a/src/core/states/StateDidAuthenticateEac2.cpp +++ b/src/core/states/StateDidAuthenticateEac2.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/CVCertificate.h" @@ -37,8 +37,8 @@ void StateDidAuthenticateEac2::run() auto cvcChain = getContext()->getChainForCertificationAuthority(*getContext()->getPaceOutputData()); if (!cvcChain.isValid()) { - setStatus(GlobalStatus::Code::Workflow_No_Permission_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_No_Permission_Error); + Q_EMIT fireAbort(); return; } @@ -49,10 +49,11 @@ void StateDidAuthenticateEac2::run() void StateDidAuthenticateEac2::onCardCommandDone(QSharedPointer pCommand) { - if (pCommand->getReturnCode() != CardReturnCode::OK) + const CardReturnCode returnCode = pCommand->getReturnCode(); + if (returnCode != CardReturnCode::OK) { - setStatus(GlobalStatus::Code::Workflow_No_Permission_Error); - Q_EMIT fireError(); + updateStatus(returnCode == CardReturnCode::COMMAND_FAILED ? GlobalStatus::Code::Workflow_Card_Removed : GlobalStatus::Code::Workflow_No_Permission_Error); + Q_EMIT fireAbort(); } auto eac2Command = pCommand.staticCast(); @@ -61,5 +62,5 @@ void StateDidAuthenticateEac2::onCardCommandDone(QSharedPointer response->setEfCardSecurity(eac2Command->getEfCardSecurityAsHex()); response->setNonce(eac2Command->getNonceAsHex()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateDidAuthenticateEac2.h b/src/core/states/StateDidAuthenticateEac2.h index f191618..56d49dc 100644 --- a/src/core/states/StateDidAuthenticateEac2.h +++ b/src/core/states/StateDidAuthenticateEac2.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateDidList.cpp b/src/core/states/StateDidList.cpp index 5ae7040..80dc837 100644 --- a/src/core/states/StateDidList.cpp +++ b/src/core/states/StateDidList.cpp @@ -1,7 +1,5 @@ /*! - * StateDidList.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/DidListResponse.h" @@ -20,5 +18,5 @@ StateDidList::StateDidList(const QSharedPointer& pContext) void StateDidList::run() { Q_ASSERT(!getContext()->getDidList().isNull()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateDidList.h b/src/core/states/StateDidList.h index 85acad2..67ff08b 100644 --- a/src/core/states/StateDidList.h +++ b/src/core/states/StateDidList.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateEACAdditionalInputType.cpp b/src/core/states/StateEACAdditionalInputType.cpp index 58d36a2..7512d7c 100644 --- a/src/core/states/StateEACAdditionalInputType.cpp +++ b/src/core/states/StateEACAdditionalInputType.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateEACAdditionalInputType.h" @@ -17,7 +17,7 @@ void StateEACAdditionalInputType::run() Q_ASSERT(!getContext()->getDidAuthenticateEac2().isNull()); if (!getContext()->getDidAuthenticateEac2()->getSignature().isEmpty()) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { diff --git a/src/core/states/StateEACAdditionalInputType.h b/src/core/states/StateEACAdditionalInputType.h index c674dbb..14d2b73 100644 --- a/src/core/states/StateEACAdditionalInputType.h +++ b/src/core/states/StateEACAdditionalInputType.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateEditAccessRights.cpp b/src/core/states/StateEditAccessRights.cpp index fe4acc7..afe4839 100644 --- a/src/core/states/StateEditAccessRights.cpp +++ b/src/core/states/StateEditAccessRights.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "StateEditAccessRights.h" @@ -14,5 +14,5 @@ StateEditAccessRights::StateEditAccessRights(const QSharedPointercallEstablishPaceChannelCommand(this, &StateEstablishPaceCan::onEstablishConnectionDone, PACE_PIN_ID::PACE_CAN, getContext()->getCan()); + mConnections += cardConnection->callEstablishPaceChannelCommand(this, &StateEstablishPaceCan::onEstablishConnectionDone, PACE_PASSWORD_ID::PACE_CAN, getContext()->getCan()); getContext()->setCan(QString()); } @@ -40,13 +38,13 @@ void StateEstablishPaceCan::onEstablishConnectionDone(QSharedPointersetLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); break; case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireCancel(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; case CardReturnCode::INVALID_CAN: @@ -55,8 +53,8 @@ void StateEstablishPaceCan::onEstablishConnectionDone(QSharedPointercallEstablishPaceChannelCommand(this, &StateEstablishPacePin::onEstablishConnectionDone, - PACE_PIN_ID::PACE_PIN, + PACE_PASSWORD_ID::PACE_PIN, getContext()->getPin(), effectiveChat, certificateDescription); @@ -66,13 +64,13 @@ void StateEstablishPacePin::onEstablishConnectionDone(QSharedPointersetLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); break; case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireCancel(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; case CardReturnCode::INVALID_PIN: @@ -81,8 +79,8 @@ void StateEstablishPacePin::onEstablishConnectionDone(QSharedPointersetSuccessMessage(tr("PIN successfully unblocked")); } - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); break; case CardReturnCode::CANCELLATION_BY_USER: getContext()->setLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireCancel(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; case CardReturnCode::INVALID_PUK: @@ -63,13 +61,13 @@ void StateEstablishPacePuk::onEstablishConnectionDone(QSharedPointersetLastPaceResultAndRetryCounter(returnCode, getContext()->getCardConnection()->getReaderInfo().getRetryCounter()); - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); Q_EMIT fireInoperativePuk(); break; default: - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireError(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); break; } } diff --git a/src/core/states/StateEstablishPacePuk.h b/src/core/states/StateEstablishPacePuk.h index 1bdb974..ac9b951 100644 --- a/src/core/states/StateEstablishPacePuk.h +++ b/src/core/states/StateEstablishPacePuk.h @@ -2,7 +2,7 @@ * \brief Controller for the step that tries to establish a PACE * connection using the card's PUK. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateExtractCvcsFromEac1InputType.cpp b/src/core/states/StateExtractCvcsFromEac1InputType.cpp new file mode 100644 index 0000000..fc58809 --- /dev/null +++ b/src/core/states/StateExtractCvcsFromEac1InputType.cpp @@ -0,0 +1,70 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateExtractCvcsFromEac1InputType.h" + +#include "AppSettings.h" + +using namespace governikus; + +StateExtractCvcsFromEac1InputType::StateExtractCvcsFromEac1InputType(const QSharedPointer& pContext) + : AbstractGenericState(pContext) +{ +} + + +void StateExtractCvcsFromEac1InputType::run() +{ + Q_ASSERT(getContext()->getDidAuthenticateEac1()); + + bool foundTerminalCvc = false, foundDvCvc = false; + for (const auto& cvc : getContext()->getDidAuthenticateEac1()->getCvCertificates()) + { + const auto& cvcAccessRole = cvc->getBody().getCHAT().getAccessRole(); + + if (cvcAccessRole == AccessRole::AT) + { + if (foundTerminalCvc) + { + qCritical() << "More than one terminal certificate found in EAC1InputType"; + updateStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); + Q_EMIT fireAbort(); + return; + } + foundTerminalCvc = true; + getContext()->setTerminalCvc(cvc); + } + else if (cvcAccessRole == AccessRole::DV_no_f || cvcAccessRole == AccessRole::DV_od) + { + if (foundDvCvc) + { + qCritical() << "More than one DV certificate found in EAC1InputType"; + updateStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); + Q_EMIT fireAbort(); + return; + } + foundDvCvc = true; + getContext()->setDvCvc(cvc); + } + } + + if (!foundTerminalCvc) + { + qCritical() << "No terminal certificate found in EAC1InputType"; + updateStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); + Q_EMIT fireAbort(); + return; + } + if (!foundDvCvc) + { + qCritical() << "No DV certificate found in EAC1InputType"; + updateStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); + Q_EMIT fireAbort(); + return; + } + + getContext()->initCvcChainBuilder(); + + Q_EMIT fireContinue(); +} diff --git a/src/core/states/StateExtractCvcsFromEac1InputType.h b/src/core/states/StateExtractCvcsFromEac1InputType.h new file mode 100644 index 0000000..3cbba35 --- /dev/null +++ b/src/core/states/StateExtractCvcsFromEac1InputType.h @@ -0,0 +1,28 @@ +/*! + * \brief State to process InputType of EAC1. Extract certificates and set it to context. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "states/AbstractGenericState.h" + +class test_StateExtractCvcsFromEac1InputType; + +namespace governikus +{ + +class StateExtractCvcsFromEac1InputType + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + friend class ::test_StateExtractCvcsFromEac1InputType; + + StateExtractCvcsFromEac1InputType(const QSharedPointer& pContext); + virtual void run() override; +}; + +} /* namespace governikus */ diff --git a/src/core/states/StateExtractCvcsFromEac1IntputType.cpp b/src/core/states/StateExtractCvcsFromEac1IntputType.cpp deleted file mode 100644 index 821b624..0000000 --- a/src/core/states/StateExtractCvcsFromEac1IntputType.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StateExtractCvcsFromEac1IntputType.h" - -#include "AppSettings.h" - -using namespace governikus; - -StateExtractCvcsFromEac1IntputType::StateExtractCvcsFromEac1IntputType(const QSharedPointer& pContext) - : AbstractGenericState(pContext) -{ -} - - -void StateExtractCvcsFromEac1IntputType::run() -{ - Q_ASSERT(getContext()->getDidAuthenticateEac1()); - - bool foundTerminalCvc = false, foundDvCvc = false; - for (const auto& cvc : getContext()->getDidAuthenticateEac1()->getCvCertificates()) - { - if (cvc->getBody().getCHAT().getAccessRole() == AccessRole::AT) - { - if (foundTerminalCvc) - { - qCritical() << "More than one terminal certificate found in EAC1InputType"; - setStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); - Q_EMIT fireError(); - return; - } - foundTerminalCvc = true; - getContext()->setTerminalCvc(cvc); - } - else if (cvc->getBody().getCHAT().getAccessRole() == AccessRole::DV_no_f) - { - if (foundDvCvc) - { - qCritical() << "More than one DV certificate found in EAC1InputType"; - setStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); - Q_EMIT fireError(); - return; - } - foundDvCvc = true; - getContext()->setDvCvc(cvc); - } - } - - if (!foundTerminalCvc) - { - qCritical() << "No terminal certificate found in EAC1InputType"; - setStatus(GlobalStatus::Code::Workflow_No_Unique_AtCvc); - Q_EMIT fireError(); - return; - } - if (!foundDvCvc) - { - qCritical() << "No DV certificate found in EAC1InputType"; - setStatus(GlobalStatus::Code::Workflow_No_Unique_DvCvc); - Q_EMIT fireError(); - return; - } - - getContext()->initCvcChainBuilder(); - - Q_EMIT fireSuccess(); -} diff --git a/src/core/states/StateExtractCvcsFromEac1IntputType.h b/src/core/states/StateExtractCvcsFromEac1IntputType.h deleted file mode 100644 index 97d5557..0000000 --- a/src/core/states/StateExtractCvcsFromEac1IntputType.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * \brief State to process InputType of EAC1. Extract certificates and set it to context. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "states/AbstractGenericState.h" - -class test_StateExtractCvcsFromEac1InputType; - -namespace governikus -{ - -class StateExtractCvcsFromEac1IntputType - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - friend class ::test_StateExtractCvcsFromEac1InputType; - - StateExtractCvcsFromEac1IntputType(const QSharedPointer& pContext); - virtual void run() override; -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateGenericSendReceive.cpp b/src/core/states/StateGenericSendReceive.cpp index 15dd218..284db7f 100644 --- a/src/core/states/StateGenericSendReceive.cpp +++ b/src/core/states/StateGenericSendReceive.cpp @@ -1,18 +1,22 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "CertificateChecker.h" -#include "paos/PaosHandler.h" #include "StateGenericSendReceive.h" -#include "TlsConfiguration.h" + +#include "CertificateChecker.h" +#include "Env.h" +#include "paos/PaosHandler.h" +#include "TlsChecker.h" + +#include Q_DECLARE_LOGGING_CATEGORY(network) using namespace governikus; -StateGenericSendReceive::StateGenericSendReceive(QSharedPointer pContext, const QVector& pTypesToReceive) +StateGenericSendReceive::StateGenericSendReceive(const QSharedPointer& pContext, const QVector& pTypesToReceive) : AbstractGenericState(pContext) , mTypesToReceive(pTypesToReceive) , mReply() @@ -20,13 +24,13 @@ StateGenericSendReceive::StateGenericSendReceive(QSharedPointer } -StateGenericSendReceive::StateGenericSendReceive(QSharedPointer pContext, PaosType pTypesToReceive) +StateGenericSendReceive::StateGenericSendReceive(const QSharedPointer& pContext, PaosType pTypesToReceive) : StateGenericSendReceive(pContext, QVector() << pTypesToReceive) { } -void StateGenericSendReceive::setReceivedMessage(QSharedPointer pMessage) +void StateGenericSendReceive::setReceivedMessage(const QSharedPointer& pMessage) { switch (pMessage->mType) { @@ -67,6 +71,7 @@ void StateGenericSendReceive::setReceivedMessage(QSharedPointer pMe break; case PaosType::DISCONNECT: + getContext()->setDisconnect(pMessage.staticCast()); getContext()->setDisconnectResponse(QSharedPointer(new DisconnectResponse())); break; @@ -77,48 +82,56 @@ void StateGenericSendReceive::setReceivedMessage(QSharedPointer pMe } -void StateGenericSendReceive::setMessageId(QSharedPointer pPaosMessage) +void StateGenericSendReceive::setMessageId(const QSharedPointer& pPaosMessage) { - QSharedPointer messageIdHandler = getContext()->getMessageIdHandler(); + Q_ASSERT(!pPaosMessage.isNull()); + const QSharedPointer messageIdHandler = getContext()->getMessageIdHandler(); pPaosMessage->setRelatesTo(messageIdHandler->getRemoteMsgId()); pPaosMessage->setMessageId(messageIdHandler->createNewMsgId()); } -void StateGenericSendReceive::setRemoteMessageId(QSharedPointer pPaosMessage) +void StateGenericSendReceive::setRemoteMessageId(const QSharedPointer& pPaosMessage) { - QSharedPointer messageIdHandler = getContext()->getMessageIdHandler(); + const QSharedPointer messageIdHandler = getContext()->getMessageIdHandler(); messageIdHandler->setRemoteMsgId(pPaosMessage->getMessageId()); } -void StateGenericSendReceive::reportChannelEstablishmentError(const GlobalStatus::Code pStatusCode) -{ - qCCritical(network) << GlobalStatus(pStatusCode); - setStatus(pStatusCode); - Q_EMIT fireError(); -} - - void StateGenericSendReceive::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(mReply, pErrors)) + if (TlsChecker::containsFatalError(mReply, pErrors)) { - reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error); + qCCritical(network) << GlobalStatus(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Establishment_Error); + Q_EMIT fireAbort(); } } void StateGenericSendReceive::onSslHandshakeDone() { - QSslConfiguration sslConfiguration = mReply->sslConfiguration(); - qCDebug(network) << "Used session cipher" << sslConfiguration.sessionCipher(); - qCDebug(network) << "Used session protocol:" << sslConfiguration.sessionProtocol(); + const auto& cfg = mReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); - if (!checkAndSaveCertificate(sslConfiguration.peerCertificate())) + const auto statusCode = checkAndSaveCertificate(cfg.peerCertificate()); + if (statusCode != GlobalStatus::Code::No_Error) { - // checkAndSaveCertificate already set the error + qCCritical(network) << GlobalStatus(statusCode); + updateStatus(statusCode); + + // Stop listening to signals from QNetworkReply to stay in + // this state until the following timer fires the signal. + clearConnections(); + mReply->abort(); + + // We need to append the abort to the event queue, because + // QNetworkAccessManager::clearConnectionCache forces sending + // the request when the abort on QNetworkReply is not finished. + QTimer::singleShot(0, this, [this] { + Q_EMIT fireAbort(); + }); } } @@ -129,7 +142,7 @@ void StateGenericSendReceive::onPreSharedKeyAuthenticationRequired(QSslPreShared auto token = getContext()->getTcToken(); Q_ASSERT(!token.isNull()); - if (!token->getPsk().isNull()) + if (token->usePsk()) { pAuthenticator->setIdentity(token->getSessionIdentifier()); pAuthenticator->setPreSharedKey(QByteArray::fromHex(token->getPsk())); @@ -137,37 +150,49 @@ void StateGenericSendReceive::onPreSharedKeyAuthenticationRequired(QSslPreShared } -bool StateGenericSendReceive::checkAndSaveCertificate(const QSslCertificate& pCertificate) +GlobalStatus::Code StateGenericSendReceive::checkAndSaveCertificate(const QSslCertificate& pCertificate) { - switch (CertificateChecker::checkAndSaveCertificate(pCertificate, getContext()->getTcToken()->getServerAddress(), getContext())) + const QSharedPointer c = getContext(); + Q_ASSERT(!c.isNull()); + + std::function saveCertificateFunc = [&c] + (const QUrl& pUrl, const QSslCertificate& pCert) + { + c->addCertificateData(pUrl, pCert); + }; + + switch (CertificateChecker::checkAndSaveCertificate(pCertificate, c->getTcToken()->getServerAddress(), c->getDidAuthenticateEac1(), c->getDvCvc(), saveCertificateFunc)) { case CertificateChecker::CertificateStatus::Good: - return true; + return GlobalStatus::Code::No_Error; case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length: - reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length); - return false; + return GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length; case CertificateChecker::CertificateStatus::Hash_Not_In_Description: - reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description); - return false; + return GlobalStatus::Code::Workflow_TrustedChannel_Hash_Not_In_Description; } - return false; + return GlobalStatus::Code::Workflow_Processing_Error; } void StateGenericSendReceive::run() { - QSharedPointer messageToSend = getMessageToSend(); - Q_ASSERT(!messageToSend.isNull()); + setMessageId(getAsMessage()); - setMessageId(messageToSend.dynamicCast()); - if (QSharedPointer paosResponse = messageToSend.dynamicCast()) + if (QSharedPointer paosResponse = getAsResponse()) { if (!getContext()->isErrorReportedToServer() && getContext()->getStatus().isError() && !getContext()->getStatus().isOriginServer()) { - paosResponse->setResult(getContext()->getStatus()); + if (getContext()->getTransmitResponseFailed()) + { + paosResponse->setResult(GlobalStatus(GlobalStatus::Code::Paos_Error_AL_Unknown_Error)); + } + else + { + paosResponse->setResult(getContext()->getStatus()); + } getContext()->setErrorReportedToServer(true); } else @@ -182,9 +207,12 @@ void StateGenericSendReceive::run() QNetworkRequest request(token->getServerAddress()); request.setRawHeader("requestid", token->getSessionIdentifier()); - QByteArray data = messageToSend->marshall(); + const QByteArray& data = getAsCreator()->marshall(); + Q_ASSERT(!data.isEmpty()); + qCDebug(network) << "Try to send raw data:\n" << data; - mReply = getContext()->getNetworkManager().paos(request, data, !token->getPsk().isNull()); + const QByteArray& paosNamespace = PaosCreator::getNamespace(PaosCreator::Namespace::PAOS).toUtf8(); + mReply = Env::getSingleton()->paos(request, paosNamespace, data, token->usePsk()); mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGenericSendReceive::onSslErrors); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGenericSendReceive::onSslHandshakeDone); mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGenericSendReceive::onReplyFinished); @@ -201,7 +229,10 @@ void StateGenericSendReceive::onReplyFinished() if (reply->error() != QNetworkReply::NoError) { - reportChannelEstablishmentError(NetworkManager::toTrustedChannelStatus(reply)); + const auto& statusCode = NetworkManager::toTrustedChannelStatus(reply); + qCCritical(network) << GlobalStatus(statusCode); + updateStatus(statusCode); + Q_EMIT fireAbort(); return; } @@ -212,7 +243,9 @@ void StateGenericSendReceive::onReplyFinished() const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statusCode >= 500) { - reportChannelEstablishmentError(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server); + qCCritical(network) << GlobalStatus(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Error_From_Server); + Q_EMIT fireAbort(); return; } @@ -223,7 +256,7 @@ void StateGenericSendReceive::onReplyFinished() if (!mTypesToReceive.contains(paosHandler.getDetectedPaosType())) { - QString warnMsg("Received PAOS message not of expected type: "); + QString warnMsg = QStringLiteral("Received PAOS message not of expected type: "); for (const auto expectedType : mTypesToReceive) { warnMsg += expectedType; @@ -234,14 +267,14 @@ void StateGenericSendReceive::onReplyFinished() if (paosHandler.getDetectedPaosType() == PaosType::UNKNOWN) { qCCritical(network) << "The program received an unknown message from the server."; - setStatus(GlobalStatus::Code::Workflow_Unknown_Paos_Form_EidServer); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Unknown_Paos_Form_EidServer); + Q_EMIT fireAbort(); } else { qCCritical(network) << "The program received an unexpected message from the server."; - setStatus(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Unexpected_Message_From_EidServer); + Q_EMIT fireAbort(); } return; } @@ -267,11 +300,11 @@ void StateGenericSendReceive::onReplyFinished() if (result == 1) { - Q_EMIT fireError(); + Q_EMIT fireAbort(); } else if (result == 2) { - Q_EMIT fireCancel(); + Q_EMIT fireAbort(); } else { @@ -280,6 +313,6 @@ void StateGenericSendReceive::onReplyFinished() } else { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } } diff --git a/src/core/states/StateGenericSendReceive.h b/src/core/states/StateGenericSendReceive.h index 6ccc304..d47397f 100644 --- a/src/core/states/StateGenericSendReceive.h +++ b/src/core/states/StateGenericSendReceive.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,28 +26,21 @@ class StateGenericSendReceive const QVector mTypesToReceive; QPointer mReply; - void setMessageId(QSharedPointer pPaosMessage); - void setRemoteMessageId(QSharedPointer pPaosMessage); - void setReceivedMessage(QSharedPointer pMessage); - void reportChannelEstablishmentError(const GlobalStatus::Code pStatusCode); - bool checkAndSaveCertificate(const QSslCertificate& pCertificate); + void setMessageId(const QSharedPointer& pPaosMessage); + void setRemoteMessageId(const QSharedPointer& pPaosMessage); + void setReceivedMessage(const QSharedPointer& pMessage); + GlobalStatus::Code checkAndSaveCertificate(const QSslCertificate& pCertificate); void onSslErrors(const QList& pErrors); void onSslHandshakeDone(); - virtual void run(); + virtual void run() override; protected: - /** - * Creates a new instance of. - * \param pUiFactory the UiFactory to use - * \param pNewState the entered state when executing this state - * \param pTypeToSend the PAOS message type to send - * \param pTypesToReceive the expected PAOS message types to receive - * \return in case of any error 0 is returned. Otherwise the received PAOS messages position in the list pTypesToReceive plus one is returned. - */ - StateGenericSendReceive(QSharedPointer pContext, const QVector& pTypesToReceive); - StateGenericSendReceive(QSharedPointer pContext, PaosType pTypesToReceive); + StateGenericSendReceive(const QSharedPointer& pContext, const QVector& pTypesToReceive); + StateGenericSendReceive(const QSharedPointer& pContext, PaosType pTypesToReceive); - virtual QSharedPointer getMessageToSend() = 0; + virtual QSharedPointer getAsMessage() = 0; + virtual QSharedPointer getAsResponse() = 0; + virtual QSharedPointer getAsCreator() = 0; virtual void emitStateMachineSignal(int result) = 0; private Q_SLOTS: @@ -69,9 +62,21 @@ class StateSendStartPaos protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getStartPaos().staticCast(); + return getContext()->getStartPaos(); + } + + + virtual QSharedPointer getAsResponse() override + { + return QSharedPointer(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getStartPaos(); } @@ -113,9 +118,21 @@ class StateSendInitializeFrameworkResponse protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getInitializeFrameworkResponse().staticCast(); + return getContext()->getInitializeFrameworkResponse(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getInitializeFrameworkResponse(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getInitializeFrameworkResponse(); } @@ -152,9 +169,21 @@ class StateSendDIDListResponse protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getDidListResponse().staticCast(); + return getContext()->getDidListResponse(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getDidListResponse(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getDidListResponse(); } @@ -190,9 +219,21 @@ class StateSendDIDAuthenticateResponseEAC1 protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getDidAuthenticateResponseEac1().staticCast(); + return getContext()->getDidAuthenticateResponseEac1(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getDidAuthenticateResponseEac1(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getDidAuthenticateResponseEac1(); } @@ -228,9 +269,21 @@ class StateSendDIDAuthenticateResponseEACAdditionalInputType protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getDidAuthenticateResponseEacAdditionalInputType().staticCast(); + return getContext()->getDidAuthenticateResponseEacAdditionalInputType(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getDidAuthenticateResponseEacAdditionalInputType(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getDidAuthenticateResponseEacAdditionalInputType(); } @@ -261,9 +314,21 @@ class StateSendDIDAuthenticateResponseEAC2 protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getDidAuthenticateResponseEac2().staticCast(); + return getContext()->getDidAuthenticateResponseEac2(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getDidAuthenticateResponseEac2(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getDidAuthenticateResponseEac2(); } @@ -299,9 +364,21 @@ class StateSendTransmitResponse protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override { - return getContext()->getTransmitResponses().last().staticCast(); + return getContext()->getTransmitResponses().constLast(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getTransmitResponses().constLast(); + } + + + virtual QSharedPointer getAsCreator() override + { + return getContext()->getTransmitResponses().constLast(); } @@ -338,7 +415,19 @@ class StateSendDisconnectResponse protected: - virtual QSharedPointer getMessageToSend() override + virtual QSharedPointer getAsMessage() override + { + return getContext()->getDisconnectResponse(); + } + + + virtual QSharedPointer getAsResponse() override + { + return getContext()->getDisconnectResponse(); + } + + + virtual QSharedPointer getAsCreator() override { return getContext()->getDisconnectResponse(); } diff --git a/src/core/states/StateGetSelfAuthenticationData.cpp b/src/core/states/StateGetSelfAuthenticationData.cpp index bd3fbe5..f4a1f87 100644 --- a/src/core/states/StateGetSelfAuthenticationData.cpp +++ b/src/core/states/StateGetSelfAuthenticationData.cpp @@ -1,19 +1,20 @@ /*! - * StateGetSelfAuthenticationData.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateGetSelfAuthenticationData.h" #include "CertificateChecker.h" +#include "Env.h" #include "HttpStatusCode.h" #include "SelfAuthenticationData.h" -#include "TlsConfiguration.h" +#include "TlsChecker.h" -#include +#include #include +Q_DECLARE_LOGGING_CATEGORY(network) + using namespace governikus; StateGetSelfAuthenticationData::StateGetSelfAuthenticationData(const QSharedPointer& pContext) @@ -38,7 +39,7 @@ void StateGetSelfAuthenticationData::run() qDebug() << address; QNetworkRequest request(address); - mReply = getContext()->getNetworkManager().get(request); + mReply = Env::getSingleton()->get(request); mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGetSelfAuthenticationData::onSslErrors); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGetSelfAuthenticationData::onSslHandshakeDone); mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGetSelfAuthenticationData::onNetworkReply); @@ -48,15 +49,18 @@ void StateGetSelfAuthenticationData::run() void StateGetSelfAuthenticationData::reportCommunicationError(const GlobalStatus& pStatus) { qCritical() << pStatus; - setStatus(pStatus); + updateStatus(pStatus); mReply->abort(); - Q_EMIT fireError(); + Q_EMIT fireAbort(); } void StateGetSelfAuthenticationData::onSslHandshakeDone() { - if (!checkSslConnectionAndSaveCertificate(mReply->sslConfiguration())) + const auto& cfg = mReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); + + if (!checkSslConnectionAndSaveCertificate(cfg)) { // checkAndSaveCertificate already set the error mReply->abort(); @@ -66,12 +70,16 @@ void StateGetSelfAuthenticationData::onSslHandshakeDone() 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(); + const QSharedPointer& context = getContext(); + Q_ASSERT(!context.isNull()); - switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), getContext()->getRefreshUrl(), getContext())) + const auto& saveCertificateFunc = [&] + (const QUrl& pUrl, const QSslCertificate& pCertificate) + { + context->addCertificateData(pUrl, pCertificate); + }; + + switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), getContext()->getRefreshUrl(), context->getDidAuthenticateEac1(), context->getDvCvc(), saveCertificateFunc)) { case CertificateChecker::CertificateStatus::Good: break; @@ -85,9 +93,9 @@ bool StateGetSelfAuthenticationData::checkSslConnectionAndSaveCertificate(const return false; } - if (!CertificateChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) + if (!TlsChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey())) { - reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length)); + reportCommunicationError(GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length); return false; } @@ -97,7 +105,7 @@ bool StateGetSelfAuthenticationData::checkSslConnectionAndSaveCertificate(const void StateGetSelfAuthenticationData::onSslErrors(const QList& pErrors) { - if (TlsConfiguration::containsFatalError(mReply, pErrors)) + if (TlsChecker::containsFatalError(mReply, pErrors)) { reportCommunicationError(GlobalStatus(GlobalStatus::Code::Network_Ssl_Establishment_Error)); } @@ -111,23 +119,23 @@ void StateGetSelfAuthenticationData::onNetworkReply() if (statusCode == HttpStatusCode::OK) { - QSharedPointer data(new SelfAuthenticationData(mReply->readAll())); - if (data->isValid()) + const SelfAuthenticationData data(mReply->readAll()); + if (data.isValid()) { getContext()->setSelfAuthenticationData(data); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { qDebug() << "Could not read data for self authentication."; - setStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + Q_EMIT fireAbort(); } } else { qDebug() << "Could not read data for self authentication. StatusCode:" << statusCode; - setStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided); + Q_EMIT fireAbort(); } } diff --git a/src/core/states/StateGetSelfAuthenticationData.h b/src/core/states/StateGetSelfAuthenticationData.h index d523914..fb94dbb 100644 --- a/src/core/states/StateGetSelfAuthenticationData.h +++ b/src/core/states/StateGetSelfAuthenticationData.h @@ -1,14 +1,12 @@ /*! - * StateGetSelfAuthenticationData.h - * * \brief get the xml data from the given url * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "context/SelfAuthenticationContext.h" +#include "context/SelfAuthContext.h" #include "NetworkManager.h" #include "Result.h" #include "states/AbstractGenericState.h" @@ -17,7 +15,7 @@ namespace governikus { class StateGetSelfAuthenticationData - : public AbstractGenericState + : public AbstractGenericState { Q_OBJECT friend class StateBuilder; @@ -30,7 +28,7 @@ class StateGetSelfAuthenticationData bool checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration); public: - ~StateGetSelfAuthenticationData(); + virtual ~StateGetSelfAuthenticationData() override; private Q_SLOTS: void onNetworkReply(); diff --git a/src/core/states/StateGetTcToken.cpp b/src/core/states/StateGetTcToken.cpp index f94aab6..ef0c4b7 100644 --- a/src/core/states/StateGetTcToken.cpp +++ b/src/core/states/StateGetTcToken.cpp @@ -1,14 +1,13 @@ /*! - * StateGetTcToken.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateGetTcToken.h" -#include "CertificateChecker.h" +#include "AppSettings.h" +#include "Env.h" #include "NetworkManager.h" -#include "TlsConfiguration.h" +#include "TlsChecker.h" #include #include @@ -18,6 +17,7 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(developermode) +Q_DECLARE_LOGGING_CATEGORY(network) StateGetTcToken::StateGetTcToken(const QSharedPointer& pContext) @@ -43,9 +43,13 @@ void StateGetTcToken::run() if (!isValidRedirectUrl(url)) { - Q_EMIT fireError(); + Q_EMIT fireAbort(); return; } + // At this time we start the first network communication in a + // workflow. Therefore it is necessary to clear all connections + // to force new connections with the expected security settings. + Env::getSingleton()->clearConnections(); sendRequest(url); } @@ -55,7 +59,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."; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); return false; } else if (pUrl.scheme() != QLatin1String("https")) @@ -71,7 +75,7 @@ bool StateGetTcToken::isValidRedirectUrl(const QUrl& pUrl) { qCritical() << httpsError; getContext()->setTcTokenNotFound(false); - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); return false; } } @@ -87,7 +91,7 @@ void StateGetTcToken::sendRequest(const QUrl& pUrl) } QNetworkRequest request(pUrl); - mReply = getContext()->getNetworkManager().get(request); + mReply = Env::getSingleton()->get(request); mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGetTcToken::onSslErrors); mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGetTcToken::onSslHandshakeDone); mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGetTcToken::onNetworkReply); @@ -96,38 +100,35 @@ void StateGetTcToken::sendRequest(const QUrl& pUrl) void StateGetTcToken::onSslErrors(const QList& pErrors) { - TlsConfiguration::containsFatalError(mReply, pErrors); + TlsChecker::containsFatalError(mReply, pErrors); } void StateGetTcToken::onSslHandshakeDone() { - QSslConfiguration sslConfiguration = mReply->sslConfiguration(); - QSslKey ephemeralServerKey = sslConfiguration.ephemeralServerKey(); - qDebug() << "Used session cipher" << sslConfiguration.sessionCipher(); - qDebug() << "Used session protocol:" << sslConfiguration.sessionProtocol(); - qDebug() << "Used ephemeral server key:" << ephemeralServerKey; + const auto& cfg = mReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); // At this point we can only check the certificate key's length. - if (!CertificateChecker::hasValidCertificateKeyLength(sslConfiguration.peerCertificate())) + if (!TlsChecker::hasValidCertificateKeyLength(cfg.peerCertificate())) { mReply->abort(); qCritical() << "Error while connecting to the service provider. The server's SSL certificate uses an unsupported key algorithm or length."; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); + Q_EMIT fireAbort(); return; } - if (!CertificateChecker::hasValidEphemeralKeyLength(ephemeralServerKey)) + if (!TlsChecker::hasValidEphemeralKeyLength(cfg.ephemeralServerKey())) { mReply->abort(); qCritical() << "Error while connecting to the service provider. The SSL connection uses an unsupported key algorithm or length."; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error); + Q_EMIT fireAbort(); return; } - getContext()->addCertificateData(mReply->request().url(), sslConfiguration.peerCertificate()); + getContext()->addCertificateData(mReply->request().url(), cfg.peerCertificate()); } @@ -136,12 +137,16 @@ void StateGetTcToken::onNetworkReply() int statusCode = mReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QUrl redirectUrl = mReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); qDebug() << "Status Code: " << statusCode << " | RedirectUrl: " << redirectUrl; + for (const auto& header : mReply->rawHeaderPairs()) + { + qCDebug(network).nospace() << "Header | " << header.first << ": " << header.second; + } if (mReply->error() != QNetworkReply::NoError) { qCritical() << NetworkManager::toStatus(mReply.data()); - setStatus(NetworkManager::toTrustedChannelStatus(mReply.data())); - Q_EMIT fireError(); + updateStatus(NetworkManager::toTrustedChannelStatus(mReply.data())); + Q_EMIT fireAbort(); return; } @@ -153,15 +158,15 @@ void StateGetTcToken::onNetworkReply() if (!isValidRedirectUrl(redirectUrl)) { - Q_EMIT fireError(); + Q_EMIT fireAbort(); return; } 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; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); + Q_EMIT fireAbort(); return; } @@ -177,8 +182,8 @@ void StateGetTcToken::parseTcToken() if (data.isEmpty()) { qDebug() << "Received no data."; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_No_Data_Received); + Q_EMIT fireAbort(); return; } QSharedPointer tcToken(new TcToken(data)); @@ -187,11 +192,17 @@ void StateGetTcToken::parseTcToken() if (tcToken->isValid()) { - Q_EMIT fireSuccess(); + if (tcToken->usePsk()) + { + // When the tcToken provides a psk, it is necessary to clear + // all connections to force new connections with psk settings. + Env::getSingleton()->clearConnections(); + } + Q_EMIT fireContinue(); return; } qCritical() << "TCToken invalid"; - setStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_TrustedChannel_Server_Format_Error); + Q_EMIT fireAbort(); } diff --git a/src/core/states/StateGetTcToken.h b/src/core/states/StateGetTcToken.h index 2d05e02..d86603e 100644 --- a/src/core/states/StateGetTcToken.h +++ b/src/core/states/StateGetTcToken.h @@ -1,9 +1,7 @@ /*! - * StateGetTcToken.h - * * \brief State machine state: Get TCToken. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -33,7 +31,7 @@ class StateGetTcToken StateGetTcToken(const QSharedPointer& pContext); public: - virtual ~StateGetTcToken(); + virtual ~StateGetTcToken() override; private Q_SLOTS: void onNetworkReply(); diff --git a/src/core/states/StateHandleRetryCounter.cpp b/src/core/states/StateHandleRetryCounter.cpp new file mode 100644 index 0000000..8528f92 --- /dev/null +++ b/src/core/states/StateHandleRetryCounter.cpp @@ -0,0 +1,41 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateHandleRetryCounter.h" + +#include "CardConnection.h" + + +using namespace governikus; + + +StateHandleRetryCounter::StateHandleRetryCounter(const QSharedPointer& pContext) + : AbstractGenericState(pContext) +{ +} + + +void StateHandleRetryCounter::run() +{ + auto cardConnection = getContext()->getCardConnection(); + Q_ASSERT(cardConnection != nullptr); + + switch (cardConnection->getReaderInfo().getRetryCounter()) + { + 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/StateHandleRetryCounter.h b/src/core/states/StateHandleRetryCounter.h new file mode 100644 index 0000000..b2d1148 --- /dev/null +++ b/src/core/states/StateHandleRetryCounter.h @@ -0,0 +1,29 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AbstractGenericState.h" + +#include "context/ChangePinContext.h" + +namespace governikus +{ + +class StateHandleRetryCounter + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + StateHandleRetryCounter(const QSharedPointer& pContext); + virtual void run() override; + + Q_SIGNALS: + void fireRetryCounterIsZero(); + void fireRetryCounterIsOne(); + void fireRetryCounterIsGTOne(); +}; + +} /* namespace governikus */ diff --git a/src/core/states/StateInitializeFramework.cpp b/src/core/states/StateInitializeFramework.cpp index 4ef99c5..db4bbe6 100644 --- a/src/core/states/StateInitializeFramework.cpp +++ b/src/core/states/StateInitializeFramework.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/InitializeFrameworkResponse.h" @@ -16,5 +16,5 @@ StateInitializeFramework::StateInitializeFramework(const QSharedPointergetInitializeFramework().isNull()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateInitializeFramework.h b/src/core/states/StateInitializeFramework.h index 3e085da..6533d54 100644 --- a/src/core/states/StateInitializeFramework.h +++ b/src/core/states/StateInitializeFramework.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateLoadTcTokenUrl.cpp b/src/core/states/StateLoadTcTokenUrl.cpp index 291c384..803c97c 100644 --- a/src/core/states/StateLoadTcTokenUrl.cpp +++ b/src/core/states/StateLoadTcTokenUrl.cpp @@ -1,10 +1,12 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AppSettings.h" +#include "Env.h" #include "states/StateLoadTcTokenUrl.h" +#include "SecureStorage.h" using namespace governikus; @@ -16,11 +18,11 @@ StateLoadTcTokenUrl::StateLoadTcTokenUrl(const QSharedPointer& void StateLoadTcTokenUrl::run() { - const bool useTestUri = AppSettings::getInstance().getGeneralSettings().useSelfauthenticationTestUri(); + const bool useTestUri = Env::getSingleton()->getGeneralSettings().useSelfAuthTestUri(); - const QUrl& url = AppSettings::getInstance().getSecureStorage().getSelfAuthenticationUrl(useTestUri); + const QUrl& url = SecureStorage::getInstance().getSelfAuthenticationUrl(useTestUri); qDebug() << "Loaded tcTokenUrl for self authentication from securestorage:" << url; getContext()->setTcTokenUrl(url); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateLoadTcTokenUrl.h b/src/core/states/StateLoadTcTokenUrl.h index a0929b9..6f4fcb9 100644 --- a/src/core/states/StateLoadTcTokenUrl.h +++ b/src/core/states/StateLoadTcTokenUrl.h @@ -1,19 +1,19 @@ /*! * \brief Loads the tcTokenUrl for triggering the self authentication from secure storage * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "context/SelfAuthenticationContext.h" +#include "context/SelfAuthContext.h" #include "states/AbstractGenericState.h" namespace governikus { class StateLoadTcTokenUrl - : public AbstractGenericState + : public AbstractGenericState { Q_OBJECT friend class StateBuilder; diff --git a/src/core/states/StateParseTcTokenUrl.cpp b/src/core/states/StateParseTcTokenUrl.cpp index 7b3be00..e60af31 100644 --- a/src/core/states/StateParseTcTokenUrl.cpp +++ b/src/core/states/StateParseTcTokenUrl.cpp @@ -1,16 +1,14 @@ /*! - * StateParseTcTokenUrl.cpp - * * \brief Parse tcTokenURL from GET query. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateParseTcTokenUrl.h" +#include "HttpStatusCode.h" #include "Result.h" - #include using namespace governikus; @@ -28,7 +26,7 @@ void StateParseTcTokenUrl::run() if (tcTokenURL.isValid()) { getContext()->setTcTokenUrl(tcTokenURL); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { @@ -41,7 +39,7 @@ void StateParseTcTokenUrl::run() qCritical() << "No parameter tcTokenURL"; } - setStatus(GlobalStatus::Code::Workflow_Wrong_Parameter_Invocation); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Wrong_Parameter_Invocation); + Q_EMIT fireAbort(); } } diff --git a/src/core/states/StateParseTcTokenUrl.h b/src/core/states/StateParseTcTokenUrl.h index 31d6fc8..65b4480 100644 --- a/src/core/states/StateParseTcTokenUrl.h +++ b/src/core/states/StateParseTcTokenUrl.h @@ -1,9 +1,7 @@ /*! - * StateParseTcTokenUrl.h - * * \brief Implements the parsing of TcTokenUrl in header of browser request. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StatePreVerification.cpp b/src/core/states/StatePreVerification.cpp index 67d7e14..a177e34 100644 --- a/src/core/states/StatePreVerification.cpp +++ b/src/core/states/StatePreVerification.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StatePreVerification.h" @@ -8,6 +8,8 @@ #include "asn1/SignatureChecker.h" #include "AppSettings.h" #include "EnumHelper.h" +#include "Env.h" +#include "SecureStorage.h" #include @@ -17,8 +19,8 @@ using namespace governikus; StatePreVerification::StatePreVerification(const QSharedPointer& pContext) : AbstractGenericState(pContext) - , mTrustedCvcas(CVCertificate::fromHex(AppSettings::getInstance().getSecureStorage().getCVRootCertificates(true)) - + CVCertificate::fromHex(AppSettings::getInstance().getSecureStorage().getCVRootCertificates(false))) + , mTrustedCvcas(CVCertificate::fromHex(SecureStorage::getInstance().getCVRootCertificates(true)) + + CVCertificate::fromHex(SecureStorage::getInstance().getCVRootCertificates(false))) , mValidationDateTime(QDateTime::currentDateTime()) { } @@ -44,13 +46,13 @@ void StatePreVerification::run() } } - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + if (Env::getSingleton()->getGeneralSettings().isDeveloperMode()) { if (certificateChain.isProductive()) { qCritical() << "Using the developer mode is only allowed in a test environment"; - setStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); + Q_EMIT fireAbort(); return; } } @@ -58,43 +60,43 @@ void StatePreVerification::run() if (!AppSettings::getInstance().getPreVerificationSettings().isEnabled()) { qInfo() << "Pre-verification is disabled"; - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } if (!certificateChain.isValid()) { qCritical() << "Pre-verification failed: cannot build certificate chain"; - setStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); + Q_EMIT fireAbort(); return; } else if (!SignatureChecker(certificateChain).check()) { qCritical() << "Pre-verification failed: signature check failed"; - setStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); + Q_EMIT fireAbort(); return; } else if (!isValid(certificateChain)) { qCritical() << "Pre-verification failed: certificate not valid "; - setStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); + Q_EMIT fireAbort(); return; } saveCvcaLinkCertificates(certificateChain); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } -bool StatePreVerification::isValid(const QVector >& pCertificates) +bool StatePreVerification::isValid(const QVector >& pCertificates) { qDebug() << "Check certificate chain validity on" << mValidationDateTime.toString(Qt::ISODate); - QVectorIterator > i(pCertificates); + QVectorIterator > i(pCertificates); i.toBack(); while (i.hasPrevious()) { @@ -123,15 +125,28 @@ bool StatePreVerification::isValid(const QVector > } -void StatePreVerification::saveCvcaLinkCertificates(const QVector >& pCertificates) +void StatePreVerification::saveCvcaLinkCertificates(const QVector >& pCertificates) { + const auto& contains = [](const QVector >& pStore, const CVCertificate& pCert) -> bool + { + for (const auto& pCertInStore : pStore) + { + if (*pCertInStore == pCert) + { + return true; + } + } + return false; + }; + + auto& settings = Env::getSingleton()->getPreVerificationSettings(); for (const auto& certificate : pCertificates) { - if (certificate->getBody().getCHAT().getAccessRole() == AccessRole::CVCA && !mTrustedCvcas.contains(certificate)) + if (certificate->getBody().getCHAT().getAccessRole() == AccessRole::CVCA && !contains(mTrustedCvcas, *certificate)) { qInfo() << "Save link certificate" << *certificate; - AppSettings::getInstance().getPreVerificationSettings().addLinkCertificate(certificate->encode().toHex()); + settings.addLinkCertificate(certificate->encode().toHex()); } } - AppSettings::getInstance().getPreVerificationSettings().save(); + settings.save(); } diff --git a/src/core/states/StatePreVerification.h b/src/core/states/StatePreVerification.h index b23d8da..95a9502 100644 --- a/src/core/states/StatePreVerification.h +++ b/src/core/states/StatePreVerification.h @@ -1,9 +1,7 @@ /* - * StatePreVerification.h - * * \brief Performs the pre-verification of cvcs. If the pre-verification succeeds the cvc chain is set to the authentication model. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,14 +23,14 @@ class StatePreVerification friend class StateBuilder; friend class ::test_StatePreVerification; - const QVector > mTrustedCvcas; + const QVector > mTrustedCvcas; const QDateTime mValidationDateTime; StatePreVerification(const QSharedPointer& pContext); virtual void run() override; - bool isValid(const QVector >& pCertificates); - void saveCvcaLinkCertificates(const QVector >& pCertificates); + bool isValid(const QVector >& pCertificates); + void saveCvcaLinkCertificates(const QVector >& pCertificates); }; } /* namespace governikus */ diff --git a/src/core/states/StateProcessCertificatesFromEac2.cpp b/src/core/states/StateProcessCertificatesFromEac2.cpp index a3f3a3e..7f8c2d3 100644 --- a/src/core/states/StateProcessCertificatesFromEac2.cpp +++ b/src/core/states/StateProcessCertificatesFromEac2.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateProcessCertificatesFromEac2.h" @@ -24,11 +24,11 @@ void StateProcessCertificatesFromEac2::run() if (getContext()->hasChainForCertificationAuthority(*getContext()->getPaceOutputData())) { qDebug() << "CVC chain already determined, skip further processing"; - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } - QVector > cvcs; + QVector > cvcs; for (const auto& cvc : getContext()->getDidAuthenticateEac2()->getCvCertificates()) { // according to TR-03112-7, paragraph 3.6.4.2, AT certs must be ignored @@ -44,11 +44,11 @@ void StateProcessCertificatesFromEac2::run() if (!getContext()->hasChainForCertificationAuthority(*getContext()->getPaceOutputData())) { qCritical() << "No cvc chain determined, abort authentication"; - setStatus(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity); - Q_EMIT fireError(); + updateStatus(GlobalStatus::Code::Workflow_Cannot_Confirm_IdCard_Authenticity); + Q_EMIT fireAbort(); } else { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } } diff --git a/src/core/states/StateProcessCertificatesFromEac2.h b/src/core/states/StateProcessCertificatesFromEac2.h index b3b5bd8..d7f3f74 100644 --- a/src/core/states/StateProcessCertificatesFromEac2.h +++ b/src/core/states/StateProcessCertificatesFromEac2.h @@ -1,7 +1,7 @@ /*! * \brief State to process certificates from EAC2. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateProcessing.cpp b/src/core/states/StateProcessing.cpp index 28e131a..fdbf193 100644 --- a/src/core/states/StateProcessing.cpp +++ b/src/core/states/StateProcessing.cpp @@ -1,7 +1,5 @@ /*! - * StateProcessing.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateProcessing.h" @@ -19,12 +17,12 @@ void StateProcessing::run() auto activationContext = getContext()->getActivationContext(); if (activationContext->sendProcessing()) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { qCritical() << "Cannot send \"Processing\" to caller: " << activationContext->getSendError(); - setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Processing_Error, activationContext->getSendError())); - Q_EMIT fireError(); + updateStatus(GlobalStatus(GlobalStatus::Code::Workflow_Processing_Error, activationContext->getSendError())); + Q_EMIT fireAbort(); } } diff --git a/src/core/states/StateProcessing.h b/src/core/states/StateProcessing.h index fb8de3c..93e2a0a 100644 --- a/src/core/states/StateProcessing.h +++ b/src/core/states/StateProcessing.h @@ -1,9 +1,7 @@ /*! - * StateProcessing.h - * * \brief Sends a HTTP-Processing to the browser. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateRedirectBrowser.cpp b/src/core/states/StateRedirectBrowser.cpp index a8bcec5..967605e 100644 --- a/src/core/states/StateRedirectBrowser.cpp +++ b/src/core/states/StateRedirectBrowser.cpp @@ -1,7 +1,5 @@ /*! - * StateRedirectBrowser.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateRedirectBrowser.h" @@ -34,7 +32,7 @@ void StateRedirectBrowser::run() } else if (sendRedirect(getContext()->getRefreshUrl(), getContext()->getStatus())) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } } @@ -44,13 +42,13 @@ void StateRedirectBrowser::sendErrorPage(HttpStatusCode pStatus) auto activationContext = getContext()->getActivationContext(); if (activationContext->sendErrorPage(pStatus, getContext()->getStatus())) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else { qCritical() << "Cannot send error page to caller: " << activationContext->getSendError(); - setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Error_Page_Transmission_Error, activationContext->getSendError())); - Q_EMIT fireError(); + updateStatus(GlobalStatus(GlobalStatus::Code::Workflow_Error_Page_Transmission_Error, activationContext->getSendError())); + Q_EMIT fireAbort(); } } @@ -62,7 +60,7 @@ void StateRedirectBrowser::reportCommunicationError() { if (sendRedirect(getContext()->getTcToken()->getCommunicationErrorAddress(), GlobalStatus::Code::Workflow_Communication_Missing_Redirect_Url)) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } } else @@ -75,15 +73,13 @@ void StateRedirectBrowser::reportCommunicationError() bool StateRedirectBrowser::sendRedirect(const QUrl& pRedirectAddress, const GlobalStatus& pStatus) { auto activationContext = getContext()->getActivationContext(); - if (activationContext->sendRedirect(pRedirectAddress, pStatus)) - { - return true; - } - else + if (!activationContext->sendRedirect(pRedirectAddress, pStatus)) { qCritical() << "Cannot send redirect to caller: " << activationContext->getSendError(); - setStatus(GlobalStatus(GlobalStatus::Code::Workflow_Redirect_Transmission_Error, activationContext->getSendError())); - Q_EMIT fireError(); + updateStatus(GlobalStatus(GlobalStatus::Code::Workflow_Redirect_Transmission_Error, activationContext->getSendError())); + Q_EMIT fireAbort(); return false; } + + return true; } diff --git a/src/core/states/StateRedirectBrowser.h b/src/core/states/StateRedirectBrowser.h index a8702e8..209f498 100644 --- a/src/core/states/StateRedirectBrowser.h +++ b/src/core/states/StateRedirectBrowser.h @@ -1,14 +1,13 @@ /*! - * StateRedirectBrowser.h - * * \brief Send a redirect to the browser. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "context/AuthContext.h" +#include "HttpStatusCode.h" #include "Result.h" #include "states/AbstractGenericState.h" diff --git a/src/core/states/StateSelectBluetoothReader.cpp b/src/core/states/StateSelectBluetoothReader.cpp deleted file mode 100644 index 20f98e3..0000000 --- a/src/core/states/StateSelectBluetoothReader.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ReaderManager.h" -#include "StateSelectBluetoothReader.h" - -#include - -using namespace governikus; - -StateSelectBluetoothReader::StateSelectBluetoothReader(const QSharedPointer& pContext) - : AbstractGenericState(pContext, false) -{ -} - - -void StateSelectBluetoothReader::run() -{ - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StateSelectBluetoothReader::onReaderDetected); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderDeviceError, this, &StateSelectBluetoothReader::onReaderDeviceError); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StateSelectBluetoothReader::onReaderDetected); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderConnected, this, &StateSelectBluetoothReader::onReaderConnected); - - startScan(); -} - - -void StateSelectBluetoothReader::startScan() -{ - Q_ASSERT(getContext()); - - const auto& pluginInfos = ReaderManager::getInstance().getPlugInInfos(); - for (const ReaderManagerPlugInInfo& pInfo : pluginInfos) - { - if (pInfo.getPlugInType() != ReaderManagerPlugInType::BLUETOOTH) - { - continue; - } - - if (!pInfo.isEnabled()) - { - qDebug() << "Skipping scan because bluetooth is disabled"; - return; - } - - onReaderDetected(); - if (!getContext()->getReaderName().isEmpty()) - { - qDebug() << "Skipping scan because there is already a paired device:" << getContext()->getReaderName(); - return; - } - - qDebug() << "Start bluetooth scan"; - ReaderManager::getInstance().startScan(); - - return; - } -} - - -void StateSelectBluetoothReader::onReaderDetected() -{ - auto readerInfos = ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::BLUETOOTH); - if (!readerInfos.isEmpty()) - { - getContext()->setReaderName(readerInfos[0].getName()); - qDebug() << "Select first found Bluetooth reader" << readerInfos[0].getName(); - ReaderManager::getInstance().stopScan(); - - /* - * Workaround for pairing problem on Android: - * - * The reader detection process performs a BT connect, determines the services and characteristics - * and disconnects afterwards. When selecting a reader we connect again. - * This causes some timing issue. Other developers have similar problems, e.g. see - * https://github.com/NordicSemiconductor/Android-DFU-Library/issues/1#issuecomment-156790789 - * - * This lead to setting a delay of 1000 msecs. - */ - QTimer::singleShot(1000, [ = ] {ReaderManager::getInstance().connectReader(readerInfos[0].getName()); - }); - } -} - - -void StateSelectBluetoothReader::onReaderConnected() -{ - ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(getContext()->getReaderName()); - if (!readerInfo.isValid()) - { - setStatus(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible); - Q_EMIT fireError(); - } - else if (readerInfo.isConnected()) - { - qDebug() << "Bluetooth reader connected" << readerInfo.getName(); - 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 deleted file mode 100644 index afb4079..0000000 --- a/src/core/states/StateSelectBluetoothReader.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractGenericState.h" -#include "DeviceError.h" - -namespace governikus -{ - -class StateSelectBluetoothReader - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - - 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(); -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateSelectNfcReader.cpp b/src/core/states/StateSelectNfcReader.cpp deleted file mode 100644 index e08fda3..0000000 --- a/src/core/states/StateSelectNfcReader.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "context/ChangePinContext.h" -#include "ReaderManager.h" -#include "StateSelectNfcReader.h" - -using namespace governikus; - -StateSelectNfcReader::StateSelectNfcReader(const QSharedPointer& pContext) - : AbstractGenericState(pContext, false) -{ -} - - -void StateSelectNfcReader::run() -{ - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StateSelectNfcReader::onReaderDetected); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StateSelectNfcReader::onReaderDetected); - mConnections += connect(getContext().data(), &WorkflowContext::fireAbortCardSelection, this, &StateSelectNfcReader::fireAbort); - - onReaderDetected(); -} - - -void StateSelectNfcReader::onReaderDetected() -{ - auto readerInfos = ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::NFC); - if (!readerInfos.isEmpty()) - { - getContext()->setReaderName(readerInfos[0].getName()); - qDebug() << "Select first found Nfc reader" << readerInfos[0].getName(); - Q_EMIT fireSuccess(); - return; - } - - getContext()->setReaderName(QString()); - qDebug() << "No Nfc reader detected"; -} diff --git a/src/core/states/StateSelectNfcReader.h b/src/core/states/StateSelectNfcReader.h deleted file mode 100644 index bf5883e..0000000 --- a/src/core/states/StateSelectNfcReader.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractGenericState.h" - -namespace governikus -{ - -class StateSelectNfcReader - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - - StateSelectNfcReader(const QSharedPointer& pContext); - virtual void run() override; - - private Q_SLOTS: - void onReaderDetected(); - - Q_SIGNALS: - void fireAbort(); -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateSelectPcscReader.cpp b/src/core/states/StateSelectPcscReader.cpp deleted file mode 100644 index 60cabfc..0000000 --- a/src/core/states/StateSelectPcscReader.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "StateSelectPcscReader.h" - -#include -#include - -#include "ReaderManager.h" - -using namespace governikus; - -StateSelectPcscReader::StateSelectPcscReader(const QSharedPointer& pContext) - : AbstractGenericState(pContext) -{ -} - - -void StateSelectPcscReader::run() -{ - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StateSelectPcscReader::onReaderManagerSignal); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StateSelectPcscReader::onReaderManagerSignal); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StateSelectPcscReader::onReaderManagerSignal); - mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StateSelectPcscReader::onReaderManagerSignal); - mConnections += connect(getContext().data(), &WorkflowContext::fireAbortCardSelection, this, &StateSelectPcscReader::fireAbort); - - onReaderManagerSignal(); -} - - -void StateSelectPcscReader::onReaderManagerSignal() -{ - QVector readersWithNpa; - const auto allReaders = ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::PCSC); - for (const auto& readerInfo : allReaders) - { - if (readerInfo.getCardType() == CardType::EID_CARD) - { - readersWithNpa << readerInfo; - } - } - - if (readersWithNpa.size() == 1) - { - getContext()->setReaderName(readersWithNpa[0].getName()); - Q_EMIT fireSuccess(); - } -} diff --git a/src/core/states/StateSelectPcscReader.h b/src/core/states/StateSelectPcscReader.h deleted file mode 100644 index f5816d4..0000000 --- a/src/core/states/StateSelectPcscReader.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "states/AbstractGenericState.h" - -namespace governikus -{ - -class StateSelectPcscReader - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - - StateSelectPcscReader(const QSharedPointer& pContext); - virtual void run() override; - - private Q_SLOTS: - void onReaderManagerSignal(); - - Q_SIGNALS: - void fireAbort(); -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateSelectReader.cpp b/src/core/states/StateSelectReader.cpp new file mode 100644 index 0000000..b09831b --- /dev/null +++ b/src/core/states/StateSelectReader.cpp @@ -0,0 +1,121 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateSelectReader.h" + +#include "FuncUtils.h" +#include "ReaderManager.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(statemachine) + +using namespace governikus; + + +bool StateSelectReader::requiresCard(ReaderManagerPlugInType pPlugInType) +{ + return pPlugInType == ReaderManagerPlugInType::PCSC || + pPlugInType == ReaderManagerPlugInType::REMOTE; +} + + +StateSelectReader::StateSelectReader(const QSharedPointer& pContext) + : AbstractGenericState(pContext, false) +{ +} + + +void StateSelectReader::run() +{ + mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StateSelectReader::onReaderInfoChanged); + mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StateSelectReader::onReaderInfoChanged); + mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StateSelectReader::onReaderInfoChanged); + mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StateSelectReader::onReaderInfoChanged); + mConnections += connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderDeviceError, this, &StateSelectReader::onReaderDeviceError); + + onReaderInfoChanged(); + + ReaderManager& readerManager = ReaderManager::getInstance(); + const auto& readerPlugInTypes = getContext()->getReaderPlugInTypes(); + for (const auto t : readerPlugInTypes) + { + readerManager.startScan(t); + } +} + + +void StateSelectReader::onReaderInfoChanged() +{ + const QSharedPointer context = getContext(); + Q_ASSERT(context); + + const QVector& plugInTypes = context->getReaderPlugInTypes(); + const auto allReaders = ReaderManager::getInstance().getReaderInfos(plugInTypes); + const QVector selectableReaders = filter([](const ReaderInfo& info) + { + return info.isConnected() && (!requiresCard(info.getPlugInType()) || info.hasEidCard()); + }, allReaders); + + if (selectableReaders.isEmpty()) + { + qCDebug(statemachine) << "No selectable reader detected"; + + return; + } + + const ReaderInfo& readerInfo = selectableReaders.first(); + const QString readerName = readerInfo.getName(); + context->setReaderName(readerName); + qCDebug(statemachine) << "Select first found reader" << readerName << "of type" << readerInfo.getPlugInType(); + + Q_EMIT fireContinue(); +} + + +void StateSelectReader::onAbort() +{ + const QSharedPointer context = getContext(); + Q_ASSERT(context); + + ReaderManager::getInstance().stopScanAll(); + + const auto& readerName = context->getReaderName(); + if (!readerName.isEmpty()) + { + const ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(readerName); + if (readerInfo.isConnected()) + { + ReaderManager::getInstance().disconnectReader(readerName); + } + } + Q_EMIT fireRetry(); +} + + +void StateSelectReader::onReaderDeviceError(DeviceError pDeviceError) +{ + if (pDeviceError != DeviceError::DEVICE_POWERED_OFF) + { + updateStatus(DeviceErrorUtil::toGlobalStatus(pDeviceError)); + Q_EMIT fireAbort(); + } +} + + +void StateSelectReader::onEntry(QEvent* pEvent) +{ + const WorkflowContext* const context = getContext().data(); + Q_ASSERT(context); + + mConnections += connect(context, &WorkflowContext::fireAbortCardSelection, this, &StateSelectReader::onAbort); + + /* + * Note: the plugin types to be used in this state must be already set in the workflow context before this state is entered. + * Changing the plugin types in the context, e.g. from {NFC} to {BLUETOOTH}, causes the state to be left with a fireRetry signal. + */ + mConnections += connect(context, &WorkflowContext::fireReaderPlugInTypesChanged, this, &StateSelectReader::fireRetry); + + AbstractGenericState::onEntry(pEvent); +} diff --git a/src/core/states/StateSelectReader.h b/src/core/states/StateSelectReader.h new file mode 100644 index 0000000..d9c7ae4 --- /dev/null +++ b/src/core/states/StateSelectReader.h @@ -0,0 +1,36 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AbstractGenericState.h" + +namespace governikus +{ + +class StateSelectReader + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + private: + StateSelectReader(const QSharedPointer& pContext); + virtual void run() override; + + static bool requiresCard(ReaderManagerPlugInType pPlugInType); + + private Q_SLOTS: + void onReaderInfoChanged(); + void onAbort(); + void onReaderDeviceError(DeviceError pDeviceError); + + public: + void onEntry(QEvent* pEvent) override; + + Q_SIGNALS: + void fireRetry(); +}; + +} /* namespace governikus */ diff --git a/src/core/states/StateSelectReaderType.cpp b/src/core/states/StateSelectReaderType.cpp deleted file mode 100644 index 407008e..0000000 --- a/src/core/states/StateSelectReaderType.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "StateSelectReaderType.h" - - -using namespace governikus; - - -StateSelectReaderType::StateSelectReaderType(const QSharedPointer& pContext) - : AbstractGenericState(pContext) -{ -} - - -void StateSelectReaderType::onExit(QEvent* pEvent) -{ - AbstractGenericState::onExit(pEvent); - getContext()->setReaderType(ReaderManagerPlugInType::UNKNOWN); -} - - -void StateSelectReaderType::run() -{ - mConnections += connect(getContext().data(), &WorkflowContext::fireReaderTypeChanged, this, &StateSelectReaderType::onReaderTypeChanged); - - onReaderTypeChanged(); -} - - -void StateSelectReaderType::onReaderTypeChanged() -{ - getContext()->setReaderName(QString()); - - switch (getContext()->getReaderType()) - { - case ReaderManagerPlugInType::BLUETOOTH: - Q_EMIT fireSelectBluetoothReader(); - break; - - case ReaderManagerPlugInType::NFC: - Q_EMIT fireSelectNfcReader(); - break; - - case ReaderManagerPlugInType::PCSC: - Q_EMIT fireSelectPcscReader(); - break; - - case ReaderManagerPlugInType::UNKNOWN: - qInfo() << "ReaderManagerPlugInType not (yet) set to WorkflowContext, waiting..."; - break; - } -} diff --git a/src/core/states/StateSelectReaderType.h b/src/core/states/StateSelectReaderType.h deleted file mode 100644 index 0028dc2..0000000 --- a/src/core/states/StateSelectReaderType.h +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractGenericState.h" - -namespace governikus -{ - -class StateSelectReaderType - : public AbstractGenericState -{ - Q_OBJECT - friend class StateBuilder; - - StateSelectReaderType(const QSharedPointer& pContext); - - virtual void run() override; - - protected: - void onExit(QEvent* pEvent) override; - - private Q_SLOTS: - void onReaderTypeChanged(); - - Q_SIGNALS: - void fireSelectBluetoothReader(); - void fireSelectNfcReader(); - void fireSelectPcscReader(); -}; - -} /* namespace governikus */ diff --git a/src/core/states/StateStartPaos.cpp b/src/core/states/StateStartPaos.cpp index d5fca84..58d763b 100644 --- a/src/core/states/StateStartPaos.cpp +++ b/src/core/states/StateStartPaos.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -21,5 +21,5 @@ void StateStartPaos::run() auto sessionId = getContext()->getTcToken()->getSessionIdentifier(); getContext()->setStartPaos(QSharedPointer(new StartPaos(sessionId))); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateStartPaos.h b/src/core/states/StateStartPaos.h index 58791d8..a52d2e9 100644 --- a/src/core/states/StateStartPaos.h +++ b/src/core/states/StateStartPaos.h @@ -1,7 +1,7 @@ /*! * \brief State machine state: Start PAOS. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateStartPaosResponse.cpp b/src/core/states/StateStartPaosResponse.cpp index c0bc257..0c668bd 100644 --- a/src/core/states/StateStartPaosResponse.cpp +++ b/src/core/states/StateStartPaosResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "StateStartPaosResponse.h" @@ -20,12 +20,12 @@ void StateStartPaosResponse::run() const Result& result = startPaosResponse->getResult(); if (result.isOk()) { - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); return; } + // we override our result with the one sent from server qDebug() << "Processing server result:" << result.getMajorString() << result.getMinorString() << result.getMessage(); - setStatus(result.toStatus()); - Q_EMIT fireError(); - + getContext()->setStatus(result.toStatus(), false); + Q_EMIT fireAbort(); } diff --git a/src/core/states/StateStartPaosResponse.h b/src/core/states/StateStartPaosResponse.h index 95acaf1..eb316f4 100644 --- a/src/core/states/StateStartPaosResponse.h +++ b/src/core/states/StateStartPaosResponse.h @@ -1,7 +1,7 @@ /*! * \brief State to process StartPaosResponse from Server. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateTransmit.cpp b/src/core/states/StateTransmit.cpp index 8a73871..ab62320 100644 --- a/src/core/states/StateTransmit.cpp +++ b/src/core/states/StateTransmit.cpp @@ -1,7 +1,5 @@ /*! - * StateTransmit.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "CardConnection.h" @@ -36,18 +34,19 @@ void StateTransmit::onCardCommandDone(QSharedPointer pCommand) { QSharedPointer response(getContext()->getTransmitResponses().last()); response->setOutputApdus(transmitCommand->getOutputApduAsHex()); - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } else if (returnCode == CardReturnCode::UNEXPECTED_TRANSMIT_STATUS) { QSharedPointer response(getContext()->getTransmitResponses().last()); response->setOutputApdus(transmitCommand->getOutputApduAsHex()); - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); // set the result to the model so it is written to the PAOS response - Q_EMIT fireSuccess(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); // set the result to the model so it is written to the PAOS response + getContext()->setTransmitResponseFailed(true); // Return the correct return code according to the last minute test spec update. + Q_EMIT fireContinue(); } else { - setStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); - Q_EMIT fireError(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(returnCode)); + Q_EMIT fireAbort(); } } diff --git a/src/core/states/StateTransmit.h b/src/core/states/StateTransmit.h index 4b06738..57a667e 100644 --- a/src/core/states/StateTransmit.h +++ b/src/core/states/StateTransmit.h @@ -1,9 +1,7 @@ /*! - * StateTransmit.h - * * \brief Process received transmits. Send it to the card and create a response. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/StateUpdateRetryCounter.cpp b/src/core/states/StateUpdateRetryCounter.cpp index e289173..2580e0c 100644 --- a/src/core/states/StateUpdateRetryCounter.cpp +++ b/src/core/states/StateUpdateRetryCounter.cpp @@ -1,12 +1,12 @@ /*! - * StateUpdateRetryCounter.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "StateUpdateRetryCounter.h" + #include "CardConnection.h" #include "Result.h" -#include "StateUpdateRetryCounter.h" + using namespace governikus; @@ -22,8 +22,15 @@ void StateUpdateRetryCounter::run() qDebug() << "StateUpdateRetryCounter::run()"; auto cardConnection = getContext()->getCardConnection(); - Q_ASSERT(cardConnection != nullptr); - mConnections += cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); + if (cardConnection != nullptr) + { + mConnections += cardConnection->callUpdateRetryCounterCommand(this, &StateUpdateRetryCounter::onUpdateRetryCounterDone); + } + else + { + qDebug() << "Skipping update because there is no card connection"; + Q_EMIT fireContinue(); + } } @@ -34,26 +41,10 @@ void StateUpdateRetryCounter::onUpdateRetryCounterDone(QSharedPointergetReturnCode() != CardReturnCode::OK) { qCritical() << "An error occurred while communicating with the card reader, cannot determine retry counter, abort state"; - setStatus(CardReturnCodeUtil::toGlobalStatus(pCommand->getReturnCode())); - Q_EMIT fireError(); + updateStatus(CardReturnCodeUtil::toGlobalStatus(pCommand->getReturnCode())); + Q_EMIT fireAbort(); return; } - auto cardConnection = getContext()->getCardConnection(); - switch (cardConnection->getReaderInfo().getRetryCounter()) - { - 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(); - } + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateUpdateRetryCounter.h b/src/core/states/StateUpdateRetryCounter.h index 88b57c9..db42916 100644 --- a/src/core/states/StateUpdateRetryCounter.h +++ b/src/core/states/StateUpdateRetryCounter.h @@ -2,7 +2,7 @@ * \brief Controller for the step that updates the retry * counter of a card. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,11 +25,6 @@ class StateUpdateRetryCounter private Q_SLOTS: void onUpdateRetryCounterDone(QSharedPointer pCommand); - - Q_SIGNALS: - void fireRetryCounterIsZero(); - void fireRetryCounterIsOne(); - void fireRetryCounterIsGTOne(); }; } /* namespace governikus */ diff --git a/src/core/states/StateWriteHistory.cpp b/src/core/states/StateWriteHistory.cpp index 05929c9..766365f 100644 --- a/src/core/states/StateWriteHistory.cpp +++ b/src/core/states/StateWriteHistory.cpp @@ -1,7 +1,5 @@ /* - * StateWriteHistory.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AppSettings.h" @@ -21,14 +19,14 @@ void StateWriteHistory::run() if (!AppSettings::getInstance().getHistorySettings().isEnabled()) { qDebug() << "History disabled"; - Q_EMIT fireError(); + Q_EMIT fireContinue(); return; } if (getContext()->getDidAuthenticateEac1() == nullptr || getContext()->getEffectiveAccessRights().isEmpty()) { qWarning() << "No EAC1 structure or effective CHAT in model."; - Q_EMIT fireError(); + Q_EMIT fireAbort(); return; } @@ -54,11 +52,11 @@ void StateWriteHistory::run() if (!subjectName.isNull() && !termOfUsage.isNull()) { - HistoryEntry entry(subjectName, subjectUrl, certDesc->getPurpose(), QDateTime::currentDateTime(), termOfUsage + QStringLiteral("\n\n") + validity, requestedData.join(QStringLiteral(", "))); - AppSettings::getInstance().getHistorySettings().addHistoryEntry(entry); + HistoryInfo info(subjectName, subjectUrl, certDesc->getPurpose(), QDateTime::currentDateTime(), termOfUsage + QStringLiteral("\n\n") + validity, requestedData.join(QStringLiteral(", "))); + AppSettings::getInstance().getHistorySettings().addHistoryInfo(info); AppSettings::getInstance().getHistorySettings().save(); } } } - Q_EMIT fireSuccess(); + Q_EMIT fireContinue(); } diff --git a/src/core/states/StateWriteHistory.h b/src/core/states/StateWriteHistory.h index 7c02416..93806e3 100644 --- a/src/core/states/StateWriteHistory.h +++ b/src/core/states/StateWriteHistory.h @@ -1,10 +1,8 @@ /* - * StateWriteHistory.h - * * * \brief Writes the history entry . * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/core/states/remote_service/StateEstablishPaceChannel.cpp b/src/core/states/remote_service/StateEstablishPaceChannel.cpp new file mode 100644 index 0000000..cecf4b4 --- /dev/null +++ b/src/core/states/remote_service/StateEstablishPaceChannel.cpp @@ -0,0 +1,141 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateEstablishPaceChannel.h" + +#include "EstablishPACEChannelParser.h" +#include "ServerMessageHandler.h" + +#include + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +StateEstablishPaceChannel::StateEstablishPaceChannel(const QSharedPointer& pContext) + : AbstractGenericState(pContext) +{ +} + + +StateEstablishPaceChannel::~StateEstablishPaceChannel() +{ +} + + +void StateEstablishPaceChannel::onEntry(QEvent* pEvent) +{ + AbstractGenericState::onEntry(pEvent); + + const QSharedPointer& context = getContext(); + + mEstablishPaceChannelMessage = context->getEstablishPaceChannelMessage(); + Q_ASSERT(mEstablishPaceChannelMessage); + + const QSharedPointer remoteServer = context->getRemoteServer(); + Q_ASSERT(remoteServer); + mMessageHandler = remoteServer->getMessageHandler(); + Q_ASSERT(mMessageHandler); + + auto cardConnection = context->getCardConnection(); + if (!cardConnection) + { + Q_EMIT fireContinue(); + return; + } + + mConnections += connect(cardConnection.data(), &CardConnection::fireReaderInfoChanged, this, &StateEstablishPaceChannel::onReaderInfoChanged); + mConnections += connect(getContext().data(), &RemoteServiceContext::fireCancelEstablishPaceChannel, this, &StateEstablishPaceChannel::onCancelEstablishPaceChannel); + mConnections += connect(getContext()->getRemoteServer().data(), &RemoteServer::fireConnectedChanged, this, &AbstractState::fireContinue); +} + + +void StateEstablishPaceChannel::onExit(QEvent* pEvent) +{ + AbstractGenericState::onExit(pEvent); + + mMessageHandler.reset(); +} + + +void StateEstablishPaceChannel::run() +{ + const QSharedPointer& context = getContext(); + + EstablishPACEChannelParser parser = EstablishPACEChannelParser::fromCcid(mEstablishPaceChannelMessage->getInputData()); + QString pacePin; + switch (parser.getPasswordId()) + { + case PACE_PASSWORD_ID::PACE_CAN: + pacePin = context->getCan(); + context->setCan(QString()); + break; + + case PACE_PASSWORD_ID::PACE_PIN: + pacePin = context->getPin(); + context->setPin(QString()); + break; + + case PACE_PASSWORD_ID::PACE_PUK: + pacePin = context->getPuk(); + context->setPuk(QString()); + break; + + default: + mMessageHandler->sendEstablishPaceChannelResponse(mEstablishPaceChannelMessage->getSlotHandle(), EstablishPACEChannelOutput()); + return; + } + + auto cardConnection = context->getCardConnection(); + Q_ASSERT(cardConnection); + mConnections += cardConnection->callEstablishPaceChannelCommand(this, + &StateEstablishPaceChannel::onEstablishConnectionDone, + parser.getPasswordId(), + pacePin, + parser.getChat(), + parser.getCertificateDescription()); +} + + +void StateEstablishPaceChannel::onCancelEstablishPaceChannel() +{ + EstablishPACEChannelOutput channelOutput = EstablishPACEChannelOutput(); + channelOutput.setPaceReturnCode(CardReturnCode::CANCELLATION_BY_USER); + mMessageHandler->sendEstablishPaceChannelResponse(mEstablishPaceChannelMessage->getSlotHandle(), channelOutput); + + Q_EMIT fireContinue(); +} + + +void StateEstablishPaceChannel::onReaderInfoChanged(const ReaderInfo& pReaderInfo) +{ + if (!pReaderInfo.hasEidCard()) + { + EstablishPACEChannelOutput channelOutput = EstablishPACEChannelOutput(); + channelOutput.setPaceReturnCode(CardReturnCode::CARD_NOT_FOUND); + mMessageHandler->sendEstablishPaceChannelResponse(mEstablishPaceChannelMessage->getSlotHandle(), channelOutput); + + Q_EMIT fireContinue(); + } +} + + +void StateEstablishPaceChannel::onEstablishConnectionDone(QSharedPointer pCommand) +{ + const QSharedPointer establishPaceChannelCommand = pCommand.dynamicCast(); + if (establishPaceChannelCommand) + { + mMessageHandler->sendEstablishPaceChannelResponse(mEstablishPaceChannelMessage->getSlotHandle(), establishPaceChannelCommand->getPaceOutput()); + } + else + { + Q_ASSERT(false); + qCDebug(remote_device) << "Expected an EstablishPaceChannelCommand as response!"; + mMessageHandler->sendEstablishPaceChannelResponse(mEstablishPaceChannelMessage->getSlotHandle(), EstablishPACEChannelOutput()); + } + + Q_EMIT fireContinue(); +} diff --git a/src/core/states/remote_service/StateEstablishPaceChannel.h b/src/core/states/remote_service/StateEstablishPaceChannel.h new file mode 100644 index 0000000..9abca86 --- /dev/null +++ b/src/core/states/remote_service/StateEstablishPaceChannel.h @@ -0,0 +1,45 @@ +/*! + * \brief This state executes the remote message PACE channel establish. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "context/RemoteServiceContext.h" +#include "states/AbstractGenericState.h" + +namespace governikus +{ + + +class StateEstablishPaceChannel + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + private: + QSharedPointer mEstablishPaceChannelMessage; + QSharedPointer mMessageHandler; + + StateEstablishPaceChannel(const QSharedPointer& pContext); + virtual void run() override; + + private Q_SLOTS: + void onCancelEstablishPaceChannel(); + void onReaderInfoChanged(const ReaderInfo& pReaderInfo); + void onEstablishConnectionDone(QSharedPointer pCommand); + + protected: + void onExit(QEvent* pEvent) override; + + public: + virtual ~StateEstablishPaceChannel() override; + + void onEntry(QEvent* pEvent) override; + +}; + +} /* namespace governikus */ diff --git a/src/core/states/remote_service/StateProcessRemoteMessages.cpp b/src/core/states/remote_service/StateProcessRemoteMessages.cpp new file mode 100644 index 0000000..fd50f72 --- /dev/null +++ b/src/core/states/remote_service/StateProcessRemoteMessages.cpp @@ -0,0 +1,86 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateProcessRemoteMessages.h" + +#include "ServerMessageHandler.h" + + +using namespace governikus; + + +StateProcessRemoteMessages::StateProcessRemoteMessages(const QSharedPointer& pContext) + : AbstractGenericState(pContext) + , mMessageConnections() +{ +} + + +StateProcessRemoteMessages::~StateProcessRemoteMessages() +{ +} + + +void StateProcessRemoteMessages::run() +{ + const QSharedPointer context = getContext(); + const QSharedPointer server = context->getRemoteServer(); + Q_ASSERT(server); + + mConnections += connect(server.data(), &RemoteServer::fireMessageHandlerAdded, this, &StateProcessRemoteMessages::onMessageHandlerAdded); + + const auto messageHandler = server->getMessageHandler(); + if (messageHandler) + { + onMessageHandlerAdded(server->getMessageHandler()); + } + else + { + context->onResetMessageHandler(); + } +} + + +void StateProcessRemoteMessages::onMessageHandlerAdded(const QSharedPointer& pHandler) +{ + if (!pHandler) + { + return; + } + + mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireEstablishPaceChannel, this, &StateProcessRemoteMessages::onEstablishPaceChannel, Qt::UniqueConnection); + mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireClosed, this, &StateProcessRemoteMessages::onClosed, Qt::UniqueConnection); +} + + +void StateProcessRemoteMessages::onClosed() +{ + for (const auto& connection : qAsConst(mMessageConnections)) + { + disconnect(connection); + } + + getContext()->onResetMessageHandler(); +} + + +void StateProcessRemoteMessages::onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection) +{ + Q_ASSERT(pMessage); + + getContext()->setEstablishPaceChannelMessage(pMessage); + getContext()->setCardConnection(pConnection); + Q_EMIT fireEstablishPaceChannel(); +} + + +void StateProcessRemoteMessages::onExit(QEvent* pEvent) +{ + for (const auto& connection : qAsConst(mMessageConnections)) + { + disconnect(connection); + } + + AbstractState::onExit(pEvent); +} diff --git a/src/core/states/remote_service/StateProcessRemoteMessages.h b/src/core/states/remote_service/StateProcessRemoteMessages.h new file mode 100644 index 0000000..b19651a --- /dev/null +++ b/src/core/states/remote_service/StateProcessRemoteMessages.h @@ -0,0 +1,45 @@ +/*! + * \brief This state allows the processing of ordenary remote messages in the + * background and handles special PACE messages. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "context/RemoteServiceContext.h" +#include "states/AbstractGenericState.h" + +namespace governikus +{ + +class StateProcessRemoteMessages + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + private: + QVector mMessageConnections; + + StateProcessRemoteMessages(const QSharedPointer& pContext); + virtual void run() override; + + private Q_SLOTS: + void onMessageHandlerAdded(const QSharedPointer& pHandler); + void onClosed(); + void onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); + + protected: + void onExit(QEvent* pEvent) override; + + public: + virtual ~StateProcessRemoteMessages() override; + + Q_SIGNALS: + void fireEstablishPaceChannel(); + +}; + +} /* namespace governikus */ diff --git a/src/core/states/remote_service/StateStartRemoteService.cpp b/src/core/states/remote_service/StateStartRemoteService.cpp new file mode 100644 index 0000000..d2369c0 --- /dev/null +++ b/src/core/states/remote_service/StateStartRemoteService.cpp @@ -0,0 +1,44 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateStartRemoteService.h" + +#include "AppSettings.h" +#include "Env.h" +#include "ServerMessageHandler.h" + +using namespace governikus; + + +StateStartRemoteService::StateStartRemoteService(const QSharedPointer& pContext) + : AbstractGenericState(pContext) +{ +} + + +StateStartRemoteService::~StateStartRemoteService() +{ +} + + +void StateStartRemoteService::run() +{ + QSharedPointer context = getContext(); + QSharedPointer server = context->getRemoteServer(); + Q_ASSERT(server); + + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + server->start(settings.getServerName()); + + connect(server.data(), &RemoteServer::fireMessageHandlerAdded, this, &StateStartRemoteService::onMessageHandlerAdded); + + Q_EMIT fireContinue(); +} + + +void StateStartRemoteService::onMessageHandlerAdded(QSharedPointer pHandler) +{ + const QSharedPointer context = getContext(); + connect(pHandler.data(), &ServerMessageHandler::fireClosed, context.data(), &RemoteServiceContext::onResetMessageHandler, Qt::QueuedConnection); +} diff --git a/src/core/states/remote_service/StateStartRemoteService.h b/src/core/states/remote_service/StateStartRemoteService.h new file mode 100644 index 0000000..1df7b75 --- /dev/null +++ b/src/core/states/remote_service/StateStartRemoteService.h @@ -0,0 +1,34 @@ +/*! + * \brief Start the remote service. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "context/RemoteServiceContext.h" +#include "states/AbstractGenericState.h" + +namespace governikus +{ + +class StateStartRemoteService + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + StateStartRemoteService(const QSharedPointer& pContext); + + virtual void run() override; + + public: + virtual ~StateStartRemoteService() override; + + public Q_SLOTS: + void onMessageHandlerAdded(QSharedPointer pHandler); + +}; + +} /* namespace governikus */ diff --git a/src/core/states/remote_service/StateStopRemoteService.cpp b/src/core/states/remote_service/StateStopRemoteService.cpp new file mode 100644 index 0000000..66c73b5 --- /dev/null +++ b/src/core/states/remote_service/StateStopRemoteService.cpp @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StateStopRemoteService.h" + +#include "AppSettings.h" + +using namespace governikus; + + +StateStopRemoteService::StateStopRemoteService(const QSharedPointer& pContext) + : AbstractGenericState(pContext) +{ +} + + +StateStopRemoteService::~StateStopRemoteService() +{ +} + + +void StateStopRemoteService::run() +{ + Q_EMIT fireContinue(); +} + + +void StateStopRemoteService::onExit(QEvent* pEvent) +{ + // onExit: Stop if the user cancels the workflow, too. + + const QSharedPointer server = getContext()->getRemoteServer(); + Q_ASSERT(server); + server->stop(); + + AbstractState::onExit(pEvent); +} diff --git a/src/core/states/remote_service/StateStopRemoteService.h b/src/core/states/remote_service/StateStopRemoteService.h new file mode 100644 index 0000000..ff73297 --- /dev/null +++ b/src/core/states/remote_service/StateStopRemoteService.h @@ -0,0 +1,32 @@ +/*! + * \brief Stop the remote service. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "context/RemoteServiceContext.h" +#include "states/AbstractGenericState.h" + +namespace governikus +{ + +class StateStopRemoteService + : public AbstractGenericState +{ + Q_OBJECT + friend class StateBuilder; + + StateStopRemoteService(const QSharedPointer& pContext); + + virtual void run() override; + void onExit(QEvent* pEvent) override; + + public: + virtual ~StateStopRemoteService() override; + +}; + +} /* namespace governikus */ diff --git a/src/core/view/UILoader.cpp b/src/core/view/UILoader.cpp index a5afc47..3bc20e6 100644 --- a/src/core/view/UILoader.cpp +++ b/src/core/view/UILoader.cpp @@ -1,10 +1,11 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "UILoader.h" #include "SingletonHelper.h" +#include "UIPlugIn.h" #include #include diff --git a/src/core/view/UILoader.h b/src/core/view/UILoader.h index 6bfa81b..43f1429 100644 --- a/src/core/view/UILoader.h +++ b/src/core/view/UILoader.h @@ -1,13 +1,12 @@ /*! * \brief Loader to initialize UIPlugIns. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "EnumHelper.h" -#include "UIPlugIn.h" #include #include @@ -16,6 +15,9 @@ namespace governikus { +class UIPlugIn; + + defineEnumType(UIPlugInName, UIPlugInQml, UIPlugInCli, UIPlugInWidgets, UIPlugInJsonApi, UIPlugInWebSocket, UIPlugInAidl) class UILoader diff --git a/src/core/view/UIPlugIn.cpp b/src/core/view/UIPlugIn.cpp index 58e3b23..28cf275 100644 --- a/src/core/view/UIPlugIn.cpp +++ b/src/core/view/UIPlugIn.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugIn.h" @@ -28,6 +28,17 @@ void UIPlugIn::onShowUi(UiModule pModule) } +void UIPlugIn::onShowReaderSettings() +{ +} + + +void UIPlugIn::onSwitchToReaderSettingsRequested() +{ + Q_EMIT fireSwitchToReaderSettingsRequested(); +} + + #ifndef QT_NO_NETWORKPROXY void UIPlugIn::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) { diff --git a/src/core/view/UIPlugIn.h b/src/core/view/UIPlugIn.h index 7c32a8b..c3d3902 100644 --- a/src/core/view/UIPlugIn.h +++ b/src/core/view/UIPlugIn.h @@ -1,13 +1,12 @@ /*! * \brief Abstract layer to UI implementations. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "ActivationHandler.h" -#include "context/WorkflowContext.h" #include #include @@ -15,6 +14,9 @@ namespace governikus { +class WorkflowContext; + + class UIPlugIn : public QObject { @@ -30,6 +32,8 @@ class UIPlugIn virtual void onWorkflowFinished(QSharedPointer pContext) = 0; virtual void onApplicationStarted(); virtual void onShowUi(UiModule pModule); + virtual void onShowReaderSettings(); + virtual void onSwitchToReaderSettingsRequested(); #ifndef QT_NO_NETWORKPROXY virtual void onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); #endif @@ -37,6 +41,8 @@ class UIPlugIn Q_SIGNALS: void fireChangePinRequest(); void fireSelfAuthenticationRequested(); + void fireSwitchToReaderSettingsRequested(); + void fireRemoteServiceRequested(); void fireQuitApplicationRequest(); void fireCloseReminderFinished(bool pDontRemindAgain); diff --git a/src/export/CMakeLists.txt b/src/export/CMakeLists.txt index 9643abb..f35180a 100644 --- a/src/export/CMakeLists.txt +++ b/src/export/CMakeLists.txt @@ -1,3 +1,3 @@ ADD_PLATFORM_LIBRARY(AusweisAppExport) -TARGET_LINK_LIBRARIES(AusweisAppExport Qt5::Svg Qt5::PrintSupport AusweisAppSettings) +TARGET_LINK_LIBRARIES(AusweisAppExport Qt5::Core Qt5::Svg AusweisAppSettings) diff --git a/src/export/PdfCreator.cpp b/src/export/PdfCreator.cpp index 24d3889..f42a573 100644 --- a/src/export/PdfCreator.cpp +++ b/src/export/PdfCreator.cpp @@ -1,236 +1,130 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "PdfCreator.h" -#include "AppSettings.h" - -#include -#include -#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() +PdfCreator::PdfCreator(const QString& pFilename, const QString& pTitle, const QString& pHeadline, const QString& pContent) + : mPdfWriter(pFilename) + , mHeader() , mContent() + , mFooter() { - if (!mFilename.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) - { - mFilename += QLatin1String(".pdf"); - } + mHeader.setUndoRedoEnabled(false); + mContent.setUndoRedoEnabled(false); + mFooter.setUndoRedoEnabled(false); + + qDebug() << "Use filename for PDF:" << pFilename; + + const QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMargins(20, 20, 20, 15), QPageLayout::Millimeter); + mPdfWriter.setPageLayout(layout); + mPdfWriter.setCreator(QCoreApplication::applicationName()); + mPdfWriter.setTitle(pTitle); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + mPdfWriter.setPdfVersion(QPagedPaintDevice::PdfVersion_A1b); +#endif + + createHeader(pTitle, pHeadline); + createFooter(); + createContent(pContent); } -PdfCreator::~PdfCreator() +void PdfCreator::createHeader(const QString& pTitle, const QString& pHeadline) { - -} - - -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(), + const auto& header = QStringLiteral("" + "" + "" + "" + "" + "
" + "

%1 - %2

" + "

%3" + "

" + "

%4

" + "
").arg( + pTitle, + QCoreApplication::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; + pHeadline); QSvgRenderer renderer(QStringLiteral(":/images/npa.svg")); - QImage image(768, 768, QImage::Format_ARGB32); + QImage image(768, 768, QImage::Format_RGB32); 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(); + mHeader.addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("pdflogo")), image); + mHeader.setHtml(header); +} - //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())); +void PdfCreator::createContent(const QString& pContent) +{ + mContent.setHtml(pContent); +} - //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. +void PdfCreator::createFooter() +{ + const auto& footer = QStringLiteral("

%1

").arg( + tr("For further information, please see https://www.ausweisapp.bund.de/")); - QPainter painter(&printer); + mFooter.setHtml(footer); +} + +int qt_defaultDpi(); +bool PdfCreator::save() +{ + mPdfWriter.setResolution(qt_defaultDpi()); + const QRect pageArea(mPdfWriter.pageLayout().paintRectPixels(mPdfWriter.resolution())); + + QPainter painter(&mPdfWriter); + if (!painter.isActive()) + { + qCritical() << "Cannot paint into pdf file. Check file system permissions!"; + return false; + } + + mHeader.setPageSize(pageArea.size()); + mFooter.setPageSize(pageArea.size()); + const qreal headerHeight = mHeader.size().height(); + const QSizeF contentMaxPageSize(pageArea.width(), pageArea.height() - headerHeight - mFooter.size().height()); + mContent.setPageSize(contentMaxPageSize); + + const QRect contentRect = QRect(QPoint(0, 0), mContent.size().toSize()); + QRect currentRect = QRect(QPoint(0, 0), contentMaxPageSize.toSize()); 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); + { + painter.resetTransform(); + + mHeader.drawContents(&painter); + painter.translate(0, headerHeight); + + painter.save(); + painter.translate(0, -currentRect.y()); + mContent.drawContents(&painter, currentRect); + painter.restore(); + painter.translate(0, currentRect.height()); + + mFooter.drawContents(&painter); - //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(); + mPdfWriter.newPage(); } } + + return true; } diff --git a/src/export/PdfCreator.h b/src/export/PdfCreator.h index 84b2ea4..6674e7b 100644 --- a/src/export/PdfCreator.h +++ b/src/export/PdfCreator.h @@ -1,52 +1,36 @@ /*! - * \brief Tool to create PDF-Documents for history or selfauthentication result. + * \brief Tool to create PDF-Documents. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include -#include +#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; + QPdfWriter mPdfWriter; + QTextDocument mHeader; + QTextDocument mContent; + QTextDocument mFooter; - void closeTable(); + void createHeader(const QString& pTitle, const QString& pHeadline); + void createContent(const QString& pContent); + void createFooter(); 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(); - + PdfCreator(const QString& pFilename, const QString& pTitle, const QString& pHeadline, const QString& pContent); + bool save(); }; diff --git a/src/export/PdfExporter.cpp b/src/export/PdfExporter.cpp new file mode 100644 index 0000000..3b0029a --- /dev/null +++ b/src/export/PdfExporter.cpp @@ -0,0 +1,163 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PdfExporter.h" + +#include "AppSettings.h" +#include "LanguageLoader.h" +#include "PdfCreator.h" + +#include + +using namespace governikus; + +namespace +{ +QString getValueOrWhitespace(const QStringList& pValues, int i) +{ + if (i < pValues.size() && !pValues.at(i).isEmpty()) + { + return pValues.at(i); + } + return QStringLiteral(" "); +} + + +} + + +PdfExporter::PdfExporter(const QString& pFilename, bool pOpenFile, bool pFixFilename) + : mFilename(pFilename) + , mOpenFile(pOpenFile) + , mColoredRow(false) + , mColumnCount(0) + , mContent() +{ + if (pFixFilename && !mFilename.isEmpty() + && !mFilename.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) + { + mFilename += QStringLiteral(".pdf"); + } +} + + +QString PdfExporter::getContent() const +{ + return mContent.join(QString()); +} + + +void PdfExporter::checkOpenFile(bool pSuccess) +{ + if (mOpenFile && pSuccess) + { + QDesktopServices::openUrl(QUrl(mFilename)); + } +} + + +void PdfExporter::initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues) +{ + Q_ASSERT(mColumnCount == 0); + + mColumnCount = pColumnCount; + mContent << QStringLiteral(""); + for (int i = 0; i < mColumnCount; ++i) + { + const auto& width = i < pWidth.size() ? QStringLiteral(" width='%1'").arg(pWidth.at(i)) : QString(); + mContent << QStringLiteral("").arg(width, getValueOrWhitespace(pValues, i)); + } + mContent << QStringLiteral(""); +} + + +void PdfExporter::addTableRow(const QStringList& pValues) +{ + mContent << (mColoredRow ? QStringLiteral("") : QStringLiteral("")); + for (int i = 0; i < mColumnCount; ++i) + { + mContent << QStringLiteral("").arg(getValueOrWhitespace(pValues, i)); + } + mContent << QStringLiteral(""); +} + + +void PdfExporter::closeTable() +{ + mContent << QStringLiteral("
%2
%2
"); + mColumnCount = 0; + mColoredRow = false; +} + + +void PdfExporter::toggleRowColor() +{ + mColoredRow = !mColoredRow; +} + + +bool PdfExporter::exportHistory() +{ + if (mFilename.isEmpty()) + { + return false; + } + mContent.clear(); + + const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + + initTable(3, {180, 80}, {tr("Date"), tr("Details")}); + const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); + const auto& infos = AppSettings::getInstance().getHistorySettings().getHistoryInfos(); + for (const auto& entry : infos) + { + toggleRowColor(); + const QString& dateTimeEntry = locale.toString(entry.getDateTime(), dateTimeFormat); + addTableRow({dateTimeEntry, tr("Provider:"), entry.getSubjectName()}); + addTableRow({QString(), tr("Purpose:"), entry.getPurpose()}); + addTableRow({QString(), tr("Data:"), entry.getRequestedData()}); + } + closeTable(); + + const auto& now = QDateTime::currentDateTime(); + QString date = locale.toString(now, tr("dd.MM.yyyy")); + QString time = locale.toString(now, tr("hh:mm AP")); + const auto& headline = tr("At %1 %2 the following data were saved:").arg(date, time); + + PdfCreator pdf(mFilename, tr("History"), headline, getContent()); + const bool success = pdf.save(); + checkOpenFile(success); + return success; +} + + +bool PdfExporter::exportSelfInfo(const QDateTime& pDate, const QVector >& pInfoData) +{ + if (mFilename.isEmpty()) + { + return false; + } + mContent.clear(); + + initTable(2, {180}, {tr("Entry"), tr("Content")}); + for (const auto& entry : pInfoData) + { + if (!entry.first.isEmpty()) + { + toggleRowColor(); + } + addTableRow({entry.first, entry.second}); + } + closeTable(); + + const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + QString date = locale.toString(pDate, tr("dd.MM.yyyy")); + QString time = locale.toString(pDate, tr("hh:mm AP")); + const auto& headline = tr("At %1 %2 the following data has been read out of your ID card:").arg(date, time); + + PdfCreator pdf(mFilename, tr("Information"), headline, getContent()); + const bool success = pdf.save(); + checkOpenFile(success); + return success; +} diff --git a/src/export/PdfExporter.h b/src/export/PdfExporter.h new file mode 100644 index 0000000..b52c390 --- /dev/null +++ b/src/export/PdfExporter.h @@ -0,0 +1,43 @@ +/*! + * \brief Tool to export data of history or selfauthentication result. + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace governikus +{ +class PdfExporter +{ + Q_DECLARE_TR_FUNCTIONS(governikus::PdfExporter) + + private: + QString mFilename; + bool mOpenFile; + bool mColoredRow; + int mColumnCount; + QStringList mContent; + + QString getContent() const; + + void checkOpenFile(bool pSuccess); + void initTable(int pColumnCount, const QList& pWidth, const QStringList& pValues); + void closeTable(); + void addTableRow(const QStringList& pValues); + void toggleRowColor(); + + public: + PdfExporter(const QString& pFilename, bool pOpenFile = true, bool pFixFilename = true); + bool exportHistory(); + bool exportSelfInfo(const QDateTime& pDate, const QVector >& pInfoData); +}; + +} /* namespace governikus */ diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index f1b1f85..6c7792c 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -1,18 +1,60 @@ ################################## http_parser ######################################################################### -FILE(GLOB_RECURSE EXTERNAL_HTTP_PARSER_FILES http_parser/*.cpp) -ADD_LIBRARY(AusweisAppExternalHttpParser ${EXTERNAL_HTTP_PARSER_FILES}) -TARGET_INCLUDE_DIRECTORIES(AusweisAppExternalHttpParser INTERFACE "$") +FUNCTION(PRINT_HTTP_PARSER _include_dir _lib_dir) + SET(_file "${_include_dir}/http_parser.h") -IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wcovered-switch-default") - SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-covered-switch-default") + FILE(READ "${_file}" _file_content) + IF(_file_content) + STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" _major "${_file_content}") + STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" _minor "${_file_content}") + STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_PATCH[\t ]+([0-9]+).*" "\\1" _patch "${_file_content}") + SET(_version "${_major}.${_minor}.${_patch}") + ENDIF() + + IF(NOT EXISTS "${_lib_dir}") + SET(_lib_dir "INTERNAL") + ENDIF() + + MESSAGE(STATUS "HttpParser: ${_lib_dir} (${_version})") +ENDFUNCTION() + +IF(NOT CMAKE_VERSION VERSION_LESS "3.10") + FIND_PATH(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h) + FIND_LIBRARY(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser) + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_PARSER REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) + MARK_AS_ADVANCED(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY) ENDIF() -IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wconversion") - SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-conversion") +IF(HTTP_PARSER_FOUND) + ADD_LIBRARY(AusweisAppExternal::HttpParser UNKNOWN IMPORTED GLOBAL) + SET_TARGET_PROPERTIES(AusweisAppExternal::HttpParser PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${HTTP_PARSER_INCLUDE_DIR}") + SET_TARGET_PROPERTIES(AusweisAppExternal::HttpParser PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${HTTP_PARSER_LIBRARY}") + +ELSE() + SET(HTTP_PARSER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/http_parser") + FILE(GLOB_RECURSE EXTERNAL_HTTP_PARSER_FILES ${HTTP_PARSER_INCLUDE_DIR}/*.cpp) + 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") + ENDIF() + + IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wconversion") + SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-conversion") + ENDIF() + + IF("${CMAKE_CXX_FLAGS}" MATCHES "-Wold-style-cast") + SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-old-style-cast") + ENDIF() + + IF(NOT MSVC) + ADD_FLAG(-Wno-gnu-statement-expression VAR AusweisAppExternalHttpParser NAME HttpParser) + ENDIF() + + ADD_LIBRARY(AusweisAppExternal::HttpParser ALIAS AusweisAppExternalHttpParser) ENDIF() -IF(NOT MSVC) - SET_PROPERTY(TARGET AusweisAppExternalHttpParser APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-gnu-statement-expression") -ENDIF() +PRINT_HTTP_PARSER("${HTTP_PARSER_INCLUDE_DIR}" "${HTTP_PARSER_LIBRARY}") diff --git a/src/external/http_parser/LICENSE-MIT b/src/external/http_parser/LICENSE-MIT index 58010b3..1ec0ab4 100644 --- a/src/external/http_parser/LICENSE-MIT +++ b/src/external/http_parser/LICENSE-MIT @@ -1,8 +1,4 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. +Copyright Joyent, Inc. and other Node contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/src/external/http_parser/http_parser.cpp b/src/external/http_parser/http_parser.cpp index 904c7c4..d46836a 100644 --- a/src/external/http_parser/http_parser.cpp +++ b/src/external/http_parser/http_parser.cpp @@ -1,7 +1,4 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. +/* Copyright Joyent, Inc. and other Node contributors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/file_provider/CMakeLists.txt b/src/file_provider/CMakeLists.txt new file mode 100644 index 0000000..fb2e032 --- /dev/null +++ b/src/file_provider/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppFileProvider) + +TARGET_LINK_LIBRARIES(AusweisAppFileProvider Qt5::Core AusweisAppSecureStorage AusweisAppNetwork) diff --git a/src/file_provider/Downloader.cpp b/src/file_provider/Downloader.cpp new file mode 100644 index 0000000..5b28dab --- /dev/null +++ b/src/file_provider/Downloader.cpp @@ -0,0 +1,218 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Downloader.h" + +#include "Env.h" +#include "HttpStatusCode.h" +#include "ScopeGuard.h" +#include "SingletonHelper.h" +#include "TlsChecker.h" + +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(network) +Q_DECLARE_LOGGING_CATEGORY(fileprovider) + +using namespace governikus; + + +defineSingleton(Downloader) + + +Downloader & Downloader::getInstance() +{ + return *Instance; +} + + +void Downloader::scheduleDownload(QSharedPointer request) +{ + mPendingRequests.enqueue(request); + + startDownloadIfPending(); +} + + +void Downloader::startDownloadIfPending() +{ + if (mCurrentReply) + { + qCDebug(fileprovider) << "A download is already in progress... delaying."; + + return; + } + + if (mPendingRequests.isEmpty()) + { + qCDebug(fileprovider) << "No pending requests to be started."; + + return; + } + + mCurrentRequest = mPendingRequests.dequeue(); + mCurrentReply = Env::getSingleton()->get(*mCurrentRequest); + + connect(mCurrentReply, &QNetworkReply::sslErrors, this, &Downloader::onSslErrors); + connect(mCurrentReply, &QNetworkReply::encrypted, this, &Downloader::onSslHandshakeDone); + connect(mCurrentReply, &QNetworkReply::metaDataChanged, this, &Downloader::onMetadataChanged); + connect(mCurrentReply, &QNetworkReply::finished, this, &Downloader::onNetworkReplyFinished); +} + + +void Downloader::onSslErrors(const QList& pErrors) +{ + TlsChecker::containsFatalError(mCurrentReply, pErrors); +} + + +void Downloader::onSslHandshakeDone() +{ + const auto& cfg = mCurrentReply->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(network)); + + if (!Env::getSingleton()->checkUpdateServerCertificate(*mCurrentReply)) + { + const QString& textForLog = mCurrentRequest->url().fileName(); + qCritical(fileprovider).nospace() << "Untrusted certificate found [" << textForLog << "]: " << cfg.peerCertificate(); + mCurrentReply->abort(); + } +} + + +void Downloader::onMetadataChanged() +{ + const QString& fileName = mCurrentRequest->url().fileName(); + + QVariant status = mCurrentReply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute); + if (!status.isNull() && Enum::isValue(status.toInt())) + { + HttpStatusCode statusCode = static_cast(status.toInt()); + if (statusCode != HttpStatusCode::OK) + { + qCDebug(fileprovider) << "Abort request for" << fileName << "with status" << status.toInt() << "-" << statusCode; + mCurrentReply->abort(); + return; + } + qCDebug(fileprovider) << "Continue request for" << fileName << "with status" << status.toInt() << "-" << statusCode; + return; + } + + qCDebug(fileprovider) << "Unknown or missing HttpStatusCodeAttribute for" << fileName; +} + + +void Downloader::onNetworkReplyFinished() +{ + qCDebug(fileprovider) << "Downloader::onNetworkReplyFinished()"; + + const ScopeGuard guard([this] { + mCurrentReply->deleteLater(); + mCurrentReply = nullptr; + startDownloadIfPending(); + }); + + if (mCurrentRequest.isNull()) + { + qCCritical(fileprovider) << "Internal error: no running download request."; + Q_EMIT fireDownloadFailed(mCurrentRequest->url(), GlobalStatus::Code::Network_Other_Error); + + return; + } + + const QUrl url = mCurrentRequest->url(); + const QString& textForLog = mCurrentRequest->url().fileName(); + if (!Env::getSingleton()->checkUpdateServerCertificate(*mCurrentReply)) + { + qCCritical(fileprovider).nospace() << "Connection not secure [" << textForLog << "]"; + Q_EMIT fireDownloadFailed(url, GlobalStatus::Code::Network_Ssl_Establishment_Error); + + return; + } + + QDateTime lastModified = mCurrentReply->header(QNetworkRequest::KnownHeaders::LastModifiedHeader).toDateTime(); + if (!lastModified.isValid()) + { + qCWarning(fileprovider) << "Server did not provide a valid LastModifiedHeader"; + lastModified = QDateTime::currentDateTime(); + } + + const int statusCode = mCurrentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + switch (static_cast(statusCode)) + { + case HttpStatusCode::OK: + Q_EMIT fireDownloadSuccess(mCurrentRequest->url(), lastModified, mCurrentReply->readAll()); + break; + + case HttpStatusCode::NOT_MODIFIED: + Q_EMIT fireDownloadUnnecessary(url); + break; + + case HttpStatusCode::NOT_FOUND: + Q_EMIT fireDownloadFailed(url, GlobalStatus::Code::Downloader_File_Not_Found); + break; + + default: + if (mCurrentReply->error() != QNetworkReply::NoError) + { + qCCritical(fileprovider).nospace() << mCurrentReply->errorString() << " [" << textForLog << "]"; + Q_EMIT fireDownloadFailed(url, NetworkManager::toStatus(mCurrentReply)); + } + else + { + qCCritical(fileprovider).nospace() << "Invalid HTTP status code: " << statusCode << " for [" << textForLog << "]"; + Q_EMIT fireDownloadFailed(url, GlobalStatus::Code::Network_Other_Error); + } + } +} + + +Downloader::Downloader() + : mCurrentRequest() + , mCurrentReply(nullptr) + , mPendingRequests() +{ +} + + +Downloader::~Downloader() +{ + if (mCurrentReply != nullptr) + { + if (mCurrentReply->isRunning() && !mCurrentRequest.isNull()) + { + const QString& textForLog = mCurrentRequest->url().fileName(); + qCDebug(fileprovider).nospace() << "Scheduling pending update request [" << textForLog << "] for deletion"; + } + mCurrentReply->deleteLater(); + mCurrentReply = nullptr; + } +} + + +void Downloader::download(const QUrl& pUpdateUrl) +{ + qCDebug(fileprovider) << "Download:" << pUpdateUrl; + QSharedPointer request = QSharedPointer(new QNetworkRequest(pUpdateUrl)); + scheduleDownload(request); +} + + +void Downloader::downloadIfNew(const QUrl& pUpdateUrl, + const QDateTime& pCurrentTimestamp) +{ + + qCDebug(fileprovider) << "Download:" << pUpdateUrl; + QSharedPointer request = QSharedPointer(new QNetworkRequest(pUpdateUrl)); + const QString& timeStampString = QLocale::c().toString(pCurrentTimestamp, QStringLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT'")); + if (!timeStampString.isEmpty()) + { + request->setRawHeader(QByteArrayLiteral("If-Modified-Since"), timeStampString.toLatin1()); + } + // See Section 14.25 at https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + // Example timestamp string: Sun, 06 Nov 1994 08:49:37 GMT + scheduleDownload(request); +} diff --git a/src/file_provider/Downloader.h b/src/file_provider/Downloader.h new file mode 100644 index 0000000..c4d4ada --- /dev/null +++ b/src/file_provider/Downloader.h @@ -0,0 +1,58 @@ +/*! + * \brief Generic class that allows to download files from a server to the + * local application cache. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" +#include "NetworkManager.h" + +#include +#include +#include +#include +#include +#include + +namespace governikus +{ +class Downloader + : public QObject +{ + Q_OBJECT + + private: + QSharedPointer mCurrentRequest; + QNetworkReply* mCurrentReply; + QQueue > mPendingRequests; + + void scheduleDownload(QSharedPointer pDownloadRequest); + void startDownloadIfPending(); + + protected: + Downloader(); + virtual ~Downloader(); + + private Q_SLOTS: + void onSslErrors(const QList& pErrors); + void onSslHandshakeDone(); + void onMetadataChanged(); + void onNetworkReplyFinished(); + + public: + Q_INVOKABLE virtual void download(const QUrl& pUpdateUrl); + Q_INVOKABLE virtual void downloadIfNew(const QUrl& pUpdateUrl, + const QDateTime& pCurrentTimestamp); + + static Downloader& getInstance(); + + Q_SIGNALS: + void fireDownloadSuccess(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData); + void fireDownloadFailed(const QUrl& pUpdateUrl, GlobalStatus::Code pErrorCode); + void fireDownloadUnnecessary(const QUrl& pUpdateUrl); +}; + +} /* namespace governikus */ diff --git a/src/file_provider/FileProvider.cpp b/src/file_provider/FileProvider.cpp new file mode 100644 index 0000000..57e7d25 --- /dev/null +++ b/src/file_provider/FileProvider.cpp @@ -0,0 +1,50 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "FileProvider.h" + +#include "SingletonHelper.h" + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(fileprovider) + +defineSingleton(FileProvider) + + +FileProvider::FileProvider() + : mUpdatableFiles() +{ +} + + +FileProvider& FileProvider::getInstance() +{ + return *Instance; +} + + +const QSharedPointer FileProvider::getFile(const QString& pSection, const QString& pName, const QString& pDefaultPath) +{ + const QString key = pSection + QLatin1Char('/') + pName; + const QSharedPointer existingF = mUpdatableFiles.value(key, QSharedPointer()); + if (existingF.isNull()) + { + const QSharedPointer newF(new UpdatableFile(pSection, pName, pDefaultPath)); + if (!pName.isEmpty()) + { + mUpdatableFiles.insert(key, newF); + } + + return newF; + } + else + { + existingF->setDefaultPath(pDefaultPath); + + return existingF; + } +} diff --git a/src/file_provider/FileProvider.h b/src/file_provider/FileProvider.h new file mode 100644 index 0000000..e580e89 --- /dev/null +++ b/src/file_provider/FileProvider.h @@ -0,0 +1,34 @@ +/*! + * \brief Class that holds a table of the UpdatableFile instances currently in use. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "UpdatableFile.h" + +#include +#include + + +namespace governikus +{ +class FileProvider +{ + Q_GADGET + + private: + QHash > mUpdatableFiles; + + protected: + FileProvider(); + ~FileProvider() = default; + + public: + const QSharedPointer getFile(const QString& pSection, const QString& pName, const QString& pDefaultPath = QString()); + + static FileProvider& getInstance(); +}; + +} // namespace governikus diff --git a/src/file_provider/UpdatableFile.cpp b/src/file_provider/UpdatableFile.cpp new file mode 100644 index 0000000..df8f60b --- /dev/null +++ b/src/file_provider/UpdatableFile.cpp @@ -0,0 +1,376 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "UpdatableFile.h" + +#include "Downloader.h" +#include "Env.h" +#include "SecureStorage.h" + +#include +#include +#include +#include + +#ifndef QT_NO_DEBUG +#include +#endif + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(fileprovider) + +namespace +{ +const QLatin1Char Sep('/'); +} + + +const QString& UpdatableFile::getName() +{ + return mName; +} + + +QDateTime UpdatableFile::cacheTimestamp() const +{ + const QString timestampFormat = QStringLiteral("yyyyMMddhhmmss"); + const int timestampFormatSize = timestampFormat.size(); + const QString pathInCache = cachePath(); + + // The path must contain at least 1 character for the filename, + // the '_' separator, and the timestamp. + if (pathInCache.size() < 2 + timestampFormatSize) + { + return QDateTime(); + } + + return QDateTime::fromString(pathInCache.right(timestampFormatSize), timestampFormat); +} + + +const QString& UpdatableFile::getSectionCachePath() const +{ + return mSectionCachePath; +} + + +QString UpdatableFile::qrcPath() const +{ + const QString prefix = QStringLiteral("updatable-files"); + const QString path = QStringLiteral(":/") + prefix + Sep + mSection + Sep + mName; + + return QFile::exists(path) ? path : QString(); +} + + +QString UpdatableFile::cachePath() const +{ + QDir folder(mSectionCachePath); + const QStringList nameFilter = QStringList({mName + QStringLiteral("_*")}); + const QStringList matchingFiles = folder.entryList(nameFilter, QDir::Files, QDir::Name | QDir::Reversed); + + // Files are saved in the cache with the suffix _, where + // the timestamp has the format "yyyyMMddhhmmss". + // Therefore, the first matching file in the list has the newest timestamp. + return matchingFiles.isEmpty() ? QString() : mSectionCachePath + Sep + matchingFiles.first(); +} + + +QUrl UpdatableFile::updateUrl(const QString& pSection, const QString& pName) +{ + const QUrl updateServerBaseUrl = SecureStorage::getInstance().getUpdateServerBaseUrl(); + + const QString section = pSection.isEmpty() ? QString() : Sep + pSection; + return QUrl(updateServerBaseUrl.toString() + section + Sep + pName); +} + + +QString UpdatableFile::dirtyFilePath() const +{ + return mSectionCachePath.isEmpty() ? QString() : mSectionCachePath + Sep + mName + QStringLiteral(".dirty"); +} + + +QString UpdatableFile::sectionCachePath(const QString& pSection) const +{ + const QStringList cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation); + if (cachePaths.isEmpty()) + { + qCWarning(fileprovider) << "No cache paths found!"; + + return QString(); + } + + const QString cacheBasePath = cachePaths.first(); + if (cacheBasePath.isEmpty()) + { + qCWarning(fileprovider) << "Cache base folder is invalid (empty)."; + + return QString(); + } + + return cacheBasePath + Sep + pSection; +} + + +QString UpdatableFile::makeSectionCachePath(const QString& pSection) +{ + QString sectionFolderPath = sectionCachePath(pSection); + +#ifndef QT_NO_DEBUG + if (QCoreApplication::applicationName().startsWith(QLatin1String("Test"))) + { + static QTemporaryDir testDir; + Q_ASSERT(testDir.isValid()); + sectionFolderPath = testDir.path() + Sep + pSection; + } +#endif + + const QDir sectionFolder(sectionFolderPath); + if (sectionFolder.exists()) + { + return sectionFolderPath; + } + + if (sectionFolder.mkpath(sectionFolderPath)) + { + qCDebug(fileprovider) << "Created cache folder:" << sectionFolderPath; + + return sectionFolderPath; + } + + qCWarning(fileprovider) << "Cannot create cache folder:" << sectionFolderPath; + + return QString(); +} + + +void UpdatableFile::cleanupAfterUpdate(const std::function& pCustomAction) +{ + Downloader* const downloader = Env::getSingleton(); + disconnect(downloader, &Downloader::fireDownloadSuccess, this, &UpdatableFile::onDownloadSuccess); + disconnect(downloader, &Downloader::fireDownloadFailed, this, &UpdatableFile::onDownloadFailed); + disconnect(downloader, &Downloader::fireDownloadUnnecessary, this, &UpdatableFile::onDownloadUnnecessary); + + pCustomAction(); + + mUpdateRunning = false; +} + + +void UpdatableFile::onDownloadSuccess(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData) +{ + if (pUpdateUrl == mUpdateUrl) + { + const QString dateFormat = QStringLiteral("yyyyMMddhhmmss"); + const QString filePath = mSectionCachePath + Sep + mName + QLatin1Char('_') + pNewTimestamp.toString(dateFormat); + + if (writeDataToFile(pData, filePath)) + { + Q_EMIT fireUpdated(); + } + else + { + qCCritical(fileprovider) << "Could not write downloaded file" << filePath; + } + + cleanupAfterUpdate([&](){ + clearDirty(); + }); + } +} + + +void UpdatableFile::onDownloadFailed(const QUrl& pUpdateUrl, GlobalStatus::Code pErrorCode) +{ + if (pUpdateUrl == mUpdateUrl) + { + cleanupAfterUpdate([ = ](){ + qCCritical(fileprovider) << "Download failed with error code:" << pErrorCode; + }); + } +} + + +void UpdatableFile::onDownloadUnnecessary(const QUrl& pUpdateUrl) +{ + if (pUpdateUrl == mUpdateUrl) + { + cleanupAfterUpdate([&](){ + clearDirty(); + }); + } +} + + +bool UpdatableFile::writeDataToFile(const QByteArray& pData, const QString& pFilePath, bool pOverwrite) +{ + QFile file(pFilePath); + if (!pOverwrite && file.exists()) + { + qCCritical(fileprovider) << "File already exists, aborting writing file:" << pFilePath; + return false; + } + if (!file.open(QIODevice::WriteOnly)) + { + qCCritical(fileprovider) << "File could not be opened for writing:" << pFilePath; + return false; + } + if (file.write(pData) != pData.size()) + { + qCCritical(fileprovider) << "Not all data could not be written to file:" << pFilePath; + file.close(); + return false; + } + + qCDebug(fileprovider) << "Data written to file:" << pFilePath; + file.close(); + return true; +} + + +UpdatableFile::UpdatableFile(const QString& pSection, const QString& pName, const QString& pDefaultPath) + : mSection(pSection) + , mName(pName) + , mDefaultPath(pDefaultPath) + , mSectionCachePath(makeSectionCachePath(pSection)) + , mUpdateUrl(updateUrl(pSection, pName)) + , mUpdateRunning(false) +{ +} + + +QUrl UpdatableFile::lookupUrl() +{ + QString path = lookupPath(); + if (path.startsWith(QLatin1String(":/"))) + { + return QStringLiteral("qrc://") + path.midRef(1); + } + else + { + return QStringLiteral("file://") + path; + } +} + + +QString UpdatableFile::lookupPath() +{ + if (mName.isEmpty()) + { + return mDefaultPath; + } + + QString result; + const QString pathInCache = cachePath(); + if (pathInCache.isEmpty()) + { + const QString pathInQrc = qrcPath(); + result = pathInQrc.isEmpty() ? mDefaultPath : pathInQrc; + } + else + { + result = pathInCache; + } + + if (isDirty()) + { + update(); + } + + return result; +} + + +void UpdatableFile::setDefaultPath(const QString& pPath) +{ + if (mDefaultPath != pPath) + { + mDefaultPath = pPath; + } +} + + +const QString& UpdatableFile::getDefaultPath() const +{ + return mDefaultPath; +} + + +void UpdatableFile::update() +{ + qCDebug(fileprovider) << "Update Triggered for Name:" << mName << " with URL:" << mUpdateUrl; + if (!mUpdateRunning && !mName.isEmpty()) + { + mUpdateRunning = true; + + Downloader* const downloader = Env::getSingleton(); + connect(downloader, &Downloader::fireDownloadSuccess, this, &UpdatableFile::onDownloadSuccess); + connect(downloader, &Downloader::fireDownloadFailed, this, &UpdatableFile::onDownloadFailed); + connect(downloader, &Downloader::fireDownloadUnnecessary, this, &UpdatableFile::onDownloadUnnecessary); + + const QDateTime timestamp = cacheTimestamp(); + if (timestamp.isValid()) + { + downloader->downloadIfNew(mUpdateUrl, timestamp); + } + else + { + downloader->download(mUpdateUrl); + } + } +} + + +bool UpdatableFile::isDirty() const +{ + if (mName.isEmpty()) + { + return false; + } + + return QFile::exists(dirtyFilePath()); +} + + +void UpdatableFile::clearDirty() const +{ + if (mSectionCachePath.isEmpty() && !mName.isEmpty()) + { + qCCritical(fileprovider) << "Cannot clear invalid file:" << mSection << Sep << mName; + + return; + } + + const QString filePath = dirtyFilePath(); + QFile file(filePath); + if (file.exists() && !file.remove()) + { + qCCritical(fileprovider) << "Cannot remove file:" << filePath; + } +} + + +void UpdatableFile::markDirty() const +{ + if (mSectionCachePath.isEmpty() && !mName.isEmpty()) + { + qCCritical(fileprovider) << "Cannot mark invalid file:" << mSection << Sep << mName; + + return; + } + + const QString filePath = dirtyFilePath(); + QFile file(filePath); + if (!file.exists()) + { + if (!file.open(QIODevice::WriteOnly)) + { + qCCritical(fileprovider) << "Cannot create file:" << filePath; + } + + file.close(); + } +} diff --git a/src/file_provider/UpdatableFile.h b/src/file_provider/UpdatableFile.h new file mode 100644 index 0000000..c4d16a5 --- /dev/null +++ b/src/file_provider/UpdatableFile.h @@ -0,0 +1,78 @@ +/*! + * \brief Class that provides access to a file identified by a section and a name. + * The file is looked up in the local cache or in the application's resource bundle. + * This class also handles the synchronization of the local cache with the content + * provided by a server. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" + +#include +#include + +#include + +class test_UpdatableFile; +class test_ReaderConfiguration; + + +namespace governikus +{ +class UpdatableFile + : public QObject +{ + Q_OBJECT + + private: + friend class ::test_UpdatableFile; + friend class ::test_ReaderConfiguration; + + const QString mSection; + const QString mName; + QString mDefaultPath; + const QString mSectionCachePath; + const QUrl mUpdateUrl; + bool mUpdateRunning; + + const QString& getName(); + QDateTime cacheTimestamp() const; + const QString& getSectionCachePath() const; + + QString qrcPath() const; + QString cachePath() const; + QUrl updateUrl(const QString& pSection, const QString& pName); + QString dirtyFilePath() const; + QString sectionCachePath(const QString& pSection) const; + QString makeSectionCachePath(const QString& pSection); + void cleanupAfterUpdate(const std::function& pCustomAction); + bool writeDataToFile(const QByteArray& pData, const QString& pFilePath, bool pOverwrite = false); + + private Q_SLOTS: + void onDownloadSuccess(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData); + void onDownloadFailed(const QUrl& pUpdateUrl, GlobalStatus::Code pErrorCode); + void onDownloadUnnecessary(const QUrl& pUpdateUrl); + + public: + UpdatableFile(const QString& pSection, const QString& pName, const QString& pDefaultPath = QString()); + virtual ~UpdatableFile() = default; + + QUrl lookupUrl(); + QString lookupPath(); + void setDefaultPath(const QString& pPath); + const QString& getDefaultPath() const; + + void update(); + bool isDirty() const; + void clearDirty() const; + void markDirty() const; + + Q_SIGNALS: + void fireUpdated(); + +}; + +} // namespace governikus diff --git a/src/global/BuildHelper.cpp b/src/global/BuildHelper.cpp index 80df59f..8472646 100644 --- a/src/global/BuildHelper.cpp +++ b/src/global/BuildHelper.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "BuildHelper.h" @@ -18,50 +18,63 @@ const char* BuildHelper::mDateTime = __DATE__ " / " __TIME__; #ifdef Q_OS_ANDROID - -int BuildHelper::getVersionCode() +namespace { - return getVersionCode(getPackageName()); +QAndroidJniObject getPackageInfo(const QString& pPackageName, int pFlags = 0) +{ + QAndroidJniEnvironment env; + + auto context = QtAndroid::androidContext(); + auto manager = context.callObjectMethod("getPackageManager", + "()Landroid/content/pm/PackageManager;"); + + if (manager.isValid()) + { + const auto& str = QAndroidJniObject::fromString(pPackageName); + return manager.callObjectMethod("getPackageInfo", + "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;", + str.object(), pFlags); + } + + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + return QAndroidJniObject(); } -int BuildHelper::getVersionCode(const QString& pPackageName) +} + + +int BuildHelper::getVersionCode() { 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(); - } + version_code = getVersionCode(getPackageName()); } return version_code; } +int BuildHelper::getVersionCode(const QString& pPackageName) +{ + const auto info = getPackageInfo(pPackageName); + + if (info.isValid()) + { + return info.getField("versionCode"); + } + + return -1; +} + + QString BuildHelper::getPackageName() { auto context = QtAndroid::androidContext(); diff --git a/src/global/BuildHelper.h b/src/global/BuildHelper.h index 601c361..0bee347 100644 --- a/src/global/BuildHelper.h +++ b/src/global/BuildHelper.h @@ -1,7 +1,7 @@ /* * \brief Helper to get build date and time. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index 7766c9d..22e11b3 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -1,7 +1,6 @@ ADD_PLATFORM_LIBRARY(AusweisAppGlobal) -TARGET_INCLUDE_DIRECTORIES(AusweisAppGlobal SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(AusweisAppGlobal Qt5::Core ${OPENSSL_LIBRARIES} ${OSX_SECURITY}) +TARGET_LINK_LIBRARIES(AusweisAppGlobal Qt5::Core OpenSSL::Crypto ${OSX_SECURITY}) IF(ANDROID) TARGET_LINK_LIBRARIES(AusweisAppGlobal Qt5::AndroidExtras) diff --git a/src/global/CardReturnCode.cpp b/src/global/CardReturnCode.cpp index 8aa4e5c..1275365 100644 --- a/src/global/CardReturnCode.cpp +++ b/src/global/CardReturnCode.cpp @@ -1,6 +1,12 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + #include "CardReturnCode.h" #include "moc_CardReturnCode.cpp" +#include "GlobalStatus.h" + using namespace governikus; @@ -19,7 +25,6 @@ GlobalStatus CardReturnCodeUtil::toGlobalStatus(CardReturnCode pCode) 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: @@ -57,5 +62,5 @@ GlobalStatus CardReturnCodeUtil::toGlobalStatus(CardReturnCode pCode) return GlobalStatus::Code::Card_Puk_Blocked; } - return GlobalStatus::Code::Unknown_Error; + Q_UNREACHABLE(); } diff --git a/src/global/CardReturnCode.h b/src/global/CardReturnCode.h index b28cd6c..33256cf 100644 --- a/src/global/CardReturnCode.h +++ b/src/global/CardReturnCode.h @@ -1,19 +1,19 @@ /*! - * ReturnCode.h - * * \brief Global error code definitions * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "EnumHelper.h" -#include "GlobalStatus.h" namespace governikus { +class GlobalStatus; + + defineEnumType(CardReturnCode, UNDEFINED, OK, @@ -24,7 +24,6 @@ defineEnumType(CardReturnCode, INVALID_PIN, INVALID_PUK, COMMAND_FAILED, - GET_CHALLENGE_FAILED, // TODO Check if still usefull CANCELLATION_BY_USER, NEW_PIN_MISMATCH, NEW_PIN_INVALID_LENGTH, @@ -34,6 +33,7 @@ defineEnumType(CardReturnCode, PROTOCOL_ERROR, UNEXPECTED_TRANSMIT_STATUS) + class CardReturnCodeUtil { private: diff --git a/src/global/DeviceError.cpp b/src/global/DeviceError.cpp index 09c3803..2387b7a 100644 --- a/src/global/DeviceError.cpp +++ b/src/global/DeviceError.cpp @@ -1,12 +1,12 @@ /*! - * DeviceError.cpp - * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #include "DeviceError.h" #include "moc_DeviceError.cpp" +#include "GlobalStatus.h" + namespace governikus { @@ -33,7 +33,7 @@ GlobalStatus toGlobalStatus(DeviceError pDeviceError) return GlobalStatus::Code::Unknown_Error; } - return GlobalStatus::Code::Unknown_Error; + Q_UNREACHABLE(); } diff --git a/src/global/DeviceError.h b/src/global/DeviceError.h index 436b8e7..fd42af3 100644 --- a/src/global/DeviceError.h +++ b/src/global/DeviceError.h @@ -1,19 +1,19 @@ /*! - * DeviceError.h - * * \brief Global definitions for device error codes. * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "EnumHelper.h" -#include "GlobalStatus.h" namespace governikus { +class GlobalStatus; + + defineEnumType(DeviceError, UNKNOWN_ERROR, DEVICE_CONNECTION_ERROR, diff --git a/src/global/DeviceInfo.cpp b/src/global/DeviceInfo.cpp new file mode 100644 index 0000000..7af4302 --- /dev/null +++ b/src/global/DeviceInfo.cpp @@ -0,0 +1,69 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DeviceInfo.h" + +#ifdef Q_OS_ANDROID +#include +#endif + +#include + +using namespace governikus; + +DeviceInfo::DeviceInfo() +{ +} + + +DeviceInfo::~DeviceInfo() +{ +} + + +#ifdef Q_OS_ANDROID +QString DeviceInfo::getField(const char* pField) +{ + QAndroidJniObject field = QAndroidJniObject::getStaticObjectField("android/os/Build", pField, "Ljava/lang/String;"); + if (field == nullptr || !field.isValid()) + { + qCritical() << "Cannot get field:" << pField; + return QString(); + } + + return field.toString(); +} + + +#endif + +QString DeviceInfo::getPrettyInfo() +{ + return QStringLiteral("%1 (%2)").arg(getName(), getFingerprint()); +} + + +QString DeviceInfo::getName() +{ + +#ifdef Q_OS_ANDROID + return getField("MODEL"); + +#else + return QSysInfo::machineHostName(); + +#endif +} + + +QString DeviceInfo::getFingerprint() +{ +#ifdef Q_OS_ANDROID + return getField("FINGERPRINT"); + +#else + return QString(); + +#endif +} diff --git a/src/global/DeviceInfo.h b/src/global/DeviceInfo.h new file mode 100644 index 0000000..ff7e80f --- /dev/null +++ b/src/global/DeviceInfo.h @@ -0,0 +1,32 @@ +/*! + * \brief Implements a wrapper for different APIs to get + * device information like android device name. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class DeviceInfo +{ + private: + DeviceInfo(); + ~DeviceInfo(); + Q_DISABLE_COPY(DeviceInfo) + +#ifdef Q_OS_ANDROID + static QString getField(const char* pField); +#endif + + public: + static QString getPrettyInfo(); + static QString getName(); + static QString getFingerprint(); +}; + +} /* namespace governikus */ diff --git a/src/global/EnumHelper.h b/src/global/EnumHelper.h index 593fd25..e9c3717 100644 --- a/src/global/EnumHelper.h +++ b/src/global/EnumHelper.h @@ -1,9 +1,7 @@ /*! - * EnumHelper.h - * * \brief Helper class to provide a QMetaObject handler for enumerations. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -144,9 +142,9 @@ template class Enum } - static EnumTypeT fromString(const QString& pValue, EnumTypeT pDefault) + static EnumTypeT fromString(const QString& pValue, EnumTypeT pDefaultType) { - return fromString(pValue.toUtf8().constData(), pDefault); + return fromString(pValue.toUtf8().constData(), pDefaultType); } diff --git a/src/global/Env.cpp b/src/global/Env.cpp new file mode 100644 index 0000000..d8dcfd2 --- /dev/null +++ b/src/global/Env.cpp @@ -0,0 +1,151 @@ +/* + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Env.h" + +#include "SingletonHelper.h" + +#include + +using namespace governikus; + +defineSingleton(Env) + +Env::Env() +{ +} + + +Env::~Env() +{ +} + + +Env& Env::getInstance() +{ + return *Instance; +} + + +void Env::storeSingleton(Identifier pId, void* pObject) +{ + if (pObject) + { + qDebug() << "Add instance:" << pId; + mInstancesOwnership.remove(pId); + mInstancesUnmanaged.insert(pId, pObject); + mTypeInfo.insert(pId, Type::UNMANAGED); + } + else + { + removeStoredSingleton(pId); + } +} + + +void Env::storeSingleton(Identifier pId, std::shared_ptr pObject) +{ + if (pObject) + { + qDebug() << "Add owned instance:" << pId; + mInstancesUnmanaged.remove(pId); + mInstancesOwnership.insert(pId, pObject); + mTypeInfo.insert(pId, Type::OWNERSHIP); + } + else + { + removeStoredSingleton(pId); + } +} + + +void Env::removeStoredSingleton(Identifier pId) +{ + qDebug() << "Remove instance:" << pId; + mInstancesOwnership.remove(pId); + mInstancesUnmanaged.remove(pId); + mTypeInfo.remove(pId); +} + + +void* Env::fetchStoredSingleton(Env::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; + } + + Q_UNREACHABLE(); +} + + +#ifndef QT_NO_DEBUG + +void Env::resetCounter() +{ + for (auto& mock : qAsConst(getInstance().mInstancesCreator)) + { + mock->reset(); + } +} + + +void Env::clear() +{ + auto& holder = getInstance(); + holder.mInstancesOwnership.clear(); + holder.mInstancesUnmanaged.clear(); + holder.mTypeInfo.clear(); + holder.mInstancesCreator.clear(); + holder.mSharedInstances.clear(); +} + + +void Env::set(const QMetaObject& pMetaObject, void* pObject) +{ + Identifier className = pMetaObject.className(); + Q_ASSERT_X(!QByteArray(className).toLower().contains("mock"), "test", "Do you really want to mock a mock?"); + getInstance().storeSingleton(className, pObject); + +} + + +void Env::set(const QMetaObject& pMetaObject, std::shared_ptr pObject) +{ + Identifier className = pMetaObject.className(); + Q_ASSERT_X(!QByteArray(className).toLower().contains("mock"), "test", "Do you really want to mock a mock?"); + getInstance().storeSingleton(className, pObject); +} + + +void Env::setShared(const QMetaObject& pMetaObject, QSharedPointer pObject) +{ + Identifier 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); + } +} + + +Env::FuncWrapperBase::~FuncWrapperBase() +{ +} + + +#endif diff --git a/src/global/Env.h b/src/global/Env.h new file mode 100644 index 0000000..55f986a --- /dev/null +++ b/src/global/Env.h @@ -0,0 +1,312 @@ +/* + * \brief Runtime environment to create (mockable) objects. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_DEBUG +#include +#include +#endif + +class test_Env; + +namespace governikus +{ + +template T* singleton(bool& pTakeOwnership); +template T createNewObject(Args&& ... pArgs); + +class Env +{ + private: + friend class ::test_Env; + Q_DISABLE_COPY(Env) + +#ifndef QT_NO_DEBUG + class FuncWrapperBase + { + protected: + int mCounter = 0; + + public: + inline int getCounter() const + { + return mCounter; + } + + + inline void reset() + { + mCounter = 0; + } + + + virtual ~FuncWrapperBase(); + }; + + template + class FuncWrapper final + : public FuncWrapperBase + { + private: + const std::function mFunc; + + public: + FuncWrapper(const std::function& pFunc) + : mFunc(pFunc) + { + } + + + virtual ~FuncWrapper() + { + } + + + T operator()(Args&& ... pArgs) + { + ++mCounter; + return mFunc(std::forward(pArgs) ...); + } + + + }; + + using Wrapper = std::shared_ptr; + QVector mInstancesCreator; +#endif + + + enum class Type + { + UNDEFINED, + OWNERSHIP, + UNMANAGED + }; + + using Identifier = const char*; + QMap mTypeInfo; + QMap mInstancesUnmanaged; + QMap > mInstancesOwnership; + QMap > mSharedInstances; + + static Env& getInstance(); + + void storeSingleton(Identifier pId, void* pObject); + void storeSingleton(Identifier pId, std::shared_ptr pObject); + void removeStoredSingleton(Identifier pId); + void* fetchStoredSingleton(Identifier pId) const; + + 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"); + + bool ownership = true; + T* obj = singleton(ownership); + Q_ASSERT(obj); + if (ownership) + { + storeSingleton(pId, std::shared_ptr(obj)); + } + else + { + storeSingleton(pId, obj); + } + return obj; + } + + + template + typename std::enable_if::value, T*>::type storeSingleton(Identifier pId) + { + T* obj = &T::getInstance(); + storeSingleton(pId, obj); + return obj; + } + + + template + typename std::enable_if::value, T*>::type storeSingleton(Identifier pId) + { + auto obj = std::make_shared(); + storeSingleton(pId, obj); + return obj.get(); + } + + + template + inline T* fetchSingleton() + { + static_assert(QtPrivate::IsGadgetHelper::Value || QtPrivate::IsPointerToTypeDerivedFromQObject::Value, + "Singletons needs to be a Q_GADGET or an QObject/Q_OBJECT"); + Identifier id = T::staticMetaObject.className(); + void* obj = fetchStoredSingleton(id); + + if (!obj) + { + obj = storeSingleton(id); + } + + return static_cast(obj); + } + + + template + inline typename std::enable_if::type, Args ...>::value, T>::type newObject(Args&& ... pArgs) const + { + static_assert(std::is_pointer::value, "It is impossible to return implementation of interface by value. Use pointer or add constructor!"); + auto obj = createNewObject(std::forward(pArgs) ...); + Q_ASSERT(obj); + return obj; + } + + + template + inline typename std::enable_if::value, T>::type internalNewObject(Args&& ... pArgs) const + { + using t = typename std::remove_pointer::type; + return new t(std::forward(pArgs) ...); + } + + + template + inline typename std::enable_if::value, T>::type internalNewObject(Args&& ... pArgs) const + { + return T(std::forward(pArgs) ...); + } + + + template + inline typename std::enable_if::type, Args ...>::value, T>::type newObject(Args&& ... pArgs) const + { + return internalNewObject(std::forward(pArgs) ...); + } + + + template + T createObject(Args&& ... pArgs) const + { +#ifndef QT_NO_DEBUG + for (auto& mock : qAsConst(mInstancesCreator)) + { + auto creator = dynamic_cast*>(mock.get()); + if (creator) + { + return (*creator)(std::forward(pArgs) ...); + } + } +#endif + + return newObject(std::forward(pArgs) ...); + } + + + protected: + Env(); + ~Env(); + + public: + template + static T* getSingleton() + { + return getInstance().fetchSingleton(); + } + + + template + static T create(Args&& ... pArgs) + { + return getInstance().createObject(std::forward(pArgs) ...); + } + + + template + static QSharedPointer getShared() + { + static_assert(QtPrivate::IsGadgetHelper::Value || QtPrivate::IsPointerToTypeDerivedFromQObject::Value, + "Shared class needs to be a Q_GADGET or an QObject/Q_OBJECT"); + + 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 resetCounter(); + static void clear(); + static void set(const QMetaObject& pMetaObject, void* pObject = nullptr); + static void set(const QMetaObject& pMetaObject, std::shared_ptr pObject); + + template + static U* getSingleton() + { + return dynamic_cast(getSingleton()); + } + + + template + static int getCounter() + { + for (const auto& mock : qAsConst(getInstance().mInstancesCreator)) + { + if (dynamic_cast*>(mock.get())) + { + return mock->getCounter(); + } + } + + return -1; // There is no mock... use setCreator! + } + + + template + static void setCreator(const std::function& pFunc) + { + Q_ASSERT(pFunc); + + auto& holder = getInstance().mInstancesCreator; + const auto& value = Wrapper(new FuncWrapper(pFunc)); + + QMutableVectorIterator iter(holder); + while (iter.hasNext()) + { + iter.next(); + if (dynamic_cast*>(iter.value().get())) + { + iter.setValue(value); + return; + } + } + + holder << value; + } + + + static void setShared(const QMetaObject& pMetaObject, QSharedPointer pObject = QSharedPointer()); +#endif + +}; + +} /* namespace governikus */ diff --git a/src/global/EnvHolder.cpp b/src/global/EnvHolder.cpp deleted file mode 100644 index 6f57757..0000000 --- a/src/global/EnvHolder.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * \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 deleted file mode 100644 index d194c2a..0000000 --- a/src/global/EnvHolder.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * \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/FileDestination.h b/src/global/FileDestination.h index b09ab02..f69abea 100644 --- a/src/global/FileDestination.h +++ b/src/global/FileDestination.h @@ -1,7 +1,7 @@ /* * \brief Little helper that will abstract pathes of underlying systems * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/FuncUtils.h b/src/global/FuncUtils.h new file mode 100644 index 0000000..a6c831d --- /dev/null +++ b/src/global/FuncUtils.h @@ -0,0 +1,76 @@ +/*! + * \brief Template functions that allow to map and filter over QVectors. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +#include + +namespace governikus +{ + +/* + * Usage example: map([](const Reader& r){ return r.getName(); }, readers) + * + * where readers has type QVector + */ +template +typename std::enable_if::value, QVector >::type map(const std::function& pFunc, const QVector& pItems) +{ + const int sz = pItems.size(); + QVector result(sz); + for (int index = 0; index < sz; ++index) + { + result[index] = pFunc(pItems[index]); + } + + return result; +} + + +/* + * Usage example: map([](const Reader& r){ return r.getName(); }, readers) + * + * where readers has type QList + */ +template +typename std::enable_if::value, QList >::type map(const std::function& pFunc, const QList& pItems) +{ + const int sz = pItems.size(); + QList result; + for (int index = 0; index < sz; ++index) + { + result.append(pFunc(pItems[index])); + } + + return result; +} + + +/* + * Usage example: filter([](const Reader& r){ return r.getCard() != nullptr; }, readers) + * + * where readers has type QVector + */ +template +typename std::enable_if::value, QVector >::type filter(const std::function& pFunc, const QVector& pItems) +{ + QVector result; + for (const T& item : pItems) + { + if (pFunc(item)) + { + result += item; + } + } + + return result; +} + + +} diff --git a/src/global/GlobalStatus.cpp b/src/global/GlobalStatus.cpp index 29066f3..92899d1 100644 --- a/src/global/GlobalStatus.cpp +++ b/src/global/GlobalStatus.cpp @@ -1,15 +1,22 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "GlobalStatus.h" +#include "Initializer.h" + #include #define MESSAGE_SORRY "Sorry, that should not have happened! Please contact the support team." using namespace governikus; +static Initializer::Entry E([] { + qRegisterMetaType("GlobalStatus::Code"); + qRegisterMetaType("GlobalStatus"); + }); + const QString GlobalStatus::getExternalInfo(int pIndex) const { @@ -60,6 +67,9 @@ QString GlobalStatus::toErrorDescription(const bool pSimplifiedVersion) const case Code::Unknown_Error: return tr("An unexpected error has occurred during processing."); + case Code::Workflow_AlreadyInProgress_Error: + return tr("Cannot start authentication. An operation is already in progress."); + case Code::Workflow_Card_Removed: return tr("The ID card has been removed. The process is aborted."); @@ -120,6 +130,10 @@ QString GlobalStatus::toErrorDescription(const bool pSimplifiedVersion) const case Code::Workflow_TrustedChannel_No_Data_Received: return maskMessage(tr("Received no data."), pSimplifiedVersion); + case Code::Workflow_TrustedChannel_ServiceUnavailable: + case Code::Network_ServiceUnavailable: + return tr("The service is temporarily not available. Please try again later."); + case Code::Network_TimeOut: case Code::Workflow_TrustedChannel_TimeOut: return maskMessage(tr("Establishing a connection is taking too long."), pSimplifiedVersion); @@ -212,10 +226,13 @@ QString GlobalStatus::toErrorDescription(const bool pSimplifiedVersion) const return tr("Card does not exist"); case Code::Card_Communication_Error: - return tr("An error occurred while communicating with the ID card."); + return tr("An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again."); case Code::Card_Protocol_Error: - return maskMessage(tr("A protocol error has occurred."), pSimplifiedVersion); + return QStringLiteral("%1 %3.").arg( + tr("A protocol error occurred. Please make sure that your ID card is placed correctly on the card reader and try again. If the problem occurs again, please contact our support at"), + tr("https://www.ausweisapp.bund.de/en/service/support/"), + tr("AusweisApp2 Support")); case Code::Card_Invalid_Pin: return tr("The given PIN is invalid."); @@ -255,9 +272,36 @@ QString GlobalStatus::toErrorDescription(const bool pSimplifiedVersion) const case Code::RemoteReader_CloseCode_Undefined: return tr("Undefined error code occured when the remote card reader connection was closed."); + + case Code::RemoteConnector_InvalidRequest: + return tr("Remote reader connection request contains invalid parameters."); + + case Code::RemoteConnector_EmptyPassword: + return tr("Empty password in extended encryption of remote reader connection request."); + + case Code::RemoteConnector_NoSupportedApiLevel: + return tr("Remote reader connection request does not contain any supported API level."); + + case Code::RemoteConnector_ConnectionTimeout: + return tr("A timeout occurred while trying to establish a connection to a remote reader."); + + case Code::RemoteConnector_ConnectionError: + return tr("An error occurred while trying to establish a connection to a remote reader."); + + case Code::RemoteConnector_RemoteHostRefusedConnection: + return tr("Remote device has rejected the connection. Please check the pairing code."); + + case Code::Downloader_File_Not_Found: + return tr("File not found."); + + case Code::Downloader_Cannot_Save_File: + return tr("Cannot save file."); + + case Code::Downloader_Data_Corrupted: + return tr("Received data were corrupted."); } - return QString(); + Q_UNREACHABLE(); } diff --git a/src/global/GlobalStatus.h b/src/global/GlobalStatus.h index 49012d6..35087e7 100644 --- a/src/global/GlobalStatus.h +++ b/src/global/GlobalStatus.h @@ -1,7 +1,7 @@ /*! * \brief A global mapping for errors * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,11 +26,17 @@ class GlobalStatus Unknown_Error, No_Error, + Network_ServiceUnavailable, Network_Ssl_Establishment_Error, Network_TimeOut, Network_Proxy_Error, Network_Other_Error, + Downloader_File_Not_Found, + Downloader_Cannot_Save_File, + Downloader_Data_Corrupted, + + Workflow_AlreadyInProgress_Error, Workflow_Communication_Missing_Redirect_Url, Workflow_Cancellation_By_User, Workflow_Card_Removed, @@ -55,6 +61,7 @@ class GlobalStatus Workflow_TrustedChannel_Hash_Not_In_Description, Workflow_TrustedChannel_No_Data_Received, Workflow_TrustedChannel_Ssl_Certificate_Unsupported_Algorithm_Or_Length, + Workflow_TrustedChannel_ServiceUnavailable, Workflow_TrustedChannel_TimeOut, Workflow_TrustedChannel_Proxy_Error, Workflow_TrustedChannel_Ssl_Establishment_Error, @@ -122,7 +129,14 @@ class GlobalStatus RemoteReader_CloseCode_NormalClose, RemoteReader_CloseCode_AbnormalClose, - RemoteReader_CloseCode_Undefined + RemoteReader_CloseCode_Undefined, + + RemoteConnector_InvalidRequest, + RemoteConnector_EmptyPassword, + RemoteConnector_NoSupportedApiLevel, + RemoteConnector_ConnectionTimeout, + RemoteConnector_ConnectionError, + RemoteConnector_RemoteHostRefusedConnection }; enum class Origin @@ -167,7 +181,7 @@ class GlobalStatus static QString maskMessage(const QString& pMessage, const bool pMask); public: - GlobalStatus(Code pStatusCode, const QStringList& pExternalInformation = QStringList(), const Origin pOrigin = Origin::Client) + GlobalStatus(Code pStatusCode = Code::Unknown_Error, const QStringList& pExternalInformation = QStringList(), const Origin pOrigin = Origin::Client) : d(new InternalStatus(pStatusCode, pExternalInformation, pOrigin)) { @@ -197,7 +211,7 @@ class GlobalStatus bool isCancellationByUser() const; }; -typedef GlobalStatus::Origin Origin; +using Origin = GlobalStatus::Origin; defineEnumOperators(GlobalStatus::Code) diff --git a/src/global/Initializer.cpp b/src/global/Initializer.cpp new file mode 100644 index 0000000..cef18a7 --- /dev/null +++ b/src/global/Initializer.cpp @@ -0,0 +1,50 @@ +/* + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Initializer.h" + +#include "SingletonHelper.h" + +#include + +using namespace governikus; + +defineSingleton(Initializer) + +Initializer & Initializer::getInstance() +{ + return *Instance; +} + +void Initializer::init() +{ + for (const auto& entry : getInstance().mRegisteredFunctions) + { + entry(); + } +} + + +void Initializer::add(const std::function& pRegister) +{ + mRegisteredFunctions.push_back(pRegister); + + if (QCoreApplication::instance()) + { + pRegister(); + } +} + + +namespace +{ +static void initialize() +{ + Initializer::getInstance().init(); +} + + +} + +Q_COREAPP_STARTUP_FUNCTION(initialize) diff --git a/src/global/Initializer.h b/src/global/Initializer.h new file mode 100644 index 0000000..972f075 --- /dev/null +++ b/src/global/Initializer.h @@ -0,0 +1,48 @@ +/* + * \brief Initializer to register a lambda that will be executed if QCoreApplication is ready. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +class test_Initializer; + +namespace governikus +{ + +class Initializer +{ + private: + friend class ::test_Initializer; + std::list > mRegisteredFunctions; + + protected: + Initializer() = default; + ~Initializer() = default; + + public: + static Initializer& getInstance(); + + struct Entry final + { + Entry(const std::function& pRegister) + { + Initializer::getInstance().add(pRegister); + } + + + Entry(const Entry& pCopy) = delete; + Entry(const Entry&& pCopy) = delete; + Entry& operator=(const Entry& pCopy) = delete; + Entry& operator=(const Entry&& pCopy) = delete; + }; + + void init(); // No need to call this! + void add(const std::function& pRegister); +}; + +} /* namespace governikus */ diff --git a/src/global/LanguageLoader.cpp b/src/global/LanguageLoader.cpp index 2e7e9e2..62c5f58 100644 --- a/src/global/LanguageLoader.cpp +++ b/src/global/LanguageLoader.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "LanguageLoader.h" @@ -145,7 +145,7 @@ void LanguageLoader::load(const QLocale& pLocale) } } - if (!loaded && !pLocale.uiLanguages().contains(pLocale.name().replace('_', '-'))) + if (!loaded && !pLocale.uiLanguages().contains(pLocale.name().replace(QLatin1Char('_'), QLatin1Char('-')))) { qCDebug(language) << "No UI translation found... try to use system locale:" << pLocale.name(); loadTranslationFiles(QLocale(pLocale.name())); diff --git a/src/global/LanguageLoader.h b/src/global/LanguageLoader.h index 8a96cad..3f32817 100644 --- a/src/global/LanguageLoader.h +++ b/src/global/LanguageLoader.h @@ -1,7 +1,7 @@ /* * \brief Loads translation files for different languages. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -14,6 +14,7 @@ class test_LanguageLoader; class test_ProviderParser; +class test_ProviderConfigurationParser; namespace governikus { @@ -23,6 +24,7 @@ class LanguageLoader private: friend class ::test_LanguageLoader; friend class ::test_ProviderParser; + friend class ::test_ProviderConfigurationParser; static const QLocale::Language mFallbackLanguage; static QLocale mDefaultLanguage; diff --git a/src/global/LogCategories.cpp b/src/global/LogCategories.cpp index 15ce4b4..1d2db67 100644 --- a/src/global/LogCategories.cpp +++ b/src/global/LogCategories.cpp @@ -2,20 +2,31 @@ * \brief Definition of all logging categories. * * \see Q_LOGGING_CATEGORY - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include -/*! - * Logging category for all card relevant messages - */ Q_LOGGING_CATEGORY(card, "card") - -/*! - * Logging category for bluetooth - */ Q_LOGGING_CATEGORY(bluetooth, "bluetooth") +Q_LOGGING_CATEGORY(card_pcsc, "card_pcsc") +Q_LOGGING_CATEGORY(card_nfc, "card_nfc") +Q_LOGGING_CATEGORY(card_remote, "card_remote") +Q_LOGGING_CATEGORY(remote_device, "remote_device") +Q_LOGGING_CATEGORY(card_drivers, "card_drivers") +Q_LOGGING_CATEGORY(cmdline, "cmdline") +Q_LOGGING_CATEGORY(statemachine, "statemachine") +Q_LOGGING_CATEGORY(paos, "paos") +Q_LOGGING_CATEGORY(gui, "gui") +Q_LOGGING_CATEGORY(language, "language") +Q_LOGGING_CATEGORY(qml, "qml") +Q_LOGGING_CATEGORY(jsonapi, "jsonapi") +Q_LOGGING_CATEGORY(aidl, "aidl") +Q_LOGGING_CATEGORY(websocket, "websocket") +Q_LOGGING_CATEGORY(cli, "cli") +Q_LOGGING_CATEGORY(stdinput, "stdinput") +Q_LOGGING_CATEGORY(activation, "activation") +Q_LOGGING_CATEGORY(fileprovider, "fileprovider") /*! * Logging category for all security relevant messages, @@ -23,62 +34,27 @@ Q_LOGGING_CATEGORY(bluetooth, "bluetooth") */ Q_LOGGING_CATEGORY(secure, "secure", QtFatalMsg) -/*! - * Logging category for all PC/SC relevant card stuff - */ -Q_LOGGING_CATEGORY(card_pcsc, "card_pcsc") - -/*! - * Logging category for all nfc relevant card stuff - */ -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 - */ -Q_LOGGING_CATEGORY(card_drivers, "card_drivers") - -/*! - * Logging category for command line options - */ -Q_LOGGING_CATEGORY(cmdline, "cmdline") - -/*! - * Logging category for the state machine and state handling - */ -Q_LOGGING_CATEGORY(statemachine, "statemachine") - -/*! - * Logging category for PAOS message handling - */ -Q_LOGGING_CATEGORY(paos, "paos") - -/*! - * Logging category for all GUI stuff - */ -Q_LOGGING_CATEGORY(gui, "gui") - /*! * Logging category for network stuff written on our own. * I. e. unfortunately we do not log network traffic handled by third party libraries */ Q_LOGGING_CATEGORY(network, "network") +/*! + * Logging category for the secure storage module + */ +Q_LOGGING_CATEGORY(securestorage, "securestorage") + +/*! + * Logging category for the configuration module + */ +Q_LOGGING_CATEGORY(configuration, "configuration") + /*! * Logging category for systems calls / signals */ Q_LOGGING_CATEGORY(system, "system") -/*! - * Logging category for language loader - */ -Q_LOGGING_CATEGORY(language, "language") - /*! * Logging category for initial stuff like main function */ @@ -89,46 +65,16 @@ Q_LOGGING_CATEGORY(init, "init") */ Q_LOGGING_CATEGORY(update, "update") +/*! + * Logging category for app update informations + */ +Q_LOGGING_CATEGORY(appupdate, "appupdate") + /*! * Logging category for support stuff, i.e. distinctive workflow states and workflow results needed by the support team */ Q_LOGGING_CATEGORY(support, "support") -/*! - * Logging category for UIPlugInQml - */ -Q_LOGGING_CATEGORY(qml, "qml") - -/*! - * Logging category for UIPlugInJsonApi - */ -Q_LOGGING_CATEGORY(jsonapi, "jsonapi") - -/*! - * Logging category for UIPlugInAidl - */ -Q_LOGGING_CATEGORY(aidl, "aidl") - -/*! - * Logging category for UIPlugInWebSocket - */ -Q_LOGGING_CATEGORY(websocket, "websocket") - -/*! - * Logging category for UIPlugInCli - */ -Q_LOGGING_CATEGORY(cli, "cli") - -/*! - * Logging category for input received with stdin - */ -Q_LOGGING_CATEGORY(stdinput, "stdinput") - -/*! - * Logging category for activation handler - */ -Q_LOGGING_CATEGORY(activation, "activation") - /*! * Logging category for normally critical errors which are allowed to occur in developer mode */ diff --git a/src/global/LogHandler.cpp b/src/global/LogHandler.cpp index 21389a7..6d56c80 100644 --- a/src/global/LogHandler.cpp +++ b/src/global/LogHandler.cpp @@ -1,12 +1,11 @@ /* - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "LogHandler.h" #include "SingletonHelper.h" -#include #include using namespace governikus; @@ -24,7 +23,7 @@ LogHandler::LogHandler() , mEnvPattern(!qEnvironmentVariableIsEmpty("QT_MESSAGE_PATTERN")) , mFunctionFilenameSize(74) , mBacklogPosition(0) - , 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}")) + , mMessagePattern(QStringLiteral("%{category} %{time yyyy.MM.dd hh:mm:ss.zzz} %{if-debug} %{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) @@ -95,6 +94,31 @@ QByteArray LogHandler::getBacklog() } +QDateTime LogHandler::getFileDate(const QFileInfo& pInfo) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + const QFileInfo info(pInfo); + const auto& dateTime = info.birthTime(); + if (dateTime.isValid()) + { + return dateTime; + } + + return info.metadataChangeTime(); + +#else + return QFileInfo(pInfo).created(); + +#endif +} + + +QDateTime LogHandler::getCurrentLogfileDate() const +{ + return getFileDate(mLogFile); +} + + void LogHandler::resetBacklog() { const QMutexLocker mutexLocker(&mMutex); @@ -113,7 +137,7 @@ void LogHandler::copyMessageLogContext(const QMessageLogContext& pSource, QMessa } -QByteArray LogHandler::formatFilename(const char* pFilename) +QByteArray LogHandler::formatFilename(const char* pFilename) const { QByteArray filename(pFilename); @@ -125,7 +149,7 @@ QByteArray LogHandler::formatFilename(const char* pFilename) } -QByteArray LogHandler::formatFunction(const char* pFunction, const QByteArray& pFilename, int pLine) +QByteArray LogHandler::formatFunction(const char* pFunction, const QByteArray& pFilename, int pLine) const { QByteArray function(pFunction); @@ -165,17 +189,15 @@ QByteArray LogHandler::formatFunction(const char* pFunction, const QByteArray& p } -QByteArray LogHandler::formatCategory(const char* pCategory) +QByteArray LogHandler::formatCategory(const QByteArray& pCategory) const { - static const char* PADDING = " "; - static const int MAX_LENGTH = static_cast(qstrlen(PADDING)); - - QByteArray category(pCategory); - if (category.length() > MAX_LENGTH) + const int MAX_CATEGORY_LENGTH = 10; + if (pCategory.length() > MAX_CATEGORY_LENGTH) { - category = category.left(MAX_LENGTH - 3) + QByteArrayLiteral("..."); + return pCategory.left(MAX_CATEGORY_LENGTH - 3) + QByteArrayLiteral("..."); } - return category.append(PADDING, MAX_LENGTH - category.size()); + + return pCategory + QByteArray(MAX_CATEGORY_LENGTH - pCategory.size(), ' '); } @@ -198,9 +220,9 @@ void LogHandler::handleMessage(QtMsgType pType, const QMessageLogContext& pConte { const QMutexLocker mutexLocker(&mMutex); - QByteArray filename = formatFilename(pContext.file); - QByteArray function = formatFunction(pContext.function, filename, pContext.line); - QByteArray category = formatCategory(pContext.category); + const QByteArray& filename = formatFilename(pContext.file); + const QByteArray& function = formatFunction(pContext.function, filename, pContext.line); + const QByteArray& category = formatCategory(pContext.category); QMessageLogContext ctx; copyMessageLogContext(pContext, ctx, filename, function, category); @@ -208,7 +230,14 @@ void LogHandler::handleMessage(QtMsgType pType, const QMessageLogContext& pConte const QString& message = mEnvPattern ? pMsg : getPaddedLogMsg(ctx, pMsg); qSetMessagePattern(mMessagePattern); - QString logMsg = qFormatLogMessage(pType, ctx, message) + QLatin1Char('\n'); + +#ifdef Q_OS_WIN + const QLatin1String lineBreak("\r\n"); +#else + const QLatin1Char lineBreak('\n'); +#endif + + QString logMsg = qFormatLogMessage(pType, ctx, message) + lineBreak; logToFile(logMsg); #ifdef ENABLE_MESSAGE_PATTERN diff --git a/src/global/LogHandler.h b/src/global/LogHandler.h index 48e6551..bd1d328 100644 --- a/src/global/LogHandler.h +++ b/src/global/LogHandler.h @@ -1,11 +1,12 @@ /* * \brief Logging handler of QtMessageHandler * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include #include #include #include @@ -36,9 +37,9 @@ class LogHandler inline void copyMessageLogContext(const QMessageLogContext& pSource, QMessageLogContext& pDestination, const QByteArray& pFilename = QByteArray(), const QByteArray& pFunction = QByteArray(), const QByteArray& pCategory = QByteArray()); inline void logToFile(const QString& pOutput); - inline QByteArray formatFunction(const char* pFunction, const QByteArray& pFilename, int pLine); - inline QByteArray formatFilename(const char* pFilename); - inline QByteArray formatCategory(const char* pCategory); + inline QByteArray formatFunction(const char* pFunction, const QByteArray& pFilename, int pLine) const; + inline QByteArray formatFilename(const char* pFilename) const; + inline QByteArray formatCategory(const QByteArray& pCategory) const; QString getPaddedLogMsg(const QMessageLogContext& pContext, const QString& pMsg); void handleMessage(QtMsgType pType, const QMessageLogContext& pContext, const QString& pMsg); @@ -59,6 +60,8 @@ class LogHandler void resetBacklog(); QByteArray getBacklog(); + static QDateTime getFileDate(const QFileInfo& pInfo); + QDateTime getCurrentLogfileDate() const; QFileInfoList getOtherLogfiles() const; void removeOtherLogfiles(); diff --git a/src/global/MetaTypeHelper.h b/src/global/MetaTypeHelper.h deleted file mode 100644 index 8ed0ec8..0000000 --- a/src/global/MetaTypeHelper.h +++ /dev/null @@ -1,49 +0,0 @@ -/*! - * MetaTypeHelper.h - * - * \brief Helper macros REGISTER_META_TYPE() and REGISTER_POINTER_META_TYPE() to register meta types. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -template -struct RegisterMetaType -{ - RegisterMetaType(const char* name, const char* qualifiedName) - { - // Note: In theory registering the qualified name should suffice, but - // apparently sometimes Qt looks up the type by the unqualified name, - // possibly because moc isn't aware of the namespace. - qRegisterMetaType(name); - qRegisterMetaType(qualifiedName); - } - - -}; - -/*! - * Declares a meta type for the given type and registers it with the Qt meta type system. - * - * Must be placed in the global scope. - * - * \param type The unqualified name of the type, e.g. AppController. - */ -#define REGISTER_META_TYPE(type)\ - Q_DECLARE_METATYPE(governikus::type)\ - static RegisterMetaType _registerTypeHelper_##type(#type, "governikus::" #type); - -/*! - * Declares a meta type for the pointer type of the given type and registers it with the Qt meta type system. - * - * Must be placed in the global scope. - * - * \param type The unqualified name of the type, e.g. AppController. - */ -#define REGISTER_POINTER_META_TYPE(type)\ - Q_DECLARE_METATYPE(governikus::type*)\ - static RegisterMetaType _registerPointerTypeHelper_##type(#type "*", "governikus::" #type "*"); diff --git a/src/global/Randomizer.cpp b/src/global/Randomizer.cpp index 45d22c6..e12fd2f 100644 --- a/src/global/Randomizer.cpp +++ b/src/global/Randomizer.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + #include "Randomizer.h" #include "SingletonHelper.h" @@ -5,6 +9,10 @@ #include #include +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +#include +#endif + #ifdef Q_OS_WIN #include #elif defined(Q_OS_UNIX) @@ -18,7 +26,7 @@ #include #include #endif - #if defined(Q_OS_IOS) || defined(Q_OS_OSX) + #if defined(Q_OS_IOS) || defined(Q_OS_MACOS) #include #endif #endif @@ -43,6 +51,10 @@ template QList Randomizer::getEntropy() entropy += std::random_device()(); entropy += static_cast(qrand()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + entropy += QRandomGenerator::securelySeeded().generate(); +#endif + UniversalBuffer buffer; if (RAND_bytes(buffer.data, sizeof(buffer.data))) { @@ -61,7 +73,7 @@ template QList Randomizer::getEntropyWin() { QList entropy; -#ifdef Q_OS_WIN32 +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) UniversalBuffer buffer; HCRYPTPROV provider = 0; if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) @@ -127,7 +139,7 @@ template QList Randomizer::getEntropyApple() { QList entropy; -#if defined(Q_OS_IOS) || defined(Q_OS_OSX) +#if defined(Q_OS_IOS) || defined(Q_OS_MACOS) UniversalBuffer buffer; if (SecRandomCopyBytes(kSecRandomDefault, sizeof(buffer.data), buffer.data) == 0) { @@ -145,8 +157,14 @@ Randomizer::Randomizer() std::seed_seq seed(entropy.cbegin(), entropy.cend()); mGenerator.seed(seed); - static const int MINUMUM_ENTROPY_SOURCES = 5; - mSecureRandom = seed.size() >= MINUMUM_ENTROPY_SOURCES; + // We need to seed pseudo random pool of openssl. + // yes, OpenSSL is an entropy source, too. But not the only one! + UniversalBuffer buffer; + buffer.number = mGenerator(); + RAND_seed(buffer.data, sizeof(std::mt19937::result_type)); + + static const int MINIMUM_ENTROPY_SOURCES = 5; + mSecureRandom = seed.size() >= MINIMUM_ENTROPY_SOURCES; } diff --git a/src/global/Randomizer.h b/src/global/Randomizer.h index 48a25c1..05ff154 100644 --- a/src/global/Randomizer.h +++ b/src/global/Randomizer.h @@ -1,7 +1,7 @@ /*! * \brief Helper to get a Randomizer. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/ResourceLoader.cpp b/src/global/ResourceLoader.cpp index c9201b1..a494c33 100644 --- a/src/global/ResourceLoader.cpp +++ b/src/global/ResourceLoader.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "ResourceLoader.h" diff --git a/src/global/ResourceLoader.h b/src/global/ResourceLoader.h index b390513..01373bc 100644 --- a/src/global/ResourceLoader.h +++ b/src/global/ResourceLoader.h @@ -1,7 +1,7 @@ /* * \brief Handler to load and manage resources and resource files. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/Result.cpp b/src/global/Result.cpp index da420bd..e30baf5 100644 --- a/src/global/Result.cpp +++ b/src/global/Result.cpp @@ -1,7 +1,5 @@ /*! - * Result.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "Result.h" @@ -17,9 +15,9 @@ using namespace governikus; #define RESULTMINOR "http://www.bsi.bund.de/ecard/api/1.1/resultminor" const QMap Result::mMajorResults = { - {Result::Major::Ok, RESULTMAJOR "#ok"}, - {Result::Major::Warning, RESULTMAJOR "#warning"}, - {Result::Major::Error, RESULTMAJOR "#error"} + {Result::Major::Ok, QString::fromLatin1(RESULTMAJOR "#ok")}, + {Result::Major::Warning, QString::fromLatin1(RESULTMAJOR "#warning")}, + {Result::Major::Error, QString::fromLatin1(RESULTMAJOR "#error")} }; // See TR-03112, section 4.2 for details about the codes @@ -29,34 +27,34 @@ const QMap Result::mMajorResults = { // 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"}, + {GlobalStatus::Code::Paos_Error_AL_Unknown_Error, QString::fromLatin1(RESULTMINOR "/al/common#unknownError")}, + {GlobalStatus::Code::Paos_Error_AL_No_Permission, QString::fromLatin1(RESULTMINOR "/al/common#noPermission")}, + {GlobalStatus::Code::Paos_Error_AL_Internal_Error, QString::fromLatin1(RESULTMINOR "/al/common#internalError")}, + {GlobalStatus::Code::Paos_Error_AL_Parameter_Error, QString::fromLatin1(RESULTMINOR "/al/common#parameterError")}, + {GlobalStatus::Code::Paos_Error_AL_Unkown_API_Function, QString::fromLatin1(RESULTMINOR "/al/common#unkownAPIFunction")}, + {GlobalStatus::Code::Paos_Error_AL_Not_Initialized, QString::fromLatin1(RESULTMINOR "/al/common#notInitialized")}, + {GlobalStatus::Code::Paos_Error_AL_Warning_Connection_Disconnected, QString::fromLatin1(RESULTMINOR "/al/common#warningConnectionDisconnected")}, + {GlobalStatus::Code::Paos_Error_AL_Session_Terminated_Warning, QString::fromLatin1(RESULTMINOR "/al/common#SessionTerminatedWarning")}, + {GlobalStatus::Code::Paos_Error_AL_Communication_Error, QString::fromLatin1(RESULTMINOR "/al/common#communicationError")}, + {GlobalStatus::Code::Paos_Error_DP_Timeout_Error, QString::fromLatin1(RESULTMINOR "/dp#timeout")}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Channel_Handle, QString::fromLatin1(RESULTMINOR "/dp#unknownChannelHandle")}, + {GlobalStatus::Code::Paos_Error_DP_Communication_Error, QString::fromLatin1(RESULTMINOR "/dp#communicationError")}, + {GlobalStatus::Code::Paos_Error_DP_Trusted_Channel_Establishment_Failed, QString::fromLatin1(RESULTMINOR "/dp#trustedChannelEstablishmentFailed")}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Protocol, QString::fromLatin1(RESULTMINOR "/dp#unknownProtocol")}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Cipher_Suite, QString::fromLatin1(RESULTMINOR "/dp#unknownCipherSuite")}, + {GlobalStatus::Code::Paos_Error_DP_Unknown_Webservice_Binding, QString::fromLatin1(RESULTMINOR "/dp#unknownWebserviceBinding")}, + {GlobalStatus::Code::Paos_Error_DP_Node_Not_Reachable, QString::fromLatin1(RESULTMINOR "/dp#nodeNotReachable")}, + {GlobalStatus::Code::Paos_Error_IFDL_Timeout_Error, QString::fromLatin1(RESULTMINOR "/ifdl/common#timeoutError")}, + {GlobalStatus::Code::Paos_Error_IFDL_InvalidSlotHandle, QString::fromLatin1(RESULTMINOR "/ifdl/common#invalidSlotHandle")}, + {GlobalStatus::Code::Paos_Error_IFDL_CancellationByUser, QString::fromLatin1(RESULTMINOR "/ifdl#cancellationByUser")}, + {GlobalStatus::Code::Paos_Error_KEY_KeyGenerationNotPossible, QString::fromLatin1(RESULTMINOR "/il/key#keyGenerationNotPossible")}, + {GlobalStatus::Code::Paos_Error_SAL_Cancellation_by_User, QString::fromLatin1(RESULTMINOR "/sal#cancellationByUser")}, + {GlobalStatus::Code::Paos_Error_SAL_CertificateChainInterrupted, QString::fromLatin1(RESULTMINOR "/sal#certificateChainInterrupted")}, + {GlobalStatus::Code::Paos_Error_SAL_Invalid_Key, QString::fromLatin1(RESULTMINOR "/sal#invalidKey")}, + {GlobalStatus::Code::Paos_Error_SAL_SecurityConditionNotSatisfied, QString::fromLatin1(RESULTMINOR "/sal#securityConditionNotSatisfied")}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_AgeVerificationFailedWarning, QString::fromLatin1(RESULTMINOR "/sal/mEAC#AgeVerificationFailedWarning")}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_CommunityVerificationFailedWarning, QString::fromLatin1(RESULTMINOR "/sal/mEAC#CommunityVerificationFailedWarning")}, + {GlobalStatus::Code::Paos_Error_SAL_MEAC_DocumentValidityVerificationFailed, QString::fromLatin1(RESULTMINOR "/sal/mEAC#DocumentValidityVerificationFailed")} }; @@ -67,7 +65,7 @@ Result Result::fromStatus(const GlobalStatus& pStatus) case GlobalStatus::Code::Unknown_Error: case GlobalStatus::Code::Paos_Unexpected_Warning: case GlobalStatus::Code::Paos_Error_AL_Unknown_Error: - break; + return Result(Result::Major::Error, GlobalStatus::Code::Paos_Error_AL_Unknown_Error, pStatus.toErrorDescription(), pStatus.getOrigin()); case GlobalStatus::Code::No_Error: return createOk(); @@ -95,6 +93,7 @@ Result Result::fromStatus(const GlobalStatus& pStatus) 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_ServiceUnavailable: case GlobalStatus::Code::Workflow_TrustedChannel_TimeOut: case GlobalStatus::Code::Workflow_TrustedChannel_Proxy_Error: case GlobalStatus::Code::Workflow_TrustedChannel_Ssl_Establishment_Error: @@ -129,6 +128,7 @@ Result Result::fromStatus(const GlobalStatus& pStatus) 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_ServiceUnavailable: case GlobalStatus::Code::Network_TimeOut: case GlobalStatus::Code::Network_Proxy_Error: case GlobalStatus::Code::Network_Other_Error: @@ -140,6 +140,7 @@ Result Result::fromStatus(const GlobalStatus& pStatus) 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::Workflow_AlreadyInProgress_Error: case GlobalStatus::Code::Card_Not_Found: case GlobalStatus::Code::Card_Communication_Error: case GlobalStatus::Code::Card_Input_TimeOut: @@ -219,16 +220,25 @@ Result Result::fromStatus(const GlobalStatus& pStatus) case GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose: case GlobalStatus::Code::RemoteReader_CloseCode_Undefined: + case GlobalStatus::Code::RemoteConnector_InvalidRequest: + case GlobalStatus::Code::RemoteConnector_EmptyPassword: + case GlobalStatus::Code::RemoteConnector_NoSupportedApiLevel: + case GlobalStatus::Code::RemoteConnector_ConnectionTimeout: + case GlobalStatus::Code::RemoteConnector_ConnectionError: + case GlobalStatus::Code::RemoteConnector_RemoteHostRefusedConnection: + case GlobalStatus::Code::Downloader_File_Not_Found: + case GlobalStatus::Code::Downloader_Cannot_Save_File: + case GlobalStatus::Code::Downloader_Data_Corrupted: 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()); + Q_UNREACHABLE(); } Result Result::createOk() { - return Result(Result::Major::Ok, GlobalStatus::Code::Unknown_Error); + return Result(Result::Major::Ok, GlobalStatus::Code::No_Error); } @@ -263,8 +273,10 @@ GlobalStatus::Code Result::parseMinor(const QString& pMinor) if (!pMinor.isEmpty()) { qWarning() << "Unknown ResultMinor:" << pMinor; + return GlobalStatus::Code::Unknown_Error; } - return GlobalStatus::Code::Unknown_Error; + + return GlobalStatus::Code::No_Error; } @@ -342,13 +354,13 @@ QString Result::getMessage(GlobalStatus::Code pMinor) 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."); + return tr("The process was cancelled by the 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."); + return tr("This action cannot be performed. The online identification function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document 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."); @@ -454,7 +466,7 @@ bool Result::isValid() const return false; case Major::Ok: - return d->mMinor == GlobalStatus::Code::Unknown_Error; + return d->mMinor == GlobalStatus::Code::No_Error; default: return d->mMinor != GlobalStatus::Code::Unknown_Error; @@ -464,7 +476,7 @@ bool Result::isValid() const bool Result::isOk() const { - return d->mMajor == Major::Ok && d->mMinor == GlobalStatus::Code::Unknown_Error; + return d->mMajor == Major::Ok && d->mMinor == GlobalStatus::Code::No_Error; } @@ -487,7 +499,7 @@ GlobalStatus Result::toStatus() const switch (getMajor()) { case Major::Unknown: - break; + return GlobalStatus(GlobalStatus::Code::Unknown_Error, message); case Major::Ok: if (isOk()) @@ -496,14 +508,14 @@ GlobalStatus Result::toStatus() const } // FALLTHROUGH - case Major::Warning: - return GlobalStatus(GlobalStatus::Code::Paos_Unexpected_Warning, message); - case Major::Error: return GlobalStatus(getMinor(), message, d->mOrigin); + + case Major::Warning: + return GlobalStatus(GlobalStatus::Code::Paos_Unexpected_Warning, message); } - return GlobalStatus(GlobalStatus::Code::Unknown_Error, message); + Q_UNREACHABLE(); } @@ -517,28 +529,28 @@ QJsonObject Result::toJson() const { QJsonObject obj; - obj["major"] = getMajorString(); - if (getMinor() != GlobalStatus::Code::Unknown_Error) + obj[QLatin1String("major")] = getMajorString(); + if (getMinor() != GlobalStatus::Code::No_Error) { - obj["minor"] = getMinorString(); + obj[QLatin1String("minor")] = getMinorString(); } const auto& message = getMessage(); if (!message.isEmpty()) { - obj["message"] = message; + obj[QLatin1String("message")] = message; } const auto& minorDesc = Result::getMessage(getMinor()); if (!minorDesc.isEmpty()) { - obj["description"] = minorDesc; + obj[QLatin1String("description")] = minorDesc; } const auto& lang = getMessageLang(); if (!lang.isEmpty() && (!message.isEmpty() || !minorDesc.isEmpty())) { - obj["language"] = lang; + obj[QLatin1String("language")] = lang; } return obj; @@ -547,7 +559,7 @@ QJsonObject Result::toJson() const QDebug operator <<(QDebug pDbg, const governikus::Result& pResult) { - const QString string = pResult.getMajorString() % " | " % pResult.getMinorString() % " | " % pResult.getMessage(); + const QString string = pResult.getMajorString() % QLatin1String(" | ") % pResult.getMinorString() % QLatin1String(" | ") % pResult.getMessage(); QDebugStateSaver saver(pDbg); pDbg.space() << "Result:"; pDbg.quote() << string; diff --git a/src/global/Result.h b/src/global/Result.h index 253eb4c..228cff8 100644 --- a/src/global/Result.h +++ b/src/global/Result.h @@ -1,12 +1,9 @@ /*! - * Result.h - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "CardReturnCode.h" #include "GlobalStatus.h" #include diff --git a/src/global/ScopeGuard.cpp b/src/global/ScopeGuard.cpp new file mode 100644 index 0000000..bf07d6e --- /dev/null +++ b/src/global/ScopeGuard.cpp @@ -0,0 +1,40 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ScopeGuard.h" + +#include + +using namespace governikus; + +ScopeGuard::ScopeGuard(const std::function& pFunc, bool pEnabled) + : mFunction(pFunc) + , mEnabled(pEnabled) +{ + if (!mFunction) + { + qWarning() << "Cannot call an empty function"; + } +} + + +ScopeGuard::~ScopeGuard() +{ + if (mEnabled && mFunction) + { + mFunction(); + } +} + + +bool ScopeGuard::isEnabled() const +{ + return mEnabled; +} + + +void ScopeGuard::setEnabled(bool pEnabled) +{ + mEnabled = pEnabled; +} diff --git a/src/global/ScopeGuard.h b/src/global/ScopeGuard.h new file mode 100644 index 0000000..d69e83d --- /dev/null +++ b/src/global/ScopeGuard.h @@ -0,0 +1,37 @@ +/*! + * \brief Calls a lambda once the object is destroyed + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class test_ScopeGuard; + +namespace governikus +{ + +class ScopeGuard +{ + private: + friend class ::test_ScopeGuard; + + const std::function mFunction; + bool mEnabled; + + public: + ScopeGuard(const ScopeGuard& pCopy) = delete; + ScopeGuard(const ScopeGuard&& pCopy) = delete; + ScopeGuard& operator=(const ScopeGuard& pCopy) = delete; + ScopeGuard& operator=(const ScopeGuard&& pCopy) = delete; + + ScopeGuard(const std::function& pFunc, bool pEnabled = true); + ~ScopeGuard(); + + bool isEnabled() const; + void setEnabled(bool pEnabled = true); +}; + +} /* namespace governikus */ diff --git a/src/global/SingletonHelper.h b/src/global/SingletonHelper.h index 0a6430a..cf57273 100644 --- a/src/global/SingletonHelper.h +++ b/src/global/SingletonHelper.h @@ -2,7 +2,7 @@ * \brief Helper to introduce a Singleton. * Be aware to use this helper in .cpp file only! * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/UsbId.cpp b/src/global/UsbId.cpp new file mode 100644 index 0000000..bbd5168 --- /dev/null +++ b/src/global/UsbId.cpp @@ -0,0 +1,45 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "UsbId.h" + +#include +#include + +using namespace governikus; + +UsbId::UsbId(unsigned int pVendorId, unsigned int pProductId) + : mVendorId(pVendorId) + , mProductId(pProductId) +{ + +} + + +unsigned int UsbId::getVendorId() const +{ + return mVendorId; +} + + +unsigned int UsbId::getProductId() const +{ + return mProductId; +} + + +bool UsbId::operator==(const UsbId& pOther) const +{ + return mVendorId == pOther.mVendorId + && mProductId == pOther.mProductId; +} + + +QDebug operator <<(QDebug pDbg, const UsbId& pUsbId) +{ + QDebugStateSaver saver(pDbg); + pDbg << "USB Vendor ID:" << QStringLiteral("0x%1").arg(pUsbId.getVendorId(), 0, 16) << + "USB Product ID:" << QStringLiteral("0x%1").arg(pUsbId.getProductId(), 0, 16); + return pDbg; +} diff --git a/src/global/UsbId.h b/src/global/UsbId.h new file mode 100644 index 0000000..aceabef --- /dev/null +++ b/src/global/UsbId.h @@ -0,0 +1,33 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class QDebug; + +namespace governikus +{ + +class UsbId +{ + private: + unsigned int mVendorId; + unsigned int mProductId; + + public: + UsbId(unsigned int pVendorId = 0x0, unsigned int pProductId = 0x0); + + unsigned int getVendorId() const; + unsigned int getProductId() const; + + bool operator==(const UsbId& pOther) const; +}; + +} /* namespace governikus */ + +Q_DECLARE_TYPEINFO(governikus::UsbId, Q_PRIMITIVE_TYPE); + +QDebug operator <<(QDebug pDbg, const governikus::UsbId& pUsbId); diff --git a/src/global/VersionInfo.cpp b/src/global/VersionInfo.cpp index 032505e..659f49f 100644 --- a/src/global/VersionInfo.cpp +++ b/src/global/VersionInfo.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + #include "VersionInfo.h" #include @@ -8,14 +12,21 @@ using namespace governikus; +namespace +{ +#define VERSION_NAME(_name, _key)\ + QString _name(){\ + return QStringLiteral(_key);\ + } -const QString NAME = QStringLiteral("Name"); -const QString IMPL_TITLE = QStringLiteral("Implementation-Title"); -const QString IMPL_VENDOR = QStringLiteral("Implementation-Vendor"); -const QString IMPL_VERSION = QStringLiteral("Implementation-Version"); -const QString SPEC_TITLE = QStringLiteral("Specification-Title"); -const QString SPEC_VENDOR = QStringLiteral("Specification-Vendor"); -const QString SPEC_VERSION = QStringLiteral("Specification-Version"); +VERSION_NAME(NAME, "Name") +VERSION_NAME(IMPL_TITLE, "Implementation-Title") +VERSION_NAME(IMPL_VENDOR, "Implementation-Vendor") +VERSION_NAME(IMPL_VERSION, "Implementation-Version") +VERSION_NAME(SPEC_TITLE, "Specification-Title") +VERSION_NAME(SPEC_VENDOR, "Specification-Vendor") +VERSION_NAME(SPEC_VERSION, "Specification-Version") +} VersionInfo::VersionInfo(const QMap& pInfo) @@ -33,13 +44,13 @@ 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.3")} }); } @@ -47,10 +58,10 @@ VersionInfo VersionInfo::getInstance() VersionInfo VersionInfo::fromText(const QString& pText) { QMap infos; - const auto& header = pText.splitRef('\n'); + const auto& header = pText.splitRef(QLatin1Char('\n')); for (const auto& line : header) { - const auto pair = line.split(':'); + const auto pair = line.split(QLatin1Char(':')); if (pair.size() != 2 || pair[0].trimmed().isEmpty() || pair[1].trimmed().isEmpty()) { qWarning() << "Cannot parse line:" << line; @@ -70,43 +81,43 @@ bool VersionInfo::isNull() const QString VersionInfo::getName() const { - return mInfo[NAME]; + return mInfo[NAME()]; } QString VersionInfo::getImplementationTitle() const { - return mInfo[IMPL_TITLE]; + return mInfo[IMPL_TITLE()]; } QString VersionInfo::getImplementationVendor() const { - return mInfo[IMPL_VENDOR]; + return mInfo[IMPL_VENDOR()]; } QString VersionInfo::getImplementationVersion() const { - return mInfo[IMPL_VERSION]; + return mInfo[IMPL_VERSION()]; } QString VersionInfo::getSpecificationTitle() const { - return mInfo[SPEC_TITLE]; + return mInfo[SPEC_TITLE()]; } QString VersionInfo::getSpecificationVendor() const { - return mInfo[SPEC_VENDOR]; + return mInfo[SPEC_VENDOR()]; } QString VersionInfo::getSpecificationVersion() const { - return mInfo[SPEC_VERSION]; + return mInfo[SPEC_VERSION()]; } @@ -134,7 +145,7 @@ QString VersionInfo::toText() const { list += QStringLiteral("%1: %2").arg(i.key(), i.value()); } - return list.join('\n'); + return list.join(QLatin1Char('\n')); } diff --git a/src/global/VersionInfo.h b/src/global/VersionInfo.h index f800b04..6743eb2 100644 --- a/src/global/VersionInfo.h +++ b/src/global/VersionInfo.h @@ -1,7 +1,5 @@ /*! - * VersionInfo.h - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/global/VersionNumber.cpp b/src/global/VersionNumber.cpp index 3cdb6ba..3e71bc6 100644 --- a/src/global/VersionNumber.cpp +++ b/src/global/VersionNumber.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "VersionNumber.h" @@ -11,23 +11,26 @@ using namespace governikus; Q_GLOBAL_STATIC_WITH_ARGS(VersionNumber, AppVersionNumber, (QCoreApplication::applicationVersion())) -const VersionNumber &VersionNumber::getApplicationVersion() -{ - return *AppVersionNumber; -} VersionNumber::VersionNumber(const QString& pVersion) : mVersionNumber() , mSuffix() { - // do not initialize idx, otherwise you will trap into - // a gcc bug: https://bugs.alpinelinux.org/issues/7584 - int idx; + int idx = 0; mVersionNumber = QVersionNumber::fromString(pVersion, &idx); +#ifdef Q_CC_GNU + __sync_synchronize(); // a gcc bug: https://bugs.alpinelinux.org/issues/7584 +#endif mSuffix = pVersion.mid(idx).trimmed(); } +const VersionNumber& VersionNumber::getApplicationVersion() +{ + return *AppVersionNumber; +} + + const QVersionNumber& VersionNumber::getVersionNumber() const { return mVersionNumber; @@ -42,8 +45,8 @@ bool VersionNumber::isDeveloperVersion() const int VersionNumber::getDistance() const { - const int indexStart = mSuffix.indexOf(QChar('+')) + 1; - const int indexEnd = mSuffix.indexOf(QChar('-'), indexStart); + const int indexStart = mSuffix.indexOf(QLatin1Char('+')) + 1; + const int indexEnd = mSuffix.indexOf(QLatin1Char('-'), indexStart); if (indexStart && indexEnd) { bool ok; @@ -60,8 +63,8 @@ int VersionNumber::getDistance() const QString VersionNumber::getBranch() const { - const int indexStart = mSuffix.indexOf(QChar('-')) + 1; - const int indexEnd = mSuffix.indexOf(QChar('-'), indexStart); + const int indexStart = mSuffix.indexOf(QLatin1Char('-')) + 1; + const int indexEnd = mSuffix.indexOf(QLatin1Char('-'), indexStart); if (indexStart && indexEnd) { return mSuffix.mid(indexStart, indexEnd - indexStart); @@ -73,9 +76,9 @@ QString VersionNumber::getBranch() const QString VersionNumber::getRevision() const { - if (mSuffix.count(QChar('-')) > 1) + if (mSuffix.count(QLatin1Char('-')) > 1) { - const int index = mSuffix.lastIndexOf(QChar('-')) + 1; + const int index = mSuffix.lastIndexOf(QLatin1Char('-')) + 1; if (index) { return mSuffix.mid(index); diff --git a/src/global/VersionNumber.h b/src/global/VersionNumber.h index 97aaea7..023c2f0 100644 --- a/src/global/VersionNumber.h +++ b/src/global/VersionNumber.h @@ -1,7 +1,7 @@ /*! * \brief Extension to QVersionNumber. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp deleted file mode 100644 index 104271d..0000000 --- a/src/gui/AboutDialog.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG - */ - -#include "AboutDialog.h" -#include "ui_AboutDialog.h" - -#include "AppSettings.h" -#include "BuildHelper.h" - -using namespace governikus; - - -AboutDialog::AboutDialog(QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::AboutDialog) -{ - mUi->setupUi(this); - - setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); - layout()->setSizeConstraint(QLayout::SetFixedSize); // For platform != Windows: Disable maximize button - setWindowModality(Qt::WindowModal); // For platform == macOS: Make dialog slide in from the top - - setWindowTitle(tr("About %1").arg(QCoreApplication::applicationName())); - mUi->lblFurtherInformation->setText(tr("Further information: %1") - .arg(QStringLiteral("https://www.ausweisapp.bund.de/"))); - mUi->lblReleaseNotes->setText(tr("The current release notes can be found %1 here. %2") - .arg(QStringLiteral(""), QStringLiteral(""))); - mUi->lblVersion->setText(tr("Version: %1 (%2)").arg(QApplication::applicationVersion(), QString::fromLatin1(BuildHelper::getDateTime()))); - mUi->lblDeveloperModeWarning->setText(QStringLiteral("

%1

") - .arg(tr("The developer mode is aimed at integrators / developers for new service applications. For this reason, the developer mode works only in the test PKI. By activating the developer mode, some safety tests are deactivated. This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode. Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2."))); - - const QIcon icon = windowIcon(); - const QSize size = icon.actualSize(QSize(64, 64)); - mUi->imgAusweisApp2->setPixmap(icon.pixmap(size)); - - connect(mUi->btnOkay, &QPushButton::clicked, this, &QDialog::accept); - connect(this, &QDialog::accepted, this, &AboutDialog::onAccept); - - mUi->chkbDeveloperMode->setCheckState(AppSettings::getInstance().getGeneralSettings().isDeveloperMode() ? Qt::Checked : Qt::Unchecked); - - connect(mUi->chkbDeveloperMode, &QCheckBox::stateChanged, this, &AboutDialog::onCheckboxStateChanged); - onCheckboxStateChanged(); -} - - -AboutDialog::~AboutDialog() -{ -} - - -void AboutDialog::onCheckboxStateChanged() -{ - const bool developerModeActivated = mUi->chkbDeveloperMode->checkState() == Qt::Checked; - mUi->lblDeveloperModeWarning->setVisible(developerModeActivated); - resize(minimumSize()); - adjustSize(); -} - - -void AboutDialog::onAccept() -{ - const bool developerModeActivated = mUi->chkbDeveloperMode->checkState() == Qt::Checked; - GeneralSettings& generalSettings = AppSettings::getInstance().getGeneralSettings(); - if (generalSettings.isDeveloperMode() != developerModeActivated) - { - generalSettings.setDeveloperMode(developerModeActivated); - generalSettings.save(); - } -} diff --git a/src/gui/AboutDialog.h b/src/gui/AboutDialog.h deleted file mode 100644 index 857b15c..0000000 --- a/src/gui/AboutDialog.h +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * \brief Dialog to display information about the application - * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class AboutDialog; -} - -namespace governikus -{ - -class AboutDialog - : public QDialog -{ - Q_OBJECT - - private: - QScopedPointer mUi; - - private Q_SLOTS: - void onCheckboxStateChanged(); - void onAccept(); - - public: - AboutDialog(QWidget* pParent = nullptr); - virtual ~AboutDialog(); -}; - -} /* namespace governikus */ diff --git a/src/gui/AboutDialog.ui b/src/gui/AboutDialog.ui deleted file mode 100644 index dbbd213..0000000 --- a/src/gui/AboutDialog.ui +++ /dev/null @@ -1,233 +0,0 @@ - - - AboutDialog - - - - 0 - 0 - 616 - 348 - - - - - 20 - - - QLayout::SetMinimumSize - - - 0 - - - 20 - - - 0 - - - 20 - - - - - 20 - - - 20 - - - 20 - - - - - - - - 0 - 0 - - - - - 64 - 64 - - - - $Image - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 40 - - - - - - - - - - 10 - - - QLayout::SetMinimumSize - - - - - <b>AusweisApp2</b> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Ministry of the Interior. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - $Further Information - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - $Release Notes - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - $Version - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - 0 - 0 - - - - Developer mode: - - - - - - - - 0 - 0 - - - - use - - - - - - - - - $developerWarning - - - true - - - - - - - - - - - 20 - - - 20 - - - 20 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - OK - - - true - - - - - - - - - - diff --git a/src/gui/AppQtGui.cpp b/src/gui/AppQtGui.cpp deleted file mode 100644 index d5ea31d..0000000 --- a/src/gui/AppQtGui.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/*! - * AppQtGui.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "AppQtGui.h" - -#include "AppSettings.h" -#include "DiagnosisGui.h" -#include "generic/HelpAction.h" -#include "generic/Page.h" -#include "GuiProfile.h" -#include "NetworkManager.h" -#include "ReaderDriverGui.h" -#include "SetupAssistantGui.h" -#include "Updater.h" -#include "UpdateWindow.h" -#include "workflow/WorkflowAuthenticateQtGui.h" -#include "workflow/WorkflowChangePinQtGui.h" -#include "workflow/WorkflowGui.h" -#include "workflow/WorkflowSelfInfoQtGui.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if defined(Q_OS_OSX) -#import -#endif - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -AppQtGui::AppQtGui() - : QObject() - , mMainWidget(nullptr) - , mIcon(QStringLiteral(":/images/npa.svg")) - , mTrayIcon(nullptr) - , mActiveWorkflowUi() - , mSetupAssistantGui(nullptr) - , mDiagnosisGui(nullptr) - , mReaderDriverGui(nullptr) - , mAggressiveToForeground(false) -{ - initGuiProfile(); - - mMainWidget = new AppQtMainWidget(); - mMainWidget->setWindowIcon(mIcon); -} - - -AppQtGui::~AppQtGui() -{ - if (mTrayIcon != nullptr) - { - QMenu* menu = mTrayIcon->contextMenu(); - if (menu != nullptr) - { - for (auto action : menu->actions()) - { - delete action; - } - delete menu; - } - } - - delete mMainWidget; -} - - -void AppQtGui::init() -{ - connect(mMainWidget, &AppQtMainWidget::fireChangePinRequested, this, &AppQtGui::fireChangePinRequested); - connect(mMainWidget, &AppQtMainWidget::fireSetupAssistantWizardRequest, this, &AppQtGui::onSetupAssistantWizardRequest); - connect(mMainWidget, &AppQtMainWidget::fireDiagnosisRequested, this, &AppQtGui::onDiagnosisRequested); - connect(mMainWidget, &AppQtMainWidget::fireReaderDriverRequested, this, &AppQtGui::onReaderDriverRequested); - connect(mMainWidget, &AppQtMainWidget::fireCloseWindowRequested, this, &AppQtGui::onCloseWindowRequested); - connect(mMainWidget, &AppQtMainWidget::fireSelfAuthenticationRequested, this, &AppQtGui::selfAuthenticationRequested); - connect(mMainWidget, &AppQtMainWidget::fireQuitApplicationRequested, this, &AppQtGui::quitApplicationRequested); - connect(mMainWidget, &AppQtMainWidget::fireChangeHighContrast, this, &AppQtGui::onChangeHighContrast); -} - - -void AppQtGui::onApplicationStarted() -{ - if (QSystemTrayIcon::isSystemTrayAvailable()) - { - createTrayIcon(); - } - - if (mTrayIcon != nullptr) - { - mTrayIcon->show(); - mTrayIcon->showMessage(QLatin1String(""), tr("AusweisApp2 was started."), QSystemTrayIcon::NoIcon, 3000); - } - - if (!QSystemTrayIcon::isSystemTrayAvailable() - || GuiProfile::getProfile().getShowWindow() - || AppSettings::getInstance().getGeneralSettings().isShowSetupAssistant() - || AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection); - } - - if (AppSettings::getInstance().getGeneralSettings().isShowSetupAssistant()) - { - mMainWidget->setSelectedTab(nullptr); - QMetaObject::invokeMethod(this, "onSetupAssistantWizardRequest", Qt::QueuedConnection); - - // just show the setup assistant once - AppSettings::getInstance().getGeneralSettings().setShowSetupAssistant(false); - AppSettings::getInstance().getGeneralSettings().save(); - } - - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - QMetaObject::invokeMethod(this, "onDeveloperModeQuestion", Qt::QueuedConnection); - } -} - - -QSharedPointer AppQtGui::createWorkflowAuthenticateUi(const QSharedPointer& pContext) -{ - return QSharedPointer(new WorkflowAuthenticateQtGui(pContext, mMainWidget)); -} - - -QSharedPointer AppQtGui::createWorkflowChangePinUi(const QSharedPointer& pContext) -{ - return QSharedPointer(new WorkflowChangePinQtGui(pContext, mMainWidget)); -} - - -QSharedPointer AppQtGui::createWorkflowSelfInfoUi(const QSharedPointer& pContext) -{ - return QSharedPointer(new WorkflowSelfInfoQtGui(pContext, mMainWidget)); -} - - -void AppQtGui::activateWorkflowUi(QSharedPointer pWorkflowUi, bool pAllowHideAfterWorkflow) -{ - if (pWorkflowUi) - { - mActiveWorkflowUi = pWorkflowUi; - mActiveWorkflowUi->activate(); - } - - mMainWidget->activateMenuBarItems(false); - closeDialogs(); - -#ifdef Q_OS_WIN - mAggressiveToForeground = mActiveWorkflowUi.objectCast(); -#endif - bool hideAfterWorkflow = pAllowHideAfterWorkflow - && mActiveWorkflowUi.objectCast() - && AppSettings::getInstance().getGeneralSettings().isAutoCloseWindowAfterAuthentication(); - mMainWidget->setHideWindowAfterWorkflow(hideAfterWorkflow); - show(); -} - - -void AppQtGui::deactivateCurrentWorkflowUi() -{ - if (mMainWidget->isHideWindowAfterWorkflow()) - { - hideFromTaskbar(); - mMainWidget->hide(); - } - mMainWidget->activateMenuBarItems(true); - - if (mActiveWorkflowUi) - { - mActiveWorkflowUi->deactivate(); - mActiveWorkflowUi.clear(); - } -} - - -void AppQtGui::onShowUserInformation(const QString& pInformationMessage) -{ - QMessageBox msgBox(mMainWidget); - msgBox.setWindowTitle(QCoreApplication::applicationName() + " - Information"); - msgBox.setIcon(QMessageBox::Information); - msgBox.setText(pInformationMessage); - msgBox.setStandardButtons(QMessageBox::StandardButton::Ok); - msgBox.exec(); -} - - -void AppQtGui::onSetupAssistantWizardRequest() -{ - if (!mSetupAssistantGui) - { - mSetupAssistantGui = new SetupAssistantGui(mMainWidget); - connect(mSetupAssistantGui, &SetupAssistantGui::fireChangePinButtonClicked, mMainWidget, &AppQtMainWidget::onChangePinButtonClicked); - } - mSetupAssistantGui->activate(); -} - - -void AppQtGui::onDeveloperModeQuestion() -{ - QMessageBox msgBox(mMainWidget); - msgBox.setWindowModality(Qt::WindowModal); - msgBox.setWindowFlags(msgBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); - msgBox.setIconPixmap(mMainWidget->windowIcon().pixmap(QSize(48, 48))); - msgBox.setText(tr("The developer mode is enabled.")); - msgBox.setInformativeText(tr("Do you want to disable the developer mode?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - - if (msgBox.exec() == QMessageBox::Yes) - { - AppSettings::getInstance().getGeneralSettings().setDeveloperMode(false); - AppSettings::getInstance().getGeneralSettings().save(); - } -} - - -void AppQtGui::onDiagnosisRequested() -{ - if (!mDiagnosisGui) - { - mDiagnosisGui = new DiagnosisGui(mMainWidget); - } - mDiagnosisGui->activate(); -} - - -void AppQtGui::onReaderDriverRequested() -{ - if (!mReaderDriverGui) - { - mReaderDriverGui = new ReaderDriverGui(mMainWidget); - } - mReaderDriverGui->activate(); -} - - -bool AppQtGui::askChangeTransportPinNow() -{ - GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); - if (!settings.isTransportPinReminder()) - { - return false; - } - settings.setTransportPinReminder(false); - settings.save(); - - show(UiModule::PINMANAGEMENT); - closeDialogs(); - - 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); - messageBox.exec(); - - if (messageBox.clickedButton() != changePinButton) - { - return false; - } - - return true; -} - - -bool AppQtGui::eventFilter(QObject* /*pObject*/, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - - if (keyEvent->key() == Qt::BackButton || keyEvent->key() == Qt::Key_Back) - { - Q_EMIT quitApplicationRequested(); - return true; - } - } - return false; -} - - -void AppQtGui::initGuiProfile() -{ - GuiProfile& profile = GuiProfile::getProfile(); - - QSize maxWindowSize = profile.getWindowSize(); - if (!maxWindowSize.isValid()) - { - QDesktopWidget widget; - maxWindowSize = widget.screenGeometry(widget.primaryScreen()).size(); - } - - qCDebug(gui) << "max_window_size:" << maxWindowSize; - bool smallScreen = static_cast(maxWindowSize.width()) * static_cast(maxWindowSize.height()) < 700000; - if (smallScreen) - { - profile.setScreenSize(ScreenSize::SMALL); - } - else - { - profile.setScreenSize(ScreenSize::MEDIUM); - } - - profile.setShowMainTabs(!smallScreen); - - // set style sheet only if none has be specified on the command line - if (qApp->styleSheet().isEmpty()) - { - if (profile.getDebugStyleSheet().isEmpty()) - { - loadStyleSheet(profile.getStyleSheetName(), true); - } - else - { - QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList() << profile.getDebugStyleSheet(), this); - connect(watcher, &QFileSystemWatcher::fileChanged, this, &AppQtGui::onDebugStyleSheetChanged); - loadStyleSheet(profile.getDebugStyleSheet(), false); - } - } -} - - -void AppQtGui::loadStyleSheet(const QString& pStyleSheetName, bool pIsResource) -{ - QString styleSheetName = pIsResource ? QStringLiteral(":/stylesheets/") + pStyleSheetName : pStyleSheetName; - qCDebug(gui) << "loading style sheet" << styleSheetName; - QString styleSheet = readStyleSheet(styleSheetName); - if (!styleSheet.isEmpty()) - { - qApp->setStyleSheet(styleSheet); - } - else - { - qCWarning(gui) << "Failed to load global style sheet!"; - } -} - - -QString AppQtGui::readStyleSheet(const QString& pFileName) -{ - // read the file into a string - QFile file(pFileName); - if (!file.open(QIODevice::ReadOnly)) - { - qCWarning(gui) << "Failed to read style sheet:" << pFileName; - return QString(); - } - - QString styleSheet = QString::fromLatin1(file.readAll()); - file.close(); - - // resolve imports - // Note: The algorithm is very simple and e.g. doesn't detect that an import is commented out. - QRegularExpression regExp(QStringLiteral("@import\\s+\"([^\"]*)\"\\s*;")); - QRegularExpressionMatchIterator it = regExp.globalMatch(styleSheet); - if (!it.hasNext()) - { - return styleSheet; - } - - QString result; - int lastOffset = 0; - - while (it.hasNext()) - { - QRegularExpressionMatch match = it.next(); - if (lastOffset < match.capturedStart()) - { - result += styleSheet.midRef(lastOffset, match.capturedStart() - lastOffset); - } - - result += readStyleSheet(match.captured(1)); - - lastOffset = match.capturedEnd(); - } - - if (lastOffset < styleSheet.length()) - { - result += styleSheet.midRef(lastOffset); - } - - return result; -} - - -void AppQtGui::onChangeHighContrast(bool* pHighContrastOn) -{ - if (*pHighContrastOn) - { - qApp->setStyleSheet(QString()); - } - else - { - initGuiProfile(); - } -} - - -void AppQtGui::createTrayIcon() -{ - QMenu* trayIconMenu = new QMenu(nullptr); - -#if defined(Q_OS_OSX) - QAction* showApplicationAction = new QAction(tr("Open"), trayIconMenu); - connect(showApplicationAction, &QAction::triggered, this, [this] {AppQtGui::show(); - } - ); -#endif - - QAction* quitAction = new QAction(tr("Exit AusweisApp2"), trayIconMenu); - connect(quitAction, &QAction::triggered, this, &AppQtGui::quitApplicationRequested); - -#if defined(Q_OS_OSX) - trayIconMenu->addAction(showApplicationAction); - trayIconMenu->addSeparator(); -#endif - trayIconMenu->addAction(quitAction); - - mTrayIcon = new QSystemTrayIcon(mIcon, mMainWidget); - connect(mTrayIcon, &QSystemTrayIcon::activated, this, &AppQtGui::onActivated); - connect(mTrayIcon, &QSystemTrayIcon::messageClicked, this, [this] {show(UiModule::CURRENT); - }); - - mTrayIcon->setContextMenu(trayIconMenu); - mTrayIcon->setToolTip(QCoreApplication::applicationName()); -} - - -void AppQtGui::closeDialogs() -{ - if (mSetupAssistantGui) - { - mSetupAssistantGui->deactivate(); - } - if (mDiagnosisGui) - { - mDiagnosisGui->deactivate(); - } - if (mReaderDriverGui) - { - mReaderDriverGui->deactivate(); - } -} - - -void AppQtGui::hideFromTaskbar() -{ -#if defined(Q_OS_OSX) - ProcessSerialNumber psn = { - 0, kCurrentProcess - }; - TransformProcessType(&psn, kProcessTransformToBackgroundApplication); -#endif -} - - -void AppQtGui::restoreToTaskbar() -{ -#if defined(Q_OS_OSX) - ProcessSerialNumber psn = { - 0, kCurrentProcess - }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - [NSApp activateIgnoringOtherApps: YES]; -#endif -} - - -void AppQtGui::onActivated(QSystemTrayIcon::ActivationReason pReason) -{ -#ifdef Q_OS_OSX - Q_UNUSED(pReason) -#else - if (pReason == QSystemTrayIcon::Trigger) - { - show(); - } -#endif -} - - -void AppQtGui::onCloseWindowRequested(bool* pDoClose) -{ - if (mMainWidget->isRemindUserToClose()) - { - QMessageBox messageBox(mMainWidget); - messageBox.installEventFilter(this); - 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."))); - messageBox.exec(); - - Q_EMIT fireCloseReminderFinished(messageBox.checkBox()->isChecked()); - } - - if (mActiveWorkflowUi == nullptr) - { - *pDoClose = true; - } - else if ((*pDoClose = mActiveWorkflowUi->verifyAbortWorkflow())) - { - Q_EMIT mActiveWorkflowUi->fireUserCancelled(); - } - - if (*pDoClose) - { - hideFromTaskbar(); - } -} - - -void AppQtGui::onDebugStyleSheetChanged(const QString& pPath) -{ - if (QFileSystemWatcher* watcher = qobject_cast(sender())) - { - // work-around for QFileSystemWatcher no longer knowing the file after receiving the first notification - watcher->removePath(pPath); - watcher->addPath(pPath); - } - - loadStyleSheet(pPath, false); -} - - -#ifndef QT_NO_NETWORKPROXY -void AppQtGui::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) -{ - CredentialDialog dialog(mMainWidget); - dialog.setUser(pProxy.user()); - - if (dialog.exec() == QDialog::Accepted) - { - pAuthenticator->setUser(dialog.getUser()); - pAuthenticator->setPassword(dialog.getPassword()); - } -} - - -#endif - - -void AppQtGui::show(UiModule pModule) -{ - if (!mActiveWorkflowUi.isNull()) - { - pModule = UiModule::CURRENT; - } - - switch (pModule) - { - case UiModule::PINMANAGEMENT: - mMainWidget->switchToGuiModule(GuiModule::PIN_SETTINGS); - break; - - case UiModule::SETTINGS: - mMainWidget->switchToGuiModule(GuiModule::GENERAL_SETTINGS); - break; - - case UiModule::DEFAULT: - mMainWidget->switchToGuiModule(GuiModule::START_PAGE); - break; - - case UiModule::CURRENT: - // don't switch the module, just show the current one - break; - } - - restoreToTaskbar(); - - if (mMainWidget->isMinimized()) - { - mMainWidget->showNormal(); - } - - // Ensure the window's minimumSizeHint is respected (work-around for a Windows Qt bug). - if (!mMainWidget->isMaximized()) - { - QSize size = mMainWidget->size(); - size = size.expandedTo(mMainWidget->minimumSizeHint()); - 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. - const Qt::WindowFlags flags = mMainWidget->windowFlags(); - mMainWidget->setWindowFlags(flags | Qt::WindowStaysOnTopHint); - mMainWidget->show(); - mMainWidget->setWindowFlags(flags); - - mAggressiveToForeground = false; - } -#endif - - mMainWidget->show(); - mMainWidget->activateWindow(); - - // Work-around for the window not being brought to the foreground. Invoke - // activateWindow() again after the events currently pending in the event - // queue have been processed. This appears to do the job. Note that the - // first activateWindow() above is apparently still necessary. - QCoreApplication::processEvents(); - mMainWidget->activateWindow(); - - static bool firstCheck = true; - if (firstCheck) - { - firstCheck = false; - Updater::getInstance().update(); - if (AppSettings::getInstance().getGeneralSettings().isAutoUpdateCheck()) - { - new UpdateWindow(true, mMainWidget); - } - } -} - - -void AppQtGui::shutdown() -{ - if (mTrayIcon != nullptr) - { - mTrayIcon->hide(); - } -} diff --git a/src/gui/AppQtGui.h b/src/gui/AppQtGui.h deleted file mode 100644 index 22b5b78..0000000 --- a/src/gui/AppQtGui.h +++ /dev/null @@ -1,99 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppQtMainWidget.h" -#include "CredentialDialog.h" - -#include "context/AuthContext.h" -#include "context/ChangePinContext.h" -#include "context/DiagnosisContext.h" -#include "context/ReaderDriverContext.h" -#include "context/SelfAuthenticationContext.h" - -#include - -namespace governikus -{ - -class WorkflowGui; -class WorkflowAuthenticateQtGui; -class WorkflowChangePinQtGui; -class WorkflowSelfInfoQtGui; -class SetupAssistantGui; -class DiagnosisGui; -class ReaderDriverGui; - -class AppQtGui - : public QObject -{ - Q_OBJECT - - public: - AppQtGui(); - virtual ~AppQtGui(); - - virtual void init(); - - virtual QSharedPointer createWorkflowAuthenticateUi(const QSharedPointer& pContext); - virtual QSharedPointer createWorkflowChangePinUi(const QSharedPointer& pContext); - virtual QSharedPointer createWorkflowSelfInfoUi(const QSharedPointer& pContext); - - virtual void activateWorkflowUi(QSharedPointer pWorkflowUi, bool pAllowHideAfterWorkflow = true); - virtual void deactivateCurrentWorkflowUi(); - - virtual bool askChangeTransportPinNow(); - - void shutdown(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - void initGuiProfile(); - void loadStyleSheet(const QString& pStyleSheetName, bool pIsResource); - QString readStyleSheet(const QString& pFileName); - void createTrayIcon(); - void closeDialogs(); - void hideFromTaskbar(); - void restoreToTaskbar(); - - public Q_SLOTS: - 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); - void onCloseWindowRequested(bool* pDoClose); - void onDebugStyleSheetChanged(const QString& pPath); - void onChangeHighContrast(bool* pHighContrastOn); - void onSetupAssistantWizardRequest(); - void onDeveloperModeQuestion(); - void onReaderDriverRequested(); - void onDiagnosisRequested(); - - private: - AppQtMainWidget* mMainWidget; - QIcon mIcon; - QSystemTrayIcon* mTrayIcon; - QSharedPointer mActiveWorkflowUi; - SetupAssistantGui* mSetupAssistantGui; - DiagnosisGui* mDiagnosisGui; - ReaderDriverGui* mReaderDriverGui; - bool mAggressiveToForeground; - - Q_SIGNALS: - void fireCloseReminderFinished(bool pDontRemindAgain); - - void fireChangePinRequested(); - void selfAuthenticationRequested(); - void quitApplicationRequested(); -}; - -} /* namespace governikus */ diff --git a/src/gui/AppQtMainWidget.cpp b/src/gui/AppQtMainWidget.cpp deleted file mode 100644 index f6c37eb..0000000 --- a/src/gui/AppQtMainWidget.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AppQtMainWidget.h" - -#include "AboutDialog.h" -#include "BuildHelper.h" -#include "generic/ExclusiveButtonGroup.h" -#include "generic/HelpAction.h" -#include "GuiProfile.h" -#include "LogHandler.h" -#include "ReaderDetector.h" -#include "ReaderDriverDialog.h" -#include "step/AuthenticateStepsWidget.h" -#include "SetupAssistantWizard.h" -#include "ui_AppQtMainWidget.h" -#include "VersionNumber.h" -#include "workflow/WorkflowQtWidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN -#include -#endif - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(gui) - -AppQtMainWidget::AppQtMainWidget() - : QMainWindow() - , mUi(new Ui::AppQtMainWidget()) - , mTabButton2Page() - , mTabAction2Button() - , mAuthenticationWorkflowWidget(nullptr) - , mSelectedPushButton(nullptr) - , mSelectedPushButtonBeforeWorkflow(nullptr) - , mSelectedPagesBeforeWorkflow() - , mHideWindowAfterWorkflow(false) - , mLogFilesDialog() -{ - mUi->setupUi(this); - - mUi->appLogoWidget->setAttribute(Qt::WA_TransparentForMouseEvents); - - QStackedLayout* centralStackLayout = qobject_cast(mUi->centralWidget->layout()); - centralStackLayout->setStackingMode(QStackedLayout::StackAll); - centralStackLayout->setCurrentIndex(1); - - QSpacerItem* spacer = new QSpacerItem(1, mUi->logoLabel->sizeHint().height(), QSizePolicy::Fixed, QSizePolicy::Ignored); - mUi->applicationGridLayout->addItem(spacer, mUi->applicationGridLayout->rowCount(), 0); - - mUi->providerPage->layout()->setMargin(20); - mUi->historyPage->layout()->setMargin(20); - - mAuthenticationWorkflowWidget = new WorkflowQtWidget(); - mUi->workflowPage->layout()->addWidget(mAuthenticationWorkflowWidget); - mAuthenticationWorkflowWidget->getStepWidgetArea()->layout()->addWidget(new AuthenticateStepsWidget); - - //menu file - connect(mUi->actionBeenden, &QAction::triggered, this, &AppQtMainWidget::fireQuitApplicationRequested); - connect(mUi->actionSettings, &QAction::triggered, this, &AppQtMainWidget::onSettingsButtonClicked); - - //menu PIN management - connect(mUi->actionChangePin, &QAction::triggered, this, &AppQtMainWidget::onChangePinButtonClicked); - - //help - connect(mUi->actionSetupAssistant, &QAction::triggered, this, &AppQtMainWidget::fireSetupAssistantWizardRequest); - connect(mUi->actionDiagnosis, &QAction::triggered, this, &AppQtMainWidget::fireDiagnosisRequested); - - connect(mUi->actionShowProtocol, &QAction::triggered, this, &AppQtMainWidget::onOpenLoggingFileButtonClicked); - connect(mUi->actionSaveProtocol, &QAction::triggered, this, &AppQtMainWidget::onSaveLoggingFileButtonClicked); - connect(mUi->actionInfo, &QAction::triggered, this, &AppQtMainWidget::onAboutActionClicked); - connect(mUi->actionSendError, &QAction::triggered, this, &AppQtMainWidget::onSendErrorActionClicked); - connect(mUi->actionEvaluate, &QAction::triggered, this, &AppQtMainWidget::onEvaluateActionClicked); - connect(mUi->actionQuestion, &QAction::triggered, this, &AppQtMainWidget::onQuestionActionClicked); - connect(mUi->actionHelp, &QAction::triggered, this, &AppQtMainWidget::onContentActionClicked); - - connect(mUi->ausweisenPage, &SelfInformationWidget::selfAuthenticationRequested, this, &AppQtMainWidget::fireSelfAuthenticationRequested); - connect(mUi->settingsPage, &SettingsWidget::changePinRequested, this, &AppQtMainWidget::fireChangePinRequested); - connect(mUi->settingsPage, &SettingsWidget::diagnosisRequested, this, &AppQtMainWidget::fireDiagnosisRequested); - connect(mUi->settingsPage, &SettingsWidget::driverRequested, this, &AppQtMainWidget::fireReaderDriverRequested); - connect(mUi->settingsPage, &SettingsWidget::settingsDone, this, &AppQtMainWidget::onSettingsDone); - - //NavigationButtons - mUi->startPushButton->setVisible(false); - mUi->mainTabList->addButton(mUi->startPushButton); - mTabButton2Page.insert(mUi->startPushButton, mUi->applicationPage); - - struct ButtonInfo - { - QAbstractButton* mButton; - QWidget* mPage; - QAction* mAction; - const char* mOnIcon; - const char* mOffIcon; - }; - ButtonInfo buttonInfos[] = { - {mUi->ausweisenToolButton, mUi->ausweisenPage, mUi->actionAusweisen, ":/images/bt_1.svg", ":/images/bt_1b.svg"}, - {mUi->providerToolButton, mUi->providerPage, mUi->actionProvider, ":/images/bt_2.svg", ":/images/bt_2b.svg"}, - {mUi->historyToolButton, mUi->historyPage, mUi->actionHistory, ":/images/bt_3.svg", ":/images/bt_3b.svg"}, - {mUi->settingsToolButton, mUi->settingsPage, mUi->actionSettings, ":/images/bt_4.svg", ":/images/bt_4b.svg"}, - }; - - for (size_t i = 0; i < sizeof(buttonInfos) / sizeof(buttonInfos[0]); ++i) - { - const ButtonInfo& buttonInfo = buttonInfos[i]; - QIcon icon; - icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOnIcon)), QIcon::Normal, QIcon::Off); - icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOffIcon)), QIcon::Normal, QIcon::On); - - buttonInfo.mButton->setIcon(icon); - - connect(buttonInfo.mAction, &QAction::triggered, this, &AppQtMainWidget::onTabActionTriggered); - - mUi->mainTabList->addButton(buttonInfo.mButton); - mTabButton2Page.insert(buttonInfo.mButton, buttonInfo.mPage); - mTabAction2Button.insert(buttonInfo.mAction, buttonInfo.mButton); - } - - connect(mUi->mainTabList, &TabButtonGroup::buttonToggled, this, &AppQtMainWidget::onTabButtonToggled); - mUi->stackedWidget->setCurrentIndex(0); - - if (VersionNumber::getApplicationVersion().isDeveloperVersion()) - { - setWindowTitle(windowTitle() + QStringLiteral(" - Beta - ") + QCoreApplication::applicationVersion()); - mUi->betaLabel->setMinimumSize(QSize(150, 150)); - mUi->betaLabel->setPixmap(QPixmap(QStringLiteral(":/images/beta.svg")).scaled(mUi->betaLabel->width(), mUi->betaLabel->width(), Qt::KeepAspectRatio)); - mUi->betaLabel->setVisible(true); - } - - - // work-around for bug QT/QTBUG-40869 - QSet visitedObjects; - updateGeometryRecursively(this, visitedObjects); - -#ifdef Q_OS_WIN - // we need to call create() explicitly because Windows needs a handle to fire WM_ENDSESSION! - // Since we start as a systemtray only we don't have a correct handle until we call show() - create(); -#endif -} - - -AppQtMainWidget::~AppQtMainWidget() -{ -} - - -void AppQtMainWidget::changeEvent(QEvent* pEvent) -{ - if (pEvent->type() == QEvent::PaletteChange) // QEvent::StyleChange is called, too - { - -#if defined(Q_OS_WIN) - HIGHCONTRAST hc; - hc.cbSize = sizeof(hc); - - bool highContrastOn = false; - if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, FALSE) && (hc.dwFlags & HCF_HIGHCONTRASTON)) - { - qDebug() << "High contrast (SPI_GETHIGHCONTRAST) switched on."; - highContrastOn = true; - Q_EMIT fireChangeHighContrast(&highContrastOn); - } - else - { - qDebug() << "High contrast (SPI_GETHIGHCONTRAST) switched off."; - Q_EMIT fireChangeHighContrast(&highContrastOn); - } -#endif - } -} - - -void AppQtMainWidget::workflowActivated(WorkflowWidgetParent pParent, const QString& /*pName*/) -{ - QAbstractButton* tabToolButton = nullptr; - QWidget* containingWidget = nullptr; - - // activate the correct tab and set the workflow page - switch (pParent) - { - case WorkflowWidgetParent::SelfAuthentication: - case WorkflowWidgetParent::Authentication: - tabToolButton = mUi->ausweisenToolButton; - containingWidget = mUi->workflowPage; - break; - - case WorkflowWidgetParent::SettingsChangePin: - tabToolButton = mUi->settingsToolButton; - containingWidget = nullptr; - break; - } - - mSelectedPushButtonBeforeWorkflow = mSelectedPushButton; - - setSelectedTab(tabToolButton); - - if (tabToolButton != nullptr) - { - const auto tabButtons = mTabButton2Page.keys(); - for (auto button : tabButtons) - { - if (button != tabToolButton) - { - button->setEnabled(false); - } - } - } - - // show the respective page in the widget stacks - while (containingWidget != nullptr) - { - QWidget* containerParent = containingWidget->parentWidget(); - if (QStackedWidget* stackedWidget = qobject_cast(containerParent)) - { - mSelectedPagesBeforeWorkflow += stackedWidget->currentWidget(); - stackedWidget->setCurrentWidget(containingWidget); - } - - containingWidget = containerParent; - } - - mUi->settingsPage->workflowStarted(); - mUi->mainTabList->setWorkflowActive(true); - -} - - -void AppQtMainWidget::workflowDeactivated() -{ - const auto tabButtons = mTabButton2Page.keys(); - for (auto button : tabButtons) - { - button->setEnabled(true); - } - - for (auto widget : qAsConst(mSelectedPagesBeforeWorkflow)) - { - if (QStackedWidget* stackedWidget = qobject_cast(widget->parentWidget())) - { - stackedWidget->setCurrentWidget(widget); - } - - } - mSelectedPagesBeforeWorkflow.clear(); - - mUi->settingsPage->workflowFinished(); - mUi->mainTabList->setWorkflowActive(false); - - // switch back to the tab selected before the workflow - if (mSelectedPushButtonBeforeWorkflow == nullptr) - { - return; - } - setSelectedTab(mSelectedPushButtonBeforeWorkflow); - mSelectedPushButtonBeforeWorkflow = nullptr; -} - - -void AppQtMainWidget::switchToGuiModule(GuiModule pModule) -{ - switch (pModule) - { - case GuiModule::START_PAGE: - setSelectedTab(mUi->startPushButton); - break; - - case GuiModule::GENERAL_SETTINGS: - case GuiModule::PIN_SETTINGS: - setSelectedTab(mUi->settingsToolButton); - mUi->settingsPage->switchToGuiModule(pModule); - break; - } -} - - -void AppQtMainWidget::switchToPinSettingsAfterWorkflow() -{ - mHideWindowAfterWorkflow = false; - mSelectedPushButtonBeforeWorkflow = mUi->settingsToolButton; - - mSelectedPagesBeforeWorkflow.clear(); - - QWidget* containingWidget = mUi->stackedWidget->parentWidget(); - - while (containingWidget != nullptr) - { - QWidget* containerParent = containingWidget->parentWidget(); - if (qobject_cast(containerParent) != nullptr) - { - mSelectedPagesBeforeWorkflow += containingWidget; - } - - containingWidget = containerParent; - } - - mUi->settingsPage->switchToGuiModule(GuiModule::PIN_SETTINGS); -} - - -void AppQtMainWidget::closeEvent(QCloseEvent* pEvent) -{ - bool doClose = true; - Q_EMIT fireCloseWindowRequested(&doClose); - if (doClose) - { - pEvent->accept(); - } - else - { - pEvent->ignore(); - } -} - - -void AppQtMainWidget::keyPressEvent(QKeyEvent* keyEvent) -{ - switch (keyEvent->key()) - { - case Qt::Key_F1: - onContentActionClicked(); - break; - - default: - break; - } -} - - -void AppQtMainWidget::setSelectedTab(QAbstractButton* pSelectedPushButton) -{ - if (pSelectedPushButton == nullptr) - { - pSelectedPushButton = mUi->settingsToolButton; - mUi->settingsPage->switchToGuiModule(GuiModule::GENERAL_SETTINGS); - - } - if (mSelectedPushButton == mUi->settingsToolButton && mUi->settingsPage->isSettingsChanged()) - { - const auto tabButtons = mTabButton2Page.keys(); - for (auto button : tabButtons) - { - button->setChecked(button == mUi->settingsToolButton); - } - mUi->settingsPage->showSettingsChangedMessage(); - } - - mUi->appLogoWidget->setVisible(pSelectedPushButton == mUi->startPushButton); - - if (mSelectedPushButton) - { - mSelectedPushButton->clearFocus(); - } - mSelectedPushButton = pSelectedPushButton; - mSelectedPushButton->setChecked(true); - - mUi->stackedWidget->setCurrentWidget(mTabButton2Page.value(pSelectedPushButton)); -} - - -void AppQtMainWidget::activateWindow() -{ - QMainWindow::activateWindow(); - -#if defined(Q_OS_OSX) - // Workaround. When switching from "BackgroundApplication" to "ForegroundApplication" - // on MacOS, it is a known problem that the menu bar of the previous active application - // stays visible, although the window has changed to the current application. As soon - // as the user clicks the menu, it magically transforms to the correct one. We therefore - // manually trigger an update. Neither update() nor repaint() of QMenuBar solve this problem. - QMenu menu; - mUi->menuBar->addAction(menu.menuAction()); - mUi->menuBar->removeAction(menu.menuAction()); -#endif -} - - -void AppQtMainWidget::updateGeometryRecursively(QWidget* pWidget, QSet& pVisitedObjects) -{ - if (pVisitedObjects.contains(pWidget)) - { - return; - } - - pVisitedObjects.insert(pWidget); - - pWidget->updateGeometry(); - - if (pWidget->layout() != nullptr) - { - updateGeometryRecursively(pWidget->layout(), pVisitedObjects); - } - - for (QObject* child : pWidget->children()) - { - if (QWidget* widget = qobject_cast(child)) - { - updateGeometryRecursively(widget, pVisitedObjects); - } - } -} - - -void AppQtMainWidget::updateGeometryRecursively(QLayout* pLayout, QSet& pVisitedObjects) -{ - if (pVisitedObjects.contains(pLayout)) - { - return; - } - - pVisitedObjects.insert(pLayout); - - pLayout->invalidate(); - - int itemCount = pLayout->count(); - for (int i = 0; i < itemCount; ++i) - { - QLayoutItem* item = pLayout->itemAt(i); - - if (QLayout* layout = item->layout()) - { - updateGeometryRecursively(layout, pVisitedObjects); - } - else if (QWidget* widget = item->widget()) - { - updateGeometryRecursively(widget, pVisitedObjects); - } - } -} - - -void AppQtMainWidget::onSettingsDone() -{ - setSelectedTab(mUi->startPushButton); -} - - -void AppQtMainWidget::onOpenLoggingFileButtonClicked() -{ - if (!mLogFilesDialog) - { - mLogFilesDialog = new LogFilesDialog(this); - } - - mLogFilesDialog->show(); -} - - -void AppQtMainWidget::onSaveLoggingFileButtonClicked() -{ - 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 += QStringLiteral(".log"); - } - - qCDebug(gui) << "File location:" << filename; - - if (QFile::exists(filename)) - { - bool deleted = QFile::remove(filename); - qCDebug(gui) << "Delete file location:" << deleted; - } - - bool copied = LogHandler::getInstance().copy(filename); - qCDebug(gui) << "Copy log to file location:" << copied; - } -} - - -void AppQtMainWidget::onTabButtonToggled(QAbstractButton* pButton, bool pChecked) -{ - if (pChecked) - { - if (mTabButton2Page.contains(pButton) && mSelectedPushButton != pButton) - { - setSelectedTab(pButton); - } - } -} - - -void AppQtMainWidget::onTabActionTriggered() -{ - if (QAction* action = qobject_cast(sender())) - { - if (QAbstractButton* button = mTabAction2Button.value(action)) - { - setSelectedTab(button); - } - } -} - - -void AppQtMainWidget::onSettingsButtonClicked() -{ - setSelectedTab(mUi->settingsToolButton); - mUi->settingsPage->switchToGuiModule(GuiModule::GENERAL_SETTINGS); -} - - -void AppQtMainWidget::onChangePinButtonClicked() -{ - setSelectedTab(mUi->settingsToolButton); - mUi->settingsPage->switchToGuiModule(GuiModule::PIN_SETTINGS); -} - - -void AppQtMainWidget::onQuestionActionClicked() -{ - QString link = tr("https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/"); - QDesktopServices::openUrl(QUrl(link)); -} - - -void AppQtMainWidget::onSendErrorActionClicked() -{ - QString link = tr("https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/"); - QDesktopServices::openUrl(QUrl(link)); -} - - -void AppQtMainWidget::onEvaluateActionClicked() -{ - QString link = tr("https://www.ausweisapp.bund.de/en/feedback/bewerten-sie-uns/"); - QDesktopServices::openUrl(QUrl(link)); -} - - -void AppQtMainWidget::onContentActionClicked() -{ - QString name = mUi->stackedWidget->widget(mUi->stackedWidget->currentIndex())->objectName(); - if (name.startsWith(QLatin1String("settingsPage"))) - { - SettingsWidget* settingsWidget = static_cast(mUi->stackedWidget->widget(mUi->stackedWidget->currentIndex())); - HelpAction::openContextHelp(settingsWidget->getActiveTabObjectName()); - } - else - { - HelpAction::openContextHelp(name); - } -} - - -void AppQtMainWidget::onAboutActionClicked() -{ - AboutDialog* dialog = new AboutDialog(this); - dialog->show(); -} - - -void AppQtMainWidget::activateMenuBarItems(bool pEnable) -{ - mUi->actionAusweisen->setEnabled(pEnable); - mUi->actionProvider->setEnabled(pEnable); - mUi->actionHistory->setEnabled(pEnable); - mUi->actionSettings->setEnabled(pEnable); - mUi->actionChangePin->setEnabled(pEnable); - mUi->actionSetupAssistant->setEnabled(pEnable); -} - - -bool AppQtMainWidget::isRemindUserToClose() -{ - return AppSettings::getInstance().getGeneralSettings().isRemindUserToClose(); -} diff --git a/src/gui/AppQtMainWidget.h b/src/gui/AppQtMainWidget.h deleted file mode 100644 index 8c5b78e..0000000 --- a/src/gui/AppQtMainWidget.h +++ /dev/null @@ -1,122 +0,0 @@ -/*! - * \brief Main class for the top level main widget - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "context/ChangePinContext.h" -#include "generic/GuiModule.h" -#include "LogFilesDialog.h" -#include "workflow/WorkflowWidgetParent.h" - -namespace Ui -{ -class AppQtMainWidget; -} - -namespace governikus -{ - -class WorkflowQtWidget; - -class AppQtMainWidget - : public QMainWindow -{ - Q_OBJECT - - public: - AppQtMainWidget(); - virtual ~AppQtMainWidget(); - - void workflowActivated(WorkflowWidgetParent pParent, const QString& pName); - void workflowDeactivated(); - - void switchToGuiModule(GuiModule pModule); - - void switchToPinSettingsAfterWorkflow(); - - bool isHideWindowAfterWorkflow() const - { - return mHideWindowAfterWorkflow; - } - - - void setHideWindowAfterWorkflow(bool pHide) - { - mHideWindowAfterWorkflow = pHide; - } - - - void activateMenuBarItems(bool pEnable); - - WorkflowQtWidget* getAuthenticationWorkflowWidget() const - { - return mAuthenticationWorkflowWidget; - } - - - bool isRemindUserToClose(); - - void setSelectedTab(QAbstractButton* pSelectedPushButton); - - void activateWindow(); - - protected: - virtual void closeEvent(QCloseEvent* pEvent); - virtual void keyPressEvent(QKeyEvent* keyEvent); - virtual void changeEvent(QEvent* event); - - private: - static void updateGeometryRecursively(QWidget* pWidget, QSet& pVisitedObjects); - static void updateGeometryRecursively(QLayout* pLayout, QSet& pVisitedObjects); - - private Q_SLOTS: - void onSettingsDone(); - - void onOpenLoggingFileButtonClicked(); - void onSaveLoggingFileButtonClicked(); - void onTabButtonToggled(QAbstractButton* pButton, bool pChecked); - void onTabActionTriggered(); - void onAboutActionClicked(); - void onSendErrorActionClicked(); - void onEvaluateActionClicked(); - void onQuestionActionClicked(); - void onContentActionClicked(); - - public Q_SLOTS: - void onSettingsButtonClicked(); - void onChangePinButtonClicked(); - - Q_SIGNALS: - void fireSetupAssistantWizardRequest(); - void fireChangePinRequested(); - void fireDiagnosisRequested(); - void fireReaderDriverRequested(); - void fireCloseWindowRequested(bool* pDoClose); - void fireSelfAuthenticationRequested(); - void fireQuitApplicationRequested(); - void fireChangeHighContrast(bool* pHighContrastOn); - - private: - QScopedPointer mUi; - QMap mTabButton2Page; - QMap mTabAction2Button; - WorkflowQtWidget* mAuthenticationWorkflowWidget; - QAbstractButton* mSelectedPushButton; - QAbstractButton* mSelectedPushButtonBeforeWorkflow; - QVector mSelectedPagesBeforeWorkflow; - bool mHideWindowAfterWorkflow; - QPointer mLogFilesDialog; - QString mStyleSheet; -}; - -} /* namespace governikus */ diff --git a/src/gui/AppQtMainWidget.ui b/src/gui/AppQtMainWidget.ui deleted file mode 100644 index ee8691f..0000000 --- a/src/gui/AppQtMainWidget.ui +++ /dev/null @@ -1,729 +0,0 @@ - - - AppQtMainWidget - - - - 0 - 0 - 840 - 600 - - - - Qt::NoContextMenu - - - AusweisApp2 - - - - :/images/npa.svg:/images/npa.svg - - - - 64 - 64 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 10 - - - - - 16777215 - 10 - - - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Actions - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Welcome - - - true - - - true - - - - - - - - 0 - 0 - - - - margin-top: 21px; - - - Identify - - - - 32 - 32 - - - - true - - - false - - - Qt::ToolButtonTextBesideIcon - - - - - - - - 0 - 0 - - - - Provider - - - - 32 - 32 - - - - true - - - 300 - - - 100 - - - Qt::ToolButtonTextBesideIcon - - - - - - - - 0 - 0 - - - - History - - - - 32 - 32 - - - - true - - - Qt::ToolButtonTextBesideIcon - - - - - - - - 0 - 0 - - - - Settings - - - - 32 - 32 - - - - true - - - Qt::ToolButtonTextBesideIcon - - - - - - - 0 - - - 15 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 40 - - - - - - - - - - - - 1 - 0 - - - - 0 - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::StrongFocus - - - nPA and eAT Logo - - - :/images/start_nPA_eAT.png - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::StrongFocus - - - AusweisApp2 Logo - - - :/images/AppLogo_AutentApp2_2014.png - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - true - - - - - - - - 0 - - - 6 - - - 6 - - - 6 - - - 6 - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - :/images/Logo_AutentApp2_2014.png - - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 170 - - - - - - - - - - 0 - 0 - 840 - 21 - - - - true - - - - Fi&le - - - - - - - - - - - &Help - - - - - - - - - - - - - - - - - - &PIN Management - - - - - - - - - - Minimise - - - - - &Exit - - - QAction::QuitRole - - - - - &Identify - - - - - &Settings - - - - - &Manual - - - - - &Evaluate - - - - - &Report error - - - - - &About AusweisApp2 - - - QAction::AboutRole - - - - - &Provider - - - - - S&how log - - - - - Save &log - - - - - &Questions - - - - - &History - - - - - &Change PIN - - - - - &Setup assistant - - - QAction::NoRole - - - - - &Diagnosis - - - - - - governikus::TabButtonGroup - QWidget -
generic/TabButtonGroup.h
- 1 -
- - governikus::SettingsWidget - QWidget -
SettingsWidget.h
- 1 -
- - governikus::ProviderWidget - QWidget -
ProviderWidget.h
- 1 -
- - governikus::SelfInformationWidget - QWidget -
SelfInformationWidget.h
- 1 -
- - governikus::HistoryWidget - QWidget -
HistoryWidget.h
- 1 -
- - governikus::DeveloperModeHistoryWidget - QWidget -
DeveloperModeHistoryWidget.h
- 1 -
- - governikus::TabButton - QToolButton -
generic/TabButtonGroup.h
-
-
- - startPushButton - appLogoLabel - appLabel - ausweisenToolButton - providerToolButton - historyToolButton - settingsToolButton - - - - - -
diff --git a/src/gui/AppStartPage.cpp b/src/gui/AppStartPage.cpp deleted file mode 100644 index 20ebe1c..0000000 --- a/src/gui/AppStartPage.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * AppStartPage.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AppStartPage.h" - -#include "generic/LayoutBuilder.h" -#include "generic/TabButtonGroup.h" -#include "GuiProfile.h" -#include "ui_AppStartPage.h" - -#include -#include - -using namespace governikus; - -AppStartPage::AppStartPage(QWidget* pParent) - : Page(QStringLiteral(" "), pParent) - , mApplicationLogoLabel(new QLabel(this)) - , mUi(new Ui::AppStartPage()) -{ - mUi->setupUi(this); - - QPixmap applicationPixmap(QStringLiteral(":/images/AppLogo_AutentApp2_2014.png")); - QPixmap nPAeATPixmap(QStringLiteral(":/images/start_nPA_eAT.png")); - - if (GuiProfile::getProfile().isSmallScreen()) - { - mUi->applicationLogoLabel->setPixmap(applicationPixmap.scaledToWidth(186, Qt::SmoothTransformation)); - mUi->nPAeATLabel->setPixmap(nPAeATPixmap.scaledToWidth(186, Qt::SmoothTransformation)); - } - else - { - // assume we have enough space - mUi->applicationLogoLabel->setPixmap(applicationPixmap); - mUi->nPAeATLabel->setPixmap(nPAeATPixmap); - } -} - - -AppStartPage::~AppStartPage() -{ -} - - -void AppStartPage::paintEvent(QPaintEvent* /*pPaintEvent*/) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/AppStartPage.h b/src/gui/AppStartPage.h deleted file mode 100644 index bc111fc..0000000 --- a/src/gui/AppStartPage.h +++ /dev/null @@ -1,49 +0,0 @@ -/*! - * AppStartPage.h - * - * \brief Main page widget. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -#include -#include - -namespace Ui -{ -class AppStartPage; -} - -class QAbstractButton; - -namespace governikus -{ - -class TabButton; - -class AppStartPage - : public Page -{ - Q_OBJECT - - public: - AppStartPage(QWidget* pParent = nullptr); - virtual ~AppStartPage(); - - Q_SIGNALS: - void selfInfoPageRequested(); - void bookmarksPageRequested(); - void settingsPageRequested(); - - private: - QLabel* mApplicationLogoLabel; - QScopedPointer mUi; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt deleted file mode 100644 index 2b679d2..0000000 --- a/src/gui/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -ADD_PLATFORM_LIBRARY(AusweisAppWidget) - -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/CredentialDialog.cpp b/src/gui/CredentialDialog.cpp deleted file mode 100644 index 2a794b1..0000000 --- a/src/gui/CredentialDialog.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "CredentialDialog.h" -#include "ui_CredentialDialog.h" - -using namespace governikus; - -CredentialDialog::CredentialDialog(QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::CredentialDialog) -{ - mUi->setupUi(this); - - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Proxy security")); - - connect(mUi->buttonBox, &QDialogButtonBox::accepted, this, &CredentialDialog::accept); - connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &CredentialDialog::reject); -} - - -CredentialDialog::~CredentialDialog() -{ - delete mUi; -} - - -void CredentialDialog::setUser(const QString& pUser) -{ - if (!pUser.isEmpty()) - { - mUi->user->setText(pUser); - mUi->password->setFocus(); - mUi->password->setCursorPosition(0); - } -} - - -QString CredentialDialog::getUser() const -{ - return mUi->user->text(); -} - - -QString CredentialDialog::getPassword() const -{ - return mUi->password->text(); -} diff --git a/src/gui/CredentialDialog.h b/src/gui/CredentialDialog.h deleted file mode 100644 index 015557c..0000000 --- a/src/gui/CredentialDialog.h +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -namespace Ui -{ -class CredentialDialog; -} - -#include - -namespace governikus -{ - -class CredentialDialog - : public QDialog -{ - Q_OBJECT - - private: - Ui::CredentialDialog* mUi; - - public: - explicit CredentialDialog(QWidget* pParent = nullptr); - ~CredentialDialog(); - - void setUser(const QString& pUser); - - QString getUser() const; - - QString getPassword() const; - - -}; - -} /* namespace governikus */ diff --git a/src/gui/DeleteHistoryDialog.cpp b/src/gui/DeleteHistoryDialog.cpp deleted file mode 100644 index a07f5d7..0000000 --- a/src/gui/DeleteHistoryDialog.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "DeleteHistoryDialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - - -DeleteHistoryDialog::DeleteHistoryDialog(QWidget* pParent) - : QDialog(pParent) -{ - setObjectName(QStringLiteral("DeleteHistoryDialog")); - - setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Delete history")); - setLayout(new QVBoxLayout(this)); - setMinimumSize(300, -1); - - layout()->setObjectName(QStringLiteral("dialogLayout")); - - QLabel* groupBoxLabel = new QLabel(this); - groupBoxLabel->setText(tr("Delete history for this period:")); - groupBoxLabel->setWordWrap(true); - layout()->addWidget(groupBoxLabel); - - mComboBox = new QComboBox(this); - layout()->addWidget(mComboBox); - mComboBox->addItem(tr("Past hour"), (int) TimePeriod::PAST_HOUR); - mComboBox->addItem(tr("Past day"), (int) TimePeriod::PAST_DAY); - mComboBox->addItem(tr("Past week"), (int) TimePeriod::PAST_WEEK); - mComboBox->addItem(tr("Last four weeks"), (int) TimePeriod::LAST_FOUR_WEEKS); - mComboBox->addItem(tr("All history"), (int) TimePeriod::ALL_HISTORY); - - QSpacerItem* verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); - layout()->addItem(verticalSpacer); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - layout()->addWidget(buttonBox); - connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - - -QRadioButton* DeleteHistoryDialog::createRadioButtonAndAppendToGroup(const QString& pText, TimePeriod pTimePeriod) -{ - QRadioButton* button = new QRadioButton(this); - button->setText(pText); - button->setProperty("TimePeriod", Enum::getValue(pTimePeriod)); - button->setObjectName(QStringLiteral("button%1").arg(QString::number(mRadioButtonGroup->buttons().count()))); - mRadioButtonGroup->addButton(button); - return button; -} - - -TimePeriod DeleteHistoryDialog::getTimePeriod() -{ - return TimePeriod(mComboBox->currentData().toInt()); -} diff --git a/src/gui/DeleteHistoryDialog.h b/src/gui/DeleteHistoryDialog.h deleted file mode 100644 index 5f4222d..0000000 --- a/src/gui/DeleteHistoryDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "EnumHelper.h" - -#include -#include -#include -#include -#include - -namespace governikus -{ - -defineEnumType(TimePeriod, - PAST_HOUR, - PAST_DAY, - PAST_WEEK, - LAST_FOUR_WEEKS, - ALL_HISTORY - ) - -class DeleteHistoryDialog - : public QDialog -{ - Q_OBJECT - QPointer mRadioButtonGroup; - QPointer mComboBox; - - QRadioButton* createRadioButtonAndAppendToGroup(const QString& pText, TimePeriod pTimePeriod); - - public: - explicit DeleteHistoryDialog(QWidget* pParent = nullptr); - TimePeriod getTimePeriod(); -}; - -} /* namespace governikus */ diff --git a/src/gui/DetailDialog.cpp b/src/gui/DetailDialog.cpp deleted file mode 100644 index 899d81e..0000000 --- a/src/gui/DetailDialog.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * DetailDialog.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ -#include "DetailDialog.h" -#include "DetailWidget.h" -#include "generic/HelpAction.h" -#include "ui_DetailDialog.h" -#include - -using namespace governikus; - -DetailDialog::DetailDialog(QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::DetailDialog) -{ - mUi->setupUi(this); - - setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Service provider data")); - - installEventFilter(this); - - connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &DetailDialog::close); -} - - -DetailDialog::~DetailDialog() -{ - delete mUi; -} - - -void DetailDialog::setDetails(const QString& pDetails) -{ - mUi->detailWidget->setDetails(pDetails); - adjustSize(); -} - - -bool DetailDialog::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QDialog::eventFilter(pObject, pEvent); -} diff --git a/src/gui/DetailDialog.h b/src/gui/DetailDialog.h deleted file mode 100644 index 0967210..0000000 --- a/src/gui/DetailDialog.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * DetailDialog.h - * - * \brief Detail dialog for certificate description - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -namespace Ui -{ -class DetailDialog; -} - -namespace governikus -{ - -class DetailDialog - : public QDialog -{ - Q_OBJECT - - private: - Ui::DetailDialog* mUi; - - public: - explicit DetailDialog(QWidget* pParent = nullptr); - ~DetailDialog(); - - void setDetails(const QString& pDetails); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - -}; - -} /* namespace governikus */ diff --git a/src/gui/DetailWidget.cpp b/src/gui/DetailWidget.cpp deleted file mode 100644 index 2dd9d75..0000000 --- a/src/gui/DetailWidget.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * DetailWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "DetailWidget.h" -#include "ui_DetailWidget.h" -#include - -using namespace governikus; - -DetailWidget::DetailWidget(QWidget* pParent) - : Page(tr("Details"), pParent) - , mUi(new Ui::DetailWidget()) -{ - mUi->setupUi(this); - - // The scroll area may be resized while the content keeps its - // size, therefore the scroll area must have the same background - // color as the content. - mUi->scrollArea->setStyleSheet("QScrollArea { background-color: white; }" - "" - "QScrollBar {" - " background-color: #f8f6f4;" - "}"); - mUi->scrollAreaWidgetContents->setStyleSheet("border-width: 0;"); - mUi->detailText->setStyleSheet("border-width: 0;"); -} - - -DetailWidget::~DetailWidget() -{ -} - - -void DetailWidget::setDetails(const QString& pDetails) -{ - mUi->detailText->setAccessibleName(tr("Service provider details dialog") + pDetails); - mUi->detailText->setText(pDetails); -} - - -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; - - if (mUi->detailText->width() > contentMaxWidth) - { - mUi->detailText->setFixedWidth(contentMaxWidth); - } - - mUi->scrollAreaWidgetContents->setFixedHeight(mUi->detailText->height()); - mUi->scrollAreaWidgetContents->setFixedWidth(mUi->detailText->width()); - - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/DetailWidget.h b/src/gui/DetailWidget.h deleted file mode 100644 index 6764077..0000000 --- a/src/gui/DetailWidget.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * DetailWidget.h - * - * \brief Widget for cvc description. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -#include "generic/Page.h" - -namespace Ui -{ -class DetailWidget; -} - -namespace governikus -{ - -class DetailWidget - : public Page -{ - Q_OBJECT - - public: - DetailWidget(QWidget* pParent = nullptr); - virtual ~DetailWidget(); - - void setDetails(const QString& pDetails); - - private: - QScopedPointer mUi; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/DetailWidget.ui b/src/gui/DetailWidget.ui deleted file mode 100644 index c28cc0a..0000000 --- a/src/gui/DetailWidget.ui +++ /dev/null @@ -1,117 +0,0 @@ - - - DetailWidget - - - - 0 - 0 - 595 - 450 - - - - true - - - Qt::WheelFocus - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QLayout::SetMaximumSize - - - - - false - - - - - 0 - 0 - 591 - 446 - - - - - 0 - 0 - - - - - - 0 - 0 - 9 - 17 - - - - - QLayout::SetFixedSize - - - 0 - - - - - - 0 - 0 - - - - true - - - Qt::TabFocus - - - 0 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/DeveloperModeHistoryWidget.cpp b/src/gui/DeveloperModeHistoryWidget.cpp deleted file mode 100644 index fe7519f..0000000 --- a/src/gui/DeveloperModeHistoryWidget.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "AppSettings.h" -#include "DeveloperModeHistoryWidget.h" -#include "LogHandler.h" -#include "ui_DeveloperModeHistoryWidget.h" - -#include - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(developermode) - - -DeveloperModeHistoryWidget::DeveloperModeHistoryWidget(QWidget* pParent) - : QWidget(pParent) - , mUi(new Ui::DeveloperModeHistoryWidget()) -{ - mUi->setupUi(this); - - connect(&AppSettings::getInstance(), &AppSettings::fireSettingsChanged, this, &DeveloperModeHistoryWidget::onSettingsChanged); - connect(&LogHandler::getInstance(), &LogHandler::fireRawLog, this, &DeveloperModeHistoryWidget::onRawLog); - connect(mUi->btnDisableDeveloperMode, &QPushButton::clicked, this, &DeveloperModeHistoryWidget::onDisableDeveloperMode); - - // initialize visibility state - onSettingsChanged(); -} - - -DeveloperModeHistoryWidget::~DeveloperModeHistoryWidget() -{ -} - - -void DeveloperModeHistoryWidget::appendLoggingDump(const QString& pLog) -{ - QString formatted = pLog; - - // Remove outer quotation - if (formatted.startsWith("\"") && formatted.endsWith("\"")) - { - formatted = formatted.mid(1, formatted.length() - 2); - } - - mUi->plainTextEdit->appendHtml(QStringLiteral("
%1
").arg(formatted)); -} - - -void DeveloperModeHistoryWidget::onRawLog(const QString& pMsg, const QString& pCategoryName) -{ - static const QString categoryDevMode = QString::fromLatin1(developermode().categoryName()); - if (pCategoryName == categoryDevMode) - { - appendLoggingDump(pMsg); - } -} - - -void DeveloperModeHistoryWidget::onSettingsChanged() -{ - QWidget::setVisible(AppSettings::getInstance().getGeneralSettings().isDeveloperMode()); -} - - -void DeveloperModeHistoryWidget::onDisableDeveloperMode() -{ - AppSettings::getInstance().getGeneralSettings().setDeveloperMode(false); - AppSettings::getInstance().getGeneralSettings().save(); -} diff --git a/src/gui/DeveloperModeHistoryWidget.h b/src/gui/DeveloperModeHistoryWidget.h deleted file mode 100644 index cb9031a..0000000 --- a/src/gui/DeveloperModeHistoryWidget.h +++ /dev/null @@ -1,44 +0,0 @@ -/*! - * DeveloperModeHistoryWidget.h - * - * \brief A Widget to display developer mode errors which occurred - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ -#pragma once - -#include - - -namespace Ui -{ -class DeveloperModeHistoryWidget; -} - - -namespace governikus -{ - -class DeveloperModeHistoryWidget - : public QWidget -{ - Q_OBJECT - - public: - explicit DeveloperModeHistoryWidget(QWidget* pParent = nullptr); - virtual ~DeveloperModeHistoryWidget(); - - public Q_SLOTS: - void onRawLog(const QString& pMsg, const QString& pCategoryName); - void onSettingsChanged(); - - private: - QScopedPointer mUi; - - void appendLoggingDump(const QString& pLog); - - private Q_SLOTS: - void onDisableDeveloperMode(); -}; - -} /* namespace governikus */ diff --git a/src/gui/DeveloperModeHistoryWidget.ui b/src/gui/DeveloperModeHistoryWidget.ui deleted file mode 100644 index dc895d5..0000000 --- a/src/gui/DeveloperModeHistoryWidget.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - DeveloperModeHistoryWidget - - - - 0 - 0 - 599 - 248 - - - - - 0 - 0 - - - - - 0 - - - 6 - - - 0 - - - 0 - - - - - 6 - - - 6 - - - - - - 0 - 0 - - - - Qt::TabFocus - - - <html><head/><body><p align="center"><span style=" font-size:12pt; color:#ff0000;">Developer Mode: Enabled!</span></p></body></html> - - - true - - - - - - - Disable - - - - - - - - - - 0 - 0 - - - - QPlainTextEdit::NoWrap - - - true - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
- 1 -
-
- - -
diff --git a/src/gui/DiagnosisDialog.cpp b/src/gui/DiagnosisDialog.cpp deleted file mode 100644 index 90f6b11..0000000 --- a/src/gui/DiagnosisDialog.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*! - * DiagnosisDialog.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "DiagnosisDialog.h" -#include "generic/HelpAction.h" -#include "ui_DiagnosisDialog.h" - -#include -#include -#include -#include - -using namespace governikus; - - -DiagnosisDialog::DiagnosisDialog(DiagnosisContext* pContext, QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::DiagnosisDialog) - , mDiagnosisWidget(new DiagnosisWidget(pContext, pParent)) -{ - mUi->setupUi(this); - - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Diagnosis")); - - installEventFilter(this); - - mUi->diagnosisLayout->addWidget(mDiagnosisWidget); - - connect(mUi->saveButton, &QAbstractButton::clicked, this, &DiagnosisDialog::onSaveButtonClicked); - connect(mUi->closeButton, &QAbstractButton::clicked, this, &DiagnosisDialog::close); -} - - -DiagnosisDialog::~DiagnosisDialog() -{ -} - - -void DiagnosisDialog::onSaveButtonClicked() -{ - - QString fileName = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save diagnosis result"), QDir::homePath() + tr("/AusweisApp2-diagnosis.txt"), - tr("Text files (*.txt)")); - - - if (fileName.isEmpty()) - { - return; - } - if (!fileName.endsWith(QStringLiteral(".txt"), Qt::CaseSensitivity::CaseInsensitive)) - { - fileName += QStringLiteral(".txt"); - } - - QString text = mDiagnosisWidget->getInfoTextEdit(); -#ifdef Q_OS_WIN - text.replace(QLatin1Char('\n'), QStringLiteral("\r\n")); -#endif - - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QFile::Truncate) || file.write(text.toUtf8()) < 0) - { - QMessageBox::warning(this, QCoreApplication::applicationName() + " - " + tr("File error"), tr("An error occurred while saving the file.")); - } -} - - -bool DiagnosisDialog::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QDialog::eventFilter(pObject, pEvent); -} diff --git a/src/gui/DiagnosisDialog.h b/src/gui/DiagnosisDialog.h deleted file mode 100644 index 0d139ba..0000000 --- a/src/gui/DiagnosisDialog.h +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * DiagnosisDialog.h - * - * \brief Dialog for display the diagnosis information. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/DiagnosisContext.h" -#include "DiagnosisWidget.h" - -#include -#include - -namespace Ui -{ -class DiagnosisDialog; -} - -namespace governikus -{ - -class DiagnosisDialog - : public QDialog -{ - Q_OBJECT - - public: - DiagnosisDialog(DiagnosisContext* pContext, QWidget* pParent = nullptr); - virtual ~DiagnosisDialog(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - QScopedPointer mUi; - DiagnosisWidget* mDiagnosisWidget; - - private Q_SLOTS: - void onSaveButtonClicked(); -}; - -} /* namespace governikus */ diff --git a/src/gui/DiagnosisGui.cpp b/src/gui/DiagnosisGui.cpp deleted file mode 100644 index 3720688..0000000 --- a/src/gui/DiagnosisGui.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "DiagnosisGui.h" -#include "DiagnosisWidget.h" - -using namespace governikus; - -DiagnosisGui::DiagnosisGui(QWidget* pParentWidget) - : QObject(pParentWidget) - , mDialog() -{ -} - - -DiagnosisGui::~DiagnosisGui() -{ -} - - -void DiagnosisGui::activate() -{ - if (mDialog) - { - if (mDialog->isMinimized()) - { - mDialog->showNormal(); - } - if (!mDialog->isVisible()) - { - mDialog->show(); - } - mDialog->activateWindow(); - mDialog->raise(); - return; - } - - QWidget* dialogParent = qobject_cast(parent()); - if (!dialogParent) - { - return; - } - - auto context = new DiagnosisContext(); - mDialog = new DiagnosisDialog(context, dialogParent); - connect(mDialog, &QDialog::finished, this, &DiagnosisGui::fireFinished); - mDialog->show(); - - auto controller = new DiagnosisController(context, mDialog); - controller->run(); -} - - -void DiagnosisGui::deactivate() -{ - if (mDialog) - { - mDialog->close(); - } -} diff --git a/src/gui/DiagnosisGui.h b/src/gui/DiagnosisGui.h deleted file mode 100644 index 2a80ef3..0000000 --- a/src/gui/DiagnosisGui.h +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * \brief Qt widget based DiagnosisUi implementation. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/DiagnosisContext.h" -#include "controller/DiagnosisController.h" -#include "DiagnosisDialog.h" - -#include -#include - -namespace governikus -{ - -class DiagnosisGui - : public QObject -{ - Q_OBJECT - - public: - DiagnosisGui(QWidget* pParentWidget); - virtual ~DiagnosisGui(); - - void activate(); - void deactivate(); - - Q_SIGNALS: - void fireFinished(); - - private: - QPointer mDialog; -}; - -} /* namespace governikus */ diff --git a/src/gui/DiagnosisWidget.cpp b/src/gui/DiagnosisWidget.cpp deleted file mode 100644 index dc8a219..0000000 --- a/src/gui/DiagnosisWidget.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/*! - * DiagnosisWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "DiagnosisWidget.h" -#include "ui_DiagnosisWidget.h" - -#include -#include -#include -#include -#include -#include - -// Includes for version API -#include - -#include "BuildHelper.h" -#include "context/DiagnosisContext.h" -#include "generic/HelpAction.h" - -using namespace governikus; - -class DiagnosisWidget::Field -{ - public: - Field(QTextCursor& pCursor, const QString& pHeading, const QTextCharFormat& pPlainFormat, const QTextCharFormat& pHeadingFormat) - : mStart() - , mEnd() - { - pCursor.insertText(pHeading + QLatin1Char('\n'), pHeadingFormat); - mStart = pCursor; - mStart.setKeepPositionOnInsert(true); - pCursor.insertText(tr("Diagnosis is running..."), pPlainFormat); - mEnd = pCursor; - mEnd.setKeepPositionOnInsert(true); - pCursor.insertText(QStringLiteral("\n"), pPlainFormat); - } - - - void prepareSet() - { - mEnd.setKeepPositionOnInsert(false); - mEnd.clearSelection(); - mEnd.setPosition(mStart.position(), QTextCursor::KeepAnchor); - } - - - void finishSet() - { - mEnd.setKeepPositionOnInsert(true); - } - - - const QTextCursor& getCursor() const - { - return mEnd; - } - - - void setText(const QString& pText, const QTextCharFormat& pPlainFormat) - { - prepareSet(); - mEnd.insertText(pText, pPlainFormat); - finishSet(); - } - - - void setFragment(const QTextDocumentFragment& pFragment) - { - prepareSet(); - mEnd.insertFragment(pFragment); - finishSet(); - } - - - private: - QTextCursor mStart; - QTextCursor mEnd; -}; - -DiagnosisWidget::DiagnosisWidget(DiagnosisContext* pContext, QWidget* pParent) - : Page(tr("Diagnosis"), pParent) - , mUi(new Ui::DiagnosisWidget) - , mContext(pContext) - , mOsField() - , mAppVersionField() - , mPcscField() - , mReadersField() - , mTimestampField() - , mPlainTextFormat() - , mHeadingTextFormat() - , mBasicBlockFormat() - , mOsVersionTreeItem(nullptr) - , mAppVersionTreeItem(nullptr) - , mReadersTreeItem(nullptr) - , mPcscTreeItem(nullptr) - , mReaderWaitItem(nullptr) - , mPcscWaitItem(nullptr) - , mTimestampItem(nullptr) -{ - mUi->setupUi(this); - - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Diagnosis")); - - QTextCursor insertCursor(mUi->infoTextEdit->document()); - mPlainTextFormat = insertCursor.charFormat(); - mHeadingTextFormat = mPlainTextFormat; - mHeadingTextFormat.setFontWeight(QFont::Bold); - mBasicBlockFormat = insertCursor.blockFormat(); - - mOsField.reset(insertField(insertCursor, tr("Operating system"), true)); - mAppVersionField.reset(insertField(insertCursor, QCoreApplication::applicationName() + " - Version")); - mReadersField.reset(insertField(insertCursor, tr("Card reader"))); - mPcscField.reset(insertField(insertCursor, tr("PC/SC"))); - mTimestampField.reset(insertField(insertCursor, tr("Time of diagnosis"))); - - mOsVersionTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); - mOsVersionTreeItem->setText(0, tr("Operating system")); - mOsVersionTreeItem->setExpanded(true); - - (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::prettyProductName()); - (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::kernelVersion()); - (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::currentCpuArchitecture()); - - QStringList fields; - fields << QSysInfo::prettyProductName(); - fields << QSysInfo::kernelVersion(); - fields << QSysInfo::currentCpuArchitecture(); - setFieldText(mOsField, fields.join(QLatin1Char('\n'))); - - mPcscWaitItem = new QTreeWidgetItem(mPcscTreeItem); - mPcscWaitItem->setText(0, tr("Diagnosis is running...")); - - mAppVersionTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); - mAppVersionTreeItem->setText(0, QCoreApplication::applicationName() + " - Version"); - mAppVersionTreeItem->setExpanded(true); - - mReadersTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); - mReadersTreeItem->setText(0, tr("Card reader")); - mReadersTreeItem->setExpanded(true); - mReaderWaitItem = new QTreeWidgetItem(mReadersTreeItem); - mReaderWaitItem->setText(0, tr("Diagnosis is running...")); - - mPcscTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); - mPcscTreeItem->setText(0, tr("PC/SC")); - mPcscTreeItem->setExpanded(true); - mPcscWaitItem = new QTreeWidgetItem(mPcscTreeItem); - mPcscWaitItem->setText(0, tr("Diagnosis is running...")); - - mTimestampItem = new QTreeWidgetItem(mUi->infoTreeWidget); - mTimestampItem->setExpanded(true); - 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)) - }); - for (const auto& str : appVersion) - { - (new QTreeWidgetItem(mAppVersionTreeItem))->setText(0, str); - } - setFieldText(mAppVersionField, appVersion.join(QLatin1Char('\n'))); - - connect(mContext, &DiagnosisContext::pcscInfoChanged, this, &DiagnosisWidget::onPcscInfoChanged); - connect(mContext, &DiagnosisContext::readerInfosChanged, this, &DiagnosisWidget::onReaderInfosChanged); - connect(mContext, &DiagnosisContext::timestampChanged, this, &DiagnosisWidget::onTimestampChanged); - - mUi->infoTextEdit->setVisible(false); -} - - -DiagnosisWidget::~DiagnosisWidget() -{ -} - - -bool DiagnosisWidget::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QWidget::eventFilter(pObject, pEvent); -} - - -void DiagnosisWidget::onPcscInfoChanged() -{ - mPcscTreeItem->removeChild(mPcscWaitItem); - delete mPcscWaitItem; - mPcscWaitItem = nullptr; - - mPcscField->prepareSet(); - - QTextCursor insertCursor = mPcscField->getCursor(); - insertCursor.removeSelectedText(); - - //version - insertCursor.insertText(tr("Version: %1").arg(mContext->getPcscVersion()), mPlainTextFormat); - endBlockAndResetFormat(insertCursor); - (new QTreeWidgetItem(mPcscTreeItem))->setText(0, tr("Version: %1").arg(mContext->getPcscVersion())); - - //components - QTreeWidgetItem* componentTreeItem = new QTreeWidgetItem(mPcscTreeItem); - componentTreeItem->setText(0, tr("Components")); - insertComponentList(insertCursor, tr("Components:"), mContext->getPcscComponents(), componentTreeItem); - - //driver - QTreeWidgetItem* driverTreeItem = new QTreeWidgetItem(mPcscTreeItem); - driverTreeItem->setText(0, tr("Driver")); - insertComponentList(insertCursor, tr("Driver:"), mContext->getPcscDrivers(), driverTreeItem); - - mPcscField->finishSet(); - -} - - -void DiagnosisWidget::onReaderInfosChanged() -{ - mReadersTreeItem->removeChild(mReaderWaitItem); - delete mReaderWaitItem; - mReaderWaitItem = nullptr; - - const QVector& infos = mContext->getReaderInfos(); - if (infos.isEmpty()) - { - setFieldText(mReadersField, tr("not recognised")); - (new QTreeWidgetItem(mReadersTreeItem))->setText(0, tr("not recognised")); - return; - } - - mReadersField->prepareSet(); - - QTextCursor insertCursor = mReadersField->getCursor(); - insertCursor.removeSelectedText(); - QTextListFormat listFormat; - listFormat.setStyle(QTextListFormat::ListDisc); - QTextList* list = insertCursor.insertList(listFormat); - - bool isFirst = true; - for (const ReaderInfo& info : infos) - { - if (isFirst) - { - isFirst = false; - } - else - { - insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - } - - // Reset the indent. Otherwise each list element would be indented further. - QTextBlockFormat blockFormat = insertCursor.blockFormat(); - blockFormat.setIndent(0); - insertCursor.setBlockFormat(blockFormat); - - // reader name - insertCursor.insertText(info.getName(), mPlainTextFormat); - list->add(insertCursor.block()); - QTreeWidgetItem* readerTreeItem = new QTreeWidgetItem(mReadersTreeItem); - readerTreeItem->setText(0, info.getName()); - - insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - list->remove(insertCursor.block()); - - // reader type - QString readerType = info.isBasicReader() ? tr("Basic card reader") : tr("Standard / deluxe card reader"); - insertCursor.insertText(tr("Type: %1").arg(readerType), mPlainTextFormat); - (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Type: %1").arg(readerType)); - - // card type - QString cardType; - switch (info.getCardType()) - { - case CardType::NONE: - cardType = tr("not inserted", "Karte"); - break; - - case CardType::UNKNOWN: - cardType = tr("unknown type", "Karte"); - break; - - case CardType::EID_CARD: - cardType = tr("ID card (PA/eAT)"); - break; - - } - - insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - insertCursor.insertText(tr("Card: %1").arg(cardType), mPlainTextFormat); - (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Card: %1").arg(cardType)); - - - // retry counter - if (info.getCardType() == CardType::EID_CARD) - { - insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - insertCursor.insertText(tr("Retry counter: %1").arg(3 - info.getRetryCounter()), mPlainTextFormat); - (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Retry counter: %1").arg(3 - info.getRetryCounter())); - } - } - - mReadersField->finishSet(); -} - - -void DiagnosisWidget::onTimestampChanged() -{ - QString timestamp = mContext->getTimestamp().toString(tr("MMMM dd yyyy, hh:mm:ss AP")); - setFieldText(mTimestampField, timestamp); - (new QTreeWidgetItem(mTimestampItem))->setText(0, timestamp); - -} - - -QString DiagnosisWidget::getInfoTextEdit() -{ - return mUi->infoTextEdit->toPlainText(); -} - - -DiagnosisWidget::Field* DiagnosisWidget::insertField(QTextCursor& pCursor, const QString& pHeading, bool pIsFirstField) -{ - if (!pIsFirstField) - { - pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - } - - return new Field(pCursor, pHeading, mPlainTextFormat, mHeadingTextFormat); -} - - -void DiagnosisWidget::setFieldText(const QScopedPointer& pField, const QString& pText) -{ - pField->setText(pText, mPlainTextFormat); -} - - -void DiagnosisWidget::endBlockAndResetFormat(QTextCursor& pCursor) -{ - pCursor.insertText(QStringLiteral("\n")); - pCursor.setBlockFormat(mBasicBlockFormat); -} - - -void DiagnosisWidget::insertComponentList(QTextCursor& pCursor, const QString& pTitle, - const QVector& pComponents, QTreeWidgetItem* pParentTreeWidgetItem) -{ - if (pComponents.isEmpty()) - { - return; - } - - pCursor.insertText(pTitle, mPlainTextFormat); - - QTextListFormat listFormat; - listFormat.setStyle(QTextListFormat::ListDisc); - QTextList* list = pCursor.insertList(listFormat); - - bool isFirst = true; - for (const DiagnosisContext::ComponentInfo& info : pComponents) - { - if (isFirst) - { - isFirst = false; - } - else - { - pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - } - - // Reset the indent. Otherwise each list element would be indented further. - QTextBlockFormat blockFormat = pCursor.blockFormat(); - blockFormat.setIndent(0); - pCursor.setBlockFormat(blockFormat); - - // description - pCursor.insertText(info.getDescription(), mPlainTextFormat); - QTreeWidgetItem* descriptionTreeItem = new QTreeWidgetItem(pParentTreeWidgetItem); - descriptionTreeItem->setText(0, info.getDescription()); - - list->add(pCursor.block()); - - pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - list->remove(pCursor.block()); - - // company - pCursor.insertText(tr("Vendor: %1").arg(info.getManufacturer()), mPlainTextFormat); - (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("Vendor: %1").arg(info.getManufacturer())); - - // version - pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - pCursor.insertText(tr("Version: %1").arg(info.getVersion()), mPlainTextFormat); - (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("Version: %1").arg(info.getVersion())); - - // path - pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); - pCursor.insertText(tr("File path: %1").arg(info.getPath()), mPlainTextFormat); - (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("File path: %1").arg(info.getPath())); - } - - endBlockAndResetFormat(pCursor); -} diff --git a/src/gui/DiagnosisWidget.h b/src/gui/DiagnosisWidget.h deleted file mode 100644 index 9d6ec20..0000000 --- a/src/gui/DiagnosisWidget.h +++ /dev/null @@ -1,82 +0,0 @@ -/*! - * DiagnosisWidget.h - * - * \brief Widget for display the diagnosis information. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include -#include - -#include "context/DiagnosisContext.h" -#include "generic/Page.h" - -namespace Ui -{ -class DiagnosisWidget; -} - -class QTextCursor; - -namespace governikus -{ - -class DiagnosisWidget - : public Page -{ - Q_OBJECT - - public: - DiagnosisWidget(DiagnosisContext* pContext, QWidget* pParent = nullptr); - virtual ~DiagnosisWidget(); - - QString getInfoTextEdit(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - class Field; - - private Q_SLOTS: - void onPcscInfoChanged(); - void onReaderInfosChanged(); - void onTimestampChanged(); - - private: - Field* insertField(QTextCursor& pCursor, const QString& pHeading, bool pIsFirstField = false); - void setFieldText(const QScopedPointer& pField, const QString& pText); - - void endBlockAndResetFormat(QTextCursor& pCursor); - void insertComponentList(QTextCursor& pCursor, const QString& pTitle, - const QVector& pComponents, QTreeWidgetItem* pParentTreeWidgetItem); - - void deleteItem(QTreeWidgetItem* pItem); - - private: - QScopedPointer mUi; - DiagnosisContext* mContext; - QScopedPointer mOsField; - QScopedPointer mAppVersionField; - QScopedPointer mPcscField; - QScopedPointer mReadersField; - QScopedPointer mTimestampField; - QTextCharFormat mPlainTextFormat; - QTextCharFormat mHeadingTextFormat; - QTextBlockFormat mBasicBlockFormat; - - QTreeWidgetItem* mOsVersionTreeItem; - QTreeWidgetItem* mAppVersionTreeItem; - QTreeWidgetItem* mReadersTreeItem; - QTreeWidgetItem* mPcscTreeItem; - QTreeWidgetItem* mReaderWaitItem; - QTreeWidgetItem* mPcscWaitItem; - QTreeWidgetItem* mTimestampItem; -}; - -} /* namespace governikus */ diff --git a/src/gui/GeneralSettingsWidget.cpp b/src/gui/GeneralSettingsWidget.cpp deleted file mode 100644 index 612c642..0000000 --- a/src/gui/GeneralSettingsWidget.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "GeneralSettingsWidget.h" - -#include "AppSettings.h" -#include "ui_GeneralSettingsWidget.h" -#include "UpdateWindow.h" - -using namespace governikus; - -GeneralSettingsWidget::GeneralSettingsWidget(QWidget* pParent) - : Page(tr("General"), pParent) - , mUi(new Ui::GeneralSettingsWidget()) -{ - mUi->setupUi(this); - - reset(); - - connect(mUi->autostartCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - connect(mUi->regularlyUpdateCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - connect(mUi->closeWindowCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - connect(mUi->safeHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - connect(mUi->updateCheckButton, &QCheckBox::clicked, this, &GeneralSettingsWidget::onUpdateCheckButtonClicked); - connect(mUi->keylessPasswordCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); -} - - -GeneralSettingsWidget::~GeneralSettingsWidget() -{ -} - - -void GeneralSettingsWidget::showEvent(QShowEvent* pEvent) -{ - disconnect(mUi->safeHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - mUi->safeHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); - connect(mUi->safeHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); - - QWidget::showEvent(pEvent); -} - - -void GeneralSettingsWidget::apply() -{ - AppSettings::getInstance().getHistorySettings().setEnabled(mUi->safeHistoryCheckBox->isChecked()); - AppSettings::getInstance().getHistorySettings().save(); - - auto& generalSettings = AppSettings::getInstance().getGeneralSettings(); - generalSettings.setAutoCloseWindowAfterAuthentication(mUi->closeWindowCheckBox->isChecked()); - generalSettings.setAutoStart(mUi->autostartCheckBox->isChecked()); - generalSettings.setAutoUpdateCheck(mUi->regularlyUpdateCheckBox->isChecked()); - generalSettings.setUseScreenKeyboard(mUi->keylessPasswordCheckBox->isChecked()); - generalSettings.save(); -} - - -void GeneralSettingsWidget::reset() -{ - mUi->safeHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); - - const auto& generalSettings = AppSettings::getInstance().getGeneralSettings(); - mUi->closeWindowCheckBox->setChecked(generalSettings.isAutoCloseWindowAfterAuthentication()); - mUi->autostartCheckBox->setChecked(generalSettings.isAutoStart()); - mUi->regularlyUpdateCheckBox->setChecked(generalSettings.isAutoUpdateCheck()); - mUi->keylessPasswordCheckBox->setChecked(generalSettings.isUseScreenKeyboard()); -} - - -void GeneralSettingsWidget::onCheckBoxStateChanged(int) -{ - Q_EMIT settingsChanged(); -} - - -void GeneralSettingsWidget::onUpdateCheckButtonClicked() -{ - new UpdateWindow(false, this); -} diff --git a/src/gui/GeneralSettingsWidget.h b/src/gui/GeneralSettingsWidget.h deleted file mode 100644 index 9a7d765..0000000 --- a/src/gui/GeneralSettingsWidget.h +++ /dev/null @@ -1,46 +0,0 @@ -/*! - * \brief Widget for the general settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -#include -#include - -namespace Ui -{ -class GeneralSettingsWidget; -} - -namespace governikus -{ - -class GeneralSettingsWidget - : public Page -{ - Q_OBJECT - - public: - GeneralSettingsWidget(QWidget* pParent = nullptr); - virtual ~GeneralSettingsWidget(); - - void apply(); - void reset(); - - Q_SIGNALS: - void settingsChanged(); - - private Q_SLOTS: - void onCheckBoxStateChanged(int pState); - void onUpdateCheckButtonClicked(); - void showEvent(QShowEvent*); - - private: - QScopedPointer mUi; -}; - -} /* namespace governikus */ diff --git a/src/gui/GeneralSettingsWidget.ui b/src/gui/GeneralSettingsWidget.ui deleted file mode 100644 index cbe1a8a..0000000 --- a/src/gui/GeneralSettingsWidget.ui +++ /dev/null @@ -1,217 +0,0 @@ - - - GeneralSettingsWidget - - - - 0 - 0 - 431 - 206 - - - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - Qt::TabFocus - - - Software update: - - - - - - - true - - - check software update on program start - - - check on program start - - - true - - - - - - - true - - - - 0 - 0 - - - - search for updates - - - - - - - Qt::Horizontal - - - - - - - Qt::TabFocus - - - History: - - - - - - - save history - - - save - - - - - - - Qt::Horizontal - - - - - - - - 50 - false - - - - Qt::TabFocus - - - Start AusweisApp2 automatically: - - - - - - - Start AusweisApp2 automatically on system startup - - - on system start - - - - - - - Qt::Horizontal - - - - - - - Qt::TabFocus - - - Close AusweisApp2 window automatically: - - - safeHistoryCheckBox - - - - - - - Close AusweisApp2 window automatically after successful identification - - - after successful identification - - - - - - - Qt::Horizontal - - - - - - - Qt::TabFocus - - - On screen password: - - - keylessPasswordCheckBox - - - - - - - use on screen password - - - use - - - - - - - - - - Qt::Vertical - - - - 20 - 2 - - - - - - - - - diff --git a/src/gui/GuiProfile.cpp b/src/gui/GuiProfile.cpp deleted file mode 100644 index b069f8f..0000000 --- a/src/gui/GuiProfile.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*! - * GuiProfile.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "GuiProfile.h" - -using namespace governikus; - -GuiProfile GuiProfile::mProfile; - -GuiProfile::GuiProfile() - : mScreenSize(ScreenSize::SMALL) - , mShowWindow(false) - , mShowMainTabs(true) - , mWindowSize() - , mDebugStyleSheet() -{ -} - - -GuiProfile::~GuiProfile() -{ -} - - -ScreenSize GuiProfile::getScreenSize() const -{ - return mScreenSize; -} - - -void GuiProfile::setScreenSize(ScreenSize pScreenSize) -{ - mScreenSize = pScreenSize; -} - - -bool GuiProfile::isSmallScreen() const -{ - return mScreenSize == ScreenSize::SMALL ? true : false; -} - - -bool GuiProfile::isMediumScreen() const -{ - return mScreenSize == ScreenSize::MEDIUM ? true : false; -} - - -bool GuiProfile::isLargeScreen() const -{ - return mScreenSize == ScreenSize::LARGE ? true : false; -} - - -bool GuiProfile::getShowWindow() const -{ - return mShowWindow; -} - - -void GuiProfile::setShowWindow(bool pShow) -{ - mShowWindow = pShow; -} - - -bool GuiProfile::getShowMainTabs() const -{ - return mShowMainTabs; -} - - -void GuiProfile::setShowMainTabs(bool pShow) -{ - mShowMainTabs = pShow; -} - - -QSize GuiProfile::getWindowSize() const -{ - return mWindowSize; -} - - -void GuiProfile::setWindowSize(QSize pWindowSize) -{ - mWindowSize = pWindowSize; -} - - -const QString& GuiProfile::getDebugStyleSheet() const -{ - return mDebugStyleSheet; -} - - -void GuiProfile::setDebugStyleSheet(const QString& pStyleSheet) -{ - mDebugStyleSheet = pStyleSheet; -} - - -QLatin1String GuiProfile::getStyleSheetName() -{ -#if defined(Q_OS_OSX) - return QLatin1String("macos.qss"); - -#else - return QLatin1String("windows.qss"); - -#endif -} diff --git a/src/gui/GuiProfile.h b/src/gui/GuiProfile.h deleted file mode 100644 index 3d71a9e..0000000 --- a/src/gui/GuiProfile.h +++ /dev/null @@ -1,65 +0,0 @@ -/*! - * GuiProfile.h - * - * \brief Singleton GuiProfile specifies platform specific customizations the - * GUI. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "EnumHelper.h" - -#include -#include - -namespace governikus -{ - -defineEnumType(ScreenSize, - SMALL, MEDIUM, LARGE - ) - -class GuiProfile -{ - public: - GuiProfile(); - ~GuiProfile(); - - private: - static GuiProfile mProfile; - - ScreenSize mScreenSize; - bool mShowWindow; - bool mShowMainTabs; - QSize mWindowSize; - QString mDebugStyleSheet; - - public: - static GuiProfile& getProfile() - { - return mProfile; - } - - - ScreenSize getScreenSize() const; - QSize getWindowSize() const; - - void setDebugStyleSheet(const QString& pStyleSheet); - void setScreenSize(ScreenSize pScreenSize); - void setShowMainTabs(bool pShow); - void setShowWindow(bool pShow); - void setWindowSize(QSize pWindowSize); - - bool isSmallScreen() const; - bool isMediumScreen() const; - bool isLargeScreen() const; - - bool getShowWindow() const; - bool getShowMainTabs() const; - const QString& getDebugStyleSheet() const; - QLatin1String getStyleSheetName(); -}; - -} /* namespace governikus */ diff --git a/src/gui/HistoryDetailWidget.cpp b/src/gui/HistoryDetailWidget.cpp deleted file mode 100644 index c200eec..0000000 --- a/src/gui/HistoryDetailWidget.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "HistoryDetailWidget.h" -#include "ui_HistoryDetailWidget.h" - -#include - -using namespace governikus; - - -HistoryDetailWidget::HistoryDetailWidget(QWidget* pParent) - : Page(tr("History details"), pParent) - , mUi(new Ui::HistoryDetailWidget()) -{ - mUi->setupUi(this); -} - - -HistoryDetailWidget::~HistoryDetailWidget() -{ -} - - -void HistoryDetailWidget::setDetails(const QString& pDetails) -{ - mUi->detailText->setText(pDetails); -} - - -void HistoryDetailWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/HistoryDetailWidget.h b/src/gui/HistoryDetailWidget.h deleted file mode 100644 index 529f9fa..0000000 --- a/src/gui/HistoryDetailWidget.h +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * \brief Widget for history item. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -#include - -namespace Ui -{ -class HistoryDetailWidget; -} - -namespace governikus -{ - -class HistoryDetailWidget - : public Page -{ - Q_OBJECT - - public: - HistoryDetailWidget(QWidget* pParent = nullptr); - virtual ~HistoryDetailWidget(); - - void setDetails(const QString& pDetails); - - private: - QScopedPointer mUi; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/HistoryDetailWidget.ui b/src/gui/HistoryDetailWidget.ui deleted file mode 100644 index a67f872..0000000 --- a/src/gui/HistoryDetailWidget.ui +++ /dev/null @@ -1,58 +0,0 @@ - - - HistoryDetailWidget - - - - 0 - 0 - 595 - 450 - - - - Qt::TabFocus - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Qt::TabFocus - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/HistoryWidget.cpp b/src/gui/HistoryWidget.cpp deleted file mode 100644 index 003ed2c..0000000 --- a/src/gui/HistoryWidget.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "HistoryWidget.h" - -#include "DeleteHistoryDialog.h" -#include "generic/ListCheckItemWidget.h" -#include "generic/ListItem.h" -#include "generic/ListItemIconLeft.h" -#include "generic/ListItemIconRight.h" -#include "generic/ListItemSubTitle.h" -#include "generic/ListItemTitle.h" -#include "PdfCreator.h" -#include "ui_HistoryWidget.h" - -#include -#include -#include - - -using namespace governikus; - - -HistoryWidget::HistoryWidget(QWidget* pParent) - : Page(tr("History"), pParent) - , mUi(new Ui::HistoryWidget()) - , mHistoryDetailWidget(nullptr) -{ - mUi->setupUi(this); - - connect(mUi->historyDeleteButton, &QPushButton::clicked, this, &HistoryWidget::deleteHistory); - connect(mUi->historySearch, &QLineEdit::textChanged, this, &HistoryWidget::searchHistory); - connect(mUi->historyExportButton, &QPushButton::clicked, this, &HistoryWidget::exportHistory); - connect(mUi->saveHistoryCheckBox, &QCheckBox::stateChanged, this, &HistoryWidget::onCheckBoxStateChanged); - mUi->saveHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); - - init(); -} - - -HistoryWidget::~HistoryWidget() -{ -} - - -void HistoryWidget::init() -{ - QStringList header; - header += tr("Date"); - header += tr("Details"); - - mUi->historyTableWidget->setColumnCount(header.count()); - mUi->historyTableWidget->setHorizontalHeaderLabels(header); - mUi->historyTableWidget->verticalHeader()->setVisible(false); //Hide row number - mUi->historyTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //Not allowed to change content - mUi->historyTableWidget->setSortingEnabled(false); - - connect(mUi->historyTableWidget, &QTableWidget::doubleClicked, this, &HistoryWidget::onItemClicked); - - mUi->historyTableWidget->installEventFilter(this); - - mUi->noResultWidget->setVisible(false); -} - - -QWidget* HistoryWidget::getDetailActivatingWidget() const -{ - return mUi->historyTableWidget; -} - - -void HistoryWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -void HistoryWidget::showEvent(QShowEvent* pEvent) -{ - HistorySettings& settings = AppSettings::getInstance().getHistorySettings(); - updateTable(settings.getHistoryEntries()); - mUi->saveHistoryCheckBox->setChecked(settings.isEnabled()); - - QWidget::showEvent(pEvent); -} - - -void HistoryWidget::onCheckBoxStateChanged(int /*pState*/) -{ - AppSettings::getInstance().getHistorySettings().setEnabled(mUi->saveHistoryCheckBox->isChecked()); - AppSettings::getInstance().getHistorySettings().save(); -} - - -void HistoryWidget::updateTable(const QVector& pItems) -{ - mUi->historyTableWidget->clearContents(); - mUi->historyTableWidget->setRowCount(0); - - for (const HistoryEntry& entry : pItems) - { - int rowIndex = mUi->historyTableWidget->rowCount(); - mUi->historyTableWidget->insertRow(rowIndex); - - //date column with needed properties - 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(tr("MM/dd/yyyy hh:mm AP"))); - - dateLabel->setFocusPolicy(Qt::TabFocus); - dateLabel->setAccessibleName(tr("Date:") + entry.getDateTime().toString(tr("MM/dd/yyyy hh:mm AP"))); - - mUi->historyTableWidget->setCellWidget(rowIndex, 0, dateLabel); - - //details column with needed properties - QWidget* centralWidget = new QWidget(); - - QFormLayout* centralLayout = new QFormLayout(centralWidget); - centralLayout->setSpacing(6); - centralLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - - QLabel* providerLabel = new QLabel(tr("Provider:")); - providerLabel->setFocusPolicy(Qt::TabFocus); - centralLayout->setWidget(0, QFormLayout::LabelRole, providerLabel); - - QLabel* providerField = new QLabel(entry.getSubjectName()); - providerField->setFocusPolicy(Qt::TabFocus); - centralLayout->setWidget(0, QFormLayout::FieldRole, providerField); - - centralWidget->setProperty("provider", entry.getSubjectName()); - - QLabel* purposeLabel = new QLabel(tr("Purpose:")); - purposeLabel->setFocusPolicy(Qt::TabFocus); - centralLayout->setWidget(1, QFormLayout::LabelRole, purposeLabel); - - QLabel* purposeField = new QLabel(entry.getPurpose()); - purposeField->setFocusPolicy(Qt::TabFocus); - centralLayout->setWidget(1, QFormLayout::FieldRole, purposeField); - - centralWidget->setProperty("usage", entry.getPurpose()); - - QLabel* dataLabel = new QLabel(tr("Data:")); - dataLabel->setFocusPolicy(Qt::TabFocus); - dataLabel->setAlignment(Qt::AlignTop); - centralLayout->setWidget(2, QFormLayout::LabelRole, dataLabel); - - QLabel* requestedDataLabel = new QLabel(entry.getRequestedData().trimmed()); - requestedDataLabel->setWordWrap(true); - requestedDataLabel->setFocusPolicy(Qt::TabFocus); - centralLayout->setWidget(2, QFormLayout::FieldRole, requestedDataLabel); - - centralWidget->setProperty("requestedData", entry.getRequestedData()); - - mUi->historyTableWidget->setCellWidget(rowIndex, 1, centralWidget); - } - - mUi->historyTableWidget->resizeRowsToContents(); - mUi->historyTableWidget->sortByColumn(dateColumn); // Sort by date -} - - -bool HistoryWidget::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - 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) - { - QWidget* tmpWidget = qobject_cast(mUi->historyTableWidget->cellWidget(index.row(), dateColumn)); - DetailDialog d(this); - d.setDetails(tmpWidget->property("termsOfUsage").toString()); - d.exec(); - } - return true; - } - } - - return QWidget::eventFilter(pObject, pEvent); -} - - -void HistoryWidget::deleteHistory() -{ - DeleteHistoryDialog* deleteHistoryDialog = new DeleteHistoryDialog(this); - if (deleteHistoryDialog->exec() == QDialog::Rejected) - { - return; - } - - QDateTime latestToKeep = QDateTime::currentDateTime(); - switch (deleteHistoryDialog->getTimePeriod()) - { - case TimePeriod::PAST_HOUR: - latestToKeep = latestToKeep.addSecs(-60 * 60); - break; - - case TimePeriod::PAST_DAY: - latestToKeep = latestToKeep.addDays(-1); - break; - - case TimePeriod::PAST_WEEK: - latestToKeep = latestToKeep.addDays(-7); - break; - - case TimePeriod::LAST_FOUR_WEEKS: - latestToKeep = latestToKeep.addDays(-7 * 4); - break; - - case TimePeriod::ALL_HISTORY: - latestToKeep = QDateTime(); - break; - } - - HistorySettings& settings = AppSettings::getInstance().getHistorySettings(); - settings.deleteSettings(latestToKeep); - settings.save(); - updateTable(settings.getHistoryEntries()); -} - - -void HistoryWidget::exportHistory() -{ - QString pdfName = QFileDialog::getSaveFileName(this, - QApplication::applicationName() + " - " + tr("Save history"), - QDir::currentPath(), - tr("PDF Documents (*.pdf)")); - - PdfExport::exportHistory(pdfName); -} - - -void HistoryWidget::searchHistory() -{ - mUi->historyTableWidget->setVisible(true); - mUi->noResultWidget->setVisible(false); - - bool anyMatch = false; - - for (int i = 0; i < mUi->historyTableWidget->rowCount(); ++i) - { - bool match = false; - for (int j = 0; j < mUi->historyTableWidget->columnCount(); ++j) - { - QString tmpData; - QWidget* tmpWidget = qobject_cast(mUi->historyTableWidget->cellWidget(i, j)); - if (j == dateColumn) - { - tmpData = tmpWidget->property("date").toString(); - } - else - { - tmpData = tmpWidget->property("provider").toString() + " " + tmpWidget->property("usage").toString() + " " + tmpWidget->property("requestedData").toString(); - } - - if (tmpData.contains(mUi->historySearch->text(), Qt::CaseInsensitive)) - { - match = true; - anyMatch = true; - break; - } - } - mUi->historyTableWidget->setRowHidden(i, !match); - - } - - mUi->historyTableWidget->setVisible(anyMatch); - mUi->noResultWidget->setVisible(!anyMatch); -} - - -void HistoryWidget::onItemClicked(const QModelIndex& pIndex) -{ - QModelIndex idx = pIndex; - - qDebug() << "selected model index: " << idx; - - if (pIndex.isValid()) - { - QWidget* tmpWidget = qobject_cast(mUi->historyTableWidget->cellWidget(idx.row(), dateColumn)); - DetailDialog d(this); - d.setDetails(tmpWidget->property("termsOfUsage").toString()); - d.exec(); - } -} diff --git a/src/gui/HistoryWidget.h b/src/gui/HistoryWidget.h deleted file mode 100644 index 533fac3..0000000 --- a/src/gui/HistoryWidget.h +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppSettings.h" -#include "DetailDialog.h" -#include "generic/ListCheckItemWidget.h" -#include "generic/Page.h" -#include "HistoryDetailWidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Ui -{ -class HistoryWidget; -} - -namespace governikus -{ - -class ProviderDetailWidget; - -class HistoryWidget - : public Page -{ - Q_OBJECT - - public: - HistoryWidget(QWidget* pParent = nullptr); - virtual ~HistoryWidget(); - - QWidget* getDetailActivatingWidget() const; - - public Q_SLOTS: - virtual void showEvent(QShowEvent*) override; - void onCheckBoxStateChanged(int pState); - void deleteHistory(); - void exportHistory(); - void searchHistory(); - void onItemClicked(const QModelIndex& pIndex); - - private: - private: - static const int dateColumn = 0; - - QScopedPointer mUi; - HistoryDetailWidget* mHistoryDetailWidget; - - private: - virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; - virtual void paintEvent(QPaintEvent*) override; - void updateTable(const QVector& pItems); - void init(); -}; - -} /* namespace governikus */ diff --git a/src/gui/HistoryWidget.ui b/src/gui/HistoryWidget.ui deleted file mode 100644 index 9cbcc8f..0000000 --- a/src/gui/HistoryWidget.ui +++ /dev/null @@ -1,210 +0,0 @@ - - - HistoryWidget - - - - 0 - 0 - 599 - 666 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Qt::TabFocus - - - 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. - - - true - - - - - - - - - Qt::TabFocus - - - Search: - - - - - - - Please enter your search - - - - - - Please enter your search - - - - - - - - - - - - QAbstractScrollArea::AdjustToContents - - - false - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectItems - - - QAbstractItemView::ScrollPerPixel - - - QAbstractItemView::ScrollPerPixel - - - true - - - 150 - - - false - - - true - - - - - - - - 5 - - - - - No matching history entries were found. Please modify your search criteria. - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - Qt::TabFocus - - - save history: - - - History: - - - - - - - save history - - - - - - save - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Delete history... - - - - - - - save history as PDF - - - Save as PDF... - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/HistoryWidgetQml.cpp b/src/gui/HistoryWidgetQml.cpp deleted file mode 100644 index 17efad2..0000000 --- a/src/gui/HistoryWidgetQml.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 423973f..0000000 --- a/src/gui/HistoryWidgetQml.h +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * \brief A history widget which embeds QML - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppSettings.h" -#include "DetailDialog.h" -#include "generic/Page.h" -#include "HistoryModel.h" -#include "QmlExtension.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 deleted file mode 100644 index 7ea7b99..0000000 --- a/src/gui/HistoryWidgetQml.ui +++ /dev/null @@ -1,48 +0,0 @@ - - - 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 deleted file mode 100644 index d7d27d2..0000000 --- a/src/gui/LogFilesDialog.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/*! - * LogFilesDialog.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "LogFilesDialog.h" -#include "ui_LogFilesDialog.h" - -#include "generic/HelpAction.h" -#include "LogHandler.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - - -LogFilesDialog::LogFilesDialog(QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::LogFilesDialog) -{ - mUi->setupUi(this); - - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinMaxButtonsHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Log")); - - connect(mUi->saveButton, &QAbstractButton::clicked, this, &LogFilesDialog::onSaveButtonClicked); - connect(mUi->deleteButton, &QAbstractButton::clicked, this, &LogFilesDialog::onDeleteButtonClicked); - connect(mUi->closeButton, &QAbstractButton::clicked, this, &LogFilesDialog::close); - - init(); -} - - -LogFilesDialog::~LogFilesDialog() -{ -} - - -void LogFilesDialog::init() -{ - mUi->logFilesComboBox->clear(); - - auto model = new QStandardItemModel(this); - mUi->logFilesComboBox->setModel(model); - - const auto& otherLogs = LogHandler::getInstance().getOtherLogfiles(); - QList items; - items.reserve(otherLogs.size() + 1); - items << new QStandardItem(tr("Current log")); - for (const auto& entry : otherLogs) - { - auto date = entry.created(); - auto item = new QStandardItem(date.toString(tr("MM/dd/yyyy hh:mm:ss"))); - item->setData(date, Qt::UserRole); - item->setData(entry.absoluteFilePath()); - items << item; - } - - mUi->logFilesComboBox->setEnabled(!otherLogs.isEmpty()); - mUi->deleteButton->setEnabled(!otherLogs.isEmpty()); - - model->invisibleRootItem()->appendRows(items); - model->setSortRole(Qt::UserRole); - model->sort(0, Qt::DescendingOrder); - - connect(mUi->logFilesComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &LogFilesDialog::onCurrentIndexChanged); - - mUi->plainTextEdit->clear(); - appendLoggingDump(QString::fromUtf8(LogHandler::getInstance().getBacklog()).toHtmlEscaped()); - mUi->plainTextEdit->moveCursor(QTextCursor::Start); - connect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); -} - - -void LogFilesDialog::appendLoggingDump(const QString& pLog) -{ - mUi->plainTextEdit->appendHtml(QStringLiteral("
%1
").arg(pLog)); -} - - -void LogFilesDialog::doLogMsg(const QString& pMsg) -{ - appendLoggingDump(pMsg.toHtmlEscaped()); -} - - -void LogFilesDialog::onCurrentIndexChanged(int pIndex) -{ - mUi->plainTextEdit->clear(); - if (pIndex == 0) - { - connect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); - - appendLoggingDump(QString::fromUtf8(LogHandler::getInstance().getBacklog()).toHtmlEscaped()); - mUi->plainTextEdit->moveCursor(QTextCursor::Start); - } - else - { - disconnect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); - - QFile file(mUi->logFilesComboBox->itemData(pIndex, Qt::UserRole + 1).toString()); - if (file.size() < 3145728) - { - if (file.open(QIODevice::ReadOnly)) - { - appendLoggingDump(QString::fromUtf8(file.readAll())); - } - else - { - appendLoggingDump(tr("File could not be opened: ") + file.fileName()); - } - } - else - { - appendLoggingDump(tr("File is larger than 3 MB and can not be displayed: ") + file.fileName()); - } - } -} - - -void LogFilesDialog::onDeleteButtonClicked() -{ - QMessageBox::StandardButton reply = QMessageBox::question(this, tr("Delete log files"), tr("Do you really want to delete all old log files?"), QMessageBox::Yes | QMessageBox::No); - if (reply == QMessageBox::Yes) - { - LogHandler::getInstance().removeOtherLogfiles(); - init(); - } -} - - -void LogFilesDialog::onSaveButtonClicked() -{ - QString fileName = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + " - " + tr("Save log file"), QDir::homePath() + tr("/AusweisApp2-logfile.log"), - tr("Text files (*.txt)")); - - if (fileName.isEmpty()) - { - return; - } - if (!fileName.endsWith(QLatin1String(".txt"), Qt::CaseSensitivity::CaseInsensitive)) - { - fileName += QLatin1String(".txt"); - } - - QString text = mUi->plainTextEdit->toPlainText(); - #ifdef Q_OS_WIN - text.replace(QLatin1Char('\n'), QStringLiteral("\r\n")); - #endif - - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QFile::Truncate) || file.write(text.toUtf8()) < 0) - { - QMessageBox::warning(this, QCoreApplication::applicationName() + " - " + tr("File error"), tr("An error occurred while saving the file.")); - } -} - - -bool LogFilesDialog::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QDialog::eventFilter(pObject, pEvent); -} diff --git a/src/gui/LogFilesDialog.h b/src/gui/LogFilesDialog.h deleted file mode 100644 index 8e0c18b..0000000 --- a/src/gui/LogFilesDialog.h +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * LogFilesDialog.h - * - * \brief Dialog for display the old log files. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class LogFilesDialog; -} - -namespace governikus -{ - -class LogFilesDialog - : public QDialog -{ - Q_OBJECT - - public: - LogFilesDialog(QWidget* pParent = nullptr); - virtual ~LogFilesDialog(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - QScopedPointer mUi; - - void init(); - void appendLoggingDump(const QString& pLog); - - private Q_SLOTS: - void doLogMsg(const QString& pMsg); - void onSaveButtonClicked(); - void onCurrentIndexChanged(int pIndex); - void onDeleteButtonClicked(); -}; - -} /* namespace governikus */ diff --git a/src/gui/MainPage.cpp b/src/gui/MainPage.cpp deleted file mode 100644 index 5152d56..0000000 --- a/src/gui/MainPage.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/*! - * MainPage.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "MainPage.h" - -#include -#include - -#include "generic/LayoutBuilder.h" -#include "generic/TabButtonGroup.h" -#include "GuiProfile.h" - -using namespace governikus; - -MainPage::MainPage(QWidget* pParent) - : Page(QCoreApplication::applicationName(), pParent) - , mSelfInfoButton(new TabButton) - , mBookmarksButton(new TabButton) - , mHistoryButton(new TabButton) - , mSettingsButton(new TabButton) -{ - setObjectName(QStringLiteral("MainPage")); - - setSideNavigationPage(true); - - TabButtonGroup* mainNavigationGroup = new TabButtonGroup; - mainNavigationGroup->setObjectName(QStringLiteral("mainNavigationGroup")); - if (GuiProfile::getProfile().isSmallScreen()) - { - LayoutBuilder::HBox<>(mainNavigationGroup, 0, 0); - } - else - { - LayoutBuilder::VBox<>(mainNavigationGroup, 0, 0); - } - - LayoutBuilder::VBox<>(this, 0, 0).add(mainNavigationGroup); - - struct ButtonInfo - { - QToolButton* mButton; - const char* mOnIcon; - const char* mOffIcon; - QString mText; - }; - - ButtonInfo buttonInfos[] = { - {mSelfInfoButton, ":/images/bt_1b.svg", ":/images/bt_1b.svg", tr("Identify")}, - {mBookmarksButton, ":/images/bt_2b.svg", ":/images/bt_2b.svg", tr("Provider")}, - {mHistoryButton, ":/images/bt_3b.svg", ":/images/bt_3b.svg", tr("History")}, - {mSettingsButton, ":/images/bt_4b.svg", ":/images/bt_4b.svg", tr("Settings")} - }; - - for (size_t i = 0; i < sizeof(buttonInfos) / sizeof(buttonInfos[0]); ++i) - { - const ButtonInfo& buttonInfo = buttonInfos[i]; - mainNavigationGroup->layout()->addWidget(buttonInfo.mButton); - mainNavigationGroup->addButton(buttonInfo.mButton); - - buttonInfo.mButton->setText(buttonInfo.mText); - buttonInfo.mButton->setCheckable(true); - - if (GuiProfile::getProfile().isSmallScreen()) - { - buttonInfo.mButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - } - else - { - buttonInfo.mButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - } - - QIcon icon; - icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOnIcon)), QIcon::Normal, QIcon::Off); - icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOffIcon)), QIcon::Normal, QIcon::On); - buttonInfo.mButton->setIcon(icon); - } -} - - -MainPage::~MainPage() -{ -} - - -void MainPage::setNavigationEnabled(bool pEnabled) -{ - mSelfInfoButton->setEnabled(pEnabled); - mBookmarksButton->setEnabled(pEnabled); - mHistoryButton->setEnabled(pEnabled); - mSettingsButton->setEnabled(pEnabled); -} - - -QAbstractButton* MainPage::getSelfInfoButton() const -{ - return mSelfInfoButton; -} - - -QAbstractButton* MainPage::getHistoryButton() const -{ - return mHistoryButton; -} - - -QAbstractButton* MainPage::getBookmarksButton() const -{ - return mBookmarksButton; -} - - -QAbstractButton* MainPage::getSettingsButton() const -{ - return mSettingsButton; -} - - -void MainPage::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/MainPage.h b/src/gui/MainPage.h deleted file mode 100644 index 12e222d..0000000 --- a/src/gui/MainPage.h +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * MainPage.h - * - * \brief Main page widget. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -class QAbstractButton; - -namespace governikus -{ - -class TabButton; - -class MainPage - : public Page -{ - Q_OBJECT - - public: - MainPage(QWidget* pParent = nullptr); - virtual ~MainPage(); - - void setNavigationEnabled(bool pEnabled); - - QAbstractButton* getSelfInfoButton() const; - QAbstractButton* getBookmarksButton() const; - QAbstractButton* getHistoryButton() const; - QAbstractButton* getSettingsButton() const; - - private: - TabButton* mSelfInfoButton; - TabButton* mBookmarksButton; - TabButton* mHistoryButton; - TabButton* mSettingsButton; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/PinSettingsInfoWidget.cpp b/src/gui/PinSettingsInfoWidget.cpp deleted file mode 100644 index abd19b8..0000000 --- a/src/gui/PinSettingsInfoWidget.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "PinSettingsInfoWidget.h" -#include "ui_PinSettingsInfoWidget.h" - -#include - -using namespace governikus; - - -PinSettingsInfoWidget::PinSettingsInfoWidget(QWidget* pParent) - : Page(tr("Information"), pParent) - , mUi(new Ui::PinSettingsInfoWidget()) -{ - mUi->setupUi(this); -} - - -PinSettingsInfoWidget::~PinSettingsInfoWidget() -{ -} - - -void PinSettingsInfoWidget::setInfoTitle(const QString& pTitle) -{ - mUi->infoTitle->setText(pTitle); -} - - -void PinSettingsInfoWidget::setInfoDescription(const QString& pDescription) -{ - mUi->infoDescription->setText(pDescription); -} - - -void PinSettingsInfoWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/PinSettingsInfoWidget.h b/src/gui/PinSettingsInfoWidget.h deleted file mode 100644 index a4c635b..0000000 --- a/src/gui/PinSettingsInfoWidget.h +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * \brief Widget for PIN settings information. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -#include - -namespace Ui -{ -class PinSettingsInfoWidget; -} - -namespace governikus -{ - -class PinSettingsInfoWidget - : public Page -{ - Q_OBJECT - - public: - PinSettingsInfoWidget(QWidget* pParent = nullptr); - virtual ~PinSettingsInfoWidget(); - - void setInfoTitle(const QString& pTitle); - void setInfoDescription(const QString& pDescription); - - private: - QScopedPointer mUi; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/PinSettingsInfoWidget.ui b/src/gui/PinSettingsInfoWidget.ui deleted file mode 100644 index 0233fcb..0000000 --- a/src/gui/PinSettingsInfoWidget.ui +++ /dev/null @@ -1,87 +0,0 @@ - - - PinSettingsInfoWidget - - - - 0 - 0 - 313 - 96 - - - - - 0 - - - 16 - - - 0 - - - 0 - - - - - - - - 75 - true - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/PinSettingsWidget.cpp b/src/gui/PinSettingsWidget.cpp deleted file mode 100644 index 4f8ee6c..0000000 --- a/src/gui/PinSettingsWidget.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "PinSettingsWidget.h" - -#include "generic/PasswordEdit.h" -#include "generic/SmartCardUtil.h" -#include "RandomPinDialog.h" -#include "ReaderInfo.h" -#include "ReaderManager.h" -#include "SmartCardDefinitions.h" -#include "ui_PinSettingsWidget.h" - -#include -#include -#include - -Q_DECLARE_LOGGING_CATEGORY(gui) - -using namespace governikus; - -PinSettingsWidget::PinSettingsWidget(QWidget* pParent) - : Page(tr("PIN Management"), pParent) - , mUi(new Ui::PinSettingsWidget()) - , mMode(Mode::Normal) - , mRetryCounter(3) - , mPinDeactivated(false) - , mPinSettingsInfoTitle() - , mPinSettingsInfoDescription() - , mRandomPinDialog() -{ - mUi->setupUi(this); - - QRegularExpression onlyNumbersExpression(QStringLiteral("[0-9]*")); - - mUi->canEdit->setFieldWidth(6); - mUi->canEdit->setMaxLength(6); - mUi->canEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); - connect(mUi->canEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onCanTextEdited); - - mUi->oldPinEdit->setFieldWidth(6); - mUi->oldPinEdit->setMaxLength(6); - mUi->oldPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); - connect(mUi->oldPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onOldPinTextEdited); - - mUi->newPinEdit->setFieldWidth(6); - mUi->newPinEdit->setMaxLength(6); - mUi->newPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); - connect(mUi->newPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onNewPinTextEdited); - - mUi->repeatNewPinEdit->setFieldWidth(6); - mUi->repeatNewPinEdit->setMaxLength(6); - mUi->repeatNewPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); - connect(mUi->repeatNewPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onRepeatNewPinTextEdited); - - mUi->pukEdit->setFieldWidth(10); - mUi->pukEdit->setMaxLength(10); - mUi->pukEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); - connect(mUi->pukEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onPukTextEdited); - - mUi->canRandomPinButton->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - mUi->canRandomPinButton->setIconSize(QSize(44, 26)); - connect(mUi->canRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); - - mUi->oldRandomPinButton->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - mUi->oldRandomPinButton->setIconSize(QSize(44, 26)); - connect(mUi->oldRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); - - mUi->newRandomPinButton->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - mUi->newRandomPinButton->setIconSize(QSize(44, 26)); - connect(mUi->newRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); - - mUi->repeatNewRandomPinButton->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - mUi->repeatNewRandomPinButton->setIconSize(QSize(44, 26)); - connect(mUi->repeatNewRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); - - mUi->pukRandomPinButton->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - mUi->pukRandomPinButton->setIconSize(QSize(44, 26)); - connect(mUi->pukRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPukButtonClicked); -} - - -PinSettingsWidget::~PinSettingsWidget() -{ -} - - -void PinSettingsWidget::setInProgress(bool pInProgress) -{ - if (pInProgress) - { - if (mUi->stackedWidget->currentWidget() == mUi->changePinComfortPage) - { - mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortDetailsInProgressPage); - mPinSettingsInfoDescription = mUi->changePinComfortInProgressLabel->text(); - } - else if (mUi->stackedWidget->currentWidget() == mUi->changePinBasicPage) - { - mUi->canEdit->setEnabled(false); - mUi->oldPinEdit->setEnabled(false); - mUi->newPinEdit->setEnabled(false); - mUi->repeatNewPinEdit->setEnabled(false); - mUi->canRandomPinButton->setEnabled(false); - mUi->oldRandomPinButton->setEnabled(false); - mUi->newRandomPinButton->setEnabled(false); - mUi->repeatNewRandomPinButton->setEnabled(false); - } - } -} - - -QString PinSettingsWidget::getCan() const -{ - return mUi->canEdit->text(); -} - - -QString PinSettingsWidget::getPin() const -{ - return mUi->oldPinEdit->text(); -} - - -QString PinSettingsWidget::getPuk() const -{ - return mUi->pukEdit->text(); -} - - -QString PinSettingsWidget::getNewPin() const -{ - return mUi->newPinEdit->text(); -} - - -void PinSettingsWidget::setMode(PinSettingsWidget::Mode pMode) -{ - mMode = pMode; -} - - -QString PinSettingsWidget::getButtonText() const -{ - return mRetryCounter == 0 && !mPinDeactivated ? tr("Enter PUK") : tr("Change PIN"); -} - - -QVector PinSettingsWidget::getReaderWithNPA(const QVector& pReaderInfos) -{ - QVector readersWithNPA; - for (const ReaderInfo& readerInfo : pReaderInfos) - { - if (readerInfo.getCardType() == CardType::EID_CARD) - { - readersWithNPA += readerInfo; - } - } - - return readersWithNPA; -} - - -void PinSettingsWidget::updateReadersWithoutNPA(const QVector& pReaderInfos) -{ - mMode = Mode::Normal; - QVector knownReaderTypes; - QVector knownReaderInfos; - for (const ReaderInfo& readerInfo : pReaderInfos) - { - if (!knownReaderTypes.contains(readerInfo.getReaderType())) - { - knownReaderInfos += readerInfo; - knownReaderTypes += readerInfo.getReaderType(); - } - } - - bool basicReaderPage = false; - if (knownReaderInfos.size() == 1) - { - const ReaderInfo& readerInfo = knownReaderInfos.at(0); - if (readerInfo.isBasicReader()) - { - setupPinBasicPage(readerInfo); - basicReaderPage = true; - } - else - { - QPixmap pixmap(SmartCardUtil::getReaderEmptyIconPath(readerInfo.getReaderType())); - mUi->noNpaLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - } - } - else - { - QPixmap pixmap(SmartCardUtil::getMultipleReaderIconPath()); - mUi->noNpaLabel->setPixmap(pixmap.scaledToWidth(250, Qt::SmoothTransformation)); - } - - mUi->headerStackedWidget->setCurrentWidget(mUi->errorNoNpaHeaderPage); - mUi->stackedWidget->setCurrentWidget(basicReaderPage ? mUi->changePinBasicPage : mUi->errorNoNpaPage); -} - - -void PinSettingsWidget::setUseScreenKeyboard(bool pUseScreenKeyboard) -{ - mUi->canRandomPinButton->setVisible(pUseScreenKeyboard); - mUi->oldRandomPinButton->setVisible(pUseScreenKeyboard); - mUi->newRandomPinButton->setVisible(pUseScreenKeyboard); - mUi->repeatNewRandomPinButton->setVisible(pUseScreenKeyboard); - mUi->pukRandomPinButton->setVisible(pUseScreenKeyboard); -} - - -void PinSettingsWidget::fillInfoDescription(const QString& pTitle, const QString& pMessage) -{ - mPinSettingsInfoTitle = pTitle; - mPinSettingsInfoDescription = pMessage; -} - - -bool PinSettingsWidget::updateReadersForOneNPA(const ReaderInfo& pReaderInfo) -{ - mRetryCounter = pReaderInfo.getRetryCounter(); - mPinDeactivated = pReaderInfo.isPinDeactivated(); - - if (mMode == Mode::AfterPinChange) - { - setupPinSuccessfullyChangedPage(pReaderInfo); - mUi->headerStackedWidget->setCurrentWidget(mUi->pinSuccessHeaderPage); - mUi->stackedWidget->setCurrentWidget(mUi->pinSuccessPage); - return true; - } - - if (mPinDeactivated) - { - if (pReaderInfo.isBasicReader()) - { - setupPinBasicPage(pReaderInfo); - mUi->stackedWidget->setCurrentWidget(mUi->changePinBasicPage); - } - else - { - QPixmap pixmap(SmartCardUtil::getReaderIconPath(pReaderInfo.getReaderType())); - mUi->deactivatedReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - mUi->stackedWidget->setCurrentWidget(mUi->errorPinDeactivatedPage); - } - - mUi->headerStackedWidget->setCurrentWidget(mUi->errorPinDeactivatedHeaderPage); - return false; - } - - if (pReaderInfo.isBasicReader()) - { - setupPinBasicPage(pReaderInfo); - mUi->stackedWidget->setCurrentWidget(mUi->changePinBasicPage); - } - else - { - setupPinComfortPage(pReaderInfo); - mUi->stackedWidget->setCurrentWidget(mUi->changePinComfortPage); - } - - return !pReaderInfo.isBasicReader(); -} - - -void PinSettingsWidget::updateReaders() -{ - if (ReaderManager::getInstance().getReaderInfos().isEmpty()) - { - QPixmap pixmap(SmartCardUtil::getNoReaderFoundIconPath()); - mUi->noReaderLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - mUi->headerStackedWidget->setCurrentWidget(mUi->errorNoReaderHeaderPage); - mUi->stackedWidget->setCurrentWidget(mUi->errorNoReaderPage); - return; - } - - QVector readersWithNPA = getReaderWithNPA(ReaderManager::getInstance().getReaderInfos()); - mRetryCounter = 3; - bool enableButton = false; - - if (readersWithNPA.size() == 0) - { - updateReadersWithoutNPA(ReaderManager::getInstance().getReaderInfos()); - } - else if (readersWithNPA.size() == 1) - { - enableButton = updateReadersForOneNPA(readersWithNPA.at(0)); - } - else - { - mMode = Mode::Normal; - QPixmap pixmap(SmartCardUtil::getMultipleReaderIconPath()); - mUi->multipleReaderLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - mUi->headerStackedWidget->setCurrentWidget(mUi->errorMultipleNpasHeaderPage); - mUi->stackedWidget->setCurrentWidget(mUi->errorMultipleNpasPage); - } - - Q_EMIT setChangePinButtonEnabled(enableButton); -} - - -void PinSettingsWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -void PinSettingsWidget::showEvent(QShowEvent* pEvent) -{ - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &PinSettingsWidget::updateReaders); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &PinSettingsWidget::updateReaders); - - updateReaders(); - Page::showEvent(pEvent); -} - - -void PinSettingsWidget::hideEvent(QHideEvent* pEvent) -{ - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &PinSettingsWidget::updateReaders); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &PinSettingsWidget::updateReaders); - - Page::hideEvent(pEvent); - - // Reset the mode, so that the next time the users sees this widget, it doesn't show the state of the previous - // action. - mMode = Mode::Normal; - - 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. - mRandomPinDialog->reject(); - } -} - - -void PinSettingsWidget::onScanButtonClicked() -{ - ReaderManager::getInstance().startScan(); - QTimer::singleShot(3000, this, &PinSettingsWidget::onScanTimeout); -} - - -void PinSettingsWidget::onScanTimeout() -{ -} - - -void PinSettingsWidget::onUiFinished(const QString& pReaderName) -{ - qDebug() << "Set reader name" << pReaderName; - updateReaders(); -} - - -void PinSettingsWidget::onCanTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mUi->canEdit->getLineEdit()->setText(pText); - } - - if (isCanFieldVisible()) - { - if (mUi->canEdit->text().length() == 6) - { - mUi->oldPinEdit->setEnabled(true); - mUi->oldRandomPinButton->setEnabled(true); - - - if (mUi->canEdit->isLineEditActive()) - { - QTimer::singleShot(300, this, &PinSettingsWidget::focusPIN); - } - } - else - { - mUi->oldPinEdit->setEnabled(false); - mUi->oldRandomPinButton->setEnabled(false); - } - } - else - { - mUi->oldPinEdit->setEnabled(true); - mUi->oldRandomPinButton->setEnabled(true); - QTimer::singleShot(300, this, &PinSettingsWidget::focusPIN); - } - - mUi->oldPinEdit->clear(); - onOldPinTextEdited(); -} - - -void PinSettingsWidget::onOldPinTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mUi->oldPinEdit->getLineEdit()->setText(pText); - } - - bool enable = mUi->oldPinEdit->text().length() >= 5; - mUi->newPinEdit->setEnabled(enable); - mUi->newRandomPinButton->setEnabled(enable); - - if (mUi->oldPinEdit->text().length() == 6) - { - if (mUi->oldPinEdit->isLineEditActive()) - { - mUi->newPinEdit->setFocus(); - mUi->newPinEdit->setCursorPosition(0); - } - } - - mUi->newPinEdit->clear(); - onNewPinTextEdited(); -} - - -void PinSettingsWidget::onNewPinTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mUi->newPinEdit->getLineEdit()->setText(pText); - } - - bool enable = mUi->newPinEdit->text().length() == 6; - mUi->repeatNewPinEdit->setEnabled(enable); - mUi->repeatNewRandomPinButton->setEnabled(enable); - if (mUi->newPinEdit->text().length() == 6) - { - if (mUi->newPinEdit->isLineEditActive()) - { - mUi->repeatNewPinEdit->setFocus(); - mUi->repeatNewPinEdit->setCursorPosition(0); - } - } - - mUi->repeatNewPinEdit->clear(); - onRepeatNewPinTextEdited(); -} - - -void PinSettingsWidget::onRepeatNewPinTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mUi->repeatNewPinEdit->getLineEdit()->setText(pText); - } - - if (!mUi->repeatNewPinEdit->isEnabled() || mUi->newPinEdit->text().startsWith(mUi->repeatNewPinEdit->text())) - { - mUi->repeatNewPinEdit->setDigitFieldInvalid(false, tr("The PIN match.")); - - bool inputOk = mUi->repeatNewPinEdit->text().length() == 6 && mUi->repeatNewPinEdit->text() == mUi->newPinEdit->text(); - Q_EMIT setChangePinButtonEnabled(inputOk); - } - else - { - QString invalidMessage = tr("The PIN in the field \"%1\" does not match the PIN in the field \"%2\".").arg(mUi->repeatNewPinEditLabel->text().replace(QStringLiteral(":"), QLatin1String("")), mUi->newPinEditLabel->text().replace(QStringLiteral(":"), QLatin1String(""))); - mUi->repeatNewPinEdit->setDigitFieldInvalid(true, invalidMessage); - } - -} - - -void PinSettingsWidget::onPukTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mUi->pukEdit->getLineEdit()->setText(pText); - } - Q_EMIT setChangePinButtonEnabled(mUi->pukEdit->text().length() == 10); -} - - -void PinSettingsWidget::setupPinBasicPage(const ReaderInfo& pReaderInfo) -{ - mUi->canEdit->clear(); - mUi->oldPinEdit->clear(); - mUi->newPinEdit->clear(); - mUi->repeatNewPinEdit->clear(); - mUi->pukEdit->clear(); - - bool hasCard = pReaderInfo.getCardType() == CardType::EID_CARD; - - QPixmap pixmap; - if (hasCard) - { - pixmap = SmartCardUtil::getReaderIconPath(pReaderInfo.getReaderType()); - mUi->basicReaderImageLabel->setAccessibleName(tr("card reader icon")); - } - else - { - pixmap = SmartCardUtil::getReaderEmptyIconPath(pReaderInfo.getReaderType()); - mUi->basicReaderImageLabel->setAccessibleName(tr("empty card reader icon")); - } - - mUi->basicReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - - bool canEditVisible = false; - bool pukEditVisible = false; - - if (hasCard) - { - setupChangePinHeader(pReaderInfo.getRetryCounter(), true); - - switch (pReaderInfo.getRetryCounter()) - { - case 0: - pukEditVisible = true; - break; - - case 1: - canEditVisible = true; - break; - - default: - break; - } - } - - if (mPinDeactivated) - { - pukEditVisible = false; - canEditVisible = false; - hasCard = false; - } - - mUi->canEditStackedWidget->setCurrentWidget(canEditVisible ? mUi->canEditPage : mUi->noCanEditPage); - mUi->canEditLabelStackedWidget->setCurrentWidget(canEditVisible ? mUi->canEditLabelPage : mUi->noCanEditLabelPage); - - mUi->basicReaderPukStackedWidget->setCurrentWidget(pukEditVisible ? mUi->basicReaderPukPage : mUi->basicReaderPinPage); - - mUi->canEditLabel->setEnabled(hasCard); - mUi->oldPinEditLabel->setEnabled(hasCard); - mUi->newPinEditLabel->setEnabled(hasCard); - mUi->repeatNewPinEditLabel->setEnabled(hasCard); - mUi->canEdit->setEnabled(hasCard); - mUi->oldPinEdit->setEnabled(hasCard); - mUi->newPinEdit->setEnabled(hasCard); - mUi->repeatNewPinEdit->setEnabled(hasCard); - mUi->canRandomPinButton->setEnabled(hasCard); - mUi->oldRandomPinButton->setEnabled(hasCard); - mUi->newRandomPinButton->setEnabled(hasCard); - mUi->repeatNewRandomPinButton->setEnabled(hasCard); - - if (hasCard) - { - if (isCanFieldVisible()) - { - QTimer::singleShot(300, this, &PinSettingsWidget::focusCAN); - } - else if (pukEditVisible) - { - QTimer::singleShot(300, this, &PinSettingsWidget::focusPUK); - } - - if (!pukEditVisible) - { - onCanTextEdited(); - } - } -} - - -void PinSettingsWidget::focusPUK() -{ - mUi->pukEdit->setFocus(); - mUi->pukEdit->setCursorPosition(0); -} - - -void PinSettingsWidget::focusPIN() -{ - mUi->oldPinEdit->setFocus(); - mUi->oldPinEdit->setCursorPosition(0); -} - - -void PinSettingsWidget::focusCAN() -{ - mUi->canEdit->setFocus(); - mUi->canEdit->setCursorPosition(0); -} - - -void PinSettingsWidget::setupPinComfortPage(const ReaderInfo& pReaderInfo) -{ - QPixmap pixmap(SmartCardUtil::getReaderIconPath(pReaderInfo.getReaderType())); - mUi->comfortReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); - setupChangePinHeader(pReaderInfo.getRetryCounter(), false); - - switch (pReaderInfo.getRetryCounter()) - { - case 0: - mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortPukDetailsPage); - break; - - case 1: - mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortCanDetailsPage); - break; - - default: - mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortDetailsPage); - break; - } -} - - -void PinSettingsWidget::setupPinSuccessfullyChangedPage(const ReaderInfo& pReaderInfo) -{ - QPixmap pixmap(SmartCardUtil::getReaderIconPath(pReaderInfo.getReaderType())); - mUi->pinSuccessReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); -} - - -void PinSettingsWidget::setupChangePinHeader(int pRetryCounter, bool pIsBasicReader) -{ - switch (pRetryCounter) - { - case 0: - mUi->headerStackedWidget->setCurrentWidget(mUi->changePinPukHeaderPage); - break; - - case 1: - mUi->headerStackedWidget->setCurrentWidget(mUi->changePinWithCanHeaderPage); - break; - - default: - if (mMode == Mode::AfterPinUnblock) - { - mUi->headerStackedWidget->setCurrentWidget(mUi->pinUnblockedHeaderPage); - } - else - { - if (pIsBasicReader) - { - mUi->headerStackedWidget->setCurrentWidget(mUi->changePinBasicHeaderPage); - } - else - { - mUi->headerStackedWidget->setCurrentWidget(mUi->changePinComfortHeaderPage); - } - } - break; - } -} - - -bool PinSettingsWidget::isCanFieldVisible() const -{ - return mUi->canEditStackedWidget->currentWidget() == mUi->canEditPage; -} - - -void PinSettingsWidget::onRandomPinButtonClicked() -{ - const auto& readersWithNpa = getReaderWithNPA(ReaderManager::getInstance().getReaderInfos()); - const auto& selectedReaderName = readersWithNpa.size() == 1 ? readersWithNpa.at(0).getName() : QString(); - mRandomPinDialog = new RandomPinDialog(6, selectedReaderName, this); - if (mRandomPinDialog->exec() == QDialog::Accepted && !mRandomPinDialog->getPin().isEmpty()) - { - QToolButton* pinButton = qobject_cast(sender()); - if (pinButton == nullptr) - { - qCCritical(gui) << "sender == nullptr"; - } - else if (pinButton->objectName() == QLatin1String("canRandomPinButton")) - { - onCanTextEdited(mRandomPinDialog->getPin()); - } - else if (pinButton->objectName() == QLatin1String("oldRandomPinButton")) - { - onOldPinTextEdited(mRandomPinDialog->getPin()); - } - else if (pinButton->objectName() == QLatin1String("newRandomPinButton")) - { - onNewPinTextEdited(mRandomPinDialog->getPin()); - } - else if (pinButton->objectName() == QLatin1String("repeatNewRandomPinButton")) - { - onRepeatNewPinTextEdited(mRandomPinDialog->getPin()); - } - else if (pinButton->objectName() == QLatin1String("pukRandomPinButton")) - { - onPukTextEdited(mRandomPinDialog->getPin()); - } - } -} - - -void PinSettingsWidget::onRandomPukButtonClicked() -{ - const auto& readersWithNpa = getReaderWithNPA(ReaderManager::getInstance().getReaderInfos()); - const auto& selectedReaderName = readersWithNpa.size() == 1 ? readersWithNpa.at(0).getName() : QString(); - mRandomPinDialog = new RandomPinDialog(10, selectedReaderName, this); - if (mRandomPinDialog->exec() == QDialog::Accepted && !mRandomPinDialog->getPin().isEmpty()) - { - onPukTextEdited(mRandomPinDialog->getPin()); - } -} diff --git a/src/gui/PinSettingsWidget.h b/src/gui/PinSettingsWidget.h deleted file mode 100644 index f520aca..0000000 --- a/src/gui/PinSettingsWidget.h +++ /dev/null @@ -1,117 +0,0 @@ -/*! - * \brief Widget for the PIN settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "DiagnosisWidget.h" -#include "generic/Page.h" -#include "PinSettingsInfoWidget.h" - -#include - -class QLabel; - -namespace Ui -{ -class PinSettingsWidget; -} - -namespace governikus -{ - -class PasswordEdit; -class RandomPinDialog; -class ReaderInfo; - -class PinSettingsWidget - : public Page -{ - Q_OBJECT - - public: - static const int SCALEWIDTH = 200; - - enum class Mode - { - Normal, - AfterPinChange, - AfterPinUnblock, - }; - - public: - PinSettingsWidget(QWidget* pParent = nullptr); - virtual ~PinSettingsWidget(); - - void setInProgress(bool pInProgress); - - QString getCan() const; - QString getPin() const; - QString getPuk() const; - QString getNewPin() const; - - - Mode getMode() const - { - return mMode; - } - - - void setMode(Mode pMode); - QString getButtonText() const; - void setUseScreenKeyboard(bool pUseScreenKeyboard); - - Q_SIGNALS: - void setChangePinButtonEnabled(bool pEnabled); - - public Q_SLOTS: - void updateReaders(); - - protected: - virtual void paintEvent(QPaintEvent*) override; - virtual void showEvent(QShowEvent* pEvent) override; - virtual void hideEvent(QHideEvent* pEvent) override; - - private Q_SLOTS: - void onCanTextEdited(const QString& pText = QString()); - void onOldPinTextEdited(const QString& pText = QString()); - void onNewPinTextEdited(const QString& pText = QString()); - void onRepeatNewPinTextEdited(const QString& pText = QString()); - void onPukTextEdited(const QString& pText = QString()); - void focusPUK(); - void focusPIN(); - void focusCAN(); - void onRandomPinButtonClicked(); - void onRandomPukButtonClicked(); - void onScanTimeout(); - - void onScanButtonClicked(); - void onUiFinished(const QString& pReaderName); - - private: - void setupPinBasicPage(const ReaderInfo& pReaderInfo); - void setupPinComfortPage(const ReaderInfo& pReaderInfo); - void setupPinSuccessfullyChangedPage(const ReaderInfo& pReaderInfo); - void setupChangePinHeader(int pRetryCounter, bool pIsBasicReader); - - bool isCanFieldVisible() const; - - QVector getReaderWithNPA(const QVector& pReaderInfos); - void updateReadersWithoutNPA(const QVector& pReaderInfos); - bool updateReadersForOneNPA(const ReaderInfo& pReaderInfo); - - void fillInfoDescription(const QString& pTitle, const QString& pMessage); - - QScopedPointer mUi; - Mode mMode; - int mRetryCounter; - bool mPinDeactivated; - - QString mPinSettingsInfoTitle; - QString mPinSettingsInfoDescription; - QPointer mRandomPinDialog; -}; - -} /* namespace governikus */ diff --git a/src/gui/PinSettingsWidget.ui b/src/gui/PinSettingsWidget.ui deleted file mode 100644 index b519461..0000000 --- a/src/gui/PinSettingsWidget.ui +++ /dev/null @@ -1,1423 +0,0 @@ - - - PinSettingsWidget - - - - 0 - 0 - 536 - 551 - - - - - - - Qt::TabFocus - - - 3 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - 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 your competent authority. - -Please note that the PIN may only consist of digits (0-9). - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - 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 your competent authority. - -Please note that the PIN may only consist of digits (0-9). - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 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 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. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - 0 - 0 - - - - Qt::TabFocus - - - CAN on nPA icon - - - :/images/canHint.png - - - false - - - - - - - Qt::TabFocus - - - You have entered the wrong PIN two times. For a third attempt you first have to enter your six-digit card access number. 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. - - - true - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - 20 - - - - - - - - :/images/Icon_Checked.svg - - - - - - - Qt::TabFocus - - - <h4>PUK entry successful</h4><p>Your ID card is unblocked. You now have three more tries to change your PIN.</p> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - 20 - - - - - - - - :/images/Icon_Checked.svg - - - - - - - Qt::TabFocus - - - <h4>PIN successfully changed</h4> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - <html> -<h4>No card reader detected. Please make sure that a card reader is connected.</h4> -<p>If you need help or have problems with your card reader click on the "Diagnosis" button for further information. -</p> -</html> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - <html> -<h4>Please place your ID card on the card reader.</h4> -<p>If you have already placed an ID card on the card reader but it is not displayed here, please click on "Diagnosis".</p> -</html> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - <html> -<h4>Several ID cards detected</h4> -<p>Please place just one ID card on the card reader.</p> -</html> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - <html> -<h4>eID feature deactivated</h4> -<p>The eID function of your ID card is deactivated. Please contact your competent authority to activate the eID function.</p> -</html> - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - - - Qt::Horizontal - - - - - - - Qt::TabFocus - - - 2 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - 20 - - - 20 - - - - - 1 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - Current PIN / Transport PIN: - - - - - - - Qt::StrongFocus - - - - - - - Qt::StrongFocus - - - true - - - - - - - Qt::TabFocus - - - New PIN: - - - - - - - Qt::StrongFocus - - - - - - - Qt::StrongFocus - - - true - - - - - - - Qt::TabFocus - - - Confirm: - - - - - - - Qt::StrongFocus - - - - - - - Qt::StrongFocus - - - true - - - - - - - Qt::TabFocus - - - 1 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - Card access number (CAN): - - - - - - - - - 0 - 0 - - - - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::StrongFocus - - - - - - - true - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 85 - - - - - - - - - - Qt::TabFocus - - - PUK: - - - - - - - Qt::StrongFocus - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 85 - - - - - - - - - - - - 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - - 200 - 200 - - - - - 200 - 200 - - - - Qt::TabFocus - - - card reader icon - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 15 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 20 - - - 20 - - - 0 - - - 20 - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 200 - 200 - - - - - 200 - 200 - - - - Qt::TabFocus - - - card reader icon - - - Qt::AlignCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - Click on "Change PIN" to enter a new PIN. - - - Qt::AlignCenter - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Click on "Enter PUK" to unblock your ID card. - - - Qt::AlignCenter - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 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. - - - Qt::AlignCenter - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - - - Please pay attention to the display of your card reader. - - - Qt::AlignCenter - - - true - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 169 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 20 - - - 20 - - - 0 - - - 20 - - - 0 - - - - - Qt::TabFocus - - - Click on "Change PIN" if you want to change your PIN again. - -If not, you can now remove your ID card form the card reader. - - - true - - - - - - - - 0 - 0 - - - - Qt::TabFocus - - - successful PIN change icon - - - Qt::AlignCenter - - - - - - - - - - Qt::Vertical - - - - 20 - 237 - - - - - - - - - - 15 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - no reader icon - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 15 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - no id card icon - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 15 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Qt::TabFocus - - - - - - Please make sure that only one card reader with an ID card on it is connected to your computer. - - - true - - - - - - - Qt::TabFocus - - - multiple card reader icon - - - Qt::AlignCenter - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::TabFocus - - - deactivated card reader icon - - - deactivatedReaderImageLabel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Qt::Vertical - - - - 20 - 263 - - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
- - governikus::PasswordEdit - QWidget -
generic/PasswordEdit.h
- 1 -
-
- - - - -
diff --git a/src/gui/ProviderWidget.cpp b/src/gui/ProviderWidget.cpp deleted file mode 100644 index 467e1a8..0000000 --- a/src/gui/ProviderWidget.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/*! - * ProviderWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProviderWidget.h" - -#include "AppSettings.h" -#include "generic/ListCheckItemWidget.h" -#include "generic/ListItem.h" -#include "generic/ListItemIconLeft.h" -#include "generic/ListItemIconRight.h" -#include "generic/ListItemSubTitle.h" -#include "generic/ListItemTitle.h" -#include "ProviderService.h" -#include "ProviderSettings.h" -#include "ui_ProviderWidget.h" - -#include -#include -#include -#include -#include -#include - -using namespace governikus; - -ProviderWidget::ProviderWidget(QWidget* pParent) - : Page(tr("Provider"), pParent) - , mUi(new Ui::ProviderWidget()) -{ - mUi->setupUi(this); - - connect(mUi->providerSearch, &QLineEdit::textChanged, this, &ProviderWidget::searchProvider); - connect(&ProviderService::getInstance(), &ProviderService::fireUpdateFinished, this, &ProviderWidget::onProviderChanged); - - fill(); -} - - -ProviderWidget::~ProviderWidget() -{ -} - - -void ProviderWidget::onProviderChanged() -{ - mUi->providerTableWidget->clear(); - fill(); -} - - -void ProviderWidget::fill() -{ - qDebug() << "add provider for desktop widgets."; - QStringList header; - header += tr("Name"); - header += tr("Address"); - - ProviderSettings& providerSettings = AppSettings::getInstance().getProviderSettings(); - providerSettings.load(); - - mUi->providerTableWidget->setColumnCount(header.count()); - mUi->providerTableWidget->setHorizontalHeaderLabels(header); - mUi->providerTableWidget->setRowCount(providerSettings.getProviders().size()); - - int row = 0; - for (const Provider& provider : providerSettings.getProviders()) - { - - QLabel* providerName = new QLabel(provider.getLongName().isEmpty() ? provider.getShortName() : provider.getLongName()); - providerName->setFocusPolicy(Qt::TabFocus); - providerName->setToolTip(providerName->text()); - providerName->setTextFormat(Qt::RichText); - providerName->setMargin(3); - mUi->providerTableWidget->setCellWidget(row, 0, providerName); - - QLabel* providerLink = new QLabel("" + provider.getAddress() + ""); - providerLink->setToolTip(providerLink->text()); - providerLink->setFocusPolicy(Qt::TabFocus); - providerLink->setTextFormat(Qt::RichText); - providerLink->setTextInteractionFlags(Qt::TextBrowserInteraction); - providerLink->setOpenExternalLinks(true); - providerLink->setMargin(3); - mUi->providerTableWidget->setCellWidget(row, 1, providerLink); - - ++row; - } - - mUi->providerTableWidget->verticalHeader()->setVisible(false); //Hide row number - mUi->providerTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //Not allowed to change content - mUi->providerTableWidget->setAlternatingRowColors(true); //Grey and white alternating row - mUi->providerTableWidget->resizeColumnsToContents(); - - mUi->noResultWidget->setVisible(false); -} - - -void ProviderWidget::searchProvider() -{ - QString searchText = mUi->providerSearch->text().trimmed(); - mUi->providerTableWidget->setVisible(true); - mUi->noResultWidget->setVisible(false); - - bool anyMatch = false; - - for (int i = 0; i < mUi->providerTableWidget->rowCount(); ++i) - { - bool match = false; - for (int j = 0; j < mUi->providerTableWidget->columnCount(); ++j) - { - - if (qobject_cast(mUi->providerTableWidget->cellWidget(i, j))->text().contains(searchText, Qt::CaseInsensitive)) - { - match = true; - anyMatch = true; - break; - } - } - mUi->providerTableWidget->setRowHidden(i, !match); - } - - mUi->providerTableWidget->setVisible(anyMatch); - mUi->noResultWidget->setVisible(!anyMatch); -} - - -void ProviderWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/ProviderWidget.h b/src/gui/ProviderWidget.h deleted file mode 100644 index b1588c4..0000000 --- a/src/gui/ProviderWidget.h +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * ProviderWidget.h - * - * \brief The provider page in gui. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -#include "generic/ListCheckItemWidget.h" -#include "generic/Page.h" - -class QTableWidgetItem; - -namespace Ui -{ -class ProviderWidget; -} - -namespace governikus -{ - -class ProviderWidget - : public Page -{ - Q_OBJECT - - public: - ProviderWidget(QWidget* pParent = nullptr); - virtual ~ProviderWidget(); - - public Q_SLOTS: - void searchProvider(); - void onProviderChanged(); - - private: - QScopedPointer mUi; - - virtual void paintEvent(QPaintEvent*) override; - void fill(); -}; - -} /* namespace governikus */ diff --git a/src/gui/ProviderWidget.ui b/src/gui/ProviderWidget.ui deleted file mode 100644 index e1f0011..0000000 --- a/src/gui/ProviderWidget.ui +++ /dev/null @@ -1,141 +0,0 @@ - - - ProviderWidget - - - - 0 - 0 - 516 - 252 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Qt::TabFocus - - - 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. - - - <html><head/><body><p>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.</p></body></html> - - - true - - - - - - - - - Qt::TabFocus - - - Search: - - - - - - - Please enter your search - - - Please enter your search - - - - - - - - - QAbstractScrollArea::AdjustToContents - - - false - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectItems - - - false - - - false - - - 200 - - - false - - - true - - - - - - - - 5 - - - - - No matching providers were found. Please modify your search criteria. - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/ProviderWidgetQml.cpp b/src/gui/ProviderWidgetQml.cpp deleted file mode 100644 index 187856f..0000000 --- a/src/gui/ProviderWidgetQml.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 8cbcf6e..0000000 --- a/src/gui/ProviderWidgetQml.h +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * \brief TODO - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppSettings.h" -#include "generic/Page.h" -#include "HistoryModel.h" -#include "ProviderCategoryFilterModel.h" -#include "QmlExtension.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 deleted file mode 100644 index bb149a1..0000000 --- a/src/gui/ProviderWidgetQml.ui +++ /dev/null @@ -1,48 +0,0 @@ - - - ProviderWidgetQml - - - - 0 - 0 - 599 - 666 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - QQuickWidget::SizeViewToRootObject - - - - - - - - - - QQuickWidget - QWidget -
QtQuickWidgets/QQuickWidget
-
-
- - -
diff --git a/src/gui/RandomPinDialog.cpp b/src/gui/RandomPinDialog.cpp deleted file mode 100644 index 0c24b9b..0000000 --- a/src/gui/RandomPinDialog.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/*! - * RandomPinDialog.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "RandomPinDialog.h" -#include "ui_RandomPinDialog.h" - -#include "generic/HelpAction.h" -#include "Randomizer.h" -#include "ReaderManager.h" - -#include -#include - -using namespace governikus; - -static const char* PIN = "pin"; - -RandomPinDialog::RandomPinDialog(int pLength, const QString& pSelectedReader, QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::RandomPinDialog) - , mSelectedReader(pSelectedReader) -{ - mUi->setupUi(this); - mUi->pin->setMaxLength(pLength); - - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("On screen password")); - - setModal(true); - - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &RandomPinDialog::onCardRemoved); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &RandomPinDialog::onCardInserted); - - installEventFilter(this); - - mUi->pinButtons->setId(mUi->button_pos_0, 0); - mUi->pinButtons->setId(mUi->button_pos_1, 1); - mUi->pinButtons->setId(mUi->button_pos_2, 2); - mUi->pinButtons->setId(mUi->button_pos_3, 3); - mUi->pinButtons->setId(mUi->button_pos_4, 4); - mUi->pinButtons->setId(mUi->button_pos_5, 5); - mUi->pinButtons->setId(mUi->button_pos_6, 6); - mUi->pinButtons->setId(mUi->button_pos_7, 7); - mUi->pinButtons->setId(mUi->button_pos_8, 8); - mUi->pinButtons->setId(mUi->button_pos_9, 9); - - initComponents(); - createButton(); -} - - -RandomPinDialog::~RandomPinDialog() -{ -} - - -void RandomPinDialog::initComponents() -{ - mUi->clrButton->setIcon(QPixmap(QStringLiteral(":images/randompin/btn_clear.png"))); - mUi->clrButton->setIconSize(QSize(44, 26)); - connect(mUi->clrButton, &QAbstractButton::clicked, mUi->pin, &QLineEdit::clear); - - mUi->cnlButton->setIcon(QPixmap(QStringLiteral(":images/randompin/btn_cancel.png"))); - mUi->cnlButton->setIconSize(QSize(58, 50)); - connect(mUi->cnlButton, &QAbstractButton::clicked, this, &RandomPinDialog::reject); - - mUi->okButton->setIcon(QPixmap(QStringLiteral(":images/randompin/btn_ok.png"))); - mUi->okButton->setIconSize(QSize(58, 50)); - connect(mUi->okButton, &QAbstractButton::clicked, this, &RandomPinDialog::accept); -} - - -void RandomPinDialog::createButton() -{ - QVector buttonList = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 - }; - std::shuffle(buttonList.begin(), buttonList.end(), Randomizer::getInstance().getGenerator()); - - Q_ASSERT(buttonList.size() == mUi->pinButtons->buttons().size()); - for (int i = 0; i < buttonList.size(); ++i) - { - QAbstractButton* button = mUi->pinButtons->button(i); - button->setIcon(QPixmap(QStringLiteral(":images/randompin/btn_normal_%1.png").arg(buttonList.value(i)))); - button->setIconSize(QSize(58, 50)); - button->setProperty(PIN, QVariant::fromValue(buttonList.value(i))); - connect(button, &QAbstractButton::clicked, this, &RandomPinDialog::onPosButtonClicked); - } -} - - -QString RandomPinDialog::getPin() -{ - return mUi->pin->text(); -} - - -void RandomPinDialog::onPosButtonClicked() -{ - QToolButton* posButton = qobject_cast(sender()); - if (posButton) - { - mUi->pin->setText(mUi->pin->text() + "" + posButton->property(PIN).toString()); - } -} - - -void RandomPinDialog::onCardRemoved(const QString& pReaderName) -{ - if (isVisible() && pReaderName == mSelectedReader) - { - reject(); - } -} - - -void RandomPinDialog::onCardInserted() -{ - if (isVisible()) - { - reject(); - } -} - - -bool RandomPinDialog::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QDialog::eventFilter(pObject, pEvent); -} diff --git a/src/gui/RandomPinDialog.h b/src/gui/RandomPinDialog.h deleted file mode 100644 index 12c1149..0000000 --- a/src/gui/RandomPinDialog.h +++ /dev/null @@ -1,49 +0,0 @@ -/*! - * RandomPinDialog.h - * - * \brief Dialog for display the random PIN. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class RandomPinDialog; -} - -namespace governikus -{ - -class RandomPinDialog - : public QDialog -{ - Q_OBJECT - - public: - RandomPinDialog(int pLength, const QString& pSelectedReader, QWidget* pParent = nullptr); - virtual ~RandomPinDialog(); - - QString getPin(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - QScopedPointer mUi; - const QString mSelectedReader; - - void initComponents(); - void createButton(); - - private Q_SLOTS: - void onPosButtonClicked(); - void onCardRemoved(const QString& pReaderName); - void onCardInserted(); -}; - -} /* namespace governikus */ diff --git a/src/gui/RandomPinDialog.ui b/src/gui/RandomPinDialog.ui deleted file mode 100644 index 9dc2df3..0000000 --- a/src/gui/RandomPinDialog.ui +++ /dev/null @@ -1,303 +0,0 @@ - - - RandomPinDialog - - - - 0 - 0 - 293 - 181 - - - - Screen keyboard - - - - 6 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Clear - - - - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - OK - - - - - - true - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - Cancel - - - - - - true - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - * - - - - - - true - - - pinButtons - - - - - - - PIN field - - - 6 - - - QLineEdit::Password - - - true - - - - - - - - - - - - button_pos_1 - button_pos_2 - button_pos_3 - button_pos_4 - button_pos_5 - button_pos_6 - button_pos_7 - button_pos_8 - button_pos_9 - button_pos_0 - okButton - clrButton - cnlButton - pin - - - - - - - false - - - - diff --git a/src/gui/ReaderDriverDialog.cpp b/src/gui/ReaderDriverDialog.cpp deleted file mode 100644 index 0ad7e3b..0000000 --- a/src/gui/ReaderDriverDialog.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * ReaderDriverDialog.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "generic/HelpAction.h" -#include "ReaderDriverDialog.h" -#include "ui_ReaderDriverDialog.h" - - -#include - - -using namespace governikus; - -ReaderDriverDialog::ReaderDriverDialog(QWidget* pParent) - : QDialog(pParent) - , mUi(new Ui::ReaderDriverDialog) - , mReaderDriverWidget(new ReaderDriverWidget(pParent)) -{ - mUi->setupUi(this); - - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); - setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Reader Driver Integration")); - - installEventFilter(this); - - mUi->readerDriverLayout->addWidget(mReaderDriverWidget); - - connect(mUi->closeButton, &QAbstractButton::clicked, this, &ReaderDriverDialog::close); - connect(this, &ReaderDriverDialog::fireUpdateContent, mReaderDriverWidget, &ReaderDriverWidget::onUpdateContent); -} - - -ReaderDriverDialog::~ReaderDriverDialog() -{ -} - - -bool ReaderDriverDialog::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* const keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(); - return true; - } - } - return QDialog::eventFilter(pObject, pEvent); -} diff --git a/src/gui/ReaderDriverDialog.h b/src/gui/ReaderDriverDialog.h deleted file mode 100644 index 8120652..0000000 --- a/src/gui/ReaderDriverDialog.h +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * ReaderDriverDialog.h - * - * \brief Dialog for detecting attached card readers and - * suggesting an appropriate driver to be installed. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/ReaderDriverContext.h" -#include "ReaderDriverWidget.h" - -#include -#include - -namespace Ui -{ -class ReaderDriverDialog; -} - -class QTextCursor; - -namespace governikus -{ - -class ReaderDriverDialog - : public QDialog -{ - Q_OBJECT - - public: - ReaderDriverDialog(QWidget* pParent = nullptr); - virtual ~ReaderDriverDialog(); - - Q_SIGNALS: - void fireUpdateContent(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - - private: - QScopedPointer mUi; - ReaderDriverWidget* mReaderDriverWidget; -}; - -} /* namespace governikus */ diff --git a/src/gui/ReaderDriverDialog.ui b/src/gui/ReaderDriverDialog.ui deleted file mode 100644 index 73e00e6..0000000 --- a/src/gui/ReaderDriverDialog.ui +++ /dev/null @@ -1,78 +0,0 @@ - - - ReaderDriverDialog - - - Qt::WindowModal - - - - 0 - 0 - 680 - 400 - - - - Diagnosis - - - - 9 - - - 9 - - - 9 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Close - - - - - - - - - - diff --git a/src/gui/ReaderDriverGui.cpp b/src/gui/ReaderDriverGui.cpp deleted file mode 100644 index b516d97..0000000 --- a/src/gui/ReaderDriverGui.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*! - * ReaderDriverGui.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "ReaderDriverGui.h" - -#include - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(gui) - -ReaderDriverGui::ReaderDriverGui(QWidget* pParentWidget) - : QObject(pParentWidget) - , mDialog(nullptr) -{ -} - - -ReaderDriverGui::~ReaderDriverGui() -{ -} - - -void ReaderDriverGui::activate() -{ - if (!mDialog) - { - QWidget* dialogParent = qobject_cast(parent()); - if (!dialogParent) - { - return; - } - - mDialog = new ReaderDriverDialog(dialogParent); - connect(mDialog, &ReaderDriverDialog::finished, this, &ReaderDriverGui::onFinished); - connect(mDialog, &QDialog::finished, this, &ReaderDriverGui::fireFinished); - } - reactivate(); -} - - -void ReaderDriverGui::deactivate() -{ - if (mDialog) - { - mDialog->close(); - } -} - - -void ReaderDriverGui::reactivate() -{ - if (mDialog->isMinimized()) - { - mDialog->showNormal(); - } - if (!mDialog->isVisible()) - { - mDialog->show(); - } - mDialog->activateWindow(); - mDialog->raise(); - Q_EMIT mDialog->fireUpdateContent(); -} - - -void ReaderDriverGui::onFinished(int result) -{ - Q_UNUSED(result); - - mDialog = nullptr; -} diff --git a/src/gui/ReaderDriverGui.h b/src/gui/ReaderDriverGui.h deleted file mode 100644 index 656a1bc..0000000 --- a/src/gui/ReaderDriverGui.h +++ /dev/null @@ -1,42 +0,0 @@ -/*! - * ReaderDriverGui.h - * - * \brief Qt widget based ReaderDriverUi implementation. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/ReaderDriverContext.h" -#include "ReaderDriverDialog.h" - -class QWidget; - -namespace governikus -{ - -class ReaderDriverGui - : public QObject -{ - Q_OBJECT - - public: - ReaderDriverGui(QWidget* pParentWidget); - virtual ~ReaderDriverGui(); - - void activate(); - void deactivate(); - - Q_SIGNALS: - void fireFinished(); - - private: - ReaderDriverDialog* mDialog; - void reactivate(); - - private Q_SLOTS: - void onFinished(int result); -}; - -} /* namespace governikus */ diff --git a/src/gui/ReaderDriverWidget.cpp b/src/gui/ReaderDriverWidget.cpp deleted file mode 100644 index bd318fb..0000000 --- a/src/gui/ReaderDriverWidget.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "ReaderDriverWidget.h" - -#include "DriverSettings.h" -#include "generic/SmartCardUtil.h" -#include "ReaderManager.h" -#include "ui_ReaderDriverWidget.h" - -#include -#include - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -static const int DEVICE_NAME_COLUMN = 0; -static const int DEVICE_STATUS_COLUMN = 1; -static const int DEVICE_IMAGE_COLUMN = 2; - -static QTableWidgetItem* makeReadOnlyItem(const QString& text) -{ - QTableWidgetItem* const item = new QTableWidgetItem(text); - item->setFlags(item->flags() & ~Qt::ItemIsEditable); - - return item; -} - - -ReaderDriverWidget::ReaderDriverWidget(QWidget* pParent) - : Page(tr("Reader driver integration"), pParent) - , ui(new Ui::ReaderDriverWidget) - , mSelectedRow(-1) -{ - QStringList headerLabels({QString(), QString()}); - headerLabels[DEVICE_NAME_COLUMN] = tr("Device"); - headerLabels[DEVICE_STATUS_COLUMN] = tr("Status"); - - ui->setupUi(this); - ui->labelLayout->setAlignment(ui->readerLabel, Qt::AlignCenter); - ui->tableWidget->setColumnCount(3); - ui->tableWidget->setColumnWidth(DEVICE_NAME_COLUMN, getLongestReaderNameWidth()); - ui->tableWidget->setHorizontalHeaderLabels(headerLabels); - ui->tableWidget->horizontalHeader()->setStretchLastSection(true); - ui->tableWidget->verticalHeader()->setVisible(false); - ui->tableWidget->setColumnHidden(2, true); - - ui->infoText->setOpenExternalLinks(true); - - mTimer.setSingleShot(true); - mTimer.setInterval(10000); - connect(&mTimer, &QTimer::timeout, this, &ReaderDriverWidget::onTimerEvent); - - connect(ui->tableWidget, &QTableWidget::itemSelectionChanged, this, &ReaderDriverWidget::onDeviceSelectionChanged); - - connect(&mContext, &ReaderDriverContext::fireReaderChangeDetected, this, &ReaderDriverWidget::onUpdateContent); - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &ReaderDriverWidget::onUpdateContent); -} - - -ReaderDriverWidget::~ReaderDriverWidget() -{ - delete ui; -} - - -void ReaderDriverWidget::onUpdateContent() -{ - mAttachedDevices = mContext.attachedDevices(); - qCDebug(gui) << "Found" << mAttachedDevices.size() << "attached devices"; - - removeOldTableItems(); - updateTableItems(); - if (ui->tableWidget->rowCount() > 0 && ui->tableWidget->currentRow() == -1) - { - ui->tableWidget->selectRow(0); - } - onDeviceSelectionChanged(); - - mTimer.start(); -} - - -void ReaderDriverWidget::onDeviceSelectionChanged() -{ - mSelectedRow = ui->tableWidget->currentRow(); - updateInfo(); -} - - -void ReaderDriverWidget::removeOldTableItems() -{ - for (int i = ui->tableWidget->rowCount() - 1; i >= 0; i--) - { - QString deviceName = ui->tableWidget->item(i, DEVICE_NAME_COLUMN)->text(); - bool found = false; - - for (const auto& dev : mAttachedDevices) - { - if (dev->getName() == deviceName) - { - found = true; - break; - } - } - - if (!found) - { - ui->tableWidget->removeRow(i); - } - } -} - - -void ReaderDriverWidget::updateTableItems() -{ - for (const auto& dev : mAttachedDevices) - { - const QString statusText = dev->hasDriver() ? tr("Installed") : tr("Searching for driver..."); - const QString deviceName = dev->getName(); - bool found = false; - - for (int i = 0; i < ui->tableWidget->rowCount(); i++) - { - if (ui->tableWidget->item(i, DEVICE_NAME_COLUMN)->text() == deviceName) - { - if (dev->hasDriver()) - { - ui->tableWidget->setItem(i, DEVICE_STATUS_COLUMN, makeReadOnlyItem(statusText)); - } - found = true; - break; - } - } - - if (!found) - { - const int lastRow = ui->tableWidget->rowCount(); - ui->tableWidget->insertRow(lastRow); - ui->tableWidget->setItem(lastRow, DEVICE_NAME_COLUMN, makeReadOnlyItem(dev->getName())); - ui->tableWidget->setItem(lastRow, DEVICE_STATUS_COLUMN, makeReadOnlyItem(statusText)); - const QString path = SmartCardUtil::getReaderEmptyIconPath(dev->getReaderType()); - ui->tableWidget->setItem(lastRow, DEVICE_IMAGE_COLUMN, makeReadOnlyItem(path)); - } - } -} - - -void ReaderDriverWidget::updateInfo() -{ - updateInfoIcon(); - updateInfoText(); - updateInfoUpdate(); -} - - -void ReaderDriverWidget::updateInfoIcon() -{ - QString path; - if (mSelectedRow == -1) - { - path = SmartCardUtil::getNoReaderFoundIconPath(); - } - else - { - path = ui->tableWidget->item(mSelectedRow, DEVICE_IMAGE_COLUMN)->text(); - } - QPixmap pixmap(path); - const int layoutHeight = ui->detailInfoLayout->geometry().height(); - ui->readerLabel->setPixmap(pixmap.scaledToHeight(layoutHeight / 2, Qt::SmoothTransformation)); -} - - -void ReaderDriverWidget::updateInfoText() -{ - if (mSelectedRow == -1) - { - if (ui->tableWidget->rowCount() == 0) - { - ui->infoText->setHtml(tr("

No card reader detected

")); - } - else - { - ui->infoText->setHtml(tr("

Select a device to display more information about it

")); - } - } - else - { - if (mSelectedRow < 0 || mSelectedRow >= mAttachedDevices.size() || mSelectedRow >= ui->tableWidget->rowCount()) - { - // We should never get in here - qCWarning(gui) << "mSelectedRow out of range, skipping update"; - qCWarning(gui) << " mSelectedRow =" << mSelectedRow; - qCWarning(gui) << " mAttachedDevices.size() =" << mAttachedDevices.size(); - qCWarning(gui) << " ui->tableWidget->rowCount() =" << ui->tableWidget->rowCount(); - } - else if (ui->tableWidget->item(mSelectedRow, DEVICE_STATUS_COLUMN)->text() == tr("Installed")) - { - ui->infoText->setHtml(tr("

Device is installed correctly

")); - } - else - { - const QSharedPointer selectedDevice = mAttachedDevices.at(mSelectedRow); - const QString newText = tr("

Device is not configured, please download and install the driver " - "you can find at url: %1

"). - arg(selectedDevice->getDriverUrl()); - ui->infoText->setHtml(newText); - } - } -} - - -void ReaderDriverWidget::updateInfoUpdate() -{ - QTime now = QTime::currentTime(); - const QString text = tr("The list of card readers was last updated at %1."); - - ui->updateTimeLabel->setText(text.arg(now.toString(tr("hh:mm:ss AP")))); -} - - -int ReaderDriverWidget::getLongestReaderNameWidth() const -{ - static const int CELL_PADDING = 20; - - QSharedPointer settings(new DriverSettings()); - settings->load(); - - int maxWidth = 0; - const QFontMetrics metrics(QGuiApplication::font()); - for (const auto& driver : settings->getDrivers()) - { - const int deviceNameWidth = metrics.width(driver->getName()); - if (deviceNameWidth > maxWidth) - { - maxWidth = deviceNameWidth; - } - } - - return maxWidth + CELL_PADDING; -} - - -void ReaderDriverWidget::onTimerEvent() -{ - for (int i = 0; i < ui->tableWidget->rowCount(); i++) - { - if (ui->tableWidget->item(i, DEVICE_STATUS_COLUMN)->text() == tr("Searching for driver...")) - { - ui->tableWidget->setItem(i, DEVICE_STATUS_COLUMN, makeReadOnlyItem(tr("Not installed"))); - } - } -} diff --git a/src/gui/ReaderDriverWidget.h b/src/gui/ReaderDriverWidget.h deleted file mode 100644 index 17b4aa4..0000000 --- a/src/gui/ReaderDriverWidget.h +++ /dev/null @@ -1,72 +0,0 @@ -/*! - * ReaderDriverWidget.h - * - * \brief Widget for detecting attached card readers and - * suggesting an appropriate driver to be installed. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -#include "context/ReaderDriverContext.h" -#include "generic/Page.h" - -namespace Ui -{ -class ReaderDriverWidget; -} - -class QTableWidget; - -namespace governikus -{ -class ReaderDriverWidget - : public Page -{ - Q_OBJECT - - public: - explicit ReaderDriverWidget(QWidget* pParent = nullptr); - - ~ReaderDriverWidget(); - - public Q_SLOTS: - void onUpdateContent(); - - private: - Ui::ReaderDriverWidget* ui; - - ReaderDriverContext mContext; - - QVector > mAttachedDevices; - - int mSelectedRow; - - QTimer mTimer; - - void removeOldTableItems(); - - void updateTableItems(); - - void updateInfo(); - - void updateInfoIcon(); - - void updateInfoText(); - - void updateInfoUpdate(); - - // Get the names of readers from the settings and find the width - // in pixels needed to accomodate the longest name. - int getLongestReaderNameWidth() const; - - private Q_SLOTS: - void onDeviceSelectionChanged(); - void onTimerEvent(); -}; - -} diff --git a/src/gui/ReaderDriverWidget.ui b/src/gui/ReaderDriverWidget.ui deleted file mode 100644 index 3b5b846..0000000 --- a/src/gui/ReaderDriverWidget.ui +++ /dev/null @@ -1,79 +0,0 @@ - - - ReaderDriverWidget - - - - 0 - 0 - 649 - 321 - - - - - - - - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - - - - - - - - - TextLabel - - - - - - - - - - 0 - 0 - - - - - - - - - - - - - - After connecting a new card reader it can take some seconds to recognize the driver. - - - - - - - TextLabel - - - - - - - - - - - - diff --git a/src/gui/SelfInformationWidget.cpp b/src/gui/SelfInformationWidget.cpp deleted file mode 100644 index fe9ba72..0000000 --- a/src/gui/SelfInformationWidget.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "SelfInformationWidget.h" - -#include "ui_SelfInformationWidget.h" - -#include -#include -#include - -using namespace governikus; - -SelfInformationWidget::SelfInformationWidget(QWidget* pParent) - : Page(tr("Identify"), pParent) - , mUi(new Ui::SelfInformationWidget()) -{ - mUi->setupUi(this); - - connect(mUi->selfAuthenticationButton, &QAbstractButton::clicked, this, &SelfInformationWidget::selfAuthenticationRequested); - - mPixDescLogoLabel.reset(new QPixmap(QStringLiteral(":/images/siteWithLogo.png"))); - mUi->descriptionLogoLabel->setPixmap(mPixDescLogoLabel->scaled(159, 120, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); -} - - -SelfInformationWidget::~SelfInformationWidget() -{ -} - - -void SelfInformationWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/SelfInformationWidget.h b/src/gui/SelfInformationWidget.h deleted file mode 100644 index 43e7b47..0000000 --- a/src/gui/SelfInformationWidget.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * \brief Widget for starting the self information workflow. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/Page.h" - -#include - -namespace Ui -{ -class SelfInformationWidget; -} - -namespace governikus -{ - -class SelfInformationWidget - : public Page -{ - Q_OBJECT - - public: - SelfInformationWidget(QWidget* pParent = nullptr); - virtual ~SelfInformationWidget(); - - Q_SIGNALS: - void selfAuthenticationRequested(); - - private: - QScopedPointer mUi; - QScopedPointer mPixDescLogoLabel; - - void paintEvent(QPaintEvent*); -}; - -} /* namespace governikus */ diff --git a/src/gui/SelfInformationWidget.ui b/src/gui/SelfInformationWidget.ui deleted file mode 100644 index b492d31..0000000 --- a/src/gui/SelfInformationWidget.ui +++ /dev/null @@ -1,203 +0,0 @@ - - - SelfInformationWidget - - - - 0 - 0 - 607 - 375 - - - - - 20 - - - 20 - - - 20 - - - 20 - - - - - - 20 - - - 10 - - - 20 - - - 10 - - - - - - - Qt::TabFocus - - - eID Logo - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Qt::TabFocus - - - You can use your ID card anywhere you see this logo. - - - true - - - - - - - - - - - - - 20 - - - 20 - - - 20 - - - 20 - - - - - - - Qt::TabFocus - - - - - - See my personal data - - - true - - - - - - - - - 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. - - - true - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - See my personal data now... - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp deleted file mode 100644 index 45ec6d5..0000000 --- a/src/gui/SettingsWidget.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/*! - * SettingsWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AppSettings.h" -#include "SettingsWidget.h" -#include "ui_SettingsWidget.h" - -#include -#include -#include -#include - -using namespace governikus; - -SettingsWidget::SettingsWidget(QWidget* pParent) - : Page(tr("Settings"), pParent) - , mUi(new Ui::SettingsWidget()) - , mSettingsChanged(false) -{ - mUi->setupUi(this); - - mUi->driverButton->setHidden(true); - - connect(mUi->diagnosisButton, &QAbstractButton::clicked, this, &SettingsWidget::diagnosisRequested); - connect(mUi->driverButton, &QAbstractButton::clicked, this, &SettingsWidget::driverRequested); - - connect(mUi->generalTab, &GeneralSettingsWidget::settingsChanged, this, &SettingsWidget::onSettingsChanged); - connect(mUi->pinTab, &PinSettingsWidget::setChangePinButtonEnabled, this, &SettingsWidget::onSetChangePinButtonEnabled); - - connect(mUi->cancelButton, &QPushButton::clicked, this, &SettingsWidget::onCancelButtonClicked); - - mUi->applyButton->setText(tr("Apply")); - mApplyButtonText = mUi->applyButton->text(); - connect(mUi->applyButton, &QPushButton::clicked, this, &SettingsWidget::onApplyButtonClicked); - - connect(mUi->settingsTabWidget, &QTabWidget::currentChanged, this, &SettingsWidget::onTabChanged); - - mUi->pinTab->setUseScreenKeyboard(AppSettings::getInstance().getGeneralSettings().isUseScreenKeyboard()); - - setSettingsChanged(false); -} - - -SettingsWidget::~SettingsWidget() -{ -} - - -void SettingsWidget::workflowStarted() -{ - // disable the non-selected tabs - int tabCount = mUi->settingsTabWidget->count(); - for (int i = 0; i < tabCount; ++i) - { - mUi->settingsTabWidget->setTabEnabled(i, i == mUi->settingsTabWidget->currentIndex()); - } - - // disable buttons - mUi->applyButton->setEnabled(false); - mUi->cancelButton->setEnabled(false); -} - - -void SettingsWidget::workflowFinished() -{ - // enable all tabs - int tabCount = mUi->settingsTabWidget->count(); - for (int i = 0; i < tabCount; ++i) - { - mUi->settingsTabWidget->setTabEnabled(i, true); - } - - // enable buttons - mUi->applyButton->setEnabled(mSettingsChanged); - mUi->cancelButton->setEnabled(true); - - if (mUi->pinTab->isVisible()) - { - QMetaObject::invokeMethod(mUi->pinTab, "updateReaders", Qt::QueuedConnection); - } -} - - -void SettingsWidget::switchToGuiModule(GuiModule pModule) -{ - switch (pModule) - { - case GuiModule::START_PAGE: - // not handled here - break; - - case GuiModule::GENERAL_SETTINGS: - mUi->settingsTabWidget->setCurrentWidget(mUi->generalTab); - break; - - case GuiModule::PIN_SETTINGS: - mUi->settingsTabWidget->setCurrentWidget(mUi->pinTab); - break; - } -} - - -void SettingsWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -void SettingsWidget::hideEvent(QHideEvent* pEvent) -{ - onTabChanged(-1); - Page::hideEvent(pEvent); -} - - -void SettingsWidget::onTabChanged(int pIndex) -{ - if (mUi->settingsTabWidget->widget(pIndex) == mUi->pinTab || pIndex == -1) - { - if (mSettingsChanged) - { - showSettingsChangedMessage(); - } - mUi->pinTab->setUseScreenKeyboard(AppSettings::getInstance().getGeneralSettings().isUseScreenKeyboard()); - } - else - { - mUi->applyButton->setText(mApplyButtonText); - setSettingsChanged(mSettingsChanged); - } -} - - -void SettingsWidget::showSettingsChangedMessage() -{ - QMessageBox msgBox(this); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Apply settings?")); - msgBox.setWindowModality(Qt::WindowModal); - msgBox.setText(tr("Do you want to apply the changes?")); - - if (msgBox.exec() == QMessageBox::Yes) - { - applyAppSettings(); - } - else - { - resetSettings(); - } -} - - -void SettingsWidget::onApplyButtonClicked() -{ - if (mUi->settingsTabWidget->currentWidget() == mUi->pinTab) - { - // change PIN button clicked - if (mUi->pinTab->getMode() == PinSettingsWidget::Mode::AfterPinChange) - { - mUi->pinTab->setMode(PinSettingsWidget::Mode::Normal); - mUi->pinTab->updateReaders(); - } - else - { - if (mUi->pinTab->isVisible()) - { - Q_EMIT changePinRequested(); - } - } - } - else - { - applyAppSettings(); - } -} - - -bool SettingsWidget::isSettingsChanged() -{ - return mSettingsChanged; -} - - -void SettingsWidget::applyAppSettings() -{ - // apply button clicked - mUi->generalTab->apply(); - - setSettingsChanged(false); -} - - -void SettingsWidget::onCancelButtonClicked() -{ - resetSettings(); - Q_EMIT settingsDone(); -} - - -void SettingsWidget::onSetChangePinButtonEnabled(bool pEnabled) -{ - if (mUi->settingsTabWidget->currentWidget() == mUi->pinTab) - { - mUi->applyButton->setText(mUi->pinTab->getButtonText()); - mUi->applyButton->setEnabled(pEnabled); - if (pEnabled) - { - mUi->applyButton->setAutoDefault(true); - mUi->applyButton->setDefault(true); - mUi->applyButton->setFocus(); - } - } -} - - -void SettingsWidget::onSettingsChanged() -{ - setSettingsChanged(true); -} - - -void SettingsWidget::resetSettings() -{ - mUi->generalTab->reset(); - setSettingsChanged(false); -} - - -QString SettingsWidget::getActiveTabObjectName() -{ - return mUi->settingsTabWidget->currentWidget()->objectName(); -} - - -void SettingsWidget::setSettingsChanged(bool pChanged) -{ - mSettingsChanged = pChanged; - mUi->applyButton->setEnabled(pChanged); -} diff --git a/src/gui/SettingsWidget.h b/src/gui/SettingsWidget.h deleted file mode 100644 index 76ce874..0000000 --- a/src/gui/SettingsWidget.h +++ /dev/null @@ -1,72 +0,0 @@ -/*! - * SettingsWidget.h - * - * \brief Widget for the settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -#include "generic/GuiModule.h" -#include "generic/Page.h" - -namespace Ui -{ -class SettingsWidget; -} - -namespace governikus -{ - -class SettingsWidget - : public Page -{ - Q_OBJECT - - public: - SettingsWidget(QWidget* pParent = nullptr); - virtual ~SettingsWidget(); - - void workflowStarted(); - void workflowFinished(); - - void switchToGuiModule(GuiModule pModule); - - QString getActiveTabObjectName(); - - bool isSettingsChanged(); - void showSettingsChangedMessage(); - - Q_SIGNALS: - void changePinRequested(); - void diagnosisRequested(); - void driverRequested(); - void settingsDone(); - - protected: - virtual void paintEvent(QPaintEvent*) override; - virtual void hideEvent(QHideEvent* pEvent) override; - - private Q_SLOTS: - void onTabChanged(int pIndex); - void onApplyButtonClicked(); - void onCancelButtonClicked(); - - void onSetChangePinButtonEnabled(bool pEnabled); - void onSettingsChanged(); - - private: - void resetSettings(); - void setSettingsChanged(bool pChanged); - void applyAppSettings(); - - private: - QScopedPointer mUi; - QString mApplyButtonText; - bool mSettingsChanged; -}; - -} /* namespace governikus */ diff --git a/src/gui/SettingsWidget.ui b/src/gui/SettingsWidget.ui deleted file mode 100644 index 8ec56d2..0000000 --- a/src/gui/SettingsWidget.ui +++ /dev/null @@ -1,133 +0,0 @@ - - - SettingsWidget - - - - 0 - 0 - 400 - 300 - - - - - 20 - - - 20 - - - 20 - - - 20 - - - - - 0 - - - - General - - - - - PIN Management - - - - - - - - Qt::Vertical - - - - 20 - 121 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Diagnosis... - - - - - - - Look for Driver - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Cancel - - - - - - - Apply - - - - - - - - - - - governikus::GeneralSettingsWidget - QWidget -
GeneralSettingsWidget.h
- 1 -
- - governikus::PinSettingsWidget - QWidget -
PinSettingsWidget.h
- 1 -
-
- - -
diff --git a/src/gui/SetupAssistantGui.cpp b/src/gui/SetupAssistantGui.cpp deleted file mode 100644 index ca717b0..0000000 --- a/src/gui/SetupAssistantGui.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * SetupAssistantGui.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "SetupAssistantGui.h" - -#include - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -SetupAssistantGui::SetupAssistantGui(QWidget* pParentWidget) - : QObject(pParentWidget) - , mWizard(nullptr) -{ -} - - -SetupAssistantGui::~SetupAssistantGui() -{ -} - - -void SetupAssistantGui::activate() -{ - if (!mWizard) - { - QWidget* dialogParent = qobject_cast(parent()); - if (!dialogParent) - { - return; - } - - mWizard = new SetupAssistantWizard(dialogParent); - connect(mWizard, &SetupAssistantWizard::fireChangePinButtonClicked, this, &SetupAssistantGui::fireChangePinButtonClicked); - } - - mWizard->exec(); -} - - -void SetupAssistantGui::deactivate() -{ - if (mWizard) - { - mWizard->close(); - } -} diff --git a/src/gui/SetupAssistantGui.h b/src/gui/SetupAssistantGui.h deleted file mode 100644 index e35b844..0000000 --- a/src/gui/SetupAssistantGui.h +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * SetupAssistantGui.h - * - * \brief Qt widget based SetupAssistantUi implementation. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "SetupAssistantWizard.h" - -class QWidget; - -namespace governikus -{ - -class SetupAssistantGui - : public QObject -{ - Q_OBJECT - - private: - QPointer mWizard; - - public: - SetupAssistantGui(QWidget* pParentWidget); - virtual ~SetupAssistantGui(); - - void activate(); - void deactivate(); - - Q_SIGNALS: - void fireChangePinButtonClicked(); - -}; - -} /* namespace governikus */ diff --git a/src/gui/SetupAssistantWizard.cpp b/src/gui/SetupAssistantWizard.cpp deleted file mode 100644 index d02da00..0000000 --- a/src/gui/SetupAssistantWizard.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/*! - * SetupAssistantWizard.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AppSettings.h" -#include "generic/GuiUtils.h" -#include "generic/HelpAction.h" -#include "generic/SmartCardUtil.h" -#include "ReaderInfo.h" -#include "ReaderManager.h" -#include "SetupAssistantWizard.h" - -#include "ReaderDriverWidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace governikus; - - -CardReaderPage::CardReaderPage(int pStepIndex, int pPageCount, SetupAssistantWizard* pWizard) - : mWidget(new ReaderDriverWidget(this)) -{ - // QWizardPage* cardReaderPage = new QWizardPage; - this->setTitle(tr("
Step %1 of %2
Card Reader
").arg(pStepIndex).arg(pPageCount)); - - QVBoxLayout* cardReaderPageVLayout = new QVBoxLayout(this); - QLabel* cardReaderlDescLabel = new QLabel(tr("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 detected card readers and the status of the corresponding driver.")); - cardReaderlDescLabel->setWordWrap(true); - cardReaderlDescLabel->setFocusPolicy(Qt::TabFocus); - cardReaderlDescLabel->setAccessibleName(tr("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 detected card readers and the status of the corresponding driver.").arg(pStepIndex).arg(pPageCount)); - - GuiUtils::updateFontSize(cardReaderlDescLabel); - - cardReaderPageVLayout->addWidget(cardReaderlDescLabel); - cardReaderPageVLayout->addWidget(mWidget); - - connect(pWizard, &SetupAssistantWizard::currentIdChanged, mWidget, &ReaderDriverWidget::onUpdateContent); -} - - -CardReaderPage::~CardReaderPage() -{ - // No need to delete mWidget because it is handled by Qt -} - - -void CardReaderPage::initializePage() -{ - // Update widget after it has become visible - // Calling onUpdateButtonClicked directly won't work: the reader icon will not be shown - QMetaObject::invokeMethod(mWidget, "updateContent", Qt::QueuedConnection); -} - - -SetupAssistantWizard::SetupAssistantWizard(QWidget* pParent) - : QWizard(pParent) - , mPageCount(0) - , mNoScriptFinder() - , mSaveHistoryCheckBox(new QCheckBox(this)) - , mChangeTransportPinButton() -{ - setObjectName(QStringLiteral("setupAssistant")); - installEventFilter(this); - setWindowTitle(QCoreApplication::applicationName() + tr(" - setup assistant")); - setMinimumSize(700, 450); - setWizardStyle(QWizard::ClassicStyle); - setWindowModality(Qt::WindowModal); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - setOption(QWizard::NoCancelButton, false); - setAttribute(Qt::WA_DeleteOnClose); - - mPageCount = 3; - if (mNoScriptFinder.isExtensionFound()) - { - ++mPageCount; - } - - addPage(createWizardInitialPinPage()); - if (mNoScriptFinder.isExtensionFound()) - { - addPage(createWizardNoScriptExtensionPage()); - } - addPage(createWizardCardReaderPage()); - addPage(createConclusionPage()); -} - - -SetupAssistantWizard::~SetupAssistantWizard() -{ -} - - -QWizardPage* SetupAssistantWizard::createWizardInitialPinPage() -{ - QWizardPage* initialPinPage = new QWizardPage; - initialPinPage->setTitle(tr("
Step %1 of %2
Introduction
").arg(this->pageIds().size() + 1).arg(mPageCount)); - - QLabel* label = new QLabel(tr("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.").arg(mPageCount)); - label->setWordWrap(true); - label->setFocusPolicy(Qt::TabFocus); - label->setAccessibleName(tr("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.").arg(this->pageIds().size() + 1).arg(mPageCount)); - - GuiUtils::updateFontSize(label); - - QVBoxLayout* initialPinPageLayout = new QVBoxLayout; - initialPinPageLayout->addWidget(label); - - - QLabel* historyDescLabel = new QLabel(tr("
History

AusweisApp2 offers saving the course of your authentications in a history. Subsequently you can activate this option.")); - historyDescLabel->setWordWrap(true); - historyDescLabel->setFocusPolicy(Qt::TabFocus); - historyDescLabel->setAccessibleName(tr("History. AusweisApp2 offers saving the course of your authentications in a history. Subsequently you can activate this option.")); - - GuiUtils::updateFontSize(historyDescLabel); - - initialPinPageLayout->addWidget(historyDescLabel); - - QWidget* saveHistoryWidget = new QWidget(this); - - QSizePolicy saveHistorySizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - saveHistorySizePolicy.setHorizontalStretch(0); - saveHistorySizePolicy.setVerticalStretch(0); - saveHistorySizePolicy.setHeightForWidth(saveHistoryWidget->sizePolicy().hasHeightForWidth()); - saveHistoryWidget->setSizePolicy(saveHistorySizePolicy); - - QFormLayout* saveHistoryFormLayout = new QFormLayout(saveHistoryWidget); - saveHistoryFormLayout->setHorizontalSpacing(30); - saveHistoryFormLayout->setContentsMargins(11, 11, 11, 11); - saveHistoryFormLayout->setContentsMargins(0, 5, 0, 20); - - QLabel* saveHistoryLabel = new QLabel(); - saveHistoryLabel->setFocusPolicy(Qt::TabFocus); - saveHistoryLabel->setText(tr("History:")); - - GuiUtils::updateFontSize(saveHistoryLabel); - - mSaveHistoryCheckBox->setText(tr("save")); - mSaveHistoryCheckBox->setAccessibleName(tr("save history")); - mSaveHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); - - GuiUtils::updateFontSize(mSaveHistoryCheckBox); - - saveHistoryFormLayout->setWidget(0, QFormLayout::LabelRole, saveHistoryLabel); - saveHistoryFormLayout->setWidget(0, QFormLayout::FieldRole, mSaveHistoryCheckBox); - - initialPinPageLayout->addWidget(saveHistoryWidget); - - initialPinPage->setLayout(initialPinPageLayout); - - return initialPinPage; -} - - -QWizardPage* SetupAssistantWizard::createWizardCardReaderPage() -{ - // return new CardReaderPage(pageIds().size() + 1, mPageCount, this); - - QWizardPage* cardReaderPage = new QWizardPage; - cardReaderPage->setTitle(tr("
Step %1 of %2
Card Reader
").arg(this->pageIds().size() + 1).arg(mPageCount)); - - QVBoxLayout* cardReaderPageVLayout = new QVBoxLayout(cardReaderPage); - QLabel* cardReaderlDescLabel = new QLabel(tr("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.")); - cardReaderlDescLabel->setWordWrap(true); - cardReaderlDescLabel->setFocusPolicy(Qt::TabFocus); - cardReaderlDescLabel->setAccessibleName(tr("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.").arg(this->pageIds().size() + 1).arg(mPageCount)); - - GuiUtils::updateFontSize(cardReaderlDescLabel); - - cardReaderPageVLayout->addWidget(cardReaderlDescLabel); - - QGridLayout* readerGridLayout = new QGridLayout(); - readerGridLayout->setSpacing(6); - readerGridLayout->setContentsMargins(0, 0, 0, 0); - - //table - QTableWidget* cardReaderTable = new QTableWidget(); - cardReaderTable->setFrameShadow(QFrame::Plain); - cardReaderTable->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); - cardReaderTable->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - cardReaderTable->setAutoScroll(true); - cardReaderTable->setLineWidth(1); - cardReaderTable->setSelectionMode(QAbstractItemView::SingleSelection); - cardReaderTable->setSelectionBehavior(QAbstractItemView::SelectRows); - cardReaderTable->setShowGrid(false); - cardReaderTable->setTabKeyNavigation(false); - - cardReaderTable->horizontalHeader()->setVisible(false); - cardReaderTable->verticalHeader()->setVisible(false); - - //columns - cardReaderTable->setColumnCount(3); - QTableWidgetItem* readerHeaderItem = new QTableWidgetItem(); - readerHeaderItem->setText(tr("Reader")); - cardReaderTable->setHorizontalHeaderItem(0, readerHeaderItem); - - QTableWidgetItem* manufacturerHeaderItem = new QTableWidgetItem(); - manufacturerHeaderItem->setText(tr("Name / Manufacturer")); - cardReaderTable->setHorizontalHeaderItem(1, manufacturerHeaderItem); - - QTableWidgetItem* webPageHeaderItem = new QTableWidgetItem(); - webPageHeaderItem->setText(tr("Web page")); - cardReaderTable->setHorizontalHeaderItem(2, webPageHeaderItem); - - //rows - cardReaderTable->setRowCount(13); - addReader(cardReaderTable, 0, ReaderType::ACS_ACR1281_PICC_Reader); - addReader(cardReaderTable, 1, ReaderType::FEIG_OBID_myAXXESS_basic); - addReader(cardReaderTable, 2, ReaderType::Gemalto_Prox_DU); - addReader(cardReaderTable, 3, ReaderType::Gemalto_Prox_SU); - addReader(cardReaderTable, 4, ReaderType::OMNIKEY_4121_CL); - addReader(cardReaderTable, 5, ReaderType::OMNIKEY_CardMan_5x21_CL); - addReader(cardReaderTable, 6, ReaderType::KOBIL_IDToken); - addReader(cardReaderTable, 7, ReaderType::REINER_cyberJack_RFID_basis); - addReader(cardReaderTable, 8, ReaderType::REINER_cyberJack_RFID_standard); - addReader(cardReaderTable, 9, ReaderType::REINER_cyberJack_RFID_komfort); - addReader(cardReaderTable, 10, ReaderType::REINER_cyberJack_wave); - addReader(cardReaderTable, 11, ReaderType::SCM_SCL011_Contactless_Reader); - addReader(cardReaderTable, 12, ReaderType::SCM_SDI011); - - cardReaderTable->resizeRowsToContents(); - cardReaderTable->horizontalHeader()->setStretchLastSection(true); - - readerGridLayout->addWidget(cardReaderTable, 0, 0, 1, 1); - - cardReaderPageVLayout->addLayout(readerGridLayout); - - return cardReaderPage; -} - - -void SetupAssistantWizard::addReader(QTableWidget* pTableWidget, int pRow, ReaderType pReaderType) -{ - QLabel* manufacturerLabel = new QLabel(); - manufacturerLabel->setWordWrap(true); - manufacturerLabel->setMargin(3); - manufacturerLabel->setFocusPolicy(Qt::TabFocus); - - QString manufacturerWebPage; - - switch (pReaderType) - { - case ReaderType::REINER_cyberJack_RFID_komfort: - manufacturerLabel->setText(QStringLiteral("Reiner SCT
cyberJack RFID komfort")); - manufacturerWebPage = QStringLiteral("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5"); - break; - - case ReaderType::REINER_cyberJack_RFID_standard: - manufacturerLabel->setText(QStringLiteral("Reiner SCT
cyberJack RFID standard")); - manufacturerWebPage = QStringLiteral("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304820&q=driver#choice5"); - break; - - case ReaderType::REINER_cyberJack_RFID_basis: - manufacturerLabel->setText(QStringLiteral("Reiner SCT
cyberJack RFID basis")); - manufacturerWebPage = QStringLiteral("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304856&q=driver#choice5"); - break; - - case ReaderType::REINER_cyberJack_wave: - manufacturerLabel->setText(QStringLiteral("Reiner SCT
cyberJack wave")); - manufacturerWebPage = QStringLiteral("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304828&q=driver#choice5"); - break; - - case ReaderType::SCM_SCL011_Contactless_Reader: - manufacturerLabel->setText(QStringLiteral("Identive
Identive SCL011")); - manufacturerWebPage = QStringLiteral("https://support.identiv.com/scl010-scl011/"); - break; - - case ReaderType::SCM_SDI010: - case ReaderType::SCM_SDI011: - manufacturerLabel->setText(QStringLiteral("Identive
Identive SDI011")); - manufacturerWebPage = QStringLiteral("https://support.identiv.com/sdi010-011/"); - break; - - case ReaderType::KOBIL_IDToken: - manufacturerLabel->setText(QStringLiteral("Kobil
Kobil ID Token")); - manufacturerWebPage = QStringLiteral("https://www.kobil.com/de/support_de/#drivers_de"); - break; - - case ReaderType::ACS_ACR1281_PICC_Reader: - manufacturerLabel->setText(QStringLiteral("ACS
ACR1281U")); - manufacturerWebPage = QStringLiteral("http://www.idvation.com/support/faq/4-contactless-readers/acr128/?tx_irfaq_pi1%5Bcat%5D=10"); - break; - - case ReaderType::OMNIKEY_CardMan_5x21_CL: - manufacturerLabel->setText(QStringLiteral("HID Global GmbH
OMNIKEY 5321 V2")); - manufacturerWebPage = QStringLiteral("https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All"); - - break; - - case ReaderType::OMNIKEY_4121_CL: - manufacturerLabel->setText(QStringLiteral("HID Global GmbH
OMNIKEY 4121 CL")); - manufacturerWebPage = QStringLiteral("https://www.hidglobal.com/drivers?field_brand_tid=24&product_id=4077&os=All"); - - break; - - case ReaderType::FEIG_OBID_myAXXESS_basic: - manufacturerLabel->setText(QStringLiteral("FEIG electronic GmbH
myAXXESS basic")); - manufacturerWebPage = QStringLiteral("http://www.feig.de/downloads/"); - break; - - case ReaderType::Gemalto_Prox_SU: - manufacturerLabel->setText(QStringLiteral("Gemalto
Prox-SU")); - manufacturerWebPage = QStringLiteral("http://support.gemalto.com/index.php?id=prox-du_prox-su#.WOIQijvyjyQ"); - break; - - case ReaderType::Gemalto_Prox_DU: - manufacturerLabel->setText(QStringLiteral("Gemalto
Prox-DU")); - manufacturerWebPage = QStringLiteral("http://support.gemalto.com/index.php?id=prox-du_prox-su#.WOIQijvyjyQ"); - break; - - case ReaderType::UNKNOWN: - break; - } - - QLabel* readerIconLabel = new QLabel(); - readerIconLabel->setAccessibleName(tr("reader icon")); - readerIconLabel->setFocusPolicy(Qt::TabFocus); - readerIconLabel->setAlignment(Qt::AlignCenter); - QPixmap emptyReaderPixmap(SmartCardUtil::getReaderEmptyIconPath(pReaderType)); - readerIconLabel->setPixmap(emptyReaderPixmap.scaledToWidth(100, Qt::SmoothTransformation)); - - pTableWidget->setCellWidget(pRow, 0, readerIconLabel); - - manufacturerLabel->setAccessibleName(tr("Name / Manufacturer") + manufacturerLabel->text()); - - GuiUtils::updateFontSize(manufacturerLabel); - - pTableWidget->setCellWidget(pRow, 1, manufacturerLabel); - - QLabel* webPageLabel = new QLabel("" + manufacturerWebPage + ""); - webPageLabel->setWordWrap(true); - webPageLabel->setFocusPolicy(Qt::TabFocus); - webPageLabel->setTextFormat(Qt::RichText); - webPageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - webPageLabel->setOpenExternalLinks(true); - - GuiUtils::updateFontSize(webPageLabel); - - pTableWidget->setCellWidget(pRow, 2, webPageLabel); -} - - -QWizardPage* SetupAssistantWizard::createWizardNoScriptExtensionPage() -{ - QWizardPage* wizardPage = new QWizardPage; - wizardPage->setTitle(tr("
Step %1 of %2
Firefox extension NoScript
").arg(this->pageIds().size() + 1).arg(mPageCount)); - - QString descriptionText = tr("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.").arg(QCoreApplication::applicationName()); - QLabel* label = new QLabel(descriptionText); - label->setWordWrap(true); - label->setFocusPolicy(Qt::TabFocus); - label->setAccessibleName(tr("Firefox extension NoScript Step %1 of %2.").arg(this->pageIds().size() + 1).arg(mPageCount) + descriptionText); - - GuiUtils::updateFontSize(label); - - QVBoxLayout* pageLayout = new QVBoxLayout; - pageLayout->addWidget(label); - wizardPage->setLayout(pageLayout); - - return wizardPage; -} - - -QWizardPage* SetupAssistantWizard::createConclusionPage() -{ - QWizardPage* conclusionPage = new QWizardPage; - conclusionPage->setTitle(tr("
Step %1 of %2
Almost done!
").arg(this->pageIds().size() + 1).arg(mPageCount)); - - QVBoxLayout* conclusionPageVLayout = new QVBoxLayout(conclusionPage); - - 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 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 your competent authority.")); - - GuiUtils::updateFontSize(transportPinLabel); - - conclusionPageVLayout->addWidget(transportPinLabel); - - mChangeTransportPinButton = new QPushButton(conclusionPage); - mChangeTransportPinButton->setText(tr("Change PIN")); - connect(mChangeTransportPinButton.data(), &QAbstractButton::clicked, this, &SetupAssistantWizard::onChangeTransportPinButtonPressed); - - QSizePolicy transportPinSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - transportPinSizePolicy.setHorizontalStretch(0); - transportPinSizePolicy.setVerticalStretch(0); - transportPinSizePolicy.setHeightForWidth(mChangeTransportPinButton->sizePolicy().hasHeightForWidth()); - mChangeTransportPinButton->setSizePolicy(transportPinSizePolicy); - - conclusionPageVLayout->addWidget(mChangeTransportPinButton); - - - QLabel* conclusionDescLabel = new QLabel(tr("
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.")); - conclusionDescLabel->setWordWrap(true); - conclusionDescLabel->setFocusPolicy(Qt::TabFocus); - conclusionDescLabel->setAccessibleName(tr("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.").arg(this->pageIds().size() + 1).arg(mPageCount)); - - GuiUtils::updateFontSize(conclusionDescLabel); - - conclusionPageVLayout->addWidget(conclusionDescLabel); - - QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - conclusionPageVLayout->addItem(verticalSpacer); - - return conclusionPage; -} - - -void SetupAssistantWizard::onChangeTransportPinButtonPressed() -{ - AppSettings::getInstance().getHistorySettings().setEnabled(mSaveHistoryCheckBox->isChecked()); - Q_EMIT fireChangePinButtonClicked(); - close(); -} - - -void SetupAssistantWizard::accept() -{ - AppSettings::getInstance().getHistorySettings().setEnabled(mSaveHistoryCheckBox->isChecked()); - hide(); -} - - -bool SetupAssistantWizard::eventFilter(QObject* pObject, QEvent* pEvent) -{ - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_F1) - { - HelpAction::openContextHelp(this->objectName()); - return true; - } - } - return QWizard::eventFilter(pObject, pEvent); -} diff --git a/src/gui/SetupAssistantWizard.h b/src/gui/SetupAssistantWizard.h deleted file mode 100644 index d668e4b..0000000 --- a/src/gui/SetupAssistantWizard.h +++ /dev/null @@ -1,85 +0,0 @@ -/*! - * SetupAssistantWizard.h - * - * \brief Setup assistant wizard before application startup. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "GeneralSettingsWidget.h" -#include "NoScriptFinder.h" -#include "SmartCardDefinitions.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace governikus -{ - -class SetupAssistantWizard; -class ReaderDriverWidget; - -class TabButton; - -class CardReaderPage - : public QWizardPage -{ - Q_OBJECT - - public: - CardReaderPage(int pStepIndex, int pPageCount, SetupAssistantWizard* pWizard); - - virtual ~CardReaderPage(); - - virtual void initializePage() override; - - ReaderDriverWidget* const mWidget; -}; - - -class SetupAssistantWizard - : public QWizard -{ - Q_OBJECT - - int mPageCount; - NoScriptFinder mNoScriptFinder; - QPointer mSaveHistoryCheckBox; - QPointer mChangeTransportPinButton; - - public: - SetupAssistantWizard(QWidget* pParent = nullptr); - virtual ~SetupAssistantWizard(); - - virtual void accept() override; - bool isRemindWizardAgain(); - - Q_SIGNALS: - void fireChangePinButtonClicked(); - - private: - QWizardPage* createWizardInitialPinPage(); - QWizardPage* createWizardCardReaderPage(); - QWizardPage* createWizardNoScriptExtensionPage(); - QWizardPage* createConclusionPage(); - - void addReader(QTableWidget* pTableWidget, int pRow, ReaderType pReaderType); - - private Q_SLOTS: - void onChangeTransportPinButtonPressed(); - - protected: - virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; - -}; - -} /* namespace governikus */ diff --git a/src/gui/UIPlugInWidgets.cpp b/src/gui/UIPlugInWidgets.cpp deleted file mode 100644 index 406e3ff..0000000 --- a/src/gui/UIPlugInWidgets.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "UIPlugInWidgets.h" - -#include "ApplicationModel.h" -#include "workflow/WorkflowAuthenticateQtGui.h" -#include "workflow/WorkflowChangePinQtGui.h" -#include "workflow/WorkflowSelfInfoQtGui.h" - -using namespace governikus; - -UIPlugInWidgets::UIPlugInWidgets() - : UIPlugIn() - , mGui() -{ - connect(&mGui, &AppQtGui::quitApplicationRequested, this, &UIPlugIn::fireQuitApplicationRequest); - connect(&mGui, &AppQtGui::fireChangePinRequested, this, &UIPlugIn::fireChangePinRequest); - connect(&mGui, &AppQtGui::selfAuthenticationRequested, this, &UIPlugIn::fireSelfAuthenticationRequested); - connect(&mGui, &AppQtGui::fireCloseReminderFinished, this, &UIPlugInWidgets::fireCloseReminderFinished); - connect(this, &UIPlugIn::fireShowUserInformation, &mGui, &AppQtGui::onShowUserInformation); - mGui.init(); -} - - -UIPlugInWidgets::~UIPlugInWidgets() -{ -} - - -void UIPlugInWidgets::doShutdown() -{ - mGui.shutdown(); -} - - -void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext) -{ - pContext->setReaderType(ReaderManagerPlugInType::PCSC); - ApplicationModel::getWidgetInstance().resetContext(pContext); - - QSharedPointer currentWorkflowGui; - if (auto changePinContext = pContext.objectCast()) - { - currentWorkflowGui = mGui.createWorkflowChangePinUi(changePinContext); - mGui.activateWorkflowUi(currentWorkflowGui); - return; - } - - bool allowHideAfterWorklow = true; - if (auto selfAuthContext = pContext.objectCast()) - { - if (mGui.askChangeTransportPinNow()) - { - allowHideAfterWorklow = false; - Q_EMIT pContext->fireCancelWorkflow(); - } - currentWorkflowGui = mGui.createWorkflowSelfInfoUi(selfAuthContext); - } - else if (auto authContext = pContext.objectCast()) - { - if (mGui.askChangeTransportPinNow()) - { - allowHideAfterWorklow = false; - Q_EMIT pContext->fireCancelWorkflow(); - } - currentWorkflowGui = mGui.createWorkflowAuthenticateUi(authContext); - } - - Q_ASSERT(currentWorkflowGui != nullptr); - mGui.activateWorkflowUi(currentWorkflowGui, allowHideAfterWorklow); - pContext->setStateApproved(); -} - - -void UIPlugInWidgets::onWorkflowFinished(QSharedPointer pContext) -{ - Q_UNUSED(pContext) - ApplicationModel::getWidgetInstance().resetContext(); - mGui.deactivateCurrentWorkflowUi(); -} - - -void UIPlugInWidgets::onApplicationStarted() -{ - mGui.onApplicationStarted(); -} - - -void UIPlugInWidgets::onShowUi(UiModule pModule) -{ - mGui.show(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 deleted file mode 100644 index 77ffd41..0000000 --- a/src/gui/UIPlugInWidgets.h +++ /dev/null @@ -1,42 +0,0 @@ -/*! - * \brief QWidgets implementation of UIPlugIn. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppQtGui.h" -#include "view/UIPlugIn.h" - -namespace governikus -{ - -class AppQtGui; - -class UIPlugInWidgets - : public UIPlugIn -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "governikus.UIPlugIn" FILE "metadata.json") - Q_INTERFACES(governikus::UIPlugIn) - - private: - AppQtGui mGui; - - public: - UIPlugInWidgets(); - virtual ~UIPlugInWidgets(); - - public Q_SLOTS: - virtual void doShutdown() override; - virtual void onWorkflowStarted(QSharedPointer pContext) override; - 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 deleted file mode 100644 index 13ce852..0000000 --- a/src/gui/UpdateWindow.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "UpdateWindow.h" - -#include "ui_UpdateWindow.h" -#include "Updater.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 deleted file mode 100644 index b29f1bf..0000000 --- a/src/gui/UpdateWindow.h +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * \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/gui/UpdateWindow.ui b/src/gui/UpdateWindow.ui deleted file mode 100644 index e564ba6..0000000 --- a/src/gui/UpdateWindow.ui +++ /dev/null @@ -1,182 +0,0 @@ - - - UpdateWindow - - - Qt::ApplicationModal - - - - 0 - 0 - 600 - 450 - - - - Software Update - - - - :/images/npa.svg:/images/npa.svg - - - - - - - - - 75 - true - - - - Qt::TabFocus - - - A new version of AusweisApp2 is available! - - - - - - - Qt::TabFocus - - - AusweisApp2 %1 is now available - you have %2. Would you like to download it now? - - - - - - - Qt::TabFocus - - - The update file is located at: - - - - - - - Qt::TabFocus - - - <a href="%1">%1</a> - - - true - - - Qt::TextBrowserInteraction - - - - - - - - 75 - true - - - - Qt::TabFocus - - - Release Notes: - - - - - - - 160 - 80 - - - - Qt::WheelFocus - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse - - - - - - - - - - Qt::TabFocus - - - Download this update and close current "AusweisApp2". Install the update and start "AusweisApp2" again. - - - - - - - Qt::TabFocus - - - When you click "Download update", this link will be opened in your browser. - - - - - - - - - Skip update - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Remind me later - - - - - - - Download update - - - true - - - true - - - - - - - - - - - - diff --git a/src/gui/generic/BusyOverlay.cpp b/src/gui/generic/BusyOverlay.cpp deleted file mode 100644 index 8a9f1ad..0000000 --- a/src/gui/generic/BusyOverlay.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/*! - * BusyOverlay.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "BusyOverlay.h" -#include "ui_BusyOverlay.h" - -#include -#include -#include -#include -#include - -using namespace governikus; - -BusyOverlay::BusyOverlay(bool pStart, QWidget* pParent) - : QWidget(pParent) - , mUi(new Ui::BusyOverlay()) - , mMovie(new QMovie(QStringLiteral(":/images/busy_animation.gif"))) -{ - mUi->setupUi(this); - - mUi->busyAnimationLabel->setMovie(mMovie.data()); - - setStyleSheet(QStringLiteral("background-color: white;")); - - QGraphicsOpacityEffect* opacity = new QGraphicsOpacityEffect(this); - opacity->setOpacity(0.9); - setGraphicsEffect(opacity); - - if (pStart) - { - mMovie->start(); - } -} - - -BusyOverlay::~BusyOverlay() -{ -} - - -void BusyOverlay::startAnimation() -{ - if (mMovie->state() != QMovie::Running) - { - mMovie->start(); - } -} - - -void BusyOverlay::stopAnimation() -{ - if (mMovie->state() == QMovie::Running) - { - mMovie->stop(); - } -} - - -QSize BusyOverlay::sizeHint() const -{ - // make square - QSize hint = QWidget::sizeHint(); - int result = std::max(hint.width(), hint.height()); - return QSize(result, result); -} - - -void BusyOverlay::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/generic/BusyOverlay.h b/src/gui/generic/BusyOverlay.h deleted file mode 100644 index 0399d49..0000000 --- a/src/gui/generic/BusyOverlay.h +++ /dev/null @@ -1,46 +0,0 @@ -/*! - * BusyOverlay.h - * - * \brief Widget for the settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class BusyOverlay; -} - -class QMovie; - -namespace governikus -{ - -class BusyOverlay - : public QWidget -{ - Q_OBJECT - - public: - BusyOverlay(bool pStart = true, QWidget* pParent = nullptr); - virtual ~BusyOverlay(); - - void startAnimation(); - void stopAnimation(); - - virtual QSize sizeHint() const override; - - protected: - void paintEvent(QPaintEvent*) override; - - private: - QScopedPointer mUi; - QScopedPointer mMovie; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/BusyOverlayContainer.cpp b/src/gui/generic/BusyOverlayContainer.cpp deleted file mode 100644 index 1cf67a7..0000000 --- a/src/gui/generic/BusyOverlayContainer.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * BusyOverlayContainer.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "BusyOverlayContainer.h" - -#include -#include - -#include "BusyOverlay.h" - -using namespace governikus; - -BusyOverlayContainer::BusyOverlayContainer(QWidget* pWidgetToOverlay, bool pStart, QWidget* pParent) - : QStackedWidget(pParent) - , mOverlay(new BusyOverlay(pStart)) -{ - QWidget* busyOverlayContainer = new QWidget; - QBoxLayout* overlayContainerLayout = new QVBoxLayout(busyOverlayContainer); - overlayContainerLayout->addWidget(mOverlay, 0, Qt::AlignHCenter | Qt::AlignVCenter); - - QStackedLayout* stackLayout = qobject_cast(layout()); - stackLayout->setStackingMode(QStackedLayout::StackAll); - - stackLayout->addWidget(pWidgetToOverlay); - stackLayout->addWidget(busyOverlayContainer); - stackLayout->setCurrentIndex(1); -} - - -BusyOverlayContainer::~BusyOverlayContainer() -{ -} - - -void BusyOverlayContainer::startAnimation() -{ - mOverlay->startAnimation(); -} - - -void BusyOverlayContainer::stopAnimation() -{ - mOverlay->stopAnimation(); -} diff --git a/src/gui/generic/BusyOverlayContainer.h b/src/gui/generic/BusyOverlayContainer.h deleted file mode 100644 index 67a741c..0000000 --- a/src/gui/generic/BusyOverlayContainer.h +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * BusyOverlayContainer.h - * - * \brief A page in a mobile GUI. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -namespace governikus -{ - -class BusyOverlay; - -class BusyOverlayContainer - : public QStackedWidget -{ - Q_OBJECT - - public: - BusyOverlayContainer(QWidget* pWidgetToOverlay, bool pStart = true, QWidget* pParent = nullptr); - virtual ~BusyOverlayContainer(); - - void startAnimation(); - void stopAnimation(); - - private: - BusyOverlay* mOverlay; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ButtonState.h b/src/gui/generic/ButtonState.h deleted file mode 100644 index 0c36a28..0000000 --- a/src/gui/generic/ButtonState.h +++ /dev/null @@ -1,29 +0,0 @@ -/*! - * ButtonState.h - * - * \brief Defines the ButtonState enum. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -namespace governikus -{ - -enum class ButtonState -{ - /*! Button is visible, enabled, and focussed. */ - FOCUSSED, - - /*! Button is visible and enabled. */ - ENABLED, - - /*! Button is visible and disabled. */ - DISABLED, - - /*! Button is not visible. */ - HIDDEN -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/DescriptionLabel.cpp b/src/gui/generic/DescriptionLabel.cpp deleted file mode 100644 index 1406701..0000000 --- a/src/gui/generic/DescriptionLabel.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * DescriptionLabel.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "DescriptionLabel.h" -#include "GuiUtils.h" - -using namespace governikus; - -DescriptionLabel::DescriptionLabel(QWidget* pParent, Qt::WindowFlags pFlags) - : QLabel(pParent, pFlags) -{ - GuiUtils::updateFontSize(this); -} - - -DescriptionLabel::DescriptionLabel(const QString& pText, QWidget* pParent, Qt::WindowFlags pFlags) - : QLabel(pText, pParent, pFlags) -{ - GuiUtils::updateFontSize(this); -} - - -DescriptionLabel::~DescriptionLabel() -{ -} diff --git a/src/gui/generic/DescriptionLabel.h b/src/gui/generic/DescriptionLabel.h deleted file mode 100644 index a1125a0..0000000 --- a/src/gui/generic/DescriptionLabel.h +++ /dev/null @@ -1,29 +0,0 @@ -/*! - * DescriptionLabel.h - * - * \brief QLabel subclass used for description texts. - * - * Its only purpose is to serve as a class name for styling. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -namespace governikus -{ - -class DescriptionLabel - : public QLabel -{ - Q_OBJECT - - public: - DescriptionLabel(QWidget* pParent = nullptr, Qt::WindowFlags pFlags = 0); - DescriptionLabel(const QString& pText, QWidget* pParent = nullptr, Qt::WindowFlags pFlags = 0); - virtual ~DescriptionLabel(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ExclusiveButtonGroup.cpp b/src/gui/generic/ExclusiveButtonGroup.cpp deleted file mode 100644 index f703f8c..0000000 --- a/src/gui/generic/ExclusiveButtonGroup.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/*! - * ExclusiveButtonGroup.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ExclusiveButtonGroup.h" - -#include -#include - -using namespace governikus; - -ExclusiveButtonGroup::ExclusiveButtonGroup(QObject* pParent) - : QObject(pParent) - , mButtons() -{ -} - - -ExclusiveButtonGroup::~ExclusiveButtonGroup() -{ -} - - -void ExclusiveButtonGroup::addButton(QAbstractButton* pButton) -{ - mButtons += pButton; - - pButton->installEventFilter(this); - - connect(pButton, &QAbstractButton::clicked, this, &ExclusiveButtonGroup::onButtonClicked); - connect(pButton, &QAbstractButton::pressed, this, &ExclusiveButtonGroup::onButtonPressed); - connect(pButton, &QAbstractButton::released, this, &ExclusiveButtonGroup::onButtonReleased); - connect(pButton, &QAbstractButton::toggled, this, &ExclusiveButtonGroup::onButtonToggled); -} - - -void ExclusiveButtonGroup::removeButton(QAbstractButton* pButton) -{ - if (mButtons.removeAll(pButton) == 0) - { - return; - } - - pButton->removeEventFilter(this); - - disconnect(pButton, &QAbstractButton::clicked, this, &ExclusiveButtonGroup::onButtonClicked); - disconnect(pButton, &QAbstractButton::pressed, this, &ExclusiveButtonGroup::onButtonPressed); - disconnect(pButton, &QAbstractButton::released, this, &ExclusiveButtonGroup::onButtonReleased); - disconnect(pButton, &QAbstractButton::toggled, this, &ExclusiveButtonGroup::onButtonToggled); -} - - -bool ExclusiveButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) -{ - if (QAbstractButton* button = qobject_cast(pWatched)) - { - if (pEvent->type() == QEvent::MouseButtonPress && button->isChecked()) - { - return true; - } - - if (pEvent->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(pEvent); - if (keyEvent->key() == Qt::Key_Select || keyEvent->key() == Qt::Key_Space) - { - return true; - } - } - } - - return false; -} - - -void ExclusiveButtonGroup::onButtonClicked(bool /*pChecked*/) -{ - if (QAbstractButton* button = qobject_cast(sender())) - { - Q_EMIT buttonClicked(button); - } -} - - -void ExclusiveButtonGroup::onButtonPressed() -{ - if (QAbstractButton* button = qobject_cast(sender())) - { - Q_EMIT buttonPressed(button); - } -} - - -void ExclusiveButtonGroup::onButtonReleased() -{ - if (QAbstractButton* button = qobject_cast(sender())) - { - Q_EMIT buttonReleased(button); - } -} - - -void ExclusiveButtonGroup::onButtonToggled(bool pChecked) -{ - if (QAbstractButton* button = qobject_cast(sender())) - { - if (pChecked) - { - for (auto otherButton : qAsConst(mButtons)) - { - if (otherButton != button && otherButton->isChecked()) - { - otherButton->setChecked(false); - } - } - } - - Q_EMIT buttonToggled(button, pChecked); - } -} diff --git a/src/gui/generic/ExclusiveButtonGroup.h b/src/gui/generic/ExclusiveButtonGroup.h deleted file mode 100644 index 2ae70dd..0000000 --- a/src/gui/generic/ExclusiveButtonGroup.h +++ /dev/null @@ -1,58 +0,0 @@ -/*! - * ExclusiveButtonGroup.h - * - * \brief Rudimentary replacement for QButtonGroup to work around tab navigation issues. - * - * Bug in Qt 5.2.1: Buttons in a QButtonGroup cannot be navigated via the Tab key. This - * class provides a work-around for simple cases. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -class QAbstractButton; - -namespace governikus -{ - -class ExclusiveButtonGroup - : public QObject -{ - Q_OBJECT - - public: - ExclusiveButtonGroup(QObject* pParent = nullptr); - virtual ~ExclusiveButtonGroup(); - - const QVector& getButtons() const - { - return mButtons; - } - - - void addButton(QAbstractButton* pButton); - void removeButton(QAbstractButton* pButton); - - virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; - - Q_SIGNALS: - void buttonClicked(QAbstractButton* pButton); - void buttonPressed(QAbstractButton* pButton); - void buttonReleased(QAbstractButton* pButton); - void buttonToggled(QAbstractButton* pButton, bool pChecked); - - private Q_SLOTS: - void onButtonClicked(bool pChecked); - void onButtonPressed(); - void onButtonReleased(); - void onButtonToggled(bool pChecked); - - private: - QVector mButtons; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/GuiModule.h b/src/gui/generic/GuiModule.h deleted file mode 100644 index 78b1069..0000000 --- a/src/gui/generic/GuiModule.h +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * GuiModule.h - * - * \brief Defines the GuiModule enum. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -namespace governikus -{ - -enum class GuiModule -{ - START_PAGE, - GENERAL_SETTINGS, - PIN_SETTINGS, -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/GuiUtils.cpp b/src/gui/generic/GuiUtils.cpp deleted file mode 100644 index ab066e3..0000000 --- a/src/gui/generic/GuiUtils.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/*! - * GuiUtils.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "GuiUtils.h" - -#include -#include -#include -#include - -using namespace governikus; - -void GuiUtils::setFontBold(QWidget* pWidget, bool pBold) -{ - QFont font = pWidget->font(); - if (pBold != font.bold()) - { - font.setBold(pBold); - pWidget->setFont(font); - } -} - - -QFrame* GuiUtils::createLine(bool pHorizontal) -{ - QFrame* line = new QFrame; - line->setFrameShape(pHorizontal ? QFrame::HLine : QFrame::VLine); - return line; -} - - -void GuiUtils::showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent) -{ - QMessageBox messageBox(pParent); - QString title; - QString text; - switch (pReturnCode) - { - 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 CardReturnCode::INVALID_PUK: - title = tr("Wrong PUK"); - text = tr("Please enter your PUK again."); - break; - - 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 your" - " competent authority that has issued your ID card for unblocking your PIN."); - break; - - case CardReturnCode::INVALID_PIN: - default: - title = tr("Wrong PIN"); - break; - } - - if (text.isEmpty()) - { - switch (pRetryCounter) - { - case 0: - text = tr("After three wrong entries your PIN is blocked. Using the online identification" - " function is no longer possible.

You can unblock your PIN in the" - " following dialog. The program supports you with the steps now required."); - break; - - case 1: - text = tr("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)."); - break; - - default: - text = tr("The given PIN is not correct. You have %1 tries to enter the correct PIN.").arg(pRetryCounter); - break; - } - } - - messageBox.setWindowTitle(QCoreApplication::applicationName() + " - " + title); - messageBox.setWindowModality(Qt::WindowModal); - messageBox.setText(QStringLiteral("

%1

%2

").arg(title, text)); - messageBox.setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); - messageBox.setStandardButtons(QMessageBox::StandardButton::Ok); - - messageBox.exec(); -} - - -bool GuiUtils::showWrongPinBlockedDialog(QWidget* pParent) -{ - QMessageBox messageBox(pParent); - - QString title = tr("PIN blocked"); - QString text = tr("After three wrong entries your PIN is blocked. Using the online identification" - " function is no longer possible.
You can unblock the PIN as" - " follows:
  1. Select the \"Settings\" function.
  2. Select the \"PIN" - " Management\" tab.
  3. Follow the instructions on the" - " screen.
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 http://www.personalausweisportal.de.
" - "Do you want to unblock the PIN now?"); - messageBox.setWindowTitle(QCoreApplication::applicationName() + " - " + title); - messageBox.setWindowModality(Qt::WindowModal); - messageBox.setText(QStringLiteral("

%1

%2

").arg(title, text)); - messageBox.setIcon(QMessageBox::Warning); - - messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); - return messageBox.exec() == QMessageBox::Yes; -} - - -void GuiUtils::updateFontSize(QWidget* pWidget) -{ -#ifdef Q_OS_OSX - return; - -#endif - - const qreal factor = 1.2; - - QFont newFont = pWidget->font(); - - if (newFont.pixelSize() > 0) - { - // resize by factor, but add at least one pixel - int newPixelSize = qRound(newFont.pixelSize() * factor); - if (newPixelSize == newFont.pixelSize()) - { - newPixelSize += 1; - } - - newFont.setPixelSize(newPixelSize); - } - else - { - newFont.setPointSizeF(newFont.pointSizeF() * factor); - } - - pWidget->setFont(newFont); -} diff --git a/src/gui/generic/GuiUtils.h b/src/gui/generic/GuiUtils.h deleted file mode 100644 index 6e27b77..0000000 --- a/src/gui/generic/GuiUtils.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * GuiUtils.h - * - * \brief Gui utility functions. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -#include "CardReturnCode.h" - -class QFrame; - - -namespace governikus -{ - -class GuiUtils - : private QObject -{ - Q_OBJECT - - public: - static void setFontBold(QWidget* pWidget, bool pBold); - - static QFrame* createLine(bool pHorizontal); - - static void showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent); - static bool showWrongPinBlockedDialog(QWidget* pParent); - static void updateFontSize(QWidget* pWidget); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/HeaderBox.cpp b/src/gui/generic/HeaderBox.cpp deleted file mode 100644 index 064c3dc..0000000 --- a/src/gui/generic/HeaderBox.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "HeaderBox.h" - -#include -#include - -using namespace governikus; - -HeaderBox::HeaderBox(QWidget* pParent, Qt::WindowFlags pWindowFlags) - : QWidget(pParent, pWindowFlags) -{ -} - - -HeaderBox::~HeaderBox() -{ -} - - -void HeaderBox::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/generic/HeaderBox.h b/src/gui/generic/HeaderBox.h deleted file mode 100644 index 84ebeae..0000000 --- a/src/gui/generic/HeaderBox.h +++ /dev/null @@ -1,24 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -namespace governikus -{ - -class HeaderBox - : public QWidget -{ - Q_OBJECT - - public: - explicit HeaderBox(QWidget* pParent = nullptr, Qt::WindowFlags pWindowFlags = 0); - virtual ~HeaderBox(); - - void paintEvent(QPaintEvent*) override; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/HelpAction.cpp b/src/gui/generic/HelpAction.cpp deleted file mode 100644 index cd8ac8b..0000000 --- a/src/gui/generic/HelpAction.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*! - * HelpAction.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "HelpAction.h" - -#include "LanguageLoader.h" -#include "SingletonHelper.h" -#include "VersionNumber.h" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - -defineSingleton(HelpAction) - -Q_DECLARE_LOGGING_CATEGORY(gui) - -//Mapping object name to help file, \see AppQtMainWidget::onContentActionClicked() -const QMap HelpAction::mHelpMapping = { - {QStringLiteral("setupAssistant"), QStringLiteral("wizard-info.html")}, - {QStringLiteral("ausweisenPage"), QStringLiteral("identify.html")}, - {QStringLiteral("providerPage"), QStringLiteral("provider.html")}, - {QStringLiteral("historyPage"), QStringLiteral("history.html")}, - {QStringLiteral("generalTab"), QStringLiteral("settings-general.html")}, - {QStringLiteral("pinTab"), QStringLiteral("settings-pin-management.html")} -}; - - -HelpAction& HelpAction::getInstance() -{ - return *Instance; -} - - -QString HelpAction::getHelpPath(QLocale::Language pLang) const -{ - const QString langDir = QCoreApplication::applicationDirPath() % QStringLiteral("/help/") % QLocale(pLang).bcp47Name().mid(0, 2) % '/'; - - if (QDir(langDir).exists()) - { - return langDir; - } - - return QString(); -} - - -QLocale::Language HelpAction::getExistingHelpLanguage() const -{ - QLocale::Language lang = LanguageLoader::getInstance().getUsedLocale().language(); - if (!getHelpPath(lang).isNull()) - { - return lang; - } - - lang = LanguageLoader::getInstance().getFallbackLanguage(); - if (!getHelpPath(lang).isNull()) - { - return lang; - } - - return QLocale::AnyLanguage; -} - - -QString HelpAction::getContextMapping(const QString& pObjectName) const -{ - if (mHelpMapping.contains(pObjectName)) - { - return mHelpMapping.value(pObjectName); - } - else - { - qCWarning(gui) << "Cannot find help mapping:" << pObjectName; - } - - return QStringLiteral("index.html"); -} - - -QString HelpAction::getHelpUrl(const QString& pObjectName) const -{ - QLocale::Language lang = getExistingHelpLanguage(); - if (lang == QLocale::AnyLanguage) - { - return getOnlineUrl(); - } - - return QUrl::fromLocalFile(getHelpPath(lang)).toString() + getContextMapping(pObjectName); -} - - -QUrl HelpAction::getHelpUrlWrapper(const QString& pObjectName) const -{ - auto url = getHelpUrl(pObjectName); - if (!url.contains('#')) - { - return url; - } - - QFile file(QDir::tempPath() + QStringLiteral("/AusweisApp2_help.html")); - if (file.open(QIODevice::WriteOnly)) - { - QTextStream stream(&file); - stream << QStringLiteral("").arg(url) << endl; - } - - return QUrl::fromLocalFile(file.fileName()); -} - - -QString HelpAction::getOnlineUrl(const QString& pObjectName) const -{ -#ifdef Q_OS_OSX - const QLatin1String osPath("macOS"); -#else - const QLatin1String osPath("Windows"); -#endif - - const auto& appVersion = VersionNumber::getApplicationVersion().getVersionNumber(); - const QString ver = QString::number(appVersion.majorVersion()) % '.' % QString::number(appVersion.minorVersion()); - const QString locale = QLocale(LanguageLoader::getInstance().getUsedLocale().language()).bcp47Name().mid(0, 2); - const QString mapping = getContextMapping(pObjectName); - return QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/handbuch/") % ver % '/' % locale % '/' % osPath % '/' % mapping; -} - - -void HelpAction::openContextHelp(const QString& pObjectName) -{ - //const auto& url = getInstance().getHelpUrlWrapper(pObjectName); - const auto& url = QUrl(getInstance().getOnlineUrl(pObjectName)); - qCDebug(gui) << "Open manual:" << pObjectName << "|" << url; - QDesktopServices::openUrl(url); -} diff --git a/src/gui/generic/HelpAction.h b/src/gui/generic/HelpAction.h deleted file mode 100644 index cee6e41..0000000 --- a/src/gui/generic/HelpAction.h +++ /dev/null @@ -1,46 +0,0 @@ -/*! - * HelpAction.h - * - * \brief Helper class for mapping object name from f1 widget to help file. - * \see AppQtMainWidget::onContentActionClicked() - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -class test_HelpAction; - -namespace governikus -{ - -class HelpAction -{ - private: - friend class ::test_HelpAction; - - static const QMap mHelpMapping; - - Q_DISABLE_COPY(HelpAction) - - QLocale::Language getExistingHelpLanguage() const; - QString getContextMapping(const QString& pObjectName) const; - QString getHelpPath(QLocale::Language pLang) const; - QString getHelpUrl(const QString& pObjectName) const; - QUrl getHelpUrlWrapper(const QString& pObjectName) const; - QString getOnlineUrl(const QString& pObjectName = QString()) const; - - protected: - static HelpAction& getInstance(); - HelpAction() = default; - ~HelpAction() = default; - - public: - static void openContextHelp(const QString& pObjectName = QStringLiteral("applicationPage")); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/KeylessPasswordEdit.cpp b/src/gui/generic/KeylessPasswordEdit.cpp deleted file mode 100644 index 718828d..0000000 --- a/src/gui/generic/KeylessPasswordEdit.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/*! - * KeylessPasswordEdit.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "KeylessPasswordEdit.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace governikus; - -static const int MAX_MAX_LENGTH = 256; - - -static inline void initRandom() -{ - static int dummy = (qsrand(uint(QDateTime::currentMSecsSinceEpoch())), 0); - (void) dummy; -} - - -static int randomNumber() -{ - initRandom(); - return qrand(); -} - - -class KeylessPasswordEdit::RenderingHelper -{ - public: - RenderingHelper(QWidget* pParent) - : mParent(pParent) - , mLayoutValid(false) - , mHiddenDigitText() - , mUnsetDigitText(QStringLiteral("-")) - , mDigitPadding(4, 4, 4, 4) - , mButtonHeight(10) - , mButtonSpacing(4) - , mUpButtonRect() - , mDownButtonRect() - , mDigitRect() - , mTotalSize() - { - QLineEdit lineEdit; - lineEdit.setEchoMode(QLineEdit::Password); - lineEdit.setText(QStringLiteral("x")); - mHiddenDigitText = lineEdit.displayText(); - } - - - const QString& getHiddenDigitText() const - { - return mHiddenDigitText; - } - - - const QString& getUnsetDigitText() const - { - return mUnsetDigitText; - } - - - QSize getTotalSize() - { - validateLayout(); - return mTotalSize; - } - - - const QRect& getDigitRect() - { - validateLayout(); - return mDigitRect; - } - - - const QMargins& getDigitPadding() const - { - return mDigitPadding; - } - - - const QRect& getUpButtonRect() - { - validateLayout(); - return mUpButtonRect; - } - - - const QRect& getDownButtonRect() - { - validateLayout(); - return mDownButtonRect; - } - - - QColor getInactiveDigitBackgroundColor() const - { - return QColor("#FFFFFF"); - } - - - QColor getActiveDigitBackgroundColor() const - { - return QColor("#FFF9D2"); - } - - - QColor getPressedButtonBackgroundColor() const - { - return QColor("#FFCC66"); - } - - - QColor getNotPressedButtonBackgroundColor() const - { - return QColor("#FFF9D2"); - } - - - QPainterPath getButtonTrianglePath(bool pUp) - { - validateLayout(); - - QSizeF size = pUp ? mUpButtonRect.size() : mDownButtonRect.size(); - qreal padding = 2; - qreal center = size.width() / 2; - qreal top = padding; - qreal bottom = size.height() - padding; - qreal tip = pUp ? top : bottom; - qreal butt = pUp ? bottom : top; - QPainterPath path; - path.moveTo(center, tip); - path.lineTo(padding, butt); - path.lineTo(size.width() - padding, butt); - path.closeSubpath(); - return path; - } - - - private: - void validateLayout() - { - if (mLayoutValid) - { - return; - } - - QSize maxDigitSize = QSize(0, 0); - - const auto possibleChars = QStringLiteral("0123456789") + mHiddenDigitText + mUnsetDigitText; - QFontMetrics myFontMetrics = mParent->fontMetrics(); - int height = myFontMetrics.height(); - for (QChar c : possibleChars) - { - QSize digitSize(myFontMetrics.boundingRect(c).width(), height); - maxDigitSize = maxDigitSize.expandedTo(digitSize); - } - - mUpButtonRect = QRect(0, 0, maxDigitSize.width() + mDigitPadding.left() + mDigitPadding.right(), mButtonHeight); - mDigitRect = QRect(0, mUpButtonRect.top() + mUpButtonRect.height() + mButtonSpacing, mUpButtonRect.width(), maxDigitSize.height() + mDigitPadding.top() + mDigitPadding.bottom()); - mDownButtonRect = QRect(0, mDigitRect.top() + mDigitRect.height() + mButtonSpacing, mUpButtonRect.width(), mButtonHeight); - mTotalSize = QSize(mUpButtonRect.width(), mDownButtonRect.top() + mDownButtonRect.height()); - - mLayoutValid = true; - } - - - private: - QWidget* mParent; - bool mLayoutValid; - QString mHiddenDigitText; - QString mUnsetDigitText; - QMargins mDigitPadding; - int mButtonHeight; - int mButtonSpacing; - QRect mUpButtonRect; - QRect mDownButtonRect; - QRect mDigitRect; - QSize mTotalSize; - QLineEdit mLineEdit; -}; - - -class KeylessPasswordEdit::DigitButton - : public QToolButton -{ - Q_OBJECT - - public: - DigitButton(RenderingHelper* pRenderingHelper, bool pIsUpButton, QWidget* pParent = nullptr) - : QToolButton(pParent) - , mRenderingHelper(pRenderingHelper) - , mIsUpButton(pIsUpButton) - { - setAutoRepeat(true); - setAutoRepeatDelay(1000); - setAutoRepeatInterval(500); - } - - - protected: - virtual void paintEvent(QPaintEvent* /*pEvent*/) override - { - QStyleOption opt; - opt.init(this); - QPainter painter(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); - - painter.setRenderHint(QPainter::Antialiasing); - painter.fillPath(mRenderingHelper->getButtonTrianglePath(mIsUpButton), QColor(0, 0, 0)); - } - - - private: - RenderingHelper* mRenderingHelper; - bool mIsUpButton; -}; - - -class KeylessPasswordEdit::DigitField - : public QWidget -{ - Q_OBJECT - - public: - enum State - { - UNSET, - ACTIVE, - INACTIVE, - }; - - public: - DigitField(RenderingHelper* pRenderingHelper, QWidget* pParent = nullptr) - : QWidget(pParent) - , mRenderingHelper(pRenderingHelper) - , mValue(0) - , mState(State::UNSET) - , mWheelDelta(0) - , mUpButton(new DigitButton(pRenderingHelper, true, this)) - , mDownButton(new DigitButton(pRenderingHelper, false, this)) - , mActivationAnimationTimer(0) - , mActivationAnimationSteps(0) - , mDeactivationTimer(0) - , mDigitFieldInvalid(false) - { - mUpButton->setVisible(false); - mDownButton->setVisible(false); - - mUpButton->setGeometry(mRenderingHelper->getUpButtonRect()); - mDownButton->setGeometry(mRenderingHelper->getDownButtonRect()); - - connect(mUpButton, &QAbstractButton::pressed, this, &DigitField::onUpButtonPressed); - connect(mDownButton, &QAbstractButton::pressed, this, &DigitField::onDownButtonPressed); - } - - - bool isActive() const - { - return mState == State::ACTIVE; - } - - - bool hasValue() const - { - return mState != State::UNSET; - } - - - int getValue() const - { - return mValue; - } - - - void setValue(int pValue) - { - mValue = pValue; - - if (!hasValue()) - { - setState(State::INACTIVE); - } - } - - - State getState() const - { - return mState; - } - - - void setState(State pState) - { - if (pState != mState) - { - bool wasActive = isActive(); - - mState = pState; - mWheelDelta = 0; - - bool active = isActive(); - mUpButton->setVisible(active); - mDownButton->setVisible(active); - - if (active) - { - if (!wasActive) - { - mValue = randomNumber() % 10; - startActivationAnimation(); - Q_EMIT valueEdited(); - } - } - else - { - stopDeactivationTimer(); - } - - update(); - } - } - - - virtual QSize sizeHint() const override - { - return mRenderingHelper->getTotalSize(); - } - - - virtual QSize minimumSizeHint() const override - { - return mRenderingHelper->getTotalSize(); - } - - - void setDigitFieldInvalid(bool pInvalid) - { - mDigitFieldInvalid = pInvalid; - } - - - void addToValue(int pDelta) - { - mValue = ((mValue + pDelta) % 10 + 10) % 10; - update(); - startDeactivationTimer(false); - - Q_EMIT valueEdited(); - } - - - Q_SIGNALS: - void activationRequested(); - void deactivationRequested(); - void valueEdited(); - - protected: - virtual void mousePressEvent(QMouseEvent* pEvent) override - { - Q_EMIT activationRequested(); - pEvent->accept(); - } - - - virtual void wheelEvent(QWheelEvent* pEvent) override - { - if (!isActive()) - { - pEvent->ignore(); - return; - } - - mWheelDelta += pEvent->angleDelta().y(); - int steps = mWheelDelta / 120; - if (steps != 0) - { - mWheelDelta -= steps * 120; - addToValue(steps); - } - - pEvent->accept(); - } - - - virtual void paintEvent(QPaintEvent* /*pEvent*/) override - { - QStyleOption opt; - opt.init(this); - QPainter painter(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); - - QString textToDraw; - - switch (mState) - { - case State::UNSET: - textToDraw = mRenderingHelper->getUnsetDigitText(); - break; - - case State::INACTIVE: - textToDraw = mRenderingHelper->getHiddenDigitText(); - break; - - case State::ACTIVE: - textToDraw = QString(QLatin1Char(static_cast('0' + char(mValue)))); - break; - } - - QRect digitRect = mRenderingHelper->getDigitRect(); - - if (mDigitFieldInvalid && getState() == State::ACTIVE) - { - painter.fillRect(digitRect, Qt::red); - } - - painter.drawRect(digitRect.x(), digitRect.y(), digitRect.width() - 1, digitRect.height() - 1); - - digitRect -= mRenderingHelper->getDigitPadding(); - - - painter.drawText(digitRect, Qt::AlignHCenter | Qt::AlignVCenter, textToDraw); - } - - - virtual void timerEvent(QTimerEvent* pEvent) override - { - if (pEvent->timerId() == mActivationAnimationTimer) - { - mValue = randomNumber() % 10; - update(); - - if (--mActivationAnimationSteps <= 0) - { - stopActivationAnimation(); - startDeactivationTimer(true); - } - - Q_EMIT valueEdited(); - } - else if (pEvent->timerId() == mDeactivationTimer) - { - Q_EMIT deactivationRequested(); - } - } - - - private Q_SLOTS: - void onDownButtonPressed() - { - if (isActive()) - { - addToValue(-1); - } - } - - - void onUpButtonPressed() - { - if (isActive()) - { - addToValue(1); - } - } - - - private: - void startActivationAnimation() - { - stopActivationAnimation(); - - mActivationAnimationTimer = startTimer(100); - mActivationAnimationSteps = 5; - } - - - void stopActivationAnimation() - { - if (mActivationAnimationTimer != 0) - { - killTimer(mActivationAnimationTimer); - mActivationAnimationTimer = 0; - } - } - - - void startDeactivationTimer(bool pLongDelay) - { - stopDeactivationTimer(); - - mDeactivationTimer = startTimer(pLongDelay ? 10000 : 3000); - } - - - void stopDeactivationTimer() - { - if (mDeactivationTimer != 0) - { - killTimer(mDeactivationTimer); - mDeactivationTimer = 0; - } - } - - - private: - RenderingHelper* mRenderingHelper; - int mValue; - State mState; - int mWheelDelta; - DigitButton* mUpButton; - DigitButton* mDownButton; - int mActivationAnimationTimer; - int mActivationAnimationSteps; - int mDeactivationTimer; - bool mDigitFieldInvalid; -}; - - -KeylessPasswordEdit::KeylessPasswordEdit(QWidget* pParent) - : QWidget(pParent) - , mLayout(new QGridLayout(this)) - , mMinLength(0) - , mMaxLength(0) - , mRenderingHelper(new RenderingHelper(this)) - , mDigitFields() - , mActiveFieldIndex(-1) -{ - mLayout->setMargin(0); - - QFont myFont = font(); - myFont.setBold(true); - myFont.setPointSize(myFont.pointSize() + 2); - setFont(myFont); - - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - setMaxLength(6); - - setFocusPolicy(Qt::StrongFocus); -} - - -KeylessPasswordEdit::~KeylessPasswordEdit() -{ -} - - -void KeylessPasswordEdit::setMinLength(int pLength) -{ - if (pLength < 0 || pLength > MAX_MAX_LENGTH || pLength == mMinLength) - { - return; - } - - if (pLength > mMaxLength) - { - setMaxLength(pLength); - } - - mMinLength = pLength; -} - - -void KeylessPasswordEdit::setMaxLength(int pLength) -{ - if (pLength < 1 || pLength > MAX_MAX_LENGTH) - { - return; - } - - if (pLength < mMinLength) - { - setMinLength(pLength); - } - - if (mActiveFieldIndex >= pLength) - { - setActiveField(-1); - } - - mMaxLength = pLength; - - while (mMaxLength > mDigitFields.size()) - { - DigitField* field = new DigitField(mRenderingHelper.data(), this); - mLayout->addWidget(field, 0, mDigitFields.size()); - mDigitFields += field; - - connect(field, &DigitField::activationRequested, this, &KeylessPasswordEdit::onFieldActivationRequested); - connect(field, &DigitField::deactivationRequested, this, &KeylessPasswordEdit::onFieldDeactivationRequested); - connect(field, &DigitField::valueEdited, this, &KeylessPasswordEdit::onFieldValueEdited); - } - - while (mMaxLength < mDigitFields.size()) - { - DigitField* field = mDigitFields.takeLast(); - delete field; - } -} - - -void KeylessPasswordEdit::clear() -{ - setActiveField(-1); - - for (auto field : qAsConst(mDigitFields)) - { - field->setState(DigitField::State::UNSET); - } -} - - -QString KeylessPasswordEdit::text() const -{ - QString result; - for (auto field : qAsConst(mDigitFields)) - { - if (!field->hasValue()) - { - break; - } - - int value = field->getValue(); - result += char('0' + value); - } - - return result; -} - - -void KeylessPasswordEdit::setText(const QString& pText) -{ - setActiveField(-1); - - int fieldCount = mDigitFields.length(); - int length = std::min(pText.length(), fieldCount); - for (int i = 0; i < length; ++i) - { - mDigitFields.at(i)->setValue(pText.midRef(i, 1).toInt()); - } - - for (int i = length; i < fieldCount; ++i) - { - mDigitFields.at(i)->setState(DigitField::State::UNSET); - } -} - - -void KeylessPasswordEdit::paintEvent(QPaintEvent* /*pEvent*/) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -void KeylessPasswordEdit::focusInEvent(QFocusEvent* /*pEvent*/) -{ - // if completely unset, activate the first field - if (mActiveFieldIndex < 0 && !mDigitFields.isEmpty() && !mDigitFields.at(0)->hasValue()) - { - setActiveField(0); - } -} - - -void KeylessPasswordEdit::focusOutEvent(QFocusEvent* /*pEvent*/) -{ - // deactivate the active field - if (mActiveFieldIndex >= 0) - { - setActiveField(-1); - } -} - - -void KeylessPasswordEdit::keyPressEvent(QKeyEvent* pEvent) -{ - if (mDigitFields.isEmpty()) - { - return; - } - - int lastSetField = -1; - for (int i = mDigitFields.count() - 1; i >= 0; i--) - { - if (mDigitFields.at(i)->hasValue()) - { - lastSetField = i; - break; - } - } - - switch (pEvent->key()) - { - case Qt::Key_Up: - if (mActiveFieldIndex >= 0) - { - mDigitFields.at(mActiveFieldIndex)->addToValue(1); - } - break; - - case Qt::Key_Down: - if (mActiveFieldIndex >= 0) - { - mDigitFields.at(mActiveFieldIndex)->addToValue(-1); - } - break; - - case Qt::Key_Left: - if (lastSetField > 0) - { - setActiveField(lastSetField - 1); - } - break; - - case Qt::Key_Right: - if (lastSetField + 1 < mDigitFields.count()) - { - setActiveField(lastSetField + 1); - } - break; - - default: - return; - } - - pEvent->accept(); -} - - -void KeylessPasswordEdit::onFieldActivationRequested() -{ - DigitField* field = qobject_cast(sender()); - int fieldIndex = field != nullptr ? mDigitFields.indexOf(field) : -1; - if (fieldIndex >= 0) - { - setActiveField(fieldIndex); - return; - } -} - - -void KeylessPasswordEdit::onFieldDeactivationRequested() -{ - DigitField* field = qobject_cast(sender()); - int fieldIndex = field != nullptr ? mDigitFields.indexOf(field) : -1; - if (fieldIndex >= 0 && fieldIndex == mActiveFieldIndex) - { - setActiveField(-1); - return; - } -} - - -void KeylessPasswordEdit::onFieldValueEdited() -{ - Q_EMIT textEdited(text()); -} - - -void KeylessPasswordEdit::setDigitFieldsInvalid(bool pInvalid) -{ - for (auto field : qAsConst(mDigitFields)) - { - field->setDigitFieldInvalid(pInvalid); - } -} - - -void KeylessPasswordEdit::setActiveField(int pIndex) -{ - if (pIndex == mActiveFieldIndex) - { - return; - } - - // Activate the specified only, if there aren't any unset fields before it. - if (pIndex > 0 && !mDigitFields.at(pIndex - 1)->hasValue()) - { - return; - } - - // deactivate the previously active field - if (mActiveFieldIndex >= 0) - { - mDigitFields.at(mActiveFieldIndex)->setState(DigitField::State::INACTIVE); - mActiveFieldIndex = -1; - } - - // activate the new field - mActiveFieldIndex = pIndex; - - if (mActiveFieldIndex >= 0) - { - mDigitFields.at(pIndex)->setState(DigitField::State::ACTIVE); - - // unset all fields after the newly active one - int fieldCount = mDigitFields.count(); - for (int i = pIndex + 1; i < fieldCount; ++i) - { - mDigitFields.at(i)->setState(DigitField::State::UNSET); - } - } -} - - -#include "KeylessPasswordEdit.moc" diff --git a/src/gui/generic/KeylessPasswordEdit.h b/src/gui/generic/KeylessPasswordEdit.h deleted file mode 100644 index 2110fa1..0000000 --- a/src/gui/generic/KeylessPasswordEdit.h +++ /dev/null @@ -1,80 +0,0 @@ -/*! - * KeylessPasswordEdit.h - * - * \brief Widget for entering a PIN/CAN/PUK via pointer device only. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -class QGridLayout; - -namespace governikus -{ - -class KeylessPasswordEdit - : public QWidget -{ - Q_OBJECT - - private: - class RenderingHelper; - class DigitButton; - class DigitField; - - public: - KeylessPasswordEdit(QWidget* pParent = nullptr); - virtual ~KeylessPasswordEdit(); - - int getMinLength() const - { - return mMinLength; - } - - - void setMinLength(int pLength); - - int getMaxLength() const - { - return mMaxLength; - } - - - void setMaxLength(int pLength); - - void clear(); - - QString text() const; - void setText(const QString& pText); - - void setDigitFieldsInvalid(bool pInvalid); - - Q_SIGNALS: - void textEdited(const QString& pText); - - protected: - virtual void paintEvent(QPaintEvent* pEvent) override; - virtual void focusInEvent(QFocusEvent* pEvent) override; - virtual void focusOutEvent(QFocusEvent* pEvent) override; - virtual void keyPressEvent(QKeyEvent* pEvent) override; - - private: - void onFieldActivationRequested(); - void onFieldDeactivationRequested(); - void onFieldValueEdited(); - - void setActiveField(int pIndex); - - private: - QGridLayout* mLayout; - int mMinLength; - int mMaxLength; - QScopedPointer mRenderingHelper; - QVector mDigitFields; - int mActiveFieldIndex; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/LayoutBuilder.h b/src/gui/generic/LayoutBuilder.h deleted file mode 100644 index 8d5570d..0000000 --- a/src/gui/generic/LayoutBuilder.h +++ /dev/null @@ -1,248 +0,0 @@ -/*! - * LayoutBuilder.h - * - * \brief Support classes for building layouts. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -namespace governikus -{ - -namespace LayoutBuilder -{ - -struct Dummy -{ -}; - -template -class Base -{ - public: - template - Base(Arguments ... pArguments) - : mDelegate(pArguments ...) - , mParent(nullptr) - { - } - - - void setParent(ParentBuilder* pParent) - { - mParent = pParent; - } - - - template - ActualClass& add(QWidget* pWidget, Arguments ... pArguments) - { - mDelegate.addWidget(pWidget, pArguments ...); - return *static_cast(this); - } - - - template - ActualClass& add(const QString& pWidgetName, QWidget* pWidget, Arguments ... pArguments) - { - pWidget->setObjectName(pWidgetName); - mDelegate.addWidget(pWidget, pArguments ...); - return *static_cast(this); - } - - - template - ActualClass& add(QLayoutItem* pItem, Arguments ... pArguments) - { - mDelegate.addItem(pItem, pArguments ...); - return *static_cast(this); - } - - - ParentBuilder& end() - { - return *mParent; - } - - - protected: - Delegate mDelegate; - ParentBuilder* mParent; -}; - - -class BoxDelegate -{ - public: - BoxDelegate(QBoxLayout::Direction pDirection, int pMargin = -1, int pSpacing = -1) - : mLayout(new QBoxLayout(pDirection)) - { - if (pMargin >= 0) - { - mLayout->setMargin(pMargin); - } - - if (pSpacing >= 0) - { - mLayout->setSpacing(pSpacing); - } - } - - - template - BoxDelegate(QWidget* pWidget, QBoxLayout::Direction pDirection, Arguments ... pArguments) - : BoxDelegate(pDirection, pArguments ...) - { - pWidget->setLayout(mLayout); - } - - - template - BoxDelegate(QBoxLayout::Direction pDirection, QWidget* pWidget, Arguments ... pArguments) - : BoxDelegate(pWidget, pDirection, pArguments ...) - { - } - - - void addWidget(QWidget* pWidget) - { - mLayout->addWidget(pWidget); - } - - - void addItem(QLayoutItem* pItem) - { - mLayout->addItem(pItem); - } - - - private: - QBoxLayout* mLayout; - Q_DISABLE_COPY(BoxDelegate) -}; - -template -class Box - : public Base > -{ - public: - template - Box(Arguments ... pArguments) - : Base >(pArguments ...) - { - } - - -}; - - -template -class HBox - : public Box -{ - public: - template - HBox(Arguments ... pArguments) - : Box(QBoxLayout::LeftToRight, pArguments ...) - { - } - - -}; - - -template -class VBox - : public Box -{ - public: - template - VBox(Arguments ... pArguments) - : Box(QBoxLayout::TopToBottom, pArguments ...) - { - } - - -}; - - -class GridDelegate -{ - public: - GridDelegate(QGridLayout* pLayout) - : mLayout(pLayout) - { - } - - - GridDelegate(int pMargin = -1, int pSpacing = -1) - : mLayout(new QGridLayout()) - { - if (pMargin >= 0) - { - mLayout->setMargin(pMargin); - } - - if (pSpacing >= 0) - { - mLayout->setSpacing(pSpacing); - } - } - - - template - GridDelegate(QWidget* pWidget, Arguments ... pArguments) - : GridDelegate(pArguments ...) - { - pWidget->setLayout(mLayout); - } - - - void addWidget(QWidget* pWidget, int pRow, int pColumn, int pRowSpan = 1, int pColumnSpan = 1) - { - mLayout->addWidget(pWidget, pRow, pColumn, pRowSpan, pColumnSpan); - } - - - void addItem(QLayoutItem* pItem, int pRow, int pColumn, int pRowSpan = 1, int pColumnSpan = 1) - { - mLayout->addItem(pItem, pRow, pColumn, pRowSpan, pColumnSpan); - } - - - private: - QGridLayout* mLayout; - Q_DISABLE_COPY(GridDelegate) -}; - -template -class Grid - : public Base > -{ - public: - template - Grid(Arguments ... pArguments) - : Base >(pArguments ...) - { - } - - -}; - -} /* namespace LayoutBuilder */ - -} /* namespace governikus */ diff --git a/src/gui/generic/ListCheckItemWidget.cpp b/src/gui/generic/ListCheckItemWidget.cpp deleted file mode 100644 index 0e3edb2..0000000 --- a/src/gui/generic/ListCheckItemWidget.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/*! - * ListCheckItemWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include -#include -#include -#include -#include - -#include "generic/ListCheckItemWidget.h" -#include "ui_ListCheckItemWidget.h" - -using namespace governikus; - - -ListCheckItemWidget::ListCheckItemWidget(QWidget* pParent) - : QWidget(pParent) - , mUi(new Ui::ListCheckItemWidget()) -{ - mUi->setupUi(this); - mUi->listIcon->hide(); - - connect(mUi->listCheckBox, &QCheckBox::stateChanged, this, &ListCheckItemWidget::onCheckBoxChanged); - - installEventFilter(this); -} - - -ListCheckItemWidget::ListCheckItemWidget(QWidget* pParent, const QPixmap& pPixmap) - : QWidget(pParent) - , mUi(new Ui::ListCheckItemWidget()) -{ - mUi->setupUi(this); - mUi->listIcon->setScaledContents(true); - mUi->listIcon->setPixmap(pPixmap); - - connect(mUi->listCheckBox, &QCheckBox::stateChanged, this, &ListCheckItemWidget::onCheckBoxChanged); - - installEventFilter(this); -} - - -ListCheckItemWidget::~ListCheckItemWidget() -{ -} - - -void ListCheckItemWidget::itemWidgetReleased() -{ - mUi->listItemLayout->setObjectName(QStringLiteral("listItemLayout")); - //qApp->setStyleSheet(qApp->styleSheet()); -} - - -void ListCheckItemWidget::onCheckBoxChanged(int /*pChanged*/) -{ - Q_EMIT listItemWidgetChecked(this); -} - - -void ListCheckItemWidget::itemWidgetPressed() -{ - mUi->listItemLayout->setObjectName(QStringLiteral("listItemLayout_pressed")); - //qApp->setStyleSheet(qApp->styleSheet()); - - Q_EMIT listItemWidgetChecked(this); - -} - - -bool ListCheckItemWidget::eventFilter(QObject* /*pWatched*/, QEvent* pEvent) -{ - switch (pEvent->type()) - { - case QEvent::MouseButtonPress: - itemWidgetPressed(); - return false; - - break; - - case QEvent::MouseButtonRelease: - itemWidgetReleased(); - return false; - - break; - - default: - return false; - - break; - } - return false; -} - - -void ListCheckItemWidget::setHeading(const QString& pHeading) -{ - mUi->heading->setText(pHeading); -} - - -void ListCheckItemWidget::setSubHeading(const QString& pSubHeading) -{ - if (!pSubHeading.isNull() || !pSubHeading.isEmpty()) - { - mUi->subHeading->setText(pSubHeading); - } - else - { - mUi->headingFrameLayout->layout()->removeWidget(mUi->subHeading); - delete mUi->subHeading; - } -} - - -void ListCheckItemWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -QCheckBox* ListCheckItemWidget::getListItemCheckBox() -{ - return mUi->listCheckBox; -} diff --git a/src/gui/generic/ListCheckItemWidget.h b/src/gui/generic/ListCheckItemWidget.h deleted file mode 100644 index 2caedc2..0000000 --- a/src/gui/generic/ListCheckItemWidget.h +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * ListCheckItemWidget.h - * - * \brief List item widget for list actions. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -#include "generic/Page.h" - -namespace Ui -{ -class ListCheckItemWidget; -} - -namespace governikus -{ - -class ListCheckItemWidget - : public QWidget -{ - Q_OBJECT - - public: - ListCheckItemWidget(QWidget* pParent, const QPixmap& pPixmap); - ListCheckItemWidget(QWidget* pParent); - virtual ~ListCheckItemWidget(); - - void setHeading(const QString& pHeading); - void setSubHeading(const QString& pSubHeading); - - QCheckBox* getListItemCheckBox(); - - Q_SIGNALS: - void listItemWidgetChecked(ListCheckItemWidget* pListCheckItemWidget); - - private Q_SLOTS: - void onCheckBoxChanged(int pChanged); - - private: - QScopedPointer mUi; - - virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; - virtual void paintEvent(QPaintEvent*) override; - - void itemWidgetReleased(); - void itemWidgetPressed(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ListItem.cpp b/src/gui/generic/ListItem.cpp deleted file mode 100644 index 79f51ec..0000000 --- a/src/gui/generic/ListItem.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "ListItem.h" - -#include -#include - -using namespace governikus; - -ListItem::ListItem(QWidget* pParent, Qt::WindowFlags pWindowFlags) - : QWidget(pParent, pWindowFlags) -{ -} - - -ListItem::~ListItem() -{ -} - - -void ListItem::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/generic/ListItem.h b/src/gui/generic/ListItem.h deleted file mode 100644 index a1269e8..0000000 --- a/src/gui/generic/ListItem.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - - -namespace governikus -{ - -class ListItem - : public QWidget -{ - Q_OBJECT - - public: - ListItem(QWidget* pParent = nullptr, Qt::WindowFlags pWindowFlags = 0); - virtual ~ListItem(); - - void paintEvent(QPaintEvent*) override; -}; - -} diff --git a/src/gui/generic/ListItemIconLeft.cpp b/src/gui/generic/ListItemIconLeft.cpp deleted file mode 100644 index 8eb41d2..0000000 --- a/src/gui/generic/ListItemIconLeft.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "ListItemIconLeft.h" - -using namespace governikus; - -ListItemIconLeft::ListItemIconLeft(QWidget* pParent) - : QLabel(pParent) -{ -} - - -ListItemIconLeft::ListItemIconLeft(const QString& pText, QWidget* pParent) - : QLabel(pText, pParent) -{ -} - - -ListItemIconLeft::~ListItemIconLeft() -{ -} diff --git a/src/gui/generic/ListItemIconLeft.h b/src/gui/generic/ListItemIconLeft.h deleted file mode 100644 index d1780a1..0000000 --- a/src/gui/generic/ListItemIconLeft.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace governikus -{ - -class ListItemIconLeft - : public QLabel -{ - Q_OBJECT - - public: - ListItemIconLeft(QWidget* pParent = nullptr); - ListItemIconLeft(const QString& pText, QWidget* pParent = nullptr); - virtual ~ListItemIconLeft(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ListItemIconRight.cpp b/src/gui/generic/ListItemIconRight.cpp deleted file mode 100644 index 8306f6f..0000000 --- a/src/gui/generic/ListItemIconRight.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "ListItemIconRight.h" - -using namespace governikus; - -ListItemIconRight::ListItemIconRight(QWidget* pParent) - : QLabel(pParent) -{ -} - - -ListItemIconRight::ListItemIconRight(const QString& pText, QWidget* pParent) - : QLabel(pText, pParent) -{ -} - - -ListItemIconRight::~ListItemIconRight() -{ -} diff --git a/src/gui/generic/ListItemIconRight.h b/src/gui/generic/ListItemIconRight.h deleted file mode 100644 index c5a1cd8..0000000 --- a/src/gui/generic/ListItemIconRight.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace governikus -{ - -class ListItemIconRight - : public QLabel -{ - Q_OBJECT - - public: - ListItemIconRight(QWidget* pParent = nullptr); - ListItemIconRight(const QString& pText, QWidget* pParent = nullptr); - virtual ~ListItemIconRight(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ListItemSubTitle.cpp b/src/gui/generic/ListItemSubTitle.cpp deleted file mode 100644 index 3f497d4..0000000 --- a/src/gui/generic/ListItemSubTitle.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "ListItemSubTitle.h" - -using namespace governikus; - -ListItemSubTitle::ListItemSubTitle(QWidget* pParent) - : QLabel(pParent) -{ -} - - -ListItemSubTitle::ListItemSubTitle(const QString& pText, QWidget* pParent) - : QLabel(pText, pParent) -{ -} - - -ListItemSubTitle::~ListItemSubTitle() -{ -} diff --git a/src/gui/generic/ListItemSubTitle.h b/src/gui/generic/ListItemSubTitle.h deleted file mode 100644 index f2afa9e..0000000 --- a/src/gui/generic/ListItemSubTitle.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace governikus -{ - -class ListItemSubTitle - : public QLabel -{ - Q_OBJECT - - public: - ListItemSubTitle(QWidget* pParent = nullptr); - ListItemSubTitle(const QString& pText, QWidget* pParent = nullptr); - virtual ~ListItemSubTitle(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/ListItemTitle.cpp b/src/gui/generic/ListItemTitle.cpp deleted file mode 100644 index cfff8ca..0000000 --- a/src/gui/generic/ListItemTitle.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "ListItemTitle.h" - -using namespace governikus; - -ListItemTitle::ListItemTitle(QWidget* pParent) - : QLabel(pParent) -{ -} - - -ListItemTitle::ListItemTitle(const QString& pText, QWidget* pParent) - : QLabel(pText, pParent) -{ -} - - -ListItemTitle::~ListItemTitle() -{ -} diff --git a/src/gui/generic/ListItemTitle.h b/src/gui/generic/ListItemTitle.h deleted file mode 100644 index fe4df49..0000000 --- a/src/gui/generic/ListItemTitle.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace governikus -{ - -class ListItemTitle - : public QLabel -{ - Q_OBJECT - - public: - ListItemTitle(QWidget* pParent = nullptr); - ListItemTitle(const QString& pText, QWidget* pParent = nullptr); - virtual ~ListItemTitle(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/Page.cpp b/src/gui/generic/Page.cpp deleted file mode 100644 index b100e6f..0000000 --- a/src/gui/generic/Page.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*! - * Page.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "Page.h" - -#include -#include - -using namespace governikus; - -Page::Page(QWidget* pParent) - : Page(QStringLiteral("untitled page"), pParent) -{ -} - - -Page::Page(const QString& pTitle, QWidget* pParent) - : QWidget(pParent) - , mTitle(pTitle) - , mIsSideNavigationPage(false) - , mBackNavigationEnabled(true) -{ -} - - -Page::~Page() -{ -} - - -void Page::setBackNavigationEnabled(bool pEnabled) -{ - if (pEnabled != mBackNavigationEnabled) - { - mBackNavigationEnabled = pEnabled; - Q_EMIT backNavigationEnabledChanged(mBackNavigationEnabled); - } -} - - -void Page::pageAboutToBeShown() -{ - // can be overridden by derived classes -} - - -void Page::pageShowFinished() -{ - // can be overridden by derived classes -} - - -void Page::pageAboutToBeHidden() -{ - // can be overridden by derived classes -} - - -void Page::pageHideFinished() -{ - // can be overridden by derived classes -} - - -QVector Page::createLeftNavigationButtons() -{ - // can be overridden by derived classes - return QVector(); -} - - -QVector Page::createRightNavigationButtons() -{ - // can be overridden by derived classes - return QVector(); -} - - -void Page::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/generic/Page.h b/src/gui/generic/Page.h deleted file mode 100644 index d3ab341..0000000 --- a/src/gui/generic/Page.h +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * Page.h - * - * \brief A page in a mobile GUI. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - -class QAbstractButton; - -namespace governikus -{ - -class Page - : public QWidget -{ - Q_OBJECT - - public: - Page(QWidget* pParent = nullptr); - Page(const QString& pTitle, QWidget* pParent = nullptr); - virtual ~Page(); - - const QString& getTitle() const - { - return mTitle; - } - - - void setTitle(const QString& pTitle) - { - mTitle = pTitle; - } - - - bool isSideNavigationPage() const - { - return mIsSideNavigationPage; - } - - - void setSideNavigationPage(bool pIsSideNavigationPage) - { - mIsSideNavigationPage = pIsSideNavigationPage; - } - - - bool isBackNavigationEnabled() const - { - return mBackNavigationEnabled; - } - - - void setBackNavigationEnabled(bool pEnabled); - - virtual void pageAboutToBeShown(); - virtual void pageShowFinished(); - - virtual void pageAboutToBeHidden(); - virtual void pageHideFinished(); - - /*! - * \brief Create buttons shown in the top navigation bar left to the page title. The method is invoked - * right before the page is shown. The buttons will be destroyed automatically right after the page - * has been hidden. - * \return The list of buttons to be shown. If empty (the default) the default back button will be - * shown, if there is a parent page. - */ - virtual QVector createLeftNavigationButtons(); - - /*! - * \brief Create buttons shown in the top navigation bar right to the page title. The method is - * invoked right before the page is shown. The buttons will be destroyed automatically right after the - * page has been hidden. - * \return The list of buttons to be shown. - */ - virtual QVector createRightNavigationButtons(); - - Q_SIGNALS: - void activatePageRequested(); - void leftNavigationButtonsChanged(); - void rightNavigationButtonsChanged(); - void backNavigationEnabledChanged(bool pEnabled); - - protected: - void paintEvent(QPaintEvent*); - - private: - QString mTitle; - bool mIsSideNavigationPage; - bool mBackNavigationEnabled; -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/PasswordEdit.cpp b/src/gui/generic/PasswordEdit.cpp deleted file mode 100644 index b32e515..0000000 --- a/src/gui/generic/PasswordEdit.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/*! - * PasswordEdit.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "generic/PasswordEdit.h" - -#include -#include -#include -#include -#include - -#include "KeylessPasswordEdit.h" -#include "PasswordLineEdit.h" - -using namespace governikus; - -PasswordEdit::PasswordEdit(QWidget* pParent) - : QWidget(pParent) - , mKeylessEdit(new KeylessPasswordEdit(this)) - , mLineEdit(new PasswordLineEdit(this)) - , mStackedLayout(new QStackedLayout) -{ - QHBoxLayout* myLayout = new QHBoxLayout(this); - myLayout->setMargin(0); - myLayout->addLayout(mStackedLayout); - mStackedLayout->setMargin(0); - mStackedLayout->addWidget(createWrapperWidget(mLineEdit)); - mStackedLayout->addWidget(createWrapperWidget(mKeylessEdit)); - - connect(mLineEdit, &PasswordLineEdit::textEdited, this, &PasswordEdit::textEdited); - connect(mLineEdit, &PasswordLineEdit::selectionChanged, this, &PasswordEdit::selectionChanged); - - connect(mKeylessEdit, &KeylessPasswordEdit::textEdited, this, &PasswordEdit::textEdited); - - setKeylessPasswordMode(false); -} - - -PasswordEdit::~PasswordEdit() -{ -} - - -void PasswordEdit::setMaxLength(int pLength) -{ - mKeylessEdit->setMaxLength(pLength); - mLineEdit->setMaxLength(pLength); -} - - -void PasswordEdit::setFieldWidth(int pWidth) -{ - mLineEdit->setFieldWidth(pWidth); -} - - -void PasswordEdit::configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip) -{ - mLineEdit->configureValidation(pExpression, pInvalidValueToolTip); -} - - -void PasswordEdit::clear() -{ - mLineEdit->clear(); - mKeylessEdit->clear(); -} - - -QString PasswordEdit::text() const -{ - return isLineEditActive() ? mLineEdit->text() : mKeylessEdit->text(); -} - - -void PasswordEdit::setCursorPosition(int pIndex) -{ - mLineEdit->setCursorPosition(pIndex); -} - - -bool PasswordEdit::isLineEditActive() const -{ - return mStackedLayout->currentIndex() == 0; -} - - -void PasswordEdit::setKeylessPasswordMode(bool pKeylessPassword) -{ - if (pKeylessPassword) - { - setFocusProxy(mKeylessEdit); - mStackedLayout->setCurrentIndex(1); - } - else - { - setFocusProxy(mLineEdit); - mStackedLayout->setCurrentIndex(0); - } -} - - -void PasswordEdit::setDigitFieldInvalid(bool pMakeInvalid, const QString& pInvalidMessage) -{ - if (pMakeInvalid) - { - if (isLineEditActive()) - { - mLineEdit->setStyleSheet(QStringLiteral("background-color: red;")); - QToolTip::showText(mapToGlobal(QPoint(0, 20)), pInvalidMessage, mLineEdit, QRect(), 3000); - } - else - { - mKeylessEdit->setDigitFieldsInvalid(true); - } - } - else - { - isLineEditActive() ? mLineEdit->setStyleSheet(QString()) : mKeylessEdit->setDigitFieldsInvalid(false); - } -} - - -PasswordLineEdit* PasswordEdit::getLineEdit() -{ - return mLineEdit; -} - - -QWidget* PasswordEdit::createWrapperWidget(QWidget* pWidget) -{ - QWidget* wrapperWidget = new QWidget; - QHBoxLayout* wrapperLayout = new QHBoxLayout(wrapperWidget); - wrapperLayout->setMargin(0); - wrapperLayout->addWidget(pWidget); - return wrapperWidget; -} diff --git a/src/gui/generic/PasswordEdit.h b/src/gui/generic/PasswordEdit.h deleted file mode 100644 index f2df35b..0000000 --- a/src/gui/generic/PasswordEdit.h +++ /dev/null @@ -1,69 +0,0 @@ -/*! - * PasswordEdit.h - * - * \brief Widget for entering a password; can be toggled between line edit and keyless edit. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "generic/PasswordLineEdit.h" -#include - -class QRegularExpression; -class QStackedLayout; -class QToolButton; - -namespace governikus -{ - -class KeylessPasswordEdit; - - -class PasswordEdit - : public QWidget -{ - Q_OBJECT - - public: - PasswordEdit(QWidget* pParent = nullptr); - virtual ~PasswordEdit(); - - void setMaxLength(int pLength); - - /*! - * The field width is set to display pWidth characters - */ - void setFieldWidth(int pWidth); - - /*! - * Configures a regular expression for input validation. - * If the invalid value tool tip is set, it is displayed on invalid values. - */ - void configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip); - - PasswordLineEdit* getLineEdit(); - - void clear(); - QString text() const; - - void setCursorPosition(int pIndex); - void setKeylessPasswordMode(bool pKeylessPassword); - bool isLineEditActive() const; - void setDigitFieldInvalid(bool pMakeInvalid, const QString& pInvalidMessage); - - Q_SIGNALS: - void textEdited(const QString& pText); - void selectionChanged(); - - private: - static QWidget* createWrapperWidget(QWidget* pWidget); - - private: - KeylessPasswordEdit* mKeylessEdit; - PasswordLineEdit* mLineEdit; - QStackedLayout* mStackedLayout; -}; - -} diff --git a/src/gui/generic/PasswordLineEdit.cpp b/src/gui/generic/PasswordLineEdit.cpp deleted file mode 100644 index 742a941..0000000 --- a/src/gui/generic/PasswordLineEdit.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "generic/PasswordLineEdit.h" - -#include -#include -#include - -using namespace governikus; - -namespace governikus -{ -class RegExValidator - : public QRegularExpressionValidator -{ - Q_OBJECT - - private: - const QString mInvalidValueToolTip; - - public: - RegExValidator(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip, QWidget* pParent) - : QRegularExpressionValidator(pExpression, pParent) - , mInvalidValueToolTip(pInvalidValueToolTip) - { - } - - - virtual QValidator::State validate(QString& pInput, int& pPos) const - { - QValidator::State state = QRegularExpressionValidator::validate(pInput, pPos); - - if (state == State::Invalid && !mInvalidValueToolTip.isNull()) - { - QWidget* parentWidget = static_cast(this->parent()); - QToolTip::showText(parentWidget->mapToGlobal(QPoint(0, 0)), mInvalidValueToolTip, parentWidget, QRect(), 3000); - } - - return state; - } - - -}; - -} - -PasswordLineEdit::PasswordLineEdit(QWidget* pParent) - : QLineEdit(pParent) -{ - setEchoMode(QLineEdit::Password); - setInputMethodHints(inputMethodHints() | Qt::ImhHiddenText | Qt::ImhSensitiveData | Qt::ImhPreferNumbers | Qt::ImhDigitsOnly | Qt::ImhFormattedNumbersOnly); -} - - -PasswordLineEdit::~PasswordLineEdit() -{ -} - - -void PasswordLineEdit::configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip) -{ - setValidator(new RegExValidator(pExpression, pInvalidValueToolTip, this)); -} - - -void PasswordLineEdit::setFieldWidth(int pWidth) -{ - // get the display text for a password of length pWidth - setText(QString(pWidth, QLatin1Char('6'))); - int displayTextWidth = fontMetrics().width(displayText()); - clear(); - - // in QLineEdit::sizeHint() the width is calculated as - // 17th times the size of 'x' plus some magic margins. - // So we calculate this margin by subtraction to set the content size correctly. - int widthHint = sizeHint().width(); - int margin = widthHint - 17 * fontMetrics().width(QLatin1Char('x')); - - setFixedWidth(margin + displayTextWidth); -} - - -#include "PasswordLineEdit.moc" diff --git a/src/gui/generic/PasswordLineEdit.h b/src/gui/generic/PasswordLineEdit.h deleted file mode 100644 index 619ec45..0000000 --- a/src/gui/generic/PasswordLineEdit.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * \brief Custom implementation of QLineEdit that uses the password echo mode. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace governikus -{ - -class PasswordLineEdit - : public QLineEdit -{ - Q_OBJECT - - public: - PasswordLineEdit(QWidget* pParent = nullptr); - virtual ~PasswordLineEdit(); - - /*! - * The field width is set to display pWidth characters - */ - void setFieldWidth(int pWidth); - - /*! - * Configures a regular expression for input validation. - * If the invalid value tool tip is set, it is displayed on invalid values. - */ - void configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip); -}; - -} diff --git a/src/gui/generic/SmartCardUtil.cpp b/src/gui/generic/SmartCardUtil.cpp deleted file mode 100644 index 72dd1ab..0000000 --- a/src/gui/generic/SmartCardUtil.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*! - * SmartCardUtil.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "SmartCardUtil.h" - -using namespace governikus; - -static QString prefix(QStringLiteral(":/images/reader/")); - -QString SmartCardUtil::getMultipleReaderIconPath() -{ - return prefix + "default_more_cardreader.png"; -} - - -QString SmartCardUtil::getNoReaderFoundIconPath() -{ - return prefix + "default_no_cardreader_01.png"; -} - - -QString SmartCardUtil::getReaderIconPath(ReaderType pReaderType) -{ - switch (pReaderType) - { - case ReaderType::REINER_cyberJack_RFID_komfort: - return prefix + "img_Reiner_SCT_cyberjack_RFID_komfort_mit_ausweis.png"; - - case ReaderType::REINER_cyberJack_RFID_standard: - return prefix + "img_Reiner_SCT_cyberjack_RFID_standard_mit_ausweis.png"; - - case ReaderType::REINER_cyberJack_RFID_basis: - return prefix + "img_Reiner_SCT_cyberjack_RFID_basis_mit_ausweis.png"; - - case ReaderType::REINER_cyberJack_wave: - return prefix + "img_cyberjack_wave_mit_ausweis.png"; - - case ReaderType::SCM_SCL011_Contactless_Reader: - return prefix + "img_Identive_SCL011_mit_ausweis.png"; - - case ReaderType::SCM_SDI010: - case ReaderType::SCM_SDI011: - return prefix + "img_Identive_SDI011_mit_ausweis.png"; - - case ReaderType::KOBIL_IDToken: - return prefix + "img_KOBIL_ID_Token_mit_ausweis.png"; - - case ReaderType::ACS_ACR1281_PICC_Reader: - return prefix + "img_ACS_ACR1281U_mit_ausweis.png"; - - case ReaderType::OMNIKEY_CardMan_5x21_CL: - return prefix + "img_HID_Global_OMNIKEY_5321_V2_mit_ausweis.png"; - - case ReaderType::OMNIKEY_4121_CL: - return prefix + "img_HID_Omnikey_Mobile_Reader_4121_CL_mit_ausweis.png"; - - case ReaderType::FEIG_OBID_myAXXESS_basic: - return prefix + "img_FEIG_myAXXES_basic_mit_ausweis.png"; - - case ReaderType::Gemalto_Prox_SU: - return prefix + "img_Gemalto_Prox_SU_mit_ausweis.png"; - - case ReaderType::Gemalto_Prox_DU: - return prefix + "img_Gemalto_Prox_DU_mit_ausweis.png"; - - case ReaderType::UNKNOWN: - return getNoReaderFoundIconPath(); - } - return QString(); -} - - -QString SmartCardUtil::getReaderEmptyIconPath(ReaderType pReaderType) -{ - switch (pReaderType) - { - case ReaderType::REINER_cyberJack_RFID_komfort: - return prefix + "img_Reiner_SCT_cyberjack_RFID_komfort.png"; - - case ReaderType::REINER_cyberJack_RFID_standard: - return prefix + "img_Reiner_SCT_cyberjack_RFID_standard.png"; - - case ReaderType::REINER_cyberJack_RFID_basis: - return prefix + "img_Reiner_SCT_cyberjack_RFID_basis.png"; - - case ReaderType::REINER_cyberJack_wave: - return prefix + "img_cyberjack_wave.png"; - - case ReaderType::SCM_SCL011_Contactless_Reader: - return prefix + "img_Identive_SCL011.png"; - - case ReaderType::SCM_SDI010: - case ReaderType::SCM_SDI011: - return prefix + "img_Identive_SDI011.png"; - - case ReaderType::KOBIL_IDToken: - return prefix + "img_KOBIL_ID_Token.png"; - - case ReaderType::ACS_ACR1281_PICC_Reader: - return prefix + "img_ACS_ACR1281U.png"; - - case ReaderType::OMNIKEY_CardMan_5x21_CL: - return prefix + "img_HID_Global_OMNIKEY_5321_V2.png"; - - case ReaderType::OMNIKEY_4121_CL: - return prefix + "img_HID_Omnikey_Mobile_Reader_4121_CL.png"; - - case ReaderType::FEIG_OBID_myAXXESS_basic: - return prefix + "img_FEIG_myAXXES_basic.png"; - - case ReaderType::Gemalto_Prox_SU: - return prefix + "img_Gemalto_Prox_SU.png"; - - case ReaderType::Gemalto_Prox_DU: - return prefix + "img_Gemalto_Prox_DU.png"; - - case ReaderType::UNKNOWN: - return prefix + "default_no_card_found.png"; - } - return QString(); -} - - -QString SmartCardUtil::getCardIconPath(CardType pCardType) -{ - switch (pCardType) - { - case CardType::NONE: - case CardType::UNKNOWN: - return prefix + "blank_card.096.png"; - - case CardType::EID_CARD: - return prefix + "card.npa.096.png"; - } - return QString(); -} diff --git a/src/gui/generic/SmartCardUtil.h b/src/gui/generic/SmartCardUtil.h deleted file mode 100644 index 4021ab3..0000000 --- a/src/gui/generic/SmartCardUtil.h +++ /dev/null @@ -1,59 +0,0 @@ -/*! - * SmartCardUtil.h - * - * \brief Util class to provide icons for Reader and Card. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "SmartCardDefinitions.h" - -#include - -namespace governikus -{ - -class SmartCardUtil -{ - private: - SmartCardUtil(); - Q_DISABLE_COPY(SmartCardUtil) - - public: - /*! - * Gets the icon path for the specified reader type. - * \param pReaderType type of the reader - * \return icon path - */ - static QString getReaderIconPath(ReaderType pReaderType); - - /*! - * Gets the icon path for the specified empty npa reader type. - * \param pReaderType type of the reader - * \return icon path - */ - static QString getReaderEmptyIconPath(ReaderType pReaderType); - - /*! - * Gets the icon path for the specified card type. - * \param pCardType type of the card - * \return icon path - */ - static QString getCardIconPath(CardType pCardType); - - /*! - * Gets icon for multiple readers - * \return icon path - */ - static QString getMultipleReaderIconPath(); - - /*! - * Gets icon for "no reader found" - * \return icon path - */ - static QString getNoReaderFoundIconPath(); -}; - -} /* namespace governikus */ diff --git a/src/gui/generic/TabButtonGroup.cpp b/src/gui/generic/TabButtonGroup.cpp deleted file mode 100644 index f28fa90..0000000 --- a/src/gui/generic/TabButtonGroup.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*! - * TabButtonGroup.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "TabButtonGroup.h" - -#include -#include -#include -#include -#include - -using namespace governikus; - -static QAccessibleInterface* createTabButtonInterface(const QString& pKey, QObject* pObject) -{ - if (pObject->isWidgetType() && pKey == QLatin1String("governikus::TabButton")) - { - return new AccessibleTabButton(static_cast(pObject)); - } - - if (pObject->isWidgetType() && pKey == QLatin1String("governikus::TabButtonGroup")) - { - return new AccessibleTabButtonGroup(static_cast(pObject)); - } - - return nullptr; -} - - -static void registerInterfaceFactory() -{ - static bool registered = (QAccessible::installFactory(&createTabButtonInterface), true); - (void) registered; -} - - -TabButton::TabButton(QWidget* pParent) - : QToolButton(pParent) -{ - registerInterfaceFactory(); -} - - -TabButton::~TabButton() -{ -} - - -void TabButton::focusInEvent(QFocusEvent* /*pEvent*/) -{ - setChecked(true); -} - - -void TabButton::nextCheckState() -{ - setChecked(true); -} - - -TabButtonGroup::TabButtonGroup(QWidget* pParent) - : QWidget(pParent) - , mButtonGroup(new ExclusiveButtonGroup(this)) - , mWorkflowActive(false) -{ - registerInterfaceFactory(); - - setFocusPolicy(Qt::TabFocus); - - connect(mButtonGroup, &ExclusiveButtonGroup::buttonToggled, this, &TabButtonGroup::onButtonToggled); -} - - -TabButtonGroup::~TabButtonGroup() -{ -} - - -void TabButtonGroup::addButton(QAbstractButton* pButton) -{ - mButtonGroup->addButton(pButton); - - updateFocusPolicies(); - - if (pButton->parent() != this) - { - pButton->setParent(this); - } - - pButton->installEventFilter(this); -} - - -void TabButtonGroup::setWorkflowActive(bool pWorkflowActiv) -{ - mWorkflowActive = pWorkflowActiv; -} - - -bool TabButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) -{ - if (pEvent->type() != QEvent::KeyPress) - { - return false; - } - - QAbstractButton* button = qobject_cast(pWatched); - if (button == nullptr) - { - return false; - } - - // Handle cursor key navigation manually. It doesn't work, since only one - // button is focussable at all. - bool navigate = false; - bool cycle = false; - bool next = true; - - QKeyEvent* keyEvent = static_cast(pEvent); - switch (keyEvent->key()) - { - case Qt::Key_Up: - next = false; - - // fall through - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Down: - { - bool reverse = layoutDirection() == Qt::RightToLeft; - if ((keyEvent->key() == Qt::Key_Left && !reverse) - || (keyEvent->key() == Qt::Key_Right && reverse)) - { - next = false; - } - - navigate = true; - break; - } - - case Qt::Key_Tab: - case Qt::Key_Backtab: - { - Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); - if ((modifiers& Qt::CTRL) != 0 && (modifiers & ~(Qt::CTRL | Qt::SHIFT)) == 0) - { - navigate = true; - cycle = true; - next = keyEvent->key() == Qt::Key_Tab; - } - break; - } - } - - if (!navigate) - { - return false; - } - - pEvent->accept(); - - if (QAbstractButton* nextButton = getNextPrevFocussableButton(button, next, cycle)) - { - if (!mWorkflowActive) - { - nextButton->setChecked(true); - } - } - - return true; -} - - -void TabButtonGroup::onButtonToggled(QAbstractButton* pButton, bool pChecked) -{ - updateFocusPolicies(); - - if (pButton->isChecked()) - { - pButton->setFocus(); - } - - Q_EMIT buttonToggled(pButton, pChecked); -} - - -QAbstractButton* TabButtonGroup::getNextPrevFocussableButton(QAbstractButton* pCurrentButton, bool pNext, bool pCycle) const -{ - const QVector& buttons = mButtonGroup->getButtons(); - int count = buttons.count(); - if (count == 0) - { - return nullptr; - } - - int index; - if (pCurrentButton != nullptr) - { - index = buttons.indexOf(pCurrentButton); - } - else - { - index = pNext ? count - 1 : 0; - } - - if (index < 0) - { - return nullptr; - } - - int direction = pNext ? 1 : -1; - for (;; ) - { - index += direction; - if (index < 0 || index >= count) - { - if (!pCycle) - { - return nullptr; - } - - pCycle = false; - index = (index + count) % count; - } - - QAbstractButton* button = buttons.at(index); - if (button->isVisibleTo(this)) - { - return button; - } - } -} - - -void TabButtonGroup::updateFocusPolicies() -{ - bool anyButtonFocussable = false; - const QVector& buttons = mButtonGroup->getButtons(); - for (QAbstractButton* button : buttons) - { - bool buttonFocussable = button->isChecked() && button->isVisibleTo(button->parentWidget()); - anyButtonFocussable |= buttonFocussable; - button->setFocusPolicy(buttonFocussable ? Qt::TabFocus : Qt::NoFocus); - } - - if (anyButtonFocussable) - { - setFocusPolicy(Qt::NoFocus); - } - else - { - setFocusPolicy(Qt::TabFocus); - for (QAbstractButton* button : buttons) - { - if (button->isVisibleTo(button->parentWidget())) - { - button->setFocusPolicy(Qt::TabFocus); - break; - } - } - } -} - - -void TabButtonGroup::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -AccessibleTabButton::AccessibleTabButton(QWidget* pWidget) - : QAccessibleWidget(pWidget, QAccessible::PageTab) -{ -} - - -TabButton* AccessibleTabButton::getTabButton() const -{ - return static_cast(widget()); -} - - -QString AccessibleTabButton::text(QAccessible::Text /*pText*/) const -{ - QString result = getTabButton()->text(); - return result.replace(QLatin1Char('&'), QString()); -} - - -QStringList AccessibleTabButton::actionNames() const -{ - return QStringList(pressAction()); -} - - -void AccessibleTabButton::doAction(const QString& pActionName) -{ - if (pActionName == pressAction()) - { - getTabButton()->setChecked(true); - } -} - - -AccessibleTabButtonGroup::AccessibleTabButtonGroup(QWidget* pWidget) - : QAccessibleWidget(pWidget, QAccessible::PageTabList) -{ -} - - -AccessibleTabButtonGroup::~AccessibleTabButtonGroup() -{ -} - - -TabButtonGroup* AccessibleTabButtonGroup::getTabButtonGroup() const -{ - return static_cast(widget()); -} diff --git a/src/gui/generic/TabButtonGroup.h b/src/gui/generic/TabButtonGroup.h deleted file mode 100644 index 55de8bd..0000000 --- a/src/gui/generic/TabButtonGroup.h +++ /dev/null @@ -1,117 +0,0 @@ -/*! - * TabButtonGroup.h - * - * \brief Contains the accessibility friendly TabButtonGroup and TabButton classes. - * - * The other classes defined in this header are implementation private. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "ExclusiveButtonGroup.h" - -#include -#include - -namespace governikus -{ - -/*! - * \brief A push button that is presented to accessibility clients as a page tab. - */ -class TabButton - : public QToolButton -{ - Q_OBJECT - - public: - TabButton(QWidget* pParent = nullptr); - virtual ~TabButton(); - - protected: - virtual void focusInEvent(QFocusEvent* pEvent) override; - virtual void nextCheckState() override; -}; - -/*! - * \brief A widget that is presented to accessibility clients as a page tab list, - * but uses TabButtons as tabs. - * - * The class is a regular widget. Buttons (that must be checkable) added via - * addButton() are added to an exclusive button group. Only one button can be - * checked at a time. The focus handling and cursor key navigation is overridden - * so that it works like in the tab row of a regular QTabWidget. - */ -class TabButtonGroup - : public QWidget -{ - Q_OBJECT - - public: - TabButtonGroup(QWidget* pParent = nullptr); - virtual ~TabButtonGroup(); - - void addButton(QAbstractButton* pButton); - - void setWorkflowActive(bool pWorkflowActiv); - - virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; - - private Q_SLOTS: - void onButtonToggled(QAbstractButton* pButton, bool pChecked); - - private: - QAbstractButton* getNextPrevFocussableButton(QAbstractButton* pCurrentButton, bool pNext, bool pCycle) const; - void updateFocusPolicies(); - - private: - ExclusiveButtonGroup* mButtonGroup; - bool mWorkflowActive; - void paintEvent(QPaintEvent*) override; - - Q_SIGNALS: - void buttonToggled(QAbstractButton* pButton, bool pChecked); -}; - -/*! - * \brief Implementation private class providing the accessibility functionality - * for TabButton. - */ -class AccessibleTabButton - : public QAccessibleWidget -{ - public: - typedef QVector > RelationList; - - public: - AccessibleTabButton(QWidget* pWidget); - - TabButton* getTabButton() const; - - virtual QString text(QAccessible::Text pText) const override; - - virtual QStringList actionNames() const override; - virtual void doAction(const QString& pActionName) override; - -}; - -/*! - * \brief Implementation private class providing the accessibility functionality - * for TabButtonGroup. - */ -class AccessibleTabButtonGroup - : public QAccessibleWidget -{ - public: - typedef QVector > RelationList; - - public: - AccessibleTabButtonGroup(QWidget* pWidget); - virtual ~AccessibleTabButtonGroup(); - - TabButtonGroup* getTabButtonGroup() const; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/AuthenticateStepsWidget.cpp b/src/gui/step/AuthenticateStepsWidget.cpp deleted file mode 100644 index 03998e6..0000000 --- a/src/gui/step/AuthenticateStepsWidget.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * AuthenticateStepsWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "AuthenticateStepsWidget.h" -#include "ui_AuthenticateStepsWidget.h" - -#include - -#include "AppStartPage.h" -#include "generic/BusyOverlayContainer.h" - -using namespace governikus; - -AuthenticateStepsWidget::AuthenticateStepsWidget(QWidget* pParent) - : QStackedWidget(pParent) - , mUi(new Ui::AuthenticateStepsWidget()) - , mProcessingPage(new BusyOverlayContainer(new AppStartPage(), false)) -{ - mUi->setupUi(this); - - addWidget(mProcessingPage); -} - - -AuthenticateStepsWidget::~AuthenticateStepsWidget() -{ -} - - -StepAuthenticationEac1Widget* AuthenticateStepsWidget::getEac1Page() const -{ - return mUi->authenticationEac1Page; -} - - -SelfInfoWidget* AuthenticateStepsWidget::getSelfInfoPage() const -{ - return mUi->selfInfoPage; -} - - -void AuthenticateStepsWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/gui/step/AuthenticateStepsWidget.h b/src/gui/step/AuthenticateStepsWidget.h deleted file mode 100644 index 09c1b88..0000000 --- a/src/gui/step/AuthenticateStepsWidget.h +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * AuthenticateStepsWidget.h - * - * \brief A stacked widget containing the widgets for the authentication steps. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class AuthenticateStepsWidget; -} - -class QAbstractButton; - -namespace governikus -{ - -class BusyOverlayContainer; -class SelfInfoWidget; -class StepAuthenticationEac1Widget; - -class AuthenticateStepsWidget - : public QStackedWidget -{ - Q_OBJECT - - public: - AuthenticateStepsWidget(QWidget* pParent = nullptr); - virtual ~AuthenticateStepsWidget(); - - BusyOverlayContainer* getProcessingPage() const - { - return mProcessingPage; - } - - - StepAuthenticationEac1Widget* getEac1Page() const; - - SelfInfoWidget* getSelfInfoPage() const; - - protected: - void paintEvent(QPaintEvent*) override; - - private: - QScopedPointer mUi; - BusyOverlayContainer* mProcessingPage; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/SelfInfoWidget.cpp b/src/gui/step/SelfInfoWidget.cpp deleted file mode 100644 index 02736b2..0000000 --- a/src/gui/step/SelfInfoWidget.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/*! - * SelfInfoWidget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "SelfInfoWidget.h" - -#include "generic/ListItem.h" -#include "generic/ListItemSubTitle.h" -#include "generic/ListItemTitle.h" -#include "PdfCreator.h" -#include "SelfAuthenticationData.h" -#include "ui_SelfInfoWidget.h" - -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -SelfInfoWidget::SelfInfoWidget(QWidget* pParent) - : QWidget(pParent) - , mUi(new Ui::SelfInfoWidget()) - , mData(nullptr) -{ - mUi->setupUi(this); - layout()->setMargin(20); -} - - -SelfInfoWidget::~SelfInfoWidget() -{ -} - - -QString SelfInfoWidget::formatDateString(const QString& pIn) -{ - QDateTime dateTime = QDateTime::fromString(pIn, QStringLiteral("yyyy-MM-dd+hh:mm")); - return dateTime.toString(tr("dd.MM.yyyy")); -} - - -void SelfInfoWidget::setInfo(SelfAuthenticationData* pData) -{ - mData = pData; - - //delete old data from ui - QLayout* uiLayout = mUi->dataLayout; - - cleanLayout(uiLayout); - cleanLayout(mUi->saveLayout); - - - //fill layout with new data, see 18 Personalausweisgesetz (PAuswG) - if (!mData->getValue(SelfAuthData::FamilyNames).isNull()) - { - insertDataRow(tr("Family name:"), mData->getValue(SelfAuthData::FamilyNames)); - } - if (!mData->getValue(SelfAuthData::BirthName).isNull()) - { - insertDataRow(tr("Birth name:"), mData->getValue(SelfAuthData::BirthName)); - } - if (!mData->getValue(SelfAuthData::GivenNames).isNull()) - { - insertDataRow(tr("Given name(s):"), mData->getValue(SelfAuthData::GivenNames)); - } - if (!mData->getValue(SelfAuthData::AcademicTitle).isNull()) - { - insertDataRow(tr("Doctoral degree:"), mData->getValue(SelfAuthData::AcademicTitle)); - } - if (!mData->getValue(SelfAuthData::DateOfBirth).isNull()) - { - insertDataRow(tr("Date of birth:"), formatDateString(mData->getValue(SelfAuthData::DateOfBirth))); - } - if (!mData->getValue(SelfAuthData::PlaceOfBirth).isNull()) - { - insertDataRow(tr("Place of birth:"), mData->getValue(SelfAuthData::PlaceOfBirth)); - } - - if (!mData->getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo).isNull()) - { - insertDataRow(tr("Address:"), mData->getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo)); - } - if (!mData->getValue(SelfAuthData::PlaceOfResidenceStreet).isNull()) - { - insertDataRow(mData->getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo).isNull() ? tr("Address:") : QString(), mData->getValue(SelfAuthData::PlaceOfResidenceStreet)); - } - if (!mData->getValue(SelfAuthData::PlaceOfResidenceZipCode).isNull() || !mData->getValue(SelfAuthData::PlaceOfResidenceCity).isNull()) - { - insertDataRow(mData->getValue(SelfAuthData::PlaceOfResidenceStreet).isNull() ? tr("Address:") : QString(), mData->getValue(SelfAuthData::PlaceOfResidenceZipCode) + ' ' + mData->getValue(SelfAuthData::PlaceOfResidenceCity)); - - } - if (!mData->getValue(SelfAuthData::PlaceOfResidenceCountry).isNull()) - { - insertDataRow(QString(), mData->getValue(SelfAuthData::PlaceOfResidenceCountry)); - - } - - auto documentType = mData->getValue(SelfAuthData::DocumentType); - if (!documentType.isNull()) - { - insertDataRow(tr("Document type:"), documentType); - } - if (!mData->getValue(SelfAuthData::Nationality).isNull()) - { - insertDataRow(tr("Nationality:"), mData->getValue(SelfAuthData::Nationality)); - } - if (!mData->getValue(SelfAuthData::ArtisticName).isNull()) - { - insertDataRow(tr("Religious / artistic name:"), mData->getValue(SelfAuthData::ArtisticName)); - } - if (!mData->getValue(SelfAuthData::IssuingState).isNull()) - { - insertDataRow(tr("Issuing country:"), mData->getValue(SelfAuthData::IssuingState)); - } - - // Show "Residence Permit" for eAT- and Test-Cards only - // AR, AS, AF --> see TR-03127 (v1.16) chapter 3.2.3 - // TA --> Used by Test-Cards - if (!mData->getValue(SelfAuthData::ResidencePermitI).isNull() && ( - documentType == QLatin1String("AR") || - documentType == QLatin1String("AS") || - documentType == QLatin1String("AF") || - documentType == QLatin1String("TA"))) - { - insertDataRow(tr("Residence permit I:"), mData->getValue(SelfAuthData::ResidencePermitI)); - } - - QPushButton* exportButton = new QPushButton(tr("Save as PDF...")); - exportButton->setAccessibleName(tr("save id card data as pdf")); - - connect(exportButton, &QPushButton::clicked, this, &SelfInfoWidget::onPrintButtonClicked); - - mUi->saveLayout->addWidget(exportButton); - mUi->saveLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); -} - - -void SelfInfoWidget::cleanLayout(QLayout* pLayout) -{ - while (QLayoutItem* child = pLayout->itemAt(0)) - { - if (QWidget* childWidget = child->widget()) - { - pLayout->removeWidget(childWidget); - delete childWidget; - } - else - { - pLayout->removeItem(child); - delete child; - } - } -} - - -void SelfInfoWidget::insertDataRow(const QString& pLabel, const QString& pField) -{ - QLabel* tmpLabel = new QLabel(pLabel); - tmpLabel->setFocusPolicy(Qt::TabFocus); - tmpLabel->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - - QLabel* tmpField = new QLabel(pField); - tmpField->setFocusPolicy(Qt::TabFocus); - tmpField->setWordWrap(true); - - mUi->dataLayout->insertRow(-1, tmpLabel, tmpField); -} - - -void SelfInfoWidget::paintEvent(QPaintEvent*) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} - - -void SelfInfoWidget::onPrintButtonClicked() -{ - if (mData != nullptr && mData->isValid()) - { - QString pdfName = QFileDialog::getSaveFileName(this, - QApplication::applicationName() + " - " + tr("Save"), - QDir::currentPath(), - tr("PDF Documents") + " (*.pdf)"); - - if (pdfName.size() > 0) - { - PdfCreator pdf(pdfName); - QString text; - - 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()) - { - QLabel* label = qobject_cast(item->widget()); - - if (i % 2 == 0) - { - text = label->text(); - } - else - { - pdf.addTableRow({text, label->text()}); - pdf.toggleRowColor(); - } - } - } - - pdf.save(); - QDesktopServices::openUrl(pdf.getFileUrl()); - } - } -} diff --git a/src/gui/step/SelfInfoWidget.h b/src/gui/step/SelfInfoWidget.h deleted file mode 100644 index bf4b4b9..0000000 --- a/src/gui/step/SelfInfoWidget.h +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * SelfInfoWidget.h - * - * \brief A widget displaying the card data retrieved in the self info workflow. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -namespace Ui -{ -class SelfInfoWidget; -} - -namespace governikus -{ - -class SelfAuthenticationData; - -class SelfInfoWidget - : public QWidget -{ - Q_OBJECT - - public: - SelfInfoWidget(QWidget* pParent = nullptr); - virtual ~SelfInfoWidget(); - - void setInfo(SelfAuthenticationData* pData); - - protected: - void paintEvent(QPaintEvent*) override; - - private: - QScopedPointer mUi; - SelfAuthenticationData* mData; - - QString formatDateString(const QString& pIn); - void insertDataRow(const QString& pLabel, const QString& pField); - void cleanLayout(QLayout* pLayout); - - private Q_SLOTS: - void onPrintButtonClicked(); -}; - -} /* namespace governikus */ diff --git a/src/gui/step/SelfInfoWidget.ui b/src/gui/step/SelfInfoWidget.ui deleted file mode 100644 index e2babfd..0000000 --- a/src/gui/step/SelfInfoWidget.ui +++ /dev/null @@ -1,180 +0,0 @@ - - - SelfInfoWidget - - - - 0 - 0 - 515 - 400 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 0 - 20 - - - - - - - - - 9 - - - 9 - - - 9 - - - 9 - - - - - - 75 - true - - - - Qt::TabFocus - - - The following data has been read out from your ID card: - - - true - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 3 - - - - - - - 6 - - - 3 - - - 0 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 0 - 20 - - - - - - - - - - - governikus::DescriptionLabel - QLabel -
generic/DescriptionLabel.h
-
-
- - -
diff --git a/src/gui/step/StepAdviseUserToRemoveCardGui.cpp b/src/gui/step/StepAdviseUserToRemoveCardGui.cpp deleted file mode 100644 index 759fcbc..0000000 --- a/src/gui/step/StepAdviseUserToRemoveCardGui.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepAdviseUserToRemoveCardGui.h" - -#include "PinSettingsWidget.h" -#include "ReaderManager.h" - -#include - - -using namespace governikus; - - -void StepAdviseUserToRemoveCardGui::onReaderManagerSignal() -{ - if (ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).getCardType() == CardType::NONE) - { - qDebug() << "No more ID cards found -> auto closing card reminder dialog"; - - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - - mMessageBox->reject(); - } -} - - -StepAdviseUserToRemoveCardGui::StepAdviseUserToRemoveCardGui(QSharedPointer pContext, QWidget* pMainWidget) - : StepGui(pContext) - , mContext(pContext) - , mMainWidget(pMainWidget) - , mMessageBox(nullptr) -{ -} - - -StepAdviseUserToRemoveCardGui::~StepAdviseUserToRemoveCardGui() -{ -} - - -void StepAdviseUserToRemoveCardGui::activate() -{ - setCancelButtonState(ButtonState::HIDDEN); - - if (ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).getCardType() == CardType::NONE) - { - return; - } - - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); - - if (mMessageBox == nullptr) - { - mMessageBox = new QMessageBox(mMainWidget); - mMessageBox->setWindowTitle(QCoreApplication::applicationName() + " - Information"); - mMessageBox->setWindowModality(Qt::WindowModal); - 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/StepAdviseUserToRemoveCardGui.h b/src/gui/step/StepAdviseUserToRemoveCardGui.h deleted file mode 100644 index 7827e29..0000000 --- a/src/gui/step/StepAdviseUserToRemoveCardGui.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * StepAdviseUserToRemoveCardGui.h - * - * \brief Qt UI for the advise user to remove card step. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "StepGui.h" - -#include -#include - -namespace governikus -{ - -class StepAdviseUserToRemoveCardGui - : public StepGui -{ - Q_OBJECT - - public Q_SLOTS: - void onReaderManagerSignal(); - - public: - StepAdviseUserToRemoveCardGui(QSharedPointer pContext, QWidget* const pMainWidget); - virtual ~StepAdviseUserToRemoveCardGui(); - - virtual void activate(); - - private: - QSharedPointer mContext; - QWidget* const mMainWidget; - QMessageBox* mMessageBox; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepAuthenticationDoneGui.cpp b/src/gui/step/StepAuthenticationDoneGui.cpp deleted file mode 100644 index 00b1f65..0000000 --- a/src/gui/step/StepAuthenticationDoneGui.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepAuthenticationDoneGui.h" - -using namespace governikus; - - -StepAuthenticationDoneGui::StepAuthenticationDoneGui(QSharedPointer pContext) - : StepGui(pContext) -{ -} - - -StepAuthenticationDoneGui::~StepAuthenticationDoneGui() -{ -} - - -void StepAuthenticationDoneGui::forwardStep() -{ - Q_EMIT fireCancelled(); -} diff --git a/src/gui/step/StepAuthenticationDoneGui.h b/src/gui/step/StepAuthenticationDoneGui.h deleted file mode 100644 index c858288..0000000 --- a/src/gui/step/StepAuthenticationDoneGui.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * \brief Qt UI for the authentication done step. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "StepGui.h" - - -namespace governikus -{ - -class StepAuthenticationDoneGui - : public StepGui -{ - Q_OBJECT - - public: - StepAuthenticationDoneGui(QSharedPointer pContext); - virtual ~StepAuthenticationDoneGui(); - - virtual void forwardStep() override; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepAuthenticationEac1Gui.cpp b/src/gui/step/StepAuthenticationEac1Gui.cpp deleted file mode 100644 index d57ed5a..0000000 --- a/src/gui/step/StepAuthenticationEac1Gui.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "generic/GuiUtils.h" -#include "step/AuthenticateStepsWidget.h" -#include "step/StepAuthenticationEac1Widget.h" -#include "StepAuthenticationEac1Gui.h" - -#include - -using namespace governikus; - -StepAuthenticationEac1Gui::StepAuthenticationEac1Gui(QSharedPointer pContext, - AuthenticateStepsWidget* pStepsWidget) - : StepGui(pContext) - , mContext(pContext) - , mStepsWidget(pStepsWidget) - , mWidget(nullptr) - , mState(StepDidAuthenticateEac1Ui::State::EDIT_CHAT) - , mPayAttentionToReaderMsgBox(new QMessageBox(pStepsWidget->window())) -{ - mPayAttentionToReaderMsgBox->setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Information")); - mPayAttentionToReaderMsgBox->setText(tr("Please observe the display of your card reader.")); - mPayAttentionToReaderMsgBox->setIcon(QMessageBox::Information); - mPayAttentionToReaderMsgBox->setStandardButtons(QMessageBox::NoButton); -} - - -StepAuthenticationEac1Gui::~StepAuthenticationEac1Gui() -{ -} - - -void StepAuthenticationEac1Gui::activate() -{ - mWidget = mStepsWidget->getEac1Page(); - - connect(mWidget, &StepAuthenticationEac1Widget::setForwardButtonState, getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState); - connect(mWidget, &StepAuthenticationEac1Widget::setCancelButtonState, getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState); - - connect(mWidget, &StepAuthenticationEac1Widget::fireCanUpdated, this, &StepAuthenticationEac1Gui::onCanUpdated); - connect(mWidget, &StepAuthenticationEac1Widget::firePinUpdated, this, &StepAuthenticationEac1Gui::onPinUpdated); - - connect(this, &StepAuthenticationEac1Gui::fireUiFinished, this, &StepAuthenticationEac1Gui::onUiFinished); - - mWidget->setContext(mContext); - mWidget->setState(StepDidAuthenticateEac1Ui::State::INITIAL); - mStepsWidget->setCurrentWidget(mWidget); -} - - -void StepAuthenticationEac1Gui::deactivate() -{ - mWidget->setContext(QSharedPointer()); - - disconnect(mWidget, &StepAuthenticationEac1Widget::setForwardButtonState, getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState); - disconnect(mWidget, &StepAuthenticationEac1Widget::setCancelButtonState, getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState); - - disconnect(mWidget, &StepAuthenticationEac1Widget::fireCanUpdated, this, &StepAuthenticationEac1Gui::onCanUpdated); - disconnect(mWidget, &StepAuthenticationEac1Widget::firePinUpdated, this, &StepAuthenticationEac1Gui::onPinUpdated); - - disconnect(this, &StepAuthenticationEac1Gui::fireUiFinished, this, &StepAuthenticationEac1Gui::onUiFinished); -} - - -void StepAuthenticationEac1Gui::setState(StepDidAuthenticateEac1Ui::State pState) -{ - mState = pState; - - mWidget->setState(pState); - - if (pState == StepDidAuthenticateEac1Ui::State::FINISHED) - { - forwardStep(); - } -} - - -void StepAuthenticationEac1Gui::incorrectPinError() -{ - mWidget->updateButtonsAndPinWidget(); - - GuiUtils::showPinCanPukErrorDialog(mContext->getLastPaceResult(), mContext->getCardConnection()->getReaderInfo().getRetryCounter(), mStepsWidget->window()); -} - - -void StepAuthenticationEac1Gui::forwardStep() -{ - if (mState == StepDidAuthenticateEac1Ui::State::FINISHED) - { - Q_EMIT fireUiFinished(); - return; - } - - mWidget->forwardStep(); - - Q_EMIT fireUiFinished(); -} - - -void StepAuthenticationEac1Gui::hidePayAttentionToReader() -{ - mPayAttentionToReaderMsgBox->reject(); -} - - -void StepAuthenticationEac1Gui::onShowPayAttentionToReader() -{ - mPayAttentionToReaderMsgBox->open(); -} - - -void StepAuthenticationEac1Gui::onPinUpdated(const QString& pPin) -{ - mPin = pPin; -} - - -void StepAuthenticationEac1Gui::onCanUpdated(const QString& pCan) -{ - mCan = pCan; -} - - -void StepAuthenticationEac1Gui::onUiFinished() -{ - mContext->setCan(mCan); - mContext->setPin(mPin); - mContext->setStateApproved(); -} diff --git a/src/gui/step/StepAuthenticationEac1Gui.h b/src/gui/step/StepAuthenticationEac1Gui.h deleted file mode 100644 index 79aa5e8..0000000 --- a/src/gui/step/StepAuthenticationEac1Gui.h +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "StepGui.h" - -#include -#include - -namespace governikus -{ - -class AuthenticateStepsWidget; -class StepAuthenticationEac1Widget; - -class StepAuthenticationEac1Gui - : public StepGui -{ - Q_OBJECT - - private: - QSharedPointer mContext; - AuthenticateStepsWidget* mStepsWidget; - StepAuthenticationEac1Widget* mWidget; - StepDidAuthenticateEac1Ui::State mState; - QPointer mPayAttentionToReaderMsgBox; - QString mPin; - QString mCan; - - public: - StepAuthenticationEac1Gui(QSharedPointer pContext, AuthenticateStepsWidget* pStepsWidget); - virtual ~StepAuthenticationEac1Gui(); - - virtual void activate() override; - virtual void deactivate() override; - - virtual void setState(StepDidAuthenticateEac1Ui::State pState); - virtual void incorrectPinError(); - - virtual void forwardStep() override; - - virtual void hidePayAttentionToReader(); - - public Q_SLOTS: - virtual void onShowPayAttentionToReader(); - void onPinUpdated(const QString& pPin); - void onCanUpdated(const QString& pCan); - void onUiFinished(); -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepAuthenticationEac1Widget.cpp b/src/gui/step/StepAuthenticationEac1Widget.cpp deleted file mode 100644 index f9f1335..0000000 --- a/src/gui/step/StepAuthenticationEac1Widget.cpp +++ /dev/null @@ -1,613 +0,0 @@ -/*! - * StepAuthenticationEac1Widget.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepAuthenticationEac1Widget.h" -#include "ui_StepAuthenticationEac1Widget.h" - -#include "AppSettings.h" -#include "CardConnection.h" -#include "DetailDialog.h" -#include "generic/GuiUtils.h" -#include "generic/PasswordEdit.h" -#include "RandomPinDialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN32 -#include -#endif - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(gui) - -StepAuthenticationEac1Widget::StepAuthenticationEac1Widget(QWidget* pParent) - : QWidget(pParent) - , mUi(new Ui::StepAuthenticationEac1Widget()) - , mContext() - , mCANField(nullptr) - , mPINField(nullptr) - , mState(StepDidAuthenticateEac1Ui::State::INITIAL) - , mProgressBar(nullptr) - , mProgressBarLabel(nullptr) - , mCloseWindowWhenFinished() -#ifdef Q_OS_WIN32 - , mTaskbarButton(new QWinTaskbarButton(this)) -#endif -{ - mUi->setupUi(this); - - mUi->listWidgetWest->setAttribute(Qt::WA_MacShowFocusRect, false); - mUi->listWidgetEast->setAttribute(Qt::WA_MacShowFocusRect, false); - - connect(mUi->detailsPushButton, &QPushButton::clicked, this, &StepAuthenticationEac1Widget::onDetailsButtonClicked); -} - - -StepAuthenticationEac1Widget::~StepAuthenticationEac1Widget() -{ -} - - -void StepAuthenticationEac1Widget::setContext(const QSharedPointer& pContext) -{ - mContext = pContext; - #ifdef Q_OS_WIN32 - connect(mContext.data(), &AuthContext::fireResultChanged, this, &StepAuthenticationEac1Widget::onResultChanged); - #endif -} - - -void StepAuthenticationEac1Widget::setState(StepDidAuthenticateEac1Ui::State pState) -{ - if (pState == mState) - { - return; - } - mState = pState; - - 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); - updateProgressPanel(1, tr("Service provider is verified")); - break; - - case StepDidAuthenticateEac1Ui::State::AUTHENTICATING_CARD: - updateProgressPanel(2, tr("Card is being verified")); - break; - - case StepDidAuthenticateEac1Ui::State::READING_CARD_DATA: - updateProgressPanel(3, tr("Reading data")); - break; - - case StepDidAuthenticateEac1Ui::State::REDIRECTING_BROWSER: - 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; - } -} - - -void StepAuthenticationEac1Widget::forwardStep() -{ - Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); - - if (mState == StepDidAuthenticateEac1Ui::State::EDIT_CHAT) - { - 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()) - { - mUi->pinGroupBox->setVisible(false); - - int childCount = mUi->pinWidgetLayout->count(); - for (int i = 0; i < childCount; ++i) - { - QLayoutItem* child = mUi->pinWidgetLayout->itemAt(i); - if (child->widget() != nullptr) - { - child->widget()->setEnabled(false); - } - } - } - else - { - Q_EMIT setCancelButtonState(ButtonState::DISABLED); - } - } - -} - - -void StepAuthenticationEac1Widget::updateButtonsAndPinWidget() -{ - Q_EMIT setCancelButtonState(ButtonState::ENABLED); - - if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) - { - mUi->pinGroupBox->setTitle(tr("Please enter your six-digit card access number (CAN) and your PIN for identification.")); - } - else - { - mUi->pinGroupBox->setTitle(tr("Please enter your six digit PIN for identification")); - } - - if (mContext->getCardConnection()->getReaderInfo().isBasicReader()) - { - clearPinWidgetLayout(); - createBasicReaderWidget(); - focusWidget(); - } - else - { - 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")); -} - - -void StepAuthenticationEac1Widget::clearPinWidgetLayout() -{ - while (QLayoutItem* child = mUi->pinWidgetLayout->itemAt(0)) - { - if (QWidget* childWidget = child->widget()) - { - mUi->pinWidgetLayout->removeWidget(childWidget); - delete childWidget; - } - else - { - mUi->pinWidgetLayout->removeItem(child); - delete child; - } - } - - mProgressBar = nullptr; - mProgressBarLabel = nullptr; -} - - -void StepAuthenticationEac1Widget::onDetailsButtonClicked() -{ - DetailDialog d(this); - - auto eac1 = mContext->getDidAuthenticateEac1(); - CVCertificateBody body = eac1->getCvCertificates().at(0)->getBody(); - QString effectiveDate = body.getCertificateEffectiveDate().toString(Qt::DefaultLocaleShortDate); - QString expirationDate = body.getCertificateExpirationDate().toString(Qt::DefaultLocaleShortDate); - auto certificateDescription = eac1->getCertificateDescription(); - - QString details; - details += tr("Service provider:") + "\n"; - details += certificateDescription->getSubjectName(); - details += '\n'; - details += certificateDescription->getSubjectUrl(); - - details += "\n\n" + tr("Certificate issuer:") + "\n"; - details += certificateDescription->getIssuerName(); - details += '\n'; - details += certificateDescription->getIssuerUrl(); - - details += QLatin1String("\n\n"); - details += certificateDescription->getTermsOfUsage(); - details += QLatin1String("\n\n"); - details += tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate); - - // collapse multiple blank lines - details.replace(QRegularExpression(QStringLiteral("\n\n\n*")), QStringLiteral("\n\n")); - - d.setDetails(details); - d.exec(); -} - - -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() -{ - 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->getOptionalAccessRights().contains(orderedRight)) - { - addChatRightToGui(orderedRight, true, listSize); - } - else if (mContext->getRequiredAccessRights().contains(orderedRight)) - { - addChatRightToGui(orderedRight, false, listSize); - } - } -} - - -void StepAuthenticationEac1Widget::addChatRightToGui(AccessRight pRight, bool pOptional, int pListSize) -{ - QString displayText = AccessRoleAndRightsUtil::toDisplayText(pRight); - if (pRight == AccessRight::AGE_VERIFICATION) - { - displayText += QStringLiteral(" (%1)").arg(mContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); - } - QCheckBox* cb = new QCheckBox(displayText); - cb->setEnabled(pOptional); - cb->setChecked(mContext->getEffectiveAccessRights().contains(pRight)); - - mMap.insert(cb, pRight); - - connect(cb, &QCheckBox::stateChanged, this, &StepAuthenticationEac1Widget::checkBoxChanged); - - QListWidgetItem* item = new QListWidgetItem(); - item->setSizeHint(QSize(0, 20)); - if (mUi->listWidgetWest->count() < pListSize) - { - mUi->listWidgetWest->addItem(item); - mUi->listWidgetWest->setItemWidget(item, cb); - } - else - { - mUi->listWidgetEast->addItem(item); - mUi->listWidgetEast->setItemWidget(item, cb); - } -} - - -void StepAuthenticationEac1Widget::createBasicReaderWidget() -{ - QWidget* basicReaderWidget = new QWidget(); - - QHBoxLayout* basicReaderWidgetLayout = new QHBoxLayout(basicReaderWidget); - - AppSettings& appSettings = AppSettings::getInstance(); - - QRegularExpression onlyNumbersExpression(QStringLiteral("[0-9]*")); - if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) - { - mCANField = new PasswordEdit(); - mCANField->setKeylessPasswordMode(false); - mCANField->setFieldWidth(6); - mCANField->setMaxLength(6); - mCANField->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are permitted.")); - connect(mCANField, &PasswordEdit::textEdited, this, &StepAuthenticationEac1Widget::canTextEdited); - - QLabel* canLabel = new QLabel(tr("Card access number (CAN):")); - canLabel->setFocusPolicy(Qt::TabFocus); - basicReaderWidgetLayout->addWidget(canLabel); - basicReaderWidgetLayout->addWidget(mCANField); - - if (appSettings.getGeneralSettings().isUseScreenKeyboard()) - { - QToolButton* button = new QToolButton(); - button->setObjectName(QStringLiteral("canRandomButton")); - button->setAccessibleName(tr("open on screen password dialog")); - button->setAutoRaise(true); - button->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - button->setIconSize(QSize(44, 26)); - - connect(button, &QAbstractButton::clicked, this, &StepAuthenticationEac1Widget::onRandomButtonClicked); - - basicReaderWidgetLayout->addWidget(button); - } - - } - - mPINField = new PasswordEdit(); - mPINField->getLineEdit()->setAccessibleName(tr("More information with TAB")); - mPINField->setKeylessPasswordMode(false); - mPINField->setFieldWidth(6); - mPINField->setMaxLength(6); - mPINField->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are permitted.")); - connect(mPINField, &PasswordEdit::textEdited, this, &StepAuthenticationEac1Widget::pinTextEdited); - - if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) - { - mPINField->setEnabled(false); - } - - QLabel* pinLabel = new QLabel(tr("PIN:")); - pinLabel->setFocusPolicy(Qt::TabFocus); - basicReaderWidgetLayout->addWidget(pinLabel); - basicReaderWidgetLayout->addWidget(mPINField); - - if (appSettings.getGeneralSettings().isUseScreenKeyboard()) - { - QToolButton* button = new QToolButton(); - button->setObjectName(QStringLiteral("pinRandomButton")); - button->setAccessibleName(tr("open on screen password dialog")); - button->setAutoRaise(true); - button->setIcon(QPixmap(QStringLiteral(":images/randompin/screen_keyboard.png"))); - button->setIconSize(QSize(44, 26)); - - connect(button, &QAbstractButton::clicked, this, &StepAuthenticationEac1Widget::onRandomButtonClicked); - - basicReaderWidgetLayout->addWidget(button); - } - - - mUi->pinWidgetLayout->invalidate(); - mUi->pinWidgetLayout->addWidget(basicReaderWidget); -} - - -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()); - if (cb != nullptr) - { - if (pCheckState == Qt::Unchecked) - { - QMap::ConstIterator i = qAsConst(mMap).find(cb); - qCDebug(gui) << "remove from effective chat: " << i.value(); - mContext->removeEffectiveAccessRight(i.value()); - } - else - { - QMap::ConstIterator i = qAsConst(mMap).find(cb); - qCDebug(gui) << "set to effective chat: " << i.value(); - mContext->addEffectiveAccessRight(i.value()); - } - } -} - - -void StepAuthenticationEac1Widget::onRandomButtonClicked() -{ - RandomPinDialog randomPinDialog(6, mContext->getReaderName(), this); - if (randomPinDialog.exec() == QDialog::Accepted && !randomPinDialog.getPin().isEmpty()) - { - QToolButton* pinButton = qobject_cast(sender()); - if (pinButton == nullptr) - { - qCCritical(gui) << "sender == nullptr"; - } - else if (pinButton->objectName() == QLatin1String("canRandomButton")) - { - canTextEdited(randomPinDialog.getPin()); - } - else if (pinButton->objectName() == QLatin1String("pinRandomButton")) - { - pinTextEdited(randomPinDialog.getPin()); - } - } -} - - -void StepAuthenticationEac1Widget::onResultChanged() -{ -#ifdef Q_OS_WIN32 - if (mTaskbarButton && (mContext.isNull() || mContext->getStatus().isError())) - { - mTaskbarButton->progress()->stop(); - } -#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); -} - - -void StepAuthenticationEac1Widget::canTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mCANField->getLineEdit()->setText(pText); - } - - if (mCANField->text().size() == 6) - { - mPINField->setEnabled(true); - if (mCANField->isLineEditActive()) - { - mPINField->setFocus(); - } - Q_EMIT fireCanUpdated(mCANField->text()); - } - else - { - mPINField->setEnabled(false); - } - - mPINField->clear(); - pinTextEdited(QString()); -} - - -void StepAuthenticationEac1Widget::pinTextEdited(const QString& pText) -{ - if (!pText.isNull() && !pText.isEmpty()) - { - mPINField->getLineEdit()->setText(pText); - } - - if (mPINField->text().size() == 6) - { - if (mPINField->isLineEditActive()) - { - Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); - } - else - { - Q_EMIT setForwardButtonState(ButtonState::ENABLED, tr("Identify now")); - } - Q_EMIT firePinUpdated(mPINField->text()); - } - else - { - Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); - } -} - - -void StepAuthenticationEac1Widget::focusWidget() -{ - if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) - { - mCANField->setFocus(); - mCANField->setCursorPosition(0); - } - else - { - mPINField->setFocus(); - mPINField->setCursorPosition(0); - } -} diff --git a/src/gui/step/StepAuthenticationEac1Widget.h b/src/gui/step/StepAuthenticationEac1Widget.h deleted file mode 100644 index 1cf57bd..0000000 --- a/src/gui/step/StepAuthenticationEac1Widget.h +++ /dev/null @@ -1,104 +0,0 @@ -/*! - * StepAuthenticationEac1Widget.h - * - * \brief Widget for the desktop StepAuthenticationEac1Gui. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "StepGui.h" - -#include - -#ifdef Q_OS_WIN32 -#include -#endif - -class QLabel; -class QLineEdit; -class QProgressBar; - -namespace Ui -{ -class StepAuthenticationEac1Widget; -} - -class QAbstractButton; - -namespace governikus -{ - -class PasswordEdit; - -class StepAuthenticationEac1Widget - : public QWidget -{ - Q_OBJECT - - public: - StepAuthenticationEac1Widget(QWidget* pParent = nullptr); - virtual ~StepAuthenticationEac1Widget(); - - void setContext(const QSharedPointer& pContext); - - void setState(StepDidAuthenticateEac1Ui::State pState); - void forwardStep(); - - void updateButtonsAndPinWidget(); - - Q_SIGNALS: - void setForwardButtonState(ButtonState pState, const QString& pText = QString()); - void setCancelButtonState(ButtonState pState); - - void firePinUpdated(const QString& pPin); - void fireCanUpdated(const QString& pCan); - - private Q_SLOTS: - void focusWidget(); - void onDetailsButtonClicked(); - void checkBoxChanged(int pCheckState); - 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(); - - private: - QScopedPointer mUi; - QSharedPointer mContext; - QMap mMap; - - PasswordEdit* mCANField; - PasswordEdit* mPINField; - - StepDidAuthenticateEac1Ui::State mState; - QProgressBar* mProgressBar; - 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 deleted file mode 100644 index 711b20b..0000000 --- a/src/gui/step/StepAuthenticationEac1Widget.ui +++ /dev/null @@ -1,410 +0,0 @@ - - - StepAuthenticationEac1Widget - - - - 0 - 0 - 515 - 448 - - - - - 0 - 0 - - - - AusweisApp2 - - - - - - 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> - - - - - - - - - Service provider - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 6 - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - Purpose for reading out requested data: - - - - - - - Qt::TabFocus - - - true - - - - - - - Qt::TabFocus - - - Name: - - - - - - - Qt::TabFocus - - - true - - - - - - - - - - - 0 - 0 - - - - - 75 - true - - - - details - - - more... - - - false - - - - - - - - - - - - - Qt::TabFocus - - - The following data is required by the service provider. You can deselect the non-mandatory data fields if you do not want this data to be transmitted. - - - true - - - - - - - Qt::TabFocus - - - <html><head/><body><p align="justify">Here you can select or deselect data fields to be read out. Mandatory data fields required by the service provider cannot be deselected.</p></body></html> - - - - - - - - - Data - - - - 9 - - - 9 - - - 9 - - - 9 - - - - - 0 - - - - - true - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - Qt::ScrollBarAsNeeded - - - - - - - true - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - Qt::ScrollBarAsNeeded - - - 0 - - - - - - - - - - - - Qt::TabFocus - - - Important transactional information - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - true - - - - - 0 - 0 - 475 - 69 - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::TabFocus - - - background-color: white; - - - - - - Qt::PlainText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - - - - - - - - - - - - - - - 0 - - - 9 - - - 9 - - - 9 - - - 9 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - certificateDescriptionGroupBox - subjectNameLabel - subjectName - usageLabel - usage - detailsPushButton - label - groupBox - listWidgetWest - listWidgetEast - transactionInfoGroupBox - - - - diff --git a/src/gui/step/StepChooseCardGui.cpp b/src/gui/step/StepChooseCardGui.cpp deleted file mode 100644 index 77c4978..0000000 --- a/src/gui/step/StepChooseCardGui.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepChooseCardGui.h" - -#include "generic/BusyOverlayContainer.h" -#include "generic/SmartCardUtil.h" -#include "GuiProfile.h" -#include "step/AuthenticateStepsWidget.h" - -#include -#include -#include -#include -#include - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -StepChooseCardGui::StepChooseCardGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget) - : StepGui(pContext) - , mInformationMessageBox(new QMessageBox(pStepsWidget)) - , mDiagnosisGui(new DiagnosisGui(pStepsWidget)) - , mReaderDriverGui(new ReaderDriverGui(pStepsWidget)) - , mCancelButton(nullptr) - , mReaderDriverButton(nullptr) - , mDiagnosisButton(nullptr) - , mContext(pContext) -{ - mInformationMessageBox->setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - Information")); - mInformationMessageBox->setWindowModality(Qt::WindowModal); - mInformationMessageBox->setWindowFlags(mInformationMessageBox->windowFlags() & ~Qt::WindowContextHelpButtonHint); - mCancelButton = mInformationMessageBox->addButton(tr("Cancel"), QMessageBox::NoRole); - mDiagnosisButton = mInformationMessageBox->addButton(tr("Diagnosis"), QMessageBox::YesRole); - //mReaderDriverButton = mInformationMessageBox->addButton(tr("Drivers"), QMessageBox::YesRole); - - connect(mDiagnosisGui, &DiagnosisGui::fireFinished, this, &StepChooseCardGui::onReaderManagerSignal); - connect(mReaderDriverGui, &ReaderDriverGui::fireFinished, this, &StepChooseCardGui::onReaderManagerSignal); -} - - -StepChooseCardGui::~StepChooseCardGui() -{ -} - - -void StepChooseCardGui::activate() -{ - setCancelButtonState(ButtonState::ENABLED); - - connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); - onReaderManagerSignal(); -} - - -void StepChooseCardGui::deactivate() -{ - disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); -} - - -QString StepChooseCardGui::getCurrentReaderImage(const QVector& pReaderInfos) -{ - QVector knownReaderTypes; - for (const ReaderInfo& readerInfo : pReaderInfos) - { - if (!knownReaderTypes.contains(readerInfo.getReaderType())) - { - knownReaderTypes += readerInfo.getReaderType(); - } - } - - if (knownReaderTypes.size() == 1) - { - return SmartCardUtil::getReaderEmptyIconPath(knownReaderTypes.at(0)); - } - else if (knownReaderTypes.size() > 1) - { - return SmartCardUtil::getMultipleReaderIconPath(); - } - - return SmartCardUtil::getReaderEmptyIconPath(ReaderType::UNKNOWN); -} - - -void StepChooseCardGui::updateErrorMessage(const QString& pTitle, const QString& pMessage, bool closeErrorMessage) -{ - if (closeErrorMessage || mContext->getStatus().isError()) - { - mDiagnosisGui->deactivate(); - mReaderDriverGui->deactivate(); - mInformationMessageBox->done(QMessageBox::InvalidRole); - return; - } - - QString iconPath = getCurrentReaderImage(ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::PCSC)); - if (iconPath.isEmpty() || GuiProfile::getProfile().isSmallScreen()) - { - mInformationMessageBox->setIcon(QMessageBox::Information); - } - else - { - mInformationMessageBox->setIconPixmap(QPixmap(iconPath).scaledToWidth(200, Qt::SmoothTransformation)); - } - mInformationMessageBox->setText(QStringLiteral("%1").arg(pTitle)); - mInformationMessageBox->setInformativeText(pMessage); - - if (mInformationMessageBox->isVisible()) - { - // we just updated the values, no need to call exec. - return; - } - - if (mInformationMessageBox->exec() != QMessageBox::InvalidRole) - { - if (mInformationMessageBox->clickedButton() == mCancelButton) - { - Q_EMIT fireCancelled(); - } - else if (mInformationMessageBox->clickedButton() == mDiagnosisButton) - { - mDiagnosisGui->activate(); - } - // else if (mInformationMessageBox->clickedButton() == mReaderDriverButton) - // { - // mReaderDriverGui->activate(); - // } - } - // else: dialog was closed by an onErrorMessage(..., true) call (i.e. card found) -} - - -void StepChooseCardGui::onReaderManagerSignal() -{ - const auto readers = ReaderManager::getInstance().getReaderInfos(ReaderManagerPlugInType::PCSC); - QVector readersWithNpa; - for (const auto& readerInfo : readers) - { - if (readerInfo.getCardType() == CardType::EID_CARD) - { - readersWithNpa << readerInfo; - } - } - - if (readers.size() == 0) - { - updateErrorMessage(tr("No card reader detected. Please make sure that a card reader is connected."), - tr("If you need help or have problems with your card reader click on the" - " \"Diagnosis\" button for further information."), - false); - return; - } - - if (readersWithNpa.size() == 0) - { - updateErrorMessage(tr("Please place an ID card on the card reader."), - tr("If you have already placed an ID card on your card reader, click on \"Diagnosis\"" - " for further information."), - false); - } - else if (readersWithNpa.size() > 1) - { - updateErrorMessage(tr("Please place only one ID card on the card reader."), - tr("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."), - false); - } - else - { - 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 deleted file mode 100644 index a3d0bb8..0000000 --- a/src/gui/step/StepChooseCardGui.h +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * \brief GUI to select reader/card. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "DiagnosisGui.h" -#include "ReaderDriverGui.h" -#include "ReaderManager.h" -#include "StepGui.h" - -#include - -class QLabel; - -namespace governikus -{ - -class AuthenticateStepsWidget; - -class StepChooseCardGui - : public StepGui -{ - Q_OBJECT - - private: - QPointer mInformationMessageBox; - QPointer mDiagnosisGui; - QPointer mReaderDriverGui; - QPushButton* mCancelButton, * mReaderDriverButton, * mDiagnosisButton; - - QSharedPointer mContext; - - QString getCurrentReaderImage(const QVector& pReaderInfos); - void updateErrorMessage(const QString& pTitle, const QString& pMessage, bool closeErrorMessage = false); - - public Q_SLOTS: - void onReaderManagerSignal(); - - public: - StepChooseCardGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget); - virtual ~StepChooseCardGui(); - - virtual void activate() override; - virtual void deactivate() override; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepErrorGui.cpp b/src/gui/step/StepErrorGui.cpp deleted file mode 100644 index d39730f..0000000 --- a/src/gui/step/StepErrorGui.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepErrorGui.h" - -#include "AppQtMainWidget.h" -#include "generic/GuiUtils.h" - -#include -#include -#include -#include - - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(gui) - - -StepErrorGui::StepErrorGui(QSharedPointer pContext, AppQtMainWidget* const pMainWidget) - : StepGui(pContext) - , mContext(pContext) - , mMainWidget(pMainWidget) -{ -} - - -StepErrorGui::~StepErrorGui() -{ -} - - -void StepErrorGui::reportError() -{ - // Do not close the window automatically in case of errors when the workflow is done. - mMainWidget->setHideWindowAfterWorkflow(false); - - if (mContext->getStatus().is(GlobalStatus::Code::Paos_Error_SAL_Invalid_Key) && !mContext->getCardConnection()->getReaderInfo().getCardInfo().isPinDeactivated()) - { - if (GuiUtils::showWrongPinBlockedDialog(mMainWidget)) - { - mMainWidget->switchToPinSettingsAfterWorkflow(); - Q_EMIT switchedToPinSettings(); - } - else - { - Q_EMIT fireUiFinished(); - } - return; - } - - QString message = mContext->getStatus().toErrorDescription(true); - if (message.isEmpty()) - { - 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(); -} - - -void StepErrorGui::forwardStep() -{ - Q_EMIT fireUiFinished(); -} diff --git a/src/gui/step/StepErrorGui.h b/src/gui/step/StepErrorGui.h deleted file mode 100644 index 74c521e..0000000 --- a/src/gui/step/StepErrorGui.h +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * \brief GUI for step "Error". - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/WorkflowContext.h" -#include "StepGui.h" - -namespace governikus -{ - -class AppQtMainWidget; - -class StepErrorGui - : public StepGui -{ - Q_OBJECT - - public: - StepErrorGui(QSharedPointer pContext, AppQtMainWidget* const pMainWidget); - ~StepErrorGui(); - - virtual void reportError(); - - public Q_SLOTS: - virtual void forwardStep() override; - - private: - QSharedPointer mContext; - AppQtMainWidget* const mMainWidget; - - Q_SIGNALS: - void switchedToPinSettings(); -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepGui.cpp b/src/gui/step/StepGui.cpp deleted file mode 100644 index 9514120..0000000 --- a/src/gui/step/StepGui.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * StepGui.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepGui.h" - -using namespace governikus; - -StepGuiDelegate::StepGuiDelegate() - : QObject() -{ -} - - -StepGui::StepGui(const QSharedPointer& pContext) - : mDelegate(new StepGuiDelegate) -{ - connect(this, &StepGui::fireCancelled, pContext.data(), &WorkflowContext::fireCancelWorkflow); -} - - -StepGui::~StepGui() -{ -} - - -void StepGui::forwardStep() -{ - // can be implemented by subclasses -} diff --git a/src/gui/step/StepGui.h b/src/gui/step/StepGui.h deleted file mode 100644 index 109816f..0000000 --- a/src/gui/step/StepGui.h +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/WorkflowContext.h" -#include "generic/ButtonState.h" - -#include -#include -#include - -namespace governikus -{ - -struct StepDidAuthenticateEac1Ui -{ - enum class State - { - INITIAL, - EDIT_CHAT, - ENTER_PIN, - AUTHENTICATING_ESERVICE, - AUTHENTICATING_CARD, - READING_CARD_DATA, - REDIRECTING_BROWSER, - FINISHED, - }; -}; - -class Page; - -class StepGuiDelegate - : public QObject -{ - Q_OBJECT - - public: - StepGuiDelegate(); - - Q_SIGNALS: - void setForwardButtonState(ButtonState pState, const QString& pText); - void setCancelButtonState(ButtonState pState); -}; - - -class StepGui - : public QObject -{ - Q_OBJECT - - public: - StepGui(const QSharedPointer& pContext); - virtual ~StepGui(); - - StepGuiDelegate* getStepGuiDelegate() const - { - return mDelegate.data(); - } - - - virtual void activate() - { - } - - - virtual void deactivate() - { - } - - - virtual void forwardStep(); - - protected: - void setForwardButtonState(ButtonState pState, const QString& pText = QString()) - { - Q_EMIT mDelegate->setForwardButtonState(pState, pText); - } - - - void setCancelButtonState(ButtonState pState) - { - Q_EMIT mDelegate->setCancelButtonState(pState); - } - - - protected: - QScopedPointer mDelegate; - - Q_SIGNALS: - //void fireErrorMessage(QString pTitle, QString pMessage, QVector pReaderInfos, bool closeErrorMessage = false); - void fireUiFinished(); - void fireCancelled(); - -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepProcessingGui.cpp b/src/gui/step/StepProcessingGui.cpp deleted file mode 100644 index fa26124..0000000 --- a/src/gui/step/StepProcessingGui.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "generic/BusyOverlayContainer.h" -#include "step/AuthenticateStepsWidget.h" -#include "StepProcessingGui.h" - -using namespace governikus; - -StepProcessingGui::StepProcessingGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget) - : StepGui(pContext) - , mStepsWidget(pStepsWidget) -{ -} - - -StepProcessingGui::~StepProcessingGui() -{ -} - - -void StepProcessingGui::activate() -{ - setCancelButtonState(ButtonState::ENABLED); - setForwardButtonState(ButtonState::HIDDEN); - - mStepsWidget->setCurrentWidget(mStepsWidget->getProcessingPage()); - mStepsWidget->getProcessingPage()->startAnimation(); -} - - -void StepProcessingGui::deactivate() -{ - mStepsWidget->getProcessingPage()->stopAnimation(); -} diff --git a/src/gui/step/StepProcessingGui.h b/src/gui/step/StepProcessingGui.h deleted file mode 100644 index a001e8c..0000000 --- a/src/gui/step/StepProcessingGui.h +++ /dev/null @@ -1,31 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "StepGui.h" - - -namespace governikus -{ - -class AuthenticateStepsWidget; - -class StepProcessingGui - : public StepGui -{ - Q_OBJECT - - public: - StepProcessingGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget); - virtual ~StepProcessingGui(); - - virtual void activate() override; - virtual void deactivate() override; - - private: - AuthenticateStepsWidget* mStepsWidget; -}; - -} /* namespace governikus */ diff --git a/src/gui/step/StepShowSelfAuthenticationDataGui.cpp b/src/gui/step/StepShowSelfAuthenticationDataGui.cpp deleted file mode 100644 index b833b5a..0000000 --- a/src/gui/step/StepShowSelfAuthenticationDataGui.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "StepShowSelfAuthenticationDataGui.h" - -#include "step/AuthenticateStepsWidget.h" -#include "step/SelfInfoWidget.h" - -using namespace governikus; - -StepShowSelfAuthenticationDataGui::StepShowSelfAuthenticationDataGui(QSharedPointer pContext, - AuthenticateStepsWidget* pStepsWidget) - : StepGui(pContext) - , mContext(pContext) - , mStepsWidget(pStepsWidget) -{ -} - - -StepShowSelfAuthenticationDataGui::~StepShowSelfAuthenticationDataGui() -{ -} - - -void StepShowSelfAuthenticationDataGui::activate() -{ - SelfInfoWidget* selfInfoWidget = mStepsWidget->getSelfInfoPage(); - selfInfoWidget->setInfo(mContext->getSelfAuthenticationData().data()); - mStepsWidget->setCurrentWidget(selfInfoWidget); - - setForwardButtonState(ButtonState::FOCUSSED, tr("Close")); - setCancelButtonState(ButtonState::HIDDEN); -} - - -void StepShowSelfAuthenticationDataGui::deactivate() -{ -} - - -void StepShowSelfAuthenticationDataGui::forwardStep() -{ - mContext->setStateApproved(); -} diff --git a/src/gui/step/StepShowSelfAuthenticationDataGui.h b/src/gui/step/StepShowSelfAuthenticationDataGui.h deleted file mode 100644 index 9961e08..0000000 --- a/src/gui/step/StepShowSelfAuthenticationDataGui.h +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/SelfAuthenticationContext.h" -#include "StepGui.h" - -#include - -namespace governikus -{ - -class AuthenticateStepsWidget; - -class StepShowSelfAuthenticationDataGui - : public StepGui -{ - Q_OBJECT - - public: - StepShowSelfAuthenticationDataGui(QSharedPointer pContext, AuthenticateStepsWidget* pStepsWidget); - virtual ~StepShowSelfAuthenticationDataGui(); - - virtual void activate() override; - virtual void deactivate() override; - - private Q_SLOTS: - virtual void forwardStep() override; - - private: - QSharedPointer mContext; - AuthenticateStepsWidget* mStepsWidget; -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/GenericWorkflowGui.h b/src/gui/workflow/GenericWorkflowGui.h deleted file mode 100644 index 8f79993..0000000 --- a/src/gui/workflow/GenericWorkflowGui.h +++ /dev/null @@ -1,99 +0,0 @@ -/*! - * Generic WorkflowQtGui.h - * - * \brief Generic base class for Qt based WorkflowUi implementations. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppQtMainWidget.h" -#include "context/WorkflowContext.h" -#include "step/StepGui.h" -#include "WorkflowGui.h" -#include "WorkflowQtWidget.h" - -#include -#include - - -namespace governikus -{ - -template -class GenericWorkflowGui - : public WorkflowGui -{ - protected: - AppQtMainWidget* mParentWidget; - WorkflowQtWidget* mWidget; - QSharedPointer mStepGui; - QSharedPointer mContext; - - bool isActive(const QSharedPointer& pStepGui) - { - return mStepGui == pStepGui; - } - - - public: - GenericWorkflowGui(const QSharedPointer& pContext, AppQtMainWidget* pParentWidget, WorkflowQtWidget* pWidget) - : WorkflowGui() - , mParentWidget(pParentWidget) - , mWidget(pWidget) - , mStepGui(nullptr) - , mContext(pContext.objectCast()) - { - Q_ASSERT(mContext != nullptr); - connect(this, &WorkflowGui::fireUserCancelled, mContext.data(), &WorkflowContext::fireCancelWorkflow); - } - - - virtual void deactivate() - { - deactivateCurrentStepUi(); - } - - - virtual void activateStepUi(const QSharedPointer& pStepUi) - { - Q_ASSERT(pStepUi); - if (mStepGui == pStepUi) - { - return; - } - - deactivateCurrentStepUi(); - - mStepGui = pStepUi; - if (mWidget != nullptr) - { - QObject::connect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState, mWidget, &WorkflowQtWidget::setForwardButtonState); - QObject::connect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState, mWidget, &WorkflowQtWidget::setCancelButtonState); - } - pStepUi->activate(); - } - - - private: - void deactivateCurrentStepUi() - { - if (mStepGui == nullptr) - { - return; - } - - mStepGui->deactivate(); - if (mWidget != nullptr) - { - QObject::disconnect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState, mWidget, &WorkflowQtWidget::setForwardButtonState); - QObject::disconnect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState, mWidget, &WorkflowQtWidget::setCancelButtonState); - } - mStepGui.clear(); - } - - -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowAuthenticateQtGui.cpp b/src/gui/workflow/WorkflowAuthenticateQtGui.cpp deleted file mode 100644 index 4f56131..0000000 --- a/src/gui/workflow/WorkflowAuthenticateQtGui.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/*! - * WorkflowAuthenticateQtGui.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "WorkflowAuthenticateQtGui.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/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" -#include "step/StepAuthenticationEac1Gui.h" -#include "step/StepChooseCardGui.h" -#include "step/StepErrorGui.h" -#include "step/StepProcessingGui.h" -#include "workflow/WorkflowQtWidget.h" - - -using namespace governikus; - - -WorkflowAuthenticateQtGui::WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) - : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) - , mCanEntered(false) - , mAuthenticateStepsWidget(mParentWidget->findChild()) - , 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)) - , mAuthenticationDoneGui(new StepAuthenticationDoneGui(mContext)) -{ - Q_ASSERT(mAuthenticateStepsWidget != nullptr); - connect(mWidget, &WorkflowQtWidget::fireUserCancelled, this, &WorkflowGui::fireUserCancelled); - connect(mWidget, &WorkflowQtWidget::forwardStep, this, &WorkflowAuthenticateQtGui::onForwardStep); -} - - -WorkflowAuthenticateQtGui::~WorkflowAuthenticateQtGui() -{ -} - - -void WorkflowAuthenticateQtGui::activate() -{ - activateStepUi(mProcessingGui); - mParentWidget->workflowActivated(WorkflowWidgetParent::Authentication, tr("Identify")); - connect(mContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &WorkflowAuthenticateQtGui::onCurrentStateChanged); -} - - -void WorkflowAuthenticateQtGui::deactivate() -{ - mParentWidget->workflowDeactivated(); -} - - -bool WorkflowAuthenticateQtGui::verifyAbortWorkflow() -{ - QMessageBox msgBox(mParentWidget); - msgBox.setWindowTitle(QCoreApplication::applicationName() + " - " + tr("Cancel")); - msgBox.setWindowModality(Qt::WindowModal); - 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.")); - 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::onForwardStep() -{ - if (mStepGui != nullptr) - { - mStepGui->forwardStep(); - } -} - - -void WorkflowAuthenticateQtGui::onCurrentStateChanged(const QString& pNewState) -{ - if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) - { - if (!mContext->getStatus().isCancellationByUser()) - { - activateStepUi(mErrorGui); - mErrorGui->reportError(); - } - mContext->setErrorReportedToUser(); - } - - - bool approveNewState = true; - if (AbstractState::isState(pNewState)) - { - activateStepUi(mProcessingGui); - - 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(); - } - } - 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); - activateStepUi(mAuthenticationDoneGui); - } - mContext->setStateApproved(approveNewState); -} diff --git a/src/gui/workflow/WorkflowAuthenticateQtGui.h b/src/gui/workflow/WorkflowAuthenticateQtGui.h deleted file mode 100644 index 664dc03..0000000 --- a/src/gui/workflow/WorkflowAuthenticateQtGui.h +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * WorkflowAuthenticateQtGui.h - * - * \brief Qt widget based WorkflowAuthenticateUi implementation. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/AuthContext.h" -#include "GenericWorkflowGui.h" - - -namespace governikus -{ - -class AuthenticateStepsWidget; -class StepAdviseUserToRemoveCardGui; -class StepAuthenticationDoneGui; -class StepAuthenticationEac1Gui; -class StepChooseCardGui; -class StepErrorGui; -class StepProcessingGui; - - -class WorkflowAuthenticateQtGui - : public GenericWorkflowGui -{ - Q_OBJECT - - private: - bool mCanEntered; - AuthenticateStepsWidget* mAuthenticateStepsWidget; - QSharedPointer mAdviseUserToRemoveCardGui; - QSharedPointer mDidAuthenticateGui; - QSharedPointer mChooseCardGui; - QSharedPointer mErrorGui; - QSharedPointer mProcessingGui; - QSharedPointer mAuthenticationDoneGui; - - private Q_SLOTS: - void onForwardStep(); - void onCurrentStateChanged(const QString& pNewState); - - public: - WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget); - virtual ~WorkflowAuthenticateQtGui(); - - virtual void activate() override; - virtual void deactivate() override; - virtual bool verifyAbortWorkflow() override; -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowChangePinQtGui.cpp b/src/gui/workflow/WorkflowChangePinQtGui.cpp deleted file mode 100644 index 0a07592..0000000 --- a/src/gui/workflow/WorkflowChangePinQtGui.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/*! - * WorkflowChangePinQtGui.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "WorkflowChangePinQtGui.h" - -#include "AppQtMainWidget.h" -#include "generic/GuiUtils.h" -#include "PinSettingsWidget.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" - -using namespace governikus; - -WorkflowChangePinQtGui::WorkflowChangePinQtGui(QSharedPointer pContext, AppQtMainWidget* const pParentWidget) - : GenericWorkflowGui(pContext, pParentWidget, nullptr) - , mRetryCounterUpdated(false) - , mPinSettingsWidget(mParentWidget->findChild()) - , mErrorGui(new StepErrorGui(mContext, mParentWidget)) -{ - Q_ASSERT(mPinSettingsWidget); - connect(mContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &WorkflowChangePinQtGui::onStateChanged); -} - - -WorkflowChangePinQtGui::~WorkflowChangePinQtGui() -{ -} - - -void WorkflowChangePinQtGui::activate() -{ - mParentWidget->workflowActivated(WorkflowWidgetParent::SettingsChangePin, QString()); - mPinSettingsWidget->setInProgress(true); -} - - -void WorkflowChangePinQtGui::deactivate() -{ - mPinSettingsWidget->setInProgress(false); - mParentWidget->workflowDeactivated(); -} - - -bool WorkflowChangePinQtGui::verifyAbortWorkflow() -{ - // not really necessary to notify the user - return true; -} - - -void WorkflowChangePinQtGui::onStateChanged(const QString& pNextState) -{ - if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) - { - if (!mContext->getStatus().isCancellationByUser()) - { - activateStepUi(mErrorGui); - mErrorGui->reportError(); - } - mContext->setErrorReportedToUser(); - } - - if (mRetryCounterUpdated) - { - mRetryCounterUpdated = false; - if (mContext->getLastPaceResult() != CardReturnCode::OK) - { - auto newRetryCounter = mContext->getCardConnection()->getReaderInfo().getRetryCounter(); - GuiUtils::showPinCanPukErrorDialog(mContext->getLastPaceResult(), newRetryCounter, mPinSettingsWidget); - - /* - * In the desktop version we cancel the workflow after a wrong user input. - * If the user want's to try again, the workflow must be started again. - */ - Q_EMIT mContext->fireCancelWorkflow(); - return; - } - } - - if (AbstractState::isState(pNextState)) - { - mContext->setReaderType(ReaderManagerPlugInType::PCSC); - } - else if (AbstractState::isState(pNextState)) - { - mRetryCounterUpdated = true; - } - else if (AbstractState::isState(pNextState)) - { - mContext->setPin(mPinSettingsWidget->getPin()); - } - else if (AbstractState::isState(pNextState)) - { - mContext->setCan(mPinSettingsWidget->getCan()); - } - else if (AbstractState::isState(pNextState)) - { - mContext->setPuk(mPinSettingsWidget->getPuk()); - } - else if (AbstractState::isState(pNextState)) - { - mContext->setNewPin(mPinSettingsWidget->getNewPin()); - } - else if (AbstractState::isState(pNextState) && mContext->getStatus().isNoError()) - { - bool pinBlocked = (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 0); - mPinSettingsWidget->setMode(pinBlocked ? PinSettingsWidget::Mode::AfterPinUnblock : PinSettingsWidget::Mode::AfterPinChange); - } - - mContext->setStateApproved(); -} diff --git a/src/gui/workflow/WorkflowChangePinQtGui.h b/src/gui/workflow/WorkflowChangePinQtGui.h deleted file mode 100644 index 977cdb0..0000000 --- a/src/gui/workflow/WorkflowChangePinQtGui.h +++ /dev/null @@ -1,44 +0,0 @@ -/*! - * WorkflowChangePinQtGui.h - * - * \brief Qt widget based WorkflowChangePinUi implementation. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/ChangePinContext.h" -#include "GenericWorkflowGui.h" - -namespace governikus -{ - -class AppQtMainWidget; -class PinSettingsWidget; -class StepErrorGui; - - -class WorkflowChangePinQtGui - : public GenericWorkflowGui -{ - Q_OBJECT - - public: - WorkflowChangePinQtGui(QSharedPointer pContext, AppQtMainWidget* const pParentWidget); - virtual ~WorkflowChangePinQtGui(); - - virtual void activate() override; - virtual void deactivate() override; - virtual bool verifyAbortWorkflow() override; - - private Q_SLOTS: - void onStateChanged(const QString& pNextState); - - private: - bool mRetryCounterUpdated; - PinSettingsWidget* mPinSettingsWidget; - QSharedPointer mErrorGui; -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowGui.cpp b/src/gui/workflow/WorkflowGui.cpp deleted file mode 100644 index c4af89e..0000000 --- a/src/gui/workflow/WorkflowGui.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "WorkflowGui.h" - -#include "generic/Page.h" -#include "step/StepGui.h" - -using namespace governikus; - -WorkflowGuiDelegate::WorkflowGuiDelegate() -{ -} - - -WorkflowGui::WorkflowGui() - : mDelegate(new WorkflowGuiDelegate) -{ -} - - -WorkflowGui::~WorkflowGui() -{ -} diff --git a/src/gui/workflow/WorkflowGui.h b/src/gui/workflow/WorkflowGui.h deleted file mode 100644 index c8755ca..0000000 --- a/src/gui/workflow/WorkflowGui.h +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * WorkflowQtGui.h - * - * \brief Base class for Qt based WorkflowUi implementations. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include - -#include "AppQtMainWidget.h" -#include "context/WorkflowContext.h" -#include "step/StepGui.h" -#include "WorkflowQtWidget.h" -#include "WorkflowWidgetParent.h" - -namespace governikus -{ - -class WorkflowQtWidget; - -class WorkflowGuiDelegate - : public QObject -{ - Q_OBJECT - - public: - WorkflowGuiDelegate(); -}; - - -class WorkflowGui - : public QObject -{ - Q_OBJECT - - protected: - QScopedPointer mDelegate; - - public: - WorkflowGui(); - virtual ~WorkflowGui(); - - WorkflowGuiDelegate* getWorkflowGuiDelegate() const - { - return mDelegate.data(); - } - - - virtual bool verifyAbortWorkflow() = 0; - - virtual void activate() - { - } - - - virtual void deactivate() - { - } - - - Q_SIGNALS: - void fireUserCancelled(); - void fireChangePinRequest(); -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowQtWidget.cpp b/src/gui/workflow/WorkflowQtWidget.cpp deleted file mode 100644 index 7914dad..0000000 --- a/src/gui/workflow/WorkflowQtWidget.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*! - * WorkflowQtWidget_desktop.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "WorkflowQtWidget.h" - -#include -#include -#include - -using namespace governikus; - -WorkflowQtWidget::WorkflowQtWidget(QWidget* pParent) - : QWidget(pParent) - , mMainLayout(new QVBoxLayout(this)) - , mStepWidgetArea(new QWidget(this)) - , mCancelButton(nullptr) - , mForwardButton(nullptr) -{ - (new QVBoxLayout(mStepWidgetArea))->setMargin(0); - mMainLayout->addWidget(mStepWidgetArea); - mMainLayout->setMargin(0); - - QHBoxLayout* buttonLayout = new QHBoxLayout(); - buttonLayout->setMargin(0); - mMainLayout->addLayout(buttonLayout); - - QSpacerItem* horizontalSpacer = new QSpacerItem(40, 1, QSizePolicy::Expanding, QSizePolicy::Ignored); - - buttonLayout->addItem(horizontalSpacer); - - mCancelButton = new QPushButton(this); - connect(mCancelButton, &QPushButton::clicked, this, &WorkflowQtWidget::onCancelButtonClicked); - mCancelButton->setVisible(false); - buttonLayout->addWidget(mCancelButton); - setCancelButtonState(ButtonState::HIDDEN); - - mForwardButton = new QPushButton(this); - connect(mForwardButton, &QPushButton::clicked, this, &WorkflowQtWidget::forwardStep); - mForwardButton->setVisible(false); - buttonLayout->addWidget(mForwardButton); - setForwardButtonState(ButtonState::HIDDEN); -} - - -WorkflowQtWidget::~WorkflowQtWidget() -{ -} - - -void WorkflowQtWidget::addStepWidget(QWidget* pStepWidget) -{ - mStepWidgetArea->layout()->addWidget(pStepWidget); -} - - -void WorkflowQtWidget::removeStepWidget(QWidget* pStepWidget) -{ - mStepWidgetArea->layout()->removeWidget(pStepWidget); - pStepWidget->setParent(nullptr); // Remove widget from display - // Note: The Step* widgets are deleted in the Step* dtors. -} - - -void WorkflowQtWidget::setForwardButtonState(ButtonState pState, const QString& pText) -{ - setButtonState(mForwardButton, pState, pText.isEmpty() ? tr("Next") : pText); -} - - -void WorkflowQtWidget::setCancelButtonState(ButtonState pState) -{ - setButtonState(mCancelButton, pState, tr("Cancel")); -} - - -void WorkflowQtWidget::onCancelButtonClicked() -{ - setCancelButtonState(ButtonState::DISABLED); - Q_EMIT fireUserCancelled(); -} - - -void WorkflowQtWidget::setButtonState(QAbstractButton* pButton, ButtonState pState, const QString& pText) -{ - pButton->setText(pText); - - switch (pState) - { - case ButtonState::ENABLED: - pButton->setVisible(true); - pButton->setEnabled(true); - break; - - case ButtonState::DISABLED: - pButton->setVisible(true); - pButton->setEnabled(false); - break; - - case ButtonState::HIDDEN: - pButton->setVisible(false); - break; - - case ButtonState::FOCUSSED: - pButton->setVisible(true); - pButton->setEnabled(true); - focusForwardButton(); - break; - } -} - - -void WorkflowQtWidget::focusForwardButton() -{ - mForwardButton->setAutoDefault(true); - mForwardButton->setDefault(true); - mForwardButton->setFocus(); -} diff --git a/src/gui/workflow/WorkflowQtWidget.h b/src/gui/workflow/WorkflowQtWidget.h deleted file mode 100644 index 73d230d..0000000 --- a/src/gui/workflow/WorkflowQtWidget.h +++ /dev/null @@ -1,65 +0,0 @@ -/*! - * \brief Base class for workflow Qt GUI widgets. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include -#include -#include - -#include "step/StepGui.h" - -class QVBoxLayout; - -namespace governikus -{ - -class WorkflowQtWidget - : public QWidget -{ - Q_OBJECT - - public: - WorkflowQtWidget(QWidget* pParent = nullptr); - virtual ~WorkflowQtWidget(); - - QWidget* getStepWidgetArea() const - { - return mStepWidgetArea; - } - - - void addStepWidget(QWidget* widget); - void removeStepWidget(QWidget* widget); - - Q_SIGNALS: - /*! - * This signal is sent when the user presses the "Cancel" button. - */ - void fireUserCancelled(); - - /*! - * This signal is sent when the user presses the "Continue" button. - */ - void forwardStep(); - - public Q_SLOTS: - void onCancelButtonClicked(); - void setForwardButtonState(ButtonState pState, const QString& pText = QString()); - void setCancelButtonState(ButtonState pState); - - private: - void setButtonState(QAbstractButton* pButton, ButtonState pState, const QString& pText); - void focusForwardButton(); - - private: - QVBoxLayout* mMainLayout; - QWidget* mStepWidgetArea; - QPushButton* mCancelButton; - QPushButton* mForwardButton; -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowSelfInfoQtGui.cpp b/src/gui/workflow/WorkflowSelfInfoQtGui.cpp deleted file mode 100644 index 11156c8..0000000 --- a/src/gui/workflow/WorkflowSelfInfoQtGui.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/*! - * WorkflowSelfInfoQtGui.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "WorkflowSelfInfoQtGui.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" -#include "step/StepChooseCardGui.h" -#include "step/StepErrorGui.h" -#include "step/StepProcessingGui.h" -#include "step/StepShowSelfAuthenticationDataGui.h" -#include "workflow/WorkflowQtWidget.h" - - -using namespace governikus; - - -WorkflowSelfInfoQtGui::WorkflowSelfInfoQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) - : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) - , mCanEntered(false) - , mAuthenticateStepsWidget(pParentWidget->findChild()) - , 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); -} - - -WorkflowSelfInfoQtGui::~WorkflowSelfInfoQtGui() -{ -} - - -void WorkflowSelfInfoQtGui::activate() -{ - activateStepUi(mProcessingGui); - mParentWidget->workflowActivated(WorkflowWidgetParent::SelfAuthentication, tr("Identify")); - connect(mContext.data(), &SelfAuthenticationContext::fireCurrentStateChanged, this, &WorkflowSelfInfoQtGui::onCurrentStateChanged); -} - - -void WorkflowSelfInfoQtGui::deactivate() -{ - mParentWidget->workflowDeactivated(); -} - - -bool WorkflowSelfInfoQtGui::verifyAbortWorkflow() -{ - // not really necessary to notify the user - return true; -} - - -void WorkflowSelfInfoQtGui::onForwardStep() -{ - if (mStepGui) - { - mStepGui->forwardStep(); - } -} - - -void WorkflowSelfInfoQtGui::onCurrentStateChanged(const QString& pNewState) -{ - if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) - { - 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(); - } - } - 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 deleted file mode 100644 index c8637af..0000000 --- a/src/gui/workflow/WorkflowSelfInfoQtGui.h +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * WorkflowSelfInfoQtGui.h - * - * \brief Qt widget based WorkflowSelfInfoUi implementation. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "context/SelfAuthenticationContext.h" -#include "GenericWorkflowGui.h" - -namespace governikus -{ - -class AuthenticateStepsWidget; -class StepAdviseUserToRemoveCardGui; -class StepShowSelfAuthenticationDataGui; -class StepAuthenticationEac1Gui; -class StepChooseCardGui; -class StepErrorGui; -class StepProcessingGui; - -class WorkflowSelfInfoQtGui - : public GenericWorkflowGui -{ - Q_OBJECT - - private: - bool mCanEntered; - AuthenticateStepsWidget* mAuthenticateStepsWidget; - 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); - virtual ~WorkflowSelfInfoQtGui(); - - virtual void activate() override; - virtual void deactivate() override; - virtual bool verifyAbortWorkflow() override; -}; - -} /* namespace governikus */ diff --git a/src/gui/workflow/WorkflowWidgetParent.h b/src/gui/workflow/WorkflowWidgetParent.h deleted file mode 100644 index 4c84ada..0000000 --- a/src/gui/workflow/WorkflowWidgetParent.h +++ /dev/null @@ -1,23 +0,0 @@ -/*! - * WorkflowWidgetParent.h - * - * \brief Enum identifying the containers in the application GUI which can be - * parent to a workflow widget. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -namespace governikus -{ - -enum class WorkflowWidgetParent -{ - Authentication, - SettingsChangePin, - SelfAuthentication -}; - - -} /* namespace governikus */ diff --git a/src/jsonapi/MessageDispatcher.cpp b/src/jsonapi/MessageDispatcher.cpp index c94fb3b..20e22f9 100644 --- a/src/jsonapi/MessageDispatcher.cpp +++ b/src/jsonapi/MessageDispatcher.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MessageDispatcher.h" diff --git a/src/jsonapi/MessageDispatcher.h b/src/jsonapi/MessageDispatcher.h index a2e8baf..ace289f 100644 --- a/src/jsonapi/MessageDispatcher.h +++ b/src/jsonapi/MessageDispatcher.h @@ -1,7 +1,7 @@ /*! * \brief Dispatch Messages of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/jsonapi/UIPlugInJsonApi.cpp b/src/jsonapi/UIPlugInJsonApi.cpp index 627c8bf..16f6516 100644 --- a/src/jsonapi/UIPlugInJsonApi.cpp +++ b/src/jsonapi/UIPlugInJsonApi.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInJsonApi.h" @@ -29,7 +29,7 @@ UIPlugInJsonApi::~UIPlugInJsonApi() } -void UIPlugInJsonApi::callFireMessage(const QByteArray& pMsg) const +void UIPlugInJsonApi::callFireMessage(const QByteArray& pMsg) { if (!pMsg.isEmpty()) { @@ -44,12 +44,12 @@ void UIPlugInJsonApi::onWorkflowStarted(QSharedPointer pContext if (pContext.objectCast()) { #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - pContext->setReaderType(ReaderManagerPlugInType::NFC); + pContext->setReaderPlugInTypes({ReaderManagerPlugInType::NFC}); #else - pContext->setReaderType(ReaderManagerPlugInType::PCSC); + pContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC}); #endif - connect(pContext.data(), &WorkflowContext::fireCurrentStateChanged, this, &UIPlugInJsonApi::onCurrentStateChanged); + connect(pContext.data(), &WorkflowContext::fireStateChanged, this, &UIPlugInJsonApi::onStateChanged); } callFireMessage(mMessageDispatcher.init(pContext)); @@ -68,7 +68,7 @@ void UIPlugInJsonApi::onReaderEvent(const QString& pName) } -void UIPlugInJsonApi::onCurrentStateChanged(const QString& pNewState) +void UIPlugInJsonApi::onStateChanged(const QString& pNewState) { callFireMessage(mMessageDispatcher.processStateChange(pNewState)); } diff --git a/src/jsonapi/UIPlugInJsonApi.h b/src/jsonapi/UIPlugInJsonApi.h index 83df47a..c0d986c 100644 --- a/src/jsonapi/UIPlugInJsonApi.h +++ b/src/jsonapi/UIPlugInJsonApi.h @@ -1,7 +1,7 @@ /*! * \brief UIPlugIn implementation of the Json API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,24 +23,24 @@ class UIPlugInJsonApi private: MessageDispatcher mMessageDispatcher; - inline void callFireMessage(const QByteArray& pMsg) const; + inline void callFireMessage(const QByteArray& pMsg); public: UIPlugInJsonApi(); - virtual ~UIPlugInJsonApi(); + virtual ~UIPlugInJsonApi() override; private Q_SLOTS: virtual void doShutdown() override; virtual void onWorkflowStarted(QSharedPointer pContext) override; virtual void onWorkflowFinished(QSharedPointer pContext) override; void onReaderEvent(const QString& pName); - void onCurrentStateChanged(const QString& pNewState); + void onStateChanged(const QString& pNewState); public Q_SLOTS: void doMessageProcessing(const QByteArray& pMsg); Q_SIGNALS: - void fireMessage(const QByteArray& pMsg) const; + void fireMessage(const QByteArray& pMsg); }; } /* namespace governikus */ diff --git a/src/jsonapi/messages/MsgContext.cpp b/src/jsonapi/messages/MsgContext.cpp index b1232f2..b82103e 100644 --- a/src/jsonapi/messages/MsgContext.cpp +++ b/src/jsonapi/messages/MsgContext.cpp @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgContext.h" diff --git a/src/jsonapi/messages/MsgContext.h b/src/jsonapi/messages/MsgContext.h index bfa832b..147608e 100644 --- a/src/jsonapi/messages/MsgContext.h +++ b/src/jsonapi/messages/MsgContext.h @@ -1,7 +1,7 @@ /*! * \brief Context of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/jsonapi/messages/MsgHandler.cpp b/src/jsonapi/messages/MsgHandler.cpp index 9ee42cf..1888a88 100644 --- a/src/jsonapi/messages/MsgHandler.cpp +++ b/src/jsonapi/messages/MsgHandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandler.h" @@ -8,8 +8,7 @@ #include "states/StateEstablishPaceCan.h" #include "states/StateEstablishPacePin.h" #include "states/StateEstablishPacePuk.h" -#include "states/StateSelectNfcReader.h" -#include "states/StateSelectPcscReader.h" +#include "states/StateSelectReader.h" #include @@ -38,8 +37,7 @@ MsgType MsgHandler::getStateMsgType(const QString& pState) { return MsgType::ACCESS_RIGHTS; } - else if (AbstractState::isState(pState) - || AbstractState::isState(pState)) + else if (AbstractState::isState(pState)) { return MsgType::INSERT_CARD; } @@ -61,7 +59,7 @@ MsgHandler::MsgHandler(MsgType pType) , mVoid(false) , mJsonObject() { - mJsonObject["msg"] = getEnumName(mType); + mJsonObject[QLatin1String("msg")] = getEnumName(mType); } @@ -72,7 +70,7 @@ MsgHandler::MsgHandler(MsgType pType, const char* pKey, const QString& pValue) } -MsgHandler::MsgHandler(MsgType pType, const char* pKey, const QLatin1String& pValue) +MsgHandler::MsgHandler(MsgType pType, const char* pKey, const QLatin1String pValue) : MsgHandler(pType) { setValue(pKey, pValue); @@ -81,7 +79,7 @@ MsgHandler::MsgHandler(MsgType pType, const char* pKey, const QLatin1String& pVa QByteArray MsgHandler::toJson() const { - Q_ASSERT(mJsonObject["msg"].isString()); + Q_ASSERT(mJsonObject[QLatin1String("msg")].isString()); return QJsonDocument(mJsonObject).toJson(QJsonDocument::Compact); } @@ -111,7 +109,7 @@ MsgType MsgHandler::getType() const void MsgHandler::setRequest(const QJsonObject& pRequest) { - static const QLatin1String requestName("request"); + const QLatin1String requestName("request"); const auto& requestValue = pRequest[requestName]; if (!requestValue.isUndefined()) @@ -127,7 +125,7 @@ void MsgHandler::setValue(const char* pKey, const QString& pValue) } -void MsgHandler::setValue(const QLatin1String& pKey, const QLatin1String& pValue) +void MsgHandler::setValue(const QLatin1String pKey, const QLatin1String pValue) { if (pValue.size()) { @@ -136,7 +134,7 @@ void MsgHandler::setValue(const QLatin1String& pKey, const QLatin1String& pValue } -void MsgHandler::setValue(const char* pKey, const QLatin1String& pValue) +void MsgHandler::setValue(const char* pKey, const QLatin1String pValue) { setValue(QLatin1String(pKey), pValue); } @@ -148,7 +146,7 @@ void MsgHandler::setVoid(bool pVoid) } -void MsgHandler::setValue(const QLatin1String& pKey, const QString& pValue) +void MsgHandler::setValue(const QLatin1String pKey, const QString& pValue) { if (!pValue.isEmpty()) { diff --git a/src/jsonapi/messages/MsgHandler.h b/src/jsonapi/messages/MsgHandler.h index 7586868..a4449cd 100644 --- a/src/jsonapi/messages/MsgHandler.h +++ b/src/jsonapi/messages/MsgHandler.h @@ -1,7 +1,7 @@ /*! * \brief Base of all messages of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -25,12 +25,12 @@ class MsgHandler MsgHandler(MsgType pType); MsgHandler(MsgType pType, const char* pKey, const QString& pValue); - MsgHandler(MsgType pType, const char* pKey, const QLatin1String& pValue); + MsgHandler(MsgType pType, const char* pKey, const QLatin1String pValue); - void setValue(const QLatin1String& pKey, const QString& pValue); + void setValue(const QLatin1String pKey, const QString& pValue); void setValue(const char* pKey, const QString& pValue); - void setValue(const QLatin1String& pKey, const QLatin1String& pValue); - void setValue(const char* pKey, const QLatin1String& pValue); + void setValue(const QLatin1String pKey, const QLatin1String pValue); + void setValue(const char* pKey, const QLatin1String pValue); void setVoid(bool pVoid = true); diff --git a/src/jsonapi/messages/MsgHandlerAccessRights.cpp b/src/jsonapi/messages/MsgHandlerAccessRights.cpp index 50847f9..6809c6e 100644 --- a/src/jsonapi/messages/MsgHandlerAccessRights.cpp +++ b/src/jsonapi/messages/MsgHandlerAccessRights.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerAccessRights.h" @@ -22,7 +22,7 @@ MsgHandlerAccessRights::MsgHandlerAccessRights(const QJsonObject& pObj, MsgConte auto ctx = pContext.getAuthContext(); Q_ASSERT(ctx); - const auto& jsonRaw = pObj["chat"]; + const auto& jsonRaw = pObj[QLatin1String("chat")]; if (jsonRaw.isUndefined()) { setError(QLatin1String("'chat' cannot be undefined")); @@ -80,7 +80,7 @@ void MsgHandlerAccessRights::handleSetChatData(const QJsonArray& pChat, const QS } - if (!mJsonObject.contains("error")) + if (!mJsonObject.contains(QLatin1String("error"))) { pContext->setEffectiveAccessRights(effectiveChat); } @@ -111,21 +111,21 @@ void MsgHandlerAccessRights::fillAccessRights(const QSharedPointergetRequiredAccessRights()); - chat["optional"] = getAccessRights(pContext->getOptionalAccessRights()); - chat["effective"] = getAccessRights(pContext->getEffectiveAccessRights()); + chat[QLatin1String("required")] = getAccessRights(pContext->getRequiredAccessRights()); + chat[QLatin1String("optional")] = getAccessRights(pContext->getOptionalAccessRights()); + chat[QLatin1String("effective")] = getAccessRights(pContext->getEffectiveAccessRights()); - mJsonObject["chat"] = chat; + mJsonObject[QLatin1String("chat")] = chat; const auto& transactionInfo = pContext->getDidAuthenticateEac1()->getTransactionInfo(); if (!transactionInfo.isEmpty()) { - mJsonObject["transactionInfo"] = transactionInfo; + mJsonObject[QLatin1String("transactionInfo")] = transactionInfo; } const QJsonObject& aux = getAuxiliaryData(pContext); if (!aux.isEmpty()) { - mJsonObject["aux"] = aux; + mJsonObject[QLatin1String("aux")] = aux; } } @@ -142,18 +142,18 @@ QJsonObject MsgHandlerAccessRights::getAuxiliaryData(const QSharedPointerhasAgeVerificationDate()) { - obj["ageVerificationDate"] = aux->getAgeVerificationDate().toString(Qt::ISODate); - obj["requiredAge"] = aux->getRequiredAge(); + obj[QLatin1String("ageVerificationDate")] = aux->getAgeVerificationDate().toString(Qt::ISODate); + obj[QLatin1String("requiredAge")] = aux->getRequiredAge(); } if (aux->hasValidityDate()) { - obj["validityDate"] = aux->getValidityDate().toString(Qt::ISODate); + obj[QLatin1String("validityDate")] = aux->getValidityDate().toString(Qt::ISODate); } if (aux->hasCommunityID()) { - obj["communityId"] = QString::fromUtf8(aux->getCommunityID()); + obj[QLatin1String("communityId")] = QString::fromUtf8(aux->getCommunityID()); } } } @@ -162,7 +162,7 @@ QJsonObject MsgHandlerAccessRights::getAuxiliaryData(const QSharedPointer& pContext); QJsonArray getAccessRights(const QSet& pRights) const; diff --git a/src/jsonapi/messages/MsgHandlerApiLevel.cpp b/src/jsonapi/messages/MsgHandlerApiLevel.cpp index c4f7ec9..edef136 100644 --- a/src/jsonapi/messages/MsgHandlerApiLevel.cpp +++ b/src/jsonapi/messages/MsgHandlerApiLevel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerApiLevel.h" @@ -19,7 +19,7 @@ MsgHandlerApiLevel::MsgHandlerApiLevel(const MsgContext& pContext) MsgHandlerApiLevel::MsgHandlerApiLevel(const QJsonObject& pObj, MsgContext& pContext) : MsgHandler(MsgType::API_LEVEL) { - const auto& jsonLevel = pObj["level"]; + const auto& jsonLevel = pObj[QLatin1String("level")]; if (jsonLevel.isUndefined()) { setError(QLatin1String("Level cannot be undefined")); @@ -45,15 +45,15 @@ MsgHandlerApiLevel::MsgHandlerApiLevel(const QJsonObject& pObj, MsgContext& pCon } -void MsgHandlerApiLevel::setError(const QLatin1String& pError) +void MsgHandlerApiLevel::setError(const QLatin1String pError) { - mJsonObject["error"] = pError; + mJsonObject[QLatin1String("error")] = pError; } void MsgHandlerApiLevel::setCurrentLevel(MsgLevel pLevel) { - mJsonObject["current"] = static_cast(pLevel); + mJsonObject[QLatin1String("current")] = static_cast(pLevel); } @@ -65,5 +65,5 @@ void MsgHandlerApiLevel::setAvailableLevel() { availableApiLevel += static_cast(entry); } - mJsonObject["available"] = availableApiLevel; + mJsonObject[QLatin1String("available")] = availableApiLevel; } diff --git a/src/jsonapi/messages/MsgHandlerApiLevel.h b/src/jsonapi/messages/MsgHandlerApiLevel.h index 931408f..639d9b1 100644 --- a/src/jsonapi/messages/MsgHandlerApiLevel.h +++ b/src/jsonapi/messages/MsgHandlerApiLevel.h @@ -1,7 +1,7 @@ /*! * \brief Message API_LEVEL of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -16,7 +16,7 @@ class MsgHandlerApiLevel : public MsgHandler { private: - void setError(const QLatin1String& pError); + void setError(const QLatin1String pError); void setCurrentLevel(MsgLevel pLevel); void setAvailableLevel(); diff --git a/src/jsonapi/messages/MsgHandlerAuth.cpp b/src/jsonapi/messages/MsgHandlerAuth.cpp index 72e5628..4ab1cd8 100644 --- a/src/jsonapi/messages/MsgHandlerAuth.cpp +++ b/src/jsonapi/messages/MsgHandlerAuth.cpp @@ -1,11 +1,12 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerAuth.h" #include "InternalActivationHandler.h" +#include #include using namespace governikus; @@ -20,7 +21,7 @@ MsgHandlerAuth::MsgHandlerAuth() MsgHandlerAuth::MsgHandlerAuth(const QJsonObject& pObj) : MsgHandlerAuth() { - const auto& jsonTcTokenUrl = pObj["tcTokenURL"]; + const auto& jsonTcTokenUrl = pObj[QLatin1String("tcTokenURL")]; if (jsonTcTokenUrl.isUndefined()) { setError(QLatin1String("tcTokenURL cannot be undefined")); @@ -38,7 +39,7 @@ MsgHandlerAuth::MsgHandlerAuth(const QJsonObject& pObj) setVoid(); return; } - Q_ASSERT(mJsonObject["error"].isString()); + Q_ASSERT(mJsonObject[QLatin1String("error")].isString()); } } @@ -48,7 +49,7 @@ MsgHandlerAuth::MsgHandlerAuth(const QSharedPointer& pContext) { Q_ASSERT(pContext); - mJsonObject["result"] = Result(pContext->getStatus()).toJson(); + mJsonObject[QLatin1String("result")] = Result(pContext->getStatus()).toJson(); QString url; if (pContext->getRefreshUrl().isEmpty()) @@ -91,11 +92,11 @@ void MsgHandlerAuth::initAuth(const QUrl& pTcTokenUrl) { auto handler = ActivationHandler::getInstance(); Q_ASSERT(handler); - handler->runAuthentication(new InternalActivationContext(pTcTokenUrl)); + handler->runAuthentication(QSharedPointer::create(pTcTokenUrl)); } -void MsgHandlerAuth::setError(const QLatin1String& pError) +void MsgHandlerAuth::setError(const QLatin1String pError) { setValue("error", pError); } diff --git a/src/jsonapi/messages/MsgHandlerAuth.h b/src/jsonapi/messages/MsgHandlerAuth.h index 766bfd8..bb2328d 100644 --- a/src/jsonapi/messages/MsgHandlerAuth.h +++ b/src/jsonapi/messages/MsgHandlerAuth.h @@ -1,7 +1,7 @@ /*! * \brief Message Auth of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -19,7 +19,7 @@ class MsgHandlerAuth private: QUrl createUrl(const QString& pUrl); void initAuth(const QUrl& pTcTokenUrl); - void setError(const QLatin1String& pError); + void setError(const QLatin1String pError); public: MsgHandlerAuth(); diff --git a/src/jsonapi/messages/MsgHandlerBadState.cpp b/src/jsonapi/messages/MsgHandlerBadState.cpp index 5e89b77..4a038a1 100644 --- a/src/jsonapi/messages/MsgHandlerBadState.cpp +++ b/src/jsonapi/messages/MsgHandlerBadState.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerBadState.h" @@ -11,6 +11,6 @@ MsgHandlerBadState::MsgHandlerBadState(MsgCmdType pType) { if (pType != MsgCmdType::UNDEFINED) { - mJsonObject["error"] = getEnumName(pType); + mJsonObject[QLatin1String("error")] = getEnumName(pType); } } diff --git a/src/jsonapi/messages/MsgHandlerBadState.h b/src/jsonapi/messages/MsgHandlerBadState.h index 585f0d0..2315327 100644 --- a/src/jsonapi/messages/MsgHandlerBadState.h +++ b/src/jsonapi/messages/MsgHandlerBadState.h @@ -1,7 +1,7 @@ /*! * \brief Message BadState of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/jsonapi/messages/MsgHandlerCertificate.cpp b/src/jsonapi/messages/MsgHandlerCertificate.cpp index e150c4f..895d8f9 100644 --- a/src/jsonapi/messages/MsgHandlerCertificate.cpp +++ b/src/jsonapi/messages/MsgHandlerCertificate.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerCertificate.h" @@ -19,18 +19,18 @@ MsgHandlerCertificate::MsgHandlerCertificate(const MsgContext& pContext) const auto& certificateDescription = eac1->getCertificateDescription(); QJsonObject desc; - desc["subjectName"] = certificateDescription->getSubjectName(); - desc["subjectUrl"] = certificateDescription->getSubjectUrl(); - desc["issuerName"] = certificateDescription->getIssuerName(); - desc["issuerUrl"] = certificateDescription->getIssuerUrl(); - desc["termsOfUsage"] = certificateDescription->getTermsOfUsage(); - desc["purpose"] = certificateDescription->getPurpose(); + desc[QLatin1String("subjectName")] = certificateDescription->getSubjectName(); + desc[QLatin1String("subjectUrl")] = certificateDescription->getSubjectUrl(); + desc[QLatin1String("issuerName")] = certificateDescription->getIssuerName(); + desc[QLatin1String("issuerUrl")] = certificateDescription->getIssuerUrl(); + desc[QLatin1String("termsOfUsage")] = certificateDescription->getTermsOfUsage(); + desc[QLatin1String("purpose")] = certificateDescription->getPurpose(); CVCertificateBody body = eac1->getCvCertificates().at(0)->getBody(); QJsonObject validity; - validity["effectiveDate"] = body.getCertificateEffectiveDate().toString(Qt::ISODate); - validity["expirationDate"] = body.getCertificateExpirationDate().toString(Qt::ISODate); + validity[QLatin1String("effectiveDate")] = body.getCertificateEffectiveDate().toString(Qt::ISODate); + validity[QLatin1String("expirationDate")] = body.getCertificateExpirationDate().toString(Qt::ISODate); - mJsonObject["description"] = desc; - mJsonObject["validity"] = validity; + mJsonObject[QLatin1String("description")] = desc; + mJsonObject[QLatin1String("validity")] = validity; } diff --git a/src/jsonapi/messages/MsgHandlerCertificate.h b/src/jsonapi/messages/MsgHandlerCertificate.h index a294c53..aeacb4a 100644 --- a/src/jsonapi/messages/MsgHandlerCertificate.h +++ b/src/jsonapi/messages/MsgHandlerCertificate.h @@ -1,7 +1,7 @@ /*! * \brief Message handler for GET_CERTIFICATE of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/jsonapi/messages/MsgHandlerEnterCan.cpp b/src/jsonapi/messages/MsgHandlerEnterCan.cpp index b44b0ea..adeb6d9 100644 --- a/src/jsonapi/messages/MsgHandlerEnterCan.cpp +++ b/src/jsonapi/messages/MsgHandlerEnterCan.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerEnterCan.h" diff --git a/src/jsonapi/messages/MsgHandlerEnterCan.h b/src/jsonapi/messages/MsgHandlerEnterCan.h index baee425..bdb83e9 100644 --- a/src/jsonapi/messages/MsgHandlerEnterCan.h +++ b/src/jsonapi/messages/MsgHandlerEnterCan.h @@ -1,7 +1,7 @@ /*! * \brief Message EnterCan of JSON API. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/jsonapi/messages/MsgHandlerEnterNumber.cpp b/src/jsonapi/messages/MsgHandlerEnterNumber.cpp index 4658abb..ee0407e 100644 --- a/src/jsonapi/messages/MsgHandlerEnterNumber.cpp +++ b/src/jsonapi/messages/MsgHandlerEnterNumber.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MsgHandlerEnterNumber.h" @@ -21,7 +21,7 @@ MsgHandlerEnterNumber::MsgHandlerEnterNumber(MsgType pType, const MsgContext& pC void MsgHandlerEnterNumber::setError(const QString& pError) { - mJsonObject["error"] = pError; + mJsonObject[QLatin1String("error")] = pError; } @@ -31,9 +31,9 @@ void MsgHandlerEnterNumber::setReader(const QSharedPointer @@ -24,6 +27,10 @@ // Includes for version API #include +#if !defined(Q_OS_WINRT) +Q_IMPORT_PLUGIN(RemoteReaderManagerPlugIn) +#endif + #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT) Q_IMPORT_PLUGIN(PcscReaderManagerPlugIn) Q_IMPORT_PLUGIN(WebserviceActivationHandler) @@ -38,6 +45,29 @@ Q_IMPORT_PLUGIN(IntentActivationHandler) #if defined(Q_OS_IOS) Q_IMPORT_PLUGIN(CustomSchemeActivationHandler) + +Q_IMPORT_PLUGIN(QJpegPlugin) +Q_IMPORT_PLUGIN(QSvgPlugin) +Q_IMPORT_PLUGIN(QtQmlModelsPlugin) +Q_IMPORT_PLUGIN(QtQmlStateMachinePlugin) +Q_IMPORT_PLUGIN(QtGraphicalEffectsPlugin) +Q_IMPORT_PLUGIN(QtGraphicalEffectsPrivatePlugin) + +// Do not delete the comments to avoid searching for the class name +Q_IMPORT_PLUGIN(QtQuickExtrasStylesPlugin) +Q_IMPORT_PLUGIN(QtQuickControls1Plugin) +//Q_IMPORT_PLUGIN(QtQuickControls2MaterialStylePlugin) +//Q_IMPORT_PLUGIN(QtQuickControls2UniversalStylePlugin) +Q_IMPORT_PLUGIN(QtQuickControls2Plugin) +//Q_IMPORT_PLUGIN(QtQuick2DialogsPrivatePlugin) +Q_IMPORT_PLUGIN(QtQuick2DialogsPlugin) +//Q_IMPORT_PLUGIN(QtQuickExtrasPlugin) +Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin) +//Q_IMPORT_PLUGIN(QQmlLocalStoragePlugin) +//Q_IMPORT_PLUGIN(QtQuick2ParticlesPlugin) +Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin) +Q_IMPORT_PLUGIN(QtQuick2WindowPlugin) +Q_IMPORT_PLUGIN(QtQuick2Plugin) #endif #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || (defined(Q_OS_LINUX) && !defined(QT_NO_DEBUG)) @@ -82,6 +112,8 @@ static inline void printInfo() #ifdef Q_OS_ANDROID qCInfo(init) << "### Device:" << DeviceInfo::getPrettyInfo(); qCInfo(init) << "### VersionCode:" << BuildHelper::getVersionCode(); +#else + qCInfo(init) << "### Devicename:" << DeviceInfo::getName(); #endif qCInfo(init) << "### Qt Version:" << qVersion(); qCInfo(init) << "### OpenSSL Version:" << QSslSocket::sslLibraryVersionString(); @@ -100,13 +132,16 @@ static inline void printInfo() } +#include "config.h" // use in main only! Q_DECL_EXPORT int main(int argc, char** argv) { - QCoreApplication::setOrganizationName(QStringLiteral(VENDOR)); -#ifdef VENDOR_DOMAIN - QCoreApplication::setOrganizationDomain(QStringLiteral(VENDOR_DOMAIN)); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); #endif - QCoreApplication::setApplicationName(QStringLiteral("AusweisApp2")); + + QCoreApplication::setOrganizationName(QStringLiteral(VENDOR)); + QCoreApplication::setOrganizationDomain(QStringLiteral(VENDOR_DOMAIN)); + QCoreApplication::setApplicationName(QStringLiteral(PRODUCT)); QCoreApplication::setApplicationVersion(QStringLiteral(VERSION)); QGuiApplication::setQuitOnLastWindowClosed(false); @@ -118,8 +153,6 @@ Q_DECL_EXPORT 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 90117c4..279729b 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 AusweisAppExternalHttpParser) +TARGET_LINK_LIBRARIES(AusweisAppNetwork Qt5::Core Qt5::Network AusweisAppExternal::HttpParser AusweisAppGlobal AusweisAppSecureStorage AusweisAppSettings) diff --git a/src/network/DatagramHandler.cpp b/src/network/DatagramHandler.cpp index 628c3af..dc84f30 100644 --- a/src/network/DatagramHandler.cpp +++ b/src/network/DatagramHandler.cpp @@ -1,21 +1,19 @@ /*! - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "DatagramHandler.h" +#include "Initializer.h" using namespace governikus; +static Initializer::Entry X([] { + qRegisterMetaType("QHostAddress"); + }); -void DatagramHandler::registerMetaTypes() +DatagramHandler::DatagramHandler(bool) { - static bool registered = false; - if (!registered) - { - qRegisterMetaType("QHostAddress"); - registered = true; - } } diff --git a/src/network/DatagramHandler.h b/src/network/DatagramHandler.h index ebfdd0a..56f9ad7 100644 --- a/src/network/DatagramHandler.h +++ b/src/network/DatagramHandler.h @@ -1,7 +1,7 @@ /*! * \brief Provides an interface to send and receive datagrams over UDP. * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -10,23 +10,24 @@ #include #include +class test_DatagramHandlerImpl; namespace governikus { - class DatagramHandler : public QObject { Q_OBJECT - public: - static void registerMetaTypes(); + private: + friend class ::test_DatagramHandlerImpl; - DatagramHandler() = default; + public: + DatagramHandler(bool pListen = true); virtual ~DatagramHandler(); virtual bool isBound() const = 0; - virtual bool send(const QJsonDocument& pData, const QHostAddress& pAddress = QHostAddress::Broadcast) = 0; + virtual bool send(const QJsonDocument& pData) = 0; Q_SIGNALS: void fireNewMessage(const QJsonDocument& pData, const QHostAddress& pAddress); diff --git a/src/network/DatagramHandlerImpl.cpp b/src/network/DatagramHandlerImpl.cpp index b0819b9..6efc509 100644 --- a/src/network/DatagramHandlerImpl.cpp +++ b/src/network/DatagramHandlerImpl.cpp @@ -1,13 +1,14 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "DatagramHandlerImpl.h" -#include "EnvHolder.h" +#include "Env.h" #include #include +#include #include #include @@ -19,19 +20,25 @@ Q_DECLARE_LOGGING_CATEGORY(network) namespace governikus { -template<> DatagramHandler* createNewObject() +template<> DatagramHandler* createNewObject() { return new DatagramHandlerImpl; } +template<> DatagramHandler* createNewObject(bool&& pListen) +{ + return new DatagramHandlerImpl(pListen); +} + + } /* namespace governikus */ quint16 DatagramHandlerImpl::cPort = 24727; -DatagramHandlerImpl::DatagramHandlerImpl() +DatagramHandlerImpl::DatagramHandlerImpl(bool pListen) : DatagramHandler() , mSocket(new QUdpSocket) { @@ -41,7 +48,11 @@ DatagramHandlerImpl::DatagramHandlerImpl() connect(mSocket.data(), &QUdpSocket::readyRead, this, &DatagramHandlerImpl::onReadyRead); - if (mSocket->bind(cPort)) + if (!pListen) + { + qCDebug(network) << "Skipping binding"; + } + else if (mSocket->bind(cPort)) { qCDebug(network) << "Bound on port:" << mSocket->localPort(); } @@ -54,7 +65,7 @@ DatagramHandlerImpl::DatagramHandlerImpl() DatagramHandlerImpl::~DatagramHandlerImpl() { - if (isBound()) + if (DatagramHandlerImpl::isBound()) { qCDebug(network) << "Shutdown socket"; mSocket->close(); @@ -68,6 +79,47 @@ bool DatagramHandlerImpl::isBound() const } +bool DatagramHandlerImpl::send(const QJsonDocument& pData) +{ + QVector broadcastAddresses; + const auto& interfaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface& interface : interfaces) + { + const auto& entries = interface.addressEntries(); + for (const QNetworkAddressEntry& addressEntry : entries) + { + const QHostAddress& broadcastAddr = addressEntry.broadcast(); + if (broadcastAddr.isNull()) + { + continue; + } + if (addressEntry.ip().isEqual(QHostAddress::LocalHost, QHostAddress::TolerantConversion)) + { + continue; + } + + broadcastAddresses += broadcastAddr; + } + } + + if (broadcastAddresses.isEmpty()) + { + return false; + } + + for (const QHostAddress& broadcastAddr : qAsConst(broadcastAddresses)) + { + if (!send(pData, broadcastAddr)) + { + qDebug() << "Broadcasting to" << broadcastAddr << "failed"; + return false; + } + } + + return true; +} + + bool DatagramHandlerImpl::send(const QJsonDocument& pData, const QHostAddress& pAddress) { const auto& data = pData.toJson(QJsonDocument::Compact); @@ -95,12 +147,16 @@ void DatagramHandlerImpl::onReadyRead() 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; + static int timesLogged = 0; + if (timesLogged < 20) + { + qCInfo(network) << "Datagram does not contain valid JSON:" << datagram; + timesLogged++; + } } } } diff --git a/src/network/DatagramHandlerImpl.h b/src/network/DatagramHandlerImpl.h index 8e53460..ce540bb 100644 --- a/src/network/DatagramHandlerImpl.h +++ b/src/network/DatagramHandlerImpl.h @@ -1,7 +1,7 @@ /*! * \brief Provides an UDP socket to send and receive datagrams. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -29,12 +29,14 @@ class DatagramHandlerImpl static quint16 cPort; QScopedPointer mSocket; + bool send(const QJsonDocument& pData, const QHostAddress& pAddress); + public: - DatagramHandlerImpl(); - virtual ~DatagramHandlerImpl(); + DatagramHandlerImpl(bool pListen = true); + virtual ~DatagramHandlerImpl() override; virtual bool isBound() const override; - virtual bool send(const QJsonDocument& pData, const QHostAddress& pAddress = QHostAddress::Broadcast) override; + virtual bool send(const QJsonDocument& pData) override; private Q_SLOTS: void onReadyRead(); diff --git a/src/network/HttpRequest.cpp b/src/network/HttpRequest.cpp index b411eba..558a415 100644 --- a/src/network/HttpRequest.cpp +++ b/src/network/HttpRequest.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpRequest.h" @@ -8,10 +8,9 @@ using namespace governikus; -#define CAST_OBJ(parser) HttpRequest * obj = static_cast(parser->data); - Q_DECLARE_LOGGING_CATEGORY(network) +#define CAST_OBJ(parser) HttpRequest * obj = static_cast(parser->data); HttpRequest::HttpRequest(QAbstractSocket* pSocket, QObject* pParent) : QObject(pParent) @@ -113,7 +112,9 @@ void HttpRequest::onReadyRead() const auto& buffer = mSocket->readAll(); http_parser_execute(&mParser, &mParserSettings, buffer.constData(), static_cast(buffer.size())); - const auto errorCode = HTTP_PARSER_ERRNO(&mParser); + // See macro HTTP_PARSER_ERRNO if http_errno fails. + // We do not use this to avoid -Wold-style-cast warning + const auto errorCode = static_cast(mParser.http_errno); if (errorCode != HPE_OK) { qCWarning(network) << "Http request not well-formed:" << http_errno_name(errorCode) << "|" << http_errno_description(errorCode); diff --git a/src/network/HttpRequest.h b/src/network/HttpRequest.h index b581530..003b2d4 100644 --- a/src/network/HttpRequest.h +++ b/src/network/HttpRequest.h @@ -1,12 +1,12 @@ /*! * \brief Class to parse http request. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "http_parser/http_parser.h" +#include "http_parser.h" #include "HttpResponse.h" #include diff --git a/src/network/HttpResponse.cpp b/src/network/HttpResponse.cpp index b5eadd1..a056d36 100644 --- a/src/network/HttpResponse.cpp +++ b/src/network/HttpResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpResponse.h" @@ -13,10 +13,15 @@ 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"); +#define HEADER_NAME(_name, _key)\ + QByteArray _name(){\ + return QByteArrayLiteral(_key);\ + } + +HEADER_NAME(HEADER_CONTENT_LENGTH, "Content-Length") +HEADER_NAME(HEADER_CONTENT_TYPE, "Content-Type") +HEADER_NAME(HEADER_SERVER, "Server") +HEADER_NAME(HEADER_DATE, "Date") } Q_DECLARE_LOGGING_CATEGORY(network) @@ -34,9 +39,9 @@ HttpResponse::HttpResponse(HttpStatusCode pStatus, const QByteArray& pBody, cons { 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())); + setHeader(HEADER_SERVER(), QCoreApplication::applicationName().toUtf8() % version % QByteArrayLiteral(" (TR-03124-1/1.3)")); + 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())); } @@ -90,15 +95,15 @@ const QByteArray& HttpResponse::getBody() const void HttpResponse::setBody(const QByteArray& pBody, const QByteArray& pContentType) { mBody = pBody; - setHeader(HEADER_CONTENT_LENGTH, QByteArray::number(mBody.size())); + setHeader(HEADER_CONTENT_LENGTH(), QByteArray::number(mBody.size())); if (mBody.isEmpty() || pContentType.isEmpty()) { Q_ASSERT(pContentType.isEmpty()); - mHeader.remove(HEADER_CONTENT_TYPE); + mHeader.remove(HEADER_CONTENT_TYPE()); } else if (!pContentType.isEmpty()) { - setHeader(HEADER_CONTENT_TYPE, pContentType); + setHeader(HEADER_CONTENT_TYPE(), pContentType); } } diff --git a/src/network/HttpResponse.h b/src/network/HttpResponse.h index 875f62d..49d6a21 100644 --- a/src/network/HttpResponse.h +++ b/src/network/HttpResponse.h @@ -1,7 +1,7 @@ /*! * \brief Class to create http response. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/HttpServer.cpp b/src/network/HttpServer.cpp index 605c2a0..39bbe33 100644 --- a/src/network/HttpServer.cpp +++ b/src/network/HttpServer.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpServer.h" diff --git a/src/network/HttpServer.h b/src/network/HttpServer.h index 835e3b4..4747220 100644 --- a/src/network/HttpServer.h +++ b/src/network/HttpServer.h @@ -1,7 +1,7 @@ /*! * \brief Provide a HTTP server. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/HttpServerRequestor.cpp b/src/network/HttpServerRequestor.cpp index 2f5d102..cabd5fb 100644 --- a/src/network/HttpServerRequestor.cpp +++ b/src/network/HttpServerRequestor.cpp @@ -1,7 +1,8 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "Env.h" #include "HttpServerRequestor.h" #include "NetworkManager.h" @@ -49,7 +50,7 @@ QPointer HttpServerRequestor::request(const QUrl& pUrl, int pTime QNetworkRequest getRequest(pUrl); mTimer.start(pTimeOut); - mReply.reset(NetworkManager::getGlobalInstance().get(getRequest)); + mReply.reset(Env::getSingleton()->get(getRequest)); connect(mReply.data(), &QNetworkReply::finished, this, &HttpServerRequestor::finished); mEventLoop.exec(); diff --git a/src/network/HttpServerRequestor.h b/src/network/HttpServerRequestor.h index 3d399a5..d72e925 100644 --- a/src/network/HttpServerRequestor.h +++ b/src/network/HttpServerRequestor.h @@ -1,7 +1,7 @@ /* * \brief Sends one time GET requests to server. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/HttpServerStatusParser.cpp b/src/network/HttpServerStatusParser.cpp index 09ffafa..ca8db74 100644 --- a/src/network/HttpServerStatusParser.cpp +++ b/src/network/HttpServerStatusParser.cpp @@ -1,7 +1,5 @@ /*! - * HttpServerStatusParser.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpServerStatusParser.h" diff --git a/src/network/HttpServerStatusParser.h b/src/network/HttpServerStatusParser.h index 6b84e4b..440cce1 100644 --- a/src/network/HttpServerStatusParser.h +++ b/src/network/HttpServerStatusParser.h @@ -1,9 +1,7 @@ /*! - * HttpServerStatusParser.h - * * \brief Sends a status request to given url:port and tries to detect details and server header. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/HttpStatusCode.cpp b/src/network/HttpStatusCode.cpp index b0d6bcd..10ad983 100644 --- a/src/network/HttpStatusCode.cpp +++ b/src/network/HttpStatusCode.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpStatusCode.h" diff --git a/src/network/HttpStatusCode.h b/src/network/HttpStatusCode.h index d6595ca..64be69d 100644 --- a/src/network/HttpStatusCode.h +++ b/src/network/HttpStatusCode.h @@ -1,7 +1,7 @@ /*! * \brief Defines an enumeration of HTTP Status Codes as they are not defined by Qt. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp index aa4a38d..31d0d76 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -1,12 +1,14 @@ /* - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "NetworkManager.h" -#include "AppSettings.h" +#include "Env.h" #include "NetworkReplyError.h" #include "NetworkReplyTimeout.h" +#include "SecureStorage.h" +#include "SingletonHelper.h" #include "VersionInfo.h" #include @@ -18,70 +20,10 @@ using namespace governikus; -Q_GLOBAL_STATIC(NetworkManager, Instance) +defineSingleton(NetworkManager) Q_DECLARE_LOGGING_CATEGORY(network) - -QString NetworkManager::getTlsVersionString(QSsl::SslProtocol pProtocol) -{ - switch (pProtocol) - { - case QSsl::SslProtocol::AnyProtocol: - return QStringLiteral("AnyProtocol"); - - case QSsl::SslProtocol::SecureProtocols: - return QStringLiteral("SecureProtocols"); - - case QSsl::SslProtocol::SslV2: - return QStringLiteral("SslV2"); - - case QSsl::SslProtocol::SslV3: - return QStringLiteral("SslV3"); - - case QSsl::SslProtocol::TlsV1SslV3: - return QStringLiteral("TlsV1SslV3"); - - case QSsl::SslProtocol::TlsV1_0: - return QStringLiteral("TlsV1_0"); - - case QSsl::SslProtocol::TlsV1_0OrLater: - return QStringLiteral("TlsV1_0OrLater"); - - case QSsl::SslProtocol::TlsV1_1: - return QStringLiteral("TlsV1_1"); - - case QSsl::SslProtocol::TlsV1_1OrLater: - return QStringLiteral("TlsV1_1OrLater"); - - case QSsl::SslProtocol::TlsV1_2: - return QStringLiteral("TlsV1_2"); - - case QSsl::SslProtocol::TlsV1_2OrLater: - return QStringLiteral("TlsV1_2OrLater"); - - case QSsl::SslProtocol::UnknownProtocol: - return QStringLiteral("UnknownProtocol"); - } - - Q_UNREACHABLE(); -} - - -int NetworkManager::getOpenConnectionCount() -{ - return mOpenConnectionCount; -} - - -QDebug operator <<(QDebug pDbg, QSsl::SslProtocol pProtocol) -{ - QDebugStateSaver saver(pDbg); - pDbg.nospace() << NetworkManager::getTlsVersionString(pProtocol); - return pDbg; -} - - bool NetworkManager::mLockProxy = false; NetworkManager::NetworkManager() @@ -89,23 +31,9 @@ NetworkManager::NetworkManager() , mApplicationExitInProgress(false) , mOpenConnectionCount(0) , mNetAccessManager(new QNetworkAccessManager()) - , mNetAccessManagerPsk(new QNetworkAccessManager()) { - if (Instance.exists()) - { - mNetAccessManager->useAuthenticationManagerFrom(*Instance->mNetAccessManager); - mNetAccessManagerPsk->useAuthenticationManagerFrom(*Instance->mNetAccessManagerPsk); - - connect(&NetworkManager::getGlobalInstance(), &NetworkManager::fireShutdown, this, &NetworkManager::onShutdown); - } - else - { - mNetAccessManagerPsk->useAuthenticationManagerFrom(*mNetAccessManager); - } - #ifndef QT_NO_NETWORKPROXY connect(mNetAccessManager.data(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &NetworkManager::fireProxyAuthenticationRequired); - connect(mNetAccessManagerPsk.data(), &QNetworkAccessManager::proxyAuthenticationRequired, this, &NetworkManager::fireProxyAuthenticationRequired); #endif } @@ -115,13 +43,25 @@ NetworkManager::~NetworkManager() } -NetworkManager& NetworkManager::getGlobalInstance() +NetworkManager& NetworkManager::getInstance() { return *Instance; } -QNetworkReply* NetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) +int NetworkManager::getOpenConnectionCount() +{ + return mOpenConnectionCount; +} + + +void NetworkManager::clearConnections() +{ + mNetAccessManager->clearConnectionCache(); +} + + +QNetworkReply* NetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pNamespace, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) { if (mApplicationExitInProgress) { @@ -129,23 +69,16 @@ QNetworkReply* NetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& } pRequest.setHeader(QNetworkRequest::UserAgentHeader, getUserAgentHeader()); - pRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/vnd.paos+xml; charset=UTF-8"); + pRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/vnd.paos+xml; charset=UTF-8")); pRequest.setHeader(QNetworkRequest::ContentLengthHeader, QString::number(pData.size())); pRequest.setRawHeader("Connection", "keep-alive"); pRequest.setRawHeader("Accept", "text/html; application/vnd.paos+xml"); - pRequest.setRawHeader("PAOS", "ver=\"urn:liberty:paos:2006-08\""); + pRequest.setRawHeader("PAOS", QByteArray("ver=\"%1\"").replace(QByteArray("%1"), pNamespace)); QNetworkReply* response; - if (pUsePsk) - { - pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettingsPsk().getConfiguration()); - response = mNetAccessManagerPsk->post(pRequest, pData); - } - else - { - pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); - response = mNetAccessManager->post(pRequest, pData); - } + SecureStorage::TlsSuite tlsSuite = pUsePsk ? SecureStorage::TlsSuite::PSK : SecureStorage::TlsSuite::DEFAULT; + pRequest.setSslConfiguration(SecureStorage::getInstance().getTlsConfig(tlsSuite).getConfiguration()); + response = mNetAccessManager->post(pRequest, pData); trackConnection(response, pTimeoutInMilliSeconds); return response; @@ -160,35 +93,19 @@ QNetworkReply* NetworkManager::get(QNetworkRequest& pRequest, int pTimeoutInMill } pRequest.setHeader(QNetworkRequest::UserAgentHeader, getUserAgentHeader()); - pRequest.setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); + pRequest.setSslConfiguration(SecureStorage::getInstance().getTlsConfig().getConfiguration()); QNetworkReply* response = mNetAccessManager->get(pRequest); trackConnection(response, pTimeoutInMilliSeconds); return response; } -QSslSocket* NetworkManager::createSslSocket(const QUrl& pUrl) +bool NetworkManager::checkUpdateServerCertificate(const QNetworkReply& pReply) { - QSslSocket* socket = new QSslSocket(); - socket->setSslConfiguration(AppSettings::getInstance().getSecureStorage().getTlsSettings().getConfiguration()); - configureProxy(socket, pUrl); - return socket; -} + const QVector& trustedCertificates = SecureStorage::getInstance().getUpdateCertificates(); - -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); - 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 + const auto& cert = pReply.sslConfiguration().peerCertificate(); + return !cert.isNull() && trustedCertificates.contains(cert); } @@ -215,6 +132,9 @@ NetworkManager::NetworkError NetworkManager::toNetworkError(const QNetworkReply* case QNetworkReply::TimeoutError: return NetworkError::TimeOut; + case QNetworkReply::ServiceUnavailableError: + return NetworkError::ServiceUnavailable; + case QNetworkReply::ProxyAuthenticationRequiredError: case QNetworkReply::ProxyConnectionClosedError: case QNetworkReply::ProxyConnectionRefusedError: @@ -238,6 +158,9 @@ GlobalStatus NetworkManager::toTrustedChannelStatus(const QNetworkReply* const p { switch (toNetworkError(pNetworkReply)) { + case NetworkManager::NetworkError::ServiceUnavailable: + return GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable; + case NetworkManager::NetworkError::TimeOut: return GlobalStatus::Code::Workflow_TrustedChannel_TimeOut; @@ -259,6 +182,9 @@ GlobalStatus NetworkManager::toStatus(const QNetworkReply* const pNetworkReply) { switch (toNetworkError(pNetworkReply)) { + case NetworkManager::NetworkError::ServiceUnavailable: + return GlobalStatus::Code::Network_ServiceUnavailable; + case NetworkManager::NetworkError::TimeOut: return GlobalStatus::Code::Network_TimeOut; diff --git a/src/network/NetworkManager.h b/src/network/NetworkManager.h index c17ae9e..36324d2 100644 --- a/src/network/NetworkManager.h +++ b/src/network/NetworkManager.h @@ -1,7 +1,7 @@ /* * \brief Wrapper around QNetworkAccessManager * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -31,17 +31,20 @@ class NetworkManager static bool mLockProxy; QScopedPointer mNetAccessManager; - QScopedPointer mNetAccessManagerPsk; - void configureProxy(QTcpSocket* pSocket, const QUrl& pUrl); QString getUserAgentHeader() const; public Q_SLOTS: void onShutdown(); + protected: + NetworkManager(); + virtual ~NetworkManager(); + public: enum class NetworkError { + ServiceUnavailable, TimeOut, ProxyError, SslError, @@ -56,24 +59,19 @@ class NetworkManager } - static NetworkManager& getGlobalInstance(); + static NetworkManager& getInstance(); 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(); - virtual ~NetworkManager(); - - virtual QNetworkReply* paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk = true, int pTimeoutInMilliSeconds = 30000); + virtual void clearConnections(); + virtual QNetworkReply* paos(QNetworkRequest& pRequest, const QByteArray& pNamespace, const QByteArray& pData, bool pUsePsk = true, int pTimeoutInMilliSeconds = 30000); virtual QNetworkReply* get(QNetworkRequest& pRequest, int pTimeoutInMilliSeconds = 30000); - int getOpenConnectionCount(); - /*! - * Creates a QSslSocket. The parameter \a pUrl is used to set the proxy for this socket. - * The socket is *not* connected. - */ - QSslSocket* createSslSocket(const QUrl& pUrl); + virtual bool checkUpdateServerCertificate(const QNetworkReply& pReply); + + int getOpenConnectionCount(); Q_SIGNALS: void fireProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator); diff --git a/src/network/NetworkReplyError.cpp b/src/network/NetworkReplyError.cpp index 1d43161..45853a3 100644 --- a/src/network/NetworkReplyError.cpp +++ b/src/network/NetworkReplyError.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + #include "NetworkReplyError.h" using namespace governikus; @@ -27,7 +31,7 @@ NetworkReplyError::NetworkReplyError(QNetworkRequest const& pRequest, QObject* p : QNetworkReply(pParent) { setRequest(pRequest); - setError(NetworkError::OperationCanceledError, "Application shutting down"); + setError(NetworkError::OperationCanceledError, QStringLiteral("Application shutting down")); QMetaObject::invokeMethod(this, "onErrorSignals", Qt::QueuedConnection); } diff --git a/src/network/NetworkReplyError.h b/src/network/NetworkReplyError.h index df8539c..0d08d0c 100644 --- a/src/network/NetworkReplyError.h +++ b/src/network/NetworkReplyError.h @@ -1,5 +1,5 @@ /* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -15,10 +15,10 @@ class NetworkReplyError Q_OBJECT protected: - virtual qint64 readData(char* data, qint64 maxlen); + virtual qint64 readData(char* data, qint64 maxlen) override; public Q_SLOTS: - virtual void abort(); + virtual void abort() override; void onErrorSignals(); public: diff --git a/src/network/NetworkReplyTimeout.cpp b/src/network/NetworkReplyTimeout.cpp index 7f6f6bf..cc016f5 100644 --- a/src/network/NetworkReplyTimeout.cpp +++ b/src/network/NetworkReplyTimeout.cpp @@ -1,11 +1,10 @@ /*! - * NetworkReplyTimeout.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "NetworkReplyTimeout.h" +#include "Env.h" #include "NetworkManager.h" #include @@ -49,5 +48,5 @@ void NetworkReplyTimeout::setTimeout(QNetworkReply* pReply, const int pTimeout) { // since the QNetworkReply is set as parent, we don't need to care about destruction NetworkReplyTimeout* timeout = new NetworkReplyTimeout(pReply, pTimeout); - connect(&NetworkManager::getGlobalInstance(), &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown); + connect(Env::getSingleton(), &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown); } diff --git a/src/network/NetworkReplyTimeout.h b/src/network/NetworkReplyTimeout.h index 89ac688..121924c 100644 --- a/src/network/NetworkReplyTimeout.h +++ b/src/network/NetworkReplyTimeout.h @@ -1,9 +1,7 @@ /*! - * NetworkReplyTimeout.h - * * \brief Utility class to set a timeout on a QNetworkReply * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/TlsChecker.cpp b/src/network/TlsChecker.cpp new file mode 100644 index 0000000..b543206 --- /dev/null +++ b/src/network/TlsChecker.cpp @@ -0,0 +1,245 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TlsChecker.h" + +#include "AppSettings.h" +#include "Env.h" +#include "SecureStorage.h" + +#include + +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(developermode) +Q_DECLARE_LOGGING_CATEGORY(network) + +using namespace governikus; + + +bool TlsChecker::checkCertificate(const QSslCertificate& pCertificate, + QCryptographicHash::Algorithm pAlgorithm, + const QSet& pAcceptedCertificateHashes) +{ + qDebug() << "Check certificate CN=" << pCertificate.subjectInfo(QSslCertificate::CommonName) << "SN=" << pCertificate.serialNumber(); + QString hash = QString::fromLatin1(pCertificate.digest(pAlgorithm).toHex()); + qDebug() << "Certificate hash(" << pAlgorithm << ")" << hash; + qDebug() << "Accepted certificate hashes" << pAcceptedCertificateHashes; + for (const auto& acceptedHash : pAcceptedCertificateHashes) + { + if (hash.compare(acceptedHash, Qt::CaseInsensitive) == 0) + { + return true; + } + } + + return false; +} + + +bool TlsChecker::hasValidCertificateKeyLength(const QSslCertificate& pCertificate) +{ + auto keyLength = pCertificate.publicKey().length(); + auto keyAlgorithm = pCertificate.publicKey().algorithm(); + qDebug() << "Check certificate key of type" << TlsChecker::toString(keyAlgorithm) << "and key size" << keyLength; + return isValidKeyLength(keyLength, keyAlgorithm, false); +} + + +bool TlsChecker::hasValidEphemeralKeyLength(const QSslKey& pEphemeralServerKey) +{ + int keyLength = pEphemeralServerKey.length(); + QSsl::KeyAlgorithm keyAlgorithm = pEphemeralServerKey.algorithm(); + + if (keyAlgorithm == QSsl::Opaque) + { + // try do determine key algorithm and length + if (auto key = static_cast(pEphemeralServerKey.handle())) + { + keyLength = EVP_PKEY_bits(key); + switch (EVP_PKEY_base_id(key)) + { + case EVP_PKEY_RSA: + keyAlgorithm = QSsl::Rsa; + break; + + case EVP_PKEY_DSA: + /* fall through */ + case EVP_PKEY_DH: + keyAlgorithm = QSsl::Dsa; + break; + + case EVP_PKEY_EC: + keyAlgorithm = QSsl::Ec; + break; + } + } + } + + qDebug() << "Check ephemeral key of type" << TlsChecker::toString(keyAlgorithm) << "and key size" << keyLength; + return isValidKeyLength(keyLength, keyAlgorithm, true); +} + + +bool TlsChecker::isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral) +{ + const auto& secureStorage = SecureStorage::getInstance(); + 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 (Env::getSingleton()->getGeneralSettings().isDeveloperMode()) + { + qCWarning(developermode) << keySizeError; + sufficient = true; + } + else + { + qWarning() << keySizeError; + } + } + return sufficient; +} + + +QString TlsChecker::toString(QSsl::SslProtocol pProtocol) +{ + switch (pProtocol) + { + case QSsl::SslProtocol::AnyProtocol: + return QStringLiteral("AnyProtocol"); + + case QSsl::SslProtocol::SecureProtocols: + return QStringLiteral("SecureProtocols"); + + case QSsl::SslProtocol::SslV2: + return QStringLiteral("SslV2"); + + case QSsl::SslProtocol::SslV3: + return QStringLiteral("SslV3"); + + case QSsl::SslProtocol::TlsV1SslV3: + return QStringLiteral("TlsV1SslV3"); + + case QSsl::SslProtocol::TlsV1_0: + return QStringLiteral("TlsV1_0"); + + case QSsl::SslProtocol::TlsV1_0OrLater: + return QStringLiteral("TlsV1_0OrLater"); + + case QSsl::SslProtocol::TlsV1_1: + return QStringLiteral("TlsV1_1"); + + case QSsl::SslProtocol::TlsV1_1OrLater: + return QStringLiteral("TlsV1_1OrLater"); + + case QSsl::SslProtocol::TlsV1_2: + return QStringLiteral("TlsV1_2"); + + case QSsl::SslProtocol::TlsV1_2OrLater: + return QStringLiteral("TlsV1_2OrLater"); + + case QSsl::SslProtocol::UnknownProtocol: + return QStringLiteral("UnknownProtocol"); + } + + Q_UNREACHABLE(); +} + + +QString TlsChecker::toString(QSsl::KeyAlgorithm pKeyAlgorithm) +{ + switch (pKeyAlgorithm) + { + case QSsl::KeyAlgorithm::Dsa: + return QStringLiteral("Dsa"); + + case QSsl::KeyAlgorithm::Rsa: + return QStringLiteral("Rsa"); + + case QSsl::KeyAlgorithm::Ec: + return QStringLiteral("Ec"); + + default: + return QStringLiteral("Unknown (%1)").arg(pKeyAlgorithm); + } +} + + +QStringList TlsChecker::getFatalErrors(const QList& pErrors) +{ + static const QSet fatalErrors( + {QSslError::CertificateSignatureFailed, QSslError::CertificateNotYetValid, QSslError::CertificateExpired, + QSslError::InvalidNotBeforeField, QSslError::InvalidNotAfterField, QSslError::CertificateRevoked, QSslError::InvalidCaCertificate, + QSslError::CertificateRejected, QSslError::SubjectIssuerMismatch, QSslError::HostNameMismatch, + QSslError::UnspecifiedError, QSslError::NoSslSupport, QSslError::CertificateBlacklisted} + ); + + QStringList fatalErrorStrings; + for (const auto& error : pErrors) + { + QString msg = QStringLiteral("%1: %2").arg(static_cast(error.error())).arg(error.errorString()); + if (fatalErrors.contains(error.error())) + { + if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + { + qCWarning(developermode) << msg; + } + else + { + qCWarning(network) << msg; + fatalErrorStrings += msg; + } + } + else + { + qCDebug(network) << "(ignored) " << msg; + } + } + return fatalErrorStrings; +} + + +bool TlsChecker::containsFatalError(QNetworkReply* pReply, const QList& pErrors) +{ + Q_ASSERT(pReply); + + if (getFatalErrors(pErrors).isEmpty()) + { + qCDebug(network) << "Ignore SSL errors"; + pReply->ignoreSslErrors(); + return false; + } + + return true; +} + + +void TlsChecker::logSslConfig(const QSslConfiguration pCfg, QDebug pDebug) +{ + QMessageLogger logger("", 0, ""); + logger.info(network) << "Used session cipher" << pCfg.sessionCipher(); + logger.info(network) << "Used session protocol:" << toString(pCfg.sessionProtocol()); + + { + auto stream = logger.info(network); + stream << "Used ephemeral server key:"; + if (!pCfg.ephemeralServerKey().isNull()) + { + stream << pCfg.ephemeralServerKey(); + } + } + + logger.info(network) << "Used peer certificate:" << pCfg.peerCertificate(); + + pDebug << "Handshake of tls connection done!"; +} diff --git a/src/network/TlsChecker.h b/src/network/TlsChecker.h new file mode 100644 index 0000000..6f5a576 --- /dev/null +++ b/src/network/TlsChecker.h @@ -0,0 +1,52 @@ +/*! + * \brief Helper to check certificates and other security stuff of TLS/SSL. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace governikus +{ + +class TlsChecker +{ + private: + TlsChecker() = delete; + static bool isValidKeyLength(int pKeyLength, QSsl::KeyAlgorithm pKeyAlgorithm, bool pIsEphemeral); + + public: + static void logSslConfig(const QSslConfiguration pCfg, QDebug pDebug); + static QString toString(QSsl::SslProtocol pProtocol); + static QString toString(QSsl::KeyAlgorithm pKeyAlgorithm); + + static QStringList getFatalErrors(const QList& pErrors); + static bool containsFatalError(QNetworkReply* pReply, const QList& pErrors); + + /*! + * Checks, whether the certificate's hash is contained in a set of accepted certificate hashes. + */ + static bool checkCertificate(const QSslCertificate& pCertificate, + QCryptographicHash::Algorithm pAlgorithm, + const QSet& pAcceptedCertificateHashes); + + /*! + * Checks, whether the key length of the SSL certificate is of sufficient length. + */ + static bool hasValidCertificateKeyLength(const QSslCertificate& pCertificate); + + /*! + * Checks, whether the length of the ephemeral key is of sufficient length. + */ + static bool hasValidEphemeralKeyLength(const QSslKey& pEphemeralServerKey); +}; + +} /* namespace governikus */ diff --git a/src/network/TlsConfiguration.cpp b/src/network/TlsConfiguration.cpp deleted file mode 100644 index 38c9151..0000000 --- a/src/network/TlsConfiguration.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "AppSettings.h" -#include "TlsConfiguration.h" - -#include -#include -#include - -using namespace governikus; - - -Q_DECLARE_LOGGING_CATEGORY(developermode) -Q_DECLARE_LOGGING_CATEGORY(network) - -QStringList TlsConfiguration::getFatalErrors(const QList& pErrors) -{ - static const QSet fatalErrors( - {QSslError::CertificateSignatureFailed, QSslError::CertificateNotYetValid, QSslError::CertificateExpired, - QSslError::InvalidNotBeforeField, QSslError::InvalidNotAfterField, QSslError::CertificateRevoked, QSslError::InvalidCaCertificate, - QSslError::CertificateRejected, QSslError::SubjectIssuerMismatch, QSslError::HostNameMismatch, - QSslError::UnspecifiedError, QSslError::NoSslSupport, QSslError::CertificateBlacklisted} - ); - - QStringList fatalErrorStrings; - for (const auto& error : pErrors) - { - QString msg = QStringLiteral("%1: %2").arg(static_cast(error.error())).arg(error.errorString()); - if (fatalErrors.contains(error.error())) - { - if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) - { - qCWarning(developermode) << msg; - } - else - { - qCWarning(network) << msg; - fatalErrorStrings += msg; - } - } - else - { - qCWarning(network) << "(ignored) " << msg; - } - } - return fatalErrorStrings; -} - - -bool TlsConfiguration::containsFatalError(QNetworkReply* pReply, const QList& pErrors) -{ - 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 deleted file mode 100644 index 01fd14e..0000000 --- a/src/network/TlsConfiguration.h +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * \brief Default configuration for TLS connections - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "SecureStorage.h" - -#include -#include -#include -#include -#include -#include - -namespace governikus -{ - - -class TlsConfiguration -{ - private: - TlsConfiguration(); - ~TlsConfiguration(); - Q_DISABLE_COPY(TlsConfiguration) - - public: - static QStringList getFatalErrors(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 3cf4176..2a95945 100644 --- a/src/network/UrlUtil.cpp +++ b/src/network/UrlUtil.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ @@ -63,7 +63,7 @@ QUrl UrlUtil::addMajorMinor(const QUrl& pOriginUrl, const GlobalStatus& pStatus) q.setQuery(pOriginUrl.query()); q.addQueryItem(QStringLiteral("ResultMajor"), major); - if (result.getMinor() != GlobalStatus::Code::Unknown_Error) + if (result.getMinor() != GlobalStatus::Code::No_Error) { QString minor; diff --git a/src/network/UrlUtil.h b/src/network/UrlUtil.h index 6217eba..cb12e52 100644 --- a/src/network/UrlUtil.h +++ b/src/network/UrlUtil.h @@ -1,6 +1,6 @@ /*! * \brief Helper to convert \ref Result to Redirect-Result-String and some other URL stuff. - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/network/WifiInfo.cpp b/src/network/WifiInfo.cpp new file mode 100644 index 0000000..a68980d --- /dev/null +++ b/src/network/WifiInfo.cpp @@ -0,0 +1,95 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WifiInfo.h" + +#include +#include +#if defined(Q_OS_ANDROID) + #include + #include + #include +#endif + +Q_DECLARE_LOGGING_CATEGORY(qml) + + +using namespace governikus; + + +WifiInfo::WifiInfo() + : QObject() + , mWifiEnabled(getCurrentWifiEnabled()) + , mWifiEnabledTimerId(0) +{ +#if defined(Q_OS_ANDROID) + const int timeoutMs = 1000; + mWifiEnabledTimerId = startTimer(timeoutMs); +#endif +} + + +WifiInfo::~WifiInfo() +{ + +} + + +bool WifiInfo::getCurrentWifiEnabled() +{ +#if !defined(Q_OS_ANDROID) + return true; + +#else + QAndroidJniEnvironment env; + const QAndroidJniObject context(QtAndroid::androidContext()); + if (!context.isValid()) + { + qCCritical(qml) << "Cannot determine android context."; + return false; + } + + const jboolean jEnabled = QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/WifiInfo", + "wifiEnabled", + "(Landroid/content/Context;)Z", + context.object()); + + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Cannot call WifiInfo.wifiEnabled()"; + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + + return jEnabled == JNI_TRUE; + +#endif +} + + +void WifiInfo::timerEvent(QTimerEvent* pEvent) +{ + if (pEvent->timerId() == mWifiEnabledTimerId) + { + const bool currentEnabled = getCurrentWifiEnabled(); + if (mWifiEnabled != currentEnabled) + { + mWifiEnabled = currentEnabled; + Q_EMIT fireWifiEnabledChanged(mWifiEnabled); + } + } + + QObject::timerEvent(pEvent); +} + + +bool WifiInfo::isWifiEnabled() +{ +#if !defined(Q_OS_ANDROID) + qCWarning(qml) << "NOT IMPLEMENTED"; +#endif + + return mWifiEnabled; +} diff --git a/src/network/WifiInfo.h b/src/network/WifiInfo.h new file mode 100644 index 0000000..5e91d67 --- /dev/null +++ b/src/network/WifiInfo.h @@ -0,0 +1,41 @@ +/*! + * \brief Provides information about the Wifi status + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#pragma once + +#include + +namespace governikus +{ + +class WifiInfo + : public QObject +{ + Q_OBJECT + + private: + bool mWifiEnabled; + int mWifiEnabledTimerId; + + bool getCurrentWifiEnabled(); + + protected: + void timerEvent(QTimerEvent* pEvent) override; + + public: + WifiInfo(); + virtual ~WifiInfo() override; + + bool isWifiEnabled(); + + Q_SIGNALS: + void fireWifiEnabledChanged(bool pEnabled); + +}; + + +} diff --git a/src/network/WifiInfo.java b/src/network/WifiInfo.java new file mode 100644 index 0000000..0f7c47e --- /dev/null +++ b/src/network/WifiInfo.java @@ -0,0 +1,47 @@ +/* + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +package com.governikus.ausweisapp2; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; +import android.os.Build; +import android.util.Log; + +public class WifiInfo +{ + private static final String TAG = "AusweisApp2"; + + public static boolean wifiEnabled(Context context) + { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + if (android.os.Build.VERSION.SDK_INT < 21) + { + for (NetworkInfo networkInfo : connectivityManager.getAllNetworkInfo()) + { + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.getState().equals(NetworkInfo.State.CONNECTED)) + { + return true; + } + } + } + else + { + for (Network mNetwork : connectivityManager.getAllNetworks()) + { + NetworkInfo networkInfo = connectivityManager.getNetworkInfo(mNetwork); + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.getState().equals(NetworkInfo.State.CONNECTED)) + { + return true; + } + } + } + return false; + } + + +} diff --git a/src/qml/ApplicationModel.cpp b/src/qml/ApplicationModel.cpp index a5c63cf..c55925d 100644 --- a/src/qml/ApplicationModel.cpp +++ b/src/qml/ApplicationModel.cpp @@ -1,15 +1,15 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ApplicationModel.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" -#include "context/SelfAuthenticationContext.h" +#include "context/SelfAuthContext.h" +#include "Env.h" #include "ReaderInfo.h" #include "ReaderManager.h" -#include "SingletonHelper.h" #if (defined(Q_OS_LINUX) && !defined(QT_NO_DEBUG)) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) #include @@ -23,8 +23,6 @@ using namespace governikus; -defineSingleton(ApplicationModel) - void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) { @@ -42,12 +40,20 @@ void ApplicationModel::onStatusChanged(const ReaderManagerPlugInInfo& pInfo) ApplicationModel::ApplicationModel(QObject* pParent) : QObject(pParent) , mContext() + , mWifiInfo() { - connect(&ReaderManager::getInstance(), &ReaderManager::fireStatusChanged, this, &ApplicationModel::onStatusChanged); 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::onStatusChanged); connect(&ReaderManager::getInstance(), &ReaderManager::fireStatusChanged, this, &ApplicationModel::fireBluetoothReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &ApplicationModel::fireSelectedReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &ApplicationModel::fireSelectedReaderChanged); + connect(&mWifiInfo, &WifiInfo::fireWifiEnabledChanged, this, &ApplicationModel::onWifiEnabledChanged); + + onWifiEnabledChanged(); + + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireCertificateRemoved, this, &ApplicationModel::fireCertificateRemoved); } @@ -56,15 +62,17 @@ ApplicationModel::~ApplicationModel() } -ApplicationModel& ApplicationModel::getWidgetInstance() -{ - return *Instance; -} - - void ApplicationModel::resetContext(const QSharedPointer& pContext) { - mContext = pContext; + if (mContext) + { + disconnect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &ApplicationModel::fireSelectedReaderChanged); + } + + if ((mContext = pContext)) + { + connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &ApplicationModel::fireSelectedReaderChanged); + } Q_EMIT fireCurrentWorkflowChanged(); } @@ -85,13 +93,25 @@ ReaderManagerPlugInInfo ApplicationModel::getFirstPlugInInfo(ReaderManagerPlugIn bool ApplicationModel::isNfcAvailable() const { +#if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) + return getFirstPlugInInfo(ReaderManagerPlugInType::PCSC).isAvailable(); + +#else return getFirstPlugInInfo(ReaderManagerPlugInType::NFC).isAvailable(); + +#endif } bool ApplicationModel::isNfcEnabled() const { +#if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) + return getFirstPlugInInfo(ReaderManagerPlugInType::PCSC).isEnabled(); + +#else return getFirstPlugInInfo(ReaderManagerPlugInType::NFC).isEnabled(); + +#endif } @@ -107,24 +127,6 @@ bool ApplicationModel::isBluetoothEnabled() const } -QString ApplicationModel::getCurrentWorkflow() const -{ - if (mContext.objectCast()) - { - return QStringLiteral("changepin"); - } - if (mContext.objectCast()) - { - return QStringLiteral("selfauthentication"); - } - if (mContext.objectCast()) - { - return QStringLiteral("authentication"); - } - return QString(); -} - - void ApplicationModel::setBluetoothEnabled(bool pEnabled) { #if (defined(Q_OS_LINUX) && !defined(QT_NO_DEBUG)) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) @@ -176,3 +178,39 @@ bool ApplicationModel::locationPermissionRequired() const #endif } + + +QString ApplicationModel::getCurrentWorkflow() const +{ + if (mContext.objectCast()) + { + return QStringLiteral("changepin"); + } + if (mContext.objectCast()) + { + return QStringLiteral("selfauthentication"); + } + if (mContext.objectCast()) + { + return QStringLiteral("authentication"); + } + return QString(); +} + + +bool ApplicationModel::foundSelectedReader() const +{ + if (!mContext) + { + return false; + } + + return ReaderManager::getInstance().getReaderInfos(mContext->getReaderPlugInTypes()).size() > 0; +} + + +void ApplicationModel::onWifiEnabledChanged() +{ + mWifiEnabled = mWifiInfo.isWifiEnabled(); + Q_EMIT fireWifiEnabledChanged(); +} diff --git a/src/qml/ApplicationModel.h b/src/qml/ApplicationModel.h index efde4d0..d375ae5 100644 --- a/src/qml/ApplicationModel.h +++ b/src/qml/ApplicationModel.h @@ -1,7 +1,7 @@ /*! * \brief Model implementation for the application. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -9,6 +9,7 @@ #include "ReaderManagerPlugInInfo.h" #include "ReaderInfo.h" +#include "WifiInfo.h" #include #include @@ -23,41 +24,58 @@ class ApplicationModel : public QObject { Q_OBJECT + Q_PROPERTY(bool nfcEnabled READ isNfcEnabled NOTIFY fireNfcEnabledChanged) 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(bool wifiEnabled MEMBER mWifiEnabled NOTIFY fireWifiEnabledChanged) + Q_PROPERTY(QString currentWorkflow READ getCurrentWorkflow NOTIFY fireCurrentWorkflowChanged) + Q_PROPERTY(bool foundSelectedReader READ foundSelectedReader NOTIFY fireSelectedReaderChanged) QSharedPointer mContext; void onStatusChanged(const ReaderManagerPlugInInfo& pInfo); ReaderManagerPlugInInfo getFirstPlugInInfo(ReaderManagerPlugInType pType) const; + private: + WifiInfo mWifiInfo; + bool mWifiEnabled; + + private Q_SLOTS: + void onWifiEnabledChanged(); + public: ApplicationModel(QObject* pParent = nullptr); virtual ~ApplicationModel(); - - // 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 isBluetoothAvailable() const; bool isBluetoothEnabled() const; void setBluetoothEnabled(bool pEnabled); bool locationPermissionRequired() const; QString getCurrentWorkflow() const; + bool foundSelectedReader() const; Q_SIGNALS: void fireNfcEnabledChanged(); + void fireBluetoothEnabledChanged(); - void fireCurrentWorkflowChanged(); void fireBluetoothReaderChanged(); + + void fireCurrentWorkflowChanged(); + void fireSelectedReaderChanged(); + + void fireWifiEnabledChanged(); + void fireCertificateRemoved(QString pDeviceName); }; diff --git a/src/qml/AuthModel.cpp b/src/qml/AuthModel.cpp index c79452c..262c4cb 100644 --- a/src/qml/AuthModel.cpp +++ b/src/qml/AuthModel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "AuthModel.h" @@ -11,7 +11,7 @@ using namespace governikus; AuthModel::AuthModel(QObject* pParent) - : QObject(pParent) + : WorkflowModel(pParent) , mContext() , mTransactionInfo() { @@ -25,43 +25,20 @@ AuthModel::~AuthModel() void AuthModel::resetContext(const QSharedPointer& pContext) { + mContext = pContext; + WorkflowModel::resetContext(pContext); + + if (mContext) + { + connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &AuthModel::onDidAuthenticateEac1Changed); + } + if (!mTransactionInfo.isEmpty()) { mTransactionInfo.clear(); Q_EMIT fireTransactionInfoChanged(); } - - mContext = pContext; - if (mContext) - { - connect(mContext.data(), &AuthContext::fireCurrentStateChanged, this, &AuthModel::fireCurrentStateChanged); - connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &AuthModel::fireResultChanged); - connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &AuthModel::onDidAuthenticateEac1Changed); - } - - /* - * Only this state change is emitted when the context is reset, i.e. after the end of the workflow - */ - Q_EMIT fireCurrentStateChanged(getCurrentState()); -} - - -QString AuthModel::getCurrentState() const -{ - return mContext ? mContext->getCurrentState() : QString(); -} - - -QString AuthModel::getResultString() const -{ - return mContext ? mContext->getStatus().toErrorDescription(true) : QString(); -} - - -bool AuthModel::isError() const -{ - return mContext && mContext->getStatus().isError(); } @@ -71,63 +48,6 @@ const QString& AuthModel::getTransactionInfo() const } -void AuthModel::continueWorkflow() -{ - if (mContext) - { - mContext->setStateApproved(); - } -} - - -void AuthModel::cancelWorkflow() -{ - if (mContext) - { - Q_EMIT mContext->fireCancelWorkflow(); - } -} - - -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(Enum::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); - } -} - - -bool AuthModel::isBasicReader() -{ - if (mContext) - { - return mContext->getCardConnection()->getReaderInfo().isBasicReader(); - } - - return true; -} - - -void AuthModel::abortCardSelection() -{ - if (mContext) - { - Q_EMIT mContext->fireAbortCardSelection(); - } -} - - void AuthModel::onDidAuthenticateEac1Changed() { if (mContext) diff --git a/src/qml/AuthModel.h b/src/qml/AuthModel.h index a12da89..674cb26 100644 --- a/src/qml/AuthModel.h +++ b/src/qml/AuthModel.h @@ -1,27 +1,28 @@ /*! * \brief Model implementation for the authentication action. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "WorkflowModel.h" + #include #include #include + namespace governikus { class AuthContext; class AuthModel - : public QObject + : public WorkflowModel { Q_OBJECT - 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; @@ -29,28 +30,16 @@ class AuthModel public: AuthModel(QObject* pParent = nullptr); - virtual ~AuthModel(); + virtual ~AuthModel() override; void resetContext(const QSharedPointer& pContext = QSharedPointer()); - QString getCurrentState() const; - QString getResultString() const; - bool isError() const; const QString& getTransactionInfo() const; - 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 8e57fa1..beaada7 100644 --- a/src/qml/CMakeLists.txt +++ b/src/qml/CMakeLists.txt @@ -1,17 +1,19 @@ ADD_PLATFORM_LIBRARY(AusweisAppQml) -TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Svg Qt5::Qml Qt5::Quick Qt5::QuickControls2 AusweisAppCore AusweisAppGlobal) +TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Core Qt5::Svg Qt5::Qml Qt5::Quick Qt5::QuickControls2 AusweisAppCore AusweisAppGlobal AusweisAppRemoteDevice) IF(DESKTOP) TARGET_LINK_LIBRARIES(AusweisAppQml AusweisAppExport) ENDIF() IF(TARGET Qt5::Bluetooth) - TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Bluetooth) + TARGET_LINK_LIBRARIES(AusweisAppQml Qt5::Bluetooth) ENDIF() TARGET_COMPILE_DEFINITIONS(AusweisAppQml PRIVATE QT_STATICPLUGIN) -IF(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG") - STRING(REPLACE "\\" "/" RES_DIR ${RESOURCES_DIR}) - ADD_STRING_DEFINITION(${RES_DIR} "RES_DIR" "UIPlugInQml.cpp") +STRING(REPLACE "\\" "/" RES_DIR ${RESOURCES_DIR}) +IF(CMAKE_GENERATOR STREQUAL Xcode OR CMAKE_VERSION VERSION_LESS "3.8") + TARGET_COMPILE_DEFINITIONS(AusweisAppQml PRIVATE $<$:RES_DIR="\\"${RES_DIR}\\"">) +ELSE() + SET_PROPERTY(SOURCE "UIPlugInQml.cpp" APPEND PROPERTY COMPILE_FLAGS $<$:-DRES_DIR="\\"${RES_DIR}\\"">) ENDIF() diff --git a/src/qml/CertificateDescriptionModel.cpp b/src/qml/CertificateDescriptionModel.cpp index 2e22c60..1b82b6e 100644 --- a/src/qml/CertificateDescriptionModel.cpp +++ b/src/qml/CertificateDescriptionModel.cpp @@ -1,27 +1,29 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/CertificateDescription.h" #include "AppSettings.h" #include "context/AuthContext.h" -#include "context/SelfAuthenticationContext.h" +#include "context/SelfAuthContext.h" #include "CertificateDescriptionModel.h" +#include "Env.h" +#include "SecureStorage.h" using namespace governikus; -QSharedPointer CertificateDescriptionModel::getCertificateDescription() const +QSharedPointer CertificateDescriptionModel::getCertificateDescription() const { if (mContext && mContext->getDidAuthenticateEac1()) { return mContext->getDidAuthenticateEac1()->getCertificateDescription(); } - const bool useTestUri = AppSettings::getInstance().getGeneralSettings().useSelfauthenticationTestUri(); - const auto& rawCertDescr = AppSettings::getInstance().getSecureStorage().getSelfAuthenticationCertDescr(useTestUri); - QSharedPointer selfAuthCertificateDescription(CertificateDescription::fromHex(rawCertDescr)); + const bool useTestUri = Env::getSingleton()->getGeneralSettings().useSelfAuthTestUri(); + const auto& rawCertDescr = SecureStorage::getInstance().getSelfAuthenticationCertDescr(useTestUri); + QSharedPointer selfAuthCertificateDescription(CertificateDescription::fromHex(rawCertDescr)); Q_ASSERT(selfAuthCertificateDescription); return selfAuthCertificateDescription; @@ -42,7 +44,7 @@ void CertificateDescriptionModel::onDidAuthenticateEac1Changed() } -void CertificateDescriptionModel::initModelData(const QSharedPointer& pCertDescription) +void CertificateDescriptionModel::initModelData(const QSharedPointer& pCertDescription) { const QString& serviceProviderAddress = pCertDescription->getServiceProviderAddress(); const QString& purpose = getPurpose(); @@ -50,8 +52,8 @@ void CertificateDescriptionModel::initModelData(const QSharedPointergetTermsOfUsage(); 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()); + mData += QPair(tr("Service provider"), getSubjectName() + QLatin1Char('\n') + getSubjectUrl()); + mData += QPair(tr("Certificate issuer"), pCertDescription->getIssuerName() + QLatin1Char('\n') + pCertDescription->getIssuerUrl()); if (showDetailedProviderInfo) { mData += QPair(tr("Name, address and mail address of the service provider"), serviceProviderAddress); @@ -77,6 +79,12 @@ CertificateDescriptionModel::CertificateDescriptionModel(QObject* pParent) { resetContext(); connect(&AppSettings::getInstance(), &AppSettings::fireSettingsChanged, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(&AppSettings::getInstance().getGeneralSettings(), &GeneralSettings::fireSettingsChanged, this, [this]() + { + beginResetModel(); + onDidAuthenticateEac1Changed(); + endResetModel(); + }); } diff --git a/src/qml/CertificateDescriptionModel.h b/src/qml/CertificateDescriptionModel.h index 265ece5..1417c94 100644 --- a/src/qml/CertificateDescriptionModel.h +++ b/src/qml/CertificateDescriptionModel.h @@ -1,7 +1,7 @@ /*! * \brief Model implementation for the CV certificate description. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -37,9 +37,9 @@ class CertificateDescriptionModel }; - inline QSharedPointer getCertificateDescription() const; + inline QSharedPointer getCertificateDescription() const; inline QString getValidity() const; - void initModelData(const QSharedPointer& pCertDescription); + void initModelData(const QSharedPointer& pCertDescription); private Q_SLOTS: void onDidAuthenticateEac1Changed(); diff --git a/src/qml/ChangePinModel.cpp b/src/qml/ChangePinModel.cpp index 61a53c9..7537108 100644 --- a/src/qml/ChangePinModel.cpp +++ b/src/qml/ChangePinModel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "ChangePinModel.h" @@ -7,13 +7,12 @@ #include "context/ChangePinContext.h" #include "ReaderManager.h" -#include using namespace governikus; ChangePinModel::ChangePinModel(QObject* pParent) - : QObject(pParent) + : WorkflowModel(pParent) { } @@ -26,25 +25,15 @@ ChangePinModel::~ChangePinModel() void ChangePinModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; + WorkflowModel::resetContext(pContext); + if (mContext) { - connect(mContext.data(), &ChangePinContext::fireCurrentStateChanged, this, &ChangePinModel::fireCurrentStateChanged); - connect(mContext.data(), &ChangePinContext::fireResultChanged, this, &ChangePinModel::fireResultChanged); - connect(mContext.data(), &ChangePinContext::fireSuccessMessageChanged, this, &ChangePinModel::fireResultChanged); + connect(mContext.data(), &ChangePinContext::fireSuccessMessageChanged, this, &WorkflowModel::fireResultChanged); Q_EMIT fireResultChanged(); + Q_EMIT fireNewContextSet(); } - - /* - * Only this state change is emitted when the context is reset, i.e. after the end of the workflow - */ - Q_EMIT fireCurrentStateChanged(getCurrentState()); -} - - -QString ChangePinModel::getCurrentState() const -{ - return mContext ? mContext->getCurrentState() : QString(); } @@ -55,51 +44,5 @@ QString ChangePinModel::getResultString() const return QString(); } - return mContext->getStatus().isNoError() ? mContext->getSuccessMessage() : mContext->getStatus().toErrorDescription(true); -} - - -bool ChangePinModel::isResultOk() const -{ - return mContext && mContext->getStatus().isNoError(); -} - - -void ChangePinModel::startWorkflow() -{ - Q_EMIT fireStartWorkflow(); -} - - -void ChangePinModel::cancelWorkflow() -{ - if (mContext) - { - Q_EMIT mContext->fireCancelWorkflow(); - } - -} - - -void ChangePinModel::setReaderType(const QString& pReaderType) -{ - if (mContext) - { - mContext->setReaderType(Enum::fromString(pReaderType, ReaderManagerPlugInType::UNKNOWN)); - } -} - - -bool ChangePinModel::isBasicReader() -{ - return mContext->getCardConnection()->getReaderInfo().isBasicReader(); -} - - -void ChangePinModel::abortCardSelection() -{ - if (mContext) - { - Q_EMIT mContext->fireAbortCardSelection(); - } + return isError() ? WorkflowModel::getResultString() : mContext->getSuccessMessage(); } diff --git a/src/qml/ChangePinModel.h b/src/qml/ChangePinModel.h index e0a2b23..fd4c920 100644 --- a/src/qml/ChangePinModel.h +++ b/src/qml/ChangePinModel.h @@ -1,50 +1,40 @@ /*! * \brief Model implementation for the PIN action. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "WorkflowModel.h" + #include #include #include + namespace governikus { class ChangePinContext; class ChangePinModel - : public QObject + : public WorkflowModel { Q_OBJECT - Q_PROPERTY(QString currentState READ getCurrentState NOTIFY fireCurrentStateChanged) - Q_PROPERTY(QString resultString READ getResultString NOTIFY fireResultChanged) - Q_PROPERTY(bool changedPinSuccessfully READ isResultOk NOTIFY fireResultChanged) QSharedPointer mContext; public: ChangePinModel(QObject* pParent = nullptr); - virtual ~ChangePinModel(); + virtual ~ChangePinModel() override; void resetContext(const QSharedPointer& pContext = QSharedPointer()); - QString getCurrentState() const; - QString getResultString() const; - bool isResultOk() const; - - Q_INVOKABLE void startWorkflow(); - Q_INVOKABLE void cancelWorkflow(); - Q_INVOKABLE void setReaderType(const QString& pReaderType); - Q_INVOKABLE bool isBasicReader(); - Q_INVOKABLE void abortCardSelection(); + virtual QString getResultString() const override; Q_SIGNALS: - void fireStartWorkflow(); - void fireCurrentStateChanged(const QString& pState); - void fireResultChanged(); + void fireNewContextSet(); }; diff --git a/src/qml/ChatModel.cpp b/src/qml/ChatModel.cpp index 4a755a3..cc2f02b 100644 --- a/src/qml/ChatModel.cpp +++ b/src/qml/ChatModel.cpp @@ -1,14 +1,16 @@ /*! * \brief Model implementation for the chat. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ +#include "ChatModel.h" + #include "asn1/AccessRoleAndRight.h" #include "asn1/CVCertificate.h" #include "AppSettings.h" -#include "context/SelfAuthenticationContext.h" -#include "ChatModel.h" +#include "context/SelfAuthContext.h" + using namespace governikus; @@ -26,6 +28,12 @@ ChatModel::ChatModel(QObject* pParent) initFilterModel(mFilterOptionalModel, QStringLiteral("true")); initFilterModel(mFilterRequiredModel, QStringLiteral("false")); + + connect(&AppSettings::getInstance().getGeneralSettings(), &GeneralSettings::fireSettingsChanged, this, [this]() + { + beginResetModel(); + endResetModel(); + }); } @@ -41,7 +49,7 @@ void ChatModel::resetContext(const QSharedPointer& pContext) { mAuthContext = pContext; - if (pContext.objectCast()) + if (pContext.objectCast()) { /* nothing to do, access rights are static */ } diff --git a/src/qml/ChatModel.h b/src/qml/ChatModel.h index bb80647..69ee2d2 100644 --- a/src/qml/ChatModel.h +++ b/src/qml/ChatModel.h @@ -1,7 +1,7 @@ /*! * \brief Model implementation for the chat. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/qml/ConnectivityManager.cpp b/src/qml/ConnectivityManager.cpp index 69756de..3b89529 100644 --- a/src/qml/ConnectivityManager.cpp +++ b/src/qml/ConnectivityManager.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ConnectivityManager.h" diff --git a/src/qml/ConnectivityManager.h b/src/qml/ConnectivityManager.h index 44ed45a..c249db3 100644 --- a/src/qml/ConnectivityManager.h +++ b/src/qml/ConnectivityManager.h @@ -1,7 +1,7 @@ /*! * \brief Utility class providing information about network connectivity status. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -30,7 +30,7 @@ class ConnectivityManager public: ConnectivityManager(QObject* pParent = nullptr); - virtual ~ConnectivityManager(); + virtual ~ConnectivityManager() override; bool isNetworkInterfaceActive() const; void startWatching(); diff --git a/src/qml/DpiCalculator.h b/src/qml/DpiCalculator.h index 87dd7e4..e9fad39 100644 --- a/src/qml/DpiCalculator.h +++ b/src/qml/DpiCalculator.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/qml/DpiCalculator_generic.cpp b/src/qml/DpiCalculator_generic.cpp index df24eb6..36505a4 100644 --- a/src/qml/DpiCalculator_generic.cpp +++ b/src/qml/DpiCalculator_generic.cpp @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + #include "DpiCalculator.h" #include @@ -32,9 +36,18 @@ qreal DpiCalculator::getDpi() auto app = static_cast(QCoreApplication::instance()); auto screen = app->primaryScreen(); dpi = screen->logicalDotsPerInch(); - #endif qCInfo(qml) << "Determined dpi" << dpi; + +#ifndef Q_NO_DEBUG + const char* overrideDpi = "OVERRIDE_DPI"; + if (!qEnvironmentVariableIsEmpty(overrideDpi)) + { + dpi = qEnvironmentVariableIntValue(overrideDpi); + qCDebug(qml) << "Override DPI:" << dpi; + } +#endif + return dpi; } diff --git a/src/qml/DpiCalculator_ios.mm b/src/qml/DpiCalculator_ios.mm index 10a4d0f..f59da66 100644 --- a/src/qml/DpiCalculator_ios.mm +++ b/src/qml/DpiCalculator_ios.mm @@ -16,7 +16,7 @@ using namespace governikus; // screen height is orientation dependent #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) -#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT)) +#define SCREEN_MAX_LENGTH (qMax(SCREEN_WIDTH, SCREEN_HEIGHT)) #define IS_IPHONE_4 (IS_IPHONE && SCREEN_MAX_LENGTH == 480.0 && IS_RETINA) #define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0) diff --git a/src/qml/HistoryModel.cpp b/src/qml/HistoryModel.cpp index 9378ac3..819ba0e 100644 --- a/src/qml/HistoryModel.cpp +++ b/src/qml/HistoryModel.cpp @@ -1,10 +1,13 @@ /*! * \brief Model implementation for the history entries. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "HistoryModel.h" + +#include "Env.h" +#include "ProviderConfiguration.h" #include "ProviderModel.h" #include @@ -15,7 +18,7 @@ using namespace governikus; namespace { -bool matchProviderWithSubjectUrl(const Provider& pProvider, const QString& pSubjectUrl) +bool matchProviderWithSubjectUrl(const ProviderConfigurationInfo& pProvider, const QString& pSubjectUrl) { const QString subjectUrlHost = QUrl(pSubjectUrl).host(); @@ -65,15 +68,14 @@ bool ProviderNameFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex return false; } - auto entry = mHistorySettings->getHistoryEntries()[pSourceRow]; + auto entry = mHistorySettings->getHistoryInfos()[pSourceRow]; return matchProviderWithSubjectUrl(mProvider, entry.getSubjectUrl()); } -ProviderNameFilterModel::ProviderNameFilterModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings) +ProviderNameFilterModel::ProviderNameFilterModel(HistorySettings* pHistorySettings) : mHistorySettings(pHistorySettings) - , mProviderSettings(pProviderSettings) { } @@ -87,7 +89,8 @@ void ProviderNameFilterModel::setProviderAddress(const QString& pProviderAddress { if (mProvider.getAddress() != pProviderAddress) { - for (const auto& provider : mProviderSettings->getProviders()) + const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); + for (const auto& provider : providers) { if (provider.getAddress() == pProviderAddress) { @@ -105,20 +108,20 @@ void ProviderNameFilterModel::setProviderAddress(const QString& pProviderAddress } -HistoryModel::HistoryModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings, QObject* pParent) +HistoryModel::HistoryModel(HistorySettings* pHistorySettings, QObject* pParent) : QAbstractListModel(pParent) , mHistorySettings(pHistorySettings) - , mProviderSettings(pProviderSettings) , mFilterModel() - , mNameFilterModel(pHistorySettings, pProviderSettings) + , mNameFilterModel(pHistorySettings) { + updateConnections(); mFilterModel.setSourceModel(this); mFilterModel.setFilterCaseSensitivity(Qt::CaseInsensitive); mNameFilterModel.setSourceModel(this); mHistoryModelSearchFilter.setSourceModel(this); - connect(mHistorySettings, &HistorySettings::fireHistoryEntriesChanged, this, &HistoryModel::onHistoryEntriesChanged); + connect(mHistorySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); connect(mHistorySettings, &HistorySettings::fireEnabledChanged, this, &HistoryModel::fireEnabledChanged); - connect(mProviderSettings, &ProviderSettings::fireProvidersChanged, this, &HistoryModel::onProvidersChanged); + connect(Env::getSingleton(), &ProviderConfiguration::fireUpdated, this, &HistoryModel::onProvidersChanged); } @@ -127,9 +130,35 @@ HistoryModel::~HistoryModel() } +void HistoryModel::updateConnections() +{ + for (const auto& connection : qAsConst(mConnections)) + { + disconnect(connection); + } + mConnections.clear(); + + const auto& historyEntries = mHistorySettings->getHistoryInfos(); + mConnections.reserve(historyEntries.size() * 2); + for (int i = 0; i < historyEntries.size(); i++) + { + const auto& provider = determineProviderFor(historyEntries.at(i)); + const QModelIndex& modelIndex = createIndex(i, 0); + + mConnections += connect(provider.getIcon().data(), &UpdatableFile::fireUpdated, [ = ] { + Q_EMIT dataChanged(modelIndex, modelIndex, {PROVIDER_ICON}); + }); + mConnections += connect(provider.getImage().data(), &UpdatableFile::fireUpdated, [ = ] { + Q_EMIT dataChanged(modelIndex, modelIndex, {PROVIDER_IMAGE}); + }); + } +} + + void HistoryModel::onHistoryEntriesChanged() { beginResetModel(); + updateConnections(); endResetModel(); } @@ -157,7 +186,7 @@ void HistoryModel::onProvidersChanged() int HistoryModel::rowCount(const QModelIndex&) const { - return mHistorySettings->getHistoryEntries().size(); + return mHistorySettings->getHistoryInfos().size(); } @@ -165,7 +194,7 @@ QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const { if (pIndex.isValid() && pIndex.row() < rowCount()) { - auto entry = mHistorySettings->getHistoryEntries()[pIndex.row()]; + auto entry = mHistorySettings->getHistoryInfos()[pIndex.row()]; if (pRole == Qt::DisplayRole || pRole == SUBJECT) { return entry.getSubjectName(); @@ -239,7 +268,7 @@ QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const if (pRole == PROVIDER_PHONE_COST) { const auto& provider = determineProviderFor(entry); - const auto& cost = mProviderSettings->getCallCost(provider); + const auto& cost = Env::getSingleton()->getCallCost(provider); return ProviderModel::createCostString(cost); } if (pRole == PROVIDER_EMAIL) @@ -255,24 +284,25 @@ QVariant HistoryModel::data(const QModelIndex& pIndex, int pRole) const if (pRole == PROVIDER_ICON) { auto provider = determineProviderFor(entry); - return provider.getIconUrl(); + return provider.getIcon()->lookupUrl(); } if (pRole == PROVIDER_IMAGE) { auto provider = determineProviderFor(entry); - return provider.getImageUrl(); + return provider.getImage()->lookupUrl(); } } return QVariant(); } -Provider HistoryModel::determineProviderFor(const HistoryEntry& pHistoryEntry) const +ProviderConfigurationInfo HistoryModel::determineProviderFor(const HistoryInfo& pHistoryInfo) const { - QVector matchingProviders; - for (const auto& provider : mProviderSettings->getProviders()) + QVector matchingProviders; + const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); + for (const auto& provider : providers) { - if (matchProviderWithSubjectUrl(provider, pHistoryEntry.getSubjectUrl())) + if (matchProviderWithSubjectUrl(provider, pHistoryInfo.getSubjectUrl())) { matchingProviders += provider; } @@ -281,7 +311,7 @@ Provider HistoryModel::determineProviderFor(const HistoryEntry& pHistoryEntry) c { return matchingProviders.at(0); } - return Provider(); + return ProviderConfigurationInfo(); } @@ -332,13 +362,13 @@ bool HistoryModel::removeRows(int pRow, int pCount, const QModelIndex& pParent) { beginRemoveRows(pParent, pRow, pRow + pCount - 1); - auto entries = mHistorySettings->getHistoryEntries(); + auto entries = mHistorySettings->getHistoryInfos(); entries.remove(pRow, pCount); // disconnect the signal, otherwise this model gets reset - disconnect(mHistorySettings, &HistorySettings::fireHistoryEntriesChanged, this, &HistoryModel::onHistoryEntriesChanged); - mHistorySettings->setHistoryEntries(entries); - connect(mHistorySettings, &HistorySettings::fireHistoryEntriesChanged, this, &HistoryModel::onHistoryEntriesChanged); + disconnect(mHistorySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); + mHistorySettings->setHistoryInfos(entries); + connect(mHistorySettings, &HistorySettings::fireHistoryInfosChanged, this, &HistoryModel::onHistoryEntriesChanged); mHistorySettings->save(); diff --git a/src/qml/HistoryModel.h b/src/qml/HistoryModel.h index 58eb0d1..7e08c75 100644 --- a/src/qml/HistoryModel.h +++ b/src/qml/HistoryModel.h @@ -1,14 +1,14 @@ /*! * \brief Model implementation for the history entries. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "HistoryModelSearchFilter.h" #include "HistorySettings.h" -#include "ProviderSettings.h" +#include "ProviderConfigurationInfo.h" #include #include @@ -27,7 +27,7 @@ class HistoryProxyModel HistoryProxyModel(); - virtual ~HistoryProxyModel(); + virtual ~HistoryProxyModel() override; }; @@ -39,17 +39,15 @@ class ProviderNameFilterModel private: QPointer mHistorySettings; - QPointer mProviderSettings; - - Provider mProvider; + ProviderConfigurationInfo mProvider; protected: bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; public: - ProviderNameFilterModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings); + ProviderNameFilterModel(HistorySettings* pHistorySettings); - virtual ~ProviderNameFilterModel(); + virtual ~ProviderNameFilterModel() override; Q_INVOKABLE void setProviderAddress(const QString& pProviderAddress); @@ -66,27 +64,29 @@ class HistoryModel Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY fireEnabledChanged) QPointer mHistorySettings; - QPointer mProviderSettings; HistoryProxyModel mFilterModel; ProviderNameFilterModel mNameFilterModel; HistoryModelSearchFilter mHistoryModelSearchFilter; private: - Provider determineProviderFor(const HistoryEntry& pHistoryEntry) const; + QVector mConnections; + + ProviderConfigurationInfo determineProviderFor(const HistoryInfo& pHistoryInfo) const; bool isEnabled() const; void setEnabled(bool pEnabled); + void updateConnections(); private Q_SLOTS: void onHistoryEntriesChanged(); void onProvidersChanged(); Q_SIGNALS: - void fireEnabledChanged(); + void fireEnabledChanged(bool pValue); public: - HistoryModel(HistorySettings* pHistorySettings, ProviderSettings* pProviderSettings, QObject* pParent = nullptr); - virtual ~HistoryModel(); + HistoryModel(HistorySettings* pHistorySettings, QObject* pParent = nullptr); + virtual ~HistoryModel() override; enum HistoryRoles { diff --git a/src/qml/HistoryModelSearchFilter.cpp b/src/qml/HistoryModelSearchFilter.cpp index f0915a2..2df4085 100644 --- a/src/qml/HistoryModelSearchFilter.cpp +++ b/src/qml/HistoryModelSearchFilter.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HistoryModelSearchFilter.h" @@ -25,7 +25,7 @@ bool HistoryModelSearchFilter::filterAcceptsRow(int pSourceRow, const QModelInde } const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0); - if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("MM/dd/yyyy")).contains(mFilterString, Qt::CaseInsensitive) + if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("dd.MM.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)) diff --git a/src/qml/HistoryModelSearchFilter.h b/src/qml/HistoryModelSearchFilter.h index 5e7807a..8b6ef8c 100644 --- a/src/qml/HistoryModelSearchFilter.h +++ b/src/qml/HistoryModelSearchFilter.h @@ -1,7 +1,7 @@ /*! * \brief A filter to search the history model * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/qml/NumberModel.cpp b/src/qml/NumberModel.cpp index 9955ed1..5a19974 100644 --- a/src/qml/NumberModel.cpp +++ b/src/qml/NumberModel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "NumberModel.h" @@ -19,6 +19,7 @@ NumberModel::NumberModel(QObject* pParent) connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &NumberModel::onReaderInfoChanged); connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &NumberModel::onReaderInfoChanged); connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &NumberModel::onReaderInfoChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &NumberModel::onReaderInfoChanged); } @@ -146,12 +147,12 @@ QString NumberModel::getInputError() const int oldRetryCounter = mContext->getOldRetryCounter(); if (oldRetryCounter > 2) { - return tr("You have entered a wrong PIN, please try again."); + return tr("The given PIN is not correct. You have 2 tries to enter the correct PIN."); } if (oldRetryCounter == 2) { return tr("You have entered the wrong PIN twice. " - "For a third attempt, you have to enter your six-digit card access number first. " + "Prior to 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) @@ -203,7 +204,7 @@ bool NumberModel::isExtendedLengthApdusUnsupported() const if (mContext && !mContext->getReaderName().isEmpty()) { ReaderInfo readerInfo = ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()); - return readerInfo.getExtendedLengthApduSupportCode() == ExtendedLengthApduSupportCode::NOT_SUPPORTED; + return !readerInfo.sufficientApduLength(); } return false; } @@ -223,7 +224,7 @@ bool NumberModel::isCardConnected() const { if (mContext && !mContext->getReaderName().isEmpty()) { - return ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).getCardType() != CardType::NONE; + return ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).hasCard(); } return false; } diff --git a/src/qml/NumberModel.h b/src/qml/NumberModel.h index 502c040..675326c 100644 --- a/src/qml/NumberModel.h +++ b/src/qml/NumberModel.h @@ -2,7 +2,7 @@ * \brief Model for accessing PIN, CAN, PUK, according to the * currently active workflow. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/qml/ProviderCategoryFilterModel.cpp b/src/qml/ProviderCategoryFilterModel.cpp index 4e38552..9750571 100644 --- a/src/qml/ProviderCategoryFilterModel.cpp +++ b/src/qml/ProviderCategoryFilterModel.cpp @@ -1,10 +1,22 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + #include "ProviderCategoryFilterModel.h" using namespace governikus; +namespace +{ +const QStringList& getCategories() +{ + static QStringList cats({QStringLiteral("citizen"), QStringLiteral("insurance"), QStringLiteral("finance"), QStringLiteral("other")}); + return cats; +} -static const QStringList CATEGORIES({"citizen", "insurance", "finance", "other"}); + +} QString ProviderCategoryFilterModel::getSearchString() const @@ -34,7 +46,7 @@ QStringList ProviderCategoryFilterModel::getSelectedCategories() const int ProviderCategoryFilterModel::getAdditionalResultCount() const { int results = 0; - for (const QString& p : CATEGORIES) + for (const QString& p : getCategories()) { results += matchesForExcludedCategory(p); } @@ -91,12 +103,12 @@ bool ProviderCategoryFilterModel::filterAcceptsRow(int pSourceRow, const QModelI } -ProviderCategoryFilterModel::ProviderCategoryFilterModel(ProviderSettings* pSettings) : - mProviderModel(pSettings) +ProviderCategoryFilterModel::ProviderCategoryFilterModel() : + mProviderModel() { - setSourceModel(&mProviderModel); + QSortFilterProxyModel::setSourceModel(&mProviderModel); - sort(0); + QSortFilterProxyModel::sort(0); sortByCategoryFirst(false); setSortCaseSensitivity(Qt::CaseInsensitive); } @@ -149,7 +161,7 @@ void ProviderCategoryFilterModel::updateCategorySelection(const QString& pCatego void ProviderCategoryFilterModel::addAdditionalResultCategories() { bool needUpdate = false; - for (const QString& p : CATEGORIES) + for (const QString& p : getCategories()) { if (matchesForExcludedCategory(p) > 0) { diff --git a/src/qml/ProviderCategoryFilterModel.h b/src/qml/ProviderCategoryFilterModel.h index 19255de..7b12d4a 100644 --- a/src/qml/ProviderCategoryFilterModel.h +++ b/src/qml/ProviderCategoryFilterModel.h @@ -1,13 +1,12 @@ /*! * \brief Model implementation for the providers. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "ProviderModel.h" -#include "ProviderSettings.h" #include #include @@ -42,8 +41,8 @@ class ProviderCategoryFilterModel bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; public: - ProviderCategoryFilterModel(ProviderSettings* pSettings); - virtual ~ProviderCategoryFilterModel(); + ProviderCategoryFilterModel(); + virtual ~ProviderCategoryFilterModel() override; Q_INVOKABLE void sortByCategoryFirst(bool pEnabled); Q_INVOKABLE void setCategorySelection(const QString& pCategory); diff --git a/src/qml/ProviderModel.cpp b/src/qml/ProviderModel.cpp index f9a8d4b..192357a 100644 --- a/src/qml/ProviderModel.cpp +++ b/src/qml/ProviderModel.cpp @@ -1,12 +1,16 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + #include "ProviderModel.h" +#include "Env.h" +#include "ProviderConfiguration.h" + using namespace governikus; -static const QStringList CATEGORIES({"citizen", "insurance", "finance", "other"}); - - QString ProviderModel::createCostString(double pCostsPerMinute, double pCostsPerCall) { if (pCostsPerMinute > 0.0) @@ -27,18 +31,44 @@ QString ProviderModel::createAmountString(double pCents) } +void ProviderModel::updateConnections() +{ + for (const auto& connection : qAsConst(mConnections)) + { + disconnect(connection); + } + mConnections.clear(); + + const auto& providerConfigurationInfos = Env::getSingleton()->getProviderConfigurationInfos(); + mConnections.reserve(providerConfigurationInfos.size() * 2); + for (int i = 0; i < providerConfigurationInfos.size(); i++) + { + const auto& provider = providerConfigurationInfos.at(i); + const QModelIndex& modelIndex = createIndex(i, 0); + + mConnections += connect(provider.getIcon().data(), &UpdatableFile::fireUpdated, [ = ] { + Q_EMIT dataChanged(modelIndex, modelIndex, {ProviderRoles::ICON}); + }); + mConnections += connect(provider.getImage().data(), &UpdatableFile::fireUpdated, [ = ] { + Q_EMIT dataChanged(modelIndex, modelIndex, {ProviderRoles::IMAGE}); + }); + } +} + + void ProviderModel::onProvidersChanged() { beginResetModel(); + updateConnections(); endResetModel(); } -ProviderModel::ProviderModel(ProviderSettings* pSettings, QObject* pParent) +ProviderModel::ProviderModel(QObject* pParent) : QAbstractListModel(pParent) - , mSettings(pSettings) { - connect(mSettings, &ProviderSettings::fireSettingsChanged, this, &ProviderModel::onProvidersChanged); + updateConnections(); + connect(Env::getSingleton(), &ProviderConfiguration::fireUpdated, this, &ProviderModel::onProvidersChanged); } @@ -49,15 +79,17 @@ ProviderModel::~ProviderModel() int ProviderModel::rowCount(const QModelIndex&) const { - return mSettings->getProviders().size(); + return Env::getSingleton()->getProviderConfigurationInfos().size(); } QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const { + const auto& providerConfiguration = Env::getSingleton(); + if (pIndex.isValid()) { - auto provider = mSettings->getProviders().at(pIndex.row()); + auto provider = providerConfiguration->getProviderConfigurationInfos().at(pIndex.row()); if (pRole == Qt::DisplayRole) { @@ -107,7 +139,7 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const } if (pRole == PHONE_COST) { - const auto& cost = mSettings->getCallCost(provider); + const auto& cost = providerConfiguration->getCallCost(provider); return createCostString(cost); } if (pRole == EMAIL) @@ -120,11 +152,11 @@ QVariant ProviderModel::data(const QModelIndex& pIndex, int pRole) const } if (pRole == ICON) { - return provider.getIconUrl(); + return provider.getIcon()->lookupUrl(); } if (pRole == IMAGE) { - return provider.getImageUrl(); + return provider.getImage()->lookupUrl(); } if (pRole == SORT_ROLE) { diff --git a/src/qml/ProviderModel.h b/src/qml/ProviderModel.h index f99f84a..a30d89f 100644 --- a/src/qml/ProviderModel.h +++ b/src/qml/ProviderModel.h @@ -1,15 +1,15 @@ /*! * \brief Model implementation for the providers. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once -#include "ProviderSettings.h" +#include "CallCost.h" #include -#include +#include class test_ProviderModel; @@ -25,11 +25,14 @@ class ProviderModel Q_OBJECT - QPointer mSettings; - static QString createCostString(double pCostsPerMinute, double pCostsPerCall); static QString createAmountString(double pCents); + private: + QVector mConnections; + + void updateConnections(); + private Q_SLOTS: void onProvidersChanged(); @@ -54,8 +57,8 @@ class ProviderModel SORT_ROLE }; - ProviderModel(ProviderSettings* pSettings, QObject* pParent = nullptr); - virtual ~ProviderModel(); + ProviderModel(QObject* pParent = nullptr); + virtual ~ProviderModel() override; int rowCount(const QModelIndex&) const override; QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; diff --git a/src/qml/QmlExtension.h b/src/qml/QmlExtension.h index 61129f9..143aef8 100644 --- a/src/qml/QmlExtension.h +++ b/src/qml/QmlExtension.h @@ -1,7 +1,7 @@ /*! * \brief Utility for sharing text. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -23,6 +23,7 @@ class QmlExtension 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); + Q_INVOKABLE void keepScreenOn(bool pActive); }; } diff --git a/src/qml/QmlExtension_android.cpp b/src/qml/QmlExtension_android.cpp index 9680bba..1dcf4ba 100644 --- a/src/qml/QmlExtension_android.cpp +++ b/src/qml/QmlExtension_android.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "QmlExtension.h" @@ -25,11 +25,9 @@ void QmlExtension::showSettings(const QString& pAction) { QAndroidJniEnvironment env; - QAndroidJniObject jAction = QAndroidJniObject::fromString(pAction); + const 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"); + const jint flag = QAndroidJniObject::getStaticField("android/content/Intent", "FLAG_ACTIVITY_NEW_TASK"); intent.callObjectMethod("setFlags", "(I)V", flag); if (intent.isValid()) @@ -50,15 +48,15 @@ void QmlExtension::showSettings(const QString& pAction) void QmlExtension::shareText(const QString& pText, const QString& pChooserTitle) { QAndroidJniEnvironment env; - QAndroidJniObject javaActivity(QtAndroid::androidActivity()); - if (javaActivity == nullptr) + const QAndroidJniObject javaActivity(QtAndroid::androidActivity()); + if (!javaActivity.isValid()) { - qCCritical(qml) << "Cannot determine android activity"; + qCCritical(qml) << "Cannot determine android activity."; return; } - QAndroidJniObject jText = QAndroidJniObject::fromString(pText); - QAndroidJniObject jTitle = QAndroidJniObject::fromString(pChooserTitle); + const QAndroidJniObject& jText = QAndroidJniObject::fromString(pText); + const QAndroidJniObject& jTitle = QAndroidJniObject::fromString(pChooserTitle); QAndroidJniObject::callStaticMethod("com/governikus/ausweisapp2/ShareUtil", "shareText", "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V", @@ -78,20 +76,30 @@ void QmlExtension::shareText(const QString& pText, const QString& pChooserTitle) 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( + // Wait for toast activation synchronously so that the app can not be deactivated + // in the meantime and all used Java objects are still alive when accessed. + QtAndroid::runOnAndroidThreadSync([pMessage](){ + QAndroidJniEnvironment env; + + const QAndroidJniObject& jMessage = QAndroidJniObject::fromString(pMessage); + const QAndroidJniObject& toast = QAndroidJniObject::callStaticObjectMethod( "android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", - androidAppContext.object(), - javaString.object(), + QtAndroid::androidActivity().object(), + jMessage.object(), jint(1)); toast.callMethod("show"); + + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Suppressing an unexpected exception."; + env->ExceptionDescribe(); + env->ExceptionClear(); + // The toast was probably not displayed (e.g. DeadObjectException). We halt on error + // since it is used to display information to the user as required by the TR. + Q_ASSERT(false); + } }); } @@ -103,7 +111,7 @@ void QmlExtension::showFeedback(const QString& pMessage) */ QString getPublicLogFileName(QAndroidJniEnvironment& env, const QAndroidJniObject& javaActivity) { - const auto jEmptyString = QAndroidJniObject::fromString(QLatin1String("")); + const auto& jEmptyString = QAndroidJniObject::fromString(QLatin1String("")); const auto& jExternalFilesDir = javaActivity.callObjectMethod("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;", jEmptyString.object()); if (env->ExceptionCheck()) { @@ -112,7 +120,7 @@ QString getPublicLogFileName(QAndroidJniEnvironment& env, const QAndroidJniObjec env->ExceptionClear(); return QString(); } - if (jExternalFilesDir == nullptr) + if (!jExternalFilesDir.isValid()) { qCCritical(qml) << "Cannot determine externalFilesDir"; return QString(); @@ -126,13 +134,13 @@ QString getPublicLogFileName(QAndroidJniEnvironment& env, const QAndroidJniObjec env->ExceptionClear(); return QString(); } - if (jExternalFilesDirPath == nullptr) + if (!jExternalFilesDirPath.isValid()) { qCCritical(qml) << "Cannot determine externalFilesDir absolute path"; return QString(); } - const auto nowAsISO = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd'T'HH:mm:ss-t")); + 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); } @@ -140,8 +148,8 @@ QString getPublicLogFileName(QAndroidJniEnvironment& env, const QAndroidJniObjec void QmlExtension::mailLog(const QString& pEmail, const QString& pSubject, const QString& pMsg) { QAndroidJniEnvironment env; - QAndroidJniObject javaActivity(QtAndroid::androidActivity()); - if (javaActivity == nullptr) + const QAndroidJniObject javaActivity(QtAndroid::androidActivity()); + if (!javaActivity.isValid()) { qCCritical(qml) << "Cannot determine android activity"; return; @@ -181,9 +189,24 @@ void QmlExtension::mailLog(const QString& pEmail, const QString& pSubject, const bool QmlExtension::exportHistory(const QString&) const { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; return false; } +void QmlExtension::keepScreenOn(bool pActive) +{ + QtAndroid::runOnAndroidThread([pActive](){ + QtAndroid::androidActivity().callMethod("keepScreenOn", "(Z)V", pActive); + QAndroidJniEnvironment env; + if (env->ExceptionCheck()) + { + qCCritical(qml) << "Exception calling java native function."; + env->ExceptionDescribe(); + env->ExceptionClear(); + } + }); +} + + #include "moc_QmlExtension.cpp" diff --git a/src/qml/QmlExtension_generic.cpp b/src/qml/QmlExtension_generic.cpp index c859138..149bd01 100644 --- a/src/qml/QmlExtension_generic.cpp +++ b/src/qml/QmlExtension_generic.cpp @@ -1,11 +1,11 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "QmlExtension.h" #ifndef Q_OS_WINRT -#include "PdfCreator.h" +#include "PdfExporter.h" #endif #include @@ -18,25 +18,25 @@ using namespace governikus; void QmlExtension::showSettings(const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } void QmlExtension::shareText(const QString&, const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } void QmlExtension::showFeedback(const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } void QmlExtension::mailLog(const QString&, const QString&, const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } @@ -46,10 +46,17 @@ bool QmlExtension::exportHistory(const QString& pPdfUrl) const return false; #else - return PdfExport::exportHistory(QUrl(pPdfUrl).toLocalFile()); + PdfExporter exporter(QUrl(pPdfUrl).toLocalFile()); + return exporter.exportHistory(); #endif } +void QmlExtension::keepScreenOn(bool) +{ + qCWarning(qml) << "NOT IMPLEMENTED"; +} + + #include "moc_QmlExtension.cpp" diff --git a/src/qml/QmlExtension_ios.mm b/src/qml/QmlExtension_ios.mm index 2426d55..f34833d 100644 --- a/src/qml/QmlExtension_ios.mm +++ b/src/qml/QmlExtension_ios.mm @@ -14,7 +14,7 @@ using namespace governikus; void QmlExtension::showSettings(const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } @@ -35,21 +35,38 @@ void QmlExtension::shareText(const QString& pText, const QString& pChooserTitle) void QmlExtension::mailLog(const QString&, const QString&, const QString&) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; } -void QmlExtension::showFeedback(const QString&) +void QmlExtension::showFeedback(const QString& pMessage) { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + NSString* msg = pMessage.toNSString(); + + UIAlertController* alert = [UIAlertController + alertControllerWithTitle:msg + message:@"" + preferredStyle:UIAlertControllerStyleAlert]; + + UIViewController* rootController = [[UIApplication sharedApplication].keyWindow rootViewController]; + [rootController presentViewController:alert animated:YES completion:nil]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, static_cast(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [alert dismissViewControllerAnimated:YES completion:nil]; + }); } bool QmlExtension::exportHistory(const QString&) const { - qCWarning(qml) << "NOT IMPLEMENTED YET"; + qCWarning(qml) << "NOT IMPLEMENTED"; return false; } +void QmlExtension::keepScreenOn(bool) +{ + qCWarning(qml) << "NOT IMPLEMENTED"; +} + + #include "moc_QmlExtension.cpp" diff --git a/src/qml/RemoteServiceModel.cpp b/src/qml/RemoteServiceModel.cpp new file mode 100644 index 0000000..18f5ac3 --- /dev/null +++ b/src/qml/RemoteServiceModel.cpp @@ -0,0 +1,311 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteServiceModel.h" + +#include "AppSettings.h" +#include "Env.h" +#include "EstablishPACEChannelParser.h" +#include "RemoteClientImpl.h" +#include "RemoteServiceSettings.h" + +using namespace governikus; + +RemoteServiceModel::RemoteServiceModel() + : mContext() + , mWifiInfo() + , mRunnable(false) + , mCanEnableNfc(false) + , mErrorMessage() + , mPsk() + , mAvailableRemoteDevices(this, false, true) + , mKnownDevices(this, true, false) +{ + connect(&ReaderManager::getInstance(), &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &RemoteServiceModel::onEnvironmentChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &RemoteServiceModel::onEnvironmentChanged); + connect(&mWifiInfo, &WifiInfo::fireWifiEnabledChanged, this, &RemoteServiceModel::onEnvironmentChanged); + + const QSharedPointer& remoteClient = ReaderManager::getInstance().getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireDetectionChanged, this, &RemoteServiceModel::fireDetectionChanged); + + onEnvironmentChanged(); +} + + +void RemoteServiceModel::onEnvironmentChanged() +{ + bool nfcPluginAvailable = false; + bool nfcPluginEnabled = false; + const auto& allPlugins = ReaderManager::getInstance().getPlugInInfos(); + for (const auto& pluginInfo : allPlugins) + { + if (pluginInfo.getPlugInType() != ReaderManagerPlugInType::NFC) + { + // At this time no bluetooth basic reader available so we can skip + continue; + } + + nfcPluginAvailable |= pluginInfo.isAvailable(); + nfcPluginEnabled |= pluginInfo.isEnabled(); + } + + bool readerAvailable = false; + const auto& allReader = ReaderManager::getInstance().getReaderInfos(); + for (const auto& readerInfo : allReader) + { + readerAvailable |= readerInfo.isBasicReader(); + } + + const bool wifiEnabled = mWifiInfo.isWifiEnabled(); + + const bool runnable = readerAvailable && wifiEnabled; + const bool canEnableNfc = nfcPluginAvailable && !nfcPluginEnabled; + const QString errorMessage = getErrorMessage(nfcPluginAvailable, nfcPluginEnabled, wifiEnabled); + if (mRunnable != runnable || mCanEnableNfc != canEnableNfc || mErrorMessage != errorMessage) + { + mRunnable = runnable; + mCanEnableNfc = canEnableNfc; + mErrorMessage = errorMessage; + + Q_EMIT fireEnvironmentChanged(); + } + + if (!runnable && isRunning()) + { + setRunning(false); + } +} + + +bool RemoteServiceModel::isRunning() const +{ + return mContext ? mContext->isRunning() : false; +} + + +QString RemoteServiceModel::getCurrentState() const +{ + return mContext ? mContext->getCurrentState() : QString(); +} + + +void RemoteServiceModel::setRunning(bool pState) +{ + if (isRunning() == pState) + { + return; + } + + if (isRunning() && mContext) + { + Q_EMIT mContext->fireCancelWorkflow(); + } + else + { + Q_EMIT fireStartWorkflow(); + } + + Q_EMIT fireIsRunningChanged(); +} + + +QString RemoteServiceModel::getReaderPlugInType() const +{ + if (mContext) + { + return getEnumName(mContext->getReaderPlugInTypes().at(0)); + } + + return QString(); +} + + +void RemoteServiceModel::setReaderPlugInType(const QString& pReaderPlugInType) +{ + if (mContext) + { + mContext->setReaderPlugInTypes({Enum::fromString(pReaderPlugInType, ReaderManagerPlugInType::UNKNOWN)}); + } +} + + +RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices() +{ + return &mAvailableRemoteDevices; +} + + +RemoteDeviceModel* RemoteServiceModel::getKnownDevices() +{ + return &mKnownDevices; +} + + +void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus) +{ + if (pNewStatus) + { + mAvailableRemoteDevices.onWidgetShown(); + mKnownDevices.onWidgetShown(); + } + else + { + mAvailableRemoteDevices.onWidgetHidden(); + mKnownDevices.onWidgetHidden(); + } +} + + +bool RemoteServiceModel::detectRemoteDevices() +{ + const QSharedPointer& remoteClient = ReaderManager::getInstance().getRemoteClient(); + return remoteClient->isDetecting(); +} + + +void RemoteServiceModel::connectToServer(const QString& pDeviceId, const QString& pServerPsk) +{ + if (!pServerPsk.isEmpty()) + { + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireEstablishConnectionDone, this, &RemoteServiceModel::onEstablishConnectionDone); + remoteClient->establishConnection(mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId), pServerPsk); + } +} + + +void RemoteServiceModel::onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus) +{ + Q_UNUSED(pEntry); + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + disconnect(remoteClient.data(), &RemoteClient::fireEstablishConnectionDone, this, &RemoteServiceModel::onEstablishConnectionDone); + if (pStatus.isError()) + { + Q_EMIT firePairingFailed(); + } +} + + +void RemoteServiceModel::resetContext(const QSharedPointer& pContext) +{ + mPsk.clear(); + + mContext = pContext; + if (mContext) + { + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &RemoteServiceModel::fireCurrentStateChanged); + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &RemoteServiceModel::fireIsRunningChanged); + connect(mContext->getRemoteServer().data(), &RemoteServer::firePskChanged, this, [this](const QByteArray& pPsk){ + mPsk = pPsk; + }); + connect(mContext->getRemoteServer().data(), &RemoteServer::firePskChanged, this, &RemoteServiceModel::firePskChanged); + connect(mContext->getRemoteServer().data(), &RemoteServer::fireConnectedChanged, this, &RemoteServiceModel::fireConnectedChanged); + } + + Q_EMIT fireConnectedChanged(isConnected()); +} + + +void RemoteServiceModel::setPairing(bool pEnabled) +{ + if (mContext) + { + mContext->getRemoteServer()->setPairing(pEnabled); + } +} + + +QString RemoteServiceModel::getCurrentFingerprint() const +{ + if (mContext && mContext->getRemoteServer()->isConnected()) + { + return RemoteServiceSettings::generateFingerprint(mContext->getRemoteServer()->getCurrentCertificate()); + } + + return QString(); +} + + +bool RemoteServiceModel::isConnected() const +{ + if (mContext) + { + return mContext->getRemoteServer()->isConnected(); + } + + return false; +} + + +bool RemoteServiceModel::pinPadModeOn() +{ + return Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); +} + + +QString RemoteServiceModel::getPacePasswordId() const +{ + if (mContext.isNull()) + { + return QString(); + } + + const QSharedPointer establishPaceChannelMessage = mContext->getEstablishPaceChannelMessage(); + if (establishPaceChannelMessage.isNull()) + { + return QString(); + } + + const EstablishPACEChannelParser parser = EstablishPACEChannelParser::fromCcid(establishPaceChannelMessage->getInputData()); + switch (parser.getPasswordId()) + { + case PACE_PASSWORD_ID::PACE_CAN: + return QStringLiteral("CAN"); + + case PACE_PASSWORD_ID::PACE_PIN: + return QStringLiteral("PIN"); + + case PACE_PASSWORD_ID::PACE_PUK: + return QStringLiteral("PUK"); + + default: + return QString(); + } +} + + +QString RemoteServiceModel::getErrorMessage(bool pNfcPluginAvailable, bool pNfcPluginEnabled, bool pWifiEnabled) const +{ + if (!pNfcPluginAvailable) + { + return tr("NFC is not available on your device."); + } + if (!pNfcPluginEnabled) + { + return tr("Please enable NFC to use the remote service."); + } + if (!pWifiEnabled) + { + return tr("Please connect your WiFi to use the remote service."); + } + + return QString(); +} + + +void RemoteServiceModel::forgetDevice(const QString& pId) +{ + mKnownDevices.forgetDevice(pId); +} + + +void RemoteServiceModel::cancelPasswordRequest() +{ + if (mContext) + { + Q_EMIT mContext->fireCancelEstablishPaceChannel(); + } +} diff --git a/src/qml/RemoteServiceModel.h b/src/qml/RemoteServiceModel.h new file mode 100644 index 0000000..e0f43ce --- /dev/null +++ b/src/qml/RemoteServiceModel.h @@ -0,0 +1,93 @@ +/*! + * \brief Model implementation for the remote service component + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/RemoteServiceContext.h" +#include "ReaderManager.h" +#include "RemoteDeviceModel.h" +#include "WifiInfo.h" + +#include + +namespace governikus +{ + + +class RemoteServiceModel + : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString currentState READ getCurrentState NOTIFY fireCurrentStateChanged) + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY fireIsRunningChanged) + Q_PROPERTY(bool runnable MEMBER mRunnable NOTIFY fireEnvironmentChanged) + Q_PROPERTY(bool canEnableNfc MEMBER mCanEnableNfc NOTIFY fireEnvironmentChanged) + Q_PROPERTY(QString errorMessage MEMBER mErrorMessage NOTIFY fireEnvironmentChanged) + Q_PROPERTY(QByteArray psk MEMBER mPsk NOTIFY firePskChanged) + Q_PROPERTY(QString currentFingerprint READ getCurrentFingerprint NOTIFY fireConnectedChanged) + Q_PROPERTY(bool connected READ isConnected NOTIFY fireConnectedChanged) + Q_PROPERTY(QString readerPlugInType READ getReaderPlugInType WRITE setReaderPlugInType NOTIFY fireReaderPlugInTypeChanged) + Q_PROPERTY(RemoteDeviceModel * availableRemoteDevices READ getAvailableRemoteDevices CONSTANT) + Q_PROPERTY(RemoteDeviceModel * knownDevices READ getKnownDevices CONSTANT) + Q_PROPERTY(bool detectRemoteDevices READ detectRemoteDevices WRITE setDetectRemoteDevices NOTIFY fireDetectionChanged) + + private: + QSharedPointer mContext; + WifiInfo mWifiInfo; + bool mRunnable; + bool mCanEnableNfc; + QString mErrorMessage; + QByteArray mPsk; + RemoteDeviceModel mAvailableRemoteDevices; + RemoteDeviceModel mKnownDevices; + + void onEnvironmentChanged(); + QString getErrorMessage(bool pNfcPluginAvailable, bool pNfcPluginEnabled, bool pWifiEnabled) const; + + private Q_SLOTS: + void onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus); + + public: + RemoteServiceModel(); + + QString getCurrentState() const; + bool isRunning() const; + void setRunning(bool pState); + + QString getReaderPlugInType() const; + void setReaderPlugInType(const QString& pReaderPlugInType); + + RemoteDeviceModel* getAvailableRemoteDevices(); + RemoteDeviceModel* getKnownDevices(); + void setDetectRemoteDevices(bool pNewStatus); + bool detectRemoteDevices(); + Q_INVOKABLE void connectToServer(const QString& pDeviceId, const QString& pServerPsk); + + void resetContext(const QSharedPointer& pContext = QSharedPointer()); + Q_INVOKABLE void setPairing(bool pEnabled = true); + QString getCurrentFingerprint() const; + bool isConnected() const; + Q_INVOKABLE bool pinPadModeOn(); + Q_INVOKABLE QString getPacePasswordId() const; + Q_INVOKABLE void forgetDevice(const QString& pId); + Q_INVOKABLE void cancelPasswordRequest(); + + Q_SIGNALS: + void fireStartWorkflow(); + void fireCurrentStateChanged(const QString& pState); + void fireIsRunningChanged(); + void fireEnvironmentChanged(); + void firePskChanged(const QByteArray& pPsk); + void fireConnectedChanged(bool pConnected); + void fireReaderPlugInTypeChanged(); + void fireServerPskChanged(); + void fireDetectionChanged(); + void firePairingFailed(); +}; + + +} /* namespace governikus */ diff --git a/src/qml/SelfAuthenticationModel.cpp b/src/qml/SelfAuthenticationModel.cpp index 2211c5b..e71cf1f 100644 --- a/src/qml/SelfAuthenticationModel.cpp +++ b/src/qml/SelfAuthenticationModel.cpp @@ -1,103 +1,35 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "context/SelfAuthenticationContext.h" #include "SelfAuthenticationModel.h" +#include "context/SelfAuthContext.h" +#include "LanguageLoader.h" + using namespace governikus; void SelfAuthenticationModel::onSelfAuthenticationDataChanged() { beginResetModel(); - mData.clear(); + mSelfData.clear(); - if (mContext && mContext->getSelfAuthenticationData()) + if (mContext && mContext->getSelfAuthenticationData().isValid()) { - //fill layout with new data, see 18 Personalausweisgesetz (PAuswG) - - auto selfAuthenticationData = mContext->getSelfAuthenticationData(); - if (!selfAuthenticationData->getValue(SelfAuthData::FamilyNames).isNull()) + const auto& selfdata = mContext->getSelfAuthenticationData().getOrderedSelfData(); + for (const auto& entry : selfdata) { - mData += QPair(tr("Family name"), selfAuthenticationData->getValue(SelfAuthData::FamilyNames)); - } - if (!selfAuthenticationData->getValue(SelfAuthData::BirthName).isNull()) - { - mData += QPair(tr("Birth name"), selfAuthenticationData->getValue(SelfAuthData::BirthName)); - } - if (!selfAuthenticationData->getValue(SelfAuthData::GivenNames).isNull()) - { - mData += QPair(tr("Given name(s)"), selfAuthenticationData->getValue(SelfAuthData::GivenNames)); - } - if (!selfAuthenticationData->getValue(SelfAuthData::AcademicTitle).isNull()) - { - 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("MM/dd/yyyy")); - mData += QPair(tr("Date of birth"), dateString); - } - if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfBirth).isNull()) - { - mData += QPair(tr("Place of birth"), selfAuthenticationData->getValue(SelfAuthData::PlaceOfBirth)); - } - - QString address; - if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo).isNull()) - { - address += selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceNoPlaceInfo); - } - if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceStreet).isNull()) - { - address += address.isNull() ? QString() : QLatin1String("
"); - address += selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceStreet); - } - if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceZipCode).isNull() || !selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceCity).isNull()) - { - address += address.isNull() ? QString() : QLatin1String("
"); - address += selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceZipCode) + QLatin1Char(' ') + selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceCity); - } - if (!selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceCountry).isNull()) - { - address += address.isNull() ? QString() : QLatin1String("
"); - address += selfAuthenticationData->getValue(SelfAuthData::PlaceOfResidenceCountry); - } - if (!address.isNull()) - { - mData += QPair(tr("Address"), address); - } - - auto documentType = selfAuthenticationData->getValue(SelfAuthData::DocumentType); - if (!documentType.isNull()) - { - mData += QPair(tr("Document type"), documentType); - } - if (!selfAuthenticationData->getValue(SelfAuthData::Nationality).isNull()) - { - mData += QPair(tr("Nationality"), selfAuthenticationData->getValue(SelfAuthData::Nationality)); - } - if (!selfAuthenticationData->getValue(SelfAuthData::ArtisticName).isNull()) - { - mData += QPair(tr("Religious / artistic name"), selfAuthenticationData->getValue(SelfAuthData::ArtisticName)); - } - if (!selfAuthenticationData->getValue(SelfAuthData::IssuingState).isNull()) - { - mData += QPair(tr("Issuing country"), selfAuthenticationData->getValue(SelfAuthData::IssuingState)); - } - - // Show "Residence Permit" for eAT- and Test-Cards only - // AR, AS, AF --> see TR-03127 (v1.16) chapter 3.2.3 - // TA --> Used by Test-Cards - if (!selfAuthenticationData->getValue(SelfAuthData::ResidencePermitI).isNull() && ( - documentType == QLatin1String("AR") || - documentType == QLatin1String("AS") || - documentType == QLatin1String("AF") || - documentType == QLatin1String("TA"))) - { - mData += QPair(tr("Residence permit I"), selfAuthenticationData->getValue(SelfAuthData::ResidencePermitI)); + if (entry.first.isEmpty()) + { + Q_ASSERT(!mSelfData.isEmpty()); + const auto& previous = mSelfData.takeLast(); + mSelfData << qMakePair(previous.first, previous.second + QStringLiteral("
") + entry.second); + } + else + { + mSelfData << entry; + } } } @@ -108,17 +40,18 @@ void SelfAuthenticationModel::onSelfAuthenticationDataChanged() SelfAuthenticationModel::SelfAuthenticationModel(QObject* pParent) : QAbstractListModel(pParent) , mContext() + , mSelfData() { onSelfAuthenticationDataChanged(); } -void SelfAuthenticationModel::resetContext(const QSharedPointer& pContext) +void SelfAuthenticationModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; if (mContext) { - connect(mContext.data(), &SelfAuthenticationContext::fireSelfAuthenticationDataChanged, this, &SelfAuthenticationModel::onSelfAuthenticationDataChanged); + connect(mContext.data(), &SelfAuthContext::fireSelfAuthenticationDataChanged, this, &SelfAuthenticationModel::onSelfAuthenticationDataChanged); } onSelfAuthenticationDataChanged(); } @@ -152,7 +85,7 @@ bool SelfAuthenticationModel::isBasicReader() int SelfAuthenticationModel::rowCount(const QModelIndex&) const { - return mData.size(); + return mSelfData.size(); } @@ -160,7 +93,7 @@ QVariant SelfAuthenticationModel::data(const QModelIndex& pIndex, int pRole) con { if (pIndex.isValid() && pIndex.row() < rowCount()) { - auto pair = mData.at(pIndex.row()); + auto pair = mSelfData.at(pIndex.row()); if (pRole == Qt::DisplayRole || pRole == NAME) { return pair.first; @@ -181,3 +114,13 @@ QHash SelfAuthenticationModel::roleNames() const roles.insert(VALUE, "value"); return roles; } + + +bool SelfAuthenticationModel::event(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + onSelfAuthenticationDataChanged(); + } + return QAbstractListModel::event(pEvent); +} diff --git a/src/qml/SelfAuthenticationModel.h b/src/qml/SelfAuthenticationModel.h index 929a61d..b4af7e4 100644 --- a/src/qml/SelfAuthenticationModel.h +++ b/src/qml/SelfAuthenticationModel.h @@ -1,29 +1,30 @@ /*! * \brief Model implementation for the self authentication workflow. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "SelfAuthenticationData.h" + #include -#include +#include #include #include -#include namespace governikus { -class SelfAuthenticationContext; +class SelfAuthContext; class SelfAuthenticationModel : public QAbstractListModel { Q_OBJECT - QSharedPointer mContext; - QVector > mData; + QSharedPointer mContext; + SelfAuthenticationData::OrderedSelfData mSelfData; enum DataRoles { @@ -36,7 +37,7 @@ class SelfAuthenticationModel public: SelfAuthenticationModel(QObject* pParent = nullptr); - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); Q_INVOKABLE void startWorkflow(); Q_INVOKABLE void cancelWorkflow(); @@ -46,6 +47,8 @@ class SelfAuthenticationModel QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; QHash roleNames() const override; + virtual bool event(QEvent* pEvent) override; + Q_SIGNALS: void fireStartWorkflow(); diff --git a/src/qml/SettingsModel.cpp b/src/qml/SettingsModel.cpp index 6a9718c..739241d 100644 --- a/src/qml/SettingsModel.cpp +++ b/src/qml/SettingsModel.cpp @@ -1,19 +1,46 @@ /*! - * \brief Model implementation for the settings. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "SettingsModel.h" #include "AppSettings.h" +#include "Env.h" +#include "LanguageLoader.h" using namespace governikus; +SettingsModel::SettingsModel() +{ +} + + +QString SettingsModel::getEmptyString() +{ + return QString(); +} + + +QString SettingsModel::getLanguage() const +{ + return LanguageLoader::getInstance().getUsedLocale().bcp47Name(); +} + + +void SettingsModel::setLanguage(const QString& pLanguage) +{ + GeneralSettings& settings = Env::getSingleton()->getGeneralSettings(); + settings.setLanguage(QLocale(pLanguage).language()); + settings.save(); + + Q_EMIT fireLanguageChanged(); +} + + bool SettingsModel::isDeveloperMode() const { - return AppSettings::getInstance().getGeneralSettings().isDeveloperMode(); + return Env::getSingleton()->getGeneralSettings().isDeveloperMode(); } @@ -24,15 +51,15 @@ void SettingsModel::setDeveloperMode(bool pEnable) return; } - AppSettings::getInstance().getGeneralSettings().setDeveloperMode(pEnable); - AppSettings::getInstance().getGeneralSettings().save(); + Env::getSingleton()->getGeneralSettings().setDeveloperMode(pEnable); + Env::getSingleton()->getGeneralSettings().save(); Q_EMIT fireDeveloperModeChanged(); } bool SettingsModel::useSelfauthenticationTestUri() const { - return AppSettings::getInstance().getGeneralSettings().useSelfauthenticationTestUri(); + return AppSettings::getInstance().getGeneralSettings().useSelfAuthTestUri(); } @@ -43,7 +70,47 @@ void SettingsModel::setUseSelfauthenticationTestUri(bool pUse) return; } - AppSettings::getInstance().getGeneralSettings().setUseSelfauthenticationTestUri(pUse); - AppSettings::getInstance().getGeneralSettings().save(); + Env::getSingleton()->getGeneralSettings().setUseSelfauthenticationTestUri(pUse); + Env::getSingleton()->getGeneralSettings().save(); Q_EMIT fireUseSelfauthenticationTestUriChanged(); } + + +QString SettingsModel::getServerName() const +{ + return Env::getSingleton()->getRemoteServiceSettings().getServerName(); +} + + +bool SettingsModel::isValidServerName(const QString& name) const +{ + return !name.isEmpty(); +} + + +void SettingsModel::setServerName(const QString& name) +{ + RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setServerName(name); + settings.save(); +} + + +void SettingsModel::removeTrustedCertificate(const QString& pFingerprint) +{ + Env::getSingleton()->getRemoteServiceSettings().removeTrustedCertificate(pFingerprint); +} + + +bool SettingsModel::getPinPadMode() const +{ + return Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); +} + + +void SettingsModel::setPinPadMode(bool pPinPadMode) +{ + RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setPinPadMode(pPinPadMode); + settings.save(); +} diff --git a/src/qml/SettingsModel.h b/src/qml/SettingsModel.h index c626d45..3736669 100644 --- a/src/qml/SettingsModel.h +++ b/src/qml/SettingsModel.h @@ -1,14 +1,13 @@ /*! * \brief Model implementation for the settings. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include - namespace governikus { @@ -16,19 +15,41 @@ class SettingsModel : public QObject { Q_OBJECT + Q_PROPERTY(QString translationTrigger READ getEmptyString NOTIFY fireLanguageChanged) + Q_PROPERTY(QString language READ getLanguage WRITE setLanguage NOTIFY fireLanguageChanged) Q_PROPERTY(bool developerMode READ isDeveloperMode WRITE setDeveloperMode NOTIFY fireDeveloperModeChanged) Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireUseSelfauthenticationTestUriChanged) + Q_PROPERTY(bool pinPadMode READ getPinPadMode WRITE setPinPadMode NOTIFY firePinPadModeChanged) + Q_PROPERTY(QString serverName READ getServerName WRITE setServerName NOTIFY fireDeviceNameChanged) public: + SettingsModel(); + + QString getEmptyString(); + QString getLanguage() const; + void setLanguage(const QString& pLanguage); + bool isDeveloperMode() const; void setDeveloperMode(bool pEnabled); bool useSelfauthenticationTestUri() const; void setUseSelfauthenticationTestUri(bool pUse); + QString getServerName() const; + Q_INVOKABLE bool isValidServerName(const QString& name) const; + void setServerName(const QString& name); + + Q_INVOKABLE void removeTrustedCertificate(const QString& pFingerprint); + + bool getPinPadMode() const; + void setPinPadMode(bool pPinPadMode); + Q_SIGNALS: + void fireLanguageChanged(); void fireDeveloperModeChanged(); void fireUseSelfauthenticationTestUriChanged(); + void fireDeviceNameChanged(); + void firePinPadModeChanged(); }; } /* namespace governikus */ diff --git a/src/qml/ShareUtil.java b/src/qml/ShareUtil.java index 1380bf0..cbbb907 100644 --- a/src/qml/ShareUtil.java +++ b/src/qml/ShareUtil.java @@ -1,3 +1,7 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + package com.governikus.ausweisapp2; import android.app.Activity; diff --git a/src/qml/StatusBarUtil.cpp b/src/qml/StatusBarUtil.cpp index 8058bff..ad35609 100644 --- a/src/qml/StatusBarUtil.cpp +++ b/src/qml/StatusBarUtil.cpp @@ -1,8 +1,9 @@ /*! * \brief Utility for changing the color of the status bar. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ + #include "StatusBarUtil.h" #include diff --git a/src/qml/StatusBarUtil.h b/src/qml/StatusBarUtil.h index 16524ff..0aa709d 100644 --- a/src/qml/StatusBarUtil.h +++ b/src/qml/StatusBarUtil.h @@ -1,7 +1,7 @@ /*! * \brief Utility for changing the color of the status bar. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/src/qml/UIPlugInQml.cpp b/src/qml/UIPlugInQml.cpp index 98b5af3..d09db54 100644 --- a/src/qml/UIPlugInQml.cpp +++ b/src/qml/UIPlugInQml.cpp @@ -1,15 +1,17 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ +#include "UIPlugInQml.h" + #include "AppSettings.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" -#include "context/SelfAuthenticationContext.h" +#include "context/SelfAuthContext.h" #include "DpiCalculator.h" +#include "Env.h" #include "FileDestination.h" -#include "UIPlugInQml.h" -#include "Updater.h" +#include "Service.h" #ifdef Q_OS_ANDROID #include @@ -28,21 +30,6 @@ #include #endif -#if defined(Q_OS_IOS) -Q_IMPORT_PLUGIN(QSvgPlugin) -Q_IMPORT_PLUGIN(QtQuick2Plugin) -Q_IMPORT_PLUGIN(QtQuick2DialogsPlugin) -Q_IMPORT_PLUGIN(QtQuick2WindowPlugin) -Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin) -Q_IMPORT_PLUGIN(QtQmlModelsPlugin) -Q_IMPORT_PLUGIN(QtQmlStateMachinePlugin) -Q_IMPORT_PLUGIN(QtGraphicalEffectsPlugin) -//Q_IMPORT_PLUGIN(QtQuickControls2Plugin) -//Q_IMPORT_PLUGIN(QtQuickExtrasFlatPlugin) -//Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin) - -#endif - Q_DECLARE_LOGGING_CATEGORY(qml) using namespace governikus; @@ -50,8 +37,8 @@ using namespace governikus; UIPlugInQml::UIPlugInQml() : mEngine() , mDpi(DpiCalculator::getDpi()) - , mProviderModel(&AppSettings::getInstance().getProviderSettings()) - , mHistoryModel(&AppSettings::getInstance().getHistorySettings(), &AppSettings::getInstance().getProviderSettings()) + , mProviderModel() + , mHistoryModel(&AppSettings::getInstance().getHistorySettings()) , mChangePinModel() , mAuthModel() , mVersionInformationModel() @@ -65,6 +52,7 @@ UIPlugInQml::UIPlugInQml() , mExplicitPlatformStyle(getPlatformSelectors()) , mStatusBarUtil() , mConnectivityManager() + , mRemoteServiceModel() { #if defined(Q_OS_ANDROID) QGuiApplication::setFont(QFont("Roboto")); @@ -72,6 +60,8 @@ UIPlugInQml::UIPlugInQml() connect(&mChangePinModel, &ChangePinModel::fireStartWorkflow, this, &UIPlugIn::fireChangePinRequest); connect(&mSelfAuthenticationModel, &SelfAuthenticationModel::fireStartWorkflow, this, &UIPlugIn::fireSelfAuthenticationRequested); + connect(&mRemoteServiceModel, &RemoteServiceModel::fireStartWorkflow, this, &UIPlugIn::fireRemoteServiceRequested); + connect(this, &UIPlugIn::fireShowUserInformation, this, &UIPlugInQml::onShowUserInformation); init(); } @@ -83,50 +73,50 @@ UIPlugInQml::~UIPlugInQml() void UIPlugInQml::init() { -#ifndef QT_NO_DEBUG - // Our ios implementation is placed in the base folder. - // When setting on android extra selectors to ios, the ios (i.e. the base) implementations - // are not found. This happens because the selector ordering in QFileSelector is - // 1. extra selectors - // 2. default selectors (which contain the platform selector) - // 3. no selector - // We work around this by overriding the default selectors with nonsense. - static const char* envFileSelectors = "QT_FILE_SELECTORS"; // see qfileselector.cpp - static const char* envOverride = "QT_NO_BUILTIN_SELECTORS"; // see qfileselector.cpp - qputenv(envFileSelectors, "lalelu"); - qputenv(envOverride, "true"); +#if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) + qputenv("QML_DISABLE_DISK_CACHE", "true"); #endif mEngine.reset(new QQmlApplicationEngine()); - mEngine->rootContext()->setContextProperty("plugin", this); - QQmlFileSelector::get(mEngine.data())->setExtraSelectors(mExplicitPlatformStyle.split(QChar(','))); + mEngine->rootContext()->setContextProperty(QStringLiteral("plugin"), this); + QQmlFileSelector::get(mEngine.data())->setExtraSelectors(mExplicitPlatformStyle.split(QLatin1Char(','))); - mEngine->rootContext()->setContextProperty("screenDpi", mDpi); - mEngine->rootContext()->setContextProperty("providerModel", &mProviderModel); - mEngine->rootContext()->setContextProperty("historyModel", &mHistoryModel); - mEngine->rootContext()->setContextProperty("changePinModel", &mChangePinModel); - mEngine->rootContext()->setContextProperty("authModel", &mAuthModel); - mEngine->rootContext()->setContextProperty("versionInformationModel", &mVersionInformationModel); - mEngine->rootContext()->setContextProperty("qmlExtension", &mQmlExtension); - mEngine->rootContext()->setContextProperty("selfAuthenticationModel", &mSelfAuthenticationModel); - mEngine->rootContext()->setContextProperty("settingsModel", &mSettingsModel); - mEngine->rootContext()->setContextProperty("certificateDescriptionModel", &mCertificateDescriptionModel); - mEngine->rootContext()->setContextProperty("chatModel", &mChatModel); - mEngine->rootContext()->setContextProperty("numberModel", &mNumberModel); - mEngine->rootContext()->setContextProperty("applicationModel", &mApplicationModel); - mEngine->rootContext()->setContextProperty("statusBarUtil", &mStatusBarUtil); - mEngine->rootContext()->setContextProperty("connectivityManager", &mConnectivityManager); + mEngine->rootContext()->setContextProperty(QStringLiteral("screenDpi"), mDpi); + mEngine->rootContext()->setContextProperty(QStringLiteral("providerModel"), &mProviderModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("historyModel"), &mHistoryModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("changePinModel"), &mChangePinModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("authModel"), &mAuthModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("versionInformationModel"), &mVersionInformationModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("qmlExtension"), &mQmlExtension); + mEngine->rootContext()->setContextProperty(QStringLiteral("selfAuthenticationModel"), &mSelfAuthenticationModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("settingsModel"), &mSettingsModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("certificateDescriptionModel"), &mCertificateDescriptionModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("chatModel"), &mChatModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("numberModel"), &mNumberModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("applicationModel"), &mApplicationModel); + mEngine->rootContext()->setContextProperty(QStringLiteral("statusBarUtil"), &mStatusBarUtil); + mEngine->rootContext()->setContextProperty(QStringLiteral("connectivityManager"), &mConnectivityManager); + mEngine->rootContext()->setContextProperty(QStringLiteral("remoteServiceModel"), &mRemoteServiceModel); - mEngine->load(getFile(QStringLiteral("qml/main.qml"))); + mEngine->addImportPath(getPath(QStringLiteral("qml/")).toString()); + mEngine->load(getPath(QStringLiteral("qml/main.qml"))); - Updater::getInstance().update(); + Env::getSingleton()->updateConfigurations(); } QString UIPlugInQml::getPlatformSelectors() const { - static const QString TABLET_SELECTOR_PREFIX("tablet,"); +#ifndef Q_NO_DEBUG + const char* overrideSelector = "OVERRIDE_PLATFORM_SELECTOR"; + if (!qEnvironmentVariableIsEmpty(overrideSelector)) + { + const auto& platform = QString::fromLocal8Bit(qgetenv(overrideSelector)); + qCDebug(qml) << "Override platform selector:" << platform; + return platform; + } +#endif #if defined(Q_OS_ANDROID) const jboolean result = QtAndroid::androidActivity().callMethod("isTablet", "()Z"); @@ -149,9 +139,14 @@ QString UIPlugInQml::getPlatformSelectors() const const double diagonal = sqrt(width * width + height * height); const bool isTablet = diagonal > MAX_SMARTPHONE_DIAGONAL_MM; #endif - const QString platform = QGuiApplication::platformName(); - return isTablet ? TABLET_SELECTOR_PREFIX + platform : platform; +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + const QString platform = QGuiApplication::platformName(); +#else + const QString platform = QStringLiteral("android"); +#endif + + return isTablet ? QStringLiteral("tablet,") + platform : platform; } @@ -173,10 +168,15 @@ void UIPlugInQml::onWorkflowStarted(QSharedPointer pContext) mChatModel.resetContext(authContext); } - if (auto authContext = pContext.objectCast()) + if (auto authContext = pContext.objectCast()) { mSelfAuthenticationModel.resetContext(authContext); } + + if (auto remoteServiceContext = pContext.objectCast()) + { + mRemoteServiceModel.resetContext(remoteServiceContext); + } } @@ -198,10 +198,21 @@ void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) mChatModel.resetContext(); } - if (pContext.objectCast()) + if (pContext.objectCast()) { mSelfAuthenticationModel.resetContext(); } + + if (pContext.objectCast()) + { + mRemoteServiceModel.resetContext(); + } +} + + +void UIPlugInQml::onShowUserInformation(const QString& pMessage) +{ + mQmlExtension.showFeedback(pMessage); } @@ -211,21 +222,22 @@ void UIPlugInQml::doShutdown() } -QUrl UIPlugInQml::getFile(const QString& pFile) +QUrl UIPlugInQml::getPath(const QString& pRelativePath) { - const QString path = FileDestination::getPath(pFile); - #if !defined(QT_NO_DEBUG) && !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT) - if (!QFile::exists(path)) + const QString ressourceFolderPath(QStringLiteral(RES_DIR) + QLatin1Char('/') + pRelativePath); + if (QFile::exists(ressourceFolderPath)) { - return QUrl::fromLocalFile(QStringLiteral(RES_DIR) + QLatin1Char('/') + pFile); + return QUrl::fromLocalFile(ressourceFolderPath); } + #endif #if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) - return path; + return QStringLiteral("qrc:///") + pRelativePath; #else + const QString path = FileDestination::getPath(pRelativePath); return QUrl::fromLocalFile(path); #endif @@ -257,11 +269,11 @@ void UIPlugInQml::applyPlatformStyle(const QString& pPlatformStyle) bool UIPlugInQml::isDeveloperBuild() const { -#ifdef QT_NO_DEBUG - return false; +#ifndef QT_NO_DEBUG + return true; #else - return true; + return false; #endif } diff --git a/src/qml/UIPlugInQml.h b/src/qml/UIPlugInQml.h index 76d8321..4b0efd8 100644 --- a/src/qml/UIPlugInQml.h +++ b/src/qml/UIPlugInQml.h @@ -1,7 +1,7 @@ /*! * \brief UIPlugIn implementation of QML. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -18,10 +18,12 @@ #include "NumberModel.h" #include "ProviderCategoryFilterModel.h" #include "QmlExtension.h" +#include "RemoteServiceModel.h" #include "SelfAuthenticationModel.h" #include "SettingsModel.h" #include "StatusBarUtil.h" #include "VersionInformationModel.h" + #include #include @@ -55,23 +57,24 @@ class UIPlugInQml QString mExplicitPlatformStyle; StatusBarUtil mStatusBarUtil; ConnectivityManager mConnectivityManager; + RemoteServiceModel mRemoteServiceModel; QString getPlatformSelectors() const; + static QUrl getPath(const QString& pRelativePath); public: UIPlugInQml(); - virtual ~UIPlugInQml(); + virtual ~UIPlugInQml() override; QString getPlatformStyle() const; Q_INVOKABLE void applyPlatformStyle(const QString& pPlatformStyle); 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; virtual void onWorkflowFinished(QSharedPointer pContext) override; + void onShowUserInformation(const QString& pMessage); public Q_SLOTS: void doRefresh(); diff --git a/src/qml/VersionInformationModel.cpp b/src/qml/VersionInformationModel.cpp index b14e1d4..8e99ce9 100644 --- a/src/qml/VersionInformationModel.cpp +++ b/src/qml/VersionInformationModel.cpp @@ -1,12 +1,14 @@ /*! * \brief Model implementation for version information. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ +#include "VersionInformationModel.h" + +#include "AppSettings.h" #include "BuildHelper.h" #include "DeviceInfo.h" -#include "VersionInformationModel.h" #include #include @@ -19,10 +21,9 @@ using namespace governikus; -VersionInformationModel::VersionInformationModel(QObject* pParent) - : QAbstractListModel(pParent) - , mData() +void VersionInformationModel::init() { + mData.clear(); mData += QPair(tr("Application Name"), QCoreApplication::applicationName()); mData += QPair(tr("Application Version"), QCoreApplication::applicationVersion()); mData += QPair(tr("Organization"), QCoreApplication::organizationName()); @@ -43,6 +44,21 @@ VersionInformationModel::VersionInformationModel(QObject* pParent) } +VersionInformationModel::VersionInformationModel(QObject* pParent) + : QAbstractListModel(pParent) + , mData() +{ + init(); + + connect(&AppSettings::getInstance().getGeneralSettings(), &GeneralSettings::fireSettingsChanged, this, [this]() + { + beginResetModel(); + init(); + endResetModel(); + }); +} + + int VersionInformationModel::rowCount(const QModelIndex&) const { return mData.size(); diff --git a/src/qml/VersionInformationModel.h b/src/qml/VersionInformationModel.h index bb7da4a..8abcc18 100644 --- a/src/qml/VersionInformationModel.h +++ b/src/qml/VersionInformationModel.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -17,12 +17,15 @@ class VersionInformationModel { Q_OBJECT - enum HistoryRoles - { - LABEL = Qt::UserRole + 1, - TEXT - }; - QVector > mData; + private: + enum HistoryRoles + { + LABEL = Qt::UserRole + 1, + TEXT + }; + QVector > mData; + + void init(); public: VersionInformationModel(QObject* pParent = nullptr); diff --git a/src/qml/WorkflowModel.cpp b/src/qml/WorkflowModel.cpp new file mode 100644 index 0000000..f25f163 --- /dev/null +++ b/src/qml/WorkflowModel.cpp @@ -0,0 +1,122 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowModel.h" + +#include "context/AuthContext.h" + +using namespace governikus; + + +WorkflowModel::WorkflowModel(QObject* pParent) + : QObject(pParent) + , mContext() +{ +} + + +WorkflowModel::~WorkflowModel() +{ +} + + +void WorkflowModel::resetContext(const QSharedPointer& pContext) +{ + mContext = pContext; + if (mContext) + { + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &WorkflowModel::fireCurrentStateChanged); + connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &WorkflowModel::fireResultChanged); + connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireReaderPlugInTypeChanged); + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireIsBasicReaderChanged); + } + + /* + * Only this state change is emitted when the context is reset, i.e. after the end of the workflow + */ + Q_EMIT fireCurrentStateChanged(getCurrentState()); +} + + +QString WorkflowModel::getCurrentState() const +{ + return mContext ? mContext->getCurrentState() : QString(); +} + + +QString WorkflowModel::getResultString() const +{ + return mContext ? mContext->getStatus().toErrorDescription(true) : QString(); +} + + +bool WorkflowModel::isError() const +{ + return mContext && mContext->getStatus().isError(); +} + + +QString WorkflowModel::getReaderPlugInType() const +{ + if (mContext && !mContext->getReaderPlugInTypes().isEmpty()) + { + return getEnumName(mContext->getReaderPlugInTypes().at(0)); + } + + return QString(); +} + + +void WorkflowModel::setReaderPlugInType(const QString& pReaderPlugInType) +{ + if (mContext) + { + mContext->setReaderPlugInTypes({Enum::fromString(pReaderPlugInType, ReaderManagerPlugInType::UNKNOWN)}); + } +} + + +void WorkflowModel::continueWorkflow() +{ + if (mContext) + { + mContext->setStateApproved(); + } +} + + +void WorkflowModel::startWorkflow() +{ + Q_EMIT fireStartWorkflow(); +} + + +void WorkflowModel::cancelWorkflow() +{ + if (mContext) + { + Q_EMIT mContext->fireCancelWorkflow(); + } +} + + +void WorkflowModel::cancelWorkflowOnPinBlocked() +{ + if (mContext) + { + mContext->setStatus(GlobalStatus::Code::Workflow_Pin_Blocked_And_Puk_Objectionable); + Q_EMIT mContext->fireCancelWorkflow(); + } +} + + +bool WorkflowModel::isBasicReader() +{ + if (mContext && mContext->getCardConnection()) + { + return mContext->getCardConnection()->getReaderInfo().isBasicReader(); + } + + return true; +} diff --git a/src/qml/WorkflowModel.h b/src/qml/WorkflowModel.h new file mode 100644 index 0000000..e6e4ad9 --- /dev/null +++ b/src/qml/WorkflowModel.h @@ -0,0 +1,60 @@ +/*! + * \brief Model implementation for the authentication action. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + +namespace governikus +{ + +class WorkflowContext; + +class WorkflowModel + : public QObject +{ + Q_OBJECT + 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 readerPlugInType READ getReaderPlugInType WRITE setReaderPlugInType NOTIFY fireReaderPlugInTypeChanged) + Q_PROPERTY(bool isBasicReader READ isBasicReader NOTIFY fireIsBasicReaderChanged) + + private: + QSharedPointer mContext; + + public: + WorkflowModel(QObject* pParent = nullptr); + virtual ~WorkflowModel(); + + void resetContext(const QSharedPointer& pContext = QSharedPointer()); + + QString getCurrentState() const; + virtual QString getResultString() const; + bool isError() const; + + QString getReaderPlugInType() const; + void setReaderPlugInType(const QString& pReaderPlugInType); + + bool isBasicReader(); + + Q_INVOKABLE void startWorkflow(); + Q_INVOKABLE void cancelWorkflow(); + Q_INVOKABLE void cancelWorkflowOnPinBlocked(); + Q_INVOKABLE void continueWorkflow(); + + Q_SIGNALS: + void fireStartWorkflow(); + void fireCurrentStateChanged(const QString& pState); + void fireResultChanged(); + void fireReaderPlugInTypeChanged(); + void fireIsBasicReaderChanged(); +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/CMakeLists.txt b/src/remote_device/CMakeLists.txt new file mode 100644 index 0000000..b785a86 --- /dev/null +++ b/src/remote_device/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppRemoteDevice) + +TARGET_LINK_LIBRARIES(AusweisAppRemoteDevice Qt5::Core Qt5::WebSockets AusweisAppCard AusweisAppGlobal AusweisAppSecureStorage AusweisAppNetwork AusweisAppSettings) diff --git a/src/remote_device/DataChannel.cpp b/src/remote_device/DataChannel.cpp new file mode 100644 index 0000000..4428fe0 --- /dev/null +++ b/src/remote_device/DataChannel.cpp @@ -0,0 +1,26 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DataChannel.h" + + +using namespace governikus; + + +DataChannel::DataChannel() +{ +} + + +DataChannel::~DataChannel() +{ +} + + +const QString& DataChannel::getId() const +{ + static const QString EMPTY_STRING; + + return EMPTY_STRING; +} diff --git a/src/remote_device/DataChannel.h b/src/remote_device/DataChannel.h new file mode 100644 index 0000000..1fbebd9 --- /dev/null +++ b/src/remote_device/DataChannel.h @@ -0,0 +1,35 @@ +/*! + * \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, Germany + */ + +#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; + virtual const QString& getId() const; + + Q_SIGNALS: + void fireReceived(const QByteArray& pDataBlock); + void fireClosed(GlobalStatus::Code pCloseCode); +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteClientImpl.cpp b/src/remote_device/RemoteClientImpl.cpp new file mode 100644 index 0000000..2c7d066 --- /dev/null +++ b/src/remote_device/RemoteClientImpl.cpp @@ -0,0 +1,286 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteClientImpl.h" + +#include "AppSettings.h" +#include "Env.h" +#include "messages/RemoteMessageParser.h" +#include "RemoteConnectorImpl.h" + +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + +using namespace governikus; + +namespace governikus +{ + +template<> RemoteClient* createNewObject() +{ + return new RemoteClientImpl; +} + + +} + + +RemoteClientImpl::RemoteClientImpl() + : mDatagramHandler() + , mRemoteDeviceList(Env::create()) + , mErrorCounter() + , mRemoteConnectorThread() + , mRemoteConnector() + , mRemoteConnectorPending() +{ + connect(mRemoteDeviceList.data(), &RemoteDeviceList::fireDeviceAppeared, this, &RemoteClient::fireDeviceAppeared); + connect(mRemoteDeviceList.data(), &RemoteDeviceList::fireDeviceVanished, this, &RemoteClient::fireDeviceVanished); + + bootstrapRemoteConnectorThread(); +} + + +RemoteClientImpl::~RemoteClientImpl() +{ + shutdownRemoteConnectorThread(); +} + + +void RemoteClientImpl::bootstrapRemoteConnectorThread() +{ + Q_ASSERT(!mRemoteConnectorThread.isRunning()); + Q_ASSERT(mRemoteConnector.isNull()); + + mRemoteConnectorThread.setObjectName(QStringLiteral("RemoteConnectorThread")); + + mRemoteConnector = Env::create(); + mRemoteConnector->moveToThread(&mRemoteConnectorThread); + connect(&mRemoteConnectorThread, &QThread::finished, mRemoteConnector.data(), &QObject::deleteLater); + + connect(mRemoteConnector.data(), &RemoteConnector::fireRemoteDispatcherCreated, this, &RemoteClientImpl::onRemoteDispatcherCreated); + connect(mRemoteConnector.data(), &RemoteConnector::fireRemoteDispatcherError, this, &RemoteClientImpl::onRemoteDispatcherError); + + mRemoteConnectorThread.start(); +} + + +void RemoteClientImpl::shutdownRemoteConnectorThread() +{ + if (mRemoteConnectorThread.isRunning() && !mRemoteConnectorThread.isInterruptionRequested()) + { + qCDebug(remote_device) << "Shutdown RemoteConnector..."; + mRemoteConnectorThread.requestInterruption(); // do not try to stop AGAIN from dtor + mRemoteConnectorThread.quit(); + mRemoteConnectorThread.wait(2500); + qCDebug(remote_device) << "RemoteConnector:" << (mRemoteConnectorThread.isRunning() ? "still running" : "stopped"); + + Q_ASSERT(!mRemoteConnectorThread.isRunning()); + } +} + + +QSharedPointer RemoteClientImpl::mapToAndTakeRemoteConnectorPending(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) +{ + QMutableVectorIterator > i(mRemoteConnectorPending); + while (i.hasNext()) + { + QSharedPointer entry = i.next(); + if (entry->contains(pRemoteDeviceDescriptor)) + { + i.remove(); + return entry; + } + } + + Q_ASSERT(false); + return QSharedPointer(); +} + + +void RemoteClientImpl::onNewMessage(const QJsonDocument& pData, const QHostAddress& pAddress) +{ + bool isIPv4; + pAddress.toIPv4Address(&isIPv4); + if (!isIPv4) + { + static int timesLogged = 0; + if (timesLogged < 20) + { + qCCritical(remote_device) << "IPv6 not supported" << pAddress; + timesLogged++; + } + return; + } + const QSharedPointer& discovery = RemoteMessageParser().parseDiscovery(pData); + if (discovery.isNull()) + { + static int timesLogged = 0; + if (timesLogged < 20) + { + qCDebug(remote_device) << "Discarding unparsable message"; + timesLogged++; + } + return; + } + + const RemoteDeviceDescriptor remoteDeviceDescriptor(discovery, pAddress); + mRemoteDeviceList->update(remoteDeviceDescriptor); +} + + +void RemoteClientImpl::onRemoteDispatcherCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QSharedPointer& pDispatcher) +{ + mErrorCounter[pRemoteDeviceDescriptor.getIfdId()] = 0; + const QSharedPointer& entry = mapToAndTakeRemoteConnectorPending(pRemoteDeviceDescriptor); + if (entry.isNull()) + { + qCDebug(remote_device) << "Failed to map RemoteConnector response:" << pRemoteDeviceDescriptor; + Q_ASSERT(false); + return; + } + + mConnectedDeviceIds.append(entry->getRemoteDeviceDescriptor().getIfdId()); + connect(pDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteClientImpl::onDispatcherDestroyed); + + Q_EMIT fireEstablishConnectionDone(entry, GlobalStatus::Code::No_Error); + Q_EMIT fireNewRemoteDispatcher(pDispatcher); +} + + +void RemoteClientImpl::onRemoteDispatcherError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, RemoteErrorCode pErrorCode) +{ + const QSharedPointer& entry = mapToAndTakeRemoteConnectorPending(pRemoteDeviceDescriptor); + if (entry.isNull()) + { + qCDebug(remote_device) << "Failed to map RemoteConnector response:" << pRemoteDeviceDescriptor; + Q_ASSERT(false); + return; + } + + if (pErrorCode == RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION || pErrorCode == RemoteErrorCode::NO_SUPPORTED_API_LEVEL) + { + mErrorCounter[pRemoteDeviceDescriptor.getIfdId()] += 1; + if (mErrorCounter[pRemoteDeviceDescriptor.getIfdId()] >= 3) + { + qCCritical(remote_device) << "Remote device refused connection three times, removing certificate with fingerprint:" << pRemoteDeviceDescriptor.getIfdId(); + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + QString deviceName; + const auto& infos = settings.getRemoteInfos(); + for (const auto& remoteInfo : infos) + { + if (remoteInfo.getFingerprint() == pRemoteDeviceDescriptor.getIfdId()) + { + deviceName = remoteInfo.getName(); + } + } + settings.removeTrustedCertificate(pRemoteDeviceDescriptor.getIfdId()); + mErrorCounter[pRemoteDeviceDescriptor.getIfdId()] = 0; + if (!deviceName.isEmpty()) + { + Q_EMIT fireCertificateRemoved(deviceName); + } + } + } + else + { + mErrorCounter[pRemoteDeviceDescriptor.getIfdId()] = 0; + } + + Q_EMIT fireEstablishConnectionDone(entry, RemoteConnector::errorToGlobalStatus(pErrorCode)); +} + + +void RemoteClientImpl::startDetection() +{ + if (!mDatagramHandler.isNull()) + { + qCDebug(remote_device) << "Detection already started"; + return; + } + + mDatagramHandler.reset(Env::create()); + connect(mDatagramHandler.data(), &DatagramHandler::fireNewMessage, this, &RemoteClientImpl::onNewMessage); + Q_EMIT fireDetectionChanged(); +} + + +void RemoteClientImpl::stopDetection() +{ + mDatagramHandler.reset(); + mRemoteDeviceList->clear(); + Q_EMIT fireDetectionChanged(); +} + + +bool RemoteClientImpl::isDetecting() +{ + return !mDatagramHandler.isNull(); +} + + +void RemoteClientImpl::establishConnection(const QSharedPointer& pEntry, const QString& pPsk) +{ + if (mRemoteConnector.isNull()) + { + qCCritical(remote_device) << "There is no RemoteConnector!"; + Q_ASSERT(false); + } + + if (!pEntry) + { + qCWarning(remote_device) << "Cannot connect to given device."; + Q_EMIT fireEstablishConnectionDone(pEntry, GlobalStatus::Code::RemoteConnector_ConnectionError); + return; + } + + mRemoteConnectorPending += pEntry; + + QMetaObject::invokeMethod(mRemoteConnector.data(), "onConnectRequest", Qt::QueuedConnection, + Q_ARG(RemoteDeviceDescriptor, pEntry->getRemoteDeviceDescriptor()), + Q_ARG(QString, pPsk)); +} + + +QVector > RemoteClientImpl::getRemoteDevices() const +{ + return mRemoteDeviceList->getRemoteDevices(); +} + + +void RemoteClientImpl::requestRemoteDevices() +{ + Q_EMIT fireRemoteDevicesInfo(mRemoteDeviceList->getRemoteDevices()); +} + + +QVector RemoteClientImpl::getConnectedDeviceInfos() +{ + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + auto remoteInfos = settings.getRemoteInfos(); + QVector result; + for (const auto& info : remoteInfos) + { + for (const auto& id : qAsConst(mConnectedDeviceIds)) + { + if (info.getFingerprint() == id) + { + result.append(info); + } + } + } + return result; +} + + +void RemoteClientImpl::onDispatcherDestroyed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher) +{ + if (pRemoteDispatcher) + { + mConnectedDeviceIds.removeAll(pRemoteDispatcher->getId()); + } + Q_EMIT fireDispatcherDestroyed(pCloseCode, pRemoteDispatcher); +} diff --git a/src/remote_device/RemoteClientImpl.h b/src/remote_device/RemoteClientImpl.h new file mode 100644 index 0000000..cd8bd19 --- /dev/null +++ b/src/remote_device/RemoteClientImpl.h @@ -0,0 +1,64 @@ +/*! + * \brief Send RemoteReaderDiscoverCmds and maintain a list of responsive peers. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteClient.h" + +#include "DatagramHandler.h" +#include "RemoteConnector.h" +#include "RemoteDeviceList.h" + +#include +#include +#include +#include + +namespace governikus +{ + +class RemoteClientImpl + : public RemoteClient +{ + Q_OBJECT + + private: + QSharedPointer mDatagramHandler; + QScopedPointer mRemoteDeviceList; + QMap mErrorCounter; + + QThread mRemoteConnectorThread; + QPointer mRemoteConnector; + QVector > mRemoteConnectorPending; + QStringList mConnectedDeviceIds; + + void bootstrapRemoteConnectorThread(); + void shutdownRemoteConnectorThread(); + QSharedPointer mapToAndTakeRemoteConnectorPending(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor); + + private Q_SLOTS: + void onNewMessage(const QJsonDocument& pData, const QHostAddress& pAddress); + void onRemoteDispatcherCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QSharedPointer& pAdapter); + void onRemoteDispatcherError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, RemoteErrorCode pErrorCode); + void onDispatcherDestroyed(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); + + public: + RemoteClientImpl(); + virtual ~RemoteClientImpl() override; + + Q_INVOKABLE virtual void startDetection() override; + Q_INVOKABLE virtual void stopDetection() override; + Q_INVOKABLE virtual bool isDetecting() override; + + Q_INVOKABLE virtual void establishConnection(const QSharedPointer& pEntry, const QString& pPsk) override; + + virtual QVector > getRemoteDevices() const override; + Q_INVOKABLE virtual void requestRemoteDevices() override; + virtual QVector getConnectedDeviceInfos() override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteConnector.cpp b/src/remote_device/RemoteConnector.cpp new file mode 100644 index 0000000..9a64f2d --- /dev/null +++ b/src/remote_device/RemoteConnector.cpp @@ -0,0 +1,51 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteConnector.h" + +#include "Initializer.h" + +#include + +using namespace governikus; + + +static Initializer::Entry E([] { + qRegisterMetaType("QHostAddress"); + qRegisterMetaType("RemoteErrorCode"); + qRegisterMetaType >("QSharedPointer"); + qRegisterMetaType("QAbstractSocket::SocketState"); + }); + + +RemoteConnector::RemoteConnector() +{ +} + + +GlobalStatus RemoteConnector::errorToGlobalStatus(RemoteErrorCode pDeviceError) +{ + switch (pDeviceError) + { + case RemoteErrorCode::INVALID_REQUEST: + return GlobalStatus::Code::RemoteConnector_InvalidRequest; + + case RemoteErrorCode::EMPTY_PASSWORD: + return GlobalStatus::Code::RemoteConnector_EmptyPassword; + + case RemoteErrorCode::NO_SUPPORTED_API_LEVEL: + return GlobalStatus::Code::RemoteConnector_NoSupportedApiLevel; + + case RemoteErrorCode::CONNECTION_TIMEOUT: + return GlobalStatus::Code::RemoteConnector_ConnectionTimeout; + + case RemoteErrorCode::CONNECTION_ERROR: + return GlobalStatus::Code::RemoteConnector_ConnectionError; + + case RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION: + return GlobalStatus::Code::RemoteConnector_RemoteHostRefusedConnection; + } + + Q_UNREACHABLE(); +} diff --git a/src/remote_device/RemoteConnector.h b/src/remote_device/RemoteConnector.h new file mode 100644 index 0000000..56ff00a --- /dev/null +++ b/src/remote_device/RemoteConnector.h @@ -0,0 +1,48 @@ +/*! + * \brief Module that creates and manages connections from a remote client to a remote server. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" +#include "messages/RemoteMessage.h" +#include "RemoteDeviceDescriptor.h" +#include "RemoteDispatcher.h" +#include "RemoteDispatcher.h" + +#include + +namespace governikus +{ +defineEnumType(RemoteErrorCode, + INVALID_REQUEST, + EMPTY_PASSWORD, + NO_SUPPORTED_API_LEVEL, + CONNECTION_TIMEOUT, + CONNECTION_ERROR, + REMOTE_HOST_REFUSED_CONNECTION) + + +class RemoteConnector + : public QObject +{ + Q_OBJECT + + public: + RemoteConnector(); + virtual ~RemoteConnector() = default; + + static GlobalStatus errorToGlobalStatus(RemoteErrorCode pDeviceError); + + public Q_SLOTS: + virtual void onConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QString& pPsk) = 0; + + Q_SIGNALS: + void fireRemoteDispatcherCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QSharedPointer& pAdapter); + void fireRemoteDispatcherError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, RemoteErrorCode pErrorCode); + +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteConnectorImpl.cpp b/src/remote_device/RemoteConnectorImpl.cpp new file mode 100644 index 0000000..15d20ea --- /dev/null +++ b/src/remote_device/RemoteConnectorImpl.cpp @@ -0,0 +1,317 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteConnectorImpl.h" + +#include "AppSettings.h" +#include "Env.h" +#include "RemoteDispatcherImpl.h" +#include "RemoteHelper.h" +#include "SecureStorage.h" +#include "TlsChecker.h" +#include "WebSocketChannel.h" + +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +namespace governikus +{ +template<> RemoteConnector* createNewObject() +{ + return new RemoteConnectorImpl; +} + + +class ConnectRequest + : public QObject +{ + Q_OBJECT + + private: + const RemoteDeviceDescriptor mRemoteDeviceDescriptor; + const QByteArray mPsk; + const QSharedPointer mSocket; + QTimer mTimer; + + private Q_SLOTS: + void onConnected(); + void onError(QAbstractSocket::SocketError pError); + void onTimeout(); + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onSslErrors(const QList& pErrors); + + public: + ConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, + const QByteArray& pPsk, + int pTimeoutMs); + virtual ~ConnectRequest() = default; + + const RemoteDeviceDescriptor& getRemoteDeviceDescriptor() const; + + void start(); + + Q_SIGNALS: + void fireConnectionCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, + const QSharedPointer& pWebSocket); + void fireConnectionError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const RemoteErrorCode& pError); + void fireConnectionTimeout(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor); +}; + + +} + + +using namespace governikus; + + +void ConnectRequest::onConnected() +{ + mTimer.stop(); + + const auto& cfg = mSocket->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(remote_device)); + + if (!TlsChecker::hasValidCertificateKeyLength(cfg.peerCertificate()) || + (!cfg.ephemeralServerKey().isNull() && !TlsChecker::hasValidEphemeralKeyLength(cfg.ephemeralServerKey()))) + { + qCCritical(remote_device) << "Server denied... abort connection!"; + mSocket->abort(); + Q_EMIT fireConnectionError(mRemoteDeviceDescriptor, RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION); + return; + } + + qCDebug(remote_device) << "Connected to remote device"; + + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + const auto& pairingCiphers = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + if (pairingCiphers.contains(cfg.sessionCipher())) + { + qCDebug(remote_device) << "Pairing completed | Add certificate:" << cfg.peerCertificate(); + settings.addTrustedCertificate(cfg.peerCertificate()); + settings.save(); + } + else + { + auto info = settings.getRemoteInfo(cfg.peerCertificate()); + info.setLastConnected(QDateTime::currentDateTime()); + settings.updateRemoteInfo(info); + } + + Q_EMIT fireConnectionCreated(mRemoteDeviceDescriptor, mSocket); +} + + +void ConnectRequest::onError(QAbstractSocket::SocketError pError) +{ + static int timesLogged = 0; + if (timesLogged < 20) + { + qCWarning(remote_device) << "Connection error:" << pError; + timesLogged++; + } + + mTimer.stop(); + if (pError == QAbstractSocket::SocketError::RemoteHostClosedError) + { + Q_EMIT fireConnectionError(mRemoteDeviceDescriptor, RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION); + } + else + { + Q_EMIT fireConnectionError(mRemoteDeviceDescriptor, RemoteErrorCode::CONNECTION_ERROR); + } +} + + +void ConnectRequest::onTimeout() +{ + Q_EMIT fireConnectionTimeout(mRemoteDeviceDescriptor); +} + + +void ConnectRequest::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +{ + qCDebug(remote_device) << "Request pairing..."; + pAuthenticator->setPreSharedKey(mPsk); +} + + +void ConnectRequest::onSslErrors(const QList& pErrors) +{ + QList allowedErrors = { + QSslError::HostNameMismatch + }; + + const auto& config = mSocket->sslConfiguration(); + const auto& pairingCiphers = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + if (pairingCiphers.contains(config.sessionCipher())) + { + allowedErrors << QSslError::SelfSignedCertificate; + } + + bool ignoreErrors = true; + for (const auto& error : pErrors) + { + if (!allowedErrors.contains(error.error())) + { + ignoreErrors = false; + break; + } + } + + if (ignoreErrors) + { + mSocket->ignoreSslErrors(); + return; + } + + qCDebug(remote_device) << "Server is untrusted | cipher:" << config.sessionCipher() << "| certificate:" << config.peerCertificate() << "| error:" << pErrors; +} + + +ConnectRequest::ConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, + const QByteArray& pPsk, + int pTimeoutMs) + : mRemoteDeviceDescriptor(pRemoteDeviceDescriptor) + , mPsk(pPsk) + , mSocket(new QWebSocket(), &QObject::deleteLater) + , mTimer() +{ + if (!RemoteHelper::checkAndGenerateKey()) + { + qCCritical(remote_device) << "Cannot get required key/certificate for tls"; + return; + } + + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + QSslConfiguration config; + if (mPsk.isEmpty()) + { + config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + config.setCaCertificates(settings.getTrustedCertificates()); + qCCritical(remote_device) << "Start reconnect to server"; + } + else + { + config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + qCCritical(remote_device) << "Start pairing to server"; + } + config.setPrivateKey(settings.getKey()); + config.setLocalCertificate(settings.getCertificate()); + config.setPeerVerifyMode(QSslSocket::VerifyPeer); + mSocket->setSslConfiguration(config); + + connect(mSocket.data(), &QWebSocket::preSharedKeyAuthenticationRequired, this, &ConnectRequest::onPreSharedKeyAuthenticationRequired); + connect(mSocket.data(), &QWebSocket::sslErrors, this, &ConnectRequest::onSslErrors); + +#ifndef QT_NO_NETWORKPROXY + mSocket->setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); +#endif + connect(mSocket.data(), &QWebSocket::connected, this, &ConnectRequest::onConnected); + connect(mSocket.data(), QOverload::of(&QWebSocket::error), this, &ConnectRequest::onError); + + mTimer.setSingleShot(true); + mTimer.setInterval(pTimeoutMs); + connect(&mTimer, &QTimer::timeout, this, &ConnectRequest::onTimeout); +} + + +const RemoteDeviceDescriptor& ConnectRequest::getRemoteDeviceDescriptor() const +{ + return mRemoteDeviceDescriptor; +} + + +void ConnectRequest::start() +{ + mSocket->open(mRemoteDeviceDescriptor.getUrl()); + mTimer.start(); +} + + +void RemoteConnectorImpl::removeRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) +{ + QMutableVectorIterator > requestIterator(mPendingRequests); + while (requestIterator.hasNext()) + { + const QSharedPointer item = requestIterator.next(); + Q_ASSERT(item); + if (item.isNull()) + { + qCCritical(remote_device) << "Unexpected null pending request"; + + requestIterator.remove(); + } + else if (item->getRemoteDeviceDescriptor() == pRemoteDeviceDescriptor) + { + requestIterator.remove(); + } + } +} + + +void RemoteConnectorImpl::onConnectionCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, + const QSharedPointer& pWebSocket) +{ + const QSharedPointer channel(new WebSocketChannel(pWebSocket), &QObject::deleteLater); + const QSharedPointer dispatcher(Env::create(channel), &QObject::deleteLater); + + removeRequest(pRemoteDeviceDescriptor); + + Q_EMIT fireRemoteDispatcherCreated(pRemoteDeviceDescriptor, dispatcher); +} + + +void RemoteConnectorImpl::onConnectionError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const RemoteErrorCode& pError) +{ + removeRequest(pRemoteDeviceDescriptor); + + Q_EMIT fireRemoteDispatcherError(pRemoteDeviceDescriptor, pError); +} + + +void RemoteConnectorImpl::onConnectionTimeout(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) +{ + removeRequest(pRemoteDeviceDescriptor); + + Q_EMIT fireRemoteDispatcherError(pRemoteDeviceDescriptor, RemoteErrorCode::CONNECTION_TIMEOUT); +} + + +RemoteConnectorImpl::RemoteConnectorImpl(int pConnectTimeoutMs) + : mConnectTimeoutMs(pConnectTimeoutMs) + , mPendingRequests() +{ +} + + +void RemoteConnectorImpl::onConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QString& pPsk) +{ + if (pRemoteDeviceDescriptor.isNull() || pRemoteDeviceDescriptor.getIfdName().isEmpty()) + { + Q_EMIT fireRemoteDispatcherError(pRemoteDeviceDescriptor, RemoteErrorCode::INVALID_REQUEST); + return; + } + + // Currently, we only support API level 1. + if (!pRemoteDeviceDescriptor.getSupportedApis().contains(QLatin1String("IFDInterface_WebSocket_v0"))) + { + Q_EMIT fireRemoteDispatcherError(pRemoteDeviceDescriptor, RemoteErrorCode::NO_SUPPORTED_API_LEVEL); + return; + } + + const QSharedPointer newRequest(new ConnectRequest(pRemoteDeviceDescriptor, pPsk.toUtf8(), mConnectTimeoutMs), &QObject::deleteLater); + mPendingRequests += newRequest; + connect(newRequest.data(), &ConnectRequest::fireConnectionCreated, this, &RemoteConnectorImpl::onConnectionCreated); + connect(newRequest.data(), &ConnectRequest::fireConnectionError, this, &RemoteConnectorImpl::onConnectionError); + connect(newRequest.data(), &ConnectRequest::fireConnectionTimeout, this, &RemoteConnectorImpl::onConnectionTimeout); + newRequest->start(); +} + + +#include "RemoteConnectorImpl.moc" diff --git a/src/remote_device/RemoteConnectorImpl.h b/src/remote_device/RemoteConnectorImpl.h new file mode 100644 index 0000000..1adef72 --- /dev/null +++ b/src/remote_device/RemoteConnectorImpl.h @@ -0,0 +1,42 @@ +/*! + * \brief Module that creates and manages connections from a remote client to a remote server. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteConnector.h" + +#include +#include + +namespace governikus +{ +class ConnectRequest; + +class RemoteConnectorImpl + : public RemoteConnector +{ + Q_OBJECT + + private: + const int mConnectTimeoutMs; + QVector > mPendingRequests; + + void removeRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor); + + private Q_SLOTS: + void onConnectionCreated(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QSharedPointer& pWebSocket); + void onConnectionError(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const RemoteErrorCode& pError); + void onConnectionTimeout(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor); + + public: + RemoteConnectorImpl(int pConnectTimeoutMs = 5000); + virtual ~RemoteConnectorImpl() override = default; + + virtual void onConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QString& pPsk) override; + +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteDeviceDescriptor.cpp b/src/remote_device/RemoteDeviceDescriptor.cpp new file mode 100644 index 0000000..4cc447f --- /dev/null +++ b/src/remote_device/RemoteDeviceDescriptor.cpp @@ -0,0 +1,169 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceDescriptor.h" + +#include "Initializer.h" +#include "messages/Discovery.h" + + +using namespace governikus; + + +static Initializer::Entry E([] { + qRegisterMetaType("RemoteDeviceDescriptor"); + }); + + +namespace +{ +QHostAddress convertAddressProtocol(const QHostAddress& pAddress, QAbstractSocket::NetworkLayerProtocol pRequiredProtocol) +{ + const QAbstractSocket::NetworkLayerProtocol actualProtocol = pAddress.protocol(); + if (actualProtocol == pRequiredProtocol) + { + return pAddress; + } + + switch (pRequiredProtocol) + { + case QAbstractSocket::IPv4Protocol: + { + bool conversionOK = false; + const QHostAddress convertedAddress(pAddress.toIPv4Address(&conversionOK)); + return conversionOK ? convertedAddress : QHostAddress(); + } + + case QAbstractSocket::IPv6Protocol: + return QHostAddress(pAddress.toIPv6Address()); + + default: + return QHostAddress(); + } +} + + +QUrl urlFromMsgAndHost(const QSharedPointer& pMsg, + const QHostAddress& pHostAddress, + QAbstractSocket::NetworkLayerProtocol pRequiredProtocol) +{ + if (pMsg.isNull()) + { + return QUrl(); + } + + const QHostAddress convertedHostAddress = convertAddressProtocol(pHostAddress, pRequiredProtocol); + if (convertedHostAddress.isNull()) + { + return QUrl(); + } + + QUrl url; + url.setScheme(QStringLiteral("wss")); + url.setHost(convertedHostAddress.toString()); + url.setPort(pMsg->getPort()); + + return url; +} + + +} + + +RemoteDeviceDescriptor::RemoteDeviceDescriptorData::RemoteDeviceDescriptorData(const QString& pIfdName, + const QString& pIfdId, + const QStringList& pSupportedApis, + const QUrl& pRemoteUrl) + : mIfdName(pIfdName) + , mIfdId(pIfdId) + , mSupportedApis(pSupportedApis) + , mUrl(pRemoteUrl) +{ +} + + +RemoteDeviceDescriptor::RemoteDeviceDescriptorData::~RemoteDeviceDescriptorData() +{ +} + + +bool RemoteDeviceDescriptor::RemoteDeviceDescriptorData::operator==(const RemoteDeviceDescriptorData& pOther) const +{ + return mIfdName == pOther.mIfdName && + mIfdId == pOther.mIfdId && + mSupportedApis == pOther.mSupportedApis && + mUrl == pOther.mUrl; +} + + +RemoteDeviceDescriptor::RemoteDeviceDescriptorData* RemoteDeviceDescriptor::createRemoteDeviceDescriptorData(const QSharedPointer& pMsg, + const QHostAddress& pHostAddress, + QAbstractSocket::NetworkLayerProtocol pRequiredProtocol) +{ + const QUrl url = urlFromMsgAndHost(pMsg, pHostAddress, pRequiredProtocol); + if (url.isEmpty()) + { + return nullptr; + } + + const QString& ifdName = pMsg->getIfdName(); + const QString& ifdId = pMsg->getIfdId(); + const QStringList& supportedApis = pMsg->getSupportedApis(); + + return new RemoteDeviceDescriptorData(ifdName, ifdId, supportedApis, url); +} + + +RemoteDeviceDescriptor::RemoteDeviceDescriptor(const QSharedPointer& pDiscovery, + const QHostAddress& pHostAddress, + QAbstractSocket::NetworkLayerProtocol pRequiredProtocol) + : d(createRemoteDeviceDescriptorData(pDiscovery, pHostAddress, pRequiredProtocol)) +{ +} + + +const QString& RemoteDeviceDescriptor::getIfdName() const +{ + static const QString EMPTY_STRING; + + return d.data() == nullptr ? EMPTY_STRING : d->mIfdName; +} + + +const QString& RemoteDeviceDescriptor::getIfdId() const +{ + static const QString EMPTY_STRING; + + return d.data() == nullptr ? EMPTY_STRING : d->mIfdId; +} + + +const QStringList& RemoteDeviceDescriptor::getSupportedApis() const +{ + static const QStringList EMPTY_VECTOR; + + return d.data() == nullptr ? EMPTY_VECTOR : d->mSupportedApis; +} + + +const QUrl& RemoteDeviceDescriptor::getUrl() const +{ + static const QUrl EMPTY_URL; + + return d.data() == nullptr ? EMPTY_URL : d->mUrl; +} + + +bool RemoteDeviceDescriptor::isNull() const +{ + return d.data() == nullptr; +} + + +bool RemoteDeviceDescriptor::operator==(const RemoteDeviceDescriptor& pOther) const +{ + return this == &pOther || + (d.data() == nullptr && pOther.d.data() == nullptr) || + (d.data() != nullptr && pOther.d.data() != nullptr && *d == *(pOther.d)); +} diff --git a/src/remote_device/RemoteDeviceDescriptor.h b/src/remote_device/RemoteDeviceDescriptor.h new file mode 100644 index 0000000..bec85ba --- /dev/null +++ b/src/remote_device/RemoteDeviceDescriptor.h @@ -0,0 +1,78 @@ +/*! + * \brief Information needed to display a remote device in the GUI and to open + * a websocket connection to it. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include + + +namespace governikus +{ +class Discovery; + + +class RemoteDeviceDescriptor +{ + private: + class RemoteDeviceDescriptorData + : public QSharedData + { + public: + RemoteDeviceDescriptorData(const QString& pIfdName, + const QString& pIfdId, + const QStringList& pSupportedApis, + const QUrl& pUrl); + + virtual ~RemoteDeviceDescriptorData(); + + const QString mIfdName; + const QString mIfdId; + const QStringList mSupportedApis; + const QUrl mUrl; + bool operator==(const RemoteDeviceDescriptorData& pOther) const; + }; + + static RemoteDeviceDescriptorData* createRemoteDeviceDescriptorData(const QSharedPointer& pMsg, + const QHostAddress& pHostAddress, + QAbstractSocket::NetworkLayerProtocol pRequiredProtocol); + + const QSharedDataPointer d; + + public: + RemoteDeviceDescriptor() = default; + + RemoteDeviceDescriptor(const QSharedPointer& pDiscovery, + const QHostAddress& pHostAddress, + QAbstractSocket::NetworkLayerProtocol pRequiredProtocol = QAbstractSocket::IPv4Protocol); + + ~RemoteDeviceDescriptor() = default; + + const QString& getIfdName() const; + const QString& getIfdId() const; + const QStringList& getSupportedApis() const; + const QUrl& getUrl() const; + bool isNull() const; + + bool operator==(const RemoteDeviceDescriptor& pOther) const; + +}; + + +inline QDebug operator<<(QDebug pDbg, const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) +{ + QDebugStateSaver saver(pDbg); + return pDbg.noquote().nospace() << "RemoteDevice(" << pRemoteDeviceDescriptor.getIfdName() << ", " << + pRemoteDeviceDescriptor.getIfdId() << ", " << + pRemoteDeviceDescriptor.getUrl() << ", " << + pRemoteDeviceDescriptor.getSupportedApis() << ")"; +} + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteDeviceList.cpp b/src/remote_device/RemoteDeviceList.cpp new file mode 100644 index 0000000..70be0db --- /dev/null +++ b/src/remote_device/RemoteDeviceList.cpp @@ -0,0 +1,164 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceList.h" + +#include "Env.h" +#include "Initializer.h" + +using namespace governikus; + + +static Initializer::Entry E([] { + qRegisterMetaType >("QSharedPointer"); + qRegisterMetaType > >("QVector>"); + }); + + +namespace governikus +{ + +template<> RemoteDeviceList* createNewObject() +{ + return new RemoteDeviceListImpl; +} + + +template<> RemoteDeviceList* createNewObject(int&& pCheckInterval, int&& pTimeout) +{ + return new RemoteDeviceListImpl(pCheckInterval, pTimeout); +} + + +} /* namespace governikus */ + + +RemoteDeviceListEntry::RemoteDeviceListEntry(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) + : mRemoteDeviceDescriptor(pRemoteDeviceDescriptor) + , mLastSeen(QTime::currentTime()) +{ +} + + +void RemoteDeviceListEntry::setLastSeenToNow() +{ + mLastSeen = QTime::currentTime(); +} + + +bool RemoteDeviceListEntry::contains(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) const +{ + return mRemoteDeviceDescriptor == pRemoteDeviceDescriptor; +} + + +bool RemoteDeviceListEntry::isEqual(const RemoteDeviceListEntry* const pOther) const +{ + return pOther != nullptr && + mRemoteDeviceDescriptor == pOther->mRemoteDeviceDescriptor && + mLastSeen == pOther->mLastSeen; +} + + +const QTime& RemoteDeviceListEntry::getLastSeen() const +{ + return mLastSeen; +} + + +const RemoteDeviceDescriptor& RemoteDeviceListEntry::getRemoteDeviceDescriptor() const +{ + return mRemoteDeviceDescriptor; +} + + +RemoteDeviceList::RemoteDeviceList(int, int) +{ + +} + + +RemoteDeviceList::~RemoteDeviceList() +{ + +} + + +QVector > RemoteDeviceList::getRemoteDevices() const +{ + return QVector >(); +} + + +RemoteDeviceListImpl::RemoteDeviceListImpl(int pCheckInterval, int pTimeout) + : RemoteDeviceList(pCheckInterval, pTimeout) + , mTimer() + , mTimeout(pTimeout) + , mList() +{ + connect(&mTimer, &QTimer::timeout, this, &RemoteDeviceListImpl::onRemoveUnresponsiveRemoteReaders); + mTimer.setInterval(pCheckInterval); +} + + +RemoteDeviceListImpl::~RemoteDeviceListImpl() +{ + mTimer.stop(); +} + + +void RemoteDeviceListImpl::update(const RemoteDeviceDescriptor& pDescriptor) +{ + for (const QSharedPointer& entry : qAsConst(mList)) + { + if (entry->contains(pDescriptor)) + { + entry->setLastSeenToNow(); + return; + } + } + + const QSharedPointer newDevice(new RemoteDeviceListEntry(pDescriptor)); + mList.append(newDevice); + + if (!mTimer.isActive()) + { + mTimer.start(); + } + + Q_EMIT fireDeviceAppeared(newDevice); +} + + +void RemoteDeviceListImpl::clear() +{ + mList.clear(); +} + + +QVector > RemoteDeviceListImpl::getRemoteDevices() const +{ + return mList; +} + + +void RemoteDeviceListImpl::onRemoveUnresponsiveRemoteReaders() +{ + const QTime threshold(QTime::currentTime().addMSecs(-mTimeout)); + QMutableVectorIterator > i(mList); + while (i.hasNext()) + { + const QSharedPointer& pEntry = i.next(); + if (pEntry->getLastSeen() < threshold) + { + i.remove(); + Q_EMIT fireDeviceVanished(pEntry); + } + } + + if (mList.isEmpty()) + { + mTimer.stop(); + } +} diff --git a/src/remote_device/RemoteDeviceList.h b/src/remote_device/RemoteDeviceList.h new file mode 100644 index 0000000..d6d5f94 --- /dev/null +++ b/src/remote_device/RemoteDeviceList.h @@ -0,0 +1,82 @@ +/*! + * \brief Interface for RemoteDeviceList + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteDeviceDescriptor.h" + +#include +#include + + +namespace governikus +{ + +class RemoteDeviceListEntry +{ + Q_DISABLE_COPY(RemoteDeviceListEntry) + + private: + const RemoteDeviceDescriptor mRemoteDeviceDescriptor; + QTime mLastSeen; + + public: + RemoteDeviceListEntry(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor); + + void setLastSeenToNow(); + + bool contains(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor) const; + bool isEqual(const RemoteDeviceListEntry* const pOther) const; + + const QTime& getLastSeen() const; + const RemoteDeviceDescriptor& getRemoteDeviceDescriptor() const; + +}; + + +class RemoteDeviceList + : public QObject +{ + Q_OBJECT + + Q_SIGNALS: + void fireDeviceAppeared(const QSharedPointer&); + void fireDeviceVanished(const QSharedPointer&); + + public: + RemoteDeviceList(int pCheckInterval, int pTimeout); + virtual ~RemoteDeviceList(); + + virtual void update(const RemoteDeviceDescriptor& pDescriptor) = 0; + virtual void clear() = 0; + virtual QVector > getRemoteDevices() const; +}; + + +class RemoteDeviceListImpl + : public RemoteDeviceList +{ + Q_OBJECT + + private: + QTimer mTimer; + const int mTimeout; + QVector > mList; + + private Q_SLOTS: + void onRemoveUnresponsiveRemoteReaders(); + + public: + RemoteDeviceListImpl(int pCheckInterval = 1000, int pTimeout = 5000); + virtual ~RemoteDeviceListImpl() override; + + virtual void update(const RemoteDeviceDescriptor& pDescriptor) override; + virtual void clear() override; + virtual QVector > getRemoteDevices() const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteDeviceModel.cpp b/src/remote_device/RemoteDeviceModel.cpp new file mode 100644 index 0000000..1f687ab --- /dev/null +++ b/src/remote_device/RemoteDeviceModel.cpp @@ -0,0 +1,399 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceModel.h" + +#include "AppSettings.h" +#include "Env.h" +#include "LanguageLoader.h" +#include "ReaderManager.h" + +#include + + +using namespace governikus; + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString pDeviceName, const QString pId, QSharedPointer& pRemoteDeviceListEntry) + : mDeviceName(pDeviceName) + , mId(pId) + , mPaired(false) + , mNetworkVisible(false) + , mLastConnected() + , mRemoteDeviceListEntry(pRemoteDeviceListEntry) +{ + +} + + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString pDeviceName, const QString pId, bool pPaired, bool pNetworkVisible, const QDateTime& pLastConnected) + : mDeviceName(pDeviceName) + , mId(pId) + , mPaired(pPaired) + , mNetworkVisible(pNetworkVisible) + , mLastConnected(pLastConnected) + , mRemoteDeviceListEntry(nullptr) +{ + +} + + +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString pDeviceName) + : mDeviceName(pDeviceName) + , mId() + , mPaired(false) + , mNetworkVisible(false) + , mLastConnected() + , mRemoteDeviceListEntry(nullptr) +{ + +} + + +const QSharedPointer RemoteDeviceModelEntry::getRemoteDeviceListEntry() const +{ + return mRemoteDeviceListEntry; +} + + +QString RemoteDeviceModelEntry::getDeviceName() const +{ + return mDeviceName; +} + + +bool RemoteDeviceModelEntry::isPaired() const +{ + return mPaired; +} + + +void RemoteDeviceModelEntry::setPaired(bool pPaired) +{ + mPaired = pPaired; +} + + +const QString& RemoteDeviceModelEntry::getId() const +{ + return mId; +} + + +void RemoteDeviceModelEntry::setId(QString pId) +{ + mId = pId; +} + + +bool RemoteDeviceModelEntry::isNetworkVisible() const +{ + return mNetworkVisible; +} + + +void RemoteDeviceModelEntry::setNetworkVisible(bool pNetworkVisible) +{ + mNetworkVisible = pNetworkVisible; +} + + +const QDateTime& RemoteDeviceModelEntry::getLastConnected() const +{ + return mLastConnected; +} + + +void RemoteDeviceModelEntry::setLastConnected(const QDateTime& pLastConnected) +{ + mLastConnected = pLastConnected; +} + + +RemoteDeviceModel::RemoteDeviceModel(QObject* pParent, bool pShowPairedReaders, bool pShowUnpairedReaders) + : QAbstractTableModel(pParent) + , mPairedReaders() + , mAllRemoteReaders() + , mShowPairedReaders(pShowPairedReaders) + , mShowUnpairedReaders(pShowUnpairedReaders) +{ + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + connect(&settings, &RemoteServiceSettings::fireTrustedRemoteInfosChanged, this, &RemoteDeviceModel::onKnownRemoteReadersChanged); + onKnownRemoteReadersChanged(); +} + + +RemoteDeviceModel::~RemoteDeviceModel() +{ + if (mShowUnpairedReaders) + { + onWidgetHidden(); + } +} + + +QHash RemoteDeviceModel::roleNames() const +{ + QHash roles = QAbstractItemModel::roleNames(); + roles.insert(REMOTE_DEVICE_NAME, QByteArrayLiteral("remoteDeviceName")); + roles.insert(LAST_CONNECTED, QByteArrayLiteral("lastConnected")); + roles.insert(DEVICE_ID, QByteArrayLiteral("deviceId")); + roles.insert(IS_NETWORK_VISIBLE, QByteArrayLiteral("isNetworkVisible")); + return roles; +} + + +QString RemoteDeviceModel::getStatus(const RemoteDeviceModelEntry& pRemoteDeviceModelEntry) const +{ + if (mAllRemoteReaders.isEmpty()) + { + return tr("Not connected"); + } + + if (pRemoteDeviceModelEntry.isPaired()) + { + if (pRemoteDeviceModelEntry.isNetworkVisible()) + { + return tr("Paired and available"); + } + else + { + return tr("Paired and not available"); + } + } + else + { + return tr("Not paired"); + } +} + + +QVariant RemoteDeviceModel::headerData(int pSection, Qt::Orientation pOrientation, int pRole) const +{ + if (pRole == Qt::DisplayRole && pOrientation == Qt::Horizontal) + { + switch (pSection) + { + case ColumnId::ReaderName: + return tr("Device"); + + case ColumnId::ReaderStatus: + return tr("Status"); + + default: + return QVariant(); + } + } + return QVariant(); +} + + +int RemoteDeviceModel::rowCount(const QModelIndex&) const +{ + return mAllRemoteReaders.size(); +} + + +int RemoteDeviceModel::columnCount(const QModelIndex&) const +{ + return NUMBER_OF_COLUMNS; +} + + +QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const +{ + const auto& reader = mAllRemoteReaders.at(pIndex.row()); + switch (pRole) + { + case Qt::DisplayRole: + switch (pIndex.column()) + { + case ColumnId::ReaderName: + return reader.getDeviceName(); + + case ColumnId::ReaderStatus: + return getStatus(reader); + } + + case REMOTE_DEVICE_NAME: + return reader.getDeviceName(); + + case LAST_CONNECTED: + { + const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + const auto& dateTimeFormat = tr("dd.MM.YYYY hh:mm AP"); + return locale.toString(reader.getLastConnected(), dateTimeFormat); + } + + case DEVICE_ID: + return reader.getId(); + + case IS_NETWORK_VISIBLE: + return reader.isNetworkVisible(); + + default: + return QVariant(); + } + + Q_UNREACHABLE(); +} + + +const QSharedPointer RemoteDeviceModel::getRemoteDeviceListEntry(const QModelIndex& pIndex) const +{ + const int row = pIndex.row(); + if (row < 0 || row >= mAllRemoteReaders.size()) + { + return QSharedPointer(); + } + + return mAllRemoteReaders.at(row).getRemoteDeviceListEntry(); +} + + +const QSharedPointer RemoteDeviceModel::getRemoteDeviceListEntry(QString pDeviceId) const +{ + for (const auto& device : mAllRemoteReaders) + { + if (device.getId() == pDeviceId) + { + return device.getRemoteDeviceListEntry(); + } + } + return QSharedPointer(); +} + + +bool RemoteDeviceModel::isPaired(const QModelIndex& pIndex) const +{ + return mAllRemoteReaders.at(pIndex.row()).isPaired(); +} + + +void RemoteDeviceModel::onWidgetShown() +{ + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireDeviceAppeared, this, &RemoteDeviceModel::constructReaderList); + connect(remoteClient.data(), &RemoteClient::fireDeviceVanished, this, &RemoteDeviceModel::constructReaderList); + + if (!mShowUnpairedReaders) + { + return; + } + + qDebug() << "Starting Remote Device Detection"; + remoteClient->startDetection(); + constructReaderList(); +} + + +void RemoteDeviceModel::onWidgetHidden() +{ + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + disconnect(remoteClient.data(), &RemoteClient::fireDeviceAppeared, this, &RemoteDeviceModel::constructReaderList); + disconnect(remoteClient.data(), &RemoteClient::fireDeviceVanished, this, &RemoteDeviceModel::constructReaderList); + + if (!mShowUnpairedReaders) + { + return; + } + + qDebug() << "Stopping Remote Device Detection"; + remoteClient->stopDetection(); +} + + +void RemoteDeviceModel::onKnownRemoteReadersChanged() +{ + mPairedReaders.clear(); + + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + auto pairedReaders = settings.getRemoteInfos(); + for (const auto& reader : pairedReaders) + { + mPairedReaders[reader.getFingerprint()] = reader; + } + + constructReaderList(); +} + + +void RemoteDeviceModel::constructReaderList() +{ + beginResetModel(); + mAllRemoteReaders.clear(); + + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + + if (mShowPairedReaders) + { + for (const auto& pairedReader : qAsConst(mPairedReaders)) + { + bool found = false; + if (remoteClient) + { + const QVector >& foundDevices = remoteClient->getRemoteDevices(); + + for (const auto& foundDevice : foundDevices) + { + if (foundDevice && foundDevice->getRemoteDeviceDescriptor().getIfdId() == pairedReader.getFingerprint()) + { + found = true; + } + } + } + + auto newEntry = RemoteDeviceModelEntry(pairedReader.getName() + , pairedReader.getFingerprint() + , true + , found + , pairedReader.getLastConnected()); + mAllRemoteReaders.append(newEntry); + } + } + + if (mShowUnpairedReaders && remoteClient) + { + const QVector >& remoteDevices = remoteClient->getRemoteDevices(); + + for (auto deviceListEntry : remoteDevices) + { + if (!mPairedReaders.contains(deviceListEntry->getRemoteDeviceDescriptor().getIfdId())) + { + const RemoteDeviceDescriptor& descriptor = deviceListEntry->getRemoteDeviceDescriptor(); + mAllRemoteReaders.append(RemoteDeviceModelEntry(descriptor.getIfdName(), descriptor.getIfdId(), deviceListEntry)); + } + } + } + + std::sort(mAllRemoteReaders.begin(), mAllRemoteReaders.end(), [](const RemoteDeviceModelEntry& pFirst, const RemoteDeviceModelEntry& pSecond){ + return pFirst.getDeviceName() < pSecond.getDeviceName(); + }); + + endResetModel(); + Q_EMIT fireModelChanged(); +} + + +void RemoteDeviceModel::forgetDevice(const QModelIndex& pIndex) +{ + auto& modelEntry = mAllRemoteReaders.at(pIndex.row()); + const QString& id = modelEntry.getId(); + + forgetDevice(id); +} + + +void RemoteDeviceModel::forgetDevice(const QString& pDeviceId) +{ + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + settings.removeTrustedCertificate(pDeviceId); +} + + +void RemoteDeviceModel::onDeviceDisconnected(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher) +{ + Q_UNUSED(pCloseCode); + Q_UNUSED(pRemoteDispatcher); + constructReaderList(); +} diff --git a/src/remote_device/RemoteDeviceModel.h b/src/remote_device/RemoteDeviceModel.h new file mode 100644 index 0000000..a5966dd --- /dev/null +++ b/src/remote_device/RemoteDeviceModel.h @@ -0,0 +1,112 @@ +/*! + * \brief Model implementation for the remote device table + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" +#include "ReaderConfigurationInfo.h" +#include "RemoteDeviceDescriptor.h" +#include "RemoteDeviceList.h" +#include "RemoteDispatcher.h" +#include "RemoteServiceSettings.h" + +#include +#include +#include +#include + + +namespace governikus +{ + +class RemoteDeviceModelEntry +{ + private: + QString mDeviceName; + QString mId; + bool mPaired; + bool mNetworkVisible; + QDateTime mLastConnected; + QSharedPointer mRemoteDeviceListEntry; + + public: + RemoteDeviceModelEntry(const QString pDeviceName, const QString mId, QSharedPointer& pRemoteDeviceListEntry); + RemoteDeviceModelEntry(const QString pDeviceName, const QString mId, bool pPaired, bool pNetworkVisible, const QDateTime& pLastConnected); + RemoteDeviceModelEntry(const QString pDeviceName = QStringLiteral("UnknownReader")); + + bool isPaired() const; + void setPaired(bool pPaired); + const QString& getId() const; + void setId(QString pId); + bool isNetworkVisible() const; + void setNetworkVisible(bool pNetworkVisible); + const QDateTime& getLastConnected() const; + void setLastConnected(const QDateTime& pLastConnected); + + const QSharedPointer getRemoteDeviceListEntry() const; + QString getDeviceName() const; + +}; + +class RemoteDeviceModel + : public QAbstractTableModel +{ + Q_OBJECT + + private: + const int NUMBER_OF_COLUMNS = 2; + + QMap mPairedReaders; + QVector mAllRemoteReaders; + const bool mShowPairedReaders; + const bool mShowUnpairedReaders; + + QString getStatus(const RemoteDeviceModelEntry& pRemoteDeviceModelEntry) const; + void constructReaderList(); + + public: + enum SettingsRemoteRoles + { + REMOTE_DEVICE_NAME = Qt::UserRole + 1, + LAST_CONNECTED, + DEVICE_ID, + IS_NETWORK_VISIBLE + }; + + enum ColumnId : int + { + ReaderName = 0, + ReaderStatus = 1 + }; + + RemoteDeviceModel(QObject* pParent = nullptr, bool pShowPairedReaders = true, bool pShowUnpairedReaders = true); + virtual ~RemoteDeviceModel() override; + + virtual QVariant headerData(int pSection, Qt::Orientation pOrientation, int pRole) const override; + virtual int rowCount(const QModelIndex& pParent = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& pParent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; + virtual QHash roleNames() const override; + + const QSharedPointer getRemoteDeviceListEntry(const QModelIndex& pIndex) const; + const QSharedPointer getRemoteDeviceListEntry(QString pDeviceId) const; + bool isPaired(const QModelIndex& pIndex) const; + void forgetDevice(const QModelIndex& pIndex); + void forgetDevice(const QString& pDeviceId); + + public Q_SLOTS: + void onWidgetShown(); + void onWidgetHidden(); + void onKnownRemoteReadersChanged(); + void onDeviceDisconnected(GlobalStatus::Code pCloseCode, const QSharedPointer& pRemoteDispatcher); + + Q_SIGNALS: + void fireModelChanged(); + +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteDispatcherImpl.cpp b/src/remote_device/RemoteDispatcherImpl.cpp new file mode 100644 index 0000000..450e205 --- /dev/null +++ b/src/remote_device/RemoteDispatcherImpl.cpp @@ -0,0 +1,180 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDispatcherImpl.h" + +#include "AppSettings.h" +#include "Env.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +namespace governikus +{ +template<> RemoteDispatcher* createNewObject&>(const QSharedPointer& pChannel) +{ + return new RemoteDispatcherImpl(pChannel); +} + + +} /* namespace governikus */ + + +using namespace governikus; + + +void RemoteDispatcherImpl::createAndSendContext(const QJsonObject& pMessageObject) +{ + QString fail; + + if (!mContextHandle.isEmpty()) + { + qCWarning(remote_device) << "Context already established. Additional contexts are not supported"; + fail = QStringLiteral("/al/common#unknownError"); + } + + IfdEstablishContext establishContext(pMessageObject); + if (establishContext.getProtocol() != QLatin1String("IFDInterface_WebSocket_v0")) + { + qCWarning(remote_device) << "Unsupported API protocol requested:" << establishContext.getProtocol(); + fail = QStringLiteral("/al/common#unknownError"); + } + + const auto& settings = AppSettings::getInstance().getRemoteServiceSettings(); + const QString& serverName = settings.getServerName(); + if (!fail.isEmpty()) + { + qCDebug(remote_device) << "Cannot create a new ContextHandle:" << fail; + IfdEstablishContextResponse response(serverName, fail); + mDataChannel->send(response.toJson(QUuid::createUuid().toString()).toJson(QJsonDocument::Compact)); + return; + } + + IfdEstablishContextResponse response(serverName); + mContextHandle = QUuid::createUuid().toString(); + qCDebug(remote_device) << "Creating new ContextHandle:" << mContextHandle; + mDataChannel->send(response.toJson(mContextHandle).toJson(QJsonDocument::Compact)); +} + + +void RemoteDispatcherImpl::saveRemoteNameInSettings(const QString& pName) +{ + RemoteServiceSettings& settings = AppSettings::getInstance().getRemoteServiceSettings(); + auto info = settings.getRemoteInfo(getId()); + info.setName(pName); + settings.updateRemoteInfo(info); +} + + +void RemoteDispatcherImpl::onReceived(const QByteArray& pDataBlock) +{ + const auto& msgObject = RemoteMessage::parseByteArray(pDataBlock); + RemoteMessage remoteMessage(msgObject); + + if (remoteMessage.getType() == RemoteCardMessageType::UNDEFINED) + { + qCWarning(remote_device) << "Invalid message received:" << pDataBlock; + + const QSharedPointer errorMessage(new IfdError(QString(), QStringLiteral("/al/common#unknownAPIFunction"))); + send(errorMessage); + + return; + } + + if (remoteMessage.getType() == RemoteCardMessageType::IFDError) + { + qCWarning(remote_device) << "Error message received:" << pDataBlock; + return; + } + + if (remoteMessage.getType() == RemoteCardMessageType::IFDEstablishContext) + { + IfdEstablishContext establishContext(msgObject); + + saveRemoteNameInSettings(establishContext.getUdName()); + + createAndSendContext(msgObject); + return; + } + + const auto& contextHandle = remoteMessage.getContextHandle(); + if (remoteMessage.getType() == RemoteCardMessageType::IFDEstablishContextResponse) + { + IfdEstablishContextResponse establishContextResponse(msgObject); + if (establishContextResponse.resultHasError()) + { + qCWarning(remote_device) << "Establish context failed with result minor:" << establishContextResponse.getResultMinor(); + return; + } + + mContextHandle = establishContextResponse.getContextHandle(); + qCDebug(remote_device) << "Received new ContextHandle:" << mContextHandle; + } + + if (contextHandle.isEmpty() || mContextHandle != contextHandle) + { + qCWarning(remote_device) << "Invalid context handle received. Expecting:" << mContextHandle << "but got:" << pDataBlock; + return; + } + + qCDebug(remote_device) << "Received message type:" << remoteMessage.getType(); + Q_EMIT fireReceived(mParser.parse(pDataBlock), sharedFromThis()); +} + + +void RemoteDispatcherImpl::onClosed(GlobalStatus::Code pCloseCode) +{ + qCDebug(remote_device) << "Connection closed"; + + Q_EMIT fireClosed(pCloseCode, sharedFromThis()); +} + + +RemoteDispatcherImpl::RemoteDispatcherImpl(const QSharedPointer& pDataChannel) + : RemoteDispatcher() + , mDataChannel(pDataChannel) + , mParser() +{ + connect(mDataChannel.data(), &DataChannel::fireClosed, this, &RemoteDispatcherImpl::onClosed); + connect(mDataChannel.data(), &DataChannel::fireReceived, this, &RemoteDispatcherImpl::onReceived); +} + + +RemoteDispatcherImpl::~RemoteDispatcherImpl() +{ + disconnect(mDataChannel.data(), &DataChannel::fireClosed, this, &RemoteDispatcherImpl::onClosed); + disconnect(mDataChannel.data(), &DataChannel::fireReceived, this, &RemoteDispatcherImpl::onReceived); + + mDataChannel->close(); +} + + +const QString& RemoteDispatcherImpl::getId() const +{ + return mDataChannel->getId(); +} + + +const QString& RemoteDispatcherImpl::getContextHandle() const +{ + return mContextHandle; +} + + +void RemoteDispatcherImpl::send(const QSharedPointer& pMessage) +{ + const RemoteCardMessageType messageType = pMessage->getType(); + + qCDebug(remote_device) << "Send message of type:" << messageType; + Q_ASSERT(messageType == RemoteCardMessageType::IFDError || messageType == RemoteCardMessageType::IFDEstablishContext || !mContextHandle.isEmpty()); + + mDataChannel->send(pMessage->toJson(mContextHandle).toJson(QJsonDocument::Compact)); +} diff --git a/src/remote_device/RemoteDispatcherImpl.h b/src/remote_device/RemoteDispatcherImpl.h new file mode 100644 index 0000000..67ebfd0 --- /dev/null +++ b/src/remote_device/RemoteDispatcherImpl.h @@ -0,0 +1,42 @@ +/*! + * \brief Class that dispatches incoming and outgoing remote messages. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "DataChannel.h" +#include "messages/RemoteMessageParser.h" +#include "RemoteDispatcher.h" + + +namespace governikus +{ +class RemoteDispatcherImpl + : public RemoteDispatcher +{ + Q_OBJECT + + private: + const QSharedPointer mDataChannel; + const RemoteMessageParser mParser; + QString mContextHandle; + + void createAndSendContext(const QJsonObject& pMessageObject); + void saveRemoteNameInSettings(const QString& pName); + + private Q_SLOTS: + void onReceived(const QByteArray& pDataBlock); + void onClosed(GlobalStatus::Code pCloseCode); + + public: + RemoteDispatcherImpl(const QSharedPointer& pDataChannel); + virtual ~RemoteDispatcherImpl() override; + + virtual const QString& getId() const override; + virtual const QString& getContextHandle() const override; + Q_INVOKABLE virtual void send(const QSharedPointer& pMessage) override; +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteHelper.cpp b/src/remote_device/RemoteHelper.cpp new file mode 100644 index 0000000..e1b23d0 --- /dev/null +++ b/src/remote_device/RemoteHelper.cpp @@ -0,0 +1,36 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteHelper.h" + +#include "AppSettings.h" +#include "Env.h" +#include "KeyPair.h" +#include "TlsChecker.h" + +using namespace governikus; + +bool RemoteHelper::checkAndGenerateKey() +{ + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + + if (settings.getKey().isNull() + || settings.getCertificate().isNull() + || settings.getCertificate().expiryDate() < QDateTime::currentDateTime() + || !TlsChecker::hasValidCertificateKeyLength(settings.getCertificate())) + { + qDebug() << "Generate local keypair..."; + const auto& pair = KeyPair::generate(); + if (pair.isValid()) + { + settings.setKey(pair.getKey()); + settings.setCertificate(pair.getCertificate()); + return true; + } + + return false; + } + + return true; +} diff --git a/src/remote_device/RemoteHelper.h b/src/remote_device/RemoteHelper.h new file mode 100644 index 0000000..f7f34dd --- /dev/null +++ b/src/remote_device/RemoteHelper.h @@ -0,0 +1,22 @@ +/*! + * \brief Helper for some miscellaneous methods. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +namespace governikus +{ + +class RemoteHelper +{ + private: + RemoteHelper() = delete; + + public: + static bool checkAndGenerateKey(); +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteReaderAdvertiser.cpp b/src/remote_device/RemoteReaderAdvertiser.cpp new file mode 100644 index 0000000..3e7c066 --- /dev/null +++ b/src/remote_device/RemoteReaderAdvertiser.cpp @@ -0,0 +1,66 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteReaderAdvertiser.h" + +#include "DatagramHandler.h" +#include "Env.h" +#include "messages/Discovery.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +namespace governikus +{ + +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort) +{ + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort); +} + + +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pTimerInterval) +{ + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pTimerInterval); +} + + +} /* namespace governikus */ + + +using namespace governikus; + + +RemoteReaderAdvertiser::~RemoteReaderAdvertiser() +{ +} + + +void RemoteReaderAdvertiserImpl::timerEvent(QTimerEvent* pEvent) +{ + if (pEvent->timerId() == mTimerId) + { + mHandler->send(mDiscovery); + } +} + + +RemoteReaderAdvertiserImpl::~RemoteReaderAdvertiserImpl() +{ + qCDebug(remote_device) << "Stop advertising"; +} + + +RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval) + : RemoteReaderAdvertiser() + , mHandler(Env::create(false)) + , mTimerId(startTimer(pTimerInterval)) + , mDiscovery(Discovery(pIfdName, pIfdId, pPort, {QStringLiteral("IFDInterface_WebSocket_v0")}).toJson()) +{ + qCDebug(remote_device) << "Start advertising every" << pTimerInterval << "msecs"; +} diff --git a/src/remote_device/RemoteReaderAdvertiser.h b/src/remote_device/RemoteReaderAdvertiser.h new file mode 100644 index 0000000..6934e31 --- /dev/null +++ b/src/remote_device/RemoteReaderAdvertiser.h @@ -0,0 +1,53 @@ +/*! + * \brief Component advertising the remote reader functionality + * on the server side. According to the concept this is done by + * sending the message REMOTE_READER_OFFER as a UDP broadcast. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + + +namespace governikus +{ + + +class RemoteReaderAdvertiser + : public QObject +{ + Q_OBJECT + + protected: + RemoteReaderAdvertiser() = default; + + public: + virtual ~RemoteReaderAdvertiser(); +}; + + +class DatagramHandler; + + +class RemoteReaderAdvertiserImpl + : public RemoteReaderAdvertiser +{ + Q_OBJECT + + const QScopedPointer mHandler; + const int mTimerId; + const QJsonDocument mDiscovery; + + void timerEvent(QTimerEvent* pEvent) override; + + public: + virtual ~RemoteReaderAdvertiserImpl() override; + RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval = 1000); +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteServer.cpp b/src/remote_device/RemoteServer.cpp new file mode 100644 index 0000000..7b053aa --- /dev/null +++ b/src/remote_device/RemoteServer.cpp @@ -0,0 +1,111 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteServer.h" + +#include "AppSettings.h" +#include "Env.h" +#include "RemoteReaderAdvertiser.h" +#include "RemoteWebSocketServer.h" + + +using namespace governikus; + + +namespace governikus +{ + +template<> RemoteServer* createNewObject() +{ + return new RemoteServerImpl; +} + + +} + + +RemoteServer::~RemoteServer() +{ +} + + +void RemoteServerImpl::onConnectedChanged(bool pConnected) +{ + if (pConnected) + { + mRemoteReaderAdvertiser.reset(); + return; + } + + if (isRunning() && !pConnected) + { + const auto& ifdName = mWebSocketServer->getServerName(); + const auto& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); + const auto& ifdId = RemoteServiceSettings::generateFingerprint(remoteServiceSettings.getCertificate()); + quint16 port = mWebSocketServer->getServerPort(); + mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port)); + return; + } +} + + +RemoteServerImpl::RemoteServerImpl() + : RemoteServer() + , mRemoteReaderAdvertiser() + , mWebSocketServer(Env::create()) +{ + connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireConnectedChanged, this, &RemoteServerImpl::onConnectedChanged); + connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireConnectedChanged, this, &RemoteServerImpl::fireConnectedChanged); + connect(mWebSocketServer.data(), &RemoteWebSocketServer::fireMessageHandlerAdded, this, &RemoteServer::fireMessageHandlerAdded); + connect(mWebSocketServer.data(), &RemoteWebSocketServer::firePskChanged, this, &RemoteServer::firePskChanged); +} + + +bool RemoteServerImpl::isRunning() const +{ + return mWebSocketServer->isListening(); +} + + +bool RemoteServerImpl::start(const QString& pServerName) +{ + bool success = mWebSocketServer->listen(pServerName); + if (success) + { + onConnectedChanged(false); + } + return success; +} + + +void RemoteServerImpl::stop() +{ + mRemoteReaderAdvertiser.reset(); + mWebSocketServer->close(); +} + + +void RemoteServerImpl::setPairing(bool pEnable) +{ + mWebSocketServer->setPairing(pEnable); +} + + +bool RemoteServerImpl::isConnected() const +{ + return mWebSocketServer->isConnected(); +} + + +QSslCertificate RemoteServerImpl::getCurrentCertificate() const +{ + return mWebSocketServer->getCurrentCertificate(); +} + + +const QSharedPointer& RemoteServerImpl::getMessageHandler() const +{ + Q_ASSERT(mWebSocketServer); + return mWebSocketServer->getMessageHandler(); +} diff --git a/src/remote_device/RemoteServer.h b/src/remote_device/RemoteServer.h new file mode 100644 index 0000000..c28189f --- /dev/null +++ b/src/remote_device/RemoteServer.h @@ -0,0 +1,75 @@ +/*! + * \brief Remote server service to offer remote readers. + * This class controls the advertising over UDP as well as the Websocket connection management. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace governikus +{ + +class ServerMessageHandler; + +class RemoteServer + : public QObject +{ + Q_OBJECT + + protected: + RemoteServer() = default; + + public: + virtual ~RemoteServer(); + + virtual bool isRunning() const = 0; + virtual bool start(const QString& pServerName) = 0; + virtual void stop() = 0; + virtual void setPairing(bool pEnable = true) = 0; + virtual bool isConnected() const = 0; + virtual QSslCertificate getCurrentCertificate() const = 0; + virtual const QSharedPointer& getMessageHandler() const = 0; + + Q_SIGNALS: + void fireMessageHandlerAdded(QSharedPointer pHandler); + void firePskChanged(const QByteArray& pPsk); + void fireConnectedChanged(bool pConnected); +}; + + +class RemoteReaderAdvertiser; +class RemoteWebSocketServer; + + +class RemoteServerImpl + : public RemoteServer +{ + Q_OBJECT + + private: + QScopedPointer mRemoteReaderAdvertiser; + QScopedPointer mWebSocketServer; + + private Q_SLOTS: + void onConnectedChanged(bool pConnected); + + public: + RemoteServerImpl(); + + virtual bool isRunning() const override; + virtual bool start(const QString& pServerName) override; + virtual void stop() override; + virtual void setPairing(bool pEnable = true) override; + virtual bool isConnected() const override; + virtual QSslCertificate getCurrentCertificate() const override; + virtual const QSharedPointer& getMessageHandler() const override; +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteTlsServer.cpp b/src/remote_device/RemoteTlsServer.cpp new file mode 100644 index 0000000..321023b --- /dev/null +++ b/src/remote_device/RemoteTlsServer.cpp @@ -0,0 +1,200 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteTlsServer.h" + +#include "AppSettings.h" +#include "Env.h" +#include "Randomizer.h" +#include "RemoteHelper.h" +#include "SecureStorage.h" +#include "TlsChecker.h" + +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + +using namespace governikus; + + +RemoteTlsServer::RemoteTlsServer() + : QTcpServer() + , mPsk() +{ +#ifndef QT_NO_NETWORKPROXY + //listening with proxy leads to socket error QNativeSocketEnginePrivate::InvalidProxyTypeString + setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); +#endif +} + + +bool RemoteTlsServer::listen() +{ + if (isListening()) + { + return false; + } + + if (!RemoteHelper::checkAndGenerateKey()) + { + qCCritical(remote_device) << "Cannot get required key/certificate for tls"; + return false; + } + + static quint16 usedServerPort = 0; + if (!QTcpServer::listen(QHostAddress::Any, usedServerPort)) + { + qCCritical(remote_device) << "Listen failed:" << serverError() << ", " << errorString(); + return false; + } + + if (usedServerPort == 0) + { + usedServerPort = serverPort(); + } + return true; +} + + +void RemoteTlsServer::incomingConnection(qintptr pSocketDescriptor) +{ + if (mSocket.isNull()) + { + mSocket = new QSslSocket(); + + const auto cipherCfg = mPsk.isEmpty() ? SecureStorage::TlsSuite::DEFAULT : SecureStorage::TlsSuite::PSK; + QSslConfiguration config = SecureStorage::getInstance().getTlsConfigRemote(cipherCfg).getConfiguration(); + const auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + config.setPrivateKey(settings.getKey()); + config.setLocalCertificate(settings.getCertificate()); + config.setPeerVerifyMode(QSslSocket::VerifyPeer); + if (mPsk.isEmpty()) + { + config.setCaCertificates(settings.getTrustedCertificates()); + } + mSocket->setSslConfiguration(config); + + if (Q_LIKELY(mSocket->setSocketDescriptor(pSocketDescriptor))) + { + connect(mSocket.data(), QOverload&>::of(&QSslSocket::sslErrors), + this, &RemoteTlsServer::onSslErrors); + + connect(mSocket.data(), QOverload::of(&QAbstractSocket::error), + this, &RemoteTlsServer::onError); + + connect(mSocket.data(), &QSslSocket::preSharedKeyAuthenticationRequired, + this, &RemoteTlsServer::onPreSharedKeyAuthenticationRequired); + + connect(mSocket.data(), &QSslSocket::encrypted, + this, &RemoteTlsServer::onEncrypted); + + mSocket->startServerEncryption(); + } + else + { + delete mSocket.data(); + } + } + else + { + QTcpSocket socket; + socket.setSocketDescriptor(pSocketDescriptor); + socket.abort(); + qCDebug(remote_device) << "Socket already connected..."; + } +} + + +void RemoteTlsServer::onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) +{ + qCDebug(remote_device) << "Client requests pairing | identity:" << pAuthenticator->identity() << "| hint:" << pAuthenticator->identityHint(); + pAuthenticator->setPreSharedKey(mPsk); +} + + +void RemoteTlsServer::onError(QAbstractSocket::SocketError pSocketError) +{ + qCDebug(remote_device) << "Socket error:" << pSocketError; + mSocket->deleteLater(); +} + + +void RemoteTlsServer::onSslErrors(const QList& pErrors) +{ + if (pErrors.size() == 1 && pErrors.first().error() == QSslError::SelfSignedCertificate) + { + const auto& pairingCiphers = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + if (pairingCiphers.contains(mSocket->sessionCipher())) + { + qCDebug(remote_device) << "Client requests pairing | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate(); + mSocket->ignoreSslErrors(); + return; + } + } + + qCDebug(remote_device) << "Client is not allowed | cipher:" << mSocket->sessionCipher() << "| certificate:" << mSocket->peerCertificate() << "| error:" << pErrors; +} + + +void RemoteTlsServer::onEncrypted() +{ + const auto& cfg = mSocket->sslConfiguration(); + TlsChecker::logSslConfig(cfg, qInfo(remote_device)); + + if (!TlsChecker::hasValidCertificateKeyLength(cfg.peerCertificate())) + { + qCCritical(remote_device) << "Client denied... abort connection!"; + mSocket->abort(); + mSocket->deleteLater(); + return; + } + + qCDebug(remote_device) << "Client connected"; + + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + const auto& pairingCiphers = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + if (pairingCiphers.contains(cfg.sessionCipher())) + { + qCDebug(remote_device) << "Pairing completed | Add certificate:" << cfg.peerCertificate(); + settings.addTrustedCertificate(cfg.peerCertificate()); + settings.save(); + setPairing(false); + } + else + { + auto info = settings.getRemoteInfo(cfg.peerCertificate()); + info.setLastConnected(QDateTime::currentDateTime()); + settings.updateRemoteInfo(info); + } + + mSocket->disconnect(this); + Q_EMIT newConnection(mSocket.data()); +} + + +void RemoteTlsServer::setPairing(bool pEnable) +{ + if (pEnable) + { + std::uniform_int_distribution uni(0, 9999); + QByteArray pin = QByteArray::number(uni(Randomizer::getInstance().getGenerator())); + pin.prepend(4 - pin.size(), '0'); + mPsk = pin; + Q_EMIT firePskChanged(mPsk); + } + else if (!mPsk.isEmpty()) + { + mPsk.clear(); + Q_EMIT firePskChanged(mPsk); + } +} + + +QSslCertificate RemoteTlsServer::getCurrentCertificate() const +{ + return mSocket ? mSocket->sslConfiguration().peerCertificate() : QSslCertificate(); +} diff --git a/src/remote_device/RemoteTlsServer.h b/src/remote_device/RemoteTlsServer.h new file mode 100644 index 0000000..1f1f2c3 --- /dev/null +++ b/src/remote_device/RemoteTlsServer.h @@ -0,0 +1,46 @@ +/*! + * \brief QTcpServer with necessary TLS handling of remote device configuration. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace governikus +{ + +class RemoteTlsServer + : public QTcpServer +{ + Q_OBJECT + + private: + QPointer mSocket; + QByteArray mPsk; + virtual void incomingConnection(qintptr pSocketDescriptor) override; + + private Q_SLOTS: + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator); + void onError(QAbstractSocket::SocketError pSocketError); + void onSslErrors(const QList& pErrors); + void onEncrypted(); + + public: + RemoteTlsServer(); + bool listen(); + void setPairing(bool pEnable = true); + QSslCertificate getCurrentCertificate() const; + + Q_SIGNALS: + void newConnection(QTcpSocket* pSocket); + void firePskChanged(const QByteArray& pPsk); +}; + +} /* namespace governikus */ diff --git a/src/remote_device/RemoteWebSocketServer.cpp b/src/remote_device/RemoteWebSocketServer.cpp new file mode 100644 index 0000000..1955d82 --- /dev/null +++ b/src/remote_device/RemoteWebSocketServer.cpp @@ -0,0 +1,153 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteWebSocketServer.h" + +#include "AppSettings.h" +#include "Env.h" +#include "SecureStorage.h" +#include "ServerMessageHandler.h" +#include "WebSocketChannel.h" + +#include +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + +namespace governikus +{ +template<> RemoteWebSocketServer* createNewObject() +{ + return new RemoteWebSocketServerImpl; +} + + +} /* namespace governikus */ + +using namespace governikus; + + +RemoteWebSocketServer::~RemoteWebSocketServer() +{ +} + + +void RemoteWebSocketServerImpl::onWebsocketConnection() +{ + if (!mServer.hasPendingConnections()) + { + return; + } + + QSharedPointer connection(mServer.nextPendingConnection()); + if (mServerMessageHandler) + { + connection->close(QWebSocketProtocol::CloseCodePolicyViolated); + return; + } + + QSharedPointer channel(new WebSocketChannel(connection), &QObject::deleteLater); + mServerMessageHandler.reset(Env::create(channel)); + connect(mServerMessageHandler.data(), &ServerMessageHandler::fireClosed, this, &RemoteWebSocketServerImpl::onConnectionClosed); + Q_EMIT fireConnectedChanged(isConnected()); + Q_EMIT fireMessageHandlerAdded(mServerMessageHandler); +} + + +void RemoteWebSocketServerImpl::onConnectionClosed() +{ + mServerMessageHandler.reset(); + Q_EMIT fireConnectedChanged(isConnected()); +} + + +void RemoteWebSocketServerImpl::onServerError(QWebSocketProtocol::CloseCode pCloseCode) +{ + static int timesLogged = 0; + if (timesLogged < 20) + { + qCCritical(remote_device) << pCloseCode; + timesLogged++; + } +} + + +RemoteWebSocketServerImpl::RemoteWebSocketServerImpl() + : mTlsServer(new RemoteTlsServer) + , mServer(QString(), QWebSocketServer::NonSecureMode) + , mServerMessageHandler() +{ + connect(mTlsServer.data(), &RemoteTlsServer::newConnection, &mServer, &QWebSocketServer::handleConnection); + connect(mTlsServer.data(), &RemoteTlsServer::firePskChanged, this, &RemoteWebSocketServer::firePskChanged); + connect(&mServer, &QWebSocketServer::newConnection, this, &RemoteWebSocketServerImpl::onWebsocketConnection); +} + + +RemoteWebSocketServerImpl::~RemoteWebSocketServerImpl() +{ + if (mTlsServer->isListening()) + { + qCDebug(remote_device) << "Shutdown tls server"; + mTlsServer->close(); + } +} + + +bool RemoteWebSocketServerImpl::isListening() const +{ + return mTlsServer->isListening(); +} + + +bool RemoteWebSocketServerImpl::isConnected() const +{ + return !mServerMessageHandler.isNull(); +} + + +bool RemoteWebSocketServerImpl::listen(const QString& pServerName) +{ + mServer.setServerName(pServerName); + return mTlsServer->listen(); +} + + +void RemoteWebSocketServerImpl::close() +{ + mTlsServer->close(); + mServerMessageHandler.reset(); +} + + +QString RemoteWebSocketServerImpl::getServerName() const +{ + return isListening() ? mServer.serverName() : QString(); +} + + +quint16 RemoteWebSocketServerImpl::getServerPort() const +{ + return isListening() ? mTlsServer->serverPort() : 0; +} + + +void RemoteWebSocketServerImpl::setPairing(bool pEnable) +{ + mTlsServer->setPairing(pEnable); +} + + +QSslCertificate RemoteWebSocketServerImpl::getCurrentCertificate() const +{ + return mTlsServer->getCurrentCertificate(); +} + + +const QSharedPointer& RemoteWebSocketServerImpl::getMessageHandler() const +{ + return mServerMessageHandler; +} diff --git a/src/remote_device/RemoteWebSocketServer.h b/src/remote_device/RemoteWebSocketServer.h new file mode 100644 index 0000000..fa5bcb1 --- /dev/null +++ b/src/remote_device/RemoteWebSocketServer.h @@ -0,0 +1,82 @@ +/*! + * \brief WebSocketServer on the server side of a remote reader scenario. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ServerMessageHandler.h" + +#include "RemoteTlsServer.h" + +#include +#include +#include +#include +#include +#include + + +namespace governikus +{ + + +class RemoteWebSocketServer + : public QObject +{ + Q_OBJECT + + protected: + RemoteWebSocketServer() = default; + + public: + virtual ~RemoteWebSocketServer(); + + virtual bool isListening() const = 0; + virtual bool isConnected() const = 0; + virtual bool listen(const QString& pServerName) = 0; + virtual void close() = 0; + virtual QString getServerName() const = 0; + virtual quint16 getServerPort() const = 0; + virtual void setPairing(bool pEnable = true) = 0; + virtual QSslCertificate getCurrentCertificate() const = 0; + virtual const QSharedPointer& getMessageHandler() const = 0; + + Q_SIGNALS: + void fireConnectedChanged(bool pConnected); + void fireMessageHandlerAdded(QSharedPointer pHandler); + void firePskChanged(const QByteArray& pPsk); +}; + + +class RemoteWebSocketServerImpl + : public RemoteWebSocketServer +{ + Q_OBJECT + + QScopedPointer mTlsServer; + QWebSocketServer mServer; + QSharedPointer mServerMessageHandler; + + private Q_SLOTS: + void onWebsocketConnection(); + void onConnectionClosed(); + void onServerError(QWebSocketProtocol::CloseCode pCloseCode); + + public: + RemoteWebSocketServerImpl(); + virtual ~RemoteWebSocketServerImpl() override; + + virtual bool isListening() const override; + virtual bool isConnected() const override; + virtual bool listen(const QString& pServerName) override; + virtual void close() override; + virtual QString getServerName() const override; + virtual quint16 getServerPort() const override; + virtual void setPairing(bool pEnable = true) override; + virtual QSslCertificate getCurrentCertificate() const override; + virtual const QSharedPointer& getMessageHandler() const override; +}; + +} /* namespace governikus */ diff --git a/src/remote_device/ServerMessageHandler.cpp b/src/remote_device/ServerMessageHandler.cpp new file mode 100644 index 0000000..6b83e24 --- /dev/null +++ b/src/remote_device/ServerMessageHandler.cpp @@ -0,0 +1,311 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ServerMessageHandler.h" + +#include "AppSettings.h" +#include "Env.h" +#include "messages/GetIfdStatus.h" +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishPaceChannel.h" +#include "messages/IfdEstablishPaceChannelResponse.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" +#include "ReaderManager.h" +#include "RemoteDispatcher.h" + +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +namespace governikus +{ + +template<> ServerMessageHandler* createNewObject&>(QSharedPointer& pChannel) +{ + return new ServerMessageHandlerImpl(pChannel); +} + + +ServerMessageHandler::~ServerMessageHandler() +{ +} + + +ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer& pDataChannel) + : ServerMessageHandler() + , MessageReceiver() + , mReaderManager(Env::getSingleton()) + , mRemoteDispatcher(Env::create(pDataChannel), &QObject::deleteLater) + , mCardConnections() +{ + connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &ServerMessageHandlerImpl::onReceived); + connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &ServerMessageHandlerImpl::onClosed); + + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &ServerMessageHandlerImpl::onReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &ServerMessageHandlerImpl::onReaderRemoved); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderPropertiesUpdated, this, &ServerMessageHandlerImpl::onReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &ServerMessageHandlerImpl::onReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &ServerMessageHandlerImpl::onReaderChanged); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &ServerMessageHandlerImpl::onReaderChanged); +} + + +void ServerMessageHandlerImpl::process(const QSharedPointer& pMessage) +{ + if (!pMessage->getSlotName().isEmpty()) + { + const auto& readerInfo = mReaderManager->getReaderInfo(pMessage->getSlotName()); + const QSharedPointer ifdStatusMsg(new IfdStatus(readerInfo)); + mRemoteDispatcher->send(ifdStatusMsg); + + return; + } + + const auto& readerInfos = mReaderManager->getReaderInfos(); + for (const auto& readerInfo : readerInfos) + { + if (!readerInfo.isBasicReader()) + { + continue; + } + + const QSharedPointer ifdStatusMsg(new IfdStatus(readerInfo)); + mRemoteDispatcher->send(ifdStatusMsg); + } +} + + +void ServerMessageHandlerImpl::process(const QSharedPointer& pMessage) +{ + const auto& info = mReaderManager->getReaderInfo(pMessage->getSlotName()); + if (!info.isConnected()) + { + qCWarning(remote_device) << "Unknown reader" << pMessage->getSlotName(); + const QSharedPointer response(new IfdConnectResponse(pMessage->getSlotName(), QStringLiteral("/ifdl/terminal#unknownSlot"))); + mRemoteDispatcher->send(response); + return; + } + + if (!info.hasEidCard()) + { + qCWarning(remote_device) << "Cannot determine eID card for reader" << pMessage->getSlotName(); + const QSharedPointer response(new IfdConnectResponse(pMessage->getSlotName(), QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + if (mCardConnections.contains(pMessage->getSlotName())) + { + qCWarning(remote_device) << "Card is already connected" << pMessage->getSlotName(); + const QSharedPointer response(new IfdConnectResponse(pMessage->getSlotName(), QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + qCDebug(remote_device) << "Connect card" << pMessage->getSlotName(); + mReaderManager->callCreateCardConnectionCommand(pMessage->getSlotName(), this, &ServerMessageHandlerImpl::onCreateCardConnectionCommandDone); +} + + +void ServerMessageHandlerImpl::onCreateCardConnectionCommandDone(QSharedPointer pCommand) +{ + qCDebug(remote_device) << "Card connection command completed"; + if (pCommand->getCardConnection() == nullptr) + { + qCWarning(remote_device) << "Cannot connect card" << pCommand->getReaderName(); + const QSharedPointer response(new IfdConnectResponse(pCommand->getReaderName(), QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + qCInfo(remote_device) << "Card successfully connected" << pCommand->getReaderName(); + mCardConnections.insert(pCommand->getReaderName(), pCommand->getCardConnection()); + const QSharedPointer response(new IfdConnectResponse(pCommand->getReaderName())); + mRemoteDispatcher->send(response); +} + + +void ServerMessageHandlerImpl::process(const QSharedPointer& pMessage) +{ + if (!mCardConnections.contains(pMessage->getSlotHandle())) + { + qCWarning(remote_device) << "Card is not connected" << pMessage->getSlotHandle(); + const QSharedPointer response(new IfdDisconnectResponse(pMessage->getSlotHandle(), QStringLiteral("/ifdl/common#invalidSlotHandle"))); + mRemoteDispatcher->send(response); + return; + } + + mCardConnections.remove(pMessage->getSlotHandle()); + qCInfo(remote_device) << "Card successfully disconnected" << pMessage->getSlotHandle(); + const QSharedPointer response(new IfdDisconnectResponse(pMessage->getSlotHandle())); + mRemoteDispatcher->send(response); +} + + +void ServerMessageHandlerImpl::process(const QSharedPointer& pMessage) +{ + if (!mCardConnections.contains(pMessage->getSlotHandle())) + { + qCWarning(remote_device) << "Card is not connected" << pMessage->getSlotHandle(); + const QSharedPointer response(new IfdTransmitResponse(pMessage->getSlotHandle(), QByteArray(), QStringLiteral("/ifdl/common#invalidSlotHandle"))); + mRemoteDispatcher->send(response); + return; + } + + const QSharedPointer& cardConnection = mCardConnections.value(pMessage->getSlotHandle()); + const auto& commandApdu = pMessage->getInputApdu(); + + const bool pinPadMode = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); + if (pinPadMode && CommandApdu::isSecureMessaging(commandApdu)) + { + const bool stopped = cardConnection->stopSecureMessaging(); + if (stopped) + { + qCDebug(remote_device) << "The eService has established Secure Messaging. Stopping local Secure Messaging."; + } + } + + qCDebug(remote_device) << "Transmit card APDU for" << pMessage->getSlotHandle(); + InputAPDUInfo inputApduInfo(commandApdu, MSEBuilder::isUpdateRetryCounterCommand(commandApdu)); + cardConnection->callTransmitCommand(this, &ServerMessageHandlerImpl::onTransmitCardCommandDone, {inputApduInfo}); +} + + +void ServerMessageHandlerImpl::process(const QSharedPointer& pMessage) +{ + const bool pinPadMode = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); + if (!pinPadMode) + { + qCWarning(remote_device) << "EstablishPaceChannel is only available in pin pad mode."; + const QSharedPointer response(new IfdEstablishPaceChannelResponse(pMessage->getSlotHandle(), QByteArray(), QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + if (!mCardConnections.contains(pMessage->getSlotHandle())) + { + qCWarning(remote_device) << "Card is not connected" << pMessage->getSlotHandle(); + const QSharedPointer response(new IfdEstablishPaceChannelResponse(pMessage->getSlotHandle(), QByteArray(), QStringLiteral("/ifdl/common#invalidSlotHandle"))); + mRemoteDispatcher->send(response); + return; + } + + QSharedPointer connection = mCardConnections[pMessage->getSlotHandle()]; + Q_EMIT fireEstablishPaceChannel(pMessage, connection); +} + + +void ServerMessageHandlerImpl::sendEstablishPaceChannelResponse(const QString& pSlotName, const EstablishPACEChannelOutput& pChannelOutput) +{ + const QByteArray& ccid = pChannelOutput.toCcid(); + if (pChannelOutput.getPaceReturnCode() == CardReturnCode::UNKNOWN) + { + const QSharedPointer response(new IfdEstablishPaceChannelResponse(pSlotName, ccid, QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + const QSharedPointer response(new IfdEstablishPaceChannelResponse(pSlotName, ccid)); + mRemoteDispatcher->send(response); +} + + +void ServerMessageHandlerImpl::onTransmitCardCommandDone(QSharedPointer pCommand) +{ + auto transmitCommand = pCommand.staticCast(); + if (transmitCommand->getReturnCode() != CardReturnCode::OK) + { + qCWarning(remote_device) << "Card transmit for" << transmitCommand->getReaderName() << "failed" << transmitCommand->getReturnCode(); + QSharedPointer response(new IfdTransmitResponse(transmitCommand->getReaderName(), QByteArray(), QStringLiteral("/al/common#unknownError"))); + mRemoteDispatcher->send(response); + return; + } + + QByteArray responseApdu; + Q_ASSERT(transmitCommand->getOutputApduAsHex().size() == 1); // may not happen, see TransmitCommand + if (transmitCommand->getOutputApduAsHex().size() == 1) + { + responseApdu = QByteArray::fromHex(transmitCommand->getOutputApduAsHex().first()); + } + qCInfo(remote_device) << "Card transmit succeeded" << transmitCommand->getReaderName(); + QSharedPointer response(new IfdTransmitResponse(transmitCommand->getReaderName(), responseApdu)); + mRemoteDispatcher->send(response); +} + + +void ServerMessageHandlerImpl::unprocessed(const QSharedPointer& pMessage) +{ + unexpectedMessage(pMessage); +} + + +void ServerMessageHandlerImpl::unexpectedMessage(const QSharedPointer& pMessage, bool pSendMessage) +{ + qCWarning(remote_device) << "Received an unexpected message of type:" << pMessage->getType(); + + if (pSendMessage) + { + const QSharedPointer errorMessage(new IfdError(QString(), QStringLiteral("/al/common#unknownAPIFunction"))); + QMetaObject::invokeMethod(mRemoteDispatcher.data(), "send", Qt::QueuedConnection, Q_ARG(QSharedPointer, errorMessage)); + } +} + + +void ServerMessageHandlerImpl::onClosed() +{ + mCardConnections.clear(); + + Q_EMIT fireClosed(); +} + + +void ServerMessageHandlerImpl::onReceived(const QSharedPointer& pMessage) +{ + const QVector serverMessageTypes({ + RemoteCardMessageType::IFDStatus, + RemoteCardMessageType::IFDConnectResponse, + RemoteCardMessageType::IFDDisconnectResponse, + RemoteCardMessageType::IFDTransmitResponse, + RemoteCardMessageType::IFDEstablishPACEChannelResponse + }); + + if (serverMessageTypes.contains(pMessage->getType())) + { + unexpectedMessage(pMessage, true); + return; + } + + receive(pMessage); +} + + +void ServerMessageHandlerImpl::onReaderChanged(const QString& pReaderName) +{ + ReaderInfo info = mReaderManager->getReaderInfo(pReaderName); + if (!info.hasEidCard() && mCardConnections.contains(pReaderName)) + { + mCardConnections.remove(pReaderName); + qCInfo(remote_device) << "Removed CardConnection for" << pReaderName; + } + + mRemoteDispatcher->send(QSharedPointer(new IfdStatus(info))); +} + + +void ServerMessageHandlerImpl::onReaderRemoved(const QString& pReaderName) +{ + mRemoteDispatcher->send(QSharedPointer(new IfdStatus(pReaderName))); +} + + +} /* namespace governikus */ diff --git a/src/remote_device/ServerMessageHandler.h b/src/remote_device/ServerMessageHandler.h new file mode 100644 index 0000000..56092b4 --- /dev/null +++ b/src/remote_device/ServerMessageHandler.h @@ -0,0 +1,79 @@ +/*! + * \brief Handler for messages on the server side of a remote reader scenario. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "CardConnection.h" +#include "DataChannel.h" +#include "messages/MessageReceiver.h" +#include "ReaderManager.h" +#include "RemoteDispatcher.h" + +#include +#include +#include + + +namespace governikus +{ + +class CreateCardConnectionCommand; + +class ServerMessageHandler + : public QObject +{ + Q_OBJECT + + protected: + ServerMessageHandler() = default; + + public: + virtual ~ServerMessageHandler(); + + virtual void sendEstablishPaceChannelResponse(const QString& pSlotName, const EstablishPACEChannelOutput&) = 0; + + Q_SIGNALS: + void fireEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); + void fireClosed(); +}; + + +class ServerMessageHandlerImpl + : public ServerMessageHandler + , public MessageReceiver +{ + Q_OBJECT + + private: + QPointer mReaderManager; + const QSharedPointer mRemoteDispatcher; + QMap > mCardConnections; + + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + + virtual void unprocessed(const QSharedPointer& pMessage) override; + void unexpectedMessage(const QSharedPointer& pMessage, bool pSendMessage = false); + + private Q_SLOTS: + void onCreateCardConnectionCommandDone(QSharedPointer pCommand); + void onTransmitCardCommandDone(QSharedPointer pCommand); + void onClosed(); + void onReceived(const QSharedPointer& pMessage); + void onReaderChanged(const QString& pReaderName); + void onReaderRemoved(const QString& pReaderName); + + public: + ServerMessageHandlerImpl(const QSharedPointer& pDataChannel); + + virtual void sendEstablishPaceChannelResponse(const QString& pSlotName, const EstablishPACEChannelOutput& pChannelOutput) override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/WebSocketChannel.cpp b/src/remote_device/WebSocketChannel.cpp new file mode 100644 index 0000000..fab605d --- /dev/null +++ b/src/remote_device/WebSocketChannel.cpp @@ -0,0 +1,142 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WebSocketChannel.h" + +#include "RemoteServiceSettings.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + +namespace +{ +const int PING_PONG_TIMEOUT_MS = 5000; +} + + +QString WebSocketChannel::makeConnectionId(const QSharedPointer& pConnection) +{ + if (pConnection) + { + return RemoteServiceSettings::generateFingerprint(pConnection->sslConfiguration().peerCertificate()); + } + + return QString(); +} + + +WebSocketChannel::WebSocketChannel(const QSharedPointer& pConnection) + : mConnection(pConnection) + , mId(makeConnectionId(pConnection)) + , mPingTimer() + , mPongTimer() +{ + if (mConnection) + { + connect(mConnection.data(), &QWebSocket::textMessageReceived, this, &WebSocketChannel::onReceived); + connect(mConnection.data(), &QWebSocket::disconnected, this, &WebSocketChannel::onDisconnected); + connect(&mPingTimer, &QTimer::timeout, this, &WebSocketChannel::onPingScheduled); + connect(mConnection.data(), &QWebSocket::pong, this, &WebSocketChannel::onPongReceived); + connect(&mPongTimer, &QTimer::timeout, this, &WebSocketChannel::onPongTimeout); + + mPingTimer.setInterval(PING_PONG_TIMEOUT_MS); + mPingTimer.setSingleShot(true); + mPongTimer.setInterval(PING_PONG_TIMEOUT_MS); + mPongTimer.setSingleShot(true); + mPingTimer.start(); + } +} + + +WebSocketChannel::~WebSocketChannel() +{ + if (mConnection) + { + disconnect(mConnection.data(), &QWebSocket::textMessageReceived, this, &WebSocketChannel::onReceived); + disconnect(mConnection.data(), &QWebSocket::disconnected, this, &WebSocketChannel::onDisconnected); + disconnect(mConnection.data(), &QWebSocket::pong, this, &WebSocketChannel::onPongReceived); + disconnect(&mPingTimer, &QTimer::timeout, this, &WebSocketChannel::onPingScheduled); + disconnect(&mPongTimer, &QTimer::timeout, this, &WebSocketChannel::onPongTimeout); + } +} + + +void WebSocketChannel::send(const QByteArray& pDataBlock) +{ + if (mConnection) + { + mConnection->sendTextMessage(QString::fromUtf8(pDataBlock)); + } +} + + +void WebSocketChannel::close() +{ + if (mConnection) + { + // QWebSocket.close() must be executed in the thread in which the QWebSocket object lives. + if (mConnection->thread() == QThread::currentThread()) + { + mConnection->close(); + } + else + { + qCWarning(remote_device) << "Tried to close web socket from the wrong thread: skipping"; + } + } +} + + +const QString& WebSocketChannel::getId() const +{ + return mId; +} + + +void WebSocketChannel::onReceived(const QString& pMessage) +{ + Q_EMIT fireReceived(pMessage.toUtf8()); +} + + +void WebSocketChannel::onDisconnected() +{ + mPingTimer.stop(); + mPongTimer.stop(); + + Q_ASSERT(mConnection); + if (mConnection) + { + Q_EMIT fireClosed(mConnection->closeCode() == QWebSocketProtocol::CloseCodeNormal ? + GlobalStatus::Code::RemoteReader_CloseCode_NormalClose : + GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); + } +} + + +void WebSocketChannel::onPingScheduled() +{ + mConnection->ping(); + mPongTimer.start(); +} + + +void WebSocketChannel::onPongReceived() +{ + mPongTimer.stop(); + mPingTimer.start(); +} + + +void WebSocketChannel::onPongTimeout() +{ + qCDebug(remote_device) << "No pong received from remote for" << (PING_PONG_TIMEOUT_MS / 1000) << "seconds, closing socket"; + close(); +} diff --git a/src/remote_device/WebSocketChannel.h b/src/remote_device/WebSocketChannel.h new file mode 100644 index 0000000..9066d1f --- /dev/null +++ b/src/remote_device/WebSocketChannel.h @@ -0,0 +1,46 @@ +/*! + * \brief Implementation of DataChannel base on web sockets. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "DataChannel.h" + +#include +#include +#include +#include + +namespace governikus +{ +class WebSocketChannel + : public DataChannel +{ + Q_OBJECT + + private: + const QSharedPointer mConnection; + const QString mId; + QTimer mPingTimer; + QTimer mPongTimer; + static QString makeConnectionId(const QSharedPointer& pConnection); + + public: + WebSocketChannel(const QSharedPointer& pConnection); + virtual ~WebSocketChannel() override; + + virtual void send(const QByteArray& pDataBlock) override; + virtual void close() override; + virtual const QString& getId() const override; + + private Q_SLOTS: + void onReceived(const QString& pMessage); + void onDisconnected(); + void onPingScheduled(); + void onPongReceived(); + void onPongTimeout(); +}; + +} /* namespace governikus */ diff --git a/src/remote_device/messages/Discovery.cpp b/src/remote_device/messages/Discovery.cpp new file mode 100644 index 0000000..00b99e0 --- /dev/null +++ b/src/remote_device/messages/Discovery.cpp @@ -0,0 +1,76 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "Discovery.h" + +#include "Initializer.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +static Initializer::Entry E([] { + qRegisterMetaType >("QSharedPointer"); + }); + + +Discovery::Discovery(const QString& pIfdName, const QString& pIfdId, quint16 pPort, const QStringList& pSupportedApis) + : mIfdName(pIfdName) + , mIfdId(pIfdId) + , mPort(pPort) + , mSupportedApis(pSupportedApis) +{ +} + + +const QString& Discovery::getIfdName() const +{ + return mIfdName; +} + + +const QString& Discovery::getIfdId() const +{ + return mIfdId; +} + + +quint16 Discovery::getPort() const +{ + return mPort; +} + + +const QStringList& Discovery::getSupportedApis() const +{ + return mSupportedApis; +} + + +QJsonDocument Discovery::toJson() const +{ + QJsonObject result; + + result[QLatin1String("IFDName")] = mIfdName; + result[QLatin1String("IFDID")] = mIfdId; + result[QLatin1String("msg")] = QStringLiteral("REMOTE_IFD"); + result[QLatin1String("port")] = mPort; + + QJsonArray levels; + for (const auto& level : qAsConst(mSupportedApis)) + { + levels += level; + } + result[QLatin1String("SupportedAPI")] = levels; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/Discovery.h b/src/remote_device/messages/Discovery.h new file mode 100644 index 0000000..85e254a --- /dev/null +++ b/src/remote_device/messages/Discovery.h @@ -0,0 +1,34 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + +#include + + +namespace governikus +{ +class Discovery +{ + private: + const QString mIfdName; + const QString mIfdId; + const quint16 mPort; + const QStringList mSupportedApis; + + public: + Discovery(const QString& pIfdName, const QString& pIfdId, quint16 pPort, const QStringList& pSupportedApis); + ~Discovery() = default; + + const QString& getIfdName() const; + const QString& getIfdId() const; + quint16 getPort() const; + const QStringList& getSupportedApis() const; + QJsonDocument toJson() const; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/GetIfdStatus.cpp b/src/remote_device/messages/GetIfdStatus.cpp new file mode 100644 index 0000000..3976bb0 --- /dev/null +++ b/src/remote_device/messages/GetIfdStatus.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "GetIfdStatus.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_NAME, "SlotName") +} + + +GetIfdStatus::GetIfdStatus(const QString& pSlotName) + : RemoteMessage(RemoteCardMessageType::IFDGetStatus) + , mSlotName(pSlotName) +{ +} + + +GetIfdStatus::GetIfdStatus(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotName() +{ + mSlotName = getStringValue(pMessageObject, SLOT_NAME()); +} + + +const QString& GetIfdStatus::getSlotName() const +{ + return mSlotName; +} + + +QJsonDocument GetIfdStatus::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_NAME()] = mSlotName; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/GetIfdStatus.h b/src/remote_device/messages/GetIfdStatus.h new file mode 100644 index 0000000..165d082 --- /dev/null +++ b/src/remote_device/messages/GetIfdStatus.h @@ -0,0 +1,30 @@ +/*! + * \brief Classes that model the GetIFDStatus message. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + + +namespace governikus +{ +class GetIfdStatus + : public RemoteMessage +{ + private: + QString mSlotName; + + public: + GetIfdStatus(const QString& pSlotName = QString()); + GetIfdStatus(const QJsonObject& pMessageObject); + virtual ~GetIfdStatus() override = default; + + const QString& getSlotName() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdConnect.cpp b/src/remote_device/messages/IfdConnect.cpp new file mode 100644 index 0000000..79e1780 --- /dev/null +++ b/src/remote_device/messages/IfdConnect.cpp @@ -0,0 +1,63 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdConnect.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_NAME, "SlotName") +VALUE_NAME(EXCLUSIVE, "exclusive") +} + + +IfdConnect::IfdConnect(const QString& pSlotName, bool pExclusive) + : RemoteMessage(RemoteCardMessageType::IFDConnect) + , mSlotName(pSlotName) + , mExclusive(pExclusive) +{ +} + + +IfdConnect::IfdConnect(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotName() + , mExclusive(true) +{ + mSlotName = getStringValue(pMessageObject, SLOT_NAME()); + mExclusive = getBoolValue(pMessageObject, EXCLUSIVE()); +} + + +const QString& IfdConnect::getSlotName() const +{ + return mSlotName; +} + + +bool IfdConnect::isExclusive() const +{ + return mExclusive; +} + + +QJsonDocument IfdConnect::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_NAME()] = mSlotName; + result[EXCLUSIVE()] = mExclusive; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdConnect.h b/src/remote_device/messages/IfdConnect.h new file mode 100644 index 0000000..b22cc78 --- /dev/null +++ b/src/remote_device/messages/IfdConnect.h @@ -0,0 +1,30 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + + +namespace governikus +{ +class IfdConnect + : public RemoteMessage +{ + private: + QString mSlotName; + bool mExclusive; + + public: + IfdConnect(const QString& pSlotName, bool pExclusive = true); + IfdConnect(const QJsonObject& pMessageObject); + virtual ~IfdConnect() override = default; + + const QString& getSlotName() const; + bool isExclusive() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdConnectResponse.cpp b/src/remote_device/messages/IfdConnectResponse.cpp new file mode 100644 index 0000000..f5a6314 --- /dev/null +++ b/src/remote_device/messages/IfdConnectResponse.cpp @@ -0,0 +1,53 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdConnectResponse.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +} + + +IfdConnectResponse::IfdConnectResponse(const QString& pSlotHandle, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDConnectResponse, pResultMinor) + , mSlotHandle(pSlotHandle) +{ +} + + +IfdConnectResponse::IfdConnectResponse(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mSlotHandle() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); + mError = pMessageObject.value(QLatin1String("error")).toString(); +} + + +const QString& IfdConnectResponse::getSlotHandle() const +{ + return mSlotHandle; +} + + +QJsonDocument IfdConnectResponse::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdConnectResponse.h b/src/remote_device/messages/IfdConnectResponse.h new file mode 100644 index 0000000..7bf10b5 --- /dev/null +++ b/src/remote_device/messages/IfdConnectResponse.h @@ -0,0 +1,29 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessageResponse.h" + + +namespace governikus +{ +class IfdConnectResponse + : public RemoteMessageResponse +{ + private: + QString mSlotHandle; + QString mError; + + public: + IfdConnectResponse(const QString& pSlotHandle, const QString& pResultMinor = QString()); + IfdConnectResponse(const QJsonObject& pMessageObject); + virtual ~IfdConnectResponse() override = default; + + const QString& getSlotHandle() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdDisconnect.cpp b/src/remote_device/messages/IfdDisconnect.cpp new file mode 100644 index 0000000..0791304 --- /dev/null +++ b/src/remote_device/messages/IfdDisconnect.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdDisconnect.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +} + + +IfdDisconnect::IfdDisconnect(const QString& pSlotHandle) + : RemoteMessage(RemoteCardMessageType::IFDDisconnect) + , mSlotHandle(pSlotHandle) +{ +} + + +IfdDisconnect::IfdDisconnect(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotHandle() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); +} + + +const QString& IfdDisconnect::getSlotHandle() const +{ + return mSlotHandle; +} + + +QJsonDocument IfdDisconnect::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdDisconnect.h b/src/remote_device/messages/IfdDisconnect.h new file mode 100644 index 0000000..f3062d1 --- /dev/null +++ b/src/remote_device/messages/IfdDisconnect.h @@ -0,0 +1,28 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + + +namespace governikus +{ +class IfdDisconnect + : public RemoteMessage +{ + private: + QString mSlotHandle; + + public: + IfdDisconnect(const QString& pReaderName); + IfdDisconnect(const QJsonObject& pMessageObject); + virtual ~IfdDisconnect() override = default; + + const QString& getSlotHandle() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdDisconnectResponse.cpp b/src/remote_device/messages/IfdDisconnectResponse.cpp new file mode 100644 index 0000000..7102f4c --- /dev/null +++ b/src/remote_device/messages/IfdDisconnectResponse.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdDisconnectResponse.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +} + + +IfdDisconnectResponse::IfdDisconnectResponse(const QString& pSlotHandle, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDDisconnectResponse, pResultMinor) + , mSlotHandle(pSlotHandle) +{ +} + + +IfdDisconnectResponse::IfdDisconnectResponse(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mSlotHandle() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); +} + + +const QString& IfdDisconnectResponse::getSlotHandle() const +{ + return mSlotHandle; +} + + +QJsonDocument IfdDisconnectResponse::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdDisconnectResponse.h b/src/remote_device/messages/IfdDisconnectResponse.h new file mode 100644 index 0000000..e0619b0 --- /dev/null +++ b/src/remote_device/messages/IfdDisconnectResponse.h @@ -0,0 +1,28 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessageResponse.h" + + +namespace governikus +{ +class IfdDisconnectResponse + : public RemoteMessageResponse +{ + private: + QString mSlotHandle; + + public: + IfdDisconnectResponse(const QString& pSlotHandle, const QString& pResultMinor = QString()); + IfdDisconnectResponse(const QJsonObject& pMessageObject); + virtual ~IfdDisconnectResponse() override = default; + + const QString& getSlotHandle() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdError.cpp b/src/remote_device/messages/IfdError.cpp new file mode 100644 index 0000000..a39c9f7 --- /dev/null +++ b/src/remote_device/messages/IfdError.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdError.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +} + + +IfdError::IfdError(const QString& pSlotHandle, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDError, pResultMinor) + , mSlotHandle(pSlotHandle) +{ +} + + +IfdError::IfdError(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mSlotHandle() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); +} + + +const QString& IfdError::getSlotHandle() const +{ + return mSlotHandle; +} + + +QJsonDocument IfdError::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdError.h b/src/remote_device/messages/IfdError.h new file mode 100644 index 0000000..f0e1642 --- /dev/null +++ b/src/remote_device/messages/IfdError.h @@ -0,0 +1,28 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessageResponse.h" + + +namespace governikus +{ +class IfdError + : public RemoteMessageResponse +{ + private: + QString mSlotHandle; + + public: + IfdError(const QString& pSlotHandle, const QString& pResultMinor = QString()); + IfdError(const QJsonObject& pMessageObject); + virtual ~IfdError() override = default; + + const QString& getSlotHandle() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdEstablishContext.cpp b/src/remote_device/messages/IfdEstablishContext.cpp new file mode 100644 index 0000000..c912535 --- /dev/null +++ b/src/remote_device/messages/IfdEstablishContext.cpp @@ -0,0 +1,59 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdEstablishContext.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(PROTOCOL, "Protocol") +VALUE_NAME(UD_NAME, "UDName") +} + + +IfdEstablishContext::IfdEstablishContext(const QString& pProtocol, const QString& pUdName) + : RemoteMessage(RemoteCardMessageType::IFDEstablishContext) + , mProtocol(pProtocol) + , mUdName(pUdName) +{ +} + + +IfdEstablishContext::IfdEstablishContext(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mProtocol(getStringValue(pMessageObject, PROTOCOL())) + , mUdName(getStringValue(pMessageObject, UD_NAME())) +{ +} + + +const QString& IfdEstablishContext::getProtocol() const +{ + return mProtocol; +} + + +const QString& IfdEstablishContext::getUdName() const +{ + return mUdName; +} + + +QJsonDocument IfdEstablishContext::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + result[PROTOCOL()] = mProtocol; + result[UD_NAME()] = mUdName; + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdEstablishContext.h b/src/remote_device/messages/IfdEstablishContext.h new file mode 100644 index 0000000..f881813 --- /dev/null +++ b/src/remote_device/messages/IfdEstablishContext.h @@ -0,0 +1,34 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "DeviceInfo.h" +#include "RemoteMessage.h" + +#include +#include + + +namespace governikus +{ +class IfdEstablishContext + : public RemoteMessage +{ + private: + QString mProtocol; + QString mUdName; + + public: + IfdEstablishContext(const QString& pProtocol, const QString& pUdName); + IfdEstablishContext(const QJsonObject& pMessageObject); + virtual ~IfdEstablishContext() override = default; + + const QString& getProtocol() const; + const QString& getUdName() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdEstablishContextResponse.cpp b/src/remote_device/messages/IfdEstablishContextResponse.cpp new file mode 100644 index 0000000..7c8db0a --- /dev/null +++ b/src/remote_device/messages/IfdEstablishContextResponse.cpp @@ -0,0 +1,48 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdEstablishContextResponse.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + +namespace +{ +VALUE_NAME(IFD_NAME, "IFDName") +} + +IfdEstablishContextResponse::IfdEstablishContextResponse(const QString& pIfdName, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDEstablishContextResponse, pResultMinor) + , mIfdName(pIfdName) +{ +} + + +IfdEstablishContextResponse::IfdEstablishContextResponse(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mIfdName() +{ + mIfdName = getStringValue(pMessageObject, IFD_NAME()); +} + + +QJsonDocument IfdEstablishContextResponse::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + result[IFD_NAME()] = mIfdName; + return QJsonDocument(result); +} + + +const QString& IfdEstablishContextResponse::getIfdName() const +{ + return mIfdName; +} diff --git a/src/remote_device/messages/IfdEstablishContextResponse.h b/src/remote_device/messages/IfdEstablishContextResponse.h new file mode 100644 index 0000000..8ac311a --- /dev/null +++ b/src/remote_device/messages/IfdEstablishContextResponse.h @@ -0,0 +1,31 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessageResponse.h" + +#include +#include + + +namespace governikus +{ +class IfdEstablishContextResponse + : public RemoteMessageResponse +{ + private: + QString mIfdName; + + public: + IfdEstablishContextResponse(const QString& pIfdName, const QString& pResultMinor = QString()); + IfdEstablishContextResponse(const QJsonObject& pMessageObject); + virtual ~IfdEstablishContextResponse() override = default; + + const QString& getIfdName() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdEstablishPaceChannel.cpp b/src/remote_device/messages/IfdEstablishPaceChannel.cpp new file mode 100644 index 0000000..7ab2548 --- /dev/null +++ b/src/remote_device/messages/IfdEstablishPaceChannel.cpp @@ -0,0 +1,67 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "IfdEstablishPaceChannel.h" + +#include "MessageReceiver.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +VALUE_NAME(INPUT_DATA, "InputData") +} + + +IfdEstablishPaceChannel::IfdEstablishPaceChannel(const QString& pSlotHandle, const QByteArray& pInputData) + : RemoteMessage(RemoteCardMessageType::IFDEstablishPACEChannel) + , mSlotHandle(pSlotHandle) + , mInputData(pInputData) +{ + +} + + +IfdEstablishPaceChannel::IfdEstablishPaceChannel(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotHandle() + , mInputData() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); + + const QString& inputData = getStringValue(pMessageObject, INPUT_DATA()); + mInputData = QByteArray::fromHex(inputData.toUtf8()); +} + + +const QString& IfdEstablishPaceChannel::getSlotHandle() const +{ + return mSlotHandle; +} + + +const QByteArray& IfdEstablishPaceChannel::getInputData() const +{ + return mInputData; +} + + +QJsonDocument IfdEstablishPaceChannel::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + result[INPUT_DATA()] = QString::fromLatin1(mInputData.toHex()); + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdEstablishPaceChannel.h b/src/remote_device/messages/IfdEstablishPaceChannel.h new file mode 100644 index 0000000..d2cc48b --- /dev/null +++ b/src/remote_device/messages/IfdEstablishPaceChannel.h @@ -0,0 +1,33 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "MessageReceiver.h" +#include "RemoteMessage.h" + + +namespace governikus +{ + + +class IfdEstablishPaceChannel + : public RemoteMessage +{ + private: + QString mSlotHandle; + QByteArray mInputData; + + public: + IfdEstablishPaceChannel(const QString& pSlotHandle = QString(), const QByteArray& pInputData = QByteArray()); + IfdEstablishPaceChannel(const QJsonObject& pMessageObject); + virtual ~IfdEstablishPaceChannel() override = default; + + const QString& getSlotHandle() const; + const QByteArray& getInputData() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdEstablishPaceChannelResponse.cpp b/src/remote_device/messages/IfdEstablishPaceChannelResponse.cpp new file mode 100644 index 0000000..f98100f --- /dev/null +++ b/src/remote_device/messages/IfdEstablishPaceChannelResponse.cpp @@ -0,0 +1,64 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "IfdEstablishPaceChannelResponse.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +VALUE_NAME(OUTPUT_DATA, "OutputData") +} + + +IfdEstablishPaceChannelResponse::IfdEstablishPaceChannelResponse(const QString& pSlotHandle, const QByteArray& pOutputData, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDEstablishPACEChannelResponse, pResultMinor) + , mSlotHandle(pSlotHandle) + , mOutputData(pOutputData) +{ +} + + +IfdEstablishPaceChannelResponse::IfdEstablishPaceChannelResponse(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mSlotHandle() + , mOutputData() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); + + const QString& inputData = getStringValue(pMessageObject, OUTPUT_DATA()); + mOutputData = QByteArray::fromHex(inputData.toUtf8()); +} + + +const QString& IfdEstablishPaceChannelResponse::getSlotHandle() const +{ + return mSlotHandle; +} + + +const QByteArray& IfdEstablishPaceChannelResponse::getOutputData() const +{ + return mOutputData; +} + + +QJsonDocument IfdEstablishPaceChannelResponse::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + result[OUTPUT_DATA()] = QString::fromLatin1(mOutputData.toHex()); + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdEstablishPaceChannelResponse.h b/src/remote_device/messages/IfdEstablishPaceChannelResponse.h new file mode 100644 index 0000000..9629113 --- /dev/null +++ b/src/remote_device/messages/IfdEstablishPaceChannelResponse.h @@ -0,0 +1,32 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EstablishPACEChannel.h" +#include "RemoteMessageResponse.h" +#include "SmartCardDefinitions.h" + + +namespace governikus +{ +class IfdEstablishPaceChannelResponse + : public RemoteMessageResponse +{ + private: + QString mSlotHandle; + QByteArray mOutputData; + + public: + IfdEstablishPaceChannelResponse(const QString& pSlotHandle, const QByteArray& pOutputData, const QString& pResultMinor = QString()); + IfdEstablishPaceChannelResponse(const QJsonObject& pMessageObject); + virtual ~IfdEstablishPaceChannelResponse() override = default; + + const QString& getSlotHandle() const; + const QByteArray& getOutputData() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdStatus.cpp b/src/remote_device/messages/IfdStatus.cpp new file mode 100644 index 0000000..46b0236 --- /dev/null +++ b/src/remote_device/messages/IfdStatus.cpp @@ -0,0 +1,173 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdStatus.h" + +#include "AppSettings.h" +#include "Env.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_NAME, "SlotName") +VALUE_NAME(PIN_CAPABILITIES, "PINCapabilities") +VALUE_NAME(PIN_CAP_PACE, "PACE") +VALUE_NAME(PIN_CAP_EID, "eID") +VALUE_NAME(PIN_CAP_ESIGN, "eSign") +VALUE_NAME(PIN_CAP_DESTROY, "Destroy") +VALUE_NAME(MAX_APDU_LENGTH, "MaxAPDULength") +VALUE_NAME(CONNECTED_READER, "ConnectedReader") +VALUE_NAME(CARD_AVAILABLE, "CardAvailable") +VALUE_NAME(EF_ATR, "EFATR") +VALUE_NAME(EF_DIR, "EFDIR") +} + + +PaceCapabilities::PaceCapabilities(bool pPace, bool pEId, bool pESign, bool pDestroy) + : mPace(pPace) + , mEId(pEId) + , mESign(pESign) + , mDestroy(pDestroy) +{ +} + + +bool PaceCapabilities::getPace() const +{ + return mPace; +} + + +bool PaceCapabilities::getEId() const +{ + return mEId; +} + + +bool PaceCapabilities::getESign() const +{ + return mESign; +} + + +bool PaceCapabilities::getDestroy() const +{ + return mDestroy; +} + + +QJsonValue PaceCapabilities::toJson() const +{ + QJsonObject result; + result[PIN_CAP_PACE()] = mPace; + result[PIN_CAP_EID()] = mEId; + result[PIN_CAP_ESIGN()] = mESign; + result[PIN_CAP_DESTROY()] = mDestroy; + return result; +} + + +IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo) + : RemoteMessage(RemoteCardMessageType::IFDStatus) + , mSlotName(pReaderInfo.getName()) + , mPaceCapabilities(Env::getSingleton()->getRemoteServiceSettings().getPinPadMode()) + , mMaxApduLength(pReaderInfo.getMaxApduLength()) + , mConnectedReader(pReaderInfo.isConnected()) + , mCardAvailable(pReaderInfo.hasCard()) +{ +} + + +IfdStatus::IfdStatus(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotName() + , mPaceCapabilities() + , mMaxApduLength(0) + , mConnectedReader(false) + , mCardAvailable(false) +{ + mSlotName = getStringValue(pMessageObject, SLOT_NAME()); + + if (pMessageObject.contains(PIN_CAPABILITIES())) + { + QJsonValue value = pMessageObject.value(PIN_CAPABILITIES()); + if (value.isObject()) + { + QJsonObject object = value.toObject(); + bool pace = getBoolValue(object, PIN_CAP_PACE()); + bool eId = getBoolValue(object, PIN_CAP_EID()); + bool eSign = getBoolValue(object, PIN_CAP_ESIGN()); + bool destroy = getBoolValue(object, PIN_CAP_DESTROY()); + mPaceCapabilities = PaceCapabilities(pace, eId, eSign, destroy); + } + else + { + invalidType(PIN_CAPABILITIES(), QLatin1String("object")); + } + } + else + { + missingValue(PIN_CAPABILITIES()); + } + + mMaxApduLength = getIntValue(pMessageObject, MAX_APDU_LENGTH()); + mConnectedReader = getBoolValue(pMessageObject, CONNECTED_READER()); + mCardAvailable = getBoolValue(pMessageObject, CARD_AVAILABLE()); +} + + +const QString& IfdStatus::getSlotName() const +{ + return mSlotName; +} + + +const PaceCapabilities& IfdStatus::getPaceCapabilities() const +{ + return mPaceCapabilities; +} + + +int IfdStatus::getMaxApduLength() const +{ + return mMaxApduLength; +} + + +bool IfdStatus::getConnectedReader() const +{ + return mConnectedReader; +} + + +bool IfdStatus::getCardAvailable() const +{ + return mCardAvailable; +} + + +QJsonDocument IfdStatus::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_NAME()] = mSlotName; + result[PIN_CAPABILITIES()] = mPaceCapabilities.toJson(); + result[MAX_APDU_LENGTH()] = mMaxApduLength; + result[CONNECTED_READER()] = mConnectedReader; + result[CARD_AVAILABLE()] = mCardAvailable; + result[EF_ATR()] = QJsonValue(); + result[EF_DIR()] = QJsonValue(); + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdStatus.h b/src/remote_device/messages/IfdStatus.h new file mode 100644 index 0000000..3bd9743 --- /dev/null +++ b/src/remote_device/messages/IfdStatus.h @@ -0,0 +1,63 @@ +/*! + * \brief Classes that model the IFDStatus message. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ReaderInfo.h" +#include "RemoteMessage.h" + +#include + + +namespace governikus +{ +class PaceCapabilities +{ + // PACECapabilities according to TR-03119, sec. D.1.1. + + private: + bool mPace; + bool mEId; + bool mESign; + bool mDestroy; + + public: + PaceCapabilities(bool pPace = false, bool pEId = false, bool pESign = false, bool pDestroy = false); + + bool getPace() const; + bool getEId() const; + bool getESign() const; + bool getDestroy() const; + + QJsonValue toJson() const; +}; + + +class IfdStatus + : public RemoteMessage +{ + private: + QString mSlotName; + PaceCapabilities mPaceCapabilities; + int mMaxApduLength; + bool mConnectedReader; + bool mCardAvailable; + + public: + IfdStatus(const ReaderInfo& pReaderInfo); + IfdStatus(const QJsonObject& pMessageObject); + virtual ~IfdStatus() override = default; + + const QString& getSlotName() const; + const PaceCapabilities& getPaceCapabilities() const; + int getMaxApduLength() const; + bool getConnectedReader() const; + bool getCardAvailable() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdTransmit.cpp b/src/remote_device/messages/IfdTransmit.cpp new file mode 100644 index 0000000..9806465 --- /dev/null +++ b/src/remote_device/messages/IfdTransmit.cpp @@ -0,0 +1,106 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdTransmit.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +VALUE_NAME(COMMAND_APDUS, "CommandAPDUs") +VALUE_NAME(INPUT_APDU, "InputAPDU") +VALUE_NAME(ACCEPTABLE_STATUS_CODES, "AcceptableStatusCodes") +} + + +void IfdTransmit::parseCommandApdu(QJsonValue pEntry) +{ + if (!pEntry.isObject()) + { + invalidType(COMMAND_APDUS(), QLatin1String("object")); + return; + } + + const QJsonObject& commandApdu = pEntry.toObject(); + const QString& inputApdu = getStringValue(commandApdu, INPUT_APDU()); + mInputApdu = QByteArray::fromHex(inputApdu.toUtf8()); +} + + +IfdTransmit::IfdTransmit(const QString& pSlotHandle, const QByteArray& pInputApdu) + : RemoteMessage(RemoteCardMessageType::IFDTransmit) + , mSlotHandle(pSlotHandle) + , mInputApdu(pInputApdu) +{ +} + + +IfdTransmit::IfdTransmit(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mSlotHandle() + , mInputApdu() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); + + if (pMessageObject.contains(COMMAND_APDUS())) + { + const auto& value = pMessageObject.value(COMMAND_APDUS()); + if (value.isArray()) + { + parseCommandApdu(value.toArray().at(0)); + if (value.toArray().size() > 1) + { + qCDebug(remote_device) << "Only using the first CommandAPDU. Command chaining ist not supported yet"; + } + } + else + { + invalidType(COMMAND_APDUS(), QLatin1String("array")); + } + } + else + { + missingValue(COMMAND_APDUS()); + } +} + + +const QString& IfdTransmit::getSlotHandle() const +{ + return mSlotHandle; +} + + +const QByteArray& IfdTransmit::getInputApdu() const +{ + return mInputApdu; +} + + +QJsonDocument IfdTransmit::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + QJsonArray commandApdus; + QJsonObject commandApdu; + commandApdu[INPUT_APDU()] = QString::fromLatin1(mInputApdu.toHex()); + commandApdu[ACCEPTABLE_STATUS_CODES()] = QJsonValue(); + commandApdus += commandApdu; + result[COMMAND_APDUS()] = commandApdus; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdTransmit.h b/src/remote_device/messages/IfdTransmit.h new file mode 100644 index 0000000..5075522 --- /dev/null +++ b/src/remote_device/messages/IfdTransmit.h @@ -0,0 +1,34 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + +#include + + +namespace governikus +{ +class IfdTransmit + : public RemoteMessage +{ + private: + QString mSlotHandle; + QByteArray mInputApdu; + + void parseCommandApdu(QJsonValue pEntry); + + public: + IfdTransmit(const QString& pSlotHandle, const QByteArray& pInputApdu); + IfdTransmit(const QJsonObject& pMessageObject); + virtual ~IfdTransmit() override = default; + + const QString& getSlotHandle() const; + const QByteArray& getInputApdu() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/IfdTransmitResponse.cpp b/src/remote_device/messages/IfdTransmitResponse.cpp new file mode 100644 index 0000000..e439c3c --- /dev/null +++ b/src/remote_device/messages/IfdTransmitResponse.cpp @@ -0,0 +1,91 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "IfdTransmitResponse.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(SLOT_HANDLE, "SlotHandle") +VALUE_NAME(RESPONSE_APDUS, "ResponseAPDUs") +} + + +IfdTransmitResponse::IfdTransmitResponse(const QString& pSlotHandle, const QByteArray& pResponseApdu, const QString& pResultMinor) + : RemoteMessageResponse(RemoteCardMessageType::IFDTransmitResponse, pResultMinor) + , mSlotHandle(pSlotHandle) + , mResponseApdu(pResponseApdu) +{ +} + + +IfdTransmitResponse::IfdTransmitResponse(const QJsonObject& pMessageObject) + : RemoteMessageResponse(pMessageObject) + , mSlotHandle() + , mResponseApdu() +{ + mSlotHandle = getStringValue(pMessageObject, SLOT_HANDLE()); + + if (pMessageObject.contains(RESPONSE_APDUS())) + { + const auto& value = pMessageObject.value(RESPONSE_APDUS()); + if (value.isArray()) + { + const auto& inputApduValue = value.toArray().at(0); + if (inputApduValue.isString()) + { + mResponseApdu = QByteArray::fromHex(inputApduValue.toString().toUtf8()); + } + else + { + invalidType(RESPONSE_APDUS(), QLatin1String("string array")); + } + } + else + { + invalidType(RESPONSE_APDUS(), QLatin1String("array")); + } + } + else + { + missingValue(RESPONSE_APDUS()); + } +} + + +const QString& IfdTransmitResponse::getSlotHandle() const +{ + return mSlotHandle; +} + + +const QByteArray& IfdTransmitResponse::getResponseApdu() const +{ + return mResponseApdu; +} + + +QJsonDocument IfdTransmitResponse::toJson(const QString& pContextHandle) const +{ + QJsonObject result = createMessageBody(pContextHandle); + + result[SLOT_HANDLE()] = mSlotHandle; + + QJsonArray responseApdus; + responseApdus += QString::fromLatin1(mResponseApdu.toHex()); + result[RESPONSE_APDUS()] = responseApdus; + + return QJsonDocument(result); +} diff --git a/src/remote_device/messages/IfdTransmitResponse.h b/src/remote_device/messages/IfdTransmitResponse.h new file mode 100644 index 0000000..d16c4ed --- /dev/null +++ b/src/remote_device/messages/IfdTransmitResponse.h @@ -0,0 +1,32 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessageResponse.h" + +#include + + +namespace governikus +{ +class IfdTransmitResponse + : public RemoteMessageResponse +{ + private: + QString mSlotHandle; + QByteArray mResponseApdu; + + public: + IfdTransmitResponse(const QString& pSlotHandle, const QByteArray& pResponseApdu = QByteArray(), const QString& pResultMinor = QString()); + IfdTransmitResponse(const QJsonObject& pMessageObject); + virtual ~IfdTransmitResponse() override = default; + + const QString& getSlotHandle() const; + const QByteArray& getResponseApdu() const; + virtual QJsonDocument toJson(const QString& pContextHandle) const override; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/MessageReceiver.cpp b/src/remote_device/messages/MessageReceiver.cpp new file mode 100644 index 0000000..7753020 --- /dev/null +++ b/src/remote_device/messages/MessageReceiver.cpp @@ -0,0 +1,214 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MessageReceiver.h" + +#include "Discovery.h" +#include "GetIfdStatus.h" +#include "IfdConnect.h" +#include "IfdConnectResponse.h" +#include "IfdDisconnect.h" +#include "IfdDisconnectResponse.h" +#include "IfdError.h" +#include "IfdEstablishContext.h" +#include "IfdEstablishContextResponse.h" +#include "IfdEstablishPaceChannel.h" +#include "IfdEstablishPaceChannelResponse.h" +#include "IfdStatus.h" +#include "IfdTransmit.h" +#include "IfdTransmitResponse.h" + + +using namespace governikus; + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::process(const QSharedPointer& pMessage) +{ + unprocessed(pMessage); +} + + +void MessageReceiver::unprocessed(const QSharedPointer& /*pMessage*/) +{ +} + + +void MessageReceiver::receive(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher) +{ + Q_ASSERT(pMessage); + Q_UNUSED(pRemoteDispatcher); + + switch (pMessage->getType()) + { + case RemoteCardMessageType::IFDEstablishContext: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDEstablishContextResponse: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDGetStatus: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDStatus: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + + case RemoteCardMessageType::IFDConnect: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDConnectResponse: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDDisconnect: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDDisconnectResponse: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDError: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDTransmit: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDTransmitResponse: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDEstablishPACEChannel: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::IFDEstablishPACEChannelResponse: + { + const QSharedPointer castMessage = pMessage.dynamicCast(); + process(castMessage); + break; + } + + case RemoteCardMessageType::UNDEFINED: + { + unprocessed(pMessage); + break; + } + } +} diff --git a/src/remote_device/messages/MessageReceiver.h b/src/remote_device/messages/MessageReceiver.h new file mode 100644 index 0000000..281fef5 --- /dev/null +++ b/src/remote_device/messages/MessageReceiver.h @@ -0,0 +1,57 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + + +namespace governikus +{ +class RemoteMessage; +class IfdEstablishContext; +class IfdEstablishContextResponse; +class GetIfdStatus; +class ReaderListMsg; +class IfdStatus; +class IfdConnect; +class IfdConnectResponse; +class IfdDisconnect; +class IfdDisconnectResponse; +class IfdError; +class IfdTransmit; +class IfdTransmitResponse; +class IfdEstablishPaceChannel; +class IfdEstablishPaceChannelResponse; +class RemoteDispatcher; + +class MessageReceiver +{ + Q_DISABLE_COPY(MessageReceiver) + + public: + MessageReceiver() = default; + virtual ~MessageReceiver() = default; + + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage); + + virtual void unprocessed(const QSharedPointer& pMessage); + + void receive(const QSharedPointer& pMessage, const QSharedPointer& pRemoteDispatcher = QSharedPointer()); +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/RemoteMessage.cpp b/src/remote_device/messages/RemoteMessage.cpp new file mode 100644 index 0000000..350b08f --- /dev/null +++ b/src/remote_device/messages/RemoteMessage.cpp @@ -0,0 +1,189 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "RemoteMessage.h" + +#include "Initializer.h" + +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(MSG_TYPE, "msg") +VALUE_NAME(CONTEXT_HANDLE, "ContextHandle") +} + + +static Initializer::Entry E([] { + qRegisterMetaType >("QSharedPointer"); + }); + + +QJsonObject RemoteMessage::createMessageBody(const QString& pContextHandle) const +{ + QJsonObject messageBody; + messageBody[MSG_TYPE()] = getEnumName(mMessageType); + if (mMessageType == RemoteCardMessageType::IFDEstablishContext) + { + return messageBody; + } + else + { + Q_ASSERT(!pContextHandle.isEmpty() || mMessageType == RemoteCardMessageType::IFDError); + } + + messageBody[CONTEXT_HANDLE()] = pContextHandle; + return messageBody; +} + + +void RemoteMessage::missingValue(const QLatin1String& pName) +{ + qCCritical(remote_device) << "Missing value" << pName; + mIsValid = false; +} + + +void RemoteMessage::invalidType(const QLatin1String& pName, const QLatin1String& pExpectedType) +{ + qCCritical(remote_device) << "The value of" << pName << "should be of type" << pExpectedType; + mIsValid = false; +} + + +bool RemoteMessage::getBoolValue(const QJsonObject& pJsonObject, const QLatin1String& pName) +{ + if (pJsonObject.contains(pName)) + { + const auto& value = pJsonObject.value(pName); + if (value.isBool()) + { + return value.toBool(); + } + + invalidType(pName, QLatin1String("boolean")); + return false; + } + + missingValue(pName); + return false; +} + + +int RemoteMessage::getIntValue(const QJsonObject& pJsonObject, const QLatin1String& pName) +{ + if (pJsonObject.contains(pName)) + { + const auto& value = pJsonObject.value(pName); + if (value.isDouble()) + { + return value.toInt(); + } + + invalidType(pName, QLatin1String("number")); + return 0; + } + + missingValue(pName); + return 0; +} + + +QString RemoteMessage::getStringValue(const QJsonObject& pJsonObject, const QLatin1String& pName) +{ + if (pJsonObject.contains(pName)) + { + const auto& value = pJsonObject.value(pName); + if (value.isString()) + { + return value.toString(); + } + + invalidType(pName, QLatin1String("string")); + return QString(); + } + + missingValue(pName); + return QString(); +} + + +QJsonObject RemoteMessage::parseByteArray(const QByteArray& pMessage) +{ + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(pMessage, &error); + if (error.error != QJsonParseError::NoError) + { + qCWarning(remote_device) << "Json parsing failed." << error.offset << ":" << error.errorString(); + } + + const QJsonObject& obj = doc.object(); + if (obj.isEmpty()) + { + qCWarning(remote_device) << "Expected object at top level"; + } + + return obj; +} + + +RemoteMessage::RemoteMessage(RemoteCardMessageType pMessageType) + : mIsValid(true) + , mMessageType(pMessageType) + , mContextHandle() +{ +} + + +RemoteMessage::RemoteMessage(const QJsonObject& pMessageObject) + : mIsValid(true) + , mMessageType(RemoteCardMessageType::UNDEFINED) + , mContextHandle() +{ + const QString& msg = getStringValue(pMessageObject, MSG_TYPE()); + mMessageType = Enum::fromString(msg, RemoteCardMessageType::UNDEFINED); + + if (mMessageType != RemoteCardMessageType::IFDEstablishContext) + { + mContextHandle = getStringValue(pMessageObject, CONTEXT_HANDLE()); + } +} + + +bool RemoteMessage::isValid() const +{ + return mIsValid; +} + + +RemoteCardMessageType RemoteMessage::getType() const +{ + return mMessageType; +} + + +const QString& RemoteMessage::getContextHandle() const +{ + return mContextHandle; +} + + +QJsonDocument RemoteMessage::toJson(const QString& pContextHandle) const +{ + Q_ASSERT(false); + + qCCritical(remote_device) << "Unable to convert an untyped RemoteMessage to json:" << pContextHandle; + return QJsonDocument(); +} + + +#include "moc_RemoteMessage.cpp" diff --git a/src/remote_device/messages/RemoteMessage.h b/src/remote_device/messages/RemoteMessage.h new file mode 100644 index 0000000..4370edb --- /dev/null +++ b/src/remote_device/messages/RemoteMessage.h @@ -0,0 +1,71 @@ +/*! + * \brief Classes that model remote card reader messages. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" + +#include +#include +#include + + +#define VALUE_NAME(_name, _key)\ + inline QLatin1String _name(){\ + return QLatin1String(_key);\ + } + + +namespace governikus +{ +defineEnumType(RemoteCardMessageType, + IFDEstablishContext, + IFDEstablishContextResponse, + IFDGetStatus, + IFDStatus, + IFDConnect, + IFDConnectResponse, + IFDDisconnect, + IFDDisconnectResponse, + IFDError, + IFDTransmit, + IFDTransmitResponse, + IFDEstablishPACEChannel, + IFDEstablishPACEChannelResponse, + UNDEFINED) + + +class RemoteMessage +{ + private: + bool mIsValid; + RemoteCardMessageType mMessageType; + QString mContextHandle; + + protected: + virtual QJsonObject createMessageBody(const QString& pContextHandle) const; + void missingValue(const QLatin1String& pName); + void invalidType(const QLatin1String& pName, const QLatin1String& pExpectedType); + bool getBoolValue(const QJsonObject& pJsonObject, const QLatin1String& pName); + int getIntValue(const QJsonObject& pJsonObject, const QLatin1String& pName); + QString getStringValue(const QJsonObject& pJsonObject, const QLatin1String& pName); + + public: + static QJsonObject parseByteArray(const QByteArray& pMessage); + + RemoteMessage(RemoteCardMessageType pType); + RemoteMessage(const QJsonObject& pMessageObject); + virtual ~RemoteMessage() = default; + + bool isValid() const; + RemoteCardMessageType getType() const; + const QString& getContextHandle() const; + + virtual QJsonDocument toJson(const QString& pContextHandle) const; +}; + + +} /* namespace governikus */ diff --git a/src/remote_device/messages/RemoteMessageParser.cpp b/src/remote_device/messages/RemoteMessageParser.cpp new file mode 100644 index 0000000..10d4593 --- /dev/null +++ b/src/remote_device/messages/RemoteMessageParser.cpp @@ -0,0 +1,217 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "RemoteMessageParser.h" + +#include "messages/Discovery.h" +#include "messages/GetIfdStatus.h" +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/IfdEstablishPaceChannel.h" +#include "messages/IfdEstablishPaceChannelResponse.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" + +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +static QStringList parseArrayOfString(const QJsonArray& pArray) +{ + QStringList result; + for (const QJsonValue& v : pArray) + { + if (!v.isString()) + { + qCWarning(remote_device) << "Expected string but found" << v.type(); + continue; + } + result += v.toString(); + } + + return result; +} + + +static QSharedPointer fail(const QString& pLogMessage) +{ + qCWarning(remote_device) << pLogMessage; + + return QSharedPointer(); +} + + +static QSharedPointer parseMessage(const QJsonObject& pJsonObject) +{ + const RemoteMessage remoteMessage(pJsonObject); + const RemoteCardMessageType messageType = remoteMessage.getType(); + switch (messageType) + { + case RemoteCardMessageType::IFDEstablishContext: + return QSharedPointer(new IfdEstablishContext(pJsonObject)); + + case RemoteCardMessageType::IFDEstablishContextResponse: + return QSharedPointer(new IfdEstablishContextResponse(pJsonObject)); + + case RemoteCardMessageType::IFDGetStatus: + return QSharedPointer(new GetIfdStatus(pJsonObject)); + + case RemoteCardMessageType::IFDConnect: + return QSharedPointer(new IfdConnect(pJsonObject)); + + case RemoteCardMessageType::IFDDisconnect: + return QSharedPointer(new IfdDisconnect(pJsonObject)); + + case RemoteCardMessageType::IFDError: + return QSharedPointer(new IfdError(pJsonObject)); + + case RemoteCardMessageType::IFDTransmit: + return QSharedPointer(new IfdTransmit(pJsonObject)); + + case RemoteCardMessageType::IFDStatus: + return QSharedPointer(new IfdStatus(pJsonObject)); + + case RemoteCardMessageType::IFDConnectResponse: + return QSharedPointer(new IfdConnectResponse(pJsonObject)); + + case RemoteCardMessageType::IFDDisconnectResponse: + return QSharedPointer(new IfdDisconnectResponse(pJsonObject)); + + case RemoteCardMessageType::IFDTransmitResponse: + return QSharedPointer(new IfdTransmitResponse(pJsonObject)); + + case RemoteCardMessageType::IFDEstablishPACEChannel: + return QSharedPointer(new IfdEstablishPaceChannel(pJsonObject)); + + case RemoteCardMessageType::IFDEstablishPACEChannelResponse: + return QSharedPointer(new IfdEstablishPaceChannelResponse(pJsonObject)); + + case RemoteCardMessageType::UNDEFINED: + return fail(QStringLiteral("Unknown RemoteMessage received")); + } + + Q_UNREACHABLE(); +} + + +RemoteMessageParser::RemoteMessageParser() +{ +} + + +RemoteMessageParser::~RemoteMessageParser() +{ +} + + +QSharedPointer RemoteMessageParser::parseDiscovery(const QJsonDocument& pJsonDocument) const +{ + const QJsonObject& rootObject = pJsonDocument.object(); + if (rootObject.isEmpty()) + { + qCWarning(remote_device) << "Expected object at top level"; + return QSharedPointer(); + } + + const QJsonValue& ifdNameValue = rootObject.value(QLatin1String("IFDName")); + if (!ifdNameValue.isString()) + { + qCWarning(remote_device) << "The value of \"IFDName\" should be of type string"; + return QSharedPointer(); + } + const QString& idfName = ifdNameValue.toString(); + + const QJsonValue& ifdIdValue = rootObject.value(QLatin1String("IFDID")); + if (!ifdIdValue.isString()) + { + qCWarning(remote_device) << "The value of \"IFDID\" should be of type string"; + return QSharedPointer(); + } + const QString& ifdId = ifdIdValue.toString(); + + const QJsonValue& msgValue = rootObject.value(QLatin1String("msg")); + if (!msgValue.isString()) + { + qCWarning(remote_device) << "The value of \"msg\" should be of type string"; + return QSharedPointer(); + } + else if (msgValue.toString() != QLatin1String("REMOTE_IFD")) + { + qCWarning(remote_device) << "The value of \"msg\" should be \"REMOTE_IFD\""; + return QSharedPointer(); + } + // This field is not saved in the C++ object. + + const QJsonValue& portValue = rootObject.value(QLatin1String("port")); + if (!portValue.isDouble()) + { + qCWarning(remote_device) << "The value of \"port\" should be of type double"; + return QSharedPointer(); + } + const long portLong = portValue.toInt(); + if (portLong <= 0 || portLong > static_cast(USHRT_MAX)) + { + qCWarning(remote_device) << "Expected unsigned integer number (16 bit) for port number"; + return QSharedPointer(); + } + const quint16 port = static_cast(portLong); + + const QJsonValue& supportedApisValue = rootObject.value(QLatin1String("SupportedAPI")); + if (!supportedApisValue.isArray()) + { + qCWarning(remote_device) << "The value of \"availableApiLevels\" should be of type string array"; + return QSharedPointer(); + } + const QStringList& availableApiLevels = parseArrayOfString(supportedApisValue.toArray()); + + return QSharedPointer(new Discovery(idfName, ifdId, port, availableApiLevels)); +} + + +QSharedPointer RemoteMessageParser::parse(const QByteArray& pJsonData) const +{ + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(pJsonData, &error); + if (error.error != QJsonParseError::NoError) + { + qCWarning(remote_device) << pJsonData; + + return fail(QStringLiteral("Json parsing failed. Error at offset %1: %2").arg(error.offset).arg(error.errorString())); + } + + return parse(doc); +} + + +QSharedPointer RemoteMessageParser::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("msg"))) + { + return parseMessage(rootObject); + } + else + { + return fail(QStringLiteral("Root object has no messageType")); + } +} diff --git a/src/remote_device/messages/RemoteMessageParser.h b/src/remote_device/messages/RemoteMessageParser.h new file mode 100644 index 0000000..639de00 --- /dev/null +++ b/src/remote_device/messages/RemoteMessageParser.h @@ -0,0 +1,31 @@ +/*! + * \brief Class for parsing JSON data to remote card message objects. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include + + +namespace governikus +{ +class Discovery; +class RemoteMessage; + +class RemoteMessageParser +{ + public: + RemoteMessageParser(); + ~RemoteMessageParser(); + + QSharedPointer parseDiscovery(const QJsonDocument& pJsonDocument) const; + QSharedPointer parse(const QByteArray& pJsonData) const; + QSharedPointer parse(const QJsonDocument& pJsonDocument) const; +}; + +} /* namespace governikus */ diff --git a/src/remote_device/messages/RemoteMessageResponse.cpp b/src/remote_device/messages/RemoteMessageResponse.cpp new file mode 100644 index 0000000..1b9936c --- /dev/null +++ b/src/remote_device/messages/RemoteMessageResponse.cpp @@ -0,0 +1,71 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "RemoteMessageResponse.h" + +#include + + +Q_DECLARE_LOGGING_CATEGORY(remote_device) + + +using namespace governikus; + + +#define RESULTMAJOR "http://www.bsi.bund.de/ecard/api/1.1/resultmajor" + + +namespace +{ +VALUE_NAME(RESULT_MAJOR, "ResultMajor") +VALUE_NAME(RESULT_MINOR, "ResultMinor") +} + + +QJsonObject RemoteMessageResponse::createMessageBody(const QString& pContextHandle) const +{ + QJsonObject result = RemoteMessage::createMessageBody(pContextHandle); + result[RESULT_MAJOR()] = mResultMajor; + result[RESULT_MINOR()] = mResultMinor.isEmpty() ? QJsonValue() : mResultMinor; + return result; +} + + +RemoteMessageResponse::RemoteMessageResponse(RemoteCardMessageType pMessageType, const QString& pResultMinor) + : RemoteMessage(pMessageType) + , mResultMajor(QStringLiteral(RESULTMAJOR "#ok")) + , mResultMinor() +{ + if (!pResultMinor.isEmpty()) + { + mResultMajor = QStringLiteral(RESULTMAJOR "#error"); + mResultMinor = QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor") + pResultMinor; + } +} + + +RemoteMessageResponse::RemoteMessageResponse(const QJsonObject& pMessageObject) + : RemoteMessage(pMessageObject) + , mResultMajor() + , mResultMinor() +{ + mResultMajor = getStringValue(pMessageObject, RESULT_MAJOR()); + if (resultHasError()) + { + mResultMinor = getStringValue(pMessageObject, RESULT_MINOR()); + } +} + + +bool RemoteMessageResponse::resultHasError() const +{ + return mResultMajor != QLatin1String(RESULTMAJOR "#ok"); +} + + +const QString& RemoteMessageResponse::getResultMinor() const +{ + return mResultMinor; +} diff --git a/src/remote_device/messages/RemoteMessageResponse.h b/src/remote_device/messages/RemoteMessageResponse.h new file mode 100644 index 0000000..c46cda0 --- /dev/null +++ b/src/remote_device/messages/RemoteMessageResponse.h @@ -0,0 +1,34 @@ +/*! + * \brief Classes that model remote card reader response messages. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteMessage.h" + + +namespace governikus +{ +class RemoteMessageResponse + : public RemoteMessage +{ + private: + QString mResultMajor; + QString mResultMinor; + + protected: + virtual QJsonObject createMessageBody(const QString& pContextHandle) const override; + + public: + RemoteMessageResponse(RemoteCardMessageType pType, const QString& pResultMinor = QString()); + RemoteMessageResponse(const QJsonObject& pMessageObject); + virtual ~RemoteMessageResponse() override = default; + + bool resultHasError() const; + const QString& getResultMinor() const; +}; + + +} /* namespace governikus */ diff --git a/src/secure_storage/CMakeLists.txt b/src/secure_storage/CMakeLists.txt new file mode 100644 index 0000000..6c9b2a6 --- /dev/null +++ b/src/secure_storage/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppSecureStorage) + +TARGET_LINK_LIBRARIES(AusweisAppSecureStorage Qt5::Core Qt5::Network AusweisAppGlobal) diff --git a/src/secure_storage/SecureStorage.cpp b/src/secure_storage/SecureStorage.cpp new file mode 100644 index 0000000..dbbfd18 --- /dev/null +++ b/src/secure_storage/SecureStorage.cpp @@ -0,0 +1,347 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "SecureStorage.h" + +#include "FileDestination.h" +#include "SingletonHelper.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(securestorage) + +namespace +{ +#define CONFIG_NAME(_name, _key)\ + inline QLatin1String _name(){\ + return QLatin1String(_key);\ + } + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_CV_ROOT_CERTIFICATE, "cvRootCertificates") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_CV_ROOT_CERTIFICATE_TEST, "cvRootCertificatesTest") + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_UPDATE_CERTIFICATES, "updateCertificates") + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_TLS_SETTINGS, "tlsSettings") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_PSK, "tlsSettingsPsk") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_REMOTE_READER, "tlsSettingsRemoteReader") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_REMOTE_READER_PAIRING, "tlsSettingsRemoteReaderPairing") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_MIN_STATIC_KEY_SIZES, "minStaticKeySizes") +CONFIG_NAME(CONFIGURATION_GROUP_NAME_MIN_EPHEMERAL_KEY_SIZES, "minEphemeralKeySizes") + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_SELF_AUTHENTICATION, "selfAuthentication") +CONFIG_NAME(CONFIGURATION_NAME_SELF_AUTHENTICATION_URL, "url") +CONFIG_NAME(CONFIGURATION_NAME_SELF_AUTHENTICATION_TEST_URL, "testUrl") +CONFIG_NAME(CONFIGURATION_NAME_SELF_AUTHENTICATION_CERTDESCR, "certDescr") +CONFIG_NAME(CONFIGURATION_NAME_SELF_AUTHENTICATION_TEST_CERTDESCR, "testCertDescr") + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_UPDATE_SERVER, "updateServer") +CONFIG_NAME(CONFIGURATION_NAME_UPDATE_SERVER_BASE_URL, "baseUrl") + +CONFIG_NAME(CONFIGURATION_GROUP_NAME_UPDATES, "updates") +CONFIG_NAME(CONFIGURATION_NAME_APPCAST_UPDATE_URL, "release") +CONFIG_NAME(CONFIGURATION_NAME_APPCAST_BETA_UPDATE_URL, "beta") +} + +defineSingleton(SecureStorage) + + +SecureStorage::SecureStorage() + : mLoadedTime() + , mCvcas() + , mCvcasTest() + , mUpdateCertificates() + , mSelfAuthenticationUrl() + , mSelfAuthenticationTestUrl() + , mUpdateServerBaseUrl() + , mSelfAuthenticationCertDescr() + , mSelfAuthenticationTestCertDescr() + , mAppcastUpdateUrl() + , mAppcastBetaUpdateUrl() + , mTlsConfig() + , mTlsConfigPsk() + , mTlsConfigRemote() + , mTlsConfigRemotePsk() + , mMinStaticKeySizes() + , mMinEphemeralKeySizes() +{ + load(); +} + + +SecureStorage::~SecureStorage() +{ +} + + +SecureStorage& SecureStorage::getInstance() +{ + return *Instance; +} + + +void SecureStorage::load() +{ + const auto& path = FileDestination::getPath("config.json"); + + if (!QFile::exists(path)) + { + qCCritical(securestorage) << "SecureStorage not found"; + return; + } + + const auto& lastModified = QFileInfo(path).lastModified(); + if (lastModified.isValid() && lastModified <= mLoadedTime) + { + return; + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qCCritical(securestorage) << "Wasn't able to open SecureStorage"; + return; + } + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(configFile.readAll(), &parseError); + configFile.close(); + if (parseError.error != QJsonParseError::NoError) + { + qCCritical(securestorage) << "Parse error while reading SecureStorage on position " << parseError.offset << ": " << parseError.errorString(); + return; + } + QJsonObject config = document.object(); + + mCvcas.clear(); + readByteArrayList(mCvcas, config, CONFIGURATION_GROUP_NAME_CV_ROOT_CERTIFICATE()); + + mCvcasTest.clear(); + readByteArrayList(mCvcasTest, config, CONFIGURATION_GROUP_NAME_CV_ROOT_CERTIFICATE_TEST()); + + QByteArrayList certificates; + readByteArrayList(certificates, config, CONFIGURATION_GROUP_NAME_UPDATE_CERTIFICATES()); + mUpdateCertificates.clear(); + for (int i = 0; i < certificates.size(); ++i) + { + QSslCertificate certificate(QByteArray::fromHex(certificates[i]), QSsl::Der); + if (certificate.isNull()) + { + qCCritical(securestorage) << "Failed to read update certificate[" << i << "] from SecureStorage"; + continue; + } + mUpdateCertificates += certificate; + } + + QJsonValue tlsValue = config.value(CONFIGURATION_GROUP_NAME_TLS_SETTINGS()); + if (tlsValue.isObject()) + { + mTlsConfig.load(tlsValue.toObject()); + } + + QJsonValue tlsPskValue = config.value(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_PSK()); + if (tlsPskValue.isObject()) + { + mTlsConfigPsk.load(tlsPskValue.toObject()); + } + + QJsonValue tlsRemoteReaderValue = config.value(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_REMOTE_READER()); + if (tlsRemoteReaderValue.isObject()) + { + mTlsConfigRemote.load(tlsRemoteReaderValue.toObject()); + } + QJsonValue tlsRemoteReaderPairingValue = config.value(CONFIGURATION_GROUP_NAME_TLS_CONFIGURATION_REMOTE_READER_PAIRING()); + if (tlsRemoteReaderPairingValue.isObject()) + { + mTlsConfigRemotePsk.load(tlsRemoteReaderPairingValue.toObject()); + } + + mMinStaticKeySizes = readKeySizes(config, CONFIGURATION_GROUP_NAME_MIN_STATIC_KEY_SIZES()); + mMinEphemeralKeySizes = readKeySizes(config, CONFIGURATION_GROUP_NAME_MIN_EPHEMERAL_KEY_SIZES()); + + + mSelfAuthenticationUrl = readGroup(config, CONFIGURATION_GROUP_NAME_SELF_AUTHENTICATION(), CONFIGURATION_NAME_SELF_AUTHENTICATION_URL()); + mSelfAuthenticationTestUrl = readGroup(config, CONFIGURATION_GROUP_NAME_SELF_AUTHENTICATION(), CONFIGURATION_NAME_SELF_AUTHENTICATION_TEST_URL()); + mSelfAuthenticationCertDescr = readGroup(config, CONFIGURATION_GROUP_NAME_SELF_AUTHENTICATION(), CONFIGURATION_NAME_SELF_AUTHENTICATION_CERTDESCR()).toLatin1(); + mSelfAuthenticationTestCertDescr = readGroup(config, CONFIGURATION_GROUP_NAME_SELF_AUTHENTICATION(), CONFIGURATION_NAME_SELF_AUTHENTICATION_TEST_CERTDESCR()).toLatin1(); + + mUpdateServerBaseUrl = readGroup(config, CONFIGURATION_GROUP_NAME_UPDATE_SERVER(), CONFIGURATION_NAME_UPDATE_SERVER_BASE_URL()); + + mAppcastUpdateUrl = readGroup(config, CONFIGURATION_GROUP_NAME_UPDATES(), CONFIGURATION_NAME_APPCAST_UPDATE_URL()); + mAppcastBetaUpdateUrl = readGroup(config, CONFIGURATION_GROUP_NAME_UPDATES(), CONFIGURATION_NAME_APPCAST_BETA_UPDATE_URL()); + + mLoadedTime = lastModified; + qCInfo(securestorage) << "SecureStorage successfully loaded"; +} + + +const QByteArrayList& SecureStorage::getCVRootCertificates(bool pProductive) const +{ + return pProductive ? mCvcas : mCvcasTest; +} + + +const QVector& SecureStorage::getUpdateCertificates() const +{ + return mUpdateCertificates; +} + + +const QUrl& SecureStorage::getSelfAuthenticationUrl(bool pTest) const +{ + return pTest ? mSelfAuthenticationTestUrl : mSelfAuthenticationUrl; +} + + +const QByteArray& SecureStorage::getSelfAuthenticationCertDescr(bool pTest) const +{ + return pTest ? mSelfAuthenticationTestCertDescr : mSelfAuthenticationCertDescr; +} + + +const QUrl& SecureStorage::getUpdateServerBaseUrl() const +{ + return mUpdateServerBaseUrl; +} + + +const QUrl& SecureStorage::getAppcastUpdateUrl() const +{ + return mAppcastUpdateUrl; +} + + +const QUrl& SecureStorage::getAppcastBetaUpdateUrl() const +{ + return mAppcastBetaUpdateUrl; +} + + +const TlsConfiguration& SecureStorage::getTlsConfig(TlsSuite pTlsSuite) const +{ + return pTlsSuite == TlsSuite::PSK ? mTlsConfigPsk : mTlsConfig; +} + + +const TlsConfiguration& SecureStorage::getTlsConfigRemote(TlsSuite pTlsSuite) const +{ + return pTlsSuite == TlsSuite::PSK ? mTlsConfigRemotePsk : mTlsConfigRemote; +} + + +int SecureStorage::getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const +{ + if (!mMinStaticKeySizes.contains(pKeyAlgorithm)) + { + qCWarning(securestorage) << "No minimum ephemeral key size specified, returning default"; + } + return mMinStaticKeySizes.value(pKeyAlgorithm, 0); +} + + +int SecureStorage::getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const +{ + if (!mMinEphemeralKeySizes.contains(pKeyAlgorithm)) + { + qCWarning(securestorage) << "No minimum ephemeral key size specified, returning default"; + } + return mMinEphemeralKeySizes.value(pKeyAlgorithm, 0); +} + + +bool SecureStorage::readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String pName) +{ + QJsonValue value = pConfig.value(pName); + if (!value.isArray()) + { + qCCritical(securestorage) << "Expecting array for" << pName << "in SecureStorage"; + return false; + } + pArray = value.toArray(); + return true; +} + + +QString SecureStorage::readGroup(const QJsonObject& pConfig, const QLatin1String pGroup, const QLatin1String pName) +{ + QJsonValue value = pConfig.value(pGroup); + if (!value.isObject()) + { + qCCritical(securestorage) << "Expecting group for" << pGroup << "in SecureStorage"; + return QString(); + } + + QJsonObject groupObject = value.toObject(); + value = groupObject.value(pName); + if (!value.isString()) + { + qCCritical(securestorage) << "Expecting string for" << pGroup << "/" << pName << "in SecureStorage"; + return QString(); + } + + return value.toString(); +} + + +QMap SecureStorage::readKeySizes(const QJsonObject& pConfig, const QLatin1String pKey) +{ + QMap keySizes; + const auto& object = pConfig.value(pKey).toObject(); + if (!object.isEmpty()) + { + const auto& keys = object.keys(); + for (const QString& key : keys) + { + 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 + { + qCCritical(securestorage) << "Ignore unknown key type" << key; + } + } + } + return keySizes; +} + + +void SecureStorage::readByteArrayList(QByteArrayList& pArray, const QJsonObject& pConfig, const QLatin1String pName) +{ + QJsonArray jsonArray; + if (readJsonArray(jsonArray, pConfig, pName)) + { + for (int i = 0; i < jsonArray.size(); ++i) + { + QJsonValue certificate = jsonArray[i]; + if (!certificate.isString()) + { + qCCritical(securestorage) << "Expected hexstring in array[" << i << "] " << pName << " in SecureStorage"; + continue; + } + pArray += certificate.toString().toLatin1(); + } + } +} diff --git a/src/secure_storage/SecureStorage.h b/src/secure_storage/SecureStorage.h new file mode 100644 index 0000000..bbeefc7 --- /dev/null +++ b/src/secure_storage/SecureStorage.h @@ -0,0 +1,85 @@ +/*! + * \brief Utility class that provides access to the "secure storage" of the application, which contains + * the certificates for preverification and update checks. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "TlsConfiguration.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class test_SecureStorage; + + +namespace governikus +{ + +using SignatureAlgorithmPair = QPair; + +class SecureStorage +{ + friend class ::test_SecureStorage; + + private: + QDateTime mLoadedTime; + QByteArrayList mCvcas; + QByteArrayList mCvcasTest; + QVector mUpdateCertificates; + QUrl mSelfAuthenticationUrl; + QUrl mSelfAuthenticationTestUrl; + QUrl mUpdateServerBaseUrl; + QByteArray mSelfAuthenticationCertDescr; + QByteArray mSelfAuthenticationTestCertDescr; + QUrl mAppcastUpdateUrl; + QUrl mAppcastBetaUpdateUrl; + + TlsConfiguration mTlsConfig, mTlsConfigPsk, mTlsConfigRemote, mTlsConfigRemotePsk; + QMap mMinStaticKeySizes; + QMap mMinEphemeralKeySizes; + + bool readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String pName); + QString readGroup(const QJsonObject& pConfig, const QLatin1String pGroup, const QLatin1String pName); + QMap readKeySizes(const QJsonObject& pConfig, const QLatin1String pKey); + void readByteArrayList(QByteArrayList& pArray, const QJsonObject& pConfig, const QLatin1String pName); + + void load(); + + protected: + SecureStorage(); + virtual ~SecureStorage(); + + public: + static SecureStorage& getInstance(); + + enum class TlsSuite + { + DEFAULT, PSK, + }; + + const QByteArrayList& getCVRootCertificates(bool pProductive) const; + const QVector& getUpdateCertificates() const; + const QUrl& getSelfAuthenticationUrl(bool pTest = false) const; + const QByteArray& getSelfAuthenticationCertDescr(bool pTest = false) const; + const QUrl& getUpdateServerBaseUrl() const; + const QUrl& getAppcastUpdateUrl() const; + const QUrl& getAppcastBetaUpdateUrl() const; + const TlsConfiguration& getTlsConfig(TlsSuite pTlsSuite = TlsSuite::DEFAULT) const; + const TlsConfiguration& getTlsConfigRemote(TlsSuite pTlsSuite = TlsSuite::DEFAULT) const; + int getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; + int getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const; +}; + + +} // namespace governikus diff --git a/src/secure_storage/TlsConfiguration.cpp b/src/secure_storage/TlsConfiguration.cpp new file mode 100644 index 0000000..19a3dcd --- /dev/null +++ b/src/secure_storage/TlsConfiguration.cpp @@ -0,0 +1,239 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TlsConfiguration.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; +} + + +TlsConfiguration::TlsConfiguration() + : mConfiguration() +{ +} + + +TlsConfiguration::~TlsConfiguration() +{ +} + + +void TlsConfiguration::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); + +#ifdef GOVERNIKUS_QT + mConfiguration.setSignatureAndHashAlgorithms(signatureAlgorithms); +#else + Q_UNUSED(signatureAlgorithms) +#endif +} + + +QSsl::SslProtocol TlsConfiguration::getProtocolVersion() const +{ + return mConfiguration.protocol(); +} + + +QList TlsConfiguration::getCiphers() const +{ + return mConfiguration.ciphers(); +} + + +QVector TlsConfiguration::getEllipticCurves() const +{ + return mConfiguration.ellipticCurves(); +} + + +QVector TlsConfiguration::getSignatureAlgorithms() const +{ +#ifdef GOVERNIKUS_QT + return mConfiguration.signatureAndHashAlgorithms(); + +#else + return QVector(); + +#endif +} + + +const QSslConfiguration& TlsConfiguration::getConfiguration() const +{ + return mConfiguration; +} + + +bool TlsConfiguration::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 TlsConfiguration::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 TlsConfiguration::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/secure_storage/TlsConfiguration.h b/src/secure_storage/TlsConfiguration.h new file mode 100644 index 0000000..e3a60f4 --- /dev/null +++ b/src/secure_storage/TlsConfiguration.h @@ -0,0 +1,86 @@ +/*! + * \brief Configuration options for TLS channels + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + +class test_TlsConfiguration; + + +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 TlsConfiguration final +{ + friend class SecureStorage; + friend class ::test_TlsConfiguration; + friend bool operator==(const TlsConfiguration& pLeft, const TlsConfiguration& pRight); + + private: + QSslConfiguration mConfiguration; + + TlsConfiguration(); + ~TlsConfiguration(); + + bool readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, 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 TlsConfiguration& pLeft, const TlsConfiguration& pRight) +{ + return &pLeft == &pRight || ( + pLeft.mConfiguration == pRight.mConfiguration); +} + + +inline bool operator!=(const TlsConfiguration& pLeft, const TlsConfiguration& pRight) +{ + return !(pLeft == pRight); +} + + +} // namespace governikus diff --git a/src/services/AppUpdateBackend.cpp b/src/services/AppUpdateBackend.cpp deleted file mode 100644 index abd698c..0000000 --- a/src/services/AppUpdateBackend.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/*! - * \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 deleted file mode 100644 index dec5382..0000000 --- a/src/services/AppUpdateBackend.h +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * \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 index 2192ed7..3e08376 100644 --- a/src/services/AppUpdateData.cpp +++ b/src/services/AppUpdateData.cpp @@ -1,11 +1,21 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "AppUpdateData.h" +#include "AppSettings.h" +#include "Env.h" +#include "VersionNumber.h" + +#include +#include +#include + using namespace governikus; +Q_DECLARE_LOGGING_CATEGORY(appupdate) + AppUpdateData::AppUpdateData() : mDate() , mVersion() @@ -14,6 +24,20 @@ AppUpdateData::AppUpdateData() , mChecksumUrl() , mNotesUrl() , mNotes() + , mParsingResult(GlobalStatus::Code::No_Error) +{ +} + + +AppUpdateData::AppUpdateData(GlobalStatus pParsingResult) + : mDate() + , mVersion() + , mUrl() + , mSize(-1) + , mChecksumUrl() + , mNotesUrl() + , mNotes() + , mParsingResult(pParsingResult) { } @@ -27,21 +51,15 @@ bool AppUpdateData::isValid() const } -const QDateTime AppUpdateData::getDate() const -{ - return mDate; -} - - void AppUpdateData::setDate(const QDateTime& pDate) { mDate = pDate; } -const QString& AppUpdateData::getVersion() const +const QDateTime AppUpdateData::getDate() const { - return mVersion; + return mDate; } @@ -51,9 +69,9 @@ void AppUpdateData::setVersion(const QString& pVersion) } -const QUrl& AppUpdateData::getUrl() const +const QString& AppUpdateData::getVersion() const { - return mUrl; + return mVersion; } @@ -63,6 +81,12 @@ void AppUpdateData::setUrl(const QUrl& pUrl) } +const QUrl& AppUpdateData::getUrl() const +{ + return mUrl; +} + + int AppUpdateData::getSize() const { return mSize; @@ -82,15 +106,21 @@ void AppUpdateData::setSize(int pSize) } +void AppUpdateData::setChecksumUrl(const QUrl& pChecksumUrl) +{ + mChecksumUrl = pChecksumUrl; +} + + const QUrl& AppUpdateData::getChecksumUrl() const { return mChecksumUrl; } -void AppUpdateData::setChecksumUrl(const QUrl& pUrl) +void AppUpdateData::setNotesUrl(const QUrl& pNotesUrl) { - mChecksumUrl = pUrl; + mNotesUrl = pNotesUrl; } @@ -100,12 +130,6 @@ const QUrl& AppUpdateData::getNotesUrl() const } -void AppUpdateData::setNotesUrl(const QUrl& pUrl) -{ - mNotesUrl = pUrl; -} - - void AppUpdateData::setNotes(const QString& pNotes) { mNotes = pNotes; @@ -116,3 +140,102 @@ const QString& AppUpdateData::getNotes() const { return mNotes; } + + +const GlobalStatus& AppUpdateData::getParsingResult() +{ + return mParsingResult; +} + + +AppUpdateData AppUpdateData::parse(const QByteArray& pData) +{ + QJsonParseError jsonError; + + const auto& json = QJsonDocument::fromJson(pData, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + qCWarning(appupdate) << "Cannot parse json data:" << jsonError.errorString(); + return AppUpdateData(GlobalStatus::Code::Downloader_Data_Corrupted); + } + + const auto& obj = json.object(); + const QJsonValue& items = obj[QLatin1String("items")]; + + if (!items.isArray()) + { + qCWarning(appupdate) << "Field 'items' cannot be parsed"; + return AppUpdateData(GlobalStatus::Code::Downloader_Data_Corrupted); + } + + const auto& itemArray = items.toArray(); + const auto& end = itemArray.constEnd(); + for (auto iter = itemArray.constBegin(); iter != end; ++iter) + { + if (iter->isObject()) + { + auto jsonObject = iter->toObject(); + if (checkPlatformObject(jsonObject)) + { + AppUpdateData newData; + newData.setVersion(jsonObject[QLatin1String("version")].toString()); + newData.setUrl(QUrl(jsonObject[QLatin1String("url")].toString())); + newData.setNotesUrl(QUrl(jsonObject[QLatin1String("notes")].toString())); + newData.setDate(QDateTime::fromString(jsonObject[QLatin1String("date")].toString(), Qt::ISODate)); + newData.setChecksumUrl(QUrl(jsonObject[QLatin1String("checksum")].toString())); + newData.setSize(jsonObject[QLatin1String("size")].toInt(-1)); + return newData; + } + } + else + { + qCWarning(appupdate) << "Object of field 'items' cannot be parsed"; + return AppUpdateData(GlobalStatus::Code::Downloader_Data_Corrupted); + } + } + + qCWarning(appupdate()) << "No matching platform found in update json"; + return AppUpdateData(GlobalStatus::Code::No_Error); +} + + +bool AppUpdateData::checkPlatformObject(const QJsonObject& pJson) +{ + const auto& platform = pJson[QLatin1String("platform")].toString(); + + if (!isPlatform(platform)) + { + qCDebug(appupdate) << "Unused platform:" << platform; + return false; + } + + qCDebug(appupdate) << "Found platform:" << platform; + return true; +} + + +bool AppUpdateData::isPlatform(const QString& pPlatform) +{ +#ifdef Q_OS_WIN + if (pPlatform == QLatin1String("win")) + { + return true; + } +#endif + +#ifdef Q_OS_MACOS + if (pPlatform == QLatin1String("mac")) + { + return true; + } +#endif + +#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN) + if (pPlatform == QLatin1String("src")) + { + return true; + } +#endif + + return false; +} diff --git a/src/services/AppUpdateData.h b/src/services/AppUpdateData.h index 976a1da..a584b9e 100644 --- a/src/services/AppUpdateData.h +++ b/src/services/AppUpdateData.h @@ -1,12 +1,15 @@ /*! * \brief Update data implementation for application version. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "GlobalStatus.h" + #include +#include #include #include @@ -23,9 +26,14 @@ class AppUpdateData QUrl mChecksumUrl; QUrl mNotesUrl; QString mNotes; + GlobalStatus mParsingResult; + + static bool checkPlatformObject(const QJsonObject& pJson); + static bool isPlatform(const QString& pPlatform); public: AppUpdateData(); + AppUpdateData(GlobalStatus pParsingResult); bool isValid() const; @@ -42,13 +50,17 @@ class AppUpdateData void setSize(int pSize); const QUrl& getChecksumUrl() const; - void setChecksumUrl(const QUrl& pUrl); + void setChecksumUrl(const QUrl& pChecksumUrl); const QUrl& getNotesUrl() const; - void setNotesUrl(const QUrl& pUrl); + void setNotesUrl(const QUrl& pNotesUrl); const QString& getNotes() const; void setNotes(const QString& pNotes); + + const GlobalStatus& getParsingResult(); + + static AppUpdateData parse(const QByteArray& pData); }; diff --git a/src/services/AppUpdateService.cpp b/src/services/AppUpdateService.cpp deleted file mode 100644 index 7665ae2..0000000 --- a/src/services/AppUpdateService.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * \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 deleted file mode 100644 index cb1a67a..0000000 --- a/src/services/AppUpdateService.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * \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/AppUpdater.cpp b/src/services/AppUpdater.cpp new file mode 100644 index 0000000..ad911db --- /dev/null +++ b/src/services/AppUpdater.cpp @@ -0,0 +1,146 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppUpdater.h" + +#include "AppSettings.h" +#include "Downloader.h" +#include "Env.h" +#include "ProviderConfiguration.h" +#include "SecureStorage.h" +#include "VersionNumber.h" + +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +#include "ReaderConfiguration.h" +#endif + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(appupdate) + +AppUpdater::AppUpdater() + : mIgnoreNextVersionskip(false) + , mAppUpdateJsonUrl() + , mAppUpdateData() +{ + const SecureStorage& secureStorage = SecureStorage::getInstance(); + + mAppUpdateJsonUrl = VersionNumber::getApplicationVersion().isDeveloperVersion() ? secureStorage.getAppcastBetaUpdateUrl() : secureStorage.getAppcastUpdateUrl(); +} + + +void AppUpdater::checkAppUpdate(bool pIgnoreNextVersionskip) +{ + mIgnoreNextVersionskip = pIgnoreNextVersionskip; + mAppUpdateData = AppUpdateData(); + + Downloader* downloader = Env::getSingleton(); + connect(downloader, &Downloader::fireDownloadSuccess, this, &AppUpdater::onUpdateDownloadFinished); + connect(downloader, &Downloader::fireDownloadFailed, this, &AppUpdater::onUpdateDownloadFailed); + connect(downloader, &Downloader::fireDownloadUnnecessary, this, &AppUpdater::onUpdateDownloadUnnecessary); + + downloader->download(mAppUpdateJsonUrl); +} + + +const AppUpdateData& AppUpdater::getUpdateData() const +{ + return mAppUpdateData; +} + + +void AppUpdater::skipVersion(const QString& pVersion) +{ + qCInfo(appupdate) << "Skip application update:" << pVersion; + Env::getSingleton()->getGeneralSettings().skipVersion(pVersion); +} + + +void AppUpdater::onUpdateDownloadFinished(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData) +{ + Q_UNUSED(pNewTimestamp); + if (pUpdateUrl == mAppUpdateJsonUrl) + { + AppUpdateData newData = AppUpdateData::parse(pData); + if (newData.isValid()) + { + mAppUpdateData = newData; + const auto& version = mAppUpdateData.getVersion(); + + if (VersionNumber(version) > VersionNumber::getApplicationVersion()) + { + if (!mIgnoreNextVersionskip && version == Env::getSingleton()->getGeneralSettings().getSkipVersion()) + { + qCInfo(appupdate) << "Version will be skipped:" << version; + Q_EMIT fireAppUpdateCheckFinished(false, GlobalStatus::Code::No_Error); + } + else + { + mIgnoreNextVersionskip = false; + qCInfo(appupdate) << "Found new version:" << version << ", greater than old version" << QCoreApplication::applicationVersion(); + Env::getSingleton()->download(mAppUpdateData.getNotesUrl()); + return; + } + } + else + { + qCDebug(appupdate) << "No new version:" << version; + Q_EMIT fireAppUpdateCheckFinished(false, GlobalStatus::Code::No_Error); + } + } + else + { + Q_EMIT fireAppUpdateCheckFinished(false, newData.getParsingResult().getStatusCode()); + } + clearDownloaderConnection(); + } + if (pUpdateUrl == mAppUpdateData.getNotesUrl()) + { + qCDebug(appupdate) << "Release notes downloaded successfully"; + mAppUpdateData.setNotes(QString::fromUtf8(pData)); + Q_EMIT fireAppUpdateCheckFinished(true, GlobalStatus::Code::No_Error); + clearDownloaderConnection(); + } + +} + + +void AppUpdater::onUpdateDownloadFailed(const QUrl& pUpdateUrl, GlobalStatus::Code pErrorCode) +{ + if (pUpdateUrl == mAppUpdateJsonUrl) + { + qCDebug(appupdate) << "App Update JSON failed:" << GlobalStatus(pErrorCode).toErrorDescription(); + Q_EMIT fireAppUpdateCheckFinished(false, pErrorCode); + clearDownloaderConnection(); + return; + } + if (mAppUpdateData.isValid() && pUpdateUrl == mAppUpdateData.getNotesUrl()) + { + qCDebug(appupdate) << "Release Notes Download failed:" << GlobalStatus(pErrorCode).toErrorDescription(); + Q_EMIT fireAppUpdateCheckFinished(true, GlobalStatus::Code::No_Error); + clearDownloaderConnection(); + } +} + + +void AppUpdater::onUpdateDownloadUnnecessary(const QUrl& pUpdateUrl) +{ + if (pUpdateUrl == mAppUpdateJsonUrl || pUpdateUrl == mAppUpdateData.getNotesUrl()) + { + qCCritical(appupdate) << "Got a DownloadUnnecessary from Downloader, but App Updates always have to be fresh, this should not be happening"; + Q_EMIT fireAppUpdateCheckFinished(false, GlobalStatus::Code::Network_Other_Error); + clearDownloaderConnection(); + } +} + + +void AppUpdater::clearDownloaderConnection() +{ + Downloader* const downloader = Env::getSingleton(); + disconnect(downloader, &Downloader::fireDownloadSuccess, this, &AppUpdater::onUpdateDownloadFinished); + disconnect(downloader, &Downloader::fireDownloadFailed, this, &AppUpdater::onUpdateDownloadFailed); + disconnect(downloader, &Downloader::fireDownloadUnnecessary, this, &AppUpdater::onUpdateDownloadUnnecessary); +} diff --git a/src/services/AppUpdater.h b/src/services/AppUpdater.h new file mode 100644 index 0000000..1b5fc0c --- /dev/null +++ b/src/services/AppUpdater.h @@ -0,0 +1,45 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppUpdateData.h" +#include "GlobalStatus.h" + +#include +#include + +namespace governikus +{ +class AppUpdater + : public QObject +{ + Q_OBJECT + + private: + bool mIgnoreNextVersionskip; + QUrl mAppUpdateJsonUrl; + AppUpdateData mAppUpdateData; + + void clearDownloaderConnection(); + + public: + AppUpdater(); + virtual ~AppUpdater() = default; + static AppUpdater& getInstance(); + + void checkAppUpdate(bool pIgnoreNextVersionskip = false); + const AppUpdateData& getUpdateData() const; + void skipVersion(const QString& pVersion); + + private Q_SLOTS: + void onUpdateDownloadFinished(const QUrl& pUpdateUrl, const QDateTime& pNewTimestamp, const QByteArray& pData); + void onUpdateDownloadFailed(const QUrl& pUpdateUrl, GlobalStatus::Code pErrorCode); + void onUpdateDownloadUnnecessary(const QUrl& pUpdateUrl); + + Q_SIGNALS: + void fireAppUpdateCheckFinished(bool pUpdateAvailable, const GlobalStatus& pError); +}; + +} /* namespace governikus */ diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt index 2fbc981..1b4e456 100644 --- a/src/services/CMakeLists.txt +++ b/src/services/CMakeLists.txt @@ -1,3 +1,7 @@ ADD_PLATFORM_LIBRARY(AusweisAppServices) -TARGET_LINK_LIBRARIES(AusweisAppServices Qt5::Core AusweisAppCard AusweisAppNetwork AusweisAppSettings) +TARGET_LINK_LIBRARIES(AusweisAppServices Qt5::Core AusweisAppCard AusweisAppNetwork) + +IF(DESKTOP) + TARGET_LINK_LIBRARIES(AusweisAppServices AusweisAppConfiguration) +ENDIF() diff --git a/src/services/DownloadBackend.cpp b/src/services/DownloadBackend.cpp deleted file mode 100644 index cffd57e..0000000 --- a/src/services/DownloadBackend.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 80c822d..0000000 --- a/src/services/DownloadBackend.h +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * \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 deleted file mode 100644 index ab331fc..0000000 --- a/src/services/DownloadService.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 16b9a3b..0000000 --- a/src/services/DownloadService.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * \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 deleted file mode 100644 index a28dfdb..0000000 --- a/src/services/DriverParser.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*! - * DriverParser.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "DriverParser.h" -#include "SmartCardDefinitions.h" - -#include -#include -#include -#include -#include - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(card_drivers) - - -namespace -{ -const QStringList SUPPORTED_READERS( - { - getEnumName(ReaderType::REINER_cyberJack_RFID_komfort), - getEnumName(ReaderType::REINER_cyberJack_RFID_standard), - getEnumName(ReaderType::REINER_cyberJack_RFID_basis), - getEnumName(ReaderType::SCM_SDI011), - getEnumName(ReaderType::SCM_SCL011_Contactless_Reader) - }); - - -} - - -/** - * Parse a single entry of a driver list. - */ -class EntryParser -{ - private: - const QJsonValue& mJsonValue; - - const QMap mWinVersion; - - const QMap mMacVersion; - - QString getReaderType(const QJsonObject& pObject) const; - - QString getDriverUrl(const QJsonObject& pObject) const; - - bool matchPlatform(const QJsonArray& pPlatforms) const; - - QSharedPointer fail(const QString& logMessage) const; - - public: - EntryParser(const QJsonValue& pJsonValue); - - virtual ~EntryParser(); - - QSharedPointer parse() const; -}; - - -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} - } - - - ) - , mMacVersion({ - {"MV_10_9", QSysInfo::MV_10_9}, - {"MV_10_10", QSysInfo::MV_10_10}, - {"MV_10_11", QSysInfo::MV_10_11}, - {"MV_10_12", QSysInfo::MV_10_12} - } - ) -{ -} - - -EntryParser::~EntryParser() -{ -} - - -QString EntryParser::getReaderType(const QJsonObject& pObject) const -{ - const QString val = pObject.value(QStringLiteral("ReaderType")).toString(); - return SUPPORTED_READERS.contains(val) ? val : QString(); -} - - -QString EntryParser::getDriverUrl(const QJsonObject& pObject) const -{ - static const QString DRIVERS("Drivers"); - static const QString PLATFORMS("Platforms"); - static const QString URL("URL"); - - const QJsonValue driversValue = pObject.value(DRIVERS); - if (!driversValue.isArray()) - { - qCWarning(card_drivers) << "The value of 'Drivers' must be an array"; - - return QString(); - } - - const QJsonArray driversArray = driversValue.toArray(); - const int count = driversArray.count(); - for (int index = 0; index < count; index++) - { - const QJsonObject entry = driversArray.at(index).toObject(); - if (entry.isEmpty()) - { - qCWarning(card_drivers) << "Drivers entry must be a valid object"; - - return QString(); - } - - const QJsonValue platforms = entry.value(PLATFORMS); - if (!platforms.isArray()) - { - qCWarning(card_drivers) << "Invalid or missing Platforms tag"; - - return QString(); - } - - const QString url = entry.value(URL).toString(); - if (url.isEmpty()) - { - qCWarning(card_drivers) << "Invalid or missing URL tag"; - - return QString(); - } - - if (matchPlatform(platforms.toArray())) - { - return url; - } - } - - // No URL for this platform found, but entry is syntactically correct: - // return empty non-null string. - return QStringLiteral(""); -} - - -bool EntryParser::matchPlatform(const QJsonArray& pPlatforms) const -{ - const int count = pPlatforms.count(); - for (int index = 0; index < count; index++) - { - const QString platform = pPlatforms.at(index).toString(); - -#if defined(Q_OS_OSX) - if (QSysInfo::MacintoshVersion == mMacVersion.value(platform.trimmed(), QSysInfo::MV_None)) - { - return true; - } -#elif defined(Q_OS_WIN) - if (QSysInfo::WindowsVersion == mWinVersion.value(platform.trimmed(), QSysInfo::WV_None)) - { - return true; - } -#elif defined(Q_OS_LINUX) - if (platform == QLatin1String("LINUX")) - { - return true; - } -#else - Q_UNUSED(platform) -#endif - } - - return false; -} - - -QSharedPointer EntryParser::parse() const -{ - static const QString VENDOR_ID("VendorId"); - static const QString PRODUCT_ID("ProductId"); - static const QString NAME("Name"); - - if (!mJsonValue.isObject()) - { - return fail(QStringLiteral("Cannot parse Json value: object expected")); - } - - const QJsonObject object = mJsonValue.toObject(); - const QString readerType = getReaderType(object); - if (readerType.isEmpty()) - { - return fail(QStringLiteral("Invalid or missing reader type")); - } - - bool parseOk = false; - const uint vendorId = object.value(VENDOR_ID).toString().toUInt(&parseOk, 16); - if (!parseOk) - { - return fail(QStringLiteral("Invalid or missing vendor id")); - } - - const uint productId = object.value(PRODUCT_ID).toString().toUInt(&parseOk, 16); - if (!parseOk) - { - return fail(QStringLiteral("Invalid or missing product id")); - } - - const QString name = object.value(NAME).toString(); - if (name.isEmpty()) - { - return fail(QStringLiteral("Invalid or missing name")); - } - - const QString url = getDriverUrl(object); - if (url.isNull()) - { - return fail(QStringLiteral("Invalid driver URL entry")); - } - - return QSharedPointer(new Driver(readerType, vendorId, productId, name, url)); -} - - -QSharedPointer EntryParser::fail(const QString& pLogMessage) const -{ - qCWarning(card_drivers) << pLogMessage; - - return QSharedPointer(); -} - - -DriverParser::DriverParser() - : SettingsParser() -{ -} - - -DriverParser::~DriverParser() -{ -} - - -QSharedPointer DriverParser::parse(const QByteArray& pData) -{ - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(pData, &error); - if (error.error != QJsonParseError::NoError) - { - return fail(QString("Json parsing failed. Error at offset %1: %2").arg(error.offset).arg(error.errorString())); - } - - const QJsonObject rootObject = doc.object(); - if (rootObject.isEmpty()) - { - return fail(QStringLiteral("Expected object at top level")); - } - - if (!rootObject.contains(QStringLiteral("IssueDate"))) - { - return fail(QStringLiteral("Root object does not contain a property named 'IssueDate'")); - } - - const QJsonValue issueDateValue = rootObject.value(QStringLiteral("IssueDate")); - if (!issueDateValue.isString()) - { - return fail(QStringLiteral("The value of 'IssueDate' must be a string")); - } - - const QString issueDateString = issueDateValue.toString(); - const QDateTime issueDate = QDateTime::fromString(issueDateString, Qt::ISODate); - if (!issueDate.isValid()) - { - return fail(QStringLiteral("Error parsing issue date")); - } - - if (!rootObject.contains(QStringLiteral("SupportedDevices"))) - { - return fail(QStringLiteral("Root object does not contain a property named 'SupportedDevices'")); - } - - // Root object OK. Look at child list. - const QJsonValue devicesValue = rootObject.value(QStringLiteral("SupportedDevices")); - if (!devicesValue.isArray()) - { - return fail(QStringLiteral("The value of 'SupportedDevices' must be an array")); - } - - const QJsonArray devicesArray = devicesValue.toArray(); - const int count = devicesArray.count(); - QVector > drivers; - for (int index = 0; index < count; index++) - { - const QJsonValue entry = devicesArray.at(index); - auto driver = EntryParser(entry).parse(); - if (driver) - { - if (!driver->getUrl().isEmpty()) - { - drivers += driver; - } - } - else - { - return fail(QStringLiteral("Invalid driver entry: ") + entry.toString()); - } - } - - return QSharedPointer(new DriverSettings(issueDate, drivers)); -} - - -QSharedPointer DriverParser::fail(const QString& pLogMessage) -{ - qCWarning(card_drivers) << pLogMessage; - - return QSharedPointer(); -} diff --git a/src/services/DriverParser.h b/src/services/DriverParser.h deleted file mode 100644 index 807d1cc..0000000 --- a/src/services/DriverParser.h +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * DriverParser.h - * - * \brief Parser for driver configuration files - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - - -#include "DriverSettings.h" -#include "SettingsParser.h" - - -namespace governikus -{ -class DriverParser - : public SettingsParser -{ - private: - QSharedPointer fail(const QString& logMessage); - - public: - DriverParser(); - - virtual ~DriverParser(); - - /*! - * Parses the configuration data and returns DriverSettings. - * In case of any errors, the QSharedPointer is empty. - */ - virtual QSharedPointer parse(const QByteArray& pData) override; -}; - - -} /* namespace governikus */ diff --git a/src/services/DriverService.cpp b/src/services/DriverService.cpp deleted file mode 100644 index 53fd008..0000000 --- a/src/services/DriverService.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/*! - * \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" - -using namespace governikus; - -defineSingleton(DriverService) - -namespace -{ -class UpdateDriverSettingsBackend - : public UpdateSettingsBackend -{ - public: - UpdateDriverSettingsBackend(DriverSettings& pSettings) - : UpdateSettingsBackend(pSettings, - QSharedPointer >(new DriverParser()), - QStringLiteral("default-supported-devices.json"), - QStringLiteral("driver configuration")) - { - } - - - virtual ~UpdateDriverSettingsBackend() - { - } - - -}; - -} - - -DriverService::DriverService() - : UpdateService(QSharedPointer(new UpdateDriverSettingsBackend(AppSettings::getInstance().getDriverSettings())), - QStringLiteral("driver configuration")) -{ -} - - -DriverService::~DriverService() -{ -} - - -DriverService& DriverService::getInstance() -{ - return *Instance; -} diff --git a/src/services/DriverService.h b/src/services/DriverService.h deleted file mode 100644 index ff7a265..0000000 --- a/src/services/DriverService.h +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * \brief Service providing an update mechanism for the reader driver settings - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "UpdateService.h" - -namespace governikus -{ -class DriverService - : public UpdateService -{ - Q_OBJECT - - protected: - DriverService(); - virtual ~DriverService(); - - public: - static DriverService& getInstance(); -}; - -} /* namespace governikus */ diff --git a/src/services/IconCache.cpp b/src/services/IconCache.cpp deleted file mode 100644 index 45c9fe2..0000000 --- a/src/services/IconCache.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "IconCache.h" - -#include "AppSettings.h" -#include "IconUpdateBackend.h" - -#include -#include -#include - - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(update) - - -static const QLatin1String QRC_PREFIX("qrc:///"); - - -QString IconCache::getIconPathInCache(const QString& pIcon) const -{ - return mIconCacheFolderPath + pIcon; -} - - -QStringList IconCache::getIconsToDownload(const QStringList& pRequiredIcons) const -{ - QStringList result; - for (const auto& icon : pRequiredIcons) - { - if (icon.startsWith(QRC_PREFIX)) - { - continue; - } - - // Only download files that are not in the cache already. - QFile file(getIconPathInCache(icon)); - if (!file.exists()) - { - result += icon; - } - } - - qCDebug(update) << "Icons to download:" << result; - - return result; -} - - -QUrl IconCache::getRemoteIconUrl(const QString& pIcon) const -{ - return QUrl(mIconUpdateUrlBase + pIcon); -} - - -void IconCache::processNextIcon() -{ - // Nothing to do, possibly after last icon has been downloaded. - if (mPendingIcons.isEmpty()) - { - const QMap iconMap = makeIconMap(mRequiredIcons); - - mRequiredIcons.clear(); - mIconService.clear(); - - Q_EMIT fireIconMapChanged(iconMap); - } - else - { - const QString& icon = mPendingIcons.constFirst(); - - mIconService.reset(new IconService(mIconCacheFolderPath, icon)); - - mIconService->setUpdateUrl(getRemoteIconUrl(icon)); - mIconService->setTrustedUpdateCertificates(mUpdateCertificates); - - connect(mIconService.data(), &IconService::fireProcessingFinished, this, &IconCache::onProcessingFinished); - - mIconService->runUpdate(); - } -} - - -bool IconCache::canBeMapped(const QString& pIcon) const -{ - const QString pathToCheck = pIcon.startsWith(QRC_PREFIX) ? pIcon : getIconPathInCache(pIcon); - QFile file(pathToCheck); - - return file.exists(); -} - - -QMap IconCache::makeIconMap(const QStringList& pIcons) const -{ - QMap result; - - for (const auto& icon : pIcons) - { - // If the icon is a normal file, check that it is in the cache. - if (canBeMapped(icon)) - { - result.insert(icon, getLocalIconUrl(icon)); - } - } - - return result; -} - - -void IconCache::onProcessingFinished(const QString& pIcon) -{ - qCDebug(update) << "Finished processing icon" << pIcon; - - if (mPendingIcons.size() > 0) - { - if (mPendingIcons.first() == pIcon) - { - mPendingIcons.removeFirst(); - processNextIcon(); - } - else - { - // Should never happen: mPendingIcons.first() != pIcon would indicate some bug. - qCWarning(update) << "Failed to process an icon, aborting update."; - - mRequiredIcons.clear(); - mPendingIcons.clear(); - } - } -} - - -IconCache::IconCache() - : mIconCacheFolderPath() - , mIconUpdateUrlBase() - , mIconService() -{ -} - - -IconCache::~IconCache() -{ -} - - -void IconCache::setTrustedUpdateCertificates(const QVector& pUpdateCertificates) -{ - mUpdateCertificates = pUpdateCertificates; -} - - -void IconCache::setIconUpdateUrlBase(const QString& pIconUpdateUrlBase) -{ - mIconUpdateUrlBase = pIconUpdateUrlBase; -} - - -QString IconCache::getLocalIconUrl(const QString& pIcon) const -{ - return pIcon.startsWith(QRC_PREFIX) ? pIcon : QUrl::fromLocalFile(getIconPathInCache(pIcon)).toString(); -} - - -bool IconCache::init() -{ - const QStringList cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation); - if (cachePaths.isEmpty()) - { - qCWarning(update) << "No cache paths found!"; - - return false; - } - else - { - const QString cacheBasePath = cachePaths.first(); - if (cacheBasePath.isEmpty()) - { - qCWarning(update) << "Cache base folder is invalid (empty)."; - - return false; - } - - mIconCacheFolderPath = cacheBasePath + QStringLiteral("/icons/"); - const QDir cacheFolder(mIconCacheFolderPath); - - qCDebug(update) << "Initializing cache folder:" << mIconCacheFolderPath; - - return cacheFolder.exists() || cacheFolder.mkpath(mIconCacheFolderPath); - } -} - - -void IconCache::onRequiredIcons(const QStringList& pIcons) -{ - // Only run if not running already. - if (mPendingIcons.isEmpty()) - { - mRequiredIcons = pIcons; - mPendingIcons = getIconsToDownload(mRequiredIcons); - - processNextIcon(); - } -} diff --git a/src/services/IconCache.h b/src/services/IconCache.h deleted file mode 100644 index 9cd73cd..0000000 --- a/src/services/IconCache.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * \brief Class that ensures that all the icons and images specified - * in the application settings are in the application cache. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "IconService.h" -#include "ProviderSettings.h" - -#include -#include -#include -#include - - -namespace governikus -{ -class IconCache - : public QObject -{ - Q_OBJECT - - private: - QVector mUpdateCertificates; - - QString mIconCacheFolderPath; - - QString mIconUpdateUrlBase; - - QStringList mRequiredIcons; - - QStringList mPendingIcons; - - QSharedPointer mIconService; - - QString getIconPathInCache(const QString& pIcon) const; - - QStringList getIconsToDownload(const QStringList& pRequiredIcons) const; - - QUrl getRemoteIconUrl(const QString& pIcon) const; - - void processNextIcon(); - - /* - * An icon can be mapped if the corresponding file or resource exists. - */ - bool canBeMapped(const QString& pIcon) const; - - QMap makeIconMap(const QStringList& pIcons) const; - - private Q_SLOTS: - void onProcessingFinished(const QString& pIcon); - - public: - IconCache(); - - ~IconCache(); - - void setTrustedUpdateCertificates(const QVector& pUpdateCertificates); - - void setIconUpdateUrlBase(const QString& pIconUpdateUrlBase); - - QString getLocalIconUrl(const QString& pIcon) const; - - bool init(); - - public Q_SLOTS: - void onRequiredIcons(const QStringList& pIcons); - - Q_SIGNALS: - void fireIconMapChanged(const QMap& mIconMap); - -}; - - -} /* namespace governikus */ diff --git a/src/services/IconService.cpp b/src/services/IconService.cpp deleted file mode 100644 index 24098ad..0000000 --- a/src/services/IconService.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "IconService.h" - -#include "IconUpdateBackend.h" - - -using namespace governikus; - - -IconService::IconService(const QString& pIconCacheBasePath, const QString& pIcon) - : UpdateService(QSharedPointer(new IconUpdateBackend(pIconCacheBasePath, pIcon)), - QStringLiteral("icon")) - , mIcon(pIcon) -{ - connect(this, &UpdateService::fireUpdateFinished, this, &IconService::onUpdateFinished); -} - - -IconService::~IconService() -{ -} - - -void IconService::onUpdateFinished() -{ - Q_EMIT fireProcessingFinished(mIcon); -} diff --git a/src/services/IconService.h b/src/services/IconService.h deleted file mode 100644 index 6cbb308..0000000 --- a/src/services/IconService.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * \brief Class that updates an icon and stores it in the local - * application cache. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "ProviderSettings.h" -#include "UpdateService.h" - -#include - - -namespace governikus -{ -class IconService - : public UpdateService -{ - Q_OBJECT - - private: - const QString mIcon; - - public: - IconService(const QString& pIconCacheBasePath, const QString& pIcon); - - virtual ~IconService(); - - private Q_SLOTS: - void onUpdateFinished(); - - Q_SIGNALS: - void fireProcessingFinished(const QString& pIcon); - - -}; - - -} /* namespace governikus */ diff --git a/src/services/IconUpdateBackend.cpp b/src/services/IconUpdateBackend.cpp deleted file mode 100644 index 7f19449..0000000 --- a/src/services/IconUpdateBackend.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "IconUpdateBackend.h" - -#include -#include -#include - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(update) - - -IconUpdateBackend::IconUpdateBackend(const QString& pIconCacheBasePath, const QString& pIcon) - : mIcon(pIcon) - , mIconPathInCache(pIconCacheBasePath + pIcon) -{ -} - - -IconUpdateBackend::~IconUpdateBackend() -{ -} - - -QDateTime IconUpdateBackend::getIssueDate() const -{ - QFileInfo info(mIconPathInCache); - - return info.isFile() ? info.lastModified() : QDateTime(); -} - - -void IconUpdateBackend::processSuccess(const QByteArray& pData) -{ - QFile file(mIconPathInCache); - if (!file.open(QFile::OpenModeFlag::WriteOnly)) - { - qCCritical(update) << "Cannot open file" << mIconPathInCache; - } - else if (file.write(pData) != pData.size()) - { - qCCritical(update) << "Cannot write file" << mIconPathInCache; - } - - file.close(); -} - - -void IconUpdateBackend::processError(const GlobalStatus& pError) -{ - Q_UNUSED(pError) -} diff --git a/src/services/IconUpdateBackend.h b/src/services/IconUpdateBackend.h deleted file mode 100644 index 726cfd2..0000000 --- a/src/services/IconUpdateBackend.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * \brief Class that ensures that all the icons and images specified - * in the application settings are in the application cache. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "UpdateBackend.h" - -#include - -namespace governikus -{ -class IconUpdateBackend - : public UpdateBackend -{ - private: - const QString mIcon; - - const QString mIconPathInCache; - - public: - IconUpdateBackend(const QString& pIconCacheBasePath, const QString& pIcon); - - virtual ~IconUpdateBackend(); - - 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/ProviderParser.cpp b/src/services/ProviderParser.cpp deleted file mode 100644 index da06584..0000000 --- a/src/services/ProviderParser.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "LanguageString.h" -#include "ProviderParser.h" - -#include -#include - -#include - - -Q_DECLARE_LOGGING_CATEGORY(update) - - -using namespace governikus; - -namespace -{ - -inline QLatin1String getCurrentOS() -{ -#if defined(Q_OS_WIN) - return QLatin1String("win"); - -#elif defined(Q_OS_MACOS) - return QLatin1String("mac"); - -#elif defined(Q_OS_IOS) - return QLatin1String("ios"); - -#elif defined(Q_OS_ANDROID) - return QLatin1String("android"); - -#elif defined(Q_OS_LINUX) - return QLatin1String("linux"); - -#elif defined(Q_OS_BSD4) - return QLatin1String("bsd"); - -#else -#error OS not implemented -#endif -} - - -} - -ProviderParser::ProviderParser() - : SettingsParser() -{ -} - - -ProviderParser::~ProviderParser() -{ -} - - -QSharedPointer ProviderParser::parse(const QByteArray& pData) -{ - return parse(pData, getCurrentOS()); -} - - -QSharedPointer ProviderParser::parse(const QByteArray& pData, QLatin1String pCurrentOS) -{ - QJsonParseError jsonError; - 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(); - - 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); - - const QJsonArray& array = doc["provider"].toArray(); - QVector providers; - providers.reserve(array.size()); - for (const auto& entry : array) - { - const QJsonObject prov = entry.toObject(); - - if (isExcludedPlatform(prov["exclude"].toArray(), pCurrentOS)) - { - continue; - } - - const QString postalAddressCamel = prov["postalAddress"].toString(); - const QString postalAddressLower = prov["postaladdress"].toString(); - providers << Provider( - LanguageString(prov["shortName"]), - LanguageString(prov["longName"]), - LanguageString(prov["shortDescription"]), - LanguageString(prov["longDescription"]), - prov["address"].toString(), - prov["homepage"].toString(), - prov["category"].toString(), - prov["phone"].toString(), - prov["email"].toString(), - postalAddressCamel.isEmpty() ? postalAddressLower : postalAddressCamel, // Accept old format - prov["icon"].toString(), - prov["image"].toString(), - prov["tcTokenUrl"].toString(), - prov["clientUrl"].toString(), - prov["subjectUrls"].toVariant().toStringList()); - } - providerSettings->setProviders(providers); - - return providerSettings; -} - - -bool ProviderParser::isExcludedPlatform(const QJsonArray& pExcludedArray, QLatin1String pCurrentOS) -{ - const QLatin1String osType = pCurrentOS == QLatin1String("ios") || pCurrentOS == QLatin1String("android") - ? QLatin1String("mobile") - : QLatin1String("desktop"); - - for (const auto& entry : pExcludedArray) - { - const QString& value = entry.toString().toLower(); - if (value == pCurrentOS || value == osType) - { - return true; - } - } - return false; -} diff --git a/src/services/ProviderParser.h b/src/services/ProviderParser.h deleted file mode 100644 index 4860440..0000000 --- a/src/services/ProviderParser.h +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * \brief Parser for provider configuration files - * - * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany - */ - -#pragma once - -#include "ProviderSettings.h" -#include "SettingsParser.h" - -#include -#include - -class test_ProviderParser; - -namespace governikus -{ -class ProviderParser - : public SettingsParser -{ - private: - friend class ::test_ProviderParser; - static bool isExcludedPlatform(const QJsonArray& pExcludedArray, QLatin1String pCurrentOS); - QSharedPointer parse(const QByteArray& pData, QLatin1String pCurrentOS); - - public: - ProviderParser(); - virtual ~ProviderParser(); - - /*! - * Parses the configuration data and returns ProviderSettings. - * In case of any errors, the QSharedPointer is empty. - */ - virtual QSharedPointer parse(const QByteArray& pData) override; -}; - - -} /* namespace governikus */ diff --git a/src/services/ProviderService.cpp b/src/services/ProviderService.cpp deleted file mode 100644 index 429406a..0000000 --- a/src/services/ProviderService.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProviderService.h" - -#include "AppSettings.h" -#include "ProviderParser.h" -#include "ProviderSettings.h" -#include "SingletonHelper.h" -#include "UpdateSettingsBackend.h" - -using namespace governikus; - -defineSingleton(ProviderService) - -namespace -{ -class UpdateProviderSettingsBackend - : public UpdateSettingsBackend -{ - public: - UpdateProviderSettingsBackend(ProviderSettings& pSettings) - : UpdateSettingsBackend(pSettings, - QSharedPointer >(new ProviderParser()), - QStringLiteral("default-providers.json"), - QStringLiteral("provider configuration")) - { - } - - - virtual ~UpdateProviderSettingsBackend() - { - } - - -}; - -} - -ProviderService::ProviderService() - : UpdateService(QSharedPointer(new UpdateProviderSettingsBackend(AppSettings::getInstance().getProviderSettings())), - QStringLiteral("provider configuration")) -{ -} - - -ProviderService::~ProviderService() -{ -} - - -ProviderService& ProviderService::getInstance() -{ - return *Instance; -} diff --git a/src/services/ProviderService.h b/src/services/ProviderService.h deleted file mode 100644 index 7e4c36c..0000000 --- a/src/services/ProviderService.h +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * \brief Service providing an update mechanism for the provider settings - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "UpdateService.h" - -namespace governikus -{ -class ProviderService - : public UpdateService -{ - Q_OBJECT - - protected: - ProviderService(); - virtual ~ProviderService(); - - public: - static ProviderService& getInstance(); -}; - -} /* namespace governikus */ diff --git a/src/services/Service.cpp b/src/services/Service.cpp new file mode 100644 index 0000000..bf11190 --- /dev/null +++ b/src/services/Service.cpp @@ -0,0 +1,112 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Service.h" + +#include "AppSettings.h" +#include "AppUpdateData.h" +#include "Env.h" +#include "ProviderConfiguration.h" +#include "SingletonHelper.h" + +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +#include "ReaderConfiguration.h" +#endif + +#include + +using namespace governikus; + +defineSingleton(Service) + +Service::Service() + : mTimer(this) + , mUpdateScheduled(true) + , mExplicitSuccessMessage(true) + , mAppUpdater() +{ + connect(&mTimer, &QTimer::timeout, this, &Service::onTimedUpdateTriggered); + connect(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished, this, &Service::onAppUpdateFinished); + + mTimer.setSingleShot(true); + mTimer.start(mOneDayInMs); +} + + +Service& Service::getInstance() +{ + return *Instance; +} + + +void Service::updateConfigurations() +{ + QMetaObject::invokeMethod(this, "doConfigurationsUpdate", Qt::QueuedConnection); +} + + +void Service::updateApp(bool pIgnoreNextVersionskip) +{ + mUpdateScheduled = false; + mExplicitSuccessMessage = pIgnoreNextVersionskip; + mTimer.start(mOneDayInMs); + QMetaObject::invokeMethod(this, "doAppUpdate", Qt::QueuedConnection, Q_ARG(bool, pIgnoreNextVersionskip)); +} + + +void Service::doConfigurationsUpdate() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) + Env::getSingleton()->update(); +#endif + + Env::getSingleton()->update(); +} + + +void Service::doAppUpdate(bool pIgnoreNextVersionskip) +{ + mAppUpdater.checkAppUpdate(pIgnoreNextVersionskip); +} + + +void Service::onTimedUpdateTriggered() +{ + mUpdateScheduled = true; + Q_EMIT fireUpdateScheduled(); +} + + +bool Service::isUpdateScheduled() +{ + return mUpdateScheduled; +} + + +void Service::runUpdateIfNeeded() +{ + if (mUpdateScheduled) + { + updateConfigurations(); + if (Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + { + updateApp(); + } + } +} + + +const AppUpdateData& Service::getUpdateData() const +{ + return mAppUpdater.getUpdateData(); +} + + +void Service::onAppUpdateFinished(bool pUpdateAvailable, const GlobalStatus& pError) +{ + if (pUpdateAvailable || pError.isError() || mExplicitSuccessMessage) + { + Q_EMIT fireAppUpdateFinished(pUpdateAvailable, pError); + } +} diff --git a/src/services/Service.h b/src/services/Service.h new file mode 100644 index 0000000..9e118c3 --- /dev/null +++ b/src/services/Service.h @@ -0,0 +1,48 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppUpdater.h" + +#include + +namespace governikus +{ +class Service + : public QObject +{ + Q_OBJECT + + private: + QTimer mTimer; + bool mUpdateScheduled; + bool mExplicitSuccessMessage; + AppUpdater mAppUpdater; + const int mOneDayInMs = 1000 * 60 * 60 * 24; + + protected: + Service(); + ~Service() = default; + + private Q_SLOTS: + void doConfigurationsUpdate(); + void doAppUpdate(bool pIgnoreNextVersionskip); + void onTimedUpdateTriggered(); + void onAppUpdateFinished(bool pUpdateAvailable, const GlobalStatus& pError); + + public: + static Service& getInstance(); + void updateConfigurations(); + void updateApp(bool pIgnoreNextVersionskip = false); + bool isUpdateScheduled(); + void runUpdateIfNeeded(); + const AppUpdateData& getUpdateData() const; + + Q_SIGNALS: + void fireAppUpdateFinished(bool pUpdateAvailable, const GlobalStatus& pError); + void fireUpdateScheduled(); +}; + +} /* namespace governikus */ diff --git a/src/services/SettingsParser.h b/src/services/SettingsParser.h deleted file mode 100644 index 89eedfd..0000000 --- a/src/services/SettingsParser.h +++ /dev/null @@ -1,41 +0,0 @@ -/*! - * SettingsParser.h - * - * \brief Abstract definition of a parser that returns value of some class R. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - - -#include -#include - -namespace governikus -{ -template -class SettingsParser -{ - protected: - SettingsParser() - { - } - - - public: - virtual ~SettingsParser() - { - } - - - /*! - * Parses the data and returns a value wrapped in a QSharedPointer. - * - * In case of any errors, the QSharedPointer is empty. - */ - virtual QSharedPointer parse(const QByteArray& pData) = 0; -}; - - -} /* namespace governikus */ diff --git a/src/services/UpdateBackend.cpp b/src/services/UpdateBackend.cpp deleted file mode 100644 index b1d34a9..0000000 --- a/src/services/UpdateBackend.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * UpdateBackend.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - - -#include "UpdateBackend.h" - - -using namespace governikus; - - -UpdateBackend::UpdateBackend() -{ -} - - -UpdateBackend::~UpdateBackend() -{ -} diff --git a/src/services/UpdateBackend.h b/src/services/UpdateBackend.h deleted file mode 100644 index 88ef01c..0000000 --- a/src/services/UpdateBackend.h +++ /dev/null @@ -1,35 +0,0 @@ -/*! - * UpdateBackend.h - * - * \brief Interface for classes that perform some processing with - * data that has been downloaded during an update. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - - -#pragma once - -#include "GlobalStatus.h" - -#include -#include - - -namespace governikus -{ -class UpdateBackend -{ - public: - UpdateBackend(); - - virtual ~UpdateBackend(); - - virtual QDateTime getIssueDate() const = 0; - - virtual void processSuccess(const QByteArray& pData) = 0; - - virtual void processError(const GlobalStatus& pError) = 0; -}; - -} diff --git a/src/services/UpdateService.cpp b/src/services/UpdateService.cpp deleted file mode 100644 index a14473d..0000000 --- a/src/services/UpdateService.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/*! - * UpdateService.cpp - * - * \brief Generic implementation of a service providing an update mechanism for settings, - * images, and so on. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "UpdateService.h" - -#include "HttpStatusCode.h" -#include "NetworkManager.h" -#include "TlsConfiguration.h" - -#include - - -using namespace governikus; - -Q_DECLARE_LOGGING_CATEGORY(update) - - -void UpdateService::onSslErrors(const QList& pErrors) -{ - TlsConfiguration::containsFatalError(mReply, pErrors); -} - - -void UpdateService::onSslHandshakeDone() -{ - 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; - - if (!mTrustedUpdateCertificates.contains(cert)) - { - qCritical(update).nospace() << "Untrusted certificate found [" << mNameForLog << "]: " << cert; - mReply->abort(); - } -} - - -void UpdateService::onMetadataChanged() -{ - qCDebug(update) << "Meta data changed for" << mNameForLog; - - QVariant status = mReply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute); - if (!status.isNull()) - { - qCDebug(update) << "Found header status" << status.toString(); - if (status.toInt() != HttpStatusCode::OK) - { - qCCritical(update) << "Abort request, status " << status.toInt(); - mReply->abort(); - - return; - } - } - QVariant lastModified = mReply->header(QNetworkRequest::KnownHeaders::LastModifiedHeader); - if (!lastModified.isNull()) - { - qCDebug(update) << "Found header Last-Modified" << lastModified.toString(); - const QDateTime localIssueDate = mUpdateBackend->getIssueDate(); - 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; - } - } -} - - -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(NetworkManager::toStatus(mReply)); - Q_EMIT fireUpdateFinished(); - return; - } - - mUpdateBackend->processSuccess(mReply->readAll()); - Q_EMIT fireUpdateFinished(); -} - - -UpdateService::UpdateService(const QSharedPointer& pUpdateBackend, - const QString& pNameForLog) - : mUpdateBackend(pUpdateBackend) - , mNameForLog(pNameForLog) - , mUpdateUrl() - , mTrustedUpdateCertificates() - , mReply() - , mCancel(false) -{ - Q_ASSERT_X(pUpdateBackend, "UpdateService", "invalid update backend"); -} - - -UpdateService::~UpdateService() -{ - if (mReply != nullptr) - { - if (mReply->isRunning()) - { - qCDebug(update).nospace() << "Scheduling pending update request [" << mNameForLog << "] for deletion"; - } - mReply->deleteLater(); - } -} - - -void UpdateService::setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates) -{ - mTrustedUpdateCertificates = pTrustedUpdateCertificates; -} - - -void UpdateService::setUpdateUrl(const QUrl& pUpdateUrl) -{ - mUpdateUrl = pUpdateUrl; -} - - -void UpdateService::runUpdate() -{ - 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); - connect(mReply.data(), &QNetworkReply::encrypted, this, &UpdateService::onSslHandshakeDone); - connect(mReply.data(), &QNetworkReply::metaDataChanged, this, &UpdateService::onMetadataChanged); - connect(mReply.data(), &QNetworkReply::finished, this, &UpdateService::onNetworkReplyFinished); -} diff --git a/src/services/UpdateService.h b/src/services/UpdateService.h deleted file mode 100644 index 827da5b..0000000 --- a/src/services/UpdateService.h +++ /dev/null @@ -1,82 +0,0 @@ -/*! - * UpdateService.h - * - * \brief Generic implementation of a service providing an update mechanism for settings, - * application icons, and so on. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - - -#pragma once - - -#include "UpdateBackend.h" - -#include -#include -#include -#include -#include -#include - - -namespace governikus -{ -class UpdateService - : public QObject -{ - Q_OBJECT - - private: - const QSharedPointer mUpdateBackend; - - const QString mNameForLog; - - QUrl mUpdateUrl; - - QVector mTrustedUpdateCertificates; - - QPointer mReply; - bool mCancel; - - private Q_SLOTS: - void onSslErrors(const QList& pErrors); - - void onSslHandshakeDone(); - - void onMetadataChanged(); - - void onNetworkReplyFinished(); - - protected: - template - QSharedPointer getUpdateBackend() - { - return mUpdateBackend.staticCast(); - } - - - template - QSharedPointer getUpdateBackend() const - { - return mUpdateBackend.staticCast(); - } - - - public: - UpdateService(const QSharedPointer& pUpdateBackend, - const QString& pNameForLog); - - virtual ~UpdateService(); - - void setUpdateUrl(const QUrl& pUpdateUrl); - virtual void setTrustedUpdateCertificates(const QVector& pTrustedUpdateCertificates); - void runUpdate(); - - Q_SIGNALS: - void fireUpdateFinished(); - -}; - -} /* namespace governikus */ diff --git a/src/services/UpdateSettingsBackend.h b/src/services/UpdateSettingsBackend.h deleted file mode 100644 index 94e42f6..0000000 --- a/src/services/UpdateSettingsBackend.h +++ /dev/null @@ -1,145 +0,0 @@ -/*! - * UpdateSettingsBackend.h - * - * \brief Template class that parses and updates settings. - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - - -#include "FileDestination.h" - -#include -#include -#include - - -Q_DECLARE_LOGGING_CATEGORY(update) - -namespace governikus -{ - -template -class UpdateSettingsBackend - : public UpdateBackend -{ - private: - SettingsClass& mCurrentSettings; - - const QSharedPointer > mParser; - - const QString mDefaultSettingsFilename; - - const QString mNameForLog; - - QSharedPointer loadDefaultSettings() - { - QFile file(FileDestination::getPath(mDefaultSettingsFilename)); - if (!file.exists()) - { - qCCritical(update) << "Cannot find file" << mDefaultSettingsFilename; - - return QSharedPointer(); - } - - if (!file.open(QFile::OpenModeFlag::ReadOnly | QFile::OpenModeFlag::Unbuffered)) - { - qCCritical(update) << "Cannot open file" << mDefaultSettingsFilename; - - return QSharedPointer(); - } - - const QByteArray data = file.readAll(); - file.close(); - QSharedPointer defaultSettings = mParser->parse(data); - if (defaultSettings.isNull()) - { - qCCritical(update) << QStringLiteral("Parsing of default %1 failed").arg(mNameForLog); - - return QSharedPointer(); - } - - qCDebug(update) << QStringLiteral("Loaded default %1 issued on %2").arg(mNameForLog, defaultSettings->getIssueDate().toString(Qt::DateFormat::ISODate)); - - return defaultSettings; - } - - - void saveLatestSettings(QSharedPointer pUpdatedSettings) - { - 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); - mCurrentSettings.save(); - } - else - { - qCDebug(update) << QStringLiteral("No need for replacement, current %1 is up to date").arg(mNameForLog); - } - } - - - public: - UpdateSettingsBackend(SettingsClass& pCurrentSettings, - const QSharedPointer > pParser, - const QString& pDefaultSettingsFilename, - const QString& pNameForLog) - : UpdateBackend() - , mCurrentSettings(pCurrentSettings) - , mParser(pParser) - , mDefaultSettingsFilename(pDefaultSettingsFilename) - , mNameForLog(pNameForLog) - { - // (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(); - } - } - - - virtual ~UpdateSettingsBackend() - { - } - - - virtual QDateTime getIssueDate() const override - { - return mCurrentSettings.getIssueDate(); - } - - - virtual void processSuccess(const QByteArray& pData) override - { - QSharedPointer updatedSettings = mParser->parse(pData); - if (updatedSettings.isNull()) - { - qCCritical(update) << QStringLiteral("Parsing of %1 from update site failed").arg(mNameForLog); - saveLatestSettings(QSharedPointer()); - } - else - { - qCDebug(update) << QStringLiteral("Downloaded %1 from update site issued on %2").arg(mNameForLog, updatedSettings->getIssueDate().toString(Qt::DateFormat::ISODate)); - saveLatestSettings(updatedSettings); - } - } - - - virtual void processError(const GlobalStatus& pError) override - { - Q_UNUSED(pError) - saveLatestSettings(QSharedPointer()); - } - - -}; - -} diff --git a/src/services/Updater.cpp b/src/services/Updater.cpp deleted file mode 100644 index 5cd1406..0000000 --- a/src/services/Updater.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#include "Updater.h" - -#include "AppSettings.h" -#include "AppUpdateService.h" -#include "DriverService.h" -#include "ProviderService.h" -#include "SecureStorage.h" -#include "SingletonHelper.h" -#include "VersionNumber.h" - -#include - -using namespace governikus; - -defineSingleton(Updater) - - -Updater::Updater() - : mIconCache() -{ - SecureStorage& secureStorage = AppSettings::getInstance().getSecureStorage(); - secureStorage.load(); - - auto url = VersionNumber::getApplicationVersion().isDeveloperVersion() ? secureStorage.getAppcastBetaUpdateUrl() : secureStorage.getAppcastUpdateUrl(); - 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::getInstance().setUpdateUrl(secureStorage.getDriverUpdateUrl()); - // DriverService::getInstance().setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); -#endif - - qDebug() << "Provider update url =" << secureStorage.getProviderUpdateUrl(); - ProviderService::getInstance().setUpdateUrl(secureStorage.getProviderUpdateUrl()); - ProviderService::getInstance().setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); - connect(&ProviderService::getInstance(), &UpdateService::fireUpdateFinished, this, &Updater::onUpdateProviderSettingsFinished); - - mIconCache.init(); - mIconCache.setTrustedUpdateCertificates(secureStorage.getUpdateCertificates()); - qDebug() << "Icon update url base =" << secureStorage.getProviderIconUpdateUrlBase(); - mIconCache.setIconUpdateUrlBase(secureStorage.getProviderIconUpdateUrlBase()); - - qDebug() << "Connecting icon cache with provider settings"; - connect(&AppSettings::getInstance().getProviderSettings(), &ProviderSettings::fireRequiredIcons, &mIconCache, &IconCache::onRequiredIcons); - connect(&mIconCache, &IconCache::fireIconMapChanged, &AppSettings::getInstance().getProviderSettings(), &ProviderSettings::onIconMapChanged); -} - - -Updater& Updater::getInstance() -{ - return *Instance; -} - - -void Updater::update() -{ - QMetaObject::invokeMethod(this, "doUpdateRemoteSettings", Qt::QueuedConnection); -} - - -void Updater::checkAppUpdate() -{ - AppUpdateService::getInstance().runUpdate(); -} - - -const IconCache& Updater::getIconCache() const -{ - return mIconCache; -} - - -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::getInstance().runUpdate(); -#endif - - ProviderService::getInstance().runUpdate(); -} - - -void Updater::onUpdateProviderSettingsFinished() -{ - // Connection between cache and settings is set up: request icon map to initialize settings. - AppSettings::getInstance().getProviderSettings().requestIconMap(); -} diff --git a/src/services/Updater.h b/src/services/Updater.h deleted file mode 100644 index a4c3941..0000000 --- a/src/services/Updater.h +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AppUpdateData.h" -#include "IconCache.h" - -namespace governikus -{ -class Updater - : public QObject -{ - Q_OBJECT - - private: - IconCache mIconCache; - - protected: - Updater(); - - public: - static Updater& getInstance(); - - void update(); - 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/AbstractSettings.cpp b/src/settings/AbstractSettings.cpp index d35fa2b..8f5e234 100644 --- a/src/settings/AbstractSettings.cpp +++ b/src/settings/AbstractSettings.cpp @@ -1,11 +1,17 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AbstractSettings.h" #include +#ifdef Q_OS_MACOS + #include +#endif +#ifdef Q_OS_ANDROID + #include +#endif using namespace governikus; @@ -13,6 +19,38 @@ using namespace governikus; QSharedPointer AbstractSettings::mTestDir; #endif +void AbstractSettings::createLegacyFileMapping() +{ +#ifdef Q_OS_MACOS + static bool checked = false; + if (checked) + { + return; + } + + QFileInfo oldInfo(QSettings(QCoreApplication::organizationName(), QCoreApplication::applicationName()).fileName()); + oldInfo.setCaching(false); + QFileInfo newInfo(QSettings().fileName()); + newInfo.setCaching(false); + + if (!oldInfo.isSymLink()) + { + if (oldInfo.exists() && !newInfo.exists()) + { + QFile(oldInfo.filePath()).rename(newInfo.filePath()); + } + + if (!oldInfo.exists()) + { + QFile(newInfo.filePath()).link(oldInfo.filePath()); + } + } + + checked = true; +#endif +} + + AbstractSettings::AbstractSettings() { } @@ -25,6 +63,7 @@ AbstractSettings::~AbstractSettings() QSharedPointer AbstractSettings::getStore() { + createLegacyFileMapping(); #ifndef QT_NO_DEBUG if (QCoreApplication::applicationName().startsWith(QLatin1String("Test"))) { @@ -37,24 +76,17 @@ QSharedPointer AbstractSettings::getStore() return QSharedPointer(new QSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName())); } #endif - return QSharedPointer(new QSettings(QCoreApplication::organizationName(), QCoreApplication::applicationName())); + return QSharedPointer(new QSettings()); } -void AbstractSettings::update(const AbstractSettings&) +bool AbstractSettings::appIsBackgroundService() const { - Q_ASSERT_X(false, "update", "method should be overridden by subclass"); -} - - -QVariant AbstractSettings::getSettingsValue(const QSharedPointer& pSettings, const QString& key) -{ - if (pSettings) +#ifdef Q_OS_ANDROID + if (QtAndroid::androidService().isValid()) { - return pSettings->contains(key) ? pSettings->value(key) : pSettings->value(key.toLower()); - } - else - { - return QVariant(); + return true; } +#endif + return false; } diff --git a/src/settings/AbstractSettings.h b/src/settings/AbstractSettings.h index fdff6f1..fcd45e7 100644 --- a/src/settings/AbstractSettings.h +++ b/src/settings/AbstractSettings.h @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -13,6 +13,11 @@ #include #endif +#define SETTINGS_NAME(_name, _key)\ + QString _name(){\ + return QStringLiteral(_key);\ + } + namespace governikus { @@ -21,12 +26,13 @@ class AbstractSettings { Q_OBJECT + private: + static void createLegacyFileMapping(); + protected: AbstractSettings(); virtual ~AbstractSettings(); - static QVariant getSettingsValue(const QSharedPointer& pSettings, const QString& key); - public: #ifndef QT_NO_DEBUG static QSharedPointer mTestDir; @@ -34,48 +40,13 @@ class AbstractSettings static QSharedPointer getStore(); - virtual void load() = 0; - - virtual bool isUnsaved() const = 0; - virtual void save() = 0; - virtual void update(const AbstractSettings& pOther); + bool appIsBackgroundService() const; Q_SIGNALS: void fireSettingsChanged(); }; -template bool containsAllEntries(const T& pLeftList, const T& pRightList) -{ - if (&pLeftList == &pRightList) - { - return true; - } - - if (pLeftList.size() != pRightList.size()) - { - return false; - } - - for (const auto& entry : pLeftList) - { - if (!pRightList.contains(entry)) - { - return false; - } - } - - for (const auto& entry : pRightList) - { - if (!pLeftList.contains(entry)) - { - return false; - } - } - - return true; -} - } /* namespace governikus */ diff --git a/src/settings/AppSettings.cpp b/src/settings/AppSettings.cpp index ced3ee8..b69b838 100644 --- a/src/settings/AppSettings.cpp +++ b/src/settings/AppSettings.cpp @@ -1,7 +1,5 @@ /*! - * AppSettings.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "AppSettings.h" @@ -15,21 +13,15 @@ defineSingleton(AppSettings) AppSettings::AppSettings() : AbstractSettings() - , mDriverSettings() , mGeneralSettings() , mPreVerificationSettings() - , mProviderSettings() - , 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(&mHistorySettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); connect(&mRemoteReaderSettings, &AbstractSettings::fireSettingsChanged, this, &AbstractSettings::fireSettingsChanged); - } @@ -44,43 +36,15 @@ AppSettings& AppSettings::getInstance() } -void AppSettings::load() -{ - mDriverSettings.load(); - mGeneralSettings.load(); - mPreVerificationSettings.load(); - mProviderSettings.load(); - mSecureStorage.load(); - mHistorySettings.load(); - mRemoteReaderSettings.load(); -} - - -bool AppSettings::isUnsaved() const -{ - AppSettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - void AppSettings::save() { - mDriverSettings.save(); mGeneralSettings.save(); mPreVerificationSettings.save(); - mProviderSettings.save(); mHistorySettings.save(); mRemoteReaderSettings.save(); } -DriverSettings& AppSettings::getDriverSettings() -{ - return mDriverSettings; -} - - GeneralSettings& AppSettings::getGeneralSettings() { return mGeneralSettings; @@ -93,25 +57,13 @@ PreVerificationSettings& AppSettings::getPreVerificationSettings() } -ProviderSettings& AppSettings::getProviderSettings() -{ - return mProviderSettings; -} - - -SecureStorage& AppSettings::getSecureStorage() -{ - return mSecureStorage; -} - - HistorySettings& AppSettings::getHistorySettings() { return mHistorySettings; } -RemoteReaderSettings& AppSettings::getRemoteReaderSettings() +RemoteServiceSettings& AppSettings::getRemoteServiceSettings() { return mRemoteReaderSettings; } diff --git a/src/settings/AppSettings.h b/src/settings/AppSettings.h index 23f4b05..a650d91 100644 --- a/src/settings/AppSettings.h +++ b/src/settings/AppSettings.h @@ -1,21 +1,16 @@ /*! - * AppSettings.h - * * \brief Contains the definition of the AppSettings class. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "AbstractSettings.h" -#include "DriverSettings.h" #include "GeneralSettings.h" #include "HistorySettings.h" #include "PreVerificationSettings.h" -#include "ProviderSettings.h" -#include "RemoteReaderSettings.h" -#include "SecureStorage.h" +#include "RemoteServiceSettings.h" #include @@ -32,54 +27,26 @@ class AppSettings { Q_OBJECT friend class ::test_AppSettings; - friend bool operator==(const AppSettings& pLeft, const AppSettings& pRight); private: - DriverSettings mDriverSettings; GeneralSettings mGeneralSettings; PreVerificationSettings mPreVerificationSettings; - ProviderSettings mProviderSettings; - SecureStorage mSecureStorage; HistorySettings mHistorySettings; - RemoteReaderSettings mRemoteReaderSettings; + RemoteServiceSettings mRemoteReaderSettings; protected: AppSettings(); - virtual ~AppSettings(); + virtual ~AppSettings() override; public: static AppSettings& getInstance(); - - virtual void load() override; - virtual bool isUnsaved() const override; virtual void save() override; - DriverSettings& getDriverSettings(); - GeneralSettings& getGeneralSettings(); - PreVerificationSettings& getPreVerificationSettings(); - ProviderSettings& getProviderSettings(); - SecureStorage& getSecureStorage(); - HistorySettings& getHistorySettings(); - RemoteReaderSettings& getRemoteReaderSettings(); + virtual GeneralSettings& getGeneralSettings(); + virtual PreVerificationSettings& getPreVerificationSettings(); + virtual HistorySettings& getHistorySettings(); + virtual RemoteServiceSettings& getRemoteServiceSettings(); }; -inline bool operator==(const AppSettings& pLeft, const AppSettings& pRight) -{ - return &pLeft == &pRight || ( - pLeft.mDriverSettings == pRight.mDriverSettings && - pLeft.mGeneralSettings == pRight.mGeneralSettings && - pLeft.mPreVerificationSettings == pRight.mPreVerificationSettings && - pLeft.mProviderSettings == pRight.mProviderSettings && - pLeft.mSecureStorage == pRight.mSecureStorage && - pLeft.mHistorySettings == pRight.mHistorySettings && - pLeft.mRemoteReaderSettings == pRight.mRemoteReaderSettings); -} - - -inline bool operator!=(const AppSettings& pLeft, const AppSettings& pRight) -{ - return !(pLeft == pRight); -} - } /* namespace governikus */ diff --git a/src/settings/AutoStart.h b/src/settings/AutoStart.h new file mode 100644 index 0000000..4db37f1 --- /dev/null +++ b/src/settings/AutoStart.h @@ -0,0 +1,20 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +namespace governikus +{ + + +class AutoStart +{ + public: + static bool enabled(); + static void set(bool pEnabled); +}; + + +} /* namespace governikus */ diff --git a/src/settings/AutoStart_generic.cpp b/src/settings/AutoStart_generic.cpp new file mode 100644 index 0000000..47ce711 --- /dev/null +++ b/src/settings/AutoStart_generic.cpp @@ -0,0 +1,25 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AutoStart.h" + +#include + + +using namespace governikus; + + +bool AutoStart::enabled() +{ + return false; +} + + +void AutoStart::set(bool pEnabled) +{ + if (pEnabled) + { + qDebug() << "Autostart not supported on this system"; + } +} diff --git a/src/settings/AutoStart_osx.cpp b/src/settings/AutoStart_osx.cpp new file mode 100644 index 0000000..cd56f3b --- /dev/null +++ b/src/settings/AutoStart_osx.cpp @@ -0,0 +1,101 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AutoStart.h" + +#include +#include +#include + +#import + + +using namespace governikus; + + +static bool checkAndRemoveAutoStart(bool pRemove) +{ + qDebug() << "Loading OSX login items"; + + QRegularExpression regex("/Contents/Resources$"); + NSString* appPath = QCoreApplication::applicationDirPath().remove(regex).toNSString(); + CFURLRef url = static_cast([NSURL fileURLWithPath: appPath]); + + // Create a reference to the shared file list. + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, + kLSSharedFileListSessionLoginItems, NULL); + + if (loginItems) + { + //Retrieve the list of Login Items and cast them to + // a NSArray so that it will be easier to iterate. + NSArray* loginItemsArray = static_cast(LSSharedFileListCopySnapshot(loginItems, NULL)); + for (NSUInteger i = 0; i < [loginItemsArray count]; ++i) + { + LSSharedFileListItemRef itemRef = static_cast([loginItemsArray objectAtIndex:i]); + //Resolve the item with URL + if (LSSharedFileListItemResolve(itemRef, 0, static_cast(&url), NULL) == noErr) + { + NSURL* nsUrl = static_cast(url); + NSString* urlPath = [nsUrl path]; + if ([urlPath compare : appPath] == NSOrderedSame) + { + if (pRemove) + { + LSSharedFileListItemRemove(loginItems, itemRef); + } + + return true; + } + } + else + { + const CFStringRef stringRef = LSSharedFileListItemCopyDisplayName(itemRef); + if (stringRef) + { + const QString displayName = QString::fromCFString(stringRef); + if (displayName.startsWith(QCoreApplication::applicationName())) + { + LSSharedFileListItemRemove(loginItems, itemRef); + qDebug() << "Removed the unresolvable application with diplay name" << displayName << "from OSX login items."; + } + } + } + } + [loginItemsArray release]; + } + + return false; +} + + +bool AutoStart::enabled() +{ + return checkAndRemoveAutoStart(false); +} + + +void AutoStart::set(bool pEnabled) +{ + if (pEnabled) + { + QRegularExpression regex("/Contents/Resources$"); + NSString* path = QCoreApplication::applicationDirPath().remove(regex).toNSString(); + CFURLRef url = static_cast([NSURL fileURLWithPath: path]); + + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + if (loginItems) + { + LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL); + if (item) + { + CFRelease(item); + return; + } + } + return; + } + + checkAndRemoveAutoStart(true); +} diff --git a/src/settings/AutoStart_win.cpp b/src/settings/AutoStart_win.cpp new file mode 100644 index 0000000..5ddf214 --- /dev/null +++ b/src/settings/AutoStart_win.cpp @@ -0,0 +1,36 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AutoStart.h" + +#include +#include +#include + + +using namespace governikus; + + +bool AutoStart::enabled() +{ + QSettings windowsBootUpSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); + return windowsBootUpSettings.contains(QCoreApplication::applicationName()); +} + + +void AutoStart::set(bool pEnabled) +{ + QSettings windowsBootUpSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); + + if (pEnabled) + { + QString applicationFilePath = QCoreApplication::applicationFilePath(); + applicationFilePath.replace(QStringLiteral("/"), QString("\\")); + windowsBootUpSettings.setValue(QCoreApplication::applicationName(), "\"" + applicationFilePath + "\""); + } + else + { + windowsBootUpSettings.remove(QCoreApplication::applicationName()); + } +} diff --git a/src/settings/CMakeLists.txt b/src/settings/CMakeLists.txt index b7d3b93..923a0f9 100644 --- a/src/settings/CMakeLists.txt +++ b/src/settings/CMakeLists.txt @@ -1,6 +1,6 @@ ADD_PLATFORM_LIBRARY(AusweisAppSettings) -TARGET_LINK_LIBRARIES(AusweisAppSettings Qt5::Network Qt5::Core AusweisAppGlobal) +TARGET_LINK_LIBRARIES(AusweisAppSettings Qt5::Core Qt5::Network OpenSSL::Crypto AusweisAppGlobal) IF(MAC) TARGET_LINK_LIBRARIES(AusweisAppSettings ${OSX_APPKIT}) diff --git a/src/settings/CallCost.cpp b/src/settings/CallCost.cpp deleted file mode 100644 index 31f656e..0000000 --- a/src/settings/CallCost.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 6c2e97e..0000000 --- a/src/settings/CallCost.h +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * \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 deleted file mode 100644 index ad2ced6..0000000 --- a/src/settings/DriverSettings.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/*! - * DriverSettings.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - - -#include "DriverSettings.h" - -#include - -using namespace governikus; - - -namespace -{ -const QLatin1String SETTINGS_GROUP_NAME_DRIVERS("drivers"); - -const QLatin1String SETTINGS_NAME_ISSUEDATE("issuedate"); - -const QLatin1String SETTINGS_NAME_DRIVERS("list"); - -const QLatin1String SETTINGS_NAME_DRIVERREADERTYPE("readertype"); - -const QLatin1String SETTINGS_NAME_DRIVERVENDORID("vendorid"); - -const QLatin1String SETTINGS_NAME_DRIVERPRODUCTID("productid"); - -const QLatin1String SETTINGS_NAME_DRIVERNAME("name"); - -const QLatin1String SETTINGS_NAME_DRIVERURL("url"); -} - - -Driver::Driver(const QString& pReaderType, uint pVendorId, uint pProductId, - const QString& pName, const QString& pUrl) - : mReaderType(pReaderType) - , mVendorId(pVendorId) - , mProductId(pProductId) - , mName(pName) - , mUrl(pUrl) -{ -} - - -Driver::~Driver() -{ -} - - -const QString& Driver::getReaderType() const -{ - return mReaderType; -} - - -uint Driver::getVendorId() const -{ - return mVendorId; -} - - -uint Driver::getProductId() const -{ - return mProductId; -} - - -const QString& Driver::getName() const -{ - return mName; -} - - -const QString& Driver::getUrl() const -{ - return mUrl; -} - - -DriverSettings::DriverSettings() - : AbstractSettings() - , mIssueDate() - , mDrivers() -{ -} - - -DriverSettings::DriverSettings(const QDateTime& pIssueDate, const QVector >& pDrivers) - : AbstractSettings() - , mIssueDate(pIssueDate) - , mDrivers(pDrivers) -{ -} - - -DriverSettings::~DriverSettings() -{ -} - - -void DriverSettings::load() -{ - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_DRIVERS); - - const int listSize = settings->beginReadArray(SETTINGS_NAME_DRIVERS); - QVector > drivers; - drivers.reserve(listSize); - for (int i = 0; i < listSize; i++) - { - bool uintOk = false; - settings->setArrayIndex(i); - - const QString readerType = settings->value(SETTINGS_NAME_DRIVERREADERTYPE).toString(); - const uint vendorId = settings->value(SETTINGS_NAME_DRIVERVENDORID).toUInt(&uintOk); - if (!uintOk) - { - qWarning() << "invalid uint value in settings, skipping entry"; - - continue; - } - - const uint productId = settings->value(SETTINGS_NAME_DRIVERPRODUCTID).toUInt(&uintOk); - if (!uintOk) - { - qWarning() << "invalid uint value in settings, skipping entry"; - - continue; - } - - const QString name = settings->value(SETTINGS_NAME_DRIVERNAME).toString(); - const QString url = settings->value(SETTINGS_NAME_DRIVERURL).toString(); - const QSharedPointer driver(new Driver(readerType, vendorId, productId, name, url)); - - drivers += driver; - } - settings->endArray(); - - mDrivers = drivers; - - mIssueDate = settings->value(SETTINGS_NAME_ISSUEDATE).toDateTime(); - - settings->endGroup(); -} - - -bool DriverSettings::isUnsaved() const -{ - DriverSettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - -void DriverSettings::save() -{ - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_DRIVERS); - settings->remove(QString()); // remove the whole group first - - settings->beginWriteArray(SETTINGS_NAME_DRIVERS); - for (int i = 0; i < mDrivers.size(); i++) - { - settings->setArrayIndex(i); - - settings->setValue(SETTINGS_NAME_DRIVERREADERTYPE, mDrivers.at(i)->getReaderType()); - settings->setValue(SETTINGS_NAME_DRIVERVENDORID, mDrivers.at(i)->getVendorId()); - settings->setValue(SETTINGS_NAME_DRIVERPRODUCTID, mDrivers.at(i)->getProductId()); - settings->setValue(SETTINGS_NAME_DRIVERNAME, mDrivers.at(i)->getName()); - settings->setValue(SETTINGS_NAME_DRIVERURL, mDrivers.at(i)->getUrl()); - } - settings->endArray(); - - settings->setValue(SETTINGS_NAME_ISSUEDATE, mIssueDate); - - settings->endGroup(); - settings->sync(); -} - - -void DriverSettings::update(const AbstractSettings& pOther) -{ - const DriverSettings* const other = qobject_cast(&pOther); - if (other != nullptr) - { - mIssueDate = other->getIssueDate(); - mDrivers = other->getDrivers(); - } -} - - -const QDateTime& DriverSettings::getIssueDate() const -{ - return mIssueDate; -} - - -const QVector >& DriverSettings::getDrivers() const -{ - return mDrivers; -} diff --git a/src/settings/DriverSettings.h b/src/settings/DriverSettings.h deleted file mode 100644 index 35af20f..0000000 --- a/src/settings/DriverSettings.h +++ /dev/null @@ -1,108 +0,0 @@ -/*! - * DriverSettings.h - * - * \brief Class to retrieve and update information about available card reader drivers. - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#pragma once - - -#include "AbstractSettings.h" - - -#include -#include -#include - - -namespace governikus -{ -class Driver -{ - private: - const QString mReaderType; - - const uint mVendorId; - - const uint mProductId; - - const QString mName; - - const QString mUrl; - - public: - Driver(const QString& pReaderType, uint pVendorId, uint pProductId, - const QString& pName, const QString& pUrl); - - virtual ~Driver(); - - const QString& getReaderType() const; - - uint getVendorId() const; - - uint getProductId() const; - - const QString& getName() const; - - const QString& getUrl() const; -}; - -inline bool operator==(const Driver& pLeft, const Driver& pRight) -{ - return &pLeft == &pRight || ( - pLeft.getReaderType() == pRight.getReaderType() && - pLeft.getVendorId() == pRight.getVendorId() && - pLeft.getProductId() == pRight.getProductId() && - pLeft.getName() == pRight.getName() && - pLeft.getUrl() == pRight.getUrl()); -} - - -class DriverSettings - : public AbstractSettings -{ - Q_OBJECT - - private: - QDateTime mIssueDate; - - QVector > mDrivers; - - public: - DriverSettings(); - - DriverSettings(const QDateTime& pIssueDate, const QVector >& pDrivers); - - virtual ~DriverSettings(); - - virtual void load() override; - - virtual bool isUnsaved() const override; - - virtual void save() override; - - virtual void update(const AbstractSettings& pOther) override; - - const QDateTime& getIssueDate() const; - - const QVector >& getDrivers() const; - -}; - -inline bool operator==(const DriverSettings& pLeft, const DriverSettings& pRight) -{ - return &pLeft == &pRight || ( - pLeft.getIssueDate() == pRight.getIssueDate() && - pLeft.getDrivers() == pRight.getDrivers()); -} - - -inline bool operator!=(const DriverSettings& pLeft, const DriverSettings& pRight) -{ - return !(pLeft == pRight); -} - - -} /* namespace governikus */ diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index 6701f04..76139bb 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -1,64 +1,79 @@ /*! - * GeneralSettings.cpp - * * \brief Contains the method definitions of the GeneralSettings class. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "GeneralSettings.h" +#include "AutoStart.h" + #include #include #include -#include -#if defined(Q_OS_OSX) -#import -#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"); -const QLatin1String SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION("persistentSettingsVersion"); -const QLatin1String SETTINGS_NAME_TRANSPORT_PIN_REMINDER("transportPinReminder"); -const QLatin1String SETTINGS_NAME_DEVELOPER_MODE("developerMode"); -const QLatin1String SETTINGS_NAME_USE_SELFAUTH_TEST_URI("selfauthTestUri"); - -const QLatin1String SETTINGS_GROUP_NAME_GENERAL("common"); -const QLatin1String SETTINGS_NAME_AUTO("autoUpdateCheck"); -const QLatin1String SETTINGS_NAME_KEYLESS_PASSWORD("keylessPassword"); +namespace +{ +SETTINGS_NAME(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION, "persistentSettingsVersion") +SETTINGS_NAME(SETTINGS_NAME_SKIP_VERSION, "skipVersion") +SETTINGS_NAME(SETTINGS_NAME_AUTO_CLOSE_WINDOW, "autoCloseWindow") +SETTINGS_NAME(SETTINGS_NAME_SHOW_SETUP_ASSISTANT, "showSetupAssistant") +SETTINGS_NAME(SETTINGS_NAME_REMIND_USER_TO_CLOSE, "remindToClose") +SETTINGS_NAME(SETTINGS_NAME_TRANSPORT_PIN_REMINDER, "transportPinReminder") +SETTINGS_NAME(SETTINGS_NAME_DEVELOPER_MODE, "developerMode") +SETTINGS_NAME(SETTINGS_NAME_USE_SELF_AUTH_TEST_URI, "selfauthTestUri") +SETTINGS_NAME(SETTINGS_NAME_LANGUAGE, "language") +SETTINGS_NAME(SETTINGS_GROUP_NAME_COMMON, "common") +SETTINGS_NAME(SETTINGS_NAME_AUTO, "autoUpdateCheck") +SETTINGS_NAME(SETTINGS_NAME_KEYLESS_PASSWORD, "keylessPassword") +} GeneralSettings::GeneralSettings() : AbstractSettings() - , mAutoCloseWindowAfterAuthentication(true) - , mAutoUpdateCheck(true) - , mUseScreenKeyboard(false) - , mShowSetupAssistant(true) - , mRemindUserToClose(true) - , mPersistentSettingsVersion() - , mTransportPinReminder(true) - , mDeveloperMode(false) - , mSelfauthenticationTestUri(false) + , mStoreGeneral(getStore()) + , mStoreCommon(getStore()) { + { + // With 1.14.0 the reader and provider are no longer stored in the settings + + mStoreCommon->beginGroup(QStringLiteral("readers")); + mStoreCommon->remove(QString()); // remove the whole group + mStoreCommon->endGroup(); + + mStoreCommon->beginGroup(QStringLiteral("providers")); + mStoreCommon->remove(QString()); // remove the whole group + mStoreCommon->endGroup(); + } + + mStoreCommon->beginGroup(SETTINGS_GROUP_NAME_COMMON()); + // QFuture.result() crashes under linux and win if uninitalized mAutoStart = QtConcurrent::run([] { - return GENERAL_SETTINGS_DEFAULT_AUTOSTART; + return !GENERAL_SETTINGS_DEFAULT_AUTOSTART; }); + mAutoStart.waitForFinished(); + + // Check if the key "autoCloseWindow" (introduced in changeset 199210b0b20c) + // does not yet exist to detect a new installation. This key was the first one + // in the settings general group. + const bool isNewInstallation = !mStoreGeneral->allKeys().contains(SETTINGS_NAME_AUTO_CLOSE_WINDOW()); + if (isNewInstallation) + { + mStoreGeneral->setValue(SETTINGS_NAME_AUTO_CLOSE_WINDOW(), true); + setAutoStart(GENERAL_SETTINGS_DEFAULT_AUTOSTART); + setTransportPinReminder(true); + mStoreGeneral->sync(); + } + +#ifdef QT_NO_DEBUG + // Iterate autostart entries in order to remove broken login items on macos. + // This process might take up to 15s per entry. + mAutoStart = QtConcurrent::run(AutoStart::enabled); +#endif } @@ -68,248 +83,12 @@ GeneralSettings::~GeneralSettings() } -void GeneralSettings::load() -{ - auto settings = getStore(); - // Check if the key "autoCloseWindow" (introduced in changeset 199210b0b20c) - // does not yet exist to detect a new installation. This key was the first one - // in the settings general group. - const bool isNewInstallation = !settings->allKeys().contains(SETTINGS_NAME_AUTO_CLOSE_WINDOW); - - // for historical reasons this is not loaded/saved in the general settings group - mAutoCloseWindowAfterAuthentication = settings->value(SETTINGS_NAME_AUTO_CLOSE_WINDOW, mAutoCloseWindowAfterAuthentication).toBool(); - mShowSetupAssistant = settings->value(SETTINGS_NAME_SHOW_SETUP_ASSISTANT, mShowSetupAssistant).toBool(); - mRemindUserToClose = settings->value(SETTINGS_NAME_REMIND_USER_TO_CLOSE, mRemindUserToClose).toBool(); - mPersistentSettingsVersion = settings->value(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION, mPersistentSettingsVersion).toString(); - mTransportPinReminder = settings->value(SETTINGS_NAME_TRANSPORT_PIN_REMINDER, isNewInstallation).toBool(); - mDeveloperMode = settings->value(SETTINGS_NAME_DEVELOPER_MODE, mDeveloperMode).toBool(); - mSelfauthenticationTestUri = settings->value(SETTINGS_NAME_USE_SELFAUTH_TEST_URI, mSelfauthenticationTestUri).toBool(); - - settings->beginGroup(SETTINGS_GROUP_NAME_GENERAL); - - mAutoUpdateCheck = settings->value(SETTINGS_NAME_AUTO, mAutoUpdateCheck).toBool(); - mUseScreenKeyboard = settings->value(SETTINGS_NAME_KEYLESS_PASSWORD, mUseScreenKeyboard).toBool(); - - settings->endGroup(); - -#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) - if (isNewInstallation) - { - setAutoStart(GENERAL_SETTINGS_DEFAULT_AUTOSTART); - } - else -#endif - { - // Iterate autostart entries in order to remove broken login items on macos. - // This process might take up to 15s per entry. - mAutoStart.waitForFinished(); - mAutoStart = QtConcurrent::run(readSettingsAutoStart); - } -} - - -bool GeneralSettings::isUnsaved() const -{ - GeneralSettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - void GeneralSettings::save() { - auto settings = getStore(); + mStoreGeneral->setValue(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION(), QCoreApplication::applicationVersion()); - // for historical reasons this is not loaded/saved in the general settings group - settings->setValue(SETTINGS_NAME_AUTO_CLOSE_WINDOW, mAutoCloseWindowAfterAuthentication); - settings->setValue(SETTINGS_NAME_SHOW_SETUP_ASSISTANT, mShowSetupAssistant); - settings->setValue(SETTINGS_NAME_REMIND_USER_TO_CLOSE, mRemindUserToClose); - - mPersistentSettingsVersion = QCoreApplication::applicationVersion(); - settings->setValue(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION, mPersistentSettingsVersion); - settings->setValue(SETTINGS_NAME_TRANSPORT_PIN_REMINDER, mTransportPinReminder); - settings->setValue(SETTINGS_NAME_DEVELOPER_MODE, mDeveloperMode); - settings->setValue(SETTINGS_NAME_USE_SELFAUTH_TEST_URI, mSelfauthenticationTestUri); - - settings->beginGroup(SETTINGS_GROUP_NAME_GENERAL); - - settings->setValue(SETTINGS_NAME_AUTO, mAutoUpdateCheck); - settings->setValue(SETTINGS_NAME_KEYLESS_PASSWORD, mUseScreenKeyboard); - writeSettingsAutoStart(mAutoStart); - - settings->endGroup(); - settings->sync(); -} - - -#if defined(Q_OS_OSX) - -bool addAutoStartMacOS() -{ - QRegularExpression regex("/Contents/Resources$"); - NSString* path = QCoreApplication::applicationDirPath().remove(regex).toNSString(); - CFURLRef url = (CFURLRef)[NSURL fileURLWithPath: path]; - - LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); - if (loginItems) - { - LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL); - if (item) - { - CFRelease(item); - return true; - } - } - return false; -} - - -bool checkAndRemoveAutoStartMacOS(bool pRemove = true) -{ - qDebug() << "Loading OSX login items"; - - QRegularExpression regex("/Contents/Resources$"); - NSString* appPath = QCoreApplication::applicationDirPath().remove(regex).toNSString(); - CFURLRef url = (CFURLRef)[NSURL fileURLWithPath: appPath]; - - // Create a reference to the shared file list. - LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, - kLSSharedFileListSessionLoginItems, NULL); - - if (loginItems) - { - //Retrieve the list of Login Items and cast them to - // a NSArray so that it will be easier to iterate. - NSArray* loginItemsArray = (NSArray*) LSSharedFileListCopySnapshot(loginItems, NULL); - for (NSUInteger i = 0; i < [loginItemsArray count]; ++i) - { - LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i]; - //Resolve the item with URL - if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &url, NULL) == noErr) - { - NSString* urlPath = [(NSURL*) url path]; - if ([urlPath compare : appPath] == NSOrderedSame) - { - if (pRemove) - { - LSSharedFileListItemRemove(loginItems, itemRef); - } - - return true; - } - } - else - { - const CFStringRef stringRef = LSSharedFileListItemCopyDisplayName(itemRef); - if (stringRef) - { - const QString displayName = QString::fromCFString(stringRef); - if (displayName.startsWith(QCoreApplication::applicationName())) - { - LSSharedFileListItemRemove(loginItems, itemRef); - qDebug() << "Removed the unresolvable application with diplay name" << displayName << "from OSX login items."; - } - } - } - } - [loginItemsArray release]; - } - - return false; -} - - -#endif - - -bool GeneralSettings::readSettingsAutoStart() -{ -#ifndef QT_NO_DEBUG - if (QCoreApplication::applicationName().startsWith(QLatin1String("Test"))) - { - return Test_AutoStart; - } -#endif - -#if defined(Q_OS_WIN32) - QSettings windowsBootUpSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); - return windowsBootUpSettings.contains(QCoreApplication::applicationName()); - -#elif defined(Q_OS_OSX) - return checkAndRemoveAutoStartMacOS(false); - -#else - qDebug() << "Autostart not supported on this system"; - return false; - -#endif -} - - -void GeneralSettings::writeSettingsAutoStart(bool pAutoStart) -{ -#ifndef QT_NO_DEBUG - if (QCoreApplication::applicationName().startsWith(QLatin1String("Test"))) - { - Test_AutoStart = pAutoStart; - return; - } -#endif - - -#ifdef Q_OS_WIN32 - QSettings windowsBootUpSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat); - - if (pAutoStart) - { - QString applicationFilePath = QCoreApplication::applicationFilePath(); - applicationFilePath.replace(QStringLiteral("/"), QString("\\")); - windowsBootUpSettings.setValue(QCoreApplication::applicationName(), "\"" + applicationFilePath + "\""); - } - else - { - windowsBootUpSettings.remove(QCoreApplication::applicationName()); - } -#elif defined(Q_OS_OSX) - - pAutoStart ? addAutoStartMacOS() : checkAndRemoveAutoStartMacOS(); - -#else - qDebug() << "Autostart not supported on this system"; - Q_UNUSED(pAutoStart) -#endif -} - - -bool GeneralSettings::isAutoCloseWindowAfterAuthentication() const -{ - return mAutoCloseWindowAfterAuthentication; -} - - -void GeneralSettings::setAutoCloseWindowAfterAuthentication(bool pAutoClose) -{ - if (pAutoClose != mAutoCloseWindowAfterAuthentication) - { - mAutoCloseWindowAfterAuthentication = pAutoClose; - Q_EMIT fireSettingsChanged(); - } -} - - -bool GeneralSettings::isAutoUpdateCheck() const -{ - return mAutoUpdateCheck; -} - - -void GeneralSettings::setAutoUpdateCheck(bool pAutoCheck) -{ - if (pAutoCheck != mAutoUpdateCheck) - { - mAutoUpdateCheck = pAutoCheck; - Q_EMIT fireSettingsChanged(); - } + mStoreGeneral->sync(); + mStoreCommon->sync(); } @@ -323,27 +102,47 @@ void GeneralSettings::setAutoStart(bool pAutoStart) { if (pAutoStart != mAutoStart) { +#ifdef QT_NO_DEBUG + AutoStart::set(pAutoStart); +#endif mAutoStart.waitForFinished(); mAutoStart = QtConcurrent::run([pAutoStart] { return pAutoStart; }); - Q_EMIT fireSettingsChanged(); } } -bool GeneralSettings::isUseScreenKeyboard() const +const QString GeneralSettings::getPersistentSettingsVersion() const { - return mUseScreenKeyboard; + return mStoreGeneral->value(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION(), QString()).toString(); } -void GeneralSettings::setUseScreenKeyboard(bool pKeylessPassword) +QString GeneralSettings::getSkipVersion() { - if (pKeylessPassword != mUseScreenKeyboard) + return mStoreGeneral->value(SETTINGS_NAME_SKIP_VERSION(), QString()).toString(); +} + + +void GeneralSettings::skipVersion(const QString& pVersion) +{ + mStoreGeneral->setValue(SETTINGS_NAME_SKIP_VERSION(), pVersion); +} + + +bool GeneralSettings::isAutoCloseWindowAfterAuthentication() const +{ + return mStoreGeneral->value(SETTINGS_NAME_AUTO_CLOSE_WINDOW(), true).toBool(); +} + + +void GeneralSettings::setAutoCloseWindowAfterAuthentication(bool pAutoClose) +{ + if (pAutoClose != isAutoCloseWindowAfterAuthentication()) { - mUseScreenKeyboard = pKeylessPassword; + mStoreGeneral->setValue(SETTINGS_NAME_AUTO_CLOSE_WINDOW(), pAutoClose); Q_EMIT fireSettingsChanged(); } } @@ -351,15 +150,15 @@ void GeneralSettings::setUseScreenKeyboard(bool pKeylessPassword) bool GeneralSettings::isShowSetupAssistant() const { - return mShowSetupAssistant; + return mStoreGeneral->value(SETTINGS_NAME_SHOW_SETUP_ASSISTANT(), true).toBool(); } void GeneralSettings::setShowSetupAssistant(bool pShowSetupAssistant) { - if (pShowSetupAssistant != mShowSetupAssistant) + if (pShowSetupAssistant != isShowSetupAssistant()) { - mShowSetupAssistant = pShowSetupAssistant; + mStoreGeneral->setValue(SETTINGS_NAME_SHOW_SETUP_ASSISTANT(), pShowSetupAssistant); Q_EMIT fireSettingsChanged(); } } @@ -367,37 +166,35 @@ void GeneralSettings::setShowSetupAssistant(bool pShowSetupAssistant) bool GeneralSettings::isRemindUserToClose() const { - return mRemindUserToClose; + return mStoreGeneral->value(SETTINGS_NAME_REMIND_USER_TO_CLOSE(), true).toBool(); } void GeneralSettings::setRemindUserToClose(bool pRemindUser) { - if (pRemindUser != mRemindUserToClose) + if (pRemindUser != isRemindUserToClose()) { - mRemindUserToClose = pRemindUser; + mStoreGeneral->setValue(SETTINGS_NAME_REMIND_USER_TO_CLOSE(), pRemindUser); Q_EMIT fireSettingsChanged(); } } -const QString& GeneralSettings::getPersistentSettingsVersion() const -{ - return mPersistentSettingsVersion; -} - - bool GeneralSettings::isTransportPinReminder() const { - return mTransportPinReminder; + // The standard value should be true but we need to set it to false for backwards + // compatibility. It is set to true in the constructor if we have a new + // installation. The the standard value used in this function will only be + // used if the user upgrades from AusweisApp 1.6.3 or an older version. + return mStoreGeneral->value(SETTINGS_NAME_TRANSPORT_PIN_REMINDER(), false).toBool(); } void GeneralSettings::setTransportPinReminder(bool pTransportPinReminder) { - if (pTransportPinReminder != mTransportPinReminder) + if (pTransportPinReminder != isTransportPinReminder()) { - mTransportPinReminder = pTransportPinReminder; + mStoreGeneral->setValue(SETTINGS_NAME_TRANSPORT_PIN_REMINDER(), pTransportPinReminder); Q_EMIT fireSettingsChanged(); } } @@ -405,55 +202,92 @@ 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()) + const bool developerMode = mStoreGeneral->value(SETTINGS_NAME_DEVELOPER_MODE(), false).toBool(); + if (developerMode && appIsBackgroundService()) { - qDebug() << "Running as android service. Developer mode is disallowed."; + qDebug() << "Running as a background service. Developer mode is disallowed."; return false; } -#endif - return mDeveloperMode; + return developerMode; } void GeneralSettings::setDeveloperMode(bool pEnabled) { - if (pEnabled != mDeveloperMode) + if (pEnabled != isDeveloperMode()) { - mDeveloperMode = pEnabled; + mStoreGeneral->setValue(SETTINGS_NAME_DEVELOPER_MODE(), pEnabled); Q_EMIT fireSettingsChanged(); } } -bool GeneralSettings::useSelfauthenticationTestUri() const +bool GeneralSettings::useSelfAuthTestUri() const { - return mSelfauthenticationTestUri; + return mStoreGeneral->value(SETTINGS_NAME_USE_SELF_AUTH_TEST_URI(), false).toBool(); } void GeneralSettings::setUseSelfauthenticationTestUri(bool pUse) { - if (pUse != mSelfauthenticationTestUri) + if (pUse != useSelfAuthTestUri()) { - mSelfauthenticationTestUri = pUse; + mStoreGeneral->setValue(SETTINGS_NAME_USE_SELF_AUTH_TEST_URI(), pUse); Q_EMIT fireSettingsChanged(); } } -void GeneralSettings::skipVersion(const QString& pVersion) +QLocale::Language GeneralSettings::getLanguage() const { - auto store = getStore(); - store->setValue(SETTINGS_SKIP_VERSION, pVersion); - store->sync(); + const QString loadedLanguage = mStoreGeneral->value(SETTINGS_NAME_LANGUAGE(), QString()).toString(); + if (loadedLanguage.isEmpty()) + { + return QLocale::C; + } + + return QLocale(loadedLanguage).language(); } -QString GeneralSettings::getSkipVersion() +void GeneralSettings::setLanguage(const QLocale::Language pLanguage) { - return getStore()->value(SETTINGS_SKIP_VERSION).toString(); + if (pLanguage != getLanguage()) + { + mStoreGeneral->setValue(SETTINGS_NAME_LANGUAGE(), pLanguage == QLocale::C ? QString() : QLocale(pLanguage).bcp47Name()); + Q_EMIT fireSettingsChanged(); + } +} + + +bool GeneralSettings::isAutoUpdateCheck() const +{ + return mStoreCommon->value(SETTINGS_NAME_AUTO(), true).toBool(); +} + + +void GeneralSettings::setAutoUpdateCheck(bool pAutoCheck) +{ + if (pAutoCheck != isAutoUpdateCheck()) + { + mStoreCommon->setValue(SETTINGS_NAME_AUTO(), pAutoCheck); + Q_EMIT fireSettingsChanged(); + } +} + + +bool GeneralSettings::isUseScreenKeyboard() const +{ + return mStoreCommon->value(SETTINGS_NAME_KEYLESS_PASSWORD(), false).toBool(); +} + + +void GeneralSettings::setUseScreenKeyboard(bool pKeylessPassword) +{ + if (pKeylessPassword != isUseScreenKeyboard()) + { + mStoreCommon->setValue(SETTINGS_NAME_KEYLESS_PASSWORD(), pKeylessPassword); + Q_EMIT fireSettingsChanged(); + } } diff --git a/src/settings/GeneralSettings.h b/src/settings/GeneralSettings.h index 800f07f..2cd4662 100644 --- a/src/settings/GeneralSettings.h +++ b/src/settings/GeneralSettings.h @@ -1,9 +1,7 @@ /*! - * GeneralSettings.h - * * \brief Contains the definition of the GeneralSettings class. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -11,6 +9,7 @@ #include "AbstractSettings.h" #include +#include class test_GeneralSettings; @@ -18,18 +17,13 @@ class test_GeneralSettings; namespace governikus { - -#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) -#define GENERAL_SETTINGS_DEFAULT_AUTOSTART true +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + #define GENERAL_SETTINGS_DEFAULT_AUTOSTART true #else -#define GENERAL_SETTINGS_DEFAULT_AUTOSTART false + #define GENERAL_SETTINGS_DEFAULT_AUTOSTART false #endif -/*! - * \brief Represents general settings. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ + class GeneralSettings : public AbstractSettings { @@ -40,81 +34,26 @@ class GeneralSettings friend bool operator==(const GeneralSettings& pLeft, const GeneralSettings& pRight); private: - /*! - * automatically close the window after successful authentications - */ - bool mAutoCloseWindowAfterAuthentication; - - /*! - * automatically start the program on system start - */ QFuture mAutoStart; + QSharedPointer mStoreGeneral; + QSharedPointer mStoreCommon; - /*! - * automatically check for updated on program start - */ - bool mAutoUpdateCheck; - - /*! - * use screen keyboard - */ - bool mUseScreenKeyboard; - - /*! - * show the setup assistant on application start - */ - bool mShowSetupAssistant; - - /*! - * remind the user to close the application using the menu and not by clicking the window close button. - */ - bool mRemindUserToClose; - - /*! - * i.e. version of application instance last saving the settings - */ - QString mPersistentSettingsVersion; - - /*! - * remind the user to change the transport PIN before first authentication. - */ - bool mTransportPinReminder; - - /*! - * run the application in developer mode, e.g. failed security checks do not abort operations - */ - bool mDeveloperMode; - - /*! - * use test uri for selfauthentication to allow test id cards - */ - bool mSelfauthenticationTestUri; - - static bool readSettingsAutoStart(); - static void writeSettingsAutoStart(bool pAutoStart); GeneralSettings(); public: - static void skipVersion(const QString& pVersion); - static QString getSkipVersion(); - - virtual ~GeneralSettings(); - - virtual void load() override; - virtual bool isUnsaved() const override; + virtual ~GeneralSettings() override; virtual void save() override; - bool isAutoCloseWindowAfterAuthentication() const; - void setAutoCloseWindowAfterAuthentication(bool pAutoClose); - - bool isAutoUpdateCheck() const; - void setAutoUpdateCheck(bool pAutoUpdateCheck); - bool isAutoStart() const; void setAutoStart(bool pAutoStart); - bool isUseScreenKeyboard() const; - void setUseScreenKeyboard(bool pUseScreenKeyboard); + const QString getPersistentSettingsVersion() const; + + QString getSkipVersion(); + void skipVersion(const QString& pVersion); + + bool isAutoCloseWindowAfterAuthentication() const; + void setAutoCloseWindowAfterAuthentication(bool pAutoClose); bool isShowSetupAssistant() const; void setShowSetupAssistant(bool pShowSetupAssistant); @@ -125,36 +64,21 @@ class GeneralSettings bool isTransportPinReminder() const; void setTransportPinReminder(bool pTransportPinReminder); - const QString& getPersistentSettingsVersion() const; - bool isDeveloperMode() const; void setDeveloperMode(bool pEnabled); - bool useSelfauthenticationTestUri() const; + bool useSelfAuthTestUri() const; void setUseSelfauthenticationTestUri(bool pUse); + + QLocale::Language getLanguage() const; + void setLanguage(const QLocale::Language pLanguage); + + bool isAutoUpdateCheck() const; + void setAutoUpdateCheck(bool pAutoUpdateCheck); + + bool isUseScreenKeyboard() const; + void setUseScreenKeyboard(bool pUseScreenKeyboard); }; -inline bool operator==(const GeneralSettings& pLeft, const GeneralSettings& pRight) -{ - return &pLeft == &pRight || ( - pLeft.mShowSetupAssistant == pRight.mShowSetupAssistant && - pLeft.mRemindUserToClose == pRight.mRemindUserToClose && - pLeft.mAutoCloseWindowAfterAuthentication == pRight.mAutoCloseWindowAfterAuthentication && - pLeft.mAutoStart.result() == pRight.mAutoStart.result() && - pLeft.mAutoUpdateCheck == pRight.mAutoUpdateCheck && - pLeft.mUseScreenKeyboard == pRight.mUseScreenKeyboard && - pLeft.mPersistentSettingsVersion == pRight.mPersistentSettingsVersion && - pLeft.mTransportPinReminder == pRight.mTransportPinReminder && - pLeft.mDeveloperMode == pRight.mDeveloperMode && - pLeft.mSelfauthenticationTestUri == pRight.mSelfauthenticationTestUri); -} - - -inline bool operator!=(const GeneralSettings& pLeft, const GeneralSettings& pRight) -{ - return !(pLeft == pRight); -} - - } /* namespace governikus */ diff --git a/src/settings/HistoryInfo.cpp b/src/settings/HistoryInfo.cpp new file mode 100644 index 0000000..63eced1 --- /dev/null +++ b/src/settings/HistoryInfo.cpp @@ -0,0 +1,66 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "HistoryInfo.h" + +#include +#include + + +using namespace governikus; + + +HistoryInfo::HistoryInfo(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QString& pRequestedData) + : mSubjectName(pSubjectName) + , mSubjectUrl(pSubjectUrl) + , mPurpose(pUsage) + , mDateTime(roundToSeconds(pDateTime)) + , mTermOfUsage(pTermOfUsage) + , mRequestedData(pRequestedData) +{ +} + + +QDateTime HistoryInfo::roundToSeconds(const QDateTime& pDateTime) +{ + QDateTime roundedDateTime; + roundedDateTime.setMSecsSinceEpoch(pDateTime.toMSecsSinceEpoch() - pDateTime.toMSecsSinceEpoch() % 1000); + return roundedDateTime; +} + + +const QString& HistoryInfo::getRequestedData() const +{ + return mRequestedData; +} + + +const QString& HistoryInfo::getTermOfUsage() const +{ + return mTermOfUsage; +} + + +const QDateTime& HistoryInfo::getDateTime() const +{ + return mDateTime; +} + + +const QString& HistoryInfo::getPurpose() const +{ + return mPurpose; +} + + +const QString& HistoryInfo::getSubjectName() const +{ + return mSubjectName; +} + + +const QString& HistoryInfo::getSubjectUrl() const +{ + return mSubjectUrl; +} diff --git a/src/settings/HistoryInfo.h b/src/settings/HistoryInfo.h new file mode 100644 index 0000000..7d2c46a --- /dev/null +++ b/src/settings/HistoryInfo.h @@ -0,0 +1,86 @@ +/*! + * \brief Represents history settings. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AbstractSettings.h" + +#include +#include + + +namespace governikus +{ + +/*! + * \brief Represents a history entry, i.e. information of a successfull authentication + */ +class HistoryInfo +{ + private: + static QDateTime roundToSeconds(const QDateTime& pDateTime); + + /*! + * The subject name contained in the certificate description + */ + QString mSubjectName; + + /*! + * The subject url contained in the certificate description + */ + QString mSubjectUrl; + + /*! + * The purpose contained in the certificate description + */ + QString mPurpose; + + /*! + * The authentication date and time + */ + QDateTime mDateTime; + + /*! + * The terms of usage contained in the certificate description + */ + QString mTermOfUsage; + + /*! + * The requested data fields during authentication + */ + QString mRequestedData; + + public: + HistoryInfo() + { + } + + + HistoryInfo(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QString& pRequestedData); + + bool operator==(const HistoryInfo& pOther) const + { + return mSubjectName == pOther.mSubjectName && mSubjectUrl == pOther.mSubjectUrl && mPurpose == pOther.mPurpose + && mDateTime == pOther.mDateTime && mTermOfUsage == pOther.mTermOfUsage && mRequestedData == pOther.mRequestedData; + } + + + bool operator!=(const HistoryInfo& pOther) const + { + return !(*this == pOther); + } + + + const QString& getSubjectName() const; + const QString& getSubjectUrl() const; + const QString& getPurpose() const; + const QDateTime& getDateTime() const; + const QString& getTermOfUsage() const; + const QString& getRequestedData() const; +}; + + +} /* namespace governikus */ diff --git a/src/settings/HistorySettings.cpp b/src/settings/HistorySettings.cpp index 7080aa2..e31b8c0 100644 --- a/src/settings/HistorySettings.cpp +++ b/src/settings/HistorySettings.cpp @@ -1,96 +1,33 @@ /*! - * HistorySetting.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "HistorySettings.h" +#include #include -#ifdef Q_OS_ANDROID -#include -#include -#endif - - -// names for settings groups/keys -const QLatin1String SETTINGS_GROUP_NAME_CHRONIC("history"); -const QLatin1String SETTINGS_NAME_HISTORY_ITEMS("items"); -const QLatin1String SETTINGS_NAME_HISTORY_ENABLED("enable"); -const QLatin1String SETTINGS_NAME_CHRONIC_SUBJECTNAME("subjectName"); -const QLatin1String SETTINGS_NAME_CHRONIC_SUBJECTURL("subjectUrl"); -const QLatin1String SETTINGS_NAME_CHRONIC_USAGE("usage"); -const QLatin1String SETTINGS_NAME_CHRONIC_DATETIME("dateTime"); -const QLatin1String SETTINGS_NAME_CHRONIC_TOU("termOfUsage"); -const QLatin1String SETTINGS_NAME_CHRONIC_REQUESTED_DATA("requestedData"); - +namespace +{ +SETTINGS_NAME(SETTINGS_GROUP_NAME_CHRONIC, "history") +SETTINGS_NAME(SETTINGS_NAME_HISTORY_ITEMS, "items") +SETTINGS_NAME(SETTINGS_NAME_HISTORY_ENABLED, "enable") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_SUBJECTNAME, "subjectName") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_SUBJECTURL, "subjectUrl") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_USAGE, "usage") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_DATETIME, "dateTime") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_TOU, "termOfUsage") +SETTINGS_NAME(SETTINGS_NAME_CHRONIC_REQUESTED_DATA, "requestedData") +} using namespace governikus; -HistoryEntry::HistoryEntry(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QString& pRequestedData) - : mSubjectName(pSubjectName) - , mSubjectUrl(pSubjectUrl) - , mPurpose(pUsage) - , mDateTime(roundToSeconds(pDateTime)) - , mTermOfUsage(pTermOfUsage) - , mRequestedData(pRequestedData) -{ -} - - -QDateTime HistoryEntry::roundToSeconds(const QDateTime& pDateTime) -{ - QDateTime roundedDateTime; - roundedDateTime.setMSecsSinceEpoch(pDateTime.toMSecsSinceEpoch() - pDateTime.toMSecsSinceEpoch() % 1000); - return roundedDateTime; -} - - -const QString& HistoryEntry::getRequestedData() const -{ - return mRequestedData; -} - - -const QString& HistoryEntry::getTermOfUsage() const -{ - return mTermOfUsage; -} - - -const QDateTime& HistoryEntry::getDateTime() const -{ - return mDateTime; -} - - -const QString& HistoryEntry::getPurpose() const -{ - return mPurpose; -} - - -const QString& HistoryEntry::getSubjectName() const -{ - return mSubjectName; -} - - -const QString& HistoryEntry::getSubjectUrl() const -{ - return mSubjectUrl; -} - - HistorySettings::HistorySettings() : AbstractSettings() - , mEnabled(true) - , mHistoryEntries() + , mStore(getStore()) { - connect(this, &HistorySettings::fireEnabledChanged, this, &AbstractSettings::fireSettingsChanged); - connect(this, &HistorySettings::fireHistoryEntriesChanged, this, &AbstractSettings::fireSettingsChanged); + mStore->beginGroup(SETTINGS_GROUP_NAME_CHRONIC()); } @@ -99,128 +36,100 @@ HistorySettings::~HistorySettings() } -void HistorySettings::load() -{ - auto settings = AbstractSettings::getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_CHRONIC); - - setEnabled(settings->value(SETTINGS_NAME_HISTORY_ENABLED, true).toBool()); - - const int itemCount = settings->beginReadArray(SETTINGS_NAME_HISTORY_ITEMS); - QVector items; - items.reserve(itemCount); - for (int i = 0; i < itemCount; ++i) - { - settings->setArrayIndex(i); - QString subjectName = settings->value(SETTINGS_NAME_CHRONIC_SUBJECTNAME, "").toString(); - QString subjectUrl = settings->value(SETTINGS_NAME_CHRONIC_SUBJECTURL, "").toString(); - QString usage = settings->value(SETTINGS_NAME_CHRONIC_USAGE, "").toString(); - 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 += HistoryEntry(subjectName, subjectUrl, usage, dateTime, termsOfUsage, requestData); - } - settings->endArray(); - setHistoryEntries(items); - - settings->endGroup(); -} - - -bool HistorySettings::isUnsaved() const -{ - HistorySettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - void HistorySettings::save() { - auto settings = AbstractSettings::getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_CHRONIC); - settings->remove(QString()); // remove the whole group first + mStore->sync(); +} - settings->setValue(SETTINGS_NAME_HISTORY_ENABLED, mEnabled); - settings->beginWriteArray(SETTINGS_NAME_HISTORY_ITEMS); - const int itemCount = mHistoryEntries.count(); +bool HistorySettings::isEnabled() const +{ + return mStore->value(SETTINGS_NAME_HISTORY_ENABLED(), true).toBool(); +} + + +void HistorySettings::setEnabled(bool pEnabled) +{ + if (isEnabled() != pEnabled) + { + mStore->setValue(SETTINGS_NAME_HISTORY_ENABLED(), pEnabled); + Q_EMIT fireEnabledChanged(pEnabled); + } +} + + +QVector HistorySettings::getHistoryInfos() const +{ + const int itemCount = mStore->beginReadArray(SETTINGS_NAME_HISTORY_ITEMS()); + + QVector historyInfos; + historyInfos.reserve(itemCount); for (int i = 0; i < itemCount; ++i) { - const HistoryEntry& item = mHistoryEntries.at(i); - settings->setArrayIndex(i); - settings->setValue(SETTINGS_NAME_CHRONIC_SUBJECTNAME, item.getSubjectName()); - settings->setValue(SETTINGS_NAME_CHRONIC_SUBJECTURL, item.getSubjectUrl()); - settings->setValue(SETTINGS_NAME_CHRONIC_USAGE, item.getPurpose()); - settings->setValue(SETTINGS_NAME_CHRONIC_DATETIME, item.getDateTime().toString(Qt::ISODate)); - settings->setValue(SETTINGS_NAME_CHRONIC_TOU, item.getTermOfUsage()); - settings->setValue(SETTINGS_NAME_CHRONIC_REQUESTED_DATA, item.getRequestedData()); + mStore->setArrayIndex(i); + const QString subjectName = mStore->value(SETTINGS_NAME_CHRONIC_SUBJECTNAME(), QString()).toString(); + const QString subjectUrl = mStore->value(SETTINGS_NAME_CHRONIC_SUBJECTURL(), QString()).toString(); + const QString usage = mStore->value(SETTINGS_NAME_CHRONIC_USAGE(), QString()).toString(); + const QDateTime dateTime = QDateTime::fromString(mStore->value(SETTINGS_NAME_CHRONIC_DATETIME(), QString()).toString(), Qt::ISODate); + const QString termsOfUsage = mStore->value(SETTINGS_NAME_CHRONIC_TOU(), QString()).toString(); + const QString requestData = mStore->value(SETTINGS_NAME_CHRONIC_REQUESTED_DATA(), QString()).toString(); + historyInfos += HistoryInfo(subjectName, subjectUrl, usage, dateTime, termsOfUsage, requestData); } - settings->endArray(); - settings->endGroup(); - settings->sync(); + mStore->endArray(); + return historyInfos; +} + + +void HistorySettings::setHistoryInfos(const QVector& pHistoryInfos) +{ + mStore->beginGroup(SETTINGS_NAME_HISTORY_ITEMS()); + mStore->remove(QString()); + mStore->endGroup(); + + mStore->beginWriteArray(SETTINGS_NAME_HISTORY_ITEMS()); + for (int i = 0; i < pHistoryInfos.size(); ++i) + { + const HistoryInfo& item = pHistoryInfos.at(i); + + mStore->setArrayIndex(i); + mStore->setValue(SETTINGS_NAME_CHRONIC_SUBJECTNAME(), item.getSubjectName()); + mStore->setValue(SETTINGS_NAME_CHRONIC_SUBJECTURL(), item.getSubjectUrl()); + mStore->setValue(SETTINGS_NAME_CHRONIC_USAGE(), item.getPurpose()); + mStore->setValue(SETTINGS_NAME_CHRONIC_DATETIME(), item.getDateTime().toString(Qt::ISODate)); + mStore->setValue(SETTINGS_NAME_CHRONIC_TOU(), item.getTermOfUsage()); + mStore->setValue(SETTINGS_NAME_CHRONIC_REQUESTED_DATA(), item.getRequestedData()); + } + mStore->endArray(); + + Q_EMIT fireHistoryInfosChanged(); +} + + +void HistorySettings::addHistoryInfo(const HistoryInfo& pHistoryInfo) +{ + if (appIsBackgroundService()) + { + qDebug() << "Running as a background service. Ignoring save request for history."; + return; + } + + auto historyInfos = getHistoryInfos(); + historyInfos.prepend(pHistoryInfo); + setHistoryInfos(historyInfos); } void HistorySettings::deleteSettings(const QDateTime& pLatestToKeep) { - QVector remainingItems; - for (const auto& item : qAsConst(mHistoryEntries)) + const auto historyInfos = getHistoryInfos(); + QVector remainingItems; + for (const auto& item : historyInfos) { if (!pLatestToKeep.isNull() && item.getDateTime() <= pLatestToKeep) { remainingItems += item; } } - setHistoryEntries(remainingItems); -} - - -bool HistorySettings::isEnabled() const -{ - return mEnabled; -} - - -void HistorySettings::setEnabled(bool pEnabled) -{ - if (mEnabled != pEnabled) - { - mEnabled = pEnabled; - Q_EMIT fireEnabledChanged(); - } -} - - -const QVector& HistorySettings::getHistoryEntries() const -{ - return mHistoryEntries; -} - - -void HistorySettings::setHistoryEntries(const QVector& pHistoryEntries) -{ - if (mHistoryEntries != pHistoryEntries) - { - mHistoryEntries = pHistoryEntries; - Q_EMIT fireHistoryEntriesChanged(); - } -} - - -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(); + setHistoryInfos(remainingItems); } diff --git a/src/settings/HistorySettings.h b/src/settings/HistorySettings.h index c3d5d62..3587097 100644 --- a/src/settings/HistorySettings.h +++ b/src/settings/HistorySettings.h @@ -1,92 +1,24 @@ /*! - * HistorySetting.h - * * \brief Represents history settings. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "AbstractSettings.h" -#include -#include -#include +#include "HistoryInfo.h" + #include + class test_HistorySettings; + namespace governikus { -/*! - * \brief Represents a history entry, i.e. information of a successfull authentication - */ -class HistoryEntry -{ - private: - static QDateTime roundToSeconds(const QDateTime& pDateTime); - - /*! - * The subject name contained in the certificate description - */ - QString mSubjectName; - - /*! - * The subject url contained in the certificate description - */ - QString mSubjectUrl; - - /*! - * The purpose contained in the certificate description - */ - QString mPurpose; - - /*! - * The authentication date and time - */ - QDateTime mDateTime; - - /*! - * The terms of usage contained in the certificate description - */ - QString mTermOfUsage; - - /*! - * The requested data fields during authentication - */ - QString mRequestedData; - - public: - HistoryEntry() - { - } - - - HistoryEntry(const QString& pSubjectName, const QString& pSubjectUrl, const QString& pUsage, const QDateTime& pDateTime, const QString& pTermOfUsage, const QString& pRequestedData); - - bool operator==(const HistoryEntry& pOther) const - { - return mSubjectName == pOther.mSubjectName && mSubjectUrl == pOther.mSubjectUrl && mPurpose == pOther.mPurpose - && mDateTime == pOther.mDateTime && mTermOfUsage == pOther.mTermOfUsage && mRequestedData == pOther.mRequestedData; - } - - - bool operator!=(const HistoryEntry& pOther) const - { - return !(*this == pOther); - } - - - const QString& getSubjectName() const; - const QString& getSubjectUrl() const; - const QString& getPurpose() const; - const QDateTime& getDateTime() const; - const QString& getTermOfUsage() const; - const QString& getRequestedData() const; -}; - class HistorySettings : public AbstractSettings { @@ -95,46 +27,26 @@ class HistorySettings friend class ::test_HistorySettings; private: - bool mEnabled; - QVector mHistoryEntries; + QSharedPointer mStore; HistorySettings(); public: - virtual ~HistorySettings(); - - virtual void load() override; - - virtual bool isUnsaved() const override; - + virtual ~HistorySettings() override; virtual void save() override; - void deleteSettings(const QDateTime& pLatestToKeep = QDateTime()); - bool isEnabled() const; void setEnabled(bool pEnabled); - const QVector& getHistoryEntries() const; - void setHistoryEntries(const QVector& pHistoryEntries); - void addHistoryEntry(const HistoryEntry& pHistoryEntry); + QVector getHistoryInfos() const; + void setHistoryInfos(const QVector& pHistoryInfos); + void addHistoryInfo(const HistoryInfo& pHistoryInfo); + void deleteSettings(const QDateTime& pLatestToKeep = QDateTime()); Q_SIGNALS: - void fireEnabledChanged(); - void fireHistoryEntriesChanged(); + void fireEnabledChanged(bool pValue); + void fireHistoryInfosChanged(); }; -inline bool operator==(const HistorySettings& pLeft, const HistorySettings& pRight) -{ - return &pLeft == &pRight || ( - pLeft.isEnabled() == pRight.isEnabled() && - pLeft.getHistoryEntries() == pRight.getHistoryEntries()); -} - - -inline bool operator!=(const HistorySettings& pLeft, const HistorySettings& pRight) -{ - return !(pLeft == pRight); -} - } /* namespace governikus */ diff --git a/src/settings/KeyPair.cpp b/src/settings/KeyPair.cpp new file mode 100644 index 0000000..62acb54 --- /dev/null +++ b/src/settings/KeyPair.cpp @@ -0,0 +1,186 @@ +/* + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "KeyPair.h" + +#include "Randomizer.h" + +#include +#include +#include + +#include +#include +#include + +using namespace governikus; + +namespace +{ +struct OpenSslCustomDeleter +{ + static inline void cleanup(EVP_PKEY* pData) + { + EVP_PKEY_free(pData); + } + + + static inline void cleanup(BIGNUM* pData) + { + BN_free(pData); + } + + + static inline void cleanup(RSA* pData) + { + RSA_free(pData); + } + + + static inline void cleanup(BIO* pData) + { + BIO_free(pData); + } + + + static inline void cleanup(X509_NAME* pData) + { + X509_NAME_free(pData); + } + + +}; +} + +KeyPair::KeyPair(const QSslKey& pKey, const QSslCertificate& pCert) + : mKey(pKey) + , mCertificate(pCert) +{ +} + + +KeyPair KeyPair::generate() +{ + if (!Randomizer::getInstance().isSecureRandom()) + { + qCritical() << "Cannot get enough entropy"; + return KeyPair(); + } + + auto pkey = createKey(); + if (pkey) + { + auto cert = createCertificate(pkey); + if (cert) + { + return KeyPair(QSslKey(Qt::HANDLE(pkey), QSsl::PrivateKey), QSslCertificate(rewriteCertificate(cert.data()))); + } + else + { + OpenSslCustomDeleter::cleanup(pkey); + } + } + + return KeyPair(); +} + + +const QSslKey& KeyPair::getKey() const +{ + return mKey; +} + + +const QSslCertificate& KeyPair::getCertificate() const +{ + return mCertificate; +} + + +EVP_PKEY* KeyPair::createKey() +{ + QScopedPointer pkey(EVP_PKEY_new()); + QScopedPointer rsa(RSA_new()); + QScopedPointer exponent(BN_new()); + + if (pkey.isNull() || rsa.isNull() || exponent.isNull()) + { + qCritical() << "Cannot create EVP_PKEY/RSA/BIGNUM structure"; + return nullptr; + } + + BN_set_word(exponent.data(), RSA_F4); + if (!RSA_generate_key_ex(rsa.data(), 2048, exponent.data(), nullptr)) + { + qCritical() << "Cannot generate rsa key"; + return nullptr; + } + + if (!EVP_PKEY_assign(pkey.data(), EVP_PKEY_RSA, rsa.data())) + { + qCritical() << "Cannot assign rsa key"; + return nullptr; + } + + rsa.take(); // rsa will be managed by pkey! + return pkey.take(); +} + + +QSharedPointer KeyPair::createCertificate(EVP_PKEY* pPkey) +{ + QSharedPointer x509(X509_new(), &X509_free); + if (x509.isNull()) + { + qCritical() << "Cannot create X509 structure"; + return nullptr; + } + + auto& randomizer = Randomizer::getInstance().getGenerator(); + std::uniform_int_distribution uni_long(1); + std::uniform_int_distribution uni_qulonglong(1); + + ASN1_INTEGER_set(X509_get_serialNumber(x509.data()), uni_long(randomizer)); + // see: https://tools.ietf.org/html/rfc5280#section-4.1.2.5 + ASN1_TIME_set_string(X509_get_notBefore(x509.data()), "19700101000000Z"); + ASN1_TIME_set_string(X509_get_notAfter(x509.data()), "99991231235959Z"); + X509_set_pubkey(x509.data(), pPkey); + + auto randomSerial = QByteArray::number(uni_qulonglong(randomizer)); + QScopedPointer name(X509_NAME_dup(X509_get_subject_name(x509.data()))); + X509_NAME_add_entry_by_txt(name.data(), "CN", MBSTRING_ASC, + reinterpret_cast(QCoreApplication::applicationName().toLatin1().constData()), -1, -1, 0); + X509_NAME_add_entry_by_txt(name.data(), "serialNumber", MBSTRING_ASC, + reinterpret_cast(randomSerial.constData()), -1, -1, 0); + X509_set_subject_name(x509.data(), name.data()); + X509_set_issuer_name(x509.data(), name.data()); + + if (!X509_sign(x509.data(), pPkey, EVP_sha256())) + { + qCritical() << "Cannot sign certificate"; + return nullptr; + } + + return x509; +} + + +QByteArray KeyPair::rewriteCertificate(X509* pX509) +{ + QScopedPointer bio(BIO_new(BIO_s_mem())); + PEM_write_bio_X509(bio.data(), pX509); + char* data = nullptr; + + // See macro BIO_get_mem_data(bio, &data); if BIO_ctrl fails. + // We do not use this to avoid -Wold-style-cast warning + const long len = BIO_ctrl(bio.data(), BIO_CTRL_INFO, 0, &data); + return QByteArray(data, static_cast(len)); +} + + +bool KeyPair::isValid() const +{ + return !mKey.isNull() && !mCertificate.isNull(); +} diff --git a/src/settings/KeyPair.h b/src/settings/KeyPair.h new file mode 100644 index 0000000..24f8995 --- /dev/null +++ b/src/settings/KeyPair.h @@ -0,0 +1,42 @@ +/* + * \brief Generates a new private/public key with an X509 certificate. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace governikus +{ + +class KeyPair +{ + private: + const QSslKey mKey; + const QSslCertificate mCertificate; + + KeyPair() = default; + KeyPair(const QSslKey& pKey, const QSslCertificate& pCert); + + static QByteArray rewriteCertificate(X509* pX509); + static QSharedPointer createCertificate(EVP_PKEY* pPkey); + static EVP_PKEY* createKey(); + + public: + static KeyPair generate(); + + const QSslKey& getKey() const; + const QSslCertificate& getCertificate() const; + bool isValid() const; +}; + + +} /* namespace governikus */ diff --git a/src/settings/LanguageString.cpp b/src/settings/LanguageString.cpp deleted file mode 100644 index 161dff1..0000000 --- a/src/settings/LanguageString.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "LanguageString.h" - -#include -#include - -using namespace governikus; - - -LanguageString::LanguageString(const QJsonValue& pJson) -{ - if (!pJson.isObject()) - { - return; - } - - const QJsonObject& object = pJson.toObject(); - for (const QString& key : object.keys()) - { - mStrings[key] = object[key].toString(); - } -} - - -LanguageString::LanguageString(const QMap& pInput) - : mStrings(pInput) -{ -} - - -LanguageString::LanguageString(const QString& pString, const QLocale& pLocale) -{ - mStrings[pLocale.name()] = pString; -} - - -QString LanguageString::toString() const -{ - QString result = toString(LanguageLoader::getInstance().getUsedLocale()); - if (!result.isEmpty()) - { - return result; - } - - result = toString(LanguageLoader::getInstance().getFallbackLanguage()); - if (!result.isEmpty()) - { - return result; - } - - return mStrings[QString()]; -} - - -QString LanguageString::toString(const QLocale& pLocale) const -{ - QString result = mStrings[pLocale.name()]; - if (!result.isEmpty()) - { - return result; - } - - result = mStrings[pLocale.bcp47Name()]; - if (!result.isEmpty()) - { - return result; - } - - return QString(); -} - - -bool LanguageString::isEmpty() const -{ - return mStrings.isEmpty(); -} - - -QMap::const_iterator LanguageString::begin() const -{ - return mStrings.begin(); -} - - -QMap::const_iterator LanguageString::end() const -{ - return mStrings.end(); -} - - -LanguageString::operator QString() const -{ - return toString(); -} diff --git a/src/settings/LanguageString.h b/src/settings/LanguageString.h deleted file mode 100644 index 1862082..0000000 --- a/src/settings/LanguageString.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "LanguageLoader.h" - -#include -#include -#include - - -namespace governikus -{ - -class LanguageString -{ - friend inline bool operator==(const LanguageString& pLeft, const LanguageString& pRight); - - private: - QMap mStrings; - - QString toString(const QLocale& pLocale) const; - - public: - LanguageString(const QJsonValue& pJson); - LanguageString(const QMap& pInput); - LanguageString(const QString& pString, const QLocale& pLocale = LanguageLoader::getInstance().getUsedLocale()); - - - bool isEmpty() const; - QString toString() const; - operator QString() const; - - QMap::const_iterator begin() const; - QMap::const_iterator end() const; -}; - -inline bool operator==(const LanguageString& pLeft, const LanguageString& pRight) -{ - return pLeft.mStrings == pRight.mStrings; -} - - -} /* namespace governikus */ diff --git a/src/settings/PreVerificationSettings.cpp b/src/settings/PreVerificationSettings.cpp index 46cc939..355ed97 100644 --- a/src/settings/PreVerificationSettings.cpp +++ b/src/settings/PreVerificationSettings.cpp @@ -1,23 +1,40 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PreVerificationSettings.h" using namespace governikus; -// names for settings groups/keys -const QLatin1String SETTINGS_GROUP_NAME_PREVERIFICATION("preverification"); -const QLatin1String SETTINGS_NAME_ENABLED("enabled"); -const QLatin1String SETTINGS_NAME_LINKCERTIFICATES("linkcertificates"); -const QLatin1String SETTINGS_NAME_LINKCERTIFICATE("linkcertificate"); - +namespace +{ +SETTINGS_NAME(SETTINGS_GROUP_NAME_PREVERIFICATION, "preverification") +SETTINGS_NAME(SETTINGS_NAME_ENABLED, "enabled") +SETTINGS_NAME(SETTINGS_NAME_LINKCERTIFICATES, "linkcertificates") +SETTINGS_NAME(SETTINGS_NAME_LINKCERTIFICATE, "linkcertificate") +} PreVerificationSettings::PreVerificationSettings() : AbstractSettings() - , mLinkCertificates() - , mEnabled(true) + , mStore(getStore()) { + mStore->beginGroup(SETTINGS_GROUP_NAME_PREVERIFICATION()); +} + + +void PreVerificationSettings::updateLinkCertificates(const QByteArrayList& pLinkCertificates) +{ + mStore->beginGroup(SETTINGS_NAME_LINKCERTIFICATES()); + mStore->remove(QString()); + mStore->endGroup(); + + mStore->beginWriteArray(SETTINGS_NAME_LINKCERTIFICATES()); + for (int i = 0; i < pLinkCertificates.size(); ++i) + { + mStore->setArrayIndex(i); + mStore->setValue(SETTINGS_NAME_LINKCERTIFICATE(), pLinkCertificates.at(i)); + } + mStore->endArray(); } @@ -26,92 +43,57 @@ PreVerificationSettings::~PreVerificationSettings() } -void PreVerificationSettings::load() -{ - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_PREVERIFICATION); - mEnabled = settings->value(SETTINGS_NAME_ENABLED, mEnabled).toBool(); - const int itemCount = settings->beginReadArray(SETTINGS_NAME_LINKCERTIFICATES); - - QByteArrayList linkCertificates; - linkCertificates.reserve(itemCount); - for (int i = 0; i < itemCount; ++i) - { - settings->setArrayIndex(i); - linkCertificates += settings->value(SETTINGS_NAME_LINKCERTIFICATE).toByteArray(); - } - mLinkCertificates = linkCertificates; - - settings->endArray(); - settings->endGroup(); -} - - -bool PreVerificationSettings::isUnsaved() const -{ - PreVerificationSettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - void PreVerificationSettings::save() { - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_PREVERIFICATION); - settings->remove(QString()); // remove the whole group first - settings->setValue(SETTINGS_NAME_ENABLED, mEnabled); - settings->beginWriteArray(SETTINGS_NAME_LINKCERTIFICATES); - - for (int i = 0; i < mLinkCertificates.size(); ++i) - { - settings->setArrayIndex(i); - settings->setValue(SETTINGS_NAME_LINKCERTIFICATE, mLinkCertificates.at(i)); - } - - settings->endArray(); - settings->endGroup(); - - settings->sync(); + mStore->sync(); } bool PreVerificationSettings::isEnabled() const { - return mEnabled; + return mStore->value(SETTINGS_NAME_ENABLED(), true).toBool(); } void PreVerificationSettings::setEnabled(bool pEnabled) { - mEnabled = pEnabled; + mStore->setValue(SETTINGS_NAME_ENABLED(), pEnabled); } -const QByteArrayList& PreVerificationSettings::getLinkCertificates() const +QByteArrayList PreVerificationSettings::getLinkCertificates() const { - return mLinkCertificates; -} + const int itemCount = mStore->beginReadArray(SETTINGS_NAME_LINKCERTIFICATES()); - -bool PreVerificationSettings::removeLinkCertificate(const QByteArray& pCert) -{ - bool changed = mLinkCertificates.removeAll(pCert); - if (changed) + QByteArrayList linkCertificates; + linkCertificates.reserve(itemCount); + for (int i = 0; i < itemCount; ++i) { - Q_EMIT fireSettingsChanged(); + mStore->setArrayIndex(i); + linkCertificates += mStore->value(SETTINGS_NAME_LINKCERTIFICATE()).toByteArray(); } - return changed; + + mStore->endArray(); + return linkCertificates; } -bool PreVerificationSettings::addLinkCertificate(const QByteArray& pCert) +void PreVerificationSettings::removeLinkCertificate(const QByteArray& pCert) { - if (mLinkCertificates.contains(pCert)) + auto linkCertificates = getLinkCertificates(); + if (linkCertificates.removeAll(pCert) > 0) { - return false; + updateLinkCertificates(linkCertificates); + } +} + + +void PreVerificationSettings::addLinkCertificate(const QByteArray& pCert) +{ + auto linkCertificates = getLinkCertificates(); + if (!linkCertificates.contains(pCert)) + { + linkCertificates += pCert; + updateLinkCertificates(linkCertificates); } - mLinkCertificates += pCert; - Q_EMIT fireSettingsChanged(); - return true; } diff --git a/src/settings/PreVerificationSettings.h b/src/settings/PreVerificationSettings.h index 4ca94f3..dc88851 100644 --- a/src/settings/PreVerificationSettings.h +++ b/src/settings/PreVerificationSettings.h @@ -1,7 +1,7 @@ /*! * \brief Settings to handle PreVerification and the corresponding linked certificates. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -26,37 +26,21 @@ class PreVerificationSettings friend class ::test_StatePreVerification; private: - QByteArrayList mLinkCertificates; - bool mEnabled; + QSharedPointer mStore; PreVerificationSettings(); + void updateLinkCertificates(const QByteArrayList& pLinkCertificates); public: - virtual ~PreVerificationSettings(); - - virtual void load() override; - virtual bool isUnsaved() const override; + virtual ~PreVerificationSettings() override; virtual void save() override; bool isEnabled() const; void setEnabled(bool pEnabled); - const QByteArrayList& getLinkCertificates() const; - bool removeLinkCertificate(const QByteArray& pCert); - bool addLinkCertificate(const QByteArray& pCert); + QByteArrayList getLinkCertificates() const; + void removeLinkCertificate(const QByteArray& pCert); + void addLinkCertificate(const QByteArray& pCert); }; -inline bool operator==(const PreVerificationSettings& pLeft, const PreVerificationSettings& pRight) -{ - return &pLeft == &pRight || - (pLeft.isEnabled() == pRight.isEnabled() && - containsAllEntries(pLeft.getLinkCertificates(), pRight.getLinkCertificates())); -} - - -inline bool operator!=(const PreVerificationSettings& pLeft, const PreVerificationSettings& pRight) -{ - return !(pLeft == pRight); -} - } /* namespace governikus */ diff --git a/src/settings/ProviderSettings.cpp b/src/settings/ProviderSettings.cpp deleted file mode 100644 index 2feec89..0000000 --- a/src/settings/ProviderSettings.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - - -#include "ProviderSettings.h" - -#include "AppSettings.h" -#include "VersionNumber.h" - -#include -#include - -using namespace governikus; - - -const QLatin1String SETTINGS_GROUP_NAME_PROVIDERS("providers"); -const QLatin1String SETTINGS_DEFAULT_NAME("default"); -const QLatin1String SETTINGS_NAME_ISSUEDATE("issueDate"); -const QLatin1String SETTINGS_NAME_PROVIDERS("list"); -const QLatin1String SETTINGS_NAME_SHORTNAME("shortName"); -const QLatin1String SETTINGS_NAME_LONGNAME("longName"); -const QLatin1String SETTINGS_NAME_SHORTDESCRIPTION("shortDescription"); -const QLatin1String SETTINGS_NAME_LONGDESCRIPTION("longDescription"); -const QLatin1String SETTINGS_NAME_ADDRESS("address"); -const QLatin1String SETTINGS_NAME_HOMEPAGE("homepage"); -const QLatin1String SETTINGS_NAME_CATEGORY("category"); -const QLatin1String SETTINGS_NAME_PHONE("phone"); -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, - const LanguageString& pLongName, - const LanguageString& pShortDescription, - const LanguageString& pLongDescription, - const QString& pAddress, - const QString& pHomepage, - const QString& pCategory, - const QString& pPhone, - const QString& pEmail, - const QString& pPostalAddress, - const QString& pIcon, - const QString& pImage, - const QString& pTcTokenUrl, - const QString& pClientUrl, - const QStringList& pSubjectUrls) - : mShortName(pShortName) - , mLongName(pLongName) - , mShortDescription(pShortDescription) - , mLongDescription(pLongDescription) - , mAddress(pAddress) - , mHomepage(pHomepage) - , mCategory(pCategory) - , mPhone(pPhone) - , mEmail(pEmail) - , mPostalAddress(pPostalAddress) - , mIcon(pIcon) - , mImage(pImage) - , mLocalIconUrl() - , mLocalImageUrl() - , mTcTokenUrl(pTcTokenUrl) - , mClientUrl(pClientUrl) - , mSubjectUrls(pSubjectUrls) -{ -} - - -const LanguageString& Provider::getShortName() const -{ - return mShortName; -} - - -const LanguageString& Provider::getLongName() const -{ - return mLongName; -} - - -const LanguageString& Provider::getShortDescription() const -{ - return mShortDescription; -} - - -const LanguageString& Provider::getLongDescription() const -{ - return mLongDescription; -} - - -const QString& Provider::getAddress() const -{ - return mAddress; -} - - -QString Provider::getAddressDomain() const -{ - return QUrl::fromUserInput(mAddress).host(); -} - - -const QString& Provider::getHomepage() const -{ - return mHomepage; -} - - -QString Provider::getHomepageBase() const -{ - return QUrl::fromUserInput(mHomepage).host(); -} - - -const QString& Provider::getCategory() const -{ - return mCategory; -} - - -const QString& Provider::getPhone() const -{ - return mPhone; -} - - -const QString& Provider::getEMail() const -{ - return mEmail; -} - - -const QString& Provider::getPostalAddress() const -{ - return mPostalAddress; -} - - -const QString& Provider::getIcon() const -{ - return mIcon; -} - - -const QString& Provider::getImage() const -{ - return mImage; -} - - -const QString& Provider::getIconUrl() const -{ - return mLocalIconUrl; -} - - -const QString& Provider::getImageUrl() const -{ - return mLocalImageUrl; -} - - -const QString& Provider::getTcTokenUrl() const -{ - return mTcTokenUrl; -} - - -const QString& Provider::getClientUrl() const -{ - return mClientUrl; -} - - -const QStringList& Provider::getSubjectUrls() const -{ - return mSubjectUrls; -} - - -void Provider::setTcTokenUrl(const QString& pTcTokenUrl) -{ - mTcTokenUrl = pTcTokenUrl; -} - - -void Provider::applyMap(const QMap& pMap) -{ - if (!mIcon.isEmpty()) - { - mLocalIconUrl = pMap.value(mIcon, QString()); - } - - if (!mImage.isEmpty()) - { - mLocalImageUrl = pMap.value(mImage, QString()); - } -} - - -void ProviderSettings::applyMap() -{ - for (Provider& provider : mProviders) - { - provider.applyMap(mIconMap); - } -} - - -ProviderSettings::ProviderSettings() - : AbstractSettings() - , 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); -} - - -QStringList ProviderSettings::getRequiredIcons() const -{ - QSet icons; - - for (const Provider& provider : mProviders) - { - // Request icons / images whose names are not empty. - const QString icon = provider.getIcon(); - const QString image = provider.getImage(); - if (!icon.isEmpty()) - { - icons += icon; - } - - if (!image.isEmpty()) - { - icons += image; - } - } - - return icons.toList(); -} - - -#ifndef QT_NO_DEBUG - - -ProviderSettings::ProviderSettings(const QDateTime& pIssueDate, const QVector& pProviders) - : AbstractSettings() - , mIssueDate(pIssueDate) - , mProviders(pProviders) - , mIconMap() - , mCallCosts() -{ -} - - -#endif - - -ProviderSettings::~ProviderSettings() -{ -} - - -void ProviderSettings::load() -{ - auto settings = getStore(); - - static const VersionNumber FIRST_JSON_VERSION = VersionNumber(QStringLiteral("1.9.0")); - const QString& settingsVersionString = AppSettings::getInstance().getGeneralSettings().getPersistentSettingsVersion(); - if (!settingsVersionString.isEmpty() && VersionNumber(settingsVersionString) < FIRST_JSON_VERSION) - { - settings->beginGroup(SETTINGS_GROUP_NAME_PROVIDERS); - settings->remove(QString()); - settings->endGroup(); - - return; - } - - settings->beginGroup(SETTINGS_GROUP_NAME_PROVIDERS); - const int listSize = settings->beginReadArray(SETTINGS_NAME_PROVIDERS); - QVector providers; - providers.reserve(listSize); - for (int i = 0; i < listSize; ++i) - { - settings->setArrayIndex(i); - const LanguageString shortName = load(settings, SETTINGS_NAME_SHORTNAME); - const LanguageString longName = load(settings, SETTINGS_NAME_LONGNAME); - const LanguageString shortDescription = load(settings, SETTINGS_NAME_SHORTDESCRIPTION); - const LanguageString longDescription = load(settings, SETTINGS_NAME_LONGDESCRIPTION); - const QString address = getSettingsValue(settings, SETTINGS_NAME_ADDRESS).toString(); - const QString homepage = getSettingsValue(settings, SETTINGS_NAME_HOMEPAGE).toString(); - const QString category = getSettingsValue(settings, SETTINGS_NAME_CATEGORY).toString(); - const QString phone = getSettingsValue(settings, SETTINGS_NAME_PHONE).toString(); - const QString email = getSettingsValue(settings, SETTINGS_NAME_EMAIL).toString(); - 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, - longDescription, - address, - homepage, - category, - phone, - email, - postalAddress, - icon, - 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(); -} - - -bool ProviderSettings::isUnsaved() const -{ - ProviderSettings oldSettings; - oldSettings.load(); - return oldSettings != *this; -} - - -void ProviderSettings::save(QSharedPointer& pSettings, const QString& pGroupName, const LanguageString& pLanguageString) -{ - pSettings->beginGroup(pGroupName); - for (auto i = pLanguageString.begin(); i != pLanguageString.end(); i++) - { - QString key = i.key(); - if (key.isEmpty()) - { - key = SETTINGS_DEFAULT_NAME; // QSettings ignores empty keys - } - - pSettings->setValue(key, i.value()); - } - pSettings->endGroup(); -} - - -LanguageString ProviderSettings::load(const QSharedPointer& pSettings, const QString& pGroupName) -{ - pSettings->beginGroup(pGroupName); - const QStringList& keys = pSettings->childKeys(); - QMap map; - for (QString key : keys) - { - const QString& value = pSettings->value(key).toString(); - if (key == SETTINGS_DEFAULT_NAME) - { - key = QString(); - } - map[key] = value; - } - pSettings->endGroup(); - - return LanguageString(map); -} - - -void ProviderSettings::save() -{ - auto settings = getStore(); - settings->beginGroup(SETTINGS_GROUP_NAME_PROVIDERS); - settings->remove(QString()); // remove the whole group first - - settings->beginWriteArray(SETTINGS_NAME_PROVIDERS); - for (int i = 0; i < mProviders.size(); ++i) - { - settings->setArrayIndex(i); - auto& provider = mProviders.at(i); - - save(settings, SETTINGS_NAME_SHORTNAME, provider.getShortName()); - save(settings, SETTINGS_NAME_LONGNAME, provider.getLongName()); - save(settings, SETTINGS_NAME_SHORTDESCRIPTION, provider.getShortDescription()); - save(settings, SETTINGS_NAME_LONGDESCRIPTION, provider.getLongDescription()); - settings->setValue(SETTINGS_NAME_ADDRESS, provider.getAddress()); - settings->setValue(SETTINGS_NAME_HOMEPAGE, provider.getHomepage()); - settings->setValue(SETTINGS_NAME_CATEGORY, provider.getCategory()); - settings->setValue(SETTINGS_NAME_PHONE, provider.getPhone()); - settings->setValue(SETTINGS_NAME_EMAIL, provider.getEMail()); - 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(); - settings->sync(); -} - - -void ProviderSettings::update(const AbstractSettings& pOther) -{ - const ProviderSettings* const other = qobject_cast(&pOther); - if (other != nullptr) - { - mIssueDate = other->getIssueDate(); - setProviders(other->getProviders()); - setCallCosts(other->getCallCosts()); - } -} - - -const QDateTime& ProviderSettings::getIssueDate() const -{ - return mIssueDate; -} - - -void ProviderSettings::setIssueDate(const QDateTime& pIssueDate) -{ - if (mIssueDate != pIssueDate) - { - mIssueDate = pIssueDate; - Q_EMIT fireIssueDateChanged(); - } -} - - -const QVector& ProviderSettings::getProviders() const -{ - return mProviders; -} - - -void ProviderSettings::setProviders(const QVector& pProviders) -{ - if (mProviders != pProviders) - { - mProviders = pProviders; - - Q_EMIT fireProvidersChanged(); - - Q_EMIT fireRequiredIcons(getRequiredIcons()); - } -} - - -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()); -} - - -void ProviderSettings::onIconMapChanged(const QMap& pIconMap) -{ - if (mIconMap != pIconMap) - { - mIconMap = pIconMap; - applyMap(); - - Q_EMIT fireProvidersChanged(); - } -} diff --git a/src/settings/ProviderSettings.h b/src/settings/ProviderSettings.h deleted file mode 100644 index c108c9e..0000000 --- a/src/settings/ProviderSettings.h +++ /dev/null @@ -1,197 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractSettings.h" -#include "CallCost.h" -#include "LanguageString.h" - -#include -#include -#include - - -class test_ProviderSettings; - - -namespace governikus -{ - - -class Provider -{ - friend bool operator==(const Provider& pLeft, const Provider& pRight); - - private: - LanguageString mShortName; - LanguageString mLongName; - LanguageString mShortDescription; - LanguageString mLongDescription; - QString mAddress; - QString mHomepage; - QString mCategory; - QString mPhone; - QString mEmail; - QString mPostalAddress; - QString mIcon; - QString mImage; - QString mLocalIconUrl; - QString mLocalImageUrl; - QString mTcTokenUrl; - QString mClientUrl; - QStringList mSubjectUrls; - - public: - Provider(const LanguageString& pShortName = QString(), - const LanguageString& pLongName = QString(), - const LanguageString& pShortDescription = QString(), - const LanguageString& pLongDescription = QString(), - const QString& pAddress = QString(), - const QString& pHomepage = QString(), - const QString& pCategory = QString(), - const QString& pPhone = QString(), - const QString& pEmail = QString(), - const QString& pPostalAddress = QString(), - const QString& pIcon = QString(), - const QString& pImage = QString(), - const QString& pTcTokenUrl = QString(), - const QString& pClientUrl = QString(), - const QStringList& pSubjectUrls = QStringList() - ); - - const LanguageString& getShortName() const; - const LanguageString& getLongName() const; - const LanguageString& getShortDescription() const; - const LanguageString& getLongDescription() const; - const QString& getAddress() const; - QString getAddressDomain() const; - const QString& getHomepage() const; - QString getHomepageBase() const; - const QString& getCategory() const; - const QString& getPhone() const; - const QString& getEMail() const; - const QString& getPostalAddress() const; - const QString& getIcon() const; - const QString& getImage() const; - const QString& getIconUrl() const; - const QString& getImageUrl() const; - const QString& getTcTokenUrl() const; - const QString& getClientUrl() const; - const QStringList& getSubjectUrls() const; - - void setTcTokenUrl(const QString& pTcTokenUrl); - - // Use pMap to update icon and image urls in this provider. - void applyMap(const QMap& pMap); -}; - -inline bool operator==(const Provider& pLeft, const Provider& pRight) -{ - return &pLeft == &pRight || ( - pLeft.mShortName == pRight.mShortName && - pLeft.mLongName == pRight.mLongName && - pLeft.mShortDescription == pRight.mShortDescription && - pLeft.mLongDescription == pRight.mLongDescription && - pLeft.mAddress == pRight.mAddress && - pLeft.mHomepage == pRight.mHomepage && - pLeft.mCategory == pRight.mCategory && - pLeft.mPhone == pRight.mPhone && - pLeft.mEmail == pRight.mEmail && - pLeft.mPostalAddress == pRight.mPostalAddress && - pLeft.mIcon == pRight.mIcon && - pLeft.mImage == pRight.mImage && - pLeft.mTcTokenUrl == pRight.mTcTokenUrl && - pLeft.mClientUrl == pRight.mClientUrl); - - // since those variable won't be saved we don't need to check! - // pLeft.mLocalIconUrl == pRight.mLocalIconUrl && - // pLeft.mLocalImageUrl == pRight.mLocalImageUrl -} - - -class ProviderSettings - : public AbstractSettings -{ - Q_OBJECT - - 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(); - - 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(); - - virtual void load() override; - - virtual bool isUnsaved() const override; - - virtual void save() override; - - virtual void update(const AbstractSettings& pOther) override; - - const QDateTime& getIssueDate() const; - void setIssueDate(const QDateTime& pIssueDate); - - 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: - void onIconMapChanged(const QMap& pIconMap); - - Q_SIGNALS: - void fireIssueDateChanged(); - void fireProvidersChanged(); - void fireRequiredIcons(const QStringList& pIcons); - void fireCallCostsChanged(); -}; - -inline bool operator==(const ProviderSettings& pLeft, const ProviderSettings& pRight) -{ - return &pLeft == &pRight || ( - pLeft.mIssueDate == pRight.mIssueDate && - pLeft.mProviders == pRight.mProviders && - pLeft.mIconMap == pRight.mIconMap && - pLeft.mCallCosts == pRight.mCallCosts); -} - - -inline bool operator!=(const ProviderSettings& pLeft, const ProviderSettings& pRight) -{ - return !(pLeft == pRight); -} - - -} /* namespace governikus */ diff --git a/src/settings/RemoteReaderSettings.cpp b/src/settings/RemoteReaderSettings.cpp deleted file mode 100644 index 96f18ec..0000000 --- a/src/settings/RemoteReaderSettings.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 7a913fe..0000000 --- a/src/settings/RemoteReaderSettings.h +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * \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/RemoteServiceSettings.cpp b/src/settings/RemoteServiceSettings.cpp new file mode 100644 index 0000000..ccb8d4f --- /dev/null +++ b/src/settings/RemoteServiceSettings.cpp @@ -0,0 +1,369 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteServiceSettings.h" + +#include "DeviceInfo.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + +namespace +{ +SETTINGS_NAME(SETTINGS_GROUP_NAME_REMOTEREADER, "remotereader") +SETTINGS_NAME(SETTINGS_NAME_DEVICE_NAME, "serverName") +SETTINGS_NAME(SETTINGS_NAME_PIN_PAD_MODE, "pinPadMode") +SETTINGS_NAME(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES, "trustedCertificates") +SETTINGS_NAME(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM, "certificate") +SETTINGS_NAME(SETTINGS_NAME_TRUSTED_REMOTE_INFO, "trustedRemoteInfo") +SETTINGS_NAME(SETTINGS_NAME_KEY, "key") +SETTINGS_NAME(SETTINGS_NAME_CERTIFICATE, "certificate") +} + + +QString RemoteServiceSettings::generateFingerprint(const QSslCertificate& pCert) +{ + return pCert.isNull() ? QString() : QString::fromLatin1(pCert.digest(QCryptographicHash::Sha256).toHex()); +} + + +RemoteServiceSettings::RemoteServiceSettings() + : AbstractSettings() + , mStore(getStore()) +{ + mStore->beginGroup(SETTINGS_GROUP_NAME_REMOTEREADER()); + + if (!mStore->contains(SETTINGS_NAME_DEVICE_NAME())) + { + setServerName(QString()); + } +} + + +RemoteServiceSettings::~RemoteServiceSettings() +{ +} + + +void RemoteServiceSettings::save() +{ + mStore->sync(); +} + + +QString RemoteServiceSettings::getDefaultServerName() +{ + QString name = DeviceInfo::getName(); + if (name.isEmpty()) + { + return tr("Remote Reader"); + } + + return name; +} + + +QString RemoteServiceSettings::getServerName() const +{ + return mStore->value(SETTINGS_NAME_DEVICE_NAME(), QString()).toString(); +} + + +void RemoteServiceSettings::setServerName(const QString& pName) +{ + if (pName.isEmpty()) + { + mStore->setValue(SETTINGS_NAME_DEVICE_NAME(), getDefaultServerName()); + return; + } + + mStore->setValue(SETTINGS_NAME_DEVICE_NAME(), pName); +} + + +bool RemoteServiceSettings::getPinPadMode() const +{ + return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), false).toBool(); +} + + +void RemoteServiceSettings::setPinPadMode(bool pPinPadMode) +{ + mStore->setValue(SETTINGS_NAME_PIN_PAD_MODE(), pPinPadMode); +} + + +QList RemoteServiceSettings::getTrustedCertificates() const +{ + const int itemCount = mStore->beginReadArray(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES()); + + QList certificates; + certificates.reserve(itemCount); + for (int i = 0; i < itemCount; ++i) + { + mStore->setArrayIndex(i); + const auto& cert = mStore->value(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM(), QByteArray()).toByteArray(); + certificates << QSslCertificate(cert); + } + + mStore->endArray(); + return certificates; +} + + +void RemoteServiceSettings::setUniqueTrustedCertificates(const QSet& pCertificates) +{ + mStore->beginGroup(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES()); + mStore->remove(QString()); + mStore->endGroup(); + + mStore->beginWriteArray(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES()); + int i = 0; + for (const auto& cert : pCertificates) + { + mStore->setArrayIndex(i++); + mStore->setValue(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM(), cert.toPem()); + } + mStore->endArray(); + + syncRemoteInfos(pCertificates); + Q_EMIT fireTrustedCertificatesChanged(); +} + + +void RemoteServiceSettings::setTrustedCertificates(const QList& pCertificates) +{ + setUniqueTrustedCertificates(pCertificates.toSet()); // remove duplicates +} + + +void RemoteServiceSettings::addTrustedCertificate(const QSslCertificate& pCertificate) +{ + auto certs = getTrustedCertificates(); + certs << pCertificate; + setTrustedCertificates(certs); +} + + +void RemoteServiceSettings::removeTrustedCertificate(const QSslCertificate& pCertificate) +{ + auto certs = getTrustedCertificates(); + certs.removeAll(pCertificate); + setTrustedCertificates(certs); +} + + +void RemoteServiceSettings::removeTrustedCertificate(const QString& pFingerprint) +{ + const auto& certs = getTrustedCertificates(); + for (const auto& cert : certs) + { + if (generateFingerprint(cert) == pFingerprint) + { + removeTrustedCertificate(cert); + return; + } + } +} + + +QSslCertificate RemoteServiceSettings::getCertificate() const +{ + return QSslCertificate(mStore->value(SETTINGS_NAME_CERTIFICATE(), QByteArray()).toByteArray()); +} + + +void RemoteServiceSettings::setCertificate(const QSslCertificate& pCert) const +{ + mStore->setValue(SETTINGS_NAME_CERTIFICATE(), pCert.toPem()); +} + + +QSslKey RemoteServiceSettings::getKey() const +{ + const auto& data = mStore->value(SETTINGS_NAME_KEY(), QByteArray()).toByteArray(); + if (data.contains("BEGIN RSA PRIVATE KEY")) + { + return QSslKey(data, QSsl::Rsa); + } + + return QSslKey(); +} + + +void RemoteServiceSettings::setKey(const QSslKey& pKey) const +{ + mStore->setValue(SETTINGS_NAME_KEY(), pKey.toPem()); +} + + +RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QSslCertificate& pCertificate) const +{ + return getRemoteInfo(generateFingerprint(pCertificate)); +} + + +RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QString& pFingerprint) const +{ + const auto& infos = getRemoteInfos(); + for (const auto& item : infos) + { + if (item.getFingerprint() == pFingerprint) + { + return item; + } + } + + return RemoteInfo(); +} + + +QVector RemoteServiceSettings::getRemoteInfos() const +{ + QVector infos; + + const auto& data = mStore->value(SETTINGS_NAME_TRUSTED_REMOTE_INFO(), QByteArray()).toByteArray(); + const auto& array = QJsonDocument::fromJson(data).array(); + for (const auto& item : array) + { + const auto& obj = item.toObject(); + auto fingerprint = obj[QLatin1String("fingerprint")].toString(); + auto name = obj[QLatin1String("name")].toString(); + auto lastConnected = QDateTime::fromString(obj[QLatin1String("lastConnected")].toString(), Qt::ISODateWithMs); + infos << RemoteInfo(fingerprint, lastConnected, name); + } + + return infos; +} + + +void RemoteServiceSettings::setRemoteInfos(const QVector& pInfos) +{ + QJsonArray array; + for (const auto& item : pInfos) + { + QJsonObject obj; + obj[QLatin1String("fingerprint")] = item.getFingerprint(); + obj[QLatin1String("name")] = item.getName(); + obj[QLatin1String("lastConnected")] = item.getLastConnected().toString(Qt::ISODateWithMs); + array << obj; + } + + mStore->setValue(SETTINGS_NAME_TRUSTED_REMOTE_INFO(), QJsonDocument(array).toJson(QJsonDocument::Compact)); + Q_EMIT fireTrustedRemoteInfosChanged(); +} + + +void RemoteServiceSettings::syncRemoteInfos(const QSet& pCertificates) +{ + QStringList trustedFingerprints; + for (const auto& cert : pCertificates) + { + trustedFingerprints << generateFingerprint(cert); + } + + QVector syncedInfo; + + // remove outdated entries + const auto& infos = getRemoteInfos(); + for (const auto& info : infos) + { + if (trustedFingerprints.contains(info.getFingerprint())) + { + trustedFingerprints.removeOne(info.getFingerprint()); + syncedInfo << info; + } + } + + // add new entries + for (const auto& fingerprint : qAsConst(trustedFingerprints)) + { + syncedInfo << RemoteInfo(fingerprint, QDateTime::currentDateTime()); + } + + setRemoteInfos(syncedInfo); +} + + +bool RemoteServiceSettings::updateRemoteInfo(const RemoteInfo& pInfo) +{ + if (pInfo.getFingerprint().isEmpty()) + { + return false; + } + + auto infos = getRemoteInfos(); + QMutableVectorIterator iter(infos); + while (iter.hasNext()) + { + iter.next(); + if (iter.value().getFingerprint() == pInfo.getFingerprint()) + { + iter.setValue(pInfo); + setRemoteInfos(infos); + return true; + } + } + + return false; +} + + +RemoteServiceSettings::RemoteInfo::RemoteInfo(const QString& pFingerprint, + const QDateTime& pLastConnected, + const QString& pName) + : mFingerprint(pFingerprint) + , mName(pName) + , mLastConnected(pLastConnected) +{ +} + + +const QString& RemoteServiceSettings::RemoteInfo::getFingerprint() const +{ + return mFingerprint; +} + + +const QString& RemoteServiceSettings::RemoteInfo::getName() const +{ + return mName; +} + + +void RemoteServiceSettings::RemoteInfo::setName(const QString& pName) +{ + mName = pName; +} + + +const QDateTime& RemoteServiceSettings::RemoteInfo::getLastConnected() const +{ + return mLastConnected; +} + + +void RemoteServiceSettings::RemoteInfo::setLastConnected(const QDateTime& pLastConnected) +{ + mLastConnected = pLastConnected; +} + + +bool RemoteServiceSettings::RemoteInfo::operator==(const RemoteInfo& pOther) const +{ + return mFingerprint == pOther.mFingerprint + && mName == pOther.mName + && mLastConnected == pOther.mLastConnected; +} + + +bool RemoteServiceSettings::RemoteInfo::operator!=(const RemoteInfo& pOther) const +{ + return !(*this == pOther); +} diff --git a/src/settings/RemoteServiceSettings.h b/src/settings/RemoteServiceSettings.h new file mode 100644 index 0000000..cf7a072 --- /dev/null +++ b/src/settings/RemoteServiceSettings.h @@ -0,0 +1,114 @@ +/*! + * \brief RemoteService settings + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AbstractSettings.h" + +#include +#include +#include +#include +#include +#include +#include + +class test_RemoteServiceSettings; +class test_RemoteConnector; +class test_RemoteTlsServer; +class test_RemoteWebSocketServer; + +namespace governikus +{ + +class RemoteServiceSettings + : public AbstractSettings +{ + Q_OBJECT + + friend class AppSettings; + friend class ::test_RemoteServiceSettings; + friend class ::test_RemoteConnector; + friend class ::test_RemoteTlsServer; + friend class ::test_RemoteWebSocketServer; + + public: + class RemoteInfo + { + friend class RemoteServiceSettings; + friend class ::test_RemoteServiceSettings; + + private: + QString mFingerprint; + QString mName; + QDateTime mLastConnected; + + RemoteInfo(const QString& pFingerprint, + const QDateTime& pLastConnected = QDateTime(), + const QString& pName = QString()); + + public: + RemoteInfo() = default; + + const QString& getFingerprint() const; + + const QString& getName() const; + void setName(const QString& pName); + + const QDateTime& getLastConnected() const; + void setLastConnected(const QDateTime& pLastConnected); + + bool operator==(const RemoteInfo& pOther) const; + bool operator!=(const RemoteInfo& pOther) const; + }; + + private: + QSharedPointer mStore; + + RemoteServiceSettings(); + QString getDefaultServerName(); + void setTrustedCertificates(const QList& pCertificates); + void setUniqueTrustedCertificates(const QSet& pCertificates); + + void setRemoteInfos(const QVector& pInfos); + void syncRemoteInfos(const QSet& pCertificates); + + public: + static QString generateFingerprint(const QSslCertificate& pCert); + virtual ~RemoteServiceSettings() override; + virtual void save() override; + + QString getServerName() const; + void setServerName(const QString& pName); + + bool getPinPadMode() const; + void setPinPadMode(bool pPinPadMode); + + QList getTrustedCertificates() const; + void addTrustedCertificate(const QSslCertificate& pCertificate); + void removeTrustedCertificate(const QSslCertificate& pCertificate); + void removeTrustedCertificate(const QString& pFingerprint); + + QSslCertificate getCertificate() const; + void setCertificate(const QSslCertificate& pCert) const; + + QSslKey getKey() const; + void setKey(const QSslKey& pKey) const; + + RemoteInfo getRemoteInfo(const QSslCertificate& pCertificate) const; + RemoteInfo getRemoteInfo(const QString& pFingerprint) const; + QVector getRemoteInfos() const; + bool updateRemoteInfo(const RemoteInfo& pInfo); + + Q_SIGNALS: + void fireTrustedCertificatesChanged(); + void fireTrustedRemoteInfosChanged(); +}; + + +} /* namespace governikus */ + +Q_DECLARE_TYPEINFO(governikus::RemoteServiceSettings::RemoteInfo, Q_MOVABLE_TYPE); diff --git a/src/settings/SecureStorage.cpp b/src/settings/SecureStorage.cpp deleted file mode 100644 index 46967a9..0000000 --- a/src/settings/SecureStorage.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/*! - * SecureStorage.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "FileDestination.h" -#include "SecureStorage.h" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace governikus; - -const QLatin1String SETTINGS_GROUP_NAME_CV_ROOT_CERTIFICATE("cvRootCertificates"); -const QLatin1String SETTINGS_GROUP_NAME_CV_ROOT_CERTIFICATE_TEST("cvRootCertificatesTest"); - -const QLatin1String SETTINGS_GROUP_NAME_UPDATE_CERTIFICATES("updateCertificates"); - -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"); -const QLatin1String SETTINGS_NAME_SELF_AUTHENTICATION_TEST_URL("testUrl"); -const QLatin1String SETTINGS_NAME_SELF_AUTHENTICATION_CERTDESCR("certDescr"); -const QLatin1String SETTINGS_NAME_SELF_AUTHENTICATION_TEST_CERTDESCR("testCertDescr"); - -const QLatin1String SETTINGS_GROUP_NAME_DRIVERS("drivers"); -const QLatin1String SETTINGS_NAME_DRIVERS_UPDATE_URL("updateUrl"); - -const QLatin1String SETTINGS_GROUP_NAME_PROVIDERS("providers"); -const QLatin1String SETTINGS_NAME_PROVIDERS_UPDATE_URL("updateUrl"); -const QLatin1String SETTINGS_NAME_PROVIDERS_ICONS_UPDATE_URL_BASE("iconsUpdateUrlBase"); - -const QLatin1String SETTINGS_GROUP_NAME_UPDATES("updates"); -const QLatin1String SETTINGS_NAME_APPCAST_UPDATE_URL("release"); -const QLatin1String SETTINGS_NAME_APPCAST_BETA_UPDATE_URL("beta"); - -SecureStorage::SecureStorage() - : mLoadedTime() - , mCvcas() - , mCvcasTest() - , mUpdateCertificates() - , mSelfAuthenticationUrl() - , mSelfAuthenticationTestUrl() - , mDriverUpdateUrl() - , mProviderUpdateUrl() - , mProviderIconUpdateUrlBase() - , mSelfAuthenticationCertDescr() - , mSelfAuthenticationTestCertDescr() - , mAppcastUpdateUrl() - , mAppcastBetaUpdateUrl() - , mTlsSettings() - , mTlsSettingsPsk() -{ -} - - -SecureStorage::~SecureStorage() -{ -} - - -void SecureStorage::load() -{ - const auto& path = FileDestination::getPath("config.json"); - if (!QFile::exists(path)) - { - qCritical() << "SecureStorage not found"; - return; - } - - const auto& lastModified = QFileInfo(path).lastModified(); - if (lastModified.isValid() && lastModified <= mLoadedTime) - { - return; - } - - QFile configFile(path); - if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) - { - qCritical() << "Wasn't able to open SecureStorage"; - return; - } - - QJsonParseError parseError; - QJsonDocument document = QJsonDocument::fromJson(configFile.readAll(), &parseError); - configFile.close(); - if (parseError.error != QJsonParseError::NoError) - { - qCritical() << "Parse error while reading SecureStorage on position " << parseError.offset << ": " << parseError.errorString(); - return; - } - QJsonObject config = document.object(); - - mCvcas.clear(); - readByteArrayList(mCvcas, config, SETTINGS_GROUP_NAME_CV_ROOT_CERTIFICATE); - - mCvcasTest.clear(); - readByteArrayList(mCvcasTest, config, SETTINGS_GROUP_NAME_CV_ROOT_CERTIFICATE_TEST); - - QByteArrayList certificates; - readByteArrayList(certificates, config, SETTINGS_GROUP_NAME_UPDATE_CERTIFICATES); - mUpdateCertificates.clear(); - for (int i = 0; i < certificates.size(); ++i) - { - QSslCertificate certificate(QByteArray::fromHex(certificates[i]), QSsl::Der); - if (certificate.isNull()) - { - qCritical() << "Failed to read update certificate[" << i << "] from SecureStorage"; - continue; - } - mUpdateCertificates += certificate; - } - - QJsonValue tlsValue = config.value(SETTINGS_GROUP_NAME_TLS_SETTINGS); - if (!tlsValue.isUndefined()) - { - mTlsSettings.load(tlsValue.toObject()); - } - - QJsonValue tlsPskValue = config.value(SETTINGS_GROUP_NAME_TLS_SETTINGS_PSK); - if (!tlsPskValue.isUndefined()) - { - mTlsSettingsPsk.load(tlsPskValue.toObject()); - } - mMinStaticKeySizes = readKeySizes(config, SETTINGS_GROUP_NAME_MIN_STATIC_KEY_SIZES); - mMinEphemeralKeySizes = readKeySizes(config, SETTINGS_GROUP_NAME_MIN_EPHEMERAL_KEY_SIZES); - - - 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); - mSelfAuthenticationCertDescr = readGroup(config, SETTINGS_GROUP_NAME_SELF_AUTHENTICATION, SETTINGS_NAME_SELF_AUTHENTICATION_CERTDESCR).toLatin1(); - mSelfAuthenticationTestCertDescr = readGroup(config, SETTINGS_GROUP_NAME_SELF_AUTHENTICATION, SETTINGS_NAME_SELF_AUTHENTICATION_TEST_CERTDESCR).toLatin1(); - - mDriverUpdateUrl = readGroup(config, SETTINGS_GROUP_NAME_DRIVERS, SETTINGS_NAME_DRIVERS_UPDATE_URL); - - mProviderUpdateUrl = readGroup(config, SETTINGS_GROUP_NAME_PROVIDERS, SETTINGS_NAME_PROVIDERS_UPDATE_URL); - mProviderIconUpdateUrlBase = readGroup(config, SETTINGS_GROUP_NAME_PROVIDERS, SETTINGS_NAME_PROVIDERS_ICONS_UPDATE_URL_BASE); - - mAppcastUpdateUrl = readGroup(config, SETTINGS_GROUP_NAME_UPDATES, SETTINGS_NAME_APPCAST_UPDATE_URL); - mAppcastBetaUpdateUrl = readGroup(config, SETTINGS_GROUP_NAME_UPDATES, SETTINGS_NAME_APPCAST_BETA_UPDATE_URL); - - mLoadedTime = lastModified; - qInfo() << "SecureStorage successfully loaded"; -} - - -const QByteArrayList& SecureStorage::getCVRootCertificates(bool pProductive) const -{ - return pProductive ? mCvcas : mCvcasTest; -} - - -const QVector& SecureStorage::getUpdateCertificates() const -{ - return mUpdateCertificates; -} - - -const QUrl& SecureStorage::getSelfAuthenticationUrl(bool pTest) const -{ - return pTest ? mSelfAuthenticationTestUrl : mSelfAuthenticationUrl; -} - - -const QByteArray& SecureStorage::getSelfAuthenticationCertDescr(bool pTest) const -{ - return pTest ? mSelfAuthenticationTestCertDescr : mSelfAuthenticationCertDescr; -} - - -const QUrl& SecureStorage::getDriverUpdateUrl() const -{ - return mDriverUpdateUrl; -} - - -const QUrl& SecureStorage::getProviderUpdateUrl() const -{ - return mProviderUpdateUrl; -} - - -const QString& SecureStorage::getProviderIconUpdateUrlBase() const -{ - return mProviderIconUpdateUrlBase; -} - - -const QUrl& SecureStorage::getAppcastUpdateUrl() const -{ - return mAppcastUpdateUrl; -} - - -const QUrl& SecureStorage::getAppcastBetaUpdateUrl() const -{ - return mAppcastBetaUpdateUrl; -} - - -const TlsSettings& SecureStorage::getTlsSettings() const -{ - return mTlsSettings; -} - - -const TlsSettings& SecureStorage::getTlsSettingsPsk() const -{ - return mTlsSettingsPsk; -} - - -int SecureStorage::getMinimumStaticKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const -{ - if (!mMinStaticKeySizes.contains(pKeyAlgorithm)) - { - qWarning() << "No minimum ephemeral key size specified, returning default"; - } - return mMinStaticKeySizes.value(pKeyAlgorithm, 0); -} - - -int SecureStorage::getMinimumEphemeralKeySize(QSsl::KeyAlgorithm pKeyAlgorithm) const -{ - if (!mMinEphemeralKeySizes.contains(pKeyAlgorithm)) - { - qWarning() << "No minimum ephemeral key size specified, returning default"; - } - return mMinEphemeralKeySizes.value(pKeyAlgorithm, 0); -} - - -bool SecureStorage::readJsonArray(QJsonArray& pArray, const QJsonObject& pConfig, const QLatin1String& pName) -{ - QJsonValue value = pConfig.value(pName); - if (!value.isArray()) - { - qCritical() << "Expecting array for" << pName << "in SecureStorage"; - return false; - } - pArray = value.toArray(); - return true; -} - - -QString SecureStorage::readGroup(const QJsonObject& pConfig, const QLatin1String& pGroup, const QLatin1String& pName) -{ - QJsonValue value = pConfig.value(pGroup); - if (!value.isObject()) - { - qCritical() << "Expecting group for" << pGroup << "in SecureStorage"; - return QString(); - } - - QJsonObject groupObject = value.toObject(); - value = groupObject.value(pName); - if (!value.isString()) - { - qCritical() << "Expecting string for" << pGroup << "/" << pName << "in SecureStorage"; - return QString(); - } - - return value.toString(); -} - - -QMap SecureStorage::readKeySizes(const QJsonObject& pConfig, const QLatin1String& pKey) -{ - QMap keySizes; - const auto& object = pConfig.value(pKey).toObject(); - if (!object.isEmpty()) - { - const auto& keys = object.keys(); - for (const QString& key : keys) - { - 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 keySizes; -} - - -void SecureStorage::readByteArrayList(QByteArrayList& pArray, const QJsonObject& pConfig, const QLatin1String& pName) -{ - QJsonArray jsonArray; - if (readJsonArray(jsonArray, pConfig, pName)) - { - for (int i = 0; i < jsonArray.size(); ++i) - { - QJsonValue certificate = jsonArray[i]; - if (!certificate.isString()) - { - qCritical() << "Expected hexstring in array[" << i << "] " << pName << " in SecureStorage"; - continue; - } - pArray += certificate.toString().toLatin1(); - } - } -} diff --git a/src/settings/SecureStorage.h b/src/settings/SecureStorage.h deleted file mode 100644 index 05cc78b..0000000 --- a/src/settings/SecureStorage.h +++ /dev/null @@ -1,113 +0,0 @@ -/*! - * SecureStorage.h - * - * \brief Utility class that provides access to the "secure storage" of the application, which contains - * the certificates for preverification and update checks. - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include "AbstractSettings.h" -#include "TlsSettings.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class test_SecureStorage; - - -namespace governikus -{ - -using SignatureAlgorithmPair = QPair; - -class SecureStorage final -{ - friend class AppSettings; - friend class ::test_SecureStorage; - friend bool operator==(const SecureStorage& pLeft, const SecureStorage& pRight); - - private: - QDateTime mLoadedTime; - QByteArrayList mCvcas; - QByteArrayList mCvcasTest; - QVector mUpdateCertificates; - QUrl mSelfAuthenticationUrl; - QUrl mSelfAuthenticationTestUrl; - QUrl mDriverUpdateUrl; - QUrl mProviderUpdateUrl; - QString mProviderIconUpdateUrlBase; - QByteArray mSelfAuthenticationCertDescr; - QByteArray mSelfAuthenticationTestCertDescr; - QUrl mAppcastUpdateUrl; - QUrl mAppcastBetaUpdateUrl; - - 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); - QMap readKeySizes(const QJsonObject& pConfig, const QLatin1String& pKey); - void readByteArrayList(QByteArrayList& pArray, const QJsonObject& pConfig, const QLatin1String& pName); - - public: - void load(); - - const QByteArrayList& getCVRootCertificates(bool pProductive) const; - const QVector& getUpdateCertificates() const; - const QUrl& getSelfAuthenticationUrl(bool pTest = false) const; - const QByteArray& getSelfAuthenticationCertDescr(bool pTest = false) const; - const QUrl& getDriverUpdateUrl() const; - const QUrl& getProviderUpdateUrl() const; - const QString& getProviderIconUpdateUrlBase() const; - const QUrl& getAppcastUpdateUrl() const; - const QUrl& getAppcastBetaUpdateUrl() 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) -{ - return &pLeft == &pRight || ( - containsAllEntries(pLeft.mCvcas, pRight.mCvcas) && - containsAllEntries(pLeft.mCvcasTest, pRight.mCvcasTest) && - containsAllEntries(pLeft.mUpdateCertificates, pRight.mUpdateCertificates) && - pLeft.mSelfAuthenticationUrl == pRight.mSelfAuthenticationUrl && - pLeft.mSelfAuthenticationTestUrl == pRight.mSelfAuthenticationTestUrl && - pLeft.mDriverUpdateUrl == pRight.mDriverUpdateUrl && - pLeft.mProviderUpdateUrl == pRight.mProviderUpdateUrl && - pLeft.mProviderIconUpdateUrlBase == pRight.mProviderIconUpdateUrlBase && - pLeft.mSelfAuthenticationCertDescr == pRight.mSelfAuthenticationCertDescr && - pLeft.mSelfAuthenticationTestCertDescr == pRight.mSelfAuthenticationTestCertDescr && - pLeft.mAppcastUpdateUrl == pRight.mAppcastUpdateUrl && - pLeft.mAppcastBetaUpdateUrl == pRight.mAppcastBetaUpdateUrl && - pLeft.mTlsSettings == pRight.mTlsSettings && - pLeft.mTlsSettingsPsk == pRight.mTlsSettingsPsk && - pLeft.mMinStaticKeySizes == pRight.mMinStaticKeySizes && - pLeft.mMinEphemeralKeySizes == pRight.mMinEphemeralKeySizes); -} - - -inline bool operator!=(const SecureStorage& pLeft, const SecureStorage& pRight) -{ - return !(pLeft == pRight); -} - - -} // namespace governikus diff --git a/src/settings/TlsSettings.cpp b/src/settings/TlsSettings.cpp deleted file mode 100644 index f5f5561..0000000 --- a/src/settings/TlsSettings.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/*! - * 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 deleted file mode 100644 index 975bed7..0000000 --- a/src/settings/TlsSettings.h +++ /dev/null @@ -1,91 +0,0 @@ -/*! - * 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/CMakeLists.txt b/src/websocket/CMakeLists.txt index 758d7ef..638ac85 100644 --- a/src/websocket/CMakeLists.txt +++ b/src/websocket/CMakeLists.txt @@ -1,6 +1,6 @@ IF(TARGET Qt5::WebSockets) ADD_PLATFORM_LIBRARY(AusweisAppWebSocket) - TARGET_LINK_LIBRARIES(AusweisAppWebSocket Qt5::WebSockets AusweisAppJsonApi AusweisAppGlobal) + TARGET_LINK_LIBRARIES(AusweisAppWebSocket Qt5::Core Qt5::WebSockets AusweisAppJsonApi AusweisAppGlobal) TARGET_COMPILE_DEFINITIONS(AusweisAppWebSocket PRIVATE QT_STATICPLUGIN) ENDIF() diff --git a/src/websocket/UIPlugInWebSocket.cpp b/src/websocket/UIPlugInWebSocket.cpp index 0fe396e..ba0240e 100644 --- a/src/websocket/UIPlugInWebSocket.cpp +++ b/src/websocket/UIPlugInWebSocket.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInWebSocket.h" diff --git a/src/websocket/UIPlugInWebSocket.h b/src/websocket/UIPlugInWebSocket.h index 084f48c..e008a52 100644 --- a/src/websocket/UIPlugInWebSocket.h +++ b/src/websocket/UIPlugInWebSocket.h @@ -1,7 +1,7 @@ /*! * \brief UIPlugIn implementation of the Websocket. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -46,7 +46,7 @@ class UIPlugInWebSocket public: UIPlugInWebSocket(); - virtual ~UIPlugInWebSocket(); + virtual ~UIPlugInWebSocket() override; static void setPort(quint16 pPort); static quint16 getPort(); diff --git a/src/widget/AboutDialog.cpp b/src/widget/AboutDialog.cpp new file mode 100644 index 0000000..ff4f813 --- /dev/null +++ b/src/widget/AboutDialog.cpp @@ -0,0 +1,95 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AboutDialog.h" +#include "ui_AboutDialog.h" + +#include "AppSettings.h" +#include "BuildHelper.h" +#include "Env.h" +#include "SecureStorage.h" +#include "VersionNumber.h" + +using namespace governikus; + + +AboutDialog::AboutDialog(QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::AboutDialog) +{ + mUi->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + layout()->setSizeConstraint(QLayout::SetFixedSize); // For platform != Windows: Disable maximize button + setWindowModality(Qt::WindowModal); // For platform == macOS: Make dialog slide in from the top + + const SecureStorage& storage = SecureStorage::getInstance(); + const auto& url = VersionNumber::getApplicationVersion().isDeveloperVersion() ? storage.getAppcastBetaUpdateUrl() : storage.getAppcastUpdateUrl(); + const auto& releaseNotes = url.adjusted(QUrl::RemoveFilename).toString() + QStringLiteral("ReleaseNotes.html"); + + setWindowTitle(tr("About %1 - %2").arg(QCoreApplication::applicationName(), QCoreApplication::organizationName())); + + mUi->lblFurtherInformation->setText(QStringLiteral("%1: https://www.ausweisapp.bund.de/") + .arg(tr("Further information"))); + + mUi->lblReleaseNotes->setText(tr("The current release notes can be found %1 here.%2") + .arg(QStringLiteral("").arg(releaseNotes), QStringLiteral(""))); + + mUi->lblVersion->setText(QStringLiteral("%1: %2 (%3)").arg(tr("Version"), QApplication::applicationVersion(), QString::fromLatin1(BuildHelper::getDateTime()))); + + mUi->lblDeveloperModeWarning->setText(QStringLiteral("

%1

") + .arg(tr("The developer mode is aimed at integrators / developers for new service applications." + " For this reason, the developer mode works only in the test PKI." + " By activating the developer mode, some safety tests are deactivated." + " This means that the authentication process continues although the AusweisApp2 would usually abort the process with an error message when used in normal operation mode." + " Information on the disregarded error in the developer mode is displayed in the attached window below the AusweisApp2."))); + + const QIcon icon = windowIcon(); + const QSize size = icon.actualSize(QSize(64, 64)); + mUi->imgAusweisApp2->setPixmap(icon.pixmap(size)); + + connect(mUi->btnOkay, &QPushButton::clicked, this, &QDialog::accept); + connect(this, &QDialog::accepted, this, &AboutDialog::onAccept); + + mUi->chkbDeveloperMode->setCheckState(AppSettings::getInstance().getGeneralSettings().isDeveloperMode() ? Qt::Checked : Qt::Unchecked); + + connect(mUi->chkbDeveloperMode, &QCheckBox::stateChanged, this, &AboutDialog::onCheckboxStateChanged); + onCheckboxStateChanged(); +} + + +AboutDialog::~AboutDialog() +{ +} + + +void AboutDialog::onCheckboxStateChanged() +{ + const bool developerModeActivated = mUi->chkbDeveloperMode->checkState() == Qt::Checked; + mUi->lblDeveloperModeWarning->setVisible(developerModeActivated); + resize(minimumSize()); + adjustSize(); +} + + +void AboutDialog::onAccept() +{ + const bool developerModeActivated = mUi->chkbDeveloperMode->checkState() == Qt::Checked; + GeneralSettings& generalSettings = AppSettings::getInstance().getGeneralSettings(); + if (generalSettings.isDeveloperMode() != developerModeActivated) + { + generalSettings.setDeveloperMode(developerModeActivated); + generalSettings.save(); + } +} + + +void AboutDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/AboutDialog.h b/src/widget/AboutDialog.h new file mode 100644 index 0000000..ff280b6 --- /dev/null +++ b/src/widget/AboutDialog.h @@ -0,0 +1,40 @@ +/*! + * \brief Dialog to display information about the application + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class AboutDialog; +} + +namespace governikus +{ + +class AboutDialog + : public QDialog +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + private Q_SLOTS: + void onCheckboxStateChanged(); + void onAccept(); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + AboutDialog(QWidget* pParent = nullptr); + virtual ~AboutDialog() override; +}; + +} /* namespace governikus */ diff --git a/src/widget/AboutDialog.ui b/src/widget/AboutDialog.ui new file mode 100644 index 0000000..d41b30b --- /dev/null +++ b/src/widget/AboutDialog.ui @@ -0,0 +1,239 @@ + + + AboutDialog + + + + 0 + 0 + 616 + 348 + + + + + 20 + + + QLayout::SetMinimumSize + + + 0 + + + 20 + + + 0 + + + 20 + + + + + 20 + + + 20 + + + 20 + + + + + + + + 0 + 0 + + + + + 64 + 64 + + + + $Image + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + + + + + + 10 + + + QLayout::SetMinimumSize + + + + + + 75 + true + + + + AusweisApp2 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Ministry of the Interior. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + $Further Information + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + $Release Notes + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + $Version + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + 0 + 0 + + + + Developer mode: + + + + + + + + 0 + 0 + + + + use + + + + + + + + + $developerWarning + + + true + + + + + + + + + + + 20 + + + 20 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + true + + + + + + + + + + diff --git a/src/widget/AppQtGui.cpp b/src/widget/AppQtGui.cpp new file mode 100644 index 0000000..a6a879e --- /dev/null +++ b/src/widget/AppQtGui.cpp @@ -0,0 +1,689 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppQtGui.h" + +#include "AppSettings.h" +#include "CredentialDialog.h" +#include "DiagnosisGui.h" +#include "Env.h" +#include "generic/HelpAction.h" +#include "GuiProfile.h" +#include "NetworkManager.h" +#include "Service.h" +#include "SetupAssistantGui.h" +#include "UpdateWindow.h" +#include "workflow/WorkflowAuthenticateQtGui.h" +#include "workflow/WorkflowChangePinQtGui.h" +#include "workflow/WorkflowGui.h" +#include "workflow/WorkflowSelfInfoQtGui.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_NETWORKPROXY + #include + #include +#endif + + +#if defined(Q_OS_MACOS) +#import +#endif + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +AppQtGui::AppQtGui() + : QObject() + , mMainWidget(nullptr) + , mIcon(QStringLiteral(":/images/npa.svg")) + , mTrayIcon(nullptr) + , mActiveWorkflowUi() + , mSetupAssistantGui(nullptr) + , mDiagnosisGui(nullptr) + , mUpdateInfo(nullptr) + , mAggressiveToForeground(false) +{ + initGuiProfile(); + + mMainWidget = new AppQtMainWidget(); + mMainWidget->setWindowIcon(mIcon); + + mUpdateInfo = new QMessageBox(mMainWidget); + mUpdateInfo->setWindowTitle(QApplication::applicationName() + QStringLiteral(" - ") + tr("Updates")); + mUpdateInfo->setWindowIcon(QIcon(QStringLiteral(":/images/npa.svg"))); + mUpdateInfo->setWindowModality(Qt::WindowModal); + + Service* service = Env::getSingleton(); + connect(service, &Service::fireAppUpdateFinished, this, &AppQtGui::onAppUpdateReady); + connect(service, &Service::fireUpdateScheduled, this, &AppQtGui::onUpdateScheduled); +} + + +AppQtGui::~AppQtGui() +{ + if (mTrayIcon != nullptr) + { + QMenu* menu = mTrayIcon->contextMenu(); + if (menu != nullptr) + { + qDeleteAll(menu->actions()); + delete menu; + } + } + + delete mUpdateInfo; + delete mMainWidget; +} + + +void AppQtGui::init() +{ + connect(mMainWidget, &AppQtMainWidget::fireChangePinRequested, this, &AppQtGui::fireChangePinRequested); + connect(mMainWidget, &AppQtMainWidget::fireSetupAssistantWizardRequest, this, &AppQtGui::onSetupAssistantWizardRequest); + connect(mMainWidget, &AppQtMainWidget::fireDiagnosisRequested, this, &AppQtGui::onDiagnosisRequested); + connect(mMainWidget, &AppQtMainWidget::fireCloseWindowRequested, this, &AppQtGui::onCloseWindowRequested); + connect(mMainWidget, &AppQtMainWidget::fireSelfAuthenticationRequested, this, &AppQtGui::selfAuthenticationRequested); + connect(mMainWidget, &AppQtMainWidget::fireQuitApplicationRequested, this, &AppQtGui::quitApplicationRequested); + connect(mMainWidget, &AppQtMainWidget::fireChangeHighContrast, this, &AppQtGui::onChangeHighContrast); +} + + +void AppQtGui::onApplicationStarted() +{ + if (QSystemTrayIcon::isSystemTrayAvailable()) + { + createTrayIcon(); + } + + if (mTrayIcon != nullptr) + { + mTrayIcon->show(); + mTrayIcon->showMessage(QString(), tr("AusweisApp2 was started."), mIcon, 3000); + } + + if (!QSystemTrayIcon::isSystemTrayAvailable() + || GuiProfile::getProfile().getShowWindow() + || AppSettings::getInstance().getGeneralSettings().isShowSetupAssistant() + || AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + { + QMetaObject::invokeMethod(this, "show", Qt::QueuedConnection); + } + + if (AppSettings::getInstance().getGeneralSettings().isShowSetupAssistant()) + { + mMainWidget->setSelectedTab(nullptr); + QMetaObject::invokeMethod(this, "onSetupAssistantWizardRequest", Qt::QueuedConnection); + + // just show the setup assistant once + AppSettings::getInstance().getGeneralSettings().setShowSetupAssistant(false); + AppSettings::getInstance().getGeneralSettings().save(); + } + + if (AppSettings::getInstance().getGeneralSettings().isDeveloperMode()) + { + QMetaObject::invokeMethod(this, "onDeveloperModeQuestion", Qt::QueuedConnection); + } +} + + +QSharedPointer AppQtGui::createWorkflowAuthenticateUi(const QSharedPointer& pContext) +{ + const QSharedPointer gui(new WorkflowAuthenticateQtGui(pContext, mMainWidget)); + connect(gui.data(), &WorkflowGui::fireSwitchToReaderSettingsRequested, this, &AppQtGui::onSwitchToReaderSettingsRequested); + + return gui; +} + + +QSharedPointer AppQtGui::createWorkflowChangePinUi(const QSharedPointer& pContext) +{ + return QSharedPointer(new WorkflowChangePinQtGui(pContext, mMainWidget)); +} + + +QSharedPointer AppQtGui::createWorkflowSelfInfoUi(const QSharedPointer& pContext) +{ + const QSharedPointer gui(new WorkflowSelfInfoQtGui(pContext, mMainWidget)); + connect(gui.data(), &WorkflowGui::fireSwitchToReaderSettingsRequested, this, &AppQtGui::onSwitchToReaderSettingsRequested); + + return gui; +} + + +void AppQtGui::onSwitchToReaderSettingsRequested() +{ + mMainWidget->setHideWindowAfterWorkflow(false); + + Q_EMIT fireSwitchToReaderSettingsRequested(); +} + + +void AppQtGui::activateWorkflowUi(QSharedPointer pWorkflowUi, bool pAllowHideAfterWorkflow) +{ + if (pWorkflowUi) + { + mActiveWorkflowUi = pWorkflowUi; + mActiveWorkflowUi->activate(); + } + + mMainWidget->activateMenuBarItems(false); + closeDialogs(); + +#ifdef Q_OS_WIN + mAggressiveToForeground = mActiveWorkflowUi.objectCast(); +#endif + bool hideAfterWorkflow = pAllowHideAfterWorkflow + && mActiveWorkflowUi.objectCast() + && AppSettings::getInstance().getGeneralSettings().isAutoCloseWindowAfterAuthentication(); + mMainWidget->setHideWindowAfterWorkflow(hideAfterWorkflow); + show(); +} + + +void AppQtGui::deactivateCurrentWorkflowUi() +{ + if (mMainWidget->isHideWindowAfterWorkflow()) + { + hideFromTaskbar(); + mMainWidget->hide(); + } + mMainWidget->activateMenuBarItems(true); + + if (mActiveWorkflowUi) + { + mActiveWorkflowUi->deactivate(); + mActiveWorkflowUi.clear(); + } +} + + +void AppQtGui::onShowUserInformation(const QString& pInformationMessage) +{ + QMessageBox msgBox(mMainWidget); + msgBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Information")); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText(pInformationMessage); + msgBox.setStandardButtons(QMessageBox::StandardButton::Ok); + msgBox.exec(); +} + + +void AppQtGui::onSetupAssistantWizardRequest() +{ + Env::getSingleton()->runUpdateIfNeeded(); + + if (!mSetupAssistantGui) + { + mSetupAssistantGui = new SetupAssistantGui(mMainWidget); + connect(mSetupAssistantGui, &SetupAssistantGui::fireChangePinButtonClicked, mMainWidget, &AppQtMainWidget::onChangePinButtonClicked); + } + mSetupAssistantGui->activate(); +} + + +void AppQtGui::onDeveloperModeQuestion() +{ + QMessageBox msgBox(mMainWidget); + msgBox.setWindowModality(Qt::WindowModal); + msgBox.setWindowFlags(msgBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); + msgBox.setIconPixmap(mMainWidget->windowIcon().pixmap(QSize(48, 48))); + msgBox.setText(tr("The developer mode is enabled.")); + msgBox.setInformativeText(tr("Do you want to disable the developer mode?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + + if (msgBox.exec() == QMessageBox::Yes) + { + AppSettings::getInstance().getGeneralSettings().setDeveloperMode(false); + AppSettings::getInstance().getGeneralSettings().save(); + } +} + + +void AppQtGui::onDiagnosisRequested() +{ + if (!mDiagnosisGui) + { + mDiagnosisGui = new DiagnosisGui(mMainWidget); + } + mDiagnosisGui->activate(); +} + + +bool AppQtGui::askChangeTransportPinNow() +{ + GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); + if (!settings.isTransportPinReminder()) + { + return false; + } + settings.setTransportPinReminder(false); + settings.save(); + + show(UiModule::PINMANAGEMENT); + closeDialogs(); + + QMessageBox messageBox(mMainWidget); + messageBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("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); + messageBox.exec(); + + if (messageBox.clickedButton() != changePinButton) + { + show(UiModule::IDENTIFY); + return false; + } + + return true; +} + + +void AppQtGui::switchToReaderSettings() +{ + mMainWidget->switchToGuiModule(GuiModule::DEVICE_SETTINGS); +} + + +bool AppQtGui::eventFilter(QObject* /*pObject*/, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + + if (keyEvent->key() == Qt::BackButton || keyEvent->key() == Qt::Key_Back) + { + Q_EMIT quitApplicationRequested(); + return true; + } + } + return false; +} + + +void AppQtGui::initGuiProfile() +{ + GuiProfile& profile = GuiProfile::getProfile(); + + // set style sheet only if none has be specified on the command line + if (qApp->styleSheet().isEmpty()) + { + if (profile.getDebugStyleSheet().isEmpty()) + { + loadStyleSheet(profile.getStyleSheetName(), true); + } + else + { + QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList() << profile.getDebugStyleSheet(), this); + connect(watcher, &QFileSystemWatcher::fileChanged, this, &AppQtGui::onDebugStyleSheetChanged); + loadStyleSheet(profile.getDebugStyleSheet(), false); + } + } +} + + +void AppQtGui::loadStyleSheet(const QString& pStyleSheetName, bool pIsResource) +{ + QString styleSheetName = pIsResource ? QStringLiteral(":/stylesheets/") + pStyleSheetName : pStyleSheetName; + qCDebug(gui) << "loading style sheet" << styleSheetName; + QString styleSheet = readStyleSheet(styleSheetName); + if (!styleSheet.isEmpty()) + { + qApp->setStyleSheet(styleSheet); + } + else + { + qCWarning(gui) << "Failed to load global style sheet!"; + } +} + + +QString AppQtGui::readStyleSheet(const QString& pFileName) +{ + // read the file into a string + QFile file(pFileName); + if (!file.open(QIODevice::ReadOnly)) + { + qCWarning(gui) << "Failed to read style sheet:" << pFileName; + return QString(); + } + + QString styleSheet = QString::fromLatin1(file.readAll()); + file.close(); + + // resolve imports + // Note: The algorithm is very simple and e.g. doesn't detect that an import is commented out. + QRegularExpression regExp(QStringLiteral("@import\\s+\"([^\"]*)\"\\s*;")); + QRegularExpressionMatchIterator it = regExp.globalMatch(styleSheet); + if (!it.hasNext()) + { + return styleSheet; + } + + QString result; + int lastOffset = 0; + + while (it.hasNext()) + { + QRegularExpressionMatch match = it.next(); + if (lastOffset < match.capturedStart()) + { + result += styleSheet.midRef(lastOffset, match.capturedStart() - lastOffset); + } + + result += readStyleSheet(match.captured(1)); + + lastOffset = match.capturedEnd(); + } + + if (lastOffset < styleSheet.length()) + { + result += styleSheet.midRef(lastOffset); + } + + return result; +} + + +void AppQtGui::onChangeHighContrast(bool* pHighContrastOn) +{ + if (*pHighContrastOn) + { + qApp->setStyleSheet(QString()); + } + else + { + initGuiProfile(); + } +} + + +void AppQtGui::createTrayIcon() +{ + QMenu* trayIconMenu = new QMenu(nullptr); + +#if defined(Q_OS_MACOS) + QAction* showApplicationAction = new QAction(tr("Open"), trayIconMenu); + connect(showApplicationAction, &QAction::triggered, this, [this] { + AppQtGui::show(); + }); +#endif + + QAction* quitAction = new QAction(tr("Exit AusweisApp2"), trayIconMenu); + connect(quitAction, &QAction::triggered, this, &AppQtGui::quitApplicationRequested); + +#if defined(Q_OS_MACOS) + trayIconMenu->addAction(showApplicationAction); + trayIconMenu->addSeparator(); +#endif + trayIconMenu->addAction(quitAction); + + mTrayIcon = new QSystemTrayIcon(mIcon, mMainWidget); + connect(mTrayIcon, &QSystemTrayIcon::activated, this, &AppQtGui::onActivated); + connect(mTrayIcon, &QSystemTrayIcon::messageClicked, this, [this] { + show(UiModule::CURRENT); + }); + + mTrayIcon->setContextMenu(trayIconMenu); + mTrayIcon->setToolTip(QCoreApplication::applicationName()); +} + + +void AppQtGui::closeDialogs() +{ + if (mSetupAssistantGui) + { + mSetupAssistantGui->deactivate(); + } + if (mDiagnosisGui) + { + mDiagnosisGui->deactivate(); + } +} + + +void AppQtGui::hideFromTaskbar() +{ +#if defined(Q_OS_MACOS) + ProcessSerialNumber psn = { + 0, kCurrentProcess + }; + TransformProcessType(&psn, kProcessTransformToBackgroundApplication); +#endif +} + + +void AppQtGui::restoreToTaskbar() +{ +#if defined(Q_OS_MACOS) + ProcessSerialNumber psn = { + 0, kCurrentProcess + }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + [NSApp activateIgnoringOtherApps: YES]; +#endif +} + + +void AppQtGui::onActivated(QSystemTrayIcon::ActivationReason pReason) +{ +#ifdef Q_OS_MACOS + Q_UNUSED(pReason) +#else + if (pReason == QSystemTrayIcon::Trigger) + { + show(); + } +#endif +} + + +void AppQtGui::onCloseWindowRequested(bool* pDoClose) +{ + if (mMainWidget->isRemindUserToClose()) + { + QMessageBox messageBox(mMainWidget); + messageBox.installEventFilter(this); + messageBox.setWindowTitle(QApplication::applicationName() + QStringLiteral(" - ") + tr("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("Do not show this dialog again."))); + messageBox.exec(); + + Q_EMIT fireCloseReminderFinished(messageBox.checkBox()->isChecked()); + } + + mMainWidget->onCloseWindowRequested(); + + if (mActiveWorkflowUi == nullptr) + { + *pDoClose = true; + } + else if ((*pDoClose = mActiveWorkflowUi->verifyAbortWorkflow())) + { + Q_EMIT mActiveWorkflowUi->fireUserCancelled(); + } + + if (*pDoClose) + { + hideFromTaskbar(); + } +} + + +void AppQtGui::onDebugStyleSheetChanged(const QString& pPath) +{ + if (QFileSystemWatcher* watcher = qobject_cast(sender())) + { + // work-around for QFileSystemWatcher no longer knowing the file after receiving the first notification + watcher->removePath(pPath); + watcher->addPath(pPath); + } + + loadStyleSheet(pPath, false); +} + + +#ifndef QT_NO_NETWORKPROXY +void AppQtGui::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) +{ + CredentialDialog dialog(mMainWidget); + dialog.setUser(pProxy.user()); + + if (dialog.exec() == QDialog::Accepted) + { + pAuthenticator->setUser(dialog.getUser()); + pAuthenticator->setPassword(dialog.getPassword()); + } +} + + +#endif + + +void AppQtGui::show(UiModule pModule) +{ + if (!mActiveWorkflowUi.isNull()) + { + pModule = UiModule::CURRENT; + } + + switch (pModule) + { + case UiModule::PINMANAGEMENT: + mMainWidget->switchToGuiModule(GuiModule::PIN_SETTINGS); + break; + + case UiModule::SETTINGS: + mMainWidget->switchToGuiModule(GuiModule::GENERAL_SETTINGS); + break; + + case UiModule::IDENTIFY: + mMainWidget->switchToGuiModule(GuiModule::IDENTIFY); + break; + + + case UiModule::DEFAULT: + mMainWidget->switchToGuiModule(GuiModule::START_PAGE); + break; + + case UiModule::CURRENT: + // don't switch the module, just show the current one + break; + } + + restoreToTaskbar(); + + if (mMainWidget->isMinimized()) + { + mMainWidget->showNormal(); + } + + // Ensure the window's minimumSizeHint is respected (work-around for a Windows Qt bug). + if (!mMainWidget->isMaximized()) + { + QSize size = mMainWidget->size(); + size = size.expandedTo(mMainWidget->minimumSizeHint()); + 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. + const Qt::WindowFlags flags = mMainWidget->windowFlags(); + mMainWidget->setWindowFlags(flags | Qt::WindowStaysOnTopHint); + mMainWidget->show(); + mMainWidget->setWindowFlags(flags); + + mAggressiveToForeground = false; + } +#endif + + mMainWidget->show(); + mMainWidget->activateWindow(); + + // Work-around for the window not being brought to the foreground. Invoke + // activateWindow() again after the events currently pending in the event + // queue have been processed. This appears to do the job. Note that the + // first activateWindow() above is apparently still necessary. + QCoreApplication::processEvents(); + mMainWidget->activateWindow(); + + Env::getSingleton()->runUpdateIfNeeded(); +} + + +void AppQtGui::onAppUpdateReady(bool pSuccess, const GlobalStatus& pError) +{ + if (pError.isError()) + { + mUpdateInfo->setIcon(QMessageBox::Critical); + mUpdateInfo->setText(pError.toErrorDescription()); + mUpdateInfo->exec(); + } + else if (pSuccess) + { + const auto updateWindow = new UpdateWindow(mMainWidget); + connect(updateWindow, &UpdateWindow::fireShowUpdateDialog, + [this](QMessageBox::Icon pIcon, const QString& pMsg) + { + mUpdateInfo->setIcon(pIcon); + mUpdateInfo->setText(pMsg); + mUpdateInfo->exec(); + } + ); + } + else + { + mUpdateInfo->setIcon(QMessageBox::Information); + mUpdateInfo->setText(tr("Your software is up to date.")); + mUpdateInfo->exec(); + } +} + + +void AppQtGui::onUpdateScheduled() +{ + if (!mMainWidget->isHidden()) + { + Env::getSingleton()->runUpdateIfNeeded(); + } +} + + +void AppQtGui::shutdown() +{ + if (mTrayIcon != nullptr) + { + mTrayIcon->hide(); + } +} diff --git a/src/widget/AppQtGui.h b/src/widget/AppQtGui.h new file mode 100644 index 0000000..e875363 --- /dev/null +++ b/src/widget/AppQtGui.h @@ -0,0 +1,107 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ActivationHandler.h" +#include "GlobalStatus.h" + +#include +#include + + +#ifndef QT_NO_NETWORKPROXY +class QNetworkProxy; +class QAuthenticator; +#endif + +namespace governikus +{ + +class AppQtMainWidget; +class AuthContext; +class ChangePinContext; +class DiagnosisGui; +class SelfAuthContext; +class SetupAssistantGui; +class WorkflowGui; +class WorkflowAuthenticateQtGui; +class WorkflowChangePinQtGui; +class WorkflowSelfInfoQtGui; + +class AppQtGui + : public QObject +{ + Q_OBJECT + + public: + AppQtGui(); + virtual ~AppQtGui() override; + + virtual void init(); + + virtual QSharedPointer createWorkflowAuthenticateUi(const QSharedPointer& pContext); + virtual QSharedPointer createWorkflowChangePinUi(const QSharedPointer& pContext); + virtual QSharedPointer createWorkflowSelfInfoUi(const QSharedPointer& pContext); + + virtual void activateWorkflowUi(QSharedPointer pWorkflowUi, bool pAllowHideAfterWorkflow = true); + virtual void deactivateCurrentWorkflowUi(); + + virtual bool askChangeTransportPinNow(); + void switchToReaderSettings(); + + void shutdown(); + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + + private: + void initGuiProfile(); + void loadStyleSheet(const QString& pStyleSheetName, bool pIsResource); + QString readStyleSheet(const QString& pFileName); + void createTrayIcon(); + void closeDialogs(); + void hideFromTaskbar(); + void restoreToTaskbar(); + + public Q_SLOTS: + 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); + void onCloseWindowRequested(bool* pDoClose); + void onDebugStyleSheetChanged(const QString& pPath); + void onChangeHighContrast(bool* pHighContrastOn); + void onSetupAssistantWizardRequest(); + void onDeveloperModeQuestion(); + void onDiagnosisRequested(); + void onAppUpdateReady(bool pSuccess, const GlobalStatus& pError); + void onUpdateScheduled(); + void onSwitchToReaderSettingsRequested(); + + private: + AppQtMainWidget* mMainWidget; + QIcon mIcon; + QSystemTrayIcon* mTrayIcon; + QSharedPointer mActiveWorkflowUi; + SetupAssistantGui* mSetupAssistantGui; + DiagnosisGui* mDiagnosisGui; + QMessageBox* mUpdateInfo; + bool mAggressiveToForeground; + + Q_SIGNALS: + void fireCloseReminderFinished(bool pDontRemindAgain); + + void fireChangePinRequested(); + void selfAuthenticationRequested(); + void fireSwitchToReaderSettingsRequested(); + void quitApplicationRequested(); +}; + +} /* namespace governikus */ diff --git a/src/widget/AppQtMainWidget.cpp b/src/widget/AppQtMainWidget.cpp new file mode 100644 index 0000000..1bd1dca --- /dev/null +++ b/src/widget/AppQtMainWidget.cpp @@ -0,0 +1,617 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppQtMainWidget.h" + +#include "AboutDialog.h" +#include "AppSettings.h" +#include "BuildHelper.h" +#include "generic/ExclusiveButtonGroup.h" +#include "generic/HelpAction.h" +#include "GuiProfile.h" +#include "LanguageLoader.h" +#include "LogHandler.h" +#include "ReaderDetector.h" +#include "step/AuthenticateStepsWidget.h" +#include "SetupAssistantWizard.h" +#include "ui_AppQtMainWidget.h" +#include "VersionNumber.h" +#include "workflow/WorkflowQtWidget.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(gui) + +AppQtMainWidget::AppQtMainWidget() + : QMainWindow() + , mUi(new Ui::AppQtMainWidget()) + , mTabButton2Page() + , mTabAction2Button() + , mAuthenticationWorkflowWidget(nullptr) + , mSelectedPushButton(nullptr) + , mSelectedPushButtonBeforeWorkflow(nullptr) + , mSelectedPagesBeforeWorkflow() + , mHideWindowAfterWorkflow(false) + , mLogFilesDialog() +{ + mUi->setupUi(this); + mUi->englishButton->setBackgroundRole(QPalette::NoRole); + mUi->germanButton->setBackgroundRole(QPalette::NoRole); + + refreshLanguageButton(); + + mUi->appLogoWidget->setAttribute(Qt::WA_TransparentForMouseEvents); + + QStackedLayout* centralStackLayout = qobject_cast(mUi->centralWidget->layout()); + centralStackLayout->setStackingMode(QStackedLayout::StackAll); + centralStackLayout->setCurrentIndex(1); + + QSpacerItem* spacer = new QSpacerItem(1, mUi->logoLabel->sizeHint().height(), QSizePolicy::Fixed, QSizePolicy::Ignored); + mUi->applicationGridLayout->addItem(spacer, mUi->applicationGridLayout->rowCount(), 0); + + mUi->providerPage->layout()->setMargin(20); + mUi->historyPage->layout()->setMargin(20); + + mAuthenticationWorkflowWidget = new WorkflowQtWidget(); + mUi->workflowPage->layout()->addWidget(mAuthenticationWorkflowWidget); + mAuthenticationWorkflowWidget->getStepWidgetArea()->layout()->addWidget(new AuthenticateStepsWidget); + + //menu file + connect(mUi->actionBeenden, &QAction::triggered, this, &AppQtMainWidget::fireQuitApplicationRequested); + connect(mUi->actionSettings, &QAction::triggered, this, &AppQtMainWidget::onSettingsButtonClicked); + + //menu PIN management + connect(mUi->actionChangePin, &QAction::triggered, this, &AppQtMainWidget::onChangePinButtonClicked); + + //help + connect(mUi->actionSetupAssistant, &QAction::triggered, this, &AppQtMainWidget::fireSetupAssistantWizardRequest); + connect(mUi->actionDiagnosis, &QAction::triggered, this, &AppQtMainWidget::fireDiagnosisRequested); + + connect(mUi->actionShowProtocol, &QAction::triggered, this, &AppQtMainWidget::onOpenLoggingFileButtonClicked); + connect(mUi->actionSaveProtocol, &QAction::triggered, this, &AppQtMainWidget::onSaveLoggingFileButtonClicked); + connect(mUi->actionInfo, &QAction::triggered, this, &AppQtMainWidget::onAboutActionClicked); + connect(mUi->actionSendError, &QAction::triggered, this, &AppQtMainWidget::onSendErrorActionClicked); + connect(mUi->actionEvaluate, &QAction::triggered, this, &AppQtMainWidget::onEvaluateActionClicked); + connect(mUi->actionQuestion, &QAction::triggered, this, &AppQtMainWidget::onQuestionActionClicked); + connect(mUi->actionHelp, &QAction::triggered, this, &AppQtMainWidget::onContentActionClicked); + + connect(mUi->identifyPage, &SelfInformationWidget::selfAuthenticationRequested, this, &AppQtMainWidget::fireSelfAuthenticationRequested); + connect(mUi->settingsPage, &SettingsWidget::changePinRequested, this, &AppQtMainWidget::fireChangePinRequested); + connect(mUi->settingsPage, &SettingsWidget::diagnosisRequested, this, &AppQtMainWidget::fireDiagnosisRequested); + connect(mUi->settingsPage, &SettingsWidget::settingsDone, this, &AppQtMainWidget::onSettingsDone); + + connect(mUi->germanButton, &QPushButton::clicked, [&]() + { + setLanguage(QLocale::German); + }); + connect(mUi->englishButton, &QPushButton::clicked, [&]() + { + setLanguage(QLocale::English); + }); + + //NavigationButtons + mUi->startPushButton->setVisible(false); + mUi->mainTabList->addButton(mUi->startPushButton); + mTabButton2Page.insert(mUi->startPushButton, mUi->applicationPage); + + struct ButtonInfo + { + QAbstractButton* mButton; + QWidget* mPage; + QAction* mAction; + const char* mOnIcon; + const char* mOffIcon; + }; + ButtonInfo buttonInfos[] = { + {mUi->ausweisenToolButton, mUi->identifyPage, mUi->actionAusweisen, ":/images/bt_1.svg", ":/images/bt_1b.svg"}, + {mUi->providerToolButton, mUi->providerPage, mUi->actionProvider, ":/images/bt_2.svg", ":/images/bt_2b.svg"}, + {mUi->historyToolButton, mUi->historyPage, mUi->actionHistory, ":/images/bt_3.svg", ":/images/bt_3b.svg"}, + {mUi->settingsToolButton, mUi->settingsPage, mUi->actionSettings, ":/images/bt_4.svg", ":/images/bt_4b.svg"}, + }; + + for (size_t i = 0; i < sizeof(buttonInfos) / sizeof(buttonInfos[0]); ++i) + { + const ButtonInfo& buttonInfo = buttonInfos[i]; + QIcon icon; + icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOnIcon)), QIcon::Normal, QIcon::Off); + icon.addPixmap(QPixmap(QString::fromLatin1(buttonInfo.mOffIcon)), QIcon::Normal, QIcon::On); + + buttonInfo.mButton->setIcon(icon); + + connect(buttonInfo.mAction, &QAction::triggered, this, &AppQtMainWidget::onTabActionTriggered); + + mUi->mainTabList->addButton(buttonInfo.mButton); + mTabButton2Page.insert(buttonInfo.mButton, buttonInfo.mPage); + mTabAction2Button.insert(buttonInfo.mAction, buttonInfo.mButton); + } + + connect(mUi->mainTabList, &TabButtonGroup::buttonToggled, this, &AppQtMainWidget::onTabButtonToggled); + mUi->stackedWidget->setCurrentIndex(0); + + if (VersionNumber::getApplicationVersion().isDeveloperVersion()) + { + setWindowTitle(windowTitle() + QStringLiteral(" - Beta - ") + QCoreApplication::applicationVersion()); + mUi->betaLabel->setMinimumSize(QSize(150, 150)); + mUi->betaLabel->setPixmap(QPixmap(QStringLiteral(":/images/beta.svg")).scaled(mUi->betaLabel->width(), mUi->betaLabel->width(), Qt::KeepAspectRatio)); + mUi->betaLabel->setVisible(true); + } + + + // work-around for bug QT/QTBUG-40869 + QSet visitedObjects; + updateGeometryRecursively(this, visitedObjects); + +#ifdef Q_OS_WIN + // we need to call create() explicitly because Windows needs a handle to fire WM_ENDSESSION! + // Since we start as a systemtray only we don't have a correct handle until we call show() + create(); +#endif +} + + +AppQtMainWidget::~AppQtMainWidget() +{ +} + + +void AppQtMainWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + refreshLanguageButton(); + } + + if (pEvent->type() == QEvent::PaletteChange) // QEvent::StyleChange is called, too + { + +#if defined(Q_OS_WIN) + HIGHCONTRAST hc; + hc.cbSize = sizeof(hc); + + bool highContrastOn = false; + if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, FALSE) && (hc.dwFlags & HCF_HIGHCONTRASTON)) + { + qDebug() << "High contrast (SPI_GETHIGHCONTRAST) switched on."; + highContrastOn = true; + Q_EMIT fireChangeHighContrast(&highContrastOn); + } + else + { + qDebug() << "High contrast (SPI_GETHIGHCONTRAST) switched off."; + Q_EMIT fireChangeHighContrast(&highContrastOn); + } +#endif + } + QWidget::changeEvent(pEvent); +} + + +void AppQtMainWidget::workflowActivated(WorkflowWidgetParent pParent, const QString& /*pName*/) +{ + QAbstractButton* tabToolButton = nullptr; + QWidget* containingWidget = nullptr; + + // activate the correct tab and set the workflow page + switch (pParent) + { + case WorkflowWidgetParent::SelfAuthentication: + case WorkflowWidgetParent::Authentication: + tabToolButton = mUi->ausweisenToolButton; + containingWidget = mUi->workflowPage; + break; + + case WorkflowWidgetParent::SettingsChangePin: + tabToolButton = mUi->settingsToolButton; + containingWidget = nullptr; + break; + } + + mSelectedPushButtonBeforeWorkflow = mSelectedPushButton; + + setSelectedTab(tabToolButton); + + if (tabToolButton != nullptr) + { + const auto tabButtons = mTabButton2Page.keys(); + for (auto button : tabButtons) + { + if (button != tabToolButton) + { + button->setEnabled(false); + } + } + } + + // show the respective page in the widget stacks + while (containingWidget != nullptr) + { + QWidget* containerParent = containingWidget->parentWidget(); + if (QStackedWidget* stackedWidget = qobject_cast(containerParent)) + { + mSelectedPagesBeforeWorkflow += stackedWidget->currentWidget(); + stackedWidget->setCurrentWidget(containingWidget); + } + + containingWidget = containerParent; + } + + mUi->settingsPage->workflowStarted(); + mUi->mainTabList->setWorkflowActive(true); + +} + + +void AppQtMainWidget::workflowDeactivated() +{ + const auto tabButtons = mTabButton2Page.keys(); + for (auto button : tabButtons) + { + button->setEnabled(true); + } + + for (auto widget : qAsConst(mSelectedPagesBeforeWorkflow)) + { + if (QStackedWidget* stackedWidget = qobject_cast(widget->parentWidget())) + { + stackedWidget->setCurrentWidget(widget); + } + + } + mSelectedPagesBeforeWorkflow.clear(); + + mUi->settingsPage->workflowFinished(); + mUi->mainTabList->setWorkflowActive(false); + + // switch back to the tab selected before the workflow + if (mSelectedPushButtonBeforeWorkflow == nullptr) + { + return; + } + setSelectedTab(mSelectedPushButtonBeforeWorkflow); + mSelectedPushButtonBeforeWorkflow = nullptr; +} + + +void AppQtMainWidget::switchToGuiModule(GuiModule pModule) +{ + switch (pModule) + { + case GuiModule::START_PAGE: + setSelectedTab(mUi->startPushButton); + break; + + case GuiModule::IDENTIFY: + setSelectedTab(mUi->ausweisenToolButton); + break; + + case GuiModule::GENERAL_SETTINGS: + case GuiModule::PIN_SETTINGS: + case GuiModule::DEVICE_SETTINGS: + setSelectedTab(mUi->settingsToolButton); + mUi->settingsPage->switchToGuiModule(pModule); + break; + } +} + + +void AppQtMainWidget::switchToPinSettingsAfterWorkflow() +{ + mHideWindowAfterWorkflow = false; + mSelectedPushButtonBeforeWorkflow = mUi->settingsToolButton; + + mSelectedPagesBeforeWorkflow.clear(); + + QWidget* containingWidget = mUi->stackedWidget->parentWidget(); + + while (containingWidget != nullptr) + { + QWidget* containerParent = containingWidget->parentWidget(); + if (qobject_cast(containerParent) != nullptr) + { + mSelectedPagesBeforeWorkflow += containingWidget; + } + + containingWidget = containerParent; + } + + mUi->settingsPage->switchToGuiModule(GuiModule::PIN_SETTINGS); +} + + +void AppQtMainWidget::closeEvent(QCloseEvent* pEvent) +{ + bool doClose = true; + Q_EMIT fireCloseWindowRequested(&doClose); + if (doClose) + { + pEvent->accept(); + } + else + { + pEvent->ignore(); + } +} + + +void AppQtMainWidget::keyPressEvent(QKeyEvent* keyEvent) +{ + switch (keyEvent->key()) + { + case Qt::Key_F1: + onContentActionClicked(); + break; + + default: + break; + } +} + + +void AppQtMainWidget::setSelectedTab(QAbstractButton* pSelectedPushButton) +{ + if (pSelectedPushButton == nullptr) + { + pSelectedPushButton = mUi->settingsToolButton; + mUi->settingsPage->switchToGuiModule(GuiModule::GENERAL_SETTINGS); + + } + if (mSelectedPushButton == mUi->settingsToolButton && mUi->settingsPage->isSettingsChanged()) + { + const auto tabButtons = mTabButton2Page.keys(); + for (auto button : tabButtons) + { + button->setChecked(button == mUi->settingsToolButton); + } + mUi->settingsPage->showSettingsChangedMessage(); + } + + mUi->appLogoWidget->setVisible(pSelectedPushButton == mUi->startPushButton); + + if (mSelectedPushButton) + { + mSelectedPushButton->clearFocus(); + } + mSelectedPushButton = pSelectedPushButton; + mSelectedPushButton->setChecked(true); + + mUi->stackedWidget->setCurrentWidget(mTabButton2Page.value(pSelectedPushButton)); +} + + +void AppQtMainWidget::activateWindow() +{ + QMainWindow::activateWindow(); + +#if defined(Q_OS_MACOS) + // Workaround. When switching from "BackgroundApplication" to "ForegroundApplication" + // on MacOS, it is a known problem that the menu bar of the previous active application + // stays visible, although the window has changed to the current application. As soon + // as the user clicks the menu, it magically transforms to the correct one. We therefore + // manually trigger an update. Neither update() nor repaint() of QMenuBar solve this problem. + QMenu menu; + mUi->menuBar->addAction(menu.menuAction()); + mUi->menuBar->removeAction(menu.menuAction()); +#endif +} + + +void AppQtMainWidget::updateGeometryRecursively(QWidget* pWidget, QSet& pVisitedObjects) +{ + if (pVisitedObjects.contains(pWidget)) + { + return; + } + + pVisitedObjects.insert(pWidget); + + pWidget->updateGeometry(); + + if (pWidget->layout() != nullptr) + { + updateGeometryRecursively(pWidget->layout(), pVisitedObjects); + } + + for (QObject* child : pWidget->children()) + { + if (QWidget* widget = qobject_cast(child)) + { + updateGeometryRecursively(widget, pVisitedObjects); + } + } +} + + +void AppQtMainWidget::updateGeometryRecursively(QLayout* pLayout, QSet& pVisitedObjects) +{ + if (pVisitedObjects.contains(pLayout)) + { + return; + } + + pVisitedObjects.insert(pLayout); + + pLayout->invalidate(); + + int itemCount = pLayout->count(); + for (int i = 0; i < itemCount; ++i) + { + QLayoutItem* item = pLayout->itemAt(i); + + if (QLayout* layout = item->layout()) + { + updateGeometryRecursively(layout, pVisitedObjects); + } + else if (QWidget* widget = item->widget()) + { + updateGeometryRecursively(widget, pVisitedObjects); + } + } +} + + +void AppQtMainWidget::onSettingsDone() +{ + setSelectedTab(mUi->startPushButton); +} + + +void AppQtMainWidget::onOpenLoggingFileButtonClicked() +{ + if (!mLogFilesDialog) + { + mLogFilesDialog = new LogFilesDialog(this); + } + + mLogFilesDialog->show(); +} + + +void AppQtMainWidget::onSaveLoggingFileButtonClicked() +{ + LogFilesDialog::saveLogFile(this); +} + + +void AppQtMainWidget::onTabButtonToggled(QAbstractButton* pButton, bool pChecked) +{ + if (pChecked) + { + if (mTabButton2Page.contains(pButton) && mSelectedPushButton != pButton) + { + setSelectedTab(pButton); + } + } +} + + +void AppQtMainWidget::onTabActionTriggered() +{ + if (QAction* action = qobject_cast(sender())) + { + if (QAbstractButton* button = mTabAction2Button.value(action)) + { + setSelectedTab(button); + } + } +} + + +void AppQtMainWidget::onSettingsButtonClicked() +{ + setSelectedTab(mUi->settingsToolButton); + mUi->settingsPage->switchToGuiModule(GuiModule::GENERAL_SETTINGS); +} + + +void AppQtMainWidget::onChangePinButtonClicked() +{ + setSelectedTab(mUi->settingsToolButton); + mUi->settingsPage->switchToGuiModule(GuiModule::PIN_SETTINGS); +} + + +void AppQtMainWidget::onQuestionActionClicked() +{ + QString link = tr("https://www.ausweisapp.bund.de/en/service/haeufig-gestellte-fragen/"); + QDesktopServices::openUrl(QUrl(link)); +} + + +void AppQtMainWidget::onSendErrorActionClicked() +{ + QString link = tr("https://www.ausweisapp.bund.de/en/feedback/melden-sie-einen-fehler/"); + QDesktopServices::openUrl(QUrl(link)); +} + + +void AppQtMainWidget::onEvaluateActionClicked() +{ + QString link = tr("https://www.ausweisapp.bund.de/en/feedback/bewerten-sie-uns/"); + QDesktopServices::openUrl(QUrl(link)); +} + + +void AppQtMainWidget::onContentActionClicked() +{ + QString name = mUi->stackedWidget->widget(mUi->stackedWidget->currentIndex())->objectName(); + if (name.startsWith(QLatin1String("settingsPage"))) + { + SettingsWidget* settingsWidget = static_cast(mUi->stackedWidget->widget(mUi->stackedWidget->currentIndex())); + HelpAction::openContextHelp(settingsWidget->getActiveTabObjectName()); + } + else + { + HelpAction::openContextHelp(name); + } +} + + +void AppQtMainWidget::onAboutActionClicked() +{ + AboutDialog* dialog = new AboutDialog(this); + dialog->show(); +} + + +void AppQtMainWidget::setLanguage(QLocale::Language pLocale) +{ + GeneralSettings& generalSettings = AppSettings::getInstance().getGeneralSettings(); + generalSettings.setLanguage(pLocale); + generalSettings.save(); +} + + +void AppQtMainWidget::refreshLanguageButton() +{ + const QString& selected = QStringLiteral("border-style: solid; border-width: 1px; border-color: grey; padding: 4px;"); + const QString& unselected = QStringLiteral("padding: 4px;"); + + const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + if (locale == QLocale::English) + { + mUi->englishButton->setStyleSheet(selected); + mUi->germanButton->setStyleSheet(unselected); + } + else if (locale == QLocale::German) + { + mUi->englishButton->setStyleSheet(unselected); + mUi->germanButton->setStyleSheet(selected); + } +} + + +void AppQtMainWidget::activateMenuBarItems(bool pEnable) +{ + mUi->actionAusweisen->setEnabled(pEnable); + mUi->actionProvider->setEnabled(pEnable); + mUi->actionHistory->setEnabled(pEnable); + mUi->actionSettings->setEnabled(pEnable); + mUi->actionChangePin->setEnabled(pEnable); + mUi->actionSetupAssistant->setEnabled(pEnable); +} + + +void AppQtMainWidget::onCloseWindowRequested() +{ + mUi->settingsPage->onTabChanged(-1); +} + + +bool AppQtMainWidget::isRemindUserToClose() +{ + return AppSettings::getInstance().getGeneralSettings().isRemindUserToClose(); +} diff --git a/src/widget/AppQtMainWidget.h b/src/widget/AppQtMainWidget.h new file mode 100644 index 0000000..5980edc --- /dev/null +++ b/src/widget/AppQtMainWidget.h @@ -0,0 +1,123 @@ +/*! + * \brief Main class for the top level main widget + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "generic/GuiModule.h" +#include "LogFilesDialog.h" +#include "workflow/WorkflowWidgetParent.h" + +namespace Ui +{ +class AppQtMainWidget; +} + +namespace governikus +{ + +class WorkflowQtWidget; + +class AppQtMainWidget + : public QMainWindow +{ + Q_OBJECT + + public: + AppQtMainWidget(); + virtual ~AppQtMainWidget() override; + + void workflowActivated(WorkflowWidgetParent pParent, const QString& pName); + void workflowDeactivated(); + + void switchToGuiModule(GuiModule pModule); + + void switchToPinSettingsAfterWorkflow(); + + bool isHideWindowAfterWorkflow() const + { + return mHideWindowAfterWorkflow; + } + + + void setHideWindowAfterWorkflow(bool pHide) + { + mHideWindowAfterWorkflow = pHide; + } + + + void activateMenuBarItems(bool pEnable); + + WorkflowQtWidget* getAuthenticationWorkflowWidget() const + { + return mAuthenticationWorkflowWidget; + } + + + bool isRemindUserToClose(); + + void setSelectedTab(QAbstractButton* pSelectedPushButton); + + void activateWindow(); + + protected: + virtual void closeEvent(QCloseEvent* pEvent) override; + virtual void keyPressEvent(QKeyEvent* keyEvent) override; + virtual void changeEvent(QEvent* event) override; + + private: + static void updateGeometryRecursively(QWidget* pWidget, QSet& pVisitedObjects); + static void updateGeometryRecursively(QLayout* pLayout, QSet& pVisitedObjects); + + private Q_SLOTS: + void onSettingsDone(); + + void onOpenLoggingFileButtonClicked(); + void onSaveLoggingFileButtonClicked(); + void onTabButtonToggled(QAbstractButton* pButton, bool pChecked); + void onTabActionTriggered(); + void onAboutActionClicked(); + void onSendErrorActionClicked(); + void onEvaluateActionClicked(); + void onQuestionActionClicked(); + void onContentActionClicked(); + + public Q_SLOTS: + void onSettingsButtonClicked(); + void onChangePinButtonClicked(); + void onCloseWindowRequested(); + + Q_SIGNALS: + void fireSetupAssistantWizardRequest(); + void fireChangePinRequested(); + void fireDiagnosisRequested(); + void fireCloseWindowRequested(bool* pDoClose); + void fireSelfAuthenticationRequested(); + void fireQuitApplicationRequested(); + void fireChangeHighContrast(bool* pHighContrastOn); + + private: + QScopedPointer mUi; + QMap mTabButton2Page; + QMap mTabAction2Button; + WorkflowQtWidget* mAuthenticationWorkflowWidget; + QAbstractButton* mSelectedPushButton; + QAbstractButton* mSelectedPushButtonBeforeWorkflow; + QVector mSelectedPagesBeforeWorkflow; + bool mHideWindowAfterWorkflow; + QPointer mLogFilesDialog; + QString mStyleSheet; + void refreshLanguageButton(); + void setLanguage(QLocale::Language pLocale); +}; + +} /* namespace governikus */ diff --git a/src/widget/AppQtMainWidget.ui b/src/widget/AppQtMainWidget.ui new file mode 100644 index 0000000..6fee602 --- /dev/null +++ b/src/widget/AppQtMainWidget.ui @@ -0,0 +1,869 @@ + + + AppQtMainWidget + + + + 0 + 0 + 950 + 600 + + + + Qt::NoContextMenu + + + AusweisApp2 + + + + :/images/npa.svg:/images/npa.svg + + + + 64 + 64 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 10 + + + + + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Actions + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + 10 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 13 + 20 + + + + + + + + + 0 + 0 + + + + + 53 + 22 + + + + Switch language to German + + + padding: 4px; + + + DE + + + + :/images/location_flag_de.svg:/images/location_flag_de.svg + + + true + + + buttonGroup + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + true + + + + 0 + 0 + + + + + 53 + 23 + + + + Switch language to English + + + padding: 4px; + + + EN + + + + :/images/location_flag_en.svg:/images/location_flag_en.svg + + + false + + + true + + + buttonGroup + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + Welcome + + + true + + + true + + + + + + + + 0 + 0 + + + + margin-top: 10px; + + + Identify + + + + 32 + 32 + + + + true + + + false + + + Qt::ToolButtonTextBesideIcon + + + + + + + + 0 + 0 + + + + Provider + + + + 32 + 32 + + + + true + + + 300 + + + 100 + + + Qt::ToolButtonTextBesideIcon + + + + + + + + 0 + 0 + + + + History + + + + 32 + 32 + + + + true + + + Qt::ToolButtonTextBesideIcon + + + + + + + + 0 + 0 + + + + Settings + + + + 32 + 32 + + + + true + + + Qt::ToolButtonTextBesideIcon + + + + + + + 0 + + + 15 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + + + + + + + + 1 + 0 + + + + 0 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::StrongFocus + + + nPA and eAT Logo + + + :/images/start_nPA_eAT.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::StrongFocus + + + AusweisApp2 Logo + + + :/images/AppLogo_AutentApp2_2014.png + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + true + + + + + + + + 0 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + :/images/Logo_AutentApp2_2014.png + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 170 + + + + + + + + + + 0 + 0 + 840 + 20 + + + + true + + + + Fi&le + + + + + + + + + + + &Help + + + + + + + + + + + + + + + + + + &PIN Management + + + + + + + + + + Minimise + + + + + &Exit + + + QAction::QuitRole + + + + + &Identify + + + + + &Settings + + + + + &Manual + + + + + &Evaluate + + + + + &Report error + + + + + &About AusweisApp2 + + + QAction::AboutRole + + + + + &Provider + + + + + S&how log + + + + + Save &log + + + + + &Questions + + + + + &History + + + + + &Change PIN + + + + + &Setup assistant + + + QAction::NoRole + + + + + &Diagnosis + + + + + + governikus::TabButtonGroup + QWidget +
generic/TabButtonGroup.h
+ 1 +
+ + governikus::SettingsWidget + QWidget +
SettingsWidget.h
+ 1 +
+ + governikus::ProviderWidget + QWidget +
ProviderWidget.h
+ 1 +
+ + governikus::SelfInformationWidget + QWidget +
SelfInformationWidget.h
+ 1 +
+ + governikus::HistoryWidget + QWidget +
HistoryWidget.h
+ 1 +
+ + governikus::DeveloperModeHistoryWidget + QWidget +
DeveloperModeHistoryWidget.h
+ 1 +
+ + governikus::TabButton + QToolButton +
generic/TabButtonGroup.h
+
+
+ + startPushButton + appLogoLabel + appLabel + ausweisenToolButton + providerToolButton + historyToolButton + settingsToolButton + + + + + + + + +
diff --git a/src/widget/AppStartPage.cpp b/src/widget/AppStartPage.cpp new file mode 100644 index 0000000..19eaa6e --- /dev/null +++ b/src/widget/AppStartPage.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppStartPage.h" + +#include "generic/TabButtonGroup.h" +#include "GuiProfile.h" +#include "ui_AppStartPage.h" + +#include +#include + +using namespace governikus; + +AppStartPage::AppStartPage(QWidget* pParent) + : QWidget(pParent) + , mApplicationLogoLabel(new QLabel(this)) + , mUi(new Ui::AppStartPage()) +{ + mUi->setupUi(this); + + QPixmap applicationPixmap(QStringLiteral(":/images/AppLogo_AutentApp2_2014.png")); + QPixmap nPAeATPixmap(QStringLiteral(":/images/start_nPA_eAT.png")); + + mUi->applicationLogoLabel->setPixmap(applicationPixmap); + mUi->nPAeATLabel->setPixmap(nPAeATPixmap); +} + + +AppStartPage::~AppStartPage() +{ +} + + +void AppStartPage::paintEvent(QPaintEvent* /*pPaintEvent*/) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void AppStartPage::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/AppStartPage.h b/src/widget/AppStartPage.h new file mode 100644 index 0000000..be91472 --- /dev/null +++ b/src/widget/AppStartPage.h @@ -0,0 +1,44 @@ +/*! + * \brief Main page widget. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class AppStartPage; +} + +namespace governikus +{ + +class AppStartPage + : public QWidget +{ + Q_OBJECT + + public: + AppStartPage(QWidget* pParent = nullptr); + virtual ~AppStartPage() override; + + Q_SIGNALS: + void selfInfoPageRequested(); + void bookmarksPageRequested(); + void settingsPageRequested(); + + private: + QLabel* mApplicationLogoLabel; + QScopedPointer mUi; + + virtual void paintEvent(QPaintEvent*) override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; +}; + +} /* namespace governikus */ diff --git a/src/gui/AppStartPage.ui b/src/widget/AppStartPage.ui similarity index 100% rename from src/gui/AppStartPage.ui rename to src/widget/AppStartPage.ui diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt new file mode 100644 index 0000000..2ce00ab --- /dev/null +++ b/src/widget/CMakeLists.txt @@ -0,0 +1,8 @@ +ADD_PLATFORM_LIBRARY(AusweisAppWidget) + +TARGET_LINK_LIBRARIES(AusweisAppWidget Qt5::Core Qt5::Widgets Qt5::Svg AusweisAppCore AusweisAppGlobal AusweisAppExport AusweisAppRemoteDevice AusweisAppConfiguration) +TARGET_COMPILE_DEFINITIONS(AusweisAppWidget PRIVATE QT_STATICPLUGIN) + +IF(WIN32) + TARGET_LINK_LIBRARIES(AusweisAppWidget Qt5::WinExtras) +ENDIF() diff --git a/src/widget/CredentialDialog.cpp b/src/widget/CredentialDialog.cpp new file mode 100644 index 0000000..0954296 --- /dev/null +++ b/src/widget/CredentialDialog.cpp @@ -0,0 +1,60 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "CredentialDialog.h" +#include "ui_CredentialDialog.h" + +using namespace governikus; + +CredentialDialog::CredentialDialog(QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::CredentialDialog) +{ + mUi->setupUi(this); + + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Proxy security")); + + connect(mUi->buttonBox, &QDialogButtonBox::accepted, this, &CredentialDialog::accept); + connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &CredentialDialog::reject); +} + + +CredentialDialog::~CredentialDialog() +{ + delete mUi; +} + + +void CredentialDialog::setUser(const QString& pUser) +{ + if (!pUser.isEmpty()) + { + mUi->user->setText(pUser); + mUi->password->setFocus(); + mUi->password->setCursorPosition(0); + } +} + + +QString CredentialDialog::getUser() const +{ + return mUi->user->text(); +} + + +QString CredentialDialog::getPassword() const +{ + return mUi->password->text(); +} + + +void CredentialDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/CredentialDialog.h b/src/widget/CredentialDialog.h new file mode 100644 index 0000000..dd3c04b --- /dev/null +++ b/src/widget/CredentialDialog.h @@ -0,0 +1,43 @@ +/*! + * \brief Show a dialog to fill in proxy credentials. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +namespace Ui +{ +class CredentialDialog; +} + +#include + +namespace governikus +{ + +class CredentialDialog + : public QDialog +{ + Q_OBJECT + + private: + Ui::CredentialDialog* mUi; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + explicit CredentialDialog(QWidget* pParent = nullptr); + virtual ~CredentialDialog() override; + + void setUser(const QString& pUser); + + QString getUser() const; + + QString getPassword() const; + + +}; + +} /* namespace governikus */ diff --git a/src/gui/CredentialDialog.ui b/src/widget/CredentialDialog.ui similarity index 100% rename from src/gui/CredentialDialog.ui rename to src/widget/CredentialDialog.ui diff --git a/src/widget/DeleteHistoryDialog.cpp b/src/widget/DeleteHistoryDialog.cpp new file mode 100644 index 0000000..2900c10 --- /dev/null +++ b/src/widget/DeleteHistoryDialog.cpp @@ -0,0 +1,70 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DeleteHistoryDialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace governikus; + + +DeleteHistoryDialog::DeleteHistoryDialog(QWidget* pParent) + : QDialog(pParent) +{ + setObjectName(QStringLiteral("DeleteHistoryDialog")); + + setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Delete history")); + setLayout(new QVBoxLayout(this)); + setMinimumSize(300, -1); + + layout()->setObjectName(QStringLiteral("dialogLayout")); + + QLabel* groupBoxLabel = new QLabel(this); + groupBoxLabel->setText(tr("Delete history for this period:")); + groupBoxLabel->setWordWrap(true); + layout()->addWidget(groupBoxLabel); + + mComboBox = new QComboBox(this); + layout()->addWidget(mComboBox); + mComboBox->addItem(tr("Past hour"), static_cast(TimePeriod::PAST_HOUR)); + mComboBox->addItem(tr("Past day"), static_cast(TimePeriod::PAST_DAY)); + mComboBox->addItem(tr("Past week"), static_cast(TimePeriod::PAST_WEEK)); + mComboBox->addItem(tr("Last four weeks"), static_cast(TimePeriod::LAST_FOUR_WEEKS)); + mComboBox->addItem(tr("All history"), static_cast(TimePeriod::ALL_HISTORY)); + + QSpacerItem* verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + layout()->addItem(verticalSpacer); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + layout()->addWidget(buttonBox); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + + +QRadioButton* DeleteHistoryDialog::createRadioButtonAndAppendToGroup(const QString& pText, TimePeriod pTimePeriod) +{ + QRadioButton* button = new QRadioButton(this); + button->setText(pText); + button->setProperty("TimePeriod", Enum::getValue(pTimePeriod)); + button->setObjectName(QStringLiteral("button%1").arg(QString::number(mRadioButtonGroup->buttons().count()))); + mRadioButtonGroup->addButton(button); + return button; +} + + +TimePeriod DeleteHistoryDialog::getTimePeriod() +{ + return TimePeriod(mComboBox->currentData().toInt()); +} diff --git a/src/widget/DeleteHistoryDialog.h b/src/widget/DeleteHistoryDialog.h new file mode 100644 index 0000000..2c42006 --- /dev/null +++ b/src/widget/DeleteHistoryDialog.h @@ -0,0 +1,40 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" + +#include +#include +#include +#include +#include + +namespace governikus +{ + +defineEnumType(TimePeriod, + PAST_HOUR, + PAST_DAY, + PAST_WEEK, + LAST_FOUR_WEEKS, + ALL_HISTORY + ) + +class DeleteHistoryDialog + : public QDialog +{ + Q_OBJECT + QPointer mRadioButtonGroup; + QPointer mComboBox; + + QRadioButton* createRadioButtonAndAppendToGroup(const QString& pText, TimePeriod pTimePeriod); + + public: + explicit DeleteHistoryDialog(QWidget* pParent = nullptr); + TimePeriod getTimePeriod(); +}; + +} /* namespace governikus */ diff --git a/src/widget/DetailDialog.cpp b/src/widget/DetailDialog.cpp new file mode 100644 index 0000000..1836713 --- /dev/null +++ b/src/widget/DetailDialog.cpp @@ -0,0 +1,63 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DetailDialog.h" +#include "DetailWidget.h" +#include "generic/HelpAction.h" +#include "ui_DetailDialog.h" +#include + +using namespace governikus; + +DetailDialog::DetailDialog(QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::DetailDialog) +{ + mUi->setupUi(this); + + setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Service provider data")); + + installEventFilter(this); + + connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &DetailDialog::close); +} + + +DetailDialog::~DetailDialog() +{ + delete mUi; +} + + +void DetailDialog::setDetails(const QString& pDetails) +{ + mUi->detailWidget->setDetails(pDetails); + adjustSize(); +} + + +bool DetailDialog::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QDialog::eventFilter(pObject, pEvent); +} + + +void DetailDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DetailDialog.h b/src/widget/DetailDialog.h new file mode 100644 index 0000000..dbe570d --- /dev/null +++ b/src/widget/DetailDialog.h @@ -0,0 +1,39 @@ +/*! + * \brief Detail dialog for certificate description + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace Ui +{ +class DetailDialog; +} + +namespace governikus +{ + +class DetailDialog + : public QDialog +{ + Q_OBJECT + + private: + Ui::DetailDialog* mUi; + + public: + explicit DetailDialog(QWidget* pParent = nullptr); + virtual ~DetailDialog() override; + + void setDetails(const QString& pDetails); + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + +}; + +} /* namespace governikus */ diff --git a/src/gui/DetailDialog.ui b/src/widget/DetailDialog.ui similarity index 100% rename from src/gui/DetailDialog.ui rename to src/widget/DetailDialog.ui diff --git a/src/widget/DetailWidget.cpp b/src/widget/DetailWidget.cpp new file mode 100644 index 0000000..ed87468 --- /dev/null +++ b/src/widget/DetailWidget.cpp @@ -0,0 +1,82 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DetailWidget.h" + +#include "ui_DetailWidget.h" + +#include + +using namespace governikus; + +DetailWidget::DetailWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::DetailWidget()) +{ + mUi->setupUi(this); + + // The scroll area may be resized while the content keeps its + // size, therefore the scroll area must have the same background + // color as the content. + mUi->scrollArea->setStyleSheet(QStringLiteral("QScrollArea { background-color: white; }" + "" + "QScrollBar {" + " background-color: #f8f6f4;" + "}")); + + const QString& border = QStringLiteral("border-width: 0;"); + mUi->scrollAreaWidgetContents->setStyleSheet(border); + mUi->detailText->setStyleSheet(border); +} + + +DetailWidget::~DetailWidget() +{ +} + + +void DetailWidget::setDetails(const QString& pDetails) +{ + mUi->detailText->setAccessibleName(tr("Service provider details dialog") + pDetails); + mUi->detailText->setText(pDetails); +} + + +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; + + if (mUi->detailText->width() > contentMaxWidth) + { + mUi->detailText->setFixedWidth(contentMaxWidth); + } + + mUi->scrollAreaWidgetContents->setFixedHeight(mUi->detailText->height()); + mUi->scrollAreaWidgetContents->setFixedWidth(mUi->detailText->width()); + + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void DetailWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DetailWidget.h b/src/widget/DetailWidget.h new file mode 100644 index 0000000..d988901 --- /dev/null +++ b/src/widget/DetailWidget.h @@ -0,0 +1,41 @@ +/*! + * \brief Widget for cvc description. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class DetailWidget; +} + +namespace governikus +{ + +class DetailWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + virtual void paintEvent(QPaintEvent*) override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + DetailWidget(QWidget* pParent = nullptr); + virtual ~DetailWidget() override; + + void setDetails(const QString& pDetails); + +}; + +} /* namespace governikus */ diff --git a/src/widget/DetailWidget.ui b/src/widget/DetailWidget.ui new file mode 100644 index 0000000..f751dbf --- /dev/null +++ b/src/widget/DetailWidget.ui @@ -0,0 +1,110 @@ + + + DetailWidget + + + + 0 + 0 + 595 + 450 + + + + true + + + Qt::WheelFocus + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QLayout::SetMaximumSize + + + + + false + + + + + 0 + 0 + 591 + 446 + + + + + 0 + 0 + + + + + + 0 + 0 + 9 + 17 + + + + + QLayout::SetFixedSize + + + 0 + + + + + + 0 + 0 + + + + true + + + Qt::TabFocus + + + 0 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + + + + + + diff --git a/src/widget/DeveloperModeHistoryWidget.cpp b/src/widget/DeveloperModeHistoryWidget.cpp new file mode 100644 index 0000000..1ed79a3 --- /dev/null +++ b/src/widget/DeveloperModeHistoryWidget.cpp @@ -0,0 +1,82 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppSettings.h" +#include "DeveloperModeHistoryWidget.h" +#include "LogHandler.h" +#include "ui_DeveloperModeHistoryWidget.h" + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(developermode) + + +DeveloperModeHistoryWidget::DeveloperModeHistoryWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::DeveloperModeHistoryWidget()) +{ + mUi->setupUi(this); + + connect(&AppSettings::getInstance(), &AppSettings::fireSettingsChanged, this, &DeveloperModeHistoryWidget::onSettingsChanged); + connect(&LogHandler::getInstance(), &LogHandler::fireRawLog, this, &DeveloperModeHistoryWidget::onRawLog); + connect(mUi->btnDisableDeveloperMode, &QPushButton::clicked, this, &DeveloperModeHistoryWidget::onDisableDeveloperMode); + + // initialize visibility state + onSettingsChanged(); +} + + +DeveloperModeHistoryWidget::~DeveloperModeHistoryWidget() +{ +} + + +void DeveloperModeHistoryWidget::appendLoggingDump(const QString& pLog) +{ + QString formatted = pLog; + + // Remove outer quotation + const QLatin1Char quote('"'); + if (formatted.startsWith(quote) && formatted.endsWith(quote)) + { + formatted = formatted.mid(1, formatted.length() - 2); + } + + mUi->plainTextEdit->appendHtml(QStringLiteral("
%1
").arg(formatted)); +} + + +void DeveloperModeHistoryWidget::onRawLog(const QString& pMsg, const QString& pCategoryName) +{ + static const QString categoryDevMode = QString::fromLatin1(developermode().categoryName()); + if (pCategoryName == categoryDevMode) + { + appendLoggingDump(pMsg); + } +} + + +void DeveloperModeHistoryWidget::onSettingsChanged() +{ + QWidget::setVisible(AppSettings::getInstance().getGeneralSettings().isDeveloperMode()); +} + + +void DeveloperModeHistoryWidget::onDisableDeveloperMode() +{ + AppSettings::getInstance().getGeneralSettings().setDeveloperMode(false); + AppSettings::getInstance().getGeneralSettings().save(); +} + + +void DeveloperModeHistoryWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DeveloperModeHistoryWidget.h b/src/widget/DeveloperModeHistoryWidget.h new file mode 100644 index 0000000..485515c --- /dev/null +++ b/src/widget/DeveloperModeHistoryWidget.h @@ -0,0 +1,46 @@ +/*! + * \brief A Widget to display developer mode errors which occurred + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + + +namespace Ui +{ +class DeveloperModeHistoryWidget; +} + + +namespace governikus +{ + +class DeveloperModeHistoryWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + void appendLoggingDump(const QString& pLog); + + private Q_SLOTS: + void onDisableDeveloperMode(); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + explicit DeveloperModeHistoryWidget(QWidget* pParent = nullptr); + virtual ~DeveloperModeHistoryWidget() override; + + public Q_SLOTS: + void onRawLog(const QString& pMsg, const QString& pCategoryName); + void onSettingsChanged(); +}; + +} /* namespace governikus */ diff --git a/src/widget/DeveloperModeHistoryWidget.ui b/src/widget/DeveloperModeHistoryWidget.ui new file mode 100644 index 0000000..22897ff --- /dev/null +++ b/src/widget/DeveloperModeHistoryWidget.ui @@ -0,0 +1,101 @@ + + + DeveloperModeHistoryWidget + + + + 0 + 0 + 599 + 248 + + + + + 0 + 0 + + + + + 0 + + + 6 + + + 0 + + + 0 + + + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Qt::TabFocus + + + color: red + + + Developer Mode: Enabled! + + + Qt::AlignCenter + + + true + + + + + + + Disable + + + + + + + + + + 0 + 0 + + + + QPlainTextEdit::NoWrap + + + true + + + + + + + + diff --git a/src/widget/DeveloperSettingsWidget.cpp b/src/widget/DeveloperSettingsWidget.cpp new file mode 100644 index 0000000..2c34fdb --- /dev/null +++ b/src/widget/DeveloperSettingsWidget.cpp @@ -0,0 +1,63 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DeveloperSettingsWidget.h" +#include "ui_DeveloperSettingsWidget.h" + +#include "AppSettings.h" + +using namespace governikus; + +DeveloperSettingsWidget::DeveloperSettingsWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::DeveloperSettingsWidget()) +{ + mUi->setupUi(this); + + reset(); + + connect(mUi->selfAuthTestCheckBox, &QCheckBox::stateChanged, this, &DeveloperSettingsWidget::onCheckBoxStateChanged); +} + + +DeveloperSettingsWidget::~DeveloperSettingsWidget() +{ + +} + + +void governikus::DeveloperSettingsWidget::onCheckBoxStateChanged() +{ + Q_EMIT fireSettingsChanged(); +} + + +void DeveloperSettingsWidget::showEvent(QShowEvent* pEvent) +{ + QWidget::showEvent(pEvent); +} + + +void DeveloperSettingsWidget::apply() +{ + auto& generalSettings = AppSettings::getInstance().getGeneralSettings(); + generalSettings.setUseSelfauthenticationTestUri(mUi->selfAuthTestCheckBox->isChecked()); + generalSettings.save(); +} + + +void DeveloperSettingsWidget::reset() +{ + mUi->selfAuthTestCheckBox->setChecked(AppSettings::getInstance().getGeneralSettings().useSelfAuthTestUri()); +} + + +void DeveloperSettingsWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DeveloperSettingsWidget.h b/src/widget/DeveloperSettingsWidget.h new file mode 100644 index 0000000..dcd1fe1 --- /dev/null +++ b/src/widget/DeveloperSettingsWidget.h @@ -0,0 +1,47 @@ +/*! + * \brief Widget for the developer settings. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + + +namespace Ui +{ +class DeveloperSettingsWidget; +} + +namespace governikus +{ + +class DeveloperSettingsWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + private Q_SLOTS: + void onCheckBoxStateChanged(); + virtual void showEvent(QShowEvent*) override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + DeveloperSettingsWidget(QWidget* pParent = nullptr); + virtual ~DeveloperSettingsWidget() override; + + void apply(); + void reset(); + + Q_SIGNALS: + void fireSettingsChanged(); +}; + +} /* namespace governikus */ diff --git a/src/widget/DeveloperSettingsWidget.ui b/src/widget/DeveloperSettingsWidget.ui new file mode 100644 index 0000000..9e940f8 --- /dev/null +++ b/src/widget/DeveloperSettingsWidget.ui @@ -0,0 +1,75 @@ + + + DeveloperSettingsWidget + + + + 0 + 0 + 483 + 222 + + + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + Qt::TabFocus + + + Self authentication test URI: + + + + + + + true + + + use + + + + + + + + + + Qt::Vertical + + + + 20 + 2 + + + + + + + + + diff --git a/src/widget/DiagnosisDialog.cpp b/src/widget/DiagnosisDialog.cpp new file mode 100644 index 0000000..a3c5a42 --- /dev/null +++ b/src/widget/DiagnosisDialog.cpp @@ -0,0 +1,103 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DiagnosisDialog.h" + +#include "context/DiagnosisContext.h" +#include "DiagnosisWidget.h" +#include "generic/HelpAction.h" +#include "ui_DiagnosisDialog.h" + +#include +#include +#include +#include + +using namespace governikus; + + +DiagnosisDialog::DiagnosisDialog(DiagnosisContext* pContext, QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::DiagnosisDialog) + , mDiagnosisWidget(new DiagnosisWidget(pContext, pParent)) +{ + mUi->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Diagnosis")); + + installEventFilter(this); + + mUi->diagnosisLayout->addWidget(mDiagnosisWidget); + + connect(mUi->saveButton, &QAbstractButton::clicked, this, &DiagnosisDialog::onSaveButtonClicked); + connect(mUi->closeButton, &QAbstractButton::clicked, this, &DiagnosisDialog::close); +} + + +DiagnosisDialog::~DiagnosisDialog() +{ +} + + +void DiagnosisDialog::onSaveButtonClicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, QCoreApplication::applicationName() + + QStringLiteral(" - ") + + tr("Save diagnosis result") + , QDir::homePath() + + QLatin1Char('/') + + tr("AusweisApp2-diagnosis.txt") +#ifndef Q_OS_MACOS + , tr("Text files (*.txt)")); +#else + , tr("Text files (*.txt)"), nullptr, QFileDialog::DontUseNativeDialog); +#endif + + if (fileName.isEmpty()) + { + return; + } + if (!fileName.endsWith(QLatin1String(".txt"), Qt::CaseSensitivity::CaseInsensitive)) + { + fileName += QStringLiteral(".txt"); + } + + QString text = mDiagnosisWidget->getInfoTextEdit(); +#ifdef Q_OS_WIN + text.replace(QLatin1Char('\n'), QStringLiteral("\r\n")); +#endif + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QFile::Truncate) || file.write(text.toUtf8()) < 0) + { + QMessageBox::warning(this, QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("File error"), tr("An error occurred while saving the file.")); + } +} + + +bool DiagnosisDialog::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QDialog::eventFilter(pObject, pEvent); +} + + +void DiagnosisDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DiagnosisDialog.h b/src/widget/DiagnosisDialog.h new file mode 100644 index 0000000..ac0e81c --- /dev/null +++ b/src/widget/DiagnosisDialog.h @@ -0,0 +1,44 @@ +/*! + * \brief Dialog for display the diagnosis information. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class DiagnosisDialog; +} + +namespace governikus +{ + +class DiagnosisContext; +class DiagnosisWidget; + +class DiagnosisDialog + : public QDialog +{ + Q_OBJECT + + private: + QScopedPointer mUi; + DiagnosisWidget* mDiagnosisWidget; + + private Q_SLOTS: + void onSaveButtonClicked(); + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + public: + DiagnosisDialog(DiagnosisContext* pContext, QWidget* pParent = nullptr); + virtual ~DiagnosisDialog() override; +}; + +} /* namespace governikus */ diff --git a/src/gui/DiagnosisDialog.ui b/src/widget/DiagnosisDialog.ui similarity index 100% rename from src/gui/DiagnosisDialog.ui rename to src/widget/DiagnosisDialog.ui diff --git a/src/widget/DiagnosisGui.cpp b/src/widget/DiagnosisGui.cpp new file mode 100644 index 0000000..b0bfba2 --- /dev/null +++ b/src/widget/DiagnosisGui.cpp @@ -0,0 +1,64 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DiagnosisGui.h" + + +#include "controller/DiagnosisController.h" +#include "DiagnosisWidget.h" + +using namespace governikus; + +DiagnosisGui::DiagnosisGui(QWidget* pParentWidget) + : QObject(pParentWidget) + , mDialog() +{ +} + + +DiagnosisGui::~DiagnosisGui() +{ +} + + +void DiagnosisGui::activate() +{ + if (mDialog) + { + if (mDialog->isMinimized()) + { + mDialog->showNormal(); + } + if (!mDialog->isVisible()) + { + mDialog->show(); + } + mDialog->activateWindow(); + mDialog->raise(); + return; + } + + QWidget* dialogParent = qobject_cast(parent()); + if (!dialogParent) + { + return; + } + + auto context = new DiagnosisContext(); + mDialog = new DiagnosisDialog(context, dialogParent); + connect(mDialog, &QDialog::finished, this, &DiagnosisGui::fireFinished); + mDialog->show(); + + auto controller = new DiagnosisController(context, mDialog); + controller->run(); +} + + +void DiagnosisGui::deactivate() +{ + if (mDialog) + { + mDialog->close(); + } +} diff --git a/src/widget/DiagnosisGui.h b/src/widget/DiagnosisGui.h new file mode 100644 index 0000000..4e74e60 --- /dev/null +++ b/src/widget/DiagnosisGui.h @@ -0,0 +1,36 @@ +/*! + * \brief Qt widget based DiagnosisUi implementation. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "DiagnosisDialog.h" + +#include +#include + +namespace governikus +{ + +class DiagnosisGui + : public QObject +{ + Q_OBJECT + + public: + DiagnosisGui(QWidget* pParentWidget); + virtual ~DiagnosisGui(); + + void activate(); + void deactivate(); + + Q_SIGNALS: + void fireFinished(); + + private: + QPointer mDialog; +}; + +} /* namespace governikus */ diff --git a/src/widget/DiagnosisWidget.cpp b/src/widget/DiagnosisWidget.cpp new file mode 100644 index 0000000..b4d33ea --- /dev/null +++ b/src/widget/DiagnosisWidget.cpp @@ -0,0 +1,410 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "DiagnosisWidget.h" + +#include "LanguageLoader.h" +#include "ui_DiagnosisWidget.h" + +#include +#include +#include +#include +#include +#include + +// Includes for version API +#include + +#include "BuildHelper.h" +#include "context/DiagnosisContext.h" +#include "generic/HelpAction.h" + +using namespace governikus; + +class DiagnosisWidget::Field +{ + public: + Field(QTextCursor& pCursor, const QString& pHeading, const QTextCharFormat& pPlainFormat, const QTextCharFormat& pHeadingFormat) + : mStart() + , mEnd() + { + pCursor.insertText(pHeading + QLatin1Char('\n'), pHeadingFormat); + mStart = pCursor; + mStart.setKeepPositionOnInsert(true); + pCursor.insertText(tr("Diagnosis is running..."), pPlainFormat); + mEnd = pCursor; + mEnd.setKeepPositionOnInsert(true); + pCursor.insertText(QStringLiteral("\n"), pPlainFormat); + } + + + void prepareSet() + { + mEnd.setKeepPositionOnInsert(false); + mEnd.clearSelection(); + mEnd.setPosition(mStart.position(), QTextCursor::KeepAnchor); + } + + + void finishSet() + { + mEnd.setKeepPositionOnInsert(true); + } + + + const QTextCursor& getCursor() const + { + return mEnd; + } + + + void setText(const QString& pText, const QTextCharFormat& pPlainFormat) + { + prepareSet(); + mEnd.insertText(pText, pPlainFormat); + finishSet(); + } + + + void setFragment(const QTextDocumentFragment& pFragment) + { + prepareSet(); + mEnd.insertFragment(pFragment); + finishSet(); + } + + + private: + QTextCursor mStart; + QTextCursor mEnd; +}; + +DiagnosisWidget::DiagnosisWidget(DiagnosisContext* pContext, QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::DiagnosisWidget) + , mContext(pContext) + , mOsField() + , mAppVersionField() + , mPcscField() + , mReadersField() + , mTimestampField() + , mPlainTextFormat() + , mHeadingTextFormat() + , mBasicBlockFormat() + , mOsVersionTreeItem(nullptr) + , mAppVersionTreeItem(nullptr) + , mReadersTreeItem(nullptr) + , mPcscTreeItem(nullptr) + , mReaderWaitItem(nullptr) + , mPcscWaitItem(nullptr) + , mTimestampItem(nullptr) +{ + mUi->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Diagnosis")); + + QTextCursor insertCursor(mUi->infoTextEdit->document()); + mPlainTextFormat = insertCursor.charFormat(); + mHeadingTextFormat = mPlainTextFormat; + mHeadingTextFormat.setFontWeight(QFont::Bold); + mBasicBlockFormat = insertCursor.blockFormat(); + + mOsField.reset(insertField(insertCursor, tr("Operating system"), true)); + mAppVersionField.reset(insertField(insertCursor, QCoreApplication::applicationName())); + mReadersField.reset(insertField(insertCursor, tr("Card reader"))); + mPcscField.reset(insertField(insertCursor, tr("PC/SC"))); + mTimestampField.reset(insertField(insertCursor, tr("Time of diagnosis"))); + + mOsVersionTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); + mOsVersionTreeItem->setText(0, tr("Operating system")); + mOsVersionTreeItem->setExpanded(true); + + (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::prettyProductName()); + (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::kernelVersion()); + (new QTreeWidgetItem(mOsVersionTreeItem))->setText(0, QSysInfo::currentCpuArchitecture()); + + QStringList fields; + fields << QSysInfo::prettyProductName(); + fields << QSysInfo::kernelVersion(); + fields << QSysInfo::currentCpuArchitecture(); + setFieldText(mOsField, fields.join(QLatin1Char('\n'))); + + mPcscWaitItem = new QTreeWidgetItem(mPcscTreeItem); + mPcscWaitItem->setText(0, tr("Diagnosis is running...")); + + mAppVersionTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); + mAppVersionTreeItem->setText(0, QCoreApplication::applicationName()); + mAppVersionTreeItem->setExpanded(true); + + mReadersTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); + mReadersTreeItem->setText(0, tr("Card reader")); + mReadersTreeItem->setExpanded(true); + mReaderWaitItem = new QTreeWidgetItem(mReadersTreeItem); + mReaderWaitItem->setText(0, tr("Diagnosis is running...")); + + mPcscTreeItem = new QTreeWidgetItem(mUi->infoTreeWidget); + mPcscTreeItem->setText(0, tr("PC/SC")); + mPcscTreeItem->setExpanded(true); + mPcscWaitItem = new QTreeWidgetItem(mPcscTreeItem); + mPcscWaitItem->setText(0, tr("Diagnosis is running...")); + + mTimestampItem = new QTreeWidgetItem(mUi->infoTreeWidget); + mTimestampItem->setExpanded(true); + mTimestampItem->setText(0, tr("Time of diagnosis")); + + const QStringList appVersion({ + QStringLiteral("%1 (%2)").arg(QCoreApplication::applicationVersion(), QString::fromLatin1(BuildHelper::getDateTime())), + QCoreApplication::organizationName(), + QStringLiteral("Qt ") + QString::fromLatin1(qVersion()), + QString::fromLatin1(SSLeay_version(0)) + }); + for (const auto& str : appVersion) + { + (new QTreeWidgetItem(mAppVersionTreeItem))->setText(0, str); + } + setFieldText(mAppVersionField, appVersion.join(QLatin1Char('\n'))); + + connect(mContext, &DiagnosisContext::pcscInfoChanged, this, &DiagnosisWidget::onPcscInfoChanged); + connect(mContext, &DiagnosisContext::readerInfosChanged, this, &DiagnosisWidget::onReaderInfosChanged); + connect(mContext, &DiagnosisContext::timestampChanged, this, &DiagnosisWidget::onTimestampChanged); + + mUi->infoTextEdit->setVisible(false); +} + + +DiagnosisWidget::~DiagnosisWidget() +{ +} + + +bool DiagnosisWidget::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QWidget::eventFilter(pObject, pEvent); +} + + +void DiagnosisWidget::onPcscInfoChanged() +{ + mPcscTreeItem->removeChild(mPcscWaitItem); + delete mPcscWaitItem; + mPcscWaitItem = nullptr; + + mPcscField->prepareSet(); + + QTextCursor insertCursor = mPcscField->getCursor(); + insertCursor.removeSelectedText(); + + //version + insertCursor.insertText(tr("Version: %1").arg(mContext->getPcscVersion()), mPlainTextFormat); + endBlockAndResetFormat(insertCursor); + (new QTreeWidgetItem(mPcscTreeItem))->setText(0, tr("Version: %1").arg(mContext->getPcscVersion())); + + //components + QTreeWidgetItem* componentTreeItem = new QTreeWidgetItem(mPcscTreeItem); + componentTreeItem->setText(0, tr("Components")); + insertComponentList(insertCursor, tr("Components:"), mContext->getPcscComponents(), componentTreeItem); + + //driver + QTreeWidgetItem* driverTreeItem = new QTreeWidgetItem(mPcscTreeItem); + driverTreeItem->setText(0, tr("Driver")); + insertComponentList(insertCursor, tr("Driver:"), mContext->getPcscDrivers(), driverTreeItem); + + mPcscField->finishSet(); + +} + + +void DiagnosisWidget::onReaderInfosChanged() +{ + mReadersTreeItem->removeChild(mReaderWaitItem); + delete mReaderWaitItem; + mReaderWaitItem = nullptr; + + const QVector& infos = mContext->getReaderInfos(); + if (infos.isEmpty()) + { + setFieldText(mReadersField, tr("not recognised")); + (new QTreeWidgetItem(mReadersTreeItem))->setText(0, tr("not recognised")); + return; + } + + mReadersField->prepareSet(); + + QTextCursor insertCursor = mReadersField->getCursor(); + insertCursor.removeSelectedText(); + QTextListFormat listFormat; + listFormat.setStyle(QTextListFormat::ListDisc); + QTextList* list = insertCursor.insertList(listFormat); + + bool isFirst = true; + for (const ReaderInfo& info : infos) + { + if (isFirst) + { + isFirst = false; + } + else + { + insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + } + + // Reset the indent. Otherwise each list element would be indented further. + QTextBlockFormat blockFormat = insertCursor.blockFormat(); + blockFormat.setIndent(0); + insertCursor.setBlockFormat(blockFormat); + + // reader name + insertCursor.insertText(info.getName(), mPlainTextFormat); + list->add(insertCursor.block()); + QTreeWidgetItem* readerTreeItem = new QTreeWidgetItem(mReadersTreeItem); + readerTreeItem->setText(0, info.getName()); + + insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + list->remove(insertCursor.block()); + + // reader type + QString readerType = info.isBasicReader() ? tr("Basic card reader") : tr("Standard / deluxe card reader"); + insertCursor.insertText(tr("Type: %1").arg(readerType), mPlainTextFormat); + (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Type: %1").arg(readerType)); + + // card type + QString cardType = info.getCardTypeString(); + + insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + insertCursor.insertText(tr("Card: %1").arg(cardType), mPlainTextFormat); + (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Card: %1").arg(cardType)); + + + // retry counter + if (info.hasEidCard()) + { + insertCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + insertCursor.insertText(tr("Retry counter: %1").arg(3 - info.getRetryCounter()), mPlainTextFormat); + (new QTreeWidgetItem(readerTreeItem))->setText(0, tr("Retry counter: %1").arg(3 - info.getRetryCounter())); + } + } + + mReadersField->finishSet(); +} + + +void DiagnosisWidget::onTimestampChanged() +{ + QString timestamp = LanguageLoader::getInstance().getUsedLocale().toString(mContext->getTimestamp(), tr("d. MMMM yyyy, hh:mm:ss AP")); + setFieldText(mTimestampField, timestamp); + (new QTreeWidgetItem(mTimestampItem))->setText(0, timestamp); + +} + + +QString DiagnosisWidget::getInfoTextEdit() +{ + return mUi->infoTextEdit->toPlainText(); +} + + +DiagnosisWidget::Field* DiagnosisWidget::insertField(QTextCursor& pCursor, const QString& pHeading, bool pIsFirstField) +{ + if (!pIsFirstField) + { + pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + } + + return new Field(pCursor, pHeading, mPlainTextFormat, mHeadingTextFormat); +} + + +void DiagnosisWidget::setFieldText(const QScopedPointer& pField, const QString& pText) +{ + pField->setText(pText, mPlainTextFormat); +} + + +void DiagnosisWidget::endBlockAndResetFormat(QTextCursor& pCursor) +{ + pCursor.insertText(QStringLiteral("\n")); + pCursor.setBlockFormat(mBasicBlockFormat); +} + + +void DiagnosisWidget::insertComponentList(QTextCursor& pCursor, const QString& pTitle, + const QVector& pComponents, QTreeWidgetItem* pParentTreeWidgetItem) +{ + if (pComponents.isEmpty()) + { + return; + } + + pCursor.insertText(pTitle, mPlainTextFormat); + + QTextListFormat listFormat; + listFormat.setStyle(QTextListFormat::ListDisc); + QTextList* list = pCursor.insertList(listFormat); + + bool isFirst = true; + for (const DiagnosisContext::ComponentInfo& info : pComponents) + { + if (isFirst) + { + isFirst = false; + } + else + { + pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + } + + // Reset the indent. Otherwise each list element would be indented further. + QTextBlockFormat blockFormat = pCursor.blockFormat(); + blockFormat.setIndent(0); + pCursor.setBlockFormat(blockFormat); + + // description + pCursor.insertText(info.getDescription(), mPlainTextFormat); + QTreeWidgetItem* descriptionTreeItem = new QTreeWidgetItem(pParentTreeWidgetItem); + descriptionTreeItem->setText(0, info.getDescription()); + + list->add(pCursor.block()); + + pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + list->remove(pCursor.block()); + + // company + pCursor.insertText(tr("Vendor: %1").arg(info.getManufacturer()), mPlainTextFormat); + (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("Vendor: %1").arg(info.getManufacturer())); + + // version + pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + pCursor.insertText(tr("Version: %1").arg(info.getVersion()), mPlainTextFormat); + (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("Version: %1").arg(info.getVersion())); + + // path + pCursor.insertText(QStringLiteral("\n"), mPlainTextFormat); + pCursor.insertText(tr("File path: %1").arg(info.getPath()), mPlainTextFormat); + (new QTreeWidgetItem(descriptionTreeItem))->setText(0, tr("File path: %1").arg(info.getPath())); + } + + endBlockAndResetFormat(pCursor); +} + + +void DiagnosisWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/DiagnosisWidget.h b/src/widget/DiagnosisWidget.h new file mode 100644 index 0000000..f2eb6fb --- /dev/null +++ b/src/widget/DiagnosisWidget.h @@ -0,0 +1,80 @@ +/*! + * \brief Widget for display the diagnosis information. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include + +#include "context/DiagnosisContext.h" + +namespace Ui +{ +class DiagnosisWidget; +} + +class QTextCursor; + +namespace governikus +{ + +class DiagnosisWidget + : public QWidget +{ + Q_OBJECT + + private: + class Field; + + private Q_SLOTS: + void onPcscInfoChanged(); + void onReaderInfosChanged(); + void onTimestampChanged(); + + private: + Field* insertField(QTextCursor& pCursor, const QString& pHeading, bool pIsFirstField = false); + void setFieldText(const QScopedPointer& pField, const QString& pText); + + void endBlockAndResetFormat(QTextCursor& pCursor); + void insertComponentList(QTextCursor& pCursor, const QString& pTitle, + const QVector& pComponents, QTreeWidgetItem* pParentTreeWidgetItem); + + void deleteItem(QTreeWidgetItem* pItem); + + private: + QScopedPointer mUi; + DiagnosisContext* mContext; + QScopedPointer mOsField; + QScopedPointer mAppVersionField; + QScopedPointer mPcscField; + QScopedPointer mReadersField; + QScopedPointer mTimestampField; + QTextCharFormat mPlainTextFormat; + QTextCharFormat mHeadingTextFormat; + QTextBlockFormat mBasicBlockFormat; + + QTreeWidgetItem* mOsVersionTreeItem; + QTreeWidgetItem* mAppVersionTreeItem; + QTreeWidgetItem* mReadersTreeItem; + QTreeWidgetItem* mPcscTreeItem; + QTreeWidgetItem* mReaderWaitItem; + QTreeWidgetItem* mPcscWaitItem; + QTreeWidgetItem* mTimestampItem; + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + public: + DiagnosisWidget(DiagnosisContext* pContext, QWidget* pParent = nullptr); + virtual ~DiagnosisWidget() override; + + QString getInfoTextEdit(); +}; + +} /* namespace governikus */ diff --git a/src/gui/DiagnosisWidget.ui b/src/widget/DiagnosisWidget.ui similarity index 100% rename from src/gui/DiagnosisWidget.ui rename to src/widget/DiagnosisWidget.ui diff --git a/src/widget/GeneralSettingsWidget.cpp b/src/widget/GeneralSettingsWidget.cpp new file mode 100644 index 0000000..026e4c6 --- /dev/null +++ b/src/widget/GeneralSettingsWidget.cpp @@ -0,0 +1,95 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "GeneralSettingsWidget.h" + +#include "ui_GeneralSettingsWidget.h" + +#include "AppSettings.h" +#include "Env.h" +#include "Service.h" +#include "UpdateWindow.h" + +using namespace governikus; + +GeneralSettingsWidget::GeneralSettingsWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::GeneralSettingsWidget()) +{ + mUi->setupUi(this); + + reset(); + + connect(mUi->autostartCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + connect(mUi->regularlyUpdateCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + connect(mUi->closeWindowCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + connect(mUi->saveHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + connect(mUi->updateCheckButton, &QCheckBox::clicked, this, &GeneralSettingsWidget::onUpdateCheckButtonClicked); + connect(mUi->keylessPasswordCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); +} + + +GeneralSettingsWidget::~GeneralSettingsWidget() +{ +} + + +void GeneralSettingsWidget::showEvent(QShowEvent* pEvent) +{ + disconnect(mUi->saveHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + mUi->saveHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); + connect(mUi->saveHistoryCheckBox, &QCheckBox::stateChanged, this, &GeneralSettingsWidget::onCheckBoxStateChanged); + + QWidget::showEvent(pEvent); +} + + +void GeneralSettingsWidget::apply() +{ + auto& historySettings = AppSettings::getInstance().getHistorySettings(); + historySettings.setEnabled(mUi->saveHistoryCheckBox->isChecked()); + historySettings.save(); + + auto& generalSettings = AppSettings::getInstance().getGeneralSettings(); + generalSettings.setAutoCloseWindowAfterAuthentication(mUi->closeWindowCheckBox->isChecked()); + generalSettings.setAutoStart(mUi->autostartCheckBox->isChecked()); + generalSettings.setAutoUpdateCheck(mUi->regularlyUpdateCheckBox->isChecked()); + generalSettings.setUseScreenKeyboard(mUi->keylessPasswordCheckBox->isChecked()); + generalSettings.save(); +} + + +void GeneralSettingsWidget::reset() +{ + const auto& historySettings = AppSettings::getInstance().getHistorySettings(); + mUi->saveHistoryCheckBox->setChecked(historySettings.isEnabled()); + + const auto& generalSettings = AppSettings::getInstance().getGeneralSettings(); + mUi->closeWindowCheckBox->setChecked(generalSettings.isAutoCloseWindowAfterAuthentication()); + mUi->autostartCheckBox->setChecked(generalSettings.isAutoStart()); + mUi->regularlyUpdateCheckBox->setChecked(generalSettings.isAutoUpdateCheck()); + mUi->keylessPasswordCheckBox->setChecked(generalSettings.isUseScreenKeyboard()); +} + + +void GeneralSettingsWidget::onCheckBoxStateChanged(int) +{ + Q_EMIT settingsChanged(); +} + + +void GeneralSettingsWidget::onUpdateCheckButtonClicked() +{ + Env::getSingleton()->updateApp(true); +} + + +void GeneralSettingsWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/GeneralSettingsWidget.h b/src/widget/GeneralSettingsWidget.h new file mode 100644 index 0000000..58c050d --- /dev/null +++ b/src/widget/GeneralSettingsWidget.h @@ -0,0 +1,49 @@ +/*! + * \brief Widget for the general settings. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "GlobalStatus.h" + +#include +#include + +namespace Ui +{ +class GeneralSettingsWidget; +} + +namespace governikus +{ + +class GeneralSettingsWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + private Q_SLOTS: + void onCheckBoxStateChanged(int pState); + void onUpdateCheckButtonClicked(); + virtual void showEvent(QShowEvent*) override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + GeneralSettingsWidget(QWidget* pParent = nullptr); + virtual ~GeneralSettingsWidget() override; + + void apply(); + void reset(); + + Q_SIGNALS: + void settingsChanged(); +}; + +} /* namespace governikus */ diff --git a/src/widget/GeneralSettingsWidget.ui b/src/widget/GeneralSettingsWidget.ui new file mode 100644 index 0000000..fad6039 --- /dev/null +++ b/src/widget/GeneralSettingsWidget.ui @@ -0,0 +1,217 @@ + + + GeneralSettingsWidget + + + + 0 + 0 + 431 + 206 + + + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + Qt::TabFocus + + + Software update: + + + + + + + true + + + check software update on program start + + + check on program start + + + true + + + + + + + true + + + + 0 + 0 + + + + search for updates + + + + + + + Qt::Horizontal + + + + + + + Qt::TabFocus + + + History: + + + + + + + save history + + + save + + + + + + + Qt::Horizontal + + + + + + + + 50 + false + + + + Qt::TabFocus + + + Start AusweisApp2 automatically: + + + + + + + Start AusweisApp2 automatically on system startup + + + on system start + + + + + + + Qt::Horizontal + + + + + + + Qt::TabFocus + + + Close AusweisApp2 window automatically: + + + saveHistoryCheckBox + + + + + + + Close AusweisApp2 window automatically after successful identification + + + after successful identification + + + + + + + Qt::Horizontal + + + + + + + Qt::TabFocus + + + On screen password: + + + keylessPasswordCheckBox + + + + + + + use on screen password + + + use + + + + + + + + + + Qt::Vertical + + + + 20 + 2 + + + + + + + + + diff --git a/src/widget/GuiProfile.cpp b/src/widget/GuiProfile.cpp new file mode 100644 index 0000000..582390e --- /dev/null +++ b/src/widget/GuiProfile.cpp @@ -0,0 +1,56 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "GuiProfile.h" + +using namespace governikus; + +GuiProfile GuiProfile::mProfile; + +GuiProfile::GuiProfile() + : mShowWindow(false) + , mDebugStyleSheet() +{ +} + + +GuiProfile::~GuiProfile() +{ +} + + +bool GuiProfile::getShowWindow() const +{ + return mShowWindow; +} + + +void GuiProfile::setShowWindow(bool pShow) +{ + mShowWindow = pShow; +} + + +const QString& GuiProfile::getDebugStyleSheet() const +{ + return mDebugStyleSheet; +} + + +void GuiProfile::setDebugStyleSheet(const QString& pStyleSheet) +{ + mDebugStyleSheet = pStyleSheet; +} + + +QLatin1String GuiProfile::getStyleSheetName() +{ +#if defined(Q_OS_MACOS) + return QLatin1String("macos.qss"); + +#else + return QLatin1String("windows.qss"); + +#endif +} diff --git a/src/widget/GuiProfile.h b/src/widget/GuiProfile.h new file mode 100644 index 0000000..86585e8 --- /dev/null +++ b/src/widget/GuiProfile.h @@ -0,0 +1,45 @@ +/*! + * \brief Singleton GuiProfile specifies platform specific customizations the + * GUI. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "EnumHelper.h" + +#include +#include + +namespace governikus +{ + +class GuiProfile +{ + public: + GuiProfile(); + ~GuiProfile(); + + private: + static GuiProfile mProfile; + + bool mShowWindow; + QString mDebugStyleSheet; + + public: + static GuiProfile& getProfile() + { + return mProfile; + } + + + void setDebugStyleSheet(const QString& pStyleSheet); + void setShowWindow(bool pShow); + + bool getShowWindow() const; + const QString& getDebugStyleSheet() const; + QLatin1String getStyleSheetName(); +}; + +} /* namespace governikus */ diff --git a/src/widget/HistoryDetailWidget.cpp b/src/widget/HistoryDetailWidget.cpp new file mode 100644 index 0000000..1600556 --- /dev/null +++ b/src/widget/HistoryDetailWidget.cpp @@ -0,0 +1,49 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "HistoryDetailWidget.h" + +#include "ui_HistoryDetailWidget.h" + +#include + +using namespace governikus; + + +HistoryDetailWidget::HistoryDetailWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::HistoryDetailWidget()) +{ + mUi->setupUi(this); +} + + +HistoryDetailWidget::~HistoryDetailWidget() +{ +} + + +void HistoryDetailWidget::setDetails(const QString& pDetails) +{ + mUi->detailText->setText(pDetails); +} + + +void HistoryDetailWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void HistoryDetailWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/HistoryDetailWidget.h b/src/widget/HistoryDetailWidget.h new file mode 100644 index 0000000..bf71dfc --- /dev/null +++ b/src/widget/HistoryDetailWidget.h @@ -0,0 +1,40 @@ +/*! + * \brief Widget for history item. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class HistoryDetailWidget; +} + +namespace governikus +{ + +class HistoryDetailWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + virtual void paintEvent(QPaintEvent*) override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + HistoryDetailWidget(QWidget* pParent = nullptr); + virtual ~HistoryDetailWidget() override; + + void setDetails(const QString& pDetails); +}; + +} /* namespace governikus */ diff --git a/src/widget/HistoryDetailWidget.ui b/src/widget/HistoryDetailWidget.ui new file mode 100644 index 0000000..e698d82 --- /dev/null +++ b/src/widget/HistoryDetailWidget.ui @@ -0,0 +1,51 @@ + + + HistoryDetailWidget + + + + 0 + 0 + 595 + 450 + + + + Qt::TabFocus + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::TabFocus + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + diff --git a/src/widget/HistoryWidget.cpp b/src/widget/HistoryWidget.cpp new file mode 100644 index 0000000..6ed5eff --- /dev/null +++ b/src/widget/HistoryWidget.cpp @@ -0,0 +1,328 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "HistoryWidget.h" + +#include "ui_HistoryWidget.h" + +#include "AppSettings.h" +#include "DeleteHistoryDialog.h" +#include "DetailDialog.h" +#include "generic/ListCheckItemWidget.h" +#include "generic/ListItem.h" +#include "generic/ListItemIconLeft.h" +#include "generic/ListItemIconRight.h" +#include "generic/ListItemSubTitle.h" +#include "generic/ListItemTitle.h" +#include "LanguageLoader.h" +#include "PdfExporter.h" +#include "ScopeGuard.h" + +#include +#include +#include +#include + +using namespace governikus; + + +HistoryWidget::HistoryWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::HistoryWidget()) + , mHistoryDetailWidget(nullptr) +{ + mUi->setupUi(this); + + connect(mUi->historyDeleteButton, &QPushButton::clicked, this, &HistoryWidget::deleteHistory); + connect(mUi->historySearch, &QLineEdit::textChanged, this, &HistoryWidget::searchHistory); + connect(mUi->historyExportButton, &QPushButton::clicked, this, &HistoryWidget::exportHistory); + connect(mUi->historyTableWidget, &QTableWidget::doubleClicked, this, &HistoryWidget::onItemClicked); + connect(mUi->saveHistoryCheckBox, &QCheckBox::stateChanged, this, &HistoryWidget::onCheckBoxStateChanged); + mUi->saveHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); + + connect(&AppSettings::getInstance().getHistorySettings(), &HistorySettings::fireHistoryInfosChanged, this, &HistoryWidget::updateTable); + connect(&AppSettings::getInstance().getHistorySettings(), &HistorySettings::fireEnabledChanged, this, [this](bool pValue){ + mUi->saveHistoryCheckBox->setChecked(pValue); + }); + + init(); +} + + +HistoryWidget::~HistoryWidget() +{ +} + + +void HistoryWidget::init() +{ + QStringList header; + header += tr("Date"); + header += tr("Details"); + + mUi->historyTableWidget->setColumnCount(header.count()); + mUi->historyTableWidget->setHorizontalHeaderLabels(header); + mUi->historyTableWidget->verticalHeader()->setVisible(false); //Hide row number + mUi->historyTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //Not allowed to change content + mUi->historyTableWidget->setSortingEnabled(false); + mUi->historyTableWidget->installEventFilter(this); + + mUi->noResultWidget->setVisible(false); + updateTable(); +} + + +QWidget* HistoryWidget::getDetailActivatingWidget() const +{ + return mUi->historyTableWidget; +} + + +void HistoryWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void HistoryWidget::onCheckBoxStateChanged(int /*pState*/) +{ + auto& historySettings = AppSettings::getInstance().getHistorySettings(); + historySettings.setEnabled(mUi->saveHistoryCheckBox->isChecked()); + historySettings.save(); +} + + +void HistoryWidget::updateTable() +{ + const auto& items = AppSettings::getInstance().getHistorySettings().getHistoryInfos(); + + const ScopeGuard guard([this] { + mUi->historyTableWidget->setUpdatesEnabled(true); + }); + + mUi->historyTableWidget->setUpdatesEnabled(false); + mUi->historyTableWidget->clearContents(); + mUi->historyTableWidget->setRowCount(0); + + for (const HistoryInfo& info : items) + { + int rowIndex = mUi->historyTableWidget->rowCount(); + mUi->historyTableWidget->insertRow(rowIndex); + + //date column with needed properties + const auto& dateTime = LanguageLoader::getInstance().getUsedLocale().toString(info.getDateTime(), tr("dd.MM.yyyy hh:mm AP")); + QLabel* dateLabel = new QLabel(dateTime); + dateLabel->setContentsMargins(11, 11, 11, 11); + dateLabel->setAlignment(Qt::AlignTop); + dateLabel->setProperty("termsOfUsage", info.getTermOfUsage()); + dateLabel->setProperty("date", dateTime); + + dateLabel->setFocusPolicy(Qt::TabFocus); + dateLabel->setAccessibleName(tr("Date:") + dateTime); + + mUi->historyTableWidget->setCellWidget(rowIndex, 0, dateLabel); + + //details column with needed properties + QWidget* centralWidget = new QWidget(); + + QFormLayout* centralLayout = new QFormLayout(centralWidget); + centralLayout->setSpacing(6); + centralLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + + const auto& bold = QStringLiteral("%1:"); + QLabel* providerLabel = new QLabel(bold.arg(tr("Provider"))); + providerLabel->setFocusPolicy(Qt::TabFocus); + centralLayout->setWidget(0, QFormLayout::LabelRole, providerLabel); + + QLabel* providerField = new QLabel(info.getSubjectName()); + providerField->setFocusPolicy(Qt::TabFocus); + centralLayout->setWidget(0, QFormLayout::FieldRole, providerField); + + centralWidget->setProperty("provider", info.getSubjectName()); + + QLabel* purposeLabel = new QLabel(bold.arg(tr("Purpose"))); + purposeLabel->setFocusPolicy(Qt::TabFocus); + centralLayout->setWidget(1, QFormLayout::LabelRole, purposeLabel); + + QLabel* purposeField = new QLabel(info.getPurpose()); + purposeField->setFocusPolicy(Qt::TabFocus); + centralLayout->setWidget(1, QFormLayout::FieldRole, purposeField); + + centralWidget->setProperty("usage", info.getPurpose()); + + QLabel* dataLabel = new QLabel(bold.arg(tr("Data"))); + dataLabel->setFocusPolicy(Qt::TabFocus); + dataLabel->setAlignment(Qt::AlignTop); + centralLayout->setWidget(2, QFormLayout::LabelRole, dataLabel); + + QLabel* requestedDataLabel = new QLabel(info.getRequestedData().trimmed()); + requestedDataLabel->setWordWrap(true); + requestedDataLabel->setFocusPolicy(Qt::TabFocus); + centralLayout->setWidget(2, QFormLayout::FieldRole, requestedDataLabel); + + centralWidget->setProperty("requestedData", info.getRequestedData()); + + mUi->historyTableWidget->setCellWidget(rowIndex, 1, centralWidget); + } + + mUi->historyTableWidget->resizeRowsToContents(); + mUi->historyTableWidget->sortByColumn(dateColumn); // Sort by date +} + + +bool HistoryWidget::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + 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) + { + QWidget* tmpWidget = mUi->historyTableWidget->cellWidget(index.row(), dateColumn); + DetailDialog d(this); + d.setDetails(tmpWidget->property("termsOfUsage").toString()); + d.exec(); + } + return true; + } + } + + return QWidget::eventFilter(pObject, pEvent); +} + + +void HistoryWidget::deleteHistory() +{ + DeleteHistoryDialog* deleteHistoryDialog = new DeleteHistoryDialog(this); + if (deleteHistoryDialog->exec() == QDialog::Rejected) + { + return; + } + + QDateTime latestToKeep = QDateTime::currentDateTime(); + switch (deleteHistoryDialog->getTimePeriod()) + { + case TimePeriod::PAST_HOUR: + latestToKeep = latestToKeep.addSecs(-60 * 60); + break; + + case TimePeriod::PAST_DAY: + latestToKeep = latestToKeep.addDays(-1); + break; + + case TimePeriod::PAST_WEEK: + latestToKeep = latestToKeep.addDays(-7); + break; + + case TimePeriod::LAST_FOUR_WEEKS: + latestToKeep = latestToKeep.addDays(-7 * 4); + break; + + case TimePeriod::ALL_HISTORY: + latestToKeep = QDateTime(); + break; + } + + auto& settings = AppSettings::getInstance().getHistorySettings(); + settings.deleteSettings(latestToKeep); + settings.save(); +} + + +void HistoryWidget::exportHistory() +{ + QString filename = tr("AusweisApp2.History.%1.pdf").arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd"))); + filename = QFileDialog::getSaveFileName(this, + QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Save"), + QDir::homePath() + QLatin1Char('/') + filename, +#ifndef Q_OS_MACOS + tr("PDF Documents") + QStringLiteral(" (*.pdf)")); +#else + tr("PDF Documents") + QStringLiteral(" (*.pdf)"), nullptr, QFileDialog::DontUseNativeDialog); +#endif + + PdfExporter exporter(filename); + exporter.exportHistory(); +} + + +void HistoryWidget::searchHistory() +{ + mUi->historyTableWidget->setVisible(true); + mUi->noResultWidget->setVisible(false); + + if (mUi->historySearch->text().isEmpty()) + { + for (int i = 0; i < mUi->historyTableWidget->rowCount(); ++i) + { + mUi->historyTableWidget->setRowHidden(i, false); + } + return; + } + + bool anyMatch = false; + + for (int i = 0; i < mUi->historyTableWidget->rowCount(); ++i) + { + bool match = false; + for (int j = 0; j < mUi->historyTableWidget->columnCount(); ++j) + { + QString tmpData; + QWidget* tmpWidget = mUi->historyTableWidget->cellWidget(i, j); + if (j == dateColumn) + { + tmpData = tmpWidget->property("date").toString(); + } + else + { + tmpData = tmpWidget->property("provider").toString() + QLatin1Char(' ') + tmpWidget->property("usage").toString() + QLatin1Char(' ') + tmpWidget->property("requestedData").toString(); + } + + if (tmpData.contains(mUi->historySearch->text(), Qt::CaseInsensitive)) + { + match = true; + anyMatch = true; + break; + } + } + mUi->historyTableWidget->setRowHidden(i, !match); + + } + + mUi->historyTableWidget->setVisible(anyMatch); + mUi->noResultWidget->setVisible(!anyMatch); +} + + +void HistoryWidget::onItemClicked(const QModelIndex& pIndex) +{ + QModelIndex idx = pIndex; + + qDebug() << "selected model index: " << idx; + + if (pIndex.isValid()) + { + QWidget* tmpWidget = mUi->historyTableWidget->cellWidget(idx.row(), dateColumn); + DetailDialog d(this); + d.setDetails(tmpWidget->property("termsOfUsage").toString()); + d.exec(); + } +} + + +void HistoryWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + init(); + searchHistory(); + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/HistoryWidget.h b/src/widget/HistoryWidget.h new file mode 100644 index 0000000..b3d658a --- /dev/null +++ b/src/widget/HistoryWidget.h @@ -0,0 +1,61 @@ +/*! + * \brief Show history entries. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui +{ +class HistoryWidget; +} + +namespace governikus +{ + +class HistoryDetailWidget; + +class HistoryWidget + : public QWidget +{ + Q_OBJECT + + private: + static const int dateColumn = 0; + QScopedPointer mUi; + HistoryDetailWidget* mHistoryDetailWidget; + virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; + virtual void paintEvent(QPaintEvent*) override; + void init(); + + private Q_SLOTS: + void updateTable(); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + HistoryWidget(QWidget* pParent = nullptr); + virtual ~HistoryWidget() override; + QWidget* getDetailActivatingWidget() const; + + public Q_SLOTS: + void onCheckBoxStateChanged(int pState); + void deleteHistory(); + void exportHistory(); + void searchHistory(); + void onItemClicked(const QModelIndex& pIndex); +}; + +} /* namespace governikus */ diff --git a/src/widget/HistoryWidget.ui b/src/widget/HistoryWidget.ui new file mode 100644 index 0000000..7f682c4 --- /dev/null +++ b/src/widget/HistoryWidget.ui @@ -0,0 +1,200 @@ + + + HistoryWidget + + + + 0 + 0 + 599 + 666 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::TabFocus + + + 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. + + + true + + + + + + + + + Qt::TabFocus + + + Search: + + + + + + + Please enter your search + + + Please enter your search + + + + + + + + + + + + QAbstractScrollArea::AdjustToContents + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectItems + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + true + + + 150 + + + false + + + true + + + + + + + + 5 + + + + + No matching history entries were found. Please modify your search criteria. + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Qt::TabFocus + + + save history: + + + History: + + + + + + + save history + + + + + + save + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete history... + + + + + + + save history as PDF + + + Save as PDF... + + + + + + + + + + + + diff --git a/src/widget/LogFilesDialog.cpp b/src/widget/LogFilesDialog.cpp new file mode 100644 index 0000000..51d15a5 --- /dev/null +++ b/src/widget/LogFilesDialog.cpp @@ -0,0 +1,219 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "LanguageLoader.h" +#include "LogFilesDialog.h" +#include "ui_LogFilesDialog.h" + +#include "generic/HelpAction.h" +#include "LogHandler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(gui) + +using namespace governikus; + + +LogFilesDialog::LogFilesDialog(QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::LogFilesDialog) +{ + mUi->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinMaxButtonsHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Log")); + + connect(mUi->saveButton, &QAbstractButton::clicked, this, &LogFilesDialog::onSaveButtonClicked); + connect(mUi->deleteButton, &QAbstractButton::clicked, this, &LogFilesDialog::onDeleteButtonClicked); + connect(mUi->closeButton, &QAbstractButton::clicked, this, &LogFilesDialog::close); + + init(); +} + + +LogFilesDialog::~LogFilesDialog() +{ +} + + +void LogFilesDialog::init() +{ + mUi->logFilesComboBox->clear(); + + auto model = new QStandardItemModel(this); + mUi->logFilesComboBox->setModel(model); + + const auto& otherLogs = LogHandler::getInstance().getOtherLogfiles(); + QList items; + items.reserve(otherLogs.size() + 1); + items << new QStandardItem(tr("Current log")); + for (const auto& entry : otherLogs) + { + auto date = LogHandler::getFileDate(entry); + auto item = new QStandardItem(LanguageLoader::getInstance().getUsedLocale().toString(date, tr("dd.MM.yyyy hh:mm:ss AP"))); + item->setData(date, Qt::UserRole); + item->setData(entry.absoluteFilePath()); + items << item; + } + + mUi->logFilesComboBox->setEnabled(!otherLogs.isEmpty()); + mUi->deleteButton->setEnabled(!otherLogs.isEmpty()); + + model->invisibleRootItem()->appendRows(items); + model->setSortRole(Qt::UserRole); + model->sort(0, Qt::DescendingOrder); + + connect(mUi->logFilesComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &LogFilesDialog::onCurrentIndexChanged); + + mUi->plainTextEdit->clear(); + appendLoggingDump(QString::fromUtf8(LogHandler::getInstance().getBacklog()).toHtmlEscaped()); + mUi->plainTextEdit->moveCursor(QTextCursor::Start); + connect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); +} + + +void LogFilesDialog::appendLoggingDump(const QString& pLog) +{ + mUi->plainTextEdit->appendHtml(QStringLiteral("
%1
").arg(pLog)); +} + + +void LogFilesDialog::doLogMsg(const QString& pMsg) +{ + appendLoggingDump(pMsg.toHtmlEscaped()); +} + + +void LogFilesDialog::onCurrentIndexChanged(int pIndex) +{ + mUi->plainTextEdit->clear(); + if (pIndex == 0) + { + connect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); + + appendLoggingDump(QString::fromUtf8(LogHandler::getInstance().getBacklog()).toHtmlEscaped()); + mUi->plainTextEdit->moveCursor(QTextCursor::Start); + } + else + { + disconnect(&LogHandler::getInstance(), &LogHandler::fireLog, this, &LogFilesDialog::doLogMsg); + + QFile file(mUi->logFilesComboBox->itemData(pIndex, Qt::UserRole + 1).toString()); + if (file.size() < 3145728) + { + if (file.open(QIODevice::ReadOnly)) + { + appendLoggingDump(QString::fromUtf8(file.readAll())); + } + else + { + appendLoggingDump(tr("File could not be opened: ") + file.fileName()); + } + } + else + { + appendLoggingDump(tr("File is larger than 3 MB and can not be displayed: ") + file.fileName()); + } + } +} + + +void LogFilesDialog::onDeleteButtonClicked() +{ + QMessageBox::StandardButton reply = QMessageBox::question(this, tr("Delete log files"), tr("Do you really want to delete all old log files?"), QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) + { + LogHandler::getInstance().removeOtherLogfiles(); + init(); + } +} + + +void LogFilesDialog::onSaveButtonClicked() +{ + const int index = mUi->logFilesComboBox->currentIndex(); + + QString source; + if (index != 0) + { + source = mUi->logFilesComboBox->itemData(index, Qt::UserRole + 1).toString(); + } + + saveLogFile(this, source); +} + + +bool LogFilesDialog::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QDialog::eventFilter(pObject, pEvent); +} + + +void LogFilesDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} + + +void LogFilesDialog::saveLogFile(QWidget* pParent, const QString& pSource) +{ + const QDateTime creationDateTime = pSource.isEmpty() ? LogHandler::getInstance().getCurrentLogfileDate() : LogHandler::getFileDate(pSource); + + QString filename = QStringLiteral("AusweisApp2.%1.log").arg(creationDateTime.toString(QStringLiteral("yyyy-MM-dd_HH-mm"))); + filename = QFileDialog::getSaveFileName(pParent, + QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Save"), + QDir::homePath() + QLatin1Char('/') + filename, +#ifndef Q_OS_MACOS + QStringLiteral("*.log")); +#else + QStringLiteral("*.log"), nullptr, QFileDialog::DontUseNativeDialog); +#endif + if (!filename.isEmpty()) // if user does not select "cancel" + { + if (!filename.endsWith(QLatin1String(".log"), Qt::CaseSensitivity::CaseInsensitive) + && !filename.endsWith(QLatin1String(".txt"), Qt::CaseSensitivity::CaseInsensitive)) + { + filename += QStringLiteral(".log"); + } + + qCDebug(gui) << "File location:" << filename; + + if (QFile::exists(filename)) + { + bool deleted = QFile::remove(filename); + qCDebug(gui) << "Delete file location:" << deleted; + } + + bool copied = pSource.isEmpty() ? LogHandler::getInstance().copy(filename) : QFile::copy(pSource, filename); + qCDebug(gui) << "Copy log to file location:" << copied; + if (!copied) + { + QMessageBox::warning(pParent, QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("File error"), tr("An error occurred while saving the file.")); + } + } +} diff --git a/src/widget/LogFilesDialog.h b/src/widget/LogFilesDialog.h new file mode 100644 index 0000000..02cc0e2 --- /dev/null +++ b/src/widget/LogFilesDialog.h @@ -0,0 +1,48 @@ +/*! + * \brief Dialog for display the old log files. + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class LogFilesDialog; +} + +namespace governikus +{ + +class LogFilesDialog + : public QDialog +{ + Q_OBJECT + + public: + static void saveLogFile(QWidget* pParent, const QString& pSource = QString()); + + LogFilesDialog(QWidget* pParent = nullptr); + virtual ~LogFilesDialog() override; + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + + void init(); + void appendLoggingDump(const QString& pLog); + + private Q_SLOTS: + void doLogMsg(const QString& pMsg); + void onSaveButtonClicked(); + void onCurrentIndexChanged(int pIndex); + void onDeleteButtonClicked(); +}; + +} /* namespace governikus */ diff --git a/src/gui/LogFilesDialog.ui b/src/widget/LogFilesDialog.ui similarity index 100% rename from src/gui/LogFilesDialog.ui rename to src/widget/LogFilesDialog.ui diff --git a/src/widget/PinSettingsInfoWidget.cpp b/src/widget/PinSettingsInfoWidget.cpp new file mode 100644 index 0000000..a437342 --- /dev/null +++ b/src/widget/PinSettingsInfoWidget.cpp @@ -0,0 +1,54 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PinSettingsInfoWidget.h" +#include "ui_PinSettingsInfoWidget.h" + +#include + +using namespace governikus; + + +PinSettingsInfoWidget::PinSettingsInfoWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::PinSettingsInfoWidget()) +{ + mUi->setupUi(this); +} + + +PinSettingsInfoWidget::~PinSettingsInfoWidget() +{ +} + + +void PinSettingsInfoWidget::setInfoTitle(const QString& pTitle) +{ + mUi->infoTitle->setText(pTitle); +} + + +void PinSettingsInfoWidget::setInfoDescription(const QString& pDescription) +{ + mUi->infoDescription->setText(pDescription); +} + + +void PinSettingsInfoWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void PinSettingsInfoWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/PinSettingsInfoWidget.h b/src/widget/PinSettingsInfoWidget.h new file mode 100644 index 0000000..73f59da --- /dev/null +++ b/src/widget/PinSettingsInfoWidget.h @@ -0,0 +1,41 @@ +/*! + * \brief Widget for PIN settings information. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class PinSettingsInfoWidget; +} + +namespace governikus +{ + +class PinSettingsInfoWidget + : public QWidget +{ + Q_OBJECT + + public: + PinSettingsInfoWidget(QWidget* pParent = nullptr); + virtual ~PinSettingsInfoWidget() override; + + void setInfoTitle(const QString& pTitle); + void setInfoDescription(const QString& pDescription); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + + virtual void paintEvent(QPaintEvent*) override; +}; + +} /* namespace governikus */ diff --git a/src/widget/PinSettingsInfoWidget.ui b/src/widget/PinSettingsInfoWidget.ui new file mode 100644 index 0000000..102dd16 --- /dev/null +++ b/src/widget/PinSettingsInfoWidget.ui @@ -0,0 +1,80 @@ + + + PinSettingsInfoWidget + + + + 0 + 0 + 313 + 96 + + + + + 0 + + + 16 + + + 0 + + + 0 + + + + + + + + 75 + true + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + diff --git a/src/widget/PinSettingsWidget.cpp b/src/widget/PinSettingsWidget.cpp new file mode 100644 index 0000000..0ca6a50 --- /dev/null +++ b/src/widget/PinSettingsWidget.cpp @@ -0,0 +1,746 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PinSettingsWidget.h" + +#include "Env.h" +#include "generic/PasswordEdit.h" +#include "RandomPinDialog.h" +#include "ReaderConfiguration.h" +#include "ReaderInfo.h" +#include "ReaderManager.h" +#include "SmartCardDefinitions.h" +#include "ui_PinSettingsWidget.h" + +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(gui) + +using namespace governikus; + +PinSettingsWidget::PinSettingsWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::PinSettingsWidget()) + , mMode(Mode::Normal) + , mRetryCounter(3) + , mPinDeactivated(false) + , mPinButtonEnabled(false) + , mPinSettingsInfoTitle() + , mPinSettingsInfoDescription() + , mRandomPinDialog() +{ + mUi->setupUi(this); + + QRegularExpression onlyNumbersExpression(QStringLiteral("[0-9]*")); + + mUi->canEdit->setMaxLength(6); + mUi->canEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); + connect(mUi->canEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onCanTextEdited); + + mUi->oldPinEdit->setMaxLength(6); + mUi->oldPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); + connect(mUi->oldPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onOldPinTextEdited); + connect(mUi->oldPinEdit, &PasswordEdit::fireBackspacePressedAndEmpty, this, [this] { + if (mUi->canEdit->isVisible()) + { + mUi->canEdit->removeLastCharacter(); + mUi->canEdit->setFocus(); + } + }); + + mUi->newPinEdit->setMaxLength(6); + mUi->newPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); + connect(mUi->newPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onNewPinTextEdited); + connect(mUi->newPinEdit, &PasswordEdit::fireBackspacePressedAndEmpty, this, [this] { + mUi->oldPinEdit->removeLastCharacter(); + mUi->oldPinEdit->setFocus(); + }); + + mUi->repeatNewPinEdit->setMaxLength(6); + mUi->repeatNewPinEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); + connect(mUi->repeatNewPinEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onRepeatNewPinTextEdited); + connect(mUi->repeatNewPinEdit, &PasswordEdit::fireBackspacePressedAndEmpty, this, [this] { + mUi->newPinEdit->removeLastCharacter(); + mUi->newPinEdit->setFocus(); + }); + + mUi->pukEdit->setMaxLength(10); + mUi->pukEdit->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); + connect(mUi->pukEdit, &PasswordEdit::textEdited, this, &PinSettingsWidget::onPukTextEdited); + + mUi->canRandomPinButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + mUi->canRandomPinButton->setIconSize(QSize(44, 26)); + connect(mUi->canRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); + + mUi->oldRandomPinButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + mUi->oldRandomPinButton->setIconSize(QSize(44, 26)); + connect(mUi->oldRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); + + mUi->newRandomPinButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + mUi->newRandomPinButton->setIconSize(QSize(44, 26)); + connect(mUi->newRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); + + mUi->repeatNewRandomPinButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + mUi->repeatNewRandomPinButton->setIconSize(QSize(44, 26)); + connect(mUi->repeatNewRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPinButtonClicked); + + mUi->pukRandomPinButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + mUi->pukRandomPinButton->setIconSize(QSize(44, 26)); + connect(mUi->pukRandomPinButton, &QAbstractButton::clicked, this, &PinSettingsWidget::onRandomPukButtonClicked); +} + + +PinSettingsWidget::~PinSettingsWidget() +{ +} + + +void PinSettingsWidget::setInProgress(bool pInProgress) +{ + if (pInProgress) + { + if (mUi->stackedWidget->currentWidget() == mUi->changePinComfortPage) + { + mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortDetailsInProgressPage); + mPinSettingsInfoDescription = mUi->changePinComfortInProgressLabel->text(); + } + else if (mUi->stackedWidget->currentWidget() == mUi->changePinBasicPage) + { + mUi->canEdit->setEnabled(false); + mUi->oldPinEdit->setEnabled(false); + mUi->newPinEdit->setEnabled(false); + mUi->repeatNewPinEdit->setEnabled(false); + mUi->canRandomPinButton->setEnabled(false); + mUi->oldRandomPinButton->setEnabled(false); + mUi->newRandomPinButton->setEnabled(false); + mUi->repeatNewRandomPinButton->setEnabled(false); + } + } +} + + +QString PinSettingsWidget::getCan() const +{ + return mUi->canEdit->text(); +} + + +QString PinSettingsWidget::getPin() const +{ + return mUi->oldPinEdit->text(); +} + + +QString PinSettingsWidget::getPuk() const +{ + return mUi->pukEdit->text(); +} + + +QString PinSettingsWidget::getNewPin() const +{ + return mUi->newPinEdit->text(); +} + + +void PinSettingsWidget::setMode(PinSettingsWidget::Mode pMode) +{ + mMode = pMode; +} + + +QString PinSettingsWidget::getButtonText() const +{ + return mRetryCounter == 0 && !mPinDeactivated ? tr("Enter PUK") : tr("Change PIN"); +} + + +QVector PinSettingsWidget::getReaderWithNPA(const QVector& pReaderInfos) +{ + QVector readersWithNPA; + for (const ReaderInfo& readerInfo : pReaderInfos) + { + if (readerInfo.hasEidCard()) + { + readersWithNPA += readerInfo; + } + } + + return readersWithNPA; +} + + +void PinSettingsWidget::updateReadersWithoutNPA(const QVector& pReaderInfos) +{ + mMode = Mode::Normal; + mUi->headerStackedWidget->setCurrentWidget(mUi->errorNoNpaHeaderPage); + + bool readerWithInsufficientApduLength = false; + for (const auto& readerInfo : pReaderInfos) + { + if (!readerInfo.sufficientApduLength()) + { + readerWithInsufficientApduLength = true; + } + } + + bool basicReaderPage = false; + if (pReaderInfos.size() == 1) + { + const ReaderInfo& readerInfo = pReaderInfos.at(0); + if (readerInfo.isBasicReader()) + { + setupPinBasicPage(readerInfo); + basicReaderPage = true; + } + else + { + QPixmap pixmap(readerInfo.getReaderConfigurationInfo().getIcon()->lookupPath()); + mUi->noNpaLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + } + + if (readerWithInsufficientApduLength) + { + mUi->headerStackedWidget->setCurrentWidget(mUi->errorInsufficientApduLengthSingle); + } + } + else + { + QPixmap pixmap(ReaderConfiguration::getMultipleReaderIconPath()); + mUi->noNpaLabel->setPixmap(pixmap.scaledToWidth(250, Qt::SmoothTransformation)); + + if (readerWithInsufficientApduLength) + { + mUi->headerStackedWidget->setCurrentWidget(mUi->errorInsufficientApduLengthMulti); + } + } + + mUi->stackedWidget->setCurrentWidget(basicReaderPage ? mUi->changePinBasicPage : mUi->errorNoNpaPage); + mUi->repeatNewPinEdit->setDigitFieldInvalid(false, tr("PIN correct.")); +} + + +void PinSettingsWidget::setUseScreenKeyboard(bool pUseScreenKeyboard) +{ + mUi->canRandomPinButton->setVisible(pUseScreenKeyboard); + mUi->oldRandomPinButton->setVisible(pUseScreenKeyboard); + mUi->newRandomPinButton->setVisible(pUseScreenKeyboard); + mUi->repeatNewRandomPinButton->setVisible(pUseScreenKeyboard); + mUi->pukRandomPinButton->setVisible(pUseScreenKeyboard); +} + + +bool PinSettingsWidget::getPinButtonEnabled() const +{ + return mPinButtonEnabled; +} + + +void PinSettingsWidget::fillInfoDescription(const QString& pTitle, const QString& pMessage) +{ + mPinSettingsInfoTitle = pTitle; + mPinSettingsInfoDescription = pMessage; +} + + +bool PinSettingsWidget::updateReadersForOneNPA(const ReaderInfo& pReaderInfo) +{ + mRetryCounter = pReaderInfo.getRetryCounter(); + mPinDeactivated = pReaderInfo.isPinDeactivated(); + + if (mMode == Mode::AfterPinChange) + { + setupPinSuccessfullyChangedPage(pReaderInfo); + mUi->headerStackedWidget->setCurrentWidget(mUi->pinSuccessHeaderPage); + mUi->stackedWidget->setCurrentWidget(mUi->pinSuccessPage); + return true; + } + + if (mPinDeactivated) + { + if (pReaderInfo.isBasicReader()) + { + setupPinBasicPage(pReaderInfo); + mUi->stackedWidget->setCurrentWidget(mUi->changePinBasicPage); + } + else + { + QPixmap pixmap(pReaderInfo.getReaderConfigurationInfo().getIconWithNPA()->lookupPath()); + mUi->deactivatedReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + mUi->stackedWidget->setCurrentWidget(mUi->errorPinDeactivatedPage); + } + + mUi->headerStackedWidget->setCurrentWidget(mUi->errorPinDeactivatedHeaderPage); + return false; + } + + if (pReaderInfo.isBasicReader()) + { + setupPinBasicPage(pReaderInfo); + mUi->stackedWidget->setCurrentWidget(mUi->changePinBasicPage); + } + else + { + setupPinComfortPage(pReaderInfo); + mUi->stackedWidget->setCurrentWidget(mUi->changePinComfortPage); + } + + return !pReaderInfo.isBasicReader(); +} + + +void PinSettingsWidget::updateReaders() +{ + const ReaderManager& readerManager = *Env::getSingleton(); + if (readerManager.getReaderInfos().isEmpty()) + { + QPixmap pixmap(ReaderConfiguration::getNoReaderFoundIconPath()); + mUi->noReaderLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + mUi->headerStackedWidget->setCurrentWidget(mUi->errorNoReaderHeaderPage); + mUi->stackedWidget->setCurrentWidget(mUi->errorNoReaderPage); + return; + } + + QVector readersWithNPA = getReaderWithNPA(readerManager.getReaderInfos()); + mRetryCounter = 3; + bool enableButton = false; + + if (readersWithNPA.size() == 0) + { + updateReadersWithoutNPA(readerManager.getReaderInfos(ReaderFilter::UniqueReaderTypes)); + } + else if (readersWithNPA.size() == 1) + { + enableButton = updateReadersForOneNPA(readersWithNPA.at(0)); + } + else + { + mMode = Mode::Normal; + QPixmap pixmap(ReaderConfiguration::getMultipleReaderIconPath()); + mUi->multipleReaderLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + mUi->headerStackedWidget->setCurrentWidget(mUi->errorMultipleNpasHeaderPage); + mUi->stackedWidget->setCurrentWidget(mUi->errorMultipleNpasPage); + } + + mPinButtonEnabled = enableButton; + Q_EMIT firePinButtonEnabledUpdated(mPinButtonEnabled); +} + + +void PinSettingsWidget::onBackspacePressedOnApply() +{ + mUi->repeatNewPinEdit->removeLastCharacter(); + mUi->repeatNewPinEdit->setFocus(); + onRepeatNewPinTextEdited(); +} + + +void PinSettingsWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void PinSettingsWidget::showEvent(QShowEvent* pEvent) +{ + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &PinSettingsWidget::updateReaders); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &PinSettingsWidget::updateReaders); + + updateReaders(); + QWidget::showEvent(pEvent); +} + + +void PinSettingsWidget::hideEvent(QHideEvent* pEvent) +{ + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &PinSettingsWidget::updateReaders); + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardRetryCounterChanged, this, &PinSettingsWidget::updateReaders); + + QWidget::hideEvent(pEvent); + + // Reset the mode, so that the next time the users sees this widget, it doesn't show the state of the previous + // action. + mMode = Mode::Normal; + + 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. + mRandomPinDialog->reject(); + } +} + + +void PinSettingsWidget::onScanButtonClicked() +{ + ReaderManager::getInstance().startScanAll(); + QTimer::singleShot(3000, this, &PinSettingsWidget::onScanTimeout); +} + + +void PinSettingsWidget::onScanTimeout() +{ +} + + +void PinSettingsWidget::onUiFinished(const QString& pReaderName) +{ + qDebug() << "Set reader name" << pReaderName; + updateReaders(); +} + + +void PinSettingsWidget::onCanTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mUi->canEdit->setText(pText); + } + + if (isCanFieldVisible()) + { + if (mUi->canEdit->text().length() == 6) + { + mUi->oldPinEdit->setEnabled(true); + mUi->oldRandomPinButton->setEnabled(true); + + QTimer::singleShot(300, this, &PinSettingsWidget::focusPIN); + } + else + { + mUi->oldPinEdit->setEnabled(false); + mUi->oldRandomPinButton->setEnabled(false); + } + } + else + { + mUi->oldPinEdit->setEnabled(true); + mUi->oldRandomPinButton->setEnabled(true); + QTimer::singleShot(300, this, &PinSettingsWidget::focusPIN); + } + + mUi->oldPinEdit->clear(); + onOldPinTextEdited(); +} + + +void PinSettingsWidget::onOldPinTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mUi->oldPinEdit->setText(pText); + } + + bool enable = mUi->oldPinEdit->text().length() >= 5; + mUi->newPinEdit->setEnabled(enable); + mUi->newRandomPinButton->setEnabled(enable); + + if (mUi->oldPinEdit->text().length() == 6) + { + mUi->newPinEdit->setFocus(); + mUi->newPinEdit->setCursorPosition(0); + } + + mUi->newPinEdit->clear(); + onNewPinTextEdited(); +} + + +void PinSettingsWidget::onNewPinTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mUi->newPinEdit->setText(pText); + } + + bool enable = mUi->newPinEdit->text().length() == 6; + mUi->repeatNewPinEdit->setEnabled(enable); + mUi->repeatNewRandomPinButton->setEnabled(enable); + if (mUi->newPinEdit->text().length() == 6) + { + mUi->repeatNewPinEdit->setFocus(); + mUi->repeatNewPinEdit->setCursorPosition(0); + } + + mUi->repeatNewPinEdit->clear(); + onRepeatNewPinTextEdited(); +} + + +void PinSettingsWidget::onRepeatNewPinTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mUi->repeatNewPinEdit->setText(pText); + } + + if (!mUi->repeatNewPinEdit->isEnabled() || mUi->newPinEdit->text().startsWith(mUi->repeatNewPinEdit->text())) + { + mUi->repeatNewPinEdit->setDigitFieldInvalid(false, tr("PIN correct.")); + + bool inputOk = mUi->repeatNewPinEdit->text().length() == 6 && mUi->repeatNewPinEdit->text() == mUi->newPinEdit->text(); + mPinButtonEnabled = inputOk; + Q_EMIT firePinButtonEnabledUpdated(mPinButtonEnabled); + } + else + { + QString invalidMessage = tr("The PIN in the field \"%1\" does not match the PIN in the field \"%2\".").arg(mUi->repeatNewPinEditLabel->text().replace(QStringLiteral(":"), QLatin1String("")), mUi->newPinEditLabel->text().replace(QStringLiteral(":"), QLatin1String(""))); + mUi->repeatNewPinEdit->setDigitFieldInvalid(true, invalidMessage); + } + +} + + +void PinSettingsWidget::onPukTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mUi->pukEdit->setText(pText); + } + mPinButtonEnabled = mUi->pukEdit->text().length() == 10; + Q_EMIT firePinButtonEnabledUpdated(mPinButtonEnabled); +} + + +void PinSettingsWidget::setupPinBasicPage(const ReaderInfo& pReaderInfo) +{ + mUi->canEdit->clear(); + mUi->oldPinEdit->clear(); + mUi->newPinEdit->clear(); + mUi->repeatNewPinEdit->clear(); + mUi->pukEdit->clear(); + + bool hasCard = pReaderInfo.hasEidCard(); + + QPixmap pixmap; + if (hasCard) + { + pixmap = pReaderInfo.getReaderConfigurationInfo().getIconWithNPA()->lookupPath(); + mUi->basicReaderImageLabel->setAccessibleName(tr("Card reader icon")); + } + else + { + pixmap = pReaderInfo.getReaderConfigurationInfo().getIcon()->lookupPath(); + mUi->basicReaderImageLabel->setAccessibleName(tr("Empty card reader icon")); + } + + mUi->basicReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + + bool canEditVisible = false; + bool pukEditVisible = false; + + if (hasCard) + { + setupChangePinHeader(pReaderInfo.getRetryCounter(), true); + + switch (pReaderInfo.getRetryCounter()) + { + case 0: + pukEditVisible = true; + break; + + case 1: + canEditVisible = true; + break; + + default: + break; + } + } + + if (mPinDeactivated) + { + pukEditVisible = false; + canEditVisible = false; + hasCard = false; + } + + mUi->canEditStackedWidget->setCurrentWidget(canEditVisible ? mUi->canEditPage : mUi->noCanEditPage); + mUi->canEditLabelStackedWidget->setCurrentWidget(canEditVisible ? mUi->canEditLabelPage : mUi->noCanEditLabelPage); + + mUi->basicReaderPukStackedWidget->setCurrentWidget(pukEditVisible ? mUi->basicReaderPukPage : mUi->basicReaderPinPage); + + mUi->canEditLabel->setEnabled(hasCard); + mUi->oldPinEditLabel->setEnabled(hasCard); + mUi->newPinEditLabel->setEnabled(hasCard); + mUi->repeatNewPinEditLabel->setEnabled(hasCard); + mUi->canEdit->setEnabled(hasCard); + mUi->oldPinEdit->setEnabled(hasCard); + mUi->newPinEdit->setEnabled(hasCard); + mUi->repeatNewPinEdit->setEnabled(hasCard); + mUi->canRandomPinButton->setEnabled(hasCard); + mUi->oldRandomPinButton->setEnabled(hasCard); + mUi->newRandomPinButton->setEnabled(hasCard); + mUi->repeatNewRandomPinButton->setEnabled(hasCard); + + if (hasCard) + { + if (isCanFieldVisible()) + { + QTimer::singleShot(300, this, &PinSettingsWidget::focusCAN); + } + else if (pukEditVisible) + { + QTimer::singleShot(300, this, &PinSettingsWidget::focusPUK); + } + + if (!pukEditVisible) + { + onCanTextEdited(); + } + } +} + + +void PinSettingsWidget::focusPUK() +{ + mUi->pukEdit->setFocus(); + mUi->pukEdit->setCursorPosition(0); +} + + +void PinSettingsWidget::focusPIN() +{ + mUi->oldPinEdit->setFocus(); + mUi->oldPinEdit->setCursorPosition(0); +} + + +void PinSettingsWidget::focusCAN() +{ + mUi->canEdit->setFocus(); + mUi->canEdit->setCursorPosition(0); +} + + +void PinSettingsWidget::setupPinComfortPage(const ReaderInfo& pReaderInfo) +{ + QPixmap pixmap(pReaderInfo.getReaderConfigurationInfo().getIconWithNPA()->lookupPath()); + mUi->comfortReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); + setupChangePinHeader(pReaderInfo.getRetryCounter(), false); + + switch (pReaderInfo.getRetryCounter()) + { + case 0: + mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortPukDetailsPage); + break; + + case 1: + mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortCanDetailsPage); + break; + + default: + mUi->changePinComfortDetailsStackedWidget->setCurrentWidget(mUi->changePinComfortDetailsPage); + break; + } +} + + +void PinSettingsWidget::setupPinSuccessfullyChangedPage(const ReaderInfo& pReaderInfo) +{ + QPixmap pixmap(pReaderInfo.getReaderConfigurationInfo().getIconWithNPA()->lookupPath()); + mUi->pinSuccessReaderImageLabel->setPixmap(pixmap.scaledToWidth(SCALEWIDTH, Qt::SmoothTransformation)); +} + + +void PinSettingsWidget::setupChangePinHeader(int pRetryCounter, bool pIsBasicReader) +{ + switch (pRetryCounter) + { + case 0: + mUi->headerStackedWidget->setCurrentWidget(mUi->changePinPukHeaderPage); + break; + + case 1: + mUi->headerStackedWidget->setCurrentWidget(mUi->changePinWithCanHeaderPage); + break; + + default: + if (mMode == Mode::AfterPinUnblock) + { + mUi->headerStackedWidget->setCurrentWidget(mUi->pinUnblockedHeaderPage); + } + else + { + if (pIsBasicReader) + { + mUi->headerStackedWidget->setCurrentWidget(mUi->changePinBasicHeaderPage); + } + else + { + mUi->headerStackedWidget->setCurrentWidget(mUi->changePinComfortHeaderPage); + } + } + break; + } +} + + +bool PinSettingsWidget::isCanFieldVisible() const +{ + return mUi->canEditStackedWidget->currentWidget() == mUi->canEditPage; +} + + +void PinSettingsWidget::onRandomPinButtonClicked() +{ + const auto& readersWithNpa = getReaderWithNPA(ReaderManager::getInstance().getReaderInfos()); + const auto& selectedReaderName = readersWithNpa.size() == 1 ? readersWithNpa.at(0).getName() : QString(); + mRandomPinDialog = new RandomPinDialog(6, selectedReaderName, this); + if (mRandomPinDialog->exec() == QDialog::Accepted && !mRandomPinDialog->getPin().isEmpty()) + { + QToolButton* pinButton = qobject_cast(sender()); + if (pinButton == nullptr) + { + qCCritical(gui) << "sender == nullptr"; + } + else if (pinButton->objectName() == QLatin1String("canRandomPinButton")) + { + onCanTextEdited(mRandomPinDialog->getPin()); + } + else if (pinButton->objectName() == QLatin1String("oldRandomPinButton")) + { + onOldPinTextEdited(mRandomPinDialog->getPin()); + } + else if (pinButton->objectName() == QLatin1String("newRandomPinButton")) + { + onNewPinTextEdited(mRandomPinDialog->getPin()); + } + else if (pinButton->objectName() == QLatin1String("repeatNewRandomPinButton")) + { + onRepeatNewPinTextEdited(mRandomPinDialog->getPin()); + } + else if (pinButton->objectName() == QLatin1String("pukRandomPinButton")) + { + onPukTextEdited(mRandomPinDialog->getPin()); + } + } +} + + +void PinSettingsWidget::onRandomPukButtonClicked() +{ + const auto& readersWithNpa = getReaderWithNPA(ReaderManager::getInstance().getReaderInfos()); + const auto& selectedReaderName = readersWithNpa.size() == 1 ? readersWithNpa.at(0).getName() : QString(); + mRandomPinDialog = new RandomPinDialog(10, selectedReaderName, this); + if (mRandomPinDialog->exec() == QDialog::Accepted && !mRandomPinDialog->getPin().isEmpty()) + { + onPukTextEdited(mRandomPinDialog->getPin()); + } +} + + +void PinSettingsWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/PinSettingsWidget.h b/src/widget/PinSettingsWidget.h new file mode 100644 index 0000000..93ee514 --- /dev/null +++ b/src/widget/PinSettingsWidget.h @@ -0,0 +1,118 @@ +/*! + * \brief Widget for the PIN settings. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + + +namespace Ui +{ +class PinSettingsWidget; +} + +namespace governikus +{ + +class RandomPinDialog; +class ReaderInfo; + +class PinSettingsWidget + : public QWidget +{ + Q_OBJECT + + public: + static const int SCALEWIDTH = 200; + + enum class Mode + { + Normal, + AfterPinChange, + AfterPinUnblock, + }; + + public: + PinSettingsWidget(QWidget* pParent = nullptr); + virtual ~PinSettingsWidget() override; + + void setInProgress(bool pInProgress); + + QString getCan() const; + QString getPin() const; + QString getPuk() const; + QString getNewPin() const; + + + Mode getMode() const + { + return mMode; + } + + + void setMode(Mode pMode); + QString getButtonText() const; + void setUseScreenKeyboard(bool pUseScreenKeyboard); + + bool getPinButtonEnabled() const; + + Q_SIGNALS: + void firePinButtonEnabledUpdated(bool pEnabled); + + public Q_SLOTS: + void updateReaders(); + void onBackspacePressedOnApply(); + + protected: + virtual void paintEvent(QPaintEvent*) override; + virtual void showEvent(QShowEvent* pEvent) override; + virtual void hideEvent(QHideEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + private Q_SLOTS: + void onCanTextEdited(const QString& pText = QString()); + void onOldPinTextEdited(const QString& pText = QString()); + void onNewPinTextEdited(const QString& pText = QString()); + void onRepeatNewPinTextEdited(const QString& pText = QString()); + void onPukTextEdited(const QString& pText = QString()); + void focusPUK(); + void focusPIN(); + void focusCAN(); + void onRandomPinButtonClicked(); + void onRandomPukButtonClicked(); + void onScanTimeout(); + + void onScanButtonClicked(); + void onUiFinished(const QString& pReaderName); + + private: + void setupPinBasicPage(const ReaderInfo& pReaderInfo); + void setupPinComfortPage(const ReaderInfo& pReaderInfo); + void setupPinSuccessfullyChangedPage(const ReaderInfo& pReaderInfo); + void setupChangePinHeader(int pRetryCounter, bool pIsBasicReader); + + bool isCanFieldVisible() const; + + QVector getReaderWithNPA(const QVector& pReaderInfos); + void updateReadersWithoutNPA(const QVector& pReaderInfos); + bool updateReadersForOneNPA(const ReaderInfo& pReaderInfo); + + void fillInfoDescription(const QString& pTitle, const QString& pMessage); + + QScopedPointer mUi; + Mode mMode; + int mRetryCounter; + bool mPinDeactivated; + bool mPinButtonEnabled; + + QString mPinSettingsInfoTitle; + QString mPinSettingsInfoDescription; + QPointer mRandomPinDialog; +}; + +} /* namespace governikus */ diff --git a/src/widget/PinSettingsWidget.ui b/src/widget/PinSettingsWidget.ui new file mode 100644 index 0000000..e26ab89 --- /dev/null +++ b/src/widget/PinSettingsWidget.ui @@ -0,0 +1,1497 @@ + + + PinSettingsWidget + + + + 0 + 0 + 536 + 551 + + + + + + + Qt::NoFocus + + + 3 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + 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 your competent authority. + +Please note that the PIN may only consist of digits (0-9). + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + 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 your competent authority. + +Please note that the PIN may only consist of digits (0-9). + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 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 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. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + Qt::TabFocus + + + CAN on nPA icon + + + :/images/canHint.png + + + false + + + + + + + Qt::TabFocus + + + You have entered the wrong PIN two times. For a third attempt you first have to enter your six-digit card access number. 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. + + + true + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 20 + + + + + + + + :/images/Icon_Checked.svg + + + + + + + Qt::TabFocus + + + <h4>PUK entry successful</h4><p>Your ID card is unblocked. You now have three more tries to change your PIN.</p> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 20 + + + + + + + + :/images/Icon_Checked.svg + + + + + + + Qt::TabFocus + + + <h4>PIN successfully changed</h4> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>No card reader detected. Please make sure that a card reader is connected.</h4> +<p>If you need help or have problems with your card reader click on the "Diagnosis" button for further information. +</p> +<p>Please note: It is currently not possible to change your PIN whilst using your smartphone as a card reader. +However, you can change your PIN on your smartphone directly as long as the remote service is disabled. +</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>Please place your ID card on the card reader.</h4> +<p>If you have already placed an ID card on the card reader but it is not displayed here, please click on "Diagnosis".</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>Extended Length is not supported.</h4> +<p>Your remote reader does not meet the technical requirements (Extended Length not supported).</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>Extended Length is not supported.</h4> +<p>At least one of your card readers does not meet the technical requirements (Extended Length not supported). Please place the ID card on a different card reader.</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>Several ID cards detected</h4> +<p>Please place just one ID card on the card reader.</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + <html> +<h4>eID feature deactivated</h4> +<p>The eID function of your ID card is deactivated. Please contact the authority responsible for issuing your identification document to activate the eID function.</p> +</html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::NoFocus + + + 2 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 20 + + + 20 + + + + + 1 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + Current PIN / Transport PIN: + + + + + + + Qt::StrongFocus + + + + + + + Qt::StrongFocus + + + true + + + + + + + Qt::TabFocus + + + New PIN: + + + + + + + Qt::StrongFocus + + + + + + + Qt::StrongFocus + + + true + + + + + + + Qt::TabFocus + + + Confirm: + + + + + + + Qt::StrongFocus + + + + + + + Qt::StrongFocus + + + true + + + + + + + Qt::NoFocus + + + 1 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + Card access number (CAN): + + + + + + + + + 0 + 0 + + + + + + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::StrongFocus + + + + + + + true + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 85 + + + + + + + + + + Qt::TabFocus + + + PUK: + + + + + + + Qt::StrongFocus + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 85 + + + + + + + + + + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + 200 + 200 + + + + Qt::TabFocus + + + card reader icon + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 15 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 20 + + + 20 + + + 0 + + + 20 + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + 200 + 200 + + + + Qt::TabFocus + + + card reader icon + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + Click on "Change PIN" to enter a new PIN. + + + Qt::AlignCenter + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Click on "Enter PUK" to unblock your ID card. + + + Qt::AlignCenter + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 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. + + + Qt::AlignCenter + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + + + Please pay attention to the display of your card reader. + + + Qt::AlignCenter + + + true + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 169 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 20 + + + 20 + + + 0 + + + 20 + + + 0 + + + + + Qt::TabFocus + + + Click on "Change PIN" if you want to change your PIN again. + +If not, you can now remove your ID card form the card reader. + + + true + + + + + + + + 0 + 0 + + + + Qt::TabFocus + + + successful PIN change icon + + + Qt::AlignCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 237 + + + + + + + + + + 15 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + no reader icon + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 15 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + no id card icon + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 15 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::TabFocus + + + + + + Please make sure that only one card reader with an ID card on it is connected to your computer. + + + true + + + + + + + Qt::TabFocus + + + multiple card reader icon + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::TabFocus + + + deactivated card reader icon + + + deactivatedReaderImageLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 263 + + + + + + + + + + + + + governikus::PasswordEdit + QWidget +
generic/PasswordEdit.h
+ 1 +
+
+ + + + +
diff --git a/src/widget/ProviderWidget.cpp b/src/widget/ProviderWidget.cpp new file mode 100644 index 0000000..ca5ef86 --- /dev/null +++ b/src/widget/ProviderWidget.cpp @@ -0,0 +1,143 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderWidget.h" + +#include "Env.h" +#include "generic/ListCheckItemWidget.h" +#include "generic/ListItem.h" +#include "generic/ListItemIconLeft.h" +#include "generic/ListItemIconRight.h" +#include "generic/ListItemSubTitle.h" +#include "generic/ListItemTitle.h" +#include "ProviderConfiguration.h" +#include "ui_ProviderWidget.h" + +#include +#include +#include +#include +#include +#include + +using namespace governikus; + +ProviderWidget::ProviderWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::ProviderWidget()) +{ + mUi->setupUi(this); + + connect(mUi->providerSearch, &QLineEdit::textChanged, this, &ProviderWidget::searchProvider); + connect(Env::getSingleton(), &ProviderConfiguration::fireUpdated, this, &ProviderWidget::onProviderChanged); + + fill(); + mUi->noResultWidget->setVisible(false); + mUi->providerTableWidget->resizeColumnsToContents(); +} + + +ProviderWidget::~ProviderWidget() +{ +} + + +void ProviderWidget::onProviderChanged() +{ + mUi->providerTableWidget->clear(); + fill(); + searchProvider(); +} + + +void ProviderWidget::fill() +{ + qDebug() << "add provider for desktop widgets."; + QStringList header; + header += tr("Name"); + header += tr("Address"); + + const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); + + mUi->providerTableWidget->setColumnCount(header.count()); + mUi->providerTableWidget->setHorizontalHeaderLabels(header); + mUi->providerTableWidget->setRowCount(providers.size()); + + int row = 0; + for (const auto& provider : providers) + { + + QLabel* providerName = new QLabel(provider.getLongName().isEmpty() ? provider.getShortName() : provider.getLongName()); + providerName->setFocusPolicy(Qt::TabFocus); + providerName->setToolTip(providerName->text()); + providerName->setTextFormat(Qt::RichText); + providerName->setMargin(3); + mUi->providerTableWidget->setCellWidget(row, 0, providerName); + + QLabel* providerLink = new QLabel(QStringLiteral(R"(%1)").arg(provider.getAddress())); + providerLink->setToolTip(providerLink->text()); + providerLink->setFocusPolicy(Qt::TabFocus); + providerLink->setTextFormat(Qt::RichText); + providerLink->setTextInteractionFlags(Qt::TextBrowserInteraction); + providerLink->setOpenExternalLinks(true); + providerLink->setMargin(3); + mUi->providerTableWidget->setCellWidget(row, 1, providerLink); + + ++row; + } + + mUi->providerTableWidget->verticalHeader()->setVisible(false); //Hide row number + mUi->providerTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //Not allowed to change content + mUi->providerTableWidget->setAlternatingRowColors(true); //Grey and white alternating row +} + + +void ProviderWidget::searchProvider() +{ + QString searchText = mUi->providerSearch->text().trimmed(); + mUi->providerTableWidget->setVisible(true); + mUi->noResultWidget->setVisible(false); + + bool anyMatch = false; + + for (int i = 0; i < mUi->providerTableWidget->rowCount(); ++i) + { + bool match = false; + for (int j = 0; j < mUi->providerTableWidget->columnCount(); ++j) + { + + if (qobject_cast(mUi->providerTableWidget->cellWidget(i, j))->text().contains(searchText, Qt::CaseInsensitive)) + { + match = true; + anyMatch = true; + break; + } + } + mUi->providerTableWidget->setRowHidden(i, !match); + } + + mUi->providerTableWidget->setVisible(anyMatch); + mUi->noResultWidget->setVisible(!anyMatch); +} + + +void ProviderWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void ProviderWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + fill(); + searchProvider(); + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/ProviderWidget.h b/src/widget/ProviderWidget.h new file mode 100644 index 0000000..4690509 --- /dev/null +++ b/src/widget/ProviderWidget.h @@ -0,0 +1,45 @@ +/*! + * \brief The provider page in gui. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include + +namespace Ui +{ +class ProviderWidget; +} + +namespace governikus +{ + +class ProviderWidget + : public QWidget +{ + Q_OBJECT + + public: + ProviderWidget(QWidget* pParent = nullptr); + virtual ~ProviderWidget() override; + + public Q_SLOTS: + void searchProvider(); + void onProviderChanged(); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + + virtual void paintEvent(QPaintEvent*) override; + void fill(); +}; + +} /* namespace governikus */ diff --git a/src/widget/ProviderWidget.ui b/src/widget/ProviderWidget.ui new file mode 100644 index 0000000..697f43b --- /dev/null +++ b/src/widget/ProviderWidget.ui @@ -0,0 +1,134 @@ + + + ProviderWidget + + + + 0 + 0 + 516 + 252 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::TabFocus + + + 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. + + + 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. + + + true + + + + + + + + + Qt::TabFocus + + + Search: + + + + + + + Please enter your search + + + Please enter your search + + + + + + + + + QAbstractScrollArea::AdjustToContents + + + false + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectItems + + + false + + + false + + + 200 + + + false + + + true + + + + + + + + 5 + + + + + No matching providers were found. Please modify your search criteria. + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + diff --git a/src/widget/RandomPinDialog.cpp b/src/widget/RandomPinDialog.cpp new file mode 100644 index 0000000..90338a0 --- /dev/null +++ b/src/widget/RandomPinDialog.cpp @@ -0,0 +1,149 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RandomPinDialog.h" +#include "ui_RandomPinDialog.h" + +#include "generic/HelpAction.h" +#include "Randomizer.h" +#include "ReaderManager.h" + +#include +#include + +using namespace governikus; + +static const char* PIN = "pin"; + +RandomPinDialog::RandomPinDialog(int pLength, const QString& pSelectedReader, QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::RandomPinDialog) + , mSelectedReader(pSelectedReader) +{ + mUi->setupUi(this); + mUi->pin->setMaxLength(pLength); + + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("On screen password")); + + setModal(true); + + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &RandomPinDialog::onCardRemoved); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &RandomPinDialog::onCardInserted); + + installEventFilter(this); + + mUi->pinButtons->setId(mUi->button_pos_0, 0); + mUi->pinButtons->setId(mUi->button_pos_1, 1); + mUi->pinButtons->setId(mUi->button_pos_2, 2); + mUi->pinButtons->setId(mUi->button_pos_3, 3); + mUi->pinButtons->setId(mUi->button_pos_4, 4); + mUi->pinButtons->setId(mUi->button_pos_5, 5); + mUi->pinButtons->setId(mUi->button_pos_6, 6); + mUi->pinButtons->setId(mUi->button_pos_7, 7); + mUi->pinButtons->setId(mUi->button_pos_8, 8); + mUi->pinButtons->setId(mUi->button_pos_9, 9); + + initComponents(); + createButton(); +} + + +RandomPinDialog::~RandomPinDialog() +{ +} + + +void RandomPinDialog::initComponents() +{ + mUi->clrButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/btn_clear.png"))); + mUi->clrButton->setIconSize(QSize(44, 26)); + connect(mUi->clrButton, &QAbstractButton::clicked, mUi->pin, &QLineEdit::clear); + + mUi->cnlButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/btn_cancel.png"))); + mUi->cnlButton->setIconSize(QSize(58, 50)); + connect(mUi->cnlButton, &QAbstractButton::clicked, this, &RandomPinDialog::reject); + + mUi->okButton->setIcon(QPixmap(QStringLiteral(":/images/randompin/btn_ok.png"))); + mUi->okButton->setIconSize(QSize(58, 50)); + connect(mUi->okButton, &QAbstractButton::clicked, this, &RandomPinDialog::accept); +} + + +void RandomPinDialog::createButton() +{ + QVector buttonList = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + std::shuffle(buttonList.begin(), buttonList.end(), Randomizer::getInstance().getGenerator()); + + Q_ASSERT(buttonList.size() == mUi->pinButtons->buttons().size()); + for (int i = 0; i < buttonList.size(); ++i) + { + QAbstractButton* button = mUi->pinButtons->button(i); + button->setIcon(QPixmap(QStringLiteral(":/images/randompin/btn_normal_%1.png").arg(buttonList.value(i)))); + button->setIconSize(QSize(58, 50)); + button->setProperty(PIN, QVariant::fromValue(buttonList.value(i))); + connect(button, &QAbstractButton::clicked, this, &RandomPinDialog::onPosButtonClicked); + } +} + + +QString RandomPinDialog::getPin() +{ + return mUi->pin->text(); +} + + +void RandomPinDialog::onPosButtonClicked() +{ + QToolButton* posButton = qobject_cast(sender()); + if (posButton) + { + mUi->pin->setText(mUi->pin->text() + posButton->property(PIN).toString()); + } +} + + +void RandomPinDialog::onCardRemoved(const QString& pReaderName) +{ + if (isVisible() && pReaderName == mSelectedReader) + { + reject(); + } +} + + +void RandomPinDialog::onCardInserted() +{ + if (isVisible()) + { + reject(); + } +} + + +bool RandomPinDialog::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QDialog::eventFilter(pObject, pEvent); +} + + +void RandomPinDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/RandomPinDialog.h b/src/widget/RandomPinDialog.h new file mode 100644 index 0000000..709da78 --- /dev/null +++ b/src/widget/RandomPinDialog.h @@ -0,0 +1,48 @@ +/*! + * \brief Dialog for display the random PIN. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class RandomPinDialog; +} + +namespace governikus +{ + +class RandomPinDialog + : public QDialog +{ + Q_OBJECT + + public: + RandomPinDialog(int pLength, const QString& pSelectedReader, QWidget* pParent = nullptr); + virtual ~RandomPinDialog() override; + + QString getPin(); + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + const QString mSelectedReader; + + void initComponents(); + void createButton(); + + private Q_SLOTS: + void onPosButtonClicked(); + void onCardRemoved(const QString& pReaderName); + void onCardInserted(); +}; + +} /* namespace governikus */ diff --git a/src/widget/RandomPinDialog.ui b/src/widget/RandomPinDialog.ui new file mode 100644 index 0000000..1f5f631 --- /dev/null +++ b/src/widget/RandomPinDialog.ui @@ -0,0 +1,303 @@ + + + RandomPinDialog + + + + 0 + 0 + 293 + 181 + + + + Screen keyboard + + + + 6 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Clear + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + OK + + + + + + true + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + Cancel + + + + + + true + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + * + + + + + + true + + + pinButtons + + + + + + + PIN field + + + 6 + + + QLineEdit::Password + + + true + + + + + + + + + + + + button_pos_1 + button_pos_2 + button_pos_3 + button_pos_4 + button_pos_5 + button_pos_6 + button_pos_7 + button_pos_8 + button_pos_9 + button_pos_0 + okButton + clrButton + cnlButton + pin + + + + + + + false + + + + diff --git a/src/widget/ReaderDeviceDialog.cpp b/src/widget/ReaderDeviceDialog.cpp new file mode 100644 index 0000000..7d8f274 --- /dev/null +++ b/src/widget/ReaderDeviceDialog.cpp @@ -0,0 +1,62 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderDeviceDialog.h" + +#include "generic/HelpAction.h" +#include "ReaderDeviceWidget.h" +#include "ui_ReaderDeviceDialog.h" + +#include + + +using namespace governikus; + +ReaderDeviceDialog::ReaderDeviceDialog(QWidget* pParent) + : QDialog(pParent) + , mUi(new Ui::ReaderDeviceDialog) + , mReaderDeviceWidget(new ReaderDeviceWidget(pParent)) +{ + mUi->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Reader Driver Integration")); + + installEventFilter(this); + + mUi->readerDriverLayout->addWidget(mReaderDeviceWidget); + + connect(mUi->closeButton, &QAbstractButton::clicked, this, &ReaderDeviceDialog::close); +} + + +ReaderDeviceDialog::~ReaderDeviceDialog() +{ +} + + +bool ReaderDeviceDialog::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* const keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(); + return true; + } + } + return QDialog::eventFilter(pObject, pEvent); +} + + +void ReaderDeviceDialog::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/ReaderDeviceDialog.h b/src/widget/ReaderDeviceDialog.h new file mode 100644 index 0000000..aa7ff12 --- /dev/null +++ b/src/widget/ReaderDeviceDialog.h @@ -0,0 +1,43 @@ +/*! + * \brief Dialog for detecting attached card readers or available + * remote card readers. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class ReaderDeviceDialog; +} + + +namespace governikus +{ + +class ReaderDeviceWidget; + + +class ReaderDeviceDialog + : public QDialog +{ + Q_OBJECT + + public: + ReaderDeviceDialog(QWidget* pParent = nullptr); + virtual ~ReaderDeviceDialog() override; + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + ReaderDeviceWidget* mReaderDeviceWidget; +}; + +} /* namespace governikus */ diff --git a/src/widget/ReaderDeviceDialog.ui b/src/widget/ReaderDeviceDialog.ui new file mode 100644 index 0000000..f0cc570 --- /dev/null +++ b/src/widget/ReaderDeviceDialog.ui @@ -0,0 +1,78 @@ + + + ReaderDeviceDialog + + + Qt::WindowModal + + + + 0 + 0 + 680 + 400 + + + + Diagnosis + + + + 9 + + + 9 + + + 9 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + diff --git a/src/widget/ReaderDeviceGui.cpp b/src/widget/ReaderDeviceGui.cpp new file mode 100644 index 0000000..60391e6 --- /dev/null +++ b/src/widget/ReaderDeviceGui.cpp @@ -0,0 +1,74 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderDeviceGui.h" + +#include "ReaderDeviceDialog.h" + +#include + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(gui) + +ReaderDeviceGui::ReaderDeviceGui(QWidget* pParentWidget) + : QObject(pParentWidget) + , mDialog(nullptr) +{ +} + + +ReaderDeviceGui::~ReaderDeviceGui() +{ +} + + +void ReaderDeviceGui::activate() +{ + if (!mDialog) + { + QWidget* dialogParent = qobject_cast(parent()); + if (!dialogParent) + { + return; + } + + mDialog = new ReaderDeviceDialog(dialogParent); + connect(mDialog, &ReaderDeviceDialog::finished, this, &ReaderDeviceGui::onFinished); + connect(mDialog, &QDialog::finished, this, &ReaderDeviceGui::fireFinished); + } + reactivate(); +} + + +void ReaderDeviceGui::deactivate() +{ + if (mDialog) + { + mDialog->close(); + } +} + + +void ReaderDeviceGui::reactivate() +{ + if (mDialog->isMinimized()) + { + mDialog->showNormal(); + } + if (!mDialog->isVisible()) + { + mDialog->show(); + } + mDialog->activateWindow(); + mDialog->raise(); +} + + +void ReaderDeviceGui::onFinished(int result) +{ + Q_UNUSED(result); + + mDialog = nullptr; +} diff --git a/src/widget/ReaderDeviceGui.h b/src/widget/ReaderDeviceGui.h new file mode 100644 index 0000000..fd9aac2 --- /dev/null +++ b/src/widget/ReaderDeviceGui.h @@ -0,0 +1,42 @@ +/*! + * \brief Qt widget based ReaderDriverUi implementation. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class QWidget; + +namespace governikus +{ + +class ReaderDeviceDialog; + + +class ReaderDeviceGui + : public QObject +{ + Q_OBJECT + + public: + ReaderDeviceGui(QWidget* pParentWidget); + virtual ~ReaderDeviceGui(); + + void activate(); + void deactivate(); + + Q_SIGNALS: + void fireFinished(); + + private: + ReaderDeviceDialog* mDialog; + void reactivate(); + + private Q_SLOTS: + void onFinished(int result); +}; + +} /* namespace governikus */ diff --git a/src/widget/ReaderDeviceWidget.cpp b/src/widget/ReaderDeviceWidget.cpp new file mode 100644 index 0000000..5b5d60a --- /dev/null +++ b/src/widget/ReaderDeviceWidget.cpp @@ -0,0 +1,374 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderDeviceWidget.h" + +#include "ui_ReaderDeviceWidget.h" + +#include "Env.h" +#include "LanguageLoader.h" +#include "ReaderConfiguration.h" +#include "ReaderManager.h" +#include "RemotePinInputDialog.h" + +#include +#include +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +ReaderDeviceWidget::ReaderDeviceWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::ReaderDeviceWidget) + , mLocalReaderDataModel(this) + , mRemoteReaderDataModel(this) +{ + mUi->setupUi(this); + + mUi->tableViewLocal->setModel(&mLocalReaderDataModel); + mUi->tableViewLocal->horizontalHeader()->setStretchLastSection(true); + mUi->tableViewLocal->verticalHeader()->setVisible(false); + + mUi->tableViewRemote->setModel(&mRemoteReaderDataModel); + mUi->tableViewRemote->horizontalHeader()->setStretchLastSection(true); + mUi->tableViewRemote->verticalHeader()->setVisible(false); + + mUi->infoText->setOpenExternalLinks(true); + + connect(Env::getSingleton(), &ReaderConfiguration::fireUpdated, this, &ReaderDeviceWidget::onAdjustReaderNameColumnWidth); + onAdjustReaderNameColumnWidth(); + + connect(this, &ReaderDeviceWidget::fireWidgetShown, &mRemoteReaderDataModel, &RemoteDeviceModel::onWidgetShown); + connect(this, &ReaderDeviceWidget::fireWidgetHidden, &mRemoteReaderDataModel, &RemoteDeviceModel::onWidgetHidden); + + connect(&mLocalReaderDataModel, &ReaderDriverModel::fireModelChanged, this, &ReaderDeviceWidget::onUpdateLocalTableSelection); + connect(&mRemoteReaderDataModel, &RemoteDeviceModel::fireModelChanged, this, &ReaderDeviceWidget::onUpdateRemoteTableSelection); + onUpdateLocalTableSelection(); + onUpdateRemoteTableSelection(); + + connect(mUi->tableViewRemote->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ReaderDeviceWidget::onRemoteSelectionChanged); + connect(mUi->tableViewLocal->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ReaderDeviceWidget::onUpdateInfo); + onRemoteSelectionChanged(); + onUpdateInfo(); + + connect(mUi->connectRemote, &QPushButton::clicked, this, &ReaderDeviceWidget::onConnectClicked); + connect(mUi->forgetRemote, &QPushButton::clicked, this, &ReaderDeviceWidget::onForgetClicked); + connect(mUi->tableViewRemote, &QTableView::doubleClicked, this, &ReaderDeviceWidget::onRemoteDoubleClicked); + + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireDispatcherDestroyed, &mRemoteReaderDataModel, &RemoteDeviceModel::onDeviceDisconnected); +} + + +ReaderDeviceWidget::~ReaderDeviceWidget() +{ + +} + + +void ReaderDeviceWidget::prependAccessibleName(const QString& pAccessibleNameAddition) +{ + mUi->cardReaderDescription->setAccessibleName(pAccessibleNameAddition + mUi->cardReaderDescription->accessibleName()); +} + + +void ReaderDeviceWidget::onRemoteSelectionChanged() +{ + const QItemSelectionModel* const selectionModel = mUi->tableViewRemote->selectionModel(); + const QModelIndexList& selectionList = selectionModel->selectedRows(); + + if (selectionList.isEmpty()) + { + mUi->connectRemote->setEnabled(false); + mUi->forgetRemote->setEnabled(false); + } + else + { + const QModelIndex& index = selectionList.at(0); + if (mRemoteReaderDataModel.isPaired(index)) + { + mUi->connectRemote->setEnabled(false); + mUi->forgetRemote->setEnabled(true); + } + else + { + mUi->connectRemote->setEnabled(true); + mUi->forgetRemote->setEnabled(false); + } + } + +} + + +void ReaderDeviceWidget::onUpdateInfo() +{ + updateInfoIcon(); + updateInfoText(); + updateInfoUpdate(); +} + + +void ReaderDeviceWidget::updateInfoIcon() +{ + const QItemSelectionModel* const selectionModel = mUi->tableViewLocal->selectionModel(); + const QModelIndexList& selectionList = selectionModel->selectedRows(); + + QPixmap pixmap; + if (selectionList.isEmpty()) + { + pixmap = QPixmap(ReaderConfiguration::getNoReaderFoundIconPath()); + } + else + { + const QModelIndex& index = selectionList.at(0); + const QString& path = mLocalReaderDataModel.getReaderConfigurationInfo(index).getIcon()->lookupPath(); + pixmap = QPixmap(path); + if (mLocalReaderDataModel.isInstalledSupportedReader(index)) + { + QPixmap checkMark(QStringLiteral(":/images/green_check_mark.svg")); + checkMark = checkMark.scaledToHeight(pixmap.height() / 3, Qt::SmoothTransformation); + + const int insertAtX = pixmap.width() - checkMark.width(); + const int insertAtY = pixmap.height() / 5 - checkMark.height() / 2; + QPainter(&pixmap).drawPixmap(insertAtX, insertAtY, checkMark); + } + } + const int layoutHeight = mUi->detailInfoLayout->geometry().height(); + mUi->readerLabel->setPixmap(pixmap.scaledToHeight(layoutHeight / 2, Qt::SmoothTransformation)); + +} + + +void ReaderDeviceWidget::updateInfoText() +{ + const QItemSelectionModel* const selectionModel = mUi->tableViewLocal->selectionModel(); + const QModelIndexList& selectionList = selectionModel->selectedRows(); + + QString infoText; + if (selectionList.isEmpty()) + { + if (mLocalReaderDataModel.rowCount() == 0) + { + infoText = tr("No card reader detected"); + } + else + { + infoText = tr("Select a device to display more information about it"); + } + } + else + { + const QModelIndex& index = selectionList.at(0); + infoText = mLocalReaderDataModel.getHTMLDescription(index); + } + + if (infoText.isEmpty()) + { + mUi->stackedWidget->setCurrentWidget(mUi->emptyWidget); + } + else + { + mUi->infoText->setHtml(QStringLiteral("

") + infoText + QStringLiteral("

")); + mUi->stackedWidget->setCurrentWidget(mUi->infoText); + } +} + + +void ReaderDeviceWidget::updateInfoUpdate() +{ + const auto& now = LanguageLoader::getInstance().getUsedLocale().toString(QTime::currentTime(), tr("hh:mm:ss AP")); + const QString& text = tr("The list of card readers was last updated at %1."); + + mUi->updateTimeLabel->setText(text.arg(now)); +} + + +void ReaderDeviceWidget::onUpdateLocalTableSelection() +{ + if (mLocalReaderDataModel.rowCount() > 0) + { + mUi->localEmptyListDescriptionFrame->setVisible(false); + mUi->tableViewLocal->setVisible(true); + QItemSelectionModel* const selectionModel = mUi->tableViewLocal->selectionModel(); + if (selectionModel->selectedRows().isEmpty()) + { + selectionModel->select(mLocalReaderDataModel.index(0, ReaderDriverModel::ColumnId::ReaderName), QItemSelectionModel::Select); + selectionModel->select(mLocalReaderDataModel.index(0, ReaderDriverModel::ColumnId::ReaderStatus), QItemSelectionModel::Select); + } + } + else + { + mUi->tableViewLocal->setVisible(false); + mUi->localEmptyListDescriptionFrame->setVisible(true); + } + onUpdateInfo(); +} + + +void ReaderDeviceWidget::onUpdateRemoteTableSelection() +{ + if (mRemoteReaderDataModel.rowCount() > 0) + { + mUi->remoteEmptyListDescriptionFrame->setVisible(false); + mUi->tableViewRemote->setVisible(true); + QItemSelectionModel* const selectionModel = mUi->tableViewRemote->selectionModel(); + if (selectionModel->selectedRows().isEmpty()) + { + selectionModel->select(mRemoteReaderDataModel.index(0, RemoteDeviceModel::ColumnId::ReaderName), QItemSelectionModel::Select); + selectionModel->select(mRemoteReaderDataModel.index(0, RemoteDeviceModel::ColumnId::ReaderStatus), QItemSelectionModel::Select); + } + } + else + { + mUi->tableViewRemote->setVisible(false); + mUi->remoteEmptyListDescriptionFrame->setVisible(true); + onRemoteSelectionChanged(); + } +} + + +void ReaderDeviceWidget::onAdjustReaderNameColumnWidth() +{ + const auto& infos = Env::getSingleton()->getReaderConfigurationInfos(); + + int maxWidth = 0; + const QFontMetrics metrics(QGuiApplication::font()); + for (const auto& info : infos) + { + const int deviceNameWidth = metrics.width(info.getName()); + if (deviceNameWidth > maxWidth) + { + maxWidth = deviceNameWidth; + } + } + + if (maxWidth <= 0) + { + return; + } + + const int CELL_PADDING = 20; + mUi->tableViewLocal->setColumnWidth(0, maxWidth + CELL_PADDING); + mUi->tableViewRemote->setColumnWidth(0, maxWidth + CELL_PADDING); +} + + +void ReaderDeviceWidget::onConnectClicked() +{ + const auto& selectionModel = mUi->tableViewRemote->selectionModel(); + const QModelIndexList& selectionList = selectionModel->selectedRows(); + + if (!selectionList.isEmpty()) + { + const QModelIndex& index = selectionList.at(0); + + const QSharedPointer remoteDeviceListEntry = mRemoteReaderDataModel.getRemoteDeviceListEntry(index); + if (remoteDeviceListEntry.isNull()) + { + return; + } + + setEnabled(false); + + QMessageBox pairingInfoBox(this); + pairingInfoBox.setText(tr("Start the pairing mode on the other device if it is not already started.")); + pairingInfoBox.setWindowModality(Qt::WindowModal); + pairingInfoBox.setWindowFlags(pairingInfoBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); + pairingInfoBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + pairingInfoBox.setDefaultButton(QMessageBox::Ok); + pairingInfoBox.setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); + + if (pairingInfoBox.exec() == QMessageBox::Cancel) + { + setEnabled(true); + return; + } + + const QString pin = RemotePinInputDialog::getPin(this); + if (!pin.isEmpty()) + { + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireEstablishConnectionDone, this, &ReaderDeviceWidget::onEstablishConnectionDone); + remoteClient->establishConnection(remoteDeviceListEntry, pin); + } + + setEnabled(true); + } +} + + +void ReaderDeviceWidget::onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus) +{ + Q_UNUSED(pEntry); + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + disconnect(remoteClient.data(), &RemoteClient::fireEstablishConnectionDone, this, &ReaderDeviceWidget::onEstablishConnectionDone); + if (pStatus.isError()) + { + QMessageBox box(QApplication::activeWindow()); + box.setIcon(QMessageBox::Critical); + box.setWindowTitle(QApplication::applicationName() + QStringLiteral(" - ") + tr("Pairing")); + box.setWindowIcon(QIcon(QStringLiteral(":/images/npa.svg"))); + box.setWindowModality(Qt::WindowModal); + box.setText(pStatus.toErrorDescription()); + box.exec(); + } + else + { + } +} + + +void ReaderDeviceWidget::onForgetClicked() +{ + const auto& selectionModel = mUi->tableViewRemote->selectionModel(); + const QModelIndexList& selectionList = selectionModel->selectedRows(); + + if (!selectionList.isEmpty()) + { + const QModelIndex& index = selectionList.at(0); + + mRemoteReaderDataModel.forgetDevice(index); + } +} + + +void ReaderDeviceWidget::showEvent(QShowEvent* pEevent) +{ + onUpdateInfo(); + Q_EMIT fireWidgetShown(); + QWidget::showEvent(pEevent); +} + + +void ReaderDeviceWidget::hideEvent(QHideEvent* pEvent) +{ + Q_EMIT fireWidgetHidden(); + QWidget::hideEvent(pEvent); +} + + +void ReaderDeviceWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + onUpdateInfo(); + } + QWidget::changeEvent(pEvent); +} + + +void ReaderDeviceWidget::onRemoteDoubleClicked(const QModelIndex& pIndex) +{ + if (!mRemoteReaderDataModel.isPaired(pIndex)) + { + onConnectClicked(); + } +} diff --git a/src/widget/ReaderDeviceWidget.h b/src/widget/ReaderDeviceWidget.h new file mode 100644 index 0000000..75157af --- /dev/null +++ b/src/widget/ReaderDeviceWidget.h @@ -0,0 +1,70 @@ +/*! + * \brief Widget for detecting attached card readers and + * suggesting an appropriate driver to be installed. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppSettings.h" +#include "ReaderDriverModel.h" +#include "RemoteDeviceModel.h" + +#include +#include +#include +#include + +namespace Ui +{ +class ReaderDeviceWidget; +} + +namespace governikus +{ + +class ReaderDeviceWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + ReaderDriverModel mLocalReaderDataModel; + RemoteDeviceModel mRemoteReaderDataModel; + + void updateInfoIcon(); + void updateInfoText(); + void updateInfoUpdate(); + + static QString askForPin(QWidget* pParent); + + private Q_SLOTS: + void showEvent(QShowEvent* pEevent) override; + void hideEvent(QHideEvent* pEvent) override; + void onUpdateInfo(); + void onAdjustReaderNameColumnWidth(); + void onUpdateLocalTableSelection(); + void onUpdateRemoteTableSelection(); + void onConnectClicked(); + void onEstablishConnectionDone(const QSharedPointer& pEntry, const GlobalStatus& pStatus); + void onRemoteSelectionChanged(); + void onForgetClicked(); + void onRemoteDoubleClicked(const QModelIndex& pIndex); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + explicit ReaderDeviceWidget(QWidget* pParent = nullptr); + virtual ~ReaderDeviceWidget() override; + + void prependAccessibleName(const QString& pAccessibleNameAddition); + + Q_SIGNALS: + void fireWidgetShown(); + void fireWidgetHidden(); +}; + +} diff --git a/src/widget/ReaderDeviceWidget.ui b/src/widget/ReaderDeviceWidget.ui new file mode 100644 index 0000000..ecc970d --- /dev/null +++ b/src/widget/ReaderDeviceWidget.ui @@ -0,0 +1,391 @@ + + + ReaderDeviceWidget + + + + 0 + 0 + 649 + 440 + + + + + + + 6 + + + + + Qt::TabFocus + + + In order to use the online identification function of your ID card you need a separate card reader or a suitable smartphone. The following overview shows the status of a connected card reader or connected smartphone. + + + In order to use the online identification function of your ID card you need a separate card reader or a suitable smartphone. The following overview shows the status of a connected card reader or connected smartphone. + + + true + + + + + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + Smartphone as card reader + + + + + + + + + + 0 + 0 + + + + + 470 + 100 + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + + 0 + 0 + + + + false + + + + 470 + 100 + + + + + + + No smartphone with enabled remote service found. See online help for details of use. + + + true + + + + + + + + + + 10 + + + + + true + + + + 0 + 0 + + + + + 200 + 16777215 + + + + Pair + + + + + + + false + + + + 0 + 0 + + + + + 200 + 16777215 + + + + Forget + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + + 11 + 75 + true + + + + + + + Card readers + + + + + + + 6 + + + + + + 0 + 0 + + + + + 470 + 0 + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + + QFrame::StyledPanel + + + QFrame::Plain + + + + 0 + 0 + + + + false + + + + 470 + 100 + + + + + + + No connected card reader found. See online help for installation of card readers. + + + true + + + + + + + + + + + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + + + 0 + 0 + + + + + 200 + 16777215 + + + + + + 0 + 0 + + + + + 200 + 16777215 + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + Qt::TabFocus + + + After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. + + + After connecting a new card reader it may take a few seconds to recognize the driver. It may be necessary to restart your system after installing the driver. + + + true + + + + + + + TextLabel + + + + + + + + + + diff --git a/src/widget/ReaderDriverModel.cpp b/src/widget/ReaderDriverModel.cpp new file mode 100644 index 0000000..8d90e76 --- /dev/null +++ b/src/widget/ReaderDriverModel.cpp @@ -0,0 +1,172 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderDriverModel.h" + +#include "AppSettings.h" +#include "Env.h" +#include "ReaderConfiguration.h" +#include "ReaderDetector.h" +#include "ReaderManager.h" + + +using namespace governikus; + + +ReaderDriverModel::ReaderDriverModel(QObject* pParent) + : QAbstractTableModel(pParent) + , mKnownDrivers() + , mConnectedReaders() +{ + const ReaderManager* const readerManager = Env::getSingleton(); + + connect(readerManager, &ReaderManager::fireReaderAdded, this, &ReaderDriverModel::onUpdateContent); + connect(readerManager, &ReaderManager::fireReaderRemoved, this, &ReaderDriverModel::onUpdateContent); + connect(Env::getSingleton(), &ReaderConfiguration::fireUpdated, this, &ReaderDriverModel::onUpdateContent); + connect(Env::getSingleton(), &ReaderDetector::fireReaderChangeDetected, this, &ReaderDriverModel::onUpdateContent); + connect(Env::getSingleton(), &AppSettings::fireSettingsChanged, this, &ReaderDriverModel::onUpdateContent); + onUpdateContent(); +} + + +void ReaderDriverModel::collectReaderData() +{ + mConnectedReaders.clear(); + + const QVector installedReaders = Env::getSingleton()->getReaderInfos(ReaderFilter({ + ReaderManagerPlugInType::PCSC + , ReaderManagerPlugInType::BLUETOOTH + , ReaderManagerPlugInType::NFC + })); + + for (const auto& installedReader : installedReaders) + { + const auto& readerSettingsInfo = installedReader.getReaderConfigurationInfo(); + if (!readerSettingsInfo.getUrl().isEmpty()) + { + mKnownDrivers += readerSettingsInfo; + mConnectedReaders += readerSettingsInfo; + } + } + + QVector readersWithoutDriver; + const auto& attachedSupportedDevices = Env::getSingleton()->getAttachedSupportedDevices(); + for (const auto& info : attachedSupportedDevices) + { + if (!mConnectedReaders.contains(info)) + { + readersWithoutDriver.append(info); + } + } + mConnectedReaders += readersWithoutDriver; +} + + +QString ReaderDriverModel::getStatus(const ReaderConfigurationInfo& pReaderConfigurationInfo) const +{ + if (mConnectedReaders.isEmpty()) + { + return tr("Not connected"); + } + + if (mKnownDrivers.contains(pReaderConfigurationInfo)) + { + return tr("Connected w/ driver"); + } + + return tr("Connected w/o driver"); +} + + +void ReaderDriverModel::onUpdateContent() +{ + beginResetModel(); + collectReaderData(); + endResetModel(); + + Q_EMIT fireModelChanged(); +} + + +QVariant ReaderDriverModel::headerData(int pSection, Qt::Orientation pOrientation, int pRole) const +{ + if (pRole == Qt::DisplayRole && pOrientation == Qt::Horizontal) + { + switch (pSection) + { + case ColumnId::ReaderName: + return tr("Device"); + + case ColumnId::ReaderStatus: + return tr("Status"); + + default: + return QVariant(); + } + } + return QVariant(); +} + + +int ReaderDriverModel::rowCount(const QModelIndex&) const +{ + return mConnectedReaders.size(); +} + + +int ReaderDriverModel::columnCount(const QModelIndex&) const +{ + return NUMBER_OF_COLUMNS; +} + + +QVariant ReaderDriverModel::data(const QModelIndex& pIndex, int pRole) const +{ + if (pRole == Qt::DisplayRole) + { + const auto& reader = mConnectedReaders.at(pIndex.row()); + switch (pIndex.column()) + { + case ColumnId::ReaderName: + return reader.getName(); + + case ColumnId::ReaderStatus: + return getStatus(reader); + } + } + + return QVariant(); +} + + +const ReaderConfigurationInfo& ReaderDriverModel::getReaderConfigurationInfo(const QModelIndex& pIndex) const +{ + return mConnectedReaders.at(pIndex.row()); +} + + +QString ReaderDriverModel::getHTMLDescription(const QModelIndex& pIndex) const +{ + if (mConnectedReaders.isEmpty()) + { + return QString(); + } + + if (mKnownDrivers.contains(mConnectedReaders.at(pIndex.row()))) + { + return tr("Device is installed correctly."); + } + + return tr("Device is not configured, please download and install the driver you can find at url: %1"). + arg(QStringLiteral("%1").arg(mConnectedReaders.at(pIndex.row()).getUrl())); +} + + +bool ReaderDriverModel::isInstalledSupportedReader(const QModelIndex& pIndex) const +{ + const auto& readerSettingsInfo = mConnectedReaders.at(pIndex.row()); + const bool knownDriver = mKnownDrivers.contains(readerSettingsInfo); + const bool knownReader = readerSettingsInfo.isKnownReader(); + return knownDriver && knownReader; +} diff --git a/src/widget/ReaderDriverModel.h b/src/widget/ReaderDriverModel.h new file mode 100644 index 0000000..c6b7099 --- /dev/null +++ b/src/widget/ReaderDriverModel.h @@ -0,0 +1,59 @@ +/*! + * \brief Model implementation for the reader driver table + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "ReaderDetector.h" + +#include +#include +#include + + +namespace governikus +{ + +class ReaderDriverModel + : public QAbstractTableModel +{ + Q_OBJECT + + private: + const int NUMBER_OF_COLUMNS = 2; + + QSet mKnownDrivers; + QVector mConnectedReaders; + + QString getStatus(const ReaderConfigurationInfo& pReaderConfigurationInfo) const; + void collectReaderData(); + + public: + enum ColumnId : int + { + ReaderName = 0, + ReaderStatus = 1 + }; + ReaderDriverModel(QObject* pParent = nullptr); + + virtual QVariant headerData(int pSection, Qt::Orientation pOrientation, int pRole) const override; + virtual int rowCount(const QModelIndex& pParent = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& pParent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; + + const ReaderConfigurationInfo& getReaderConfigurationInfo(const QModelIndex& pIndex) const; + QString getHTMLDescription(const QModelIndex& pIndex) const; + bool isInstalledSupportedReader(const QModelIndex& pIndex) const; + + public Q_SLOTS: + void onUpdateContent(); + + Q_SIGNALS: + void fireModelChanged(); + +}; + + +} /* namespace governikus */ diff --git a/src/widget/RemotePinInputDialog.cpp b/src/widget/RemotePinInputDialog.cpp new file mode 100644 index 0000000..222632d --- /dev/null +++ b/src/widget/RemotePinInputDialog.cpp @@ -0,0 +1,82 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemotePinInputDialog.h" + +#include "generic/PasswordEdit.h" +#include "ui_RemotePinInputDialog.h" + +#include +#include +#include + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +RemotePinInputDialog::RemotePinInputDialog(QWidget* pParent) + : QDialog(pParent, Qt::WindowTitleHint) + , mUi(new Ui::RemotePinInputDialog()) +{ + mUi->setupUi(this); + connect(mUi->buttonBox, &QDialogButtonBox::accepted, this, &RemotePinInputDialog::onOkClicked); + connect(mUi->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + mUi->pinEntryLine->setMaxLength(4, false); + mUi->pinEntryLine->setAlignment(Qt::AlignCenter); + QRegularExpression onlyNumbersExpression(QStringLiteral("[0-9]*")); + mUi->pinEntryLine->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are allowed.")); +} + + +RemotePinInputDialog::~RemotePinInputDialog() +{ + +} + + +const QString RemotePinInputDialog::getPin(QWidget* pParent) +{ + RemotePinInputDialog dialog(pParent); + int result = dialog.exec(); + if (!result) + { + return QString(); + } + + if (isValidPin(dialog.getPinEntry())) + { + return dialog.getPinEntry(); + } + + qCCritical(gui) << "Pairing code entered was not valid (4 Digits)"; + return QString(); +} + + +bool RemotePinInputDialog::isValidPin(const QString& pPin) +{ + return QRegularExpression("[0-9]{4}").match(pPin).hasMatch(); +} + + +QString RemotePinInputDialog::getPinEntry() const +{ + return mUi->pinEntryLine->text(); +} + + +void RemotePinInputDialog::onOkClicked() +{ + if (isValidPin(getPinEntry())) + { + accept(); + } + else + { + QToolTip::showText(mUi->pinEntryLine->mapToGlobal(QPoint(0, 0)), tr("A pairing code has to be 4 digits long."), mUi->pinEntryLine, QRect(), 3000); + } +} diff --git a/src/widget/RemotePinInputDialog.h b/src/widget/RemotePinInputDialog.h new file mode 100644 index 0000000..b4a57f9 --- /dev/null +++ b/src/widget/RemotePinInputDialog.h @@ -0,0 +1,39 @@ +/*! + * \brief Dialog for PIN input for device pairing. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace Ui +{ +class RemotePinInputDialog; +} + +namespace governikus +{ + +class RemotePinInputDialog + : public QDialog +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + private Q_SLOTS: + void onOkClicked(); + + public: + RemotePinInputDialog(QWidget* pParent = 0); + virtual ~RemotePinInputDialog() override; + + static const QString getPin(QWidget* pParent); + static bool isValidPin(const QString& pPin); + QString getPinEntry() const; +}; + +} /* namespace governikus */ diff --git a/src/widget/RemotePinInputDialog.ui b/src/widget/RemotePinInputDialog.ui new file mode 100644 index 0000000..d437cc3 --- /dev/null +++ b/src/widget/RemotePinInputDialog.ui @@ -0,0 +1,153 @@ + + + RemotePinInputDialog + + + Qt::WindowModal + + + + 0 + 0 + 378 + 180 + + + + + 0 + 0 + + + + Pairing code entry + + + + 9 + + + 12 + + + 9 + + + + + + + + 0 + 0 + + + + + 200 + 70 + + + + Enter the 4-digit pairing code shown on your other device. + + + Qt::AlignCenter + + + true + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 130 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 10 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + governikus::PasswordEdit + QWidget +
generic/PasswordEdit.h
+ 1 +
+
+ + +
diff --git a/src/widget/SelfInformationWidget.cpp b/src/widget/SelfInformationWidget.cpp new file mode 100644 index 0000000..ef2e56d --- /dev/null +++ b/src/widget/SelfInformationWidget.cpp @@ -0,0 +1,68 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SelfInformationWidget.h" + +#include "AppSettings.h" +#include "ui_SelfInformationWidget.h" + +#include +#include +#include + +using namespace governikus; + +SelfInformationWidget::SelfInformationWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::SelfInformationWidget()) +{ + mUi->setupUi(this); + + connect(mUi->selfAuthenticationButton, &QAbstractButton::clicked, this, &SelfInformationWidget::selfAuthenticationRequested); + connect(&AppSettings::getInstance().getGeneralSettings(), &AbstractSettings::fireSettingsChanged, this, &SelfInformationWidget::onSettingsChanged); + + mPixDescLogoLabel.reset(new QPixmap(QStringLiteral(":/images/siteWithLogo.png"))); + mUi->descriptionLogoLabel->setPixmap(mPixDescLogoLabel->scaled(159, 120, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + + onSettingsChanged(); +} + + +SelfInformationWidget::~SelfInformationWidget() +{ +} + + +void SelfInformationWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void SelfInformationWidget::onSettingsChanged() +{ + if (AppSettings::getInstance().getGeneralSettings().useSelfAuthTestUri()) + { + mUi->selfAuthenticationButton->setStyleSheet(QStringLiteral("QPushButton { background: red; }")); + mUi->selfAuthenticationButton->setToolTip(tr("Test environment")); + } + else + { + mUi->selfAuthenticationButton->setStyleSheet(QString()); + mUi->selfAuthenticationButton->setToolTip(QString()); + } +} + + +void SelfInformationWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/SelfInformationWidget.h b/src/widget/SelfInformationWidget.h new file mode 100644 index 0000000..0b054f1 --- /dev/null +++ b/src/widget/SelfInformationWidget.h @@ -0,0 +1,45 @@ +/*! + * \brief Widget for starting the self information workflow. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class SelfInformationWidget; +} + +namespace governikus +{ + +class SelfInformationWidget + : public QWidget +{ + Q_OBJECT + + public: + SelfInformationWidget(QWidget* pParent = nullptr); + virtual ~SelfInformationWidget() override; + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + Q_SIGNALS: + void selfAuthenticationRequested(); + + private: + QScopedPointer mUi; + QScopedPointer mPixDescLogoLabel; + + virtual void paintEvent(QPaintEvent*) override; + + private Q_SLOTS: + void onSettingsChanged(); +}; + +} /* namespace governikus */ diff --git a/src/widget/SelfInformationWidget.ui b/src/widget/SelfInformationWidget.ui new file mode 100644 index 0000000..5c98d25 --- /dev/null +++ b/src/widget/SelfInformationWidget.ui @@ -0,0 +1,196 @@ + + + SelfInformationWidget + + + + 0 + 0 + 607 + 375 + + + + + 20 + + + 20 + + + 20 + + + 20 + + + + + + 20 + + + 10 + + + 20 + + + 10 + + + + + + + Qt::TabFocus + + + eID Logo + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::TabFocus + + + You can use your ID card anywhere you see this logo. + + + true + + + + + + + + + + + + + 20 + + + 20 + + + 20 + + + 20 + + + + + + + Qt::TabFocus + + + + + + See my personal data + + + true + + + + + + + + + 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. + + + true + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + See my personal data now... + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/widget/SettingsWidget.cpp b/src/widget/SettingsWidget.cpp new file mode 100644 index 0000000..64b389a --- /dev/null +++ b/src/widget/SettingsWidget.cpp @@ -0,0 +1,352 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SettingsWidget.h" + +#include "AppSettings.h" +#include "ui_SettingsWidget.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + +SettingsWidget::SettingsWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::SettingsWidget()) + , mWorkflowRunning(false) + , mSettingsChanged(false) +{ + mUi->setupUi(this); + + connect(mUi->diagnosisButton, &QAbstractButton::clicked, this, &SettingsWidget::diagnosisRequested); + + connect(mUi->generalTab, &GeneralSettingsWidget::settingsChanged, this, &SettingsWidget::onSettingsChanged); + connect(mUi->pinTab, &PinSettingsWidget::firePinButtonEnabledUpdated, this, &SettingsWidget::onUpdateButtonState); + connect(mUi->pinTab, &PinSettingsWidget::firePinButtonEnabledUpdated, this, &SettingsWidget::onUpdateApplyButtonText); + + connect(mUi->cancelButton, &QPushButton::clicked, this, &SettingsWidget::onCancelButtonClicked); + connect(mUi->applyButton, &QPushButton::clicked, this, &SettingsWidget::onApplyButtonClicked); + + connect(mUi->settingsTabWidget, &QTabWidget::currentChanged, this, &SettingsWidget::onTabChanged); + + mUi->pinTab->setUseScreenKeyboard(AppSettings::getInstance().getGeneralSettings().isUseScreenKeyboard()); + connect(this, &SettingsWidget::fireBackspacePressedOnApply, mUi->pinTab, &PinSettingsWidget::onBackspacePressedOnApply); + +#ifndef QT_NO_DEBUG + mDeveloperTab.reset(new DeveloperSettingsWidget()); + mDeveloperTab->setObjectName(QStringLiteral("developerTab")); + mUi->settingsTabWidget->addTab(mDeveloperTab.data(), QString()); + setDeveloperTabName(); + + connect(mDeveloperTab.data(), &DeveloperSettingsWidget::fireSettingsChanged, this, &SettingsWidget::onSettingsChanged); +#endif + + setSettingsChanged(false); + onUpdateApplyButtonText(); +} + + +SettingsWidget::~SettingsWidget() +{ +} + + +void SettingsWidget::keyPressEvent(QKeyEvent* pEvent) +{ + if (pEvent->key() == Qt::Key_Backspace && mUi->applyButton->hasFocus()) + { + Q_EMIT fireBackspacePressedOnApply(); + } + QWidget::keyPressEvent(pEvent); +} + + +void SettingsWidget::workflowStarted() +{ + mWorkflowRunning = true; + + // disable the non-selected tabs + int tabCount = mUi->settingsTabWidget->count(); + for (int i = 0; i < tabCount; ++i) + { + mUi->settingsTabWidget->setTabEnabled(i, i == mUi->settingsTabWidget->currentIndex()); + } + + onUpdateButtonState(); +} + + +void SettingsWidget::workflowFinished() +{ + mWorkflowRunning = false; + + // enable all tabs + int tabCount = mUi->settingsTabWidget->count(); + for (int i = 0; i < tabCount; ++i) + { + mUi->settingsTabWidget->setTabEnabled(i, true); + } + + onUpdateButtonState(); + + if (mUi->pinTab->isVisible()) + { + QMetaObject::invokeMethod(mUi->pinTab, "updateReaders", Qt::QueuedConnection); + } +} + + +void SettingsWidget::switchToGuiModule(GuiModule pModule) +{ + switch (pModule) + { + case GuiModule::START_PAGE: + case GuiModule::IDENTIFY: + // not handled here + break; + + case GuiModule::GENERAL_SETTINGS: + mUi->settingsTabWidget->setCurrentWidget(mUi->generalTab); + break; + + case GuiModule::PIN_SETTINGS: + mUi->settingsTabWidget->setCurrentWidget(mUi->pinTab); + break; + + case GuiModule::DEVICE_SETTINGS: + mUi->settingsTabWidget->setCurrentWidget(mUi->readerDeviceTab); + break; + } +} + + +void SettingsWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void SettingsWidget::hideEvent(QHideEvent* pEvent) +{ + onTabChanged(-1); + QWidget::hideEvent(pEvent); +} + + +void SettingsWidget::onTabChanged(int pIndex) +{ + if (mUi->settingsTabWidget->widget(pIndex) != mUi->generalTab) + { + if (mSettingsChanged) + { + showSettingsChangedMessage(); + } + mUi->pinTab->setUseScreenKeyboard(AppSettings::getInstance().getGeneralSettings().isUseScreenKeyboard()); + } + else + { + setSettingsChanged(mSettingsChanged); + } + + onUpdateApplyButtonText(); + onUpdateButtonState(); +} + + +void SettingsWidget::showSettingsChangedMessage() +{ + QMessageBox msgBox(this); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Apply settings?")); + msgBox.setWindowModality(Qt::WindowModal); + msgBox.setText(tr("Do you want to apply the changes?")); + + if (msgBox.exec() == QMessageBox::Yes) + { + applyAppSettings(); + } + else + { + resetSettings(); + } +} + + +void SettingsWidget::onApplyButtonClicked() +{ + const QWidget* const currentWidget = mUi->settingsTabWidget->currentWidget(); + if (currentWidget == mUi->pinTab) + { + // change PIN button clicked + if (mUi->pinTab->getMode() == PinSettingsWidget::Mode::AfterPinChange) + { + mUi->pinTab->setMode(PinSettingsWidget::Mode::Normal); + mUi->pinTab->updateReaders(); + } + else + { + if (mUi->pinTab->isVisible()) + { + Q_EMIT changePinRequested(); + } + } + } + else if (currentWidget == mUi->generalTab +#ifndef QT_NO_DEBUG + || currentWidget == mDeveloperTab.data() +#endif + ) + { + applyAppSettings(); + } + else if (currentWidget == mUi->readerDeviceTab) + { + mUi->settingsTabWidget->setCurrentWidget(mUi->generalTab); + } + +} + + +bool SettingsWidget::isSettingsChanged() +{ + return mSettingsChanged; +} + + +void SettingsWidget::applyAppSettings() +{ + // apply button clicked + mUi->generalTab->apply(); +#ifndef QT_NO_DEBUG + mDeveloperTab->apply(); +#endif + + setSettingsChanged(false); +} + + +void SettingsWidget::onCancelButtonClicked() +{ + resetSettings(); + Q_EMIT settingsDone(); +} + + +void SettingsWidget::onSettingsChanged() +{ + setSettingsChanged(true); +} + + +void SettingsWidget::resetSettings() +{ + mUi->generalTab->reset(); +#ifndef QT_NO_DEBUG + mDeveloperTab->reset(); +#endif + setSettingsChanged(false); +} + + +QString SettingsWidget::getActiveTabObjectName() +{ + return mUi->settingsTabWidget->currentWidget()->objectName(); +} + + +void SettingsWidget::setSettingsChanged(bool pChanged) +{ + mSettingsChanged = pChanged; + onUpdateButtonState(); +} + + +void SettingsWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + setDeveloperTabName(); + onUpdateApplyButtonText(); + + } + QWidget::changeEvent(pEvent); +} + + +void SettingsWidget::setDeveloperTabName() +{ +#ifndef QT_NO_DEBUG + mUi->settingsTabWidget->setTabText(mUi->settingsTabWidget->indexOf(mDeveloperTab.data()), tr("Developer Settings")); +#endif +} + + +void SettingsWidget::onUpdateApplyButtonText() +{ + const QWidget* const currentWidget = mUi->settingsTabWidget->currentWidget(); + if (currentWidget == mUi->generalTab +#ifndef QT_NO_DEBUG + || currentWidget == mDeveloperTab.data() +#endif + ) + { + mUi->applyButton->setText(tr("Apply")); + } + else if (currentWidget == mUi->pinTab) + { + mUi->applyButton->setText(mUi->pinTab->getButtonText()); + } + else if (currentWidget == mUi->readerDeviceTab) + { + mUi->applyButton->setText(tr("OK")); + } +} + + +void SettingsWidget::onUpdateButtonState() +{ + QPushButton* const applyButton = mUi->applyButton; + QPushButton* const cancelButton = mUi->cancelButton; + if (mWorkflowRunning == true) + { + applyButton->setEnabled(false); + cancelButton->setEnabled(false); + return; + } + + cancelButton->setEnabled(true); + + const QWidget* const currentWidget = mUi->settingsTabWidget->currentWidget(); + if (currentWidget == mUi->generalTab +#ifndef QT_NO_DEBUG + || currentWidget == mDeveloperTab.data() +#endif + ) + { + applyButton->setEnabled(mSettingsChanged); + } + else if (currentWidget == mUi->pinTab) + { + const bool pinButtonEnabled = mUi->pinTab->getPinButtonEnabled(); + mUi->applyButton->setEnabled(pinButtonEnabled); + if (pinButtonEnabled) + { + applyButton->setAutoDefault(true); + applyButton->setDefault(true); + applyButton->setFocus(); + } + } + else if (currentWidget == mUi->readerDeviceTab) + { + applyButton->setEnabled(true); + } +} diff --git a/src/widget/SettingsWidget.h b/src/widget/SettingsWidget.h new file mode 100644 index 0000000..2a0b388 --- /dev/null +++ b/src/widget/SettingsWidget.h @@ -0,0 +1,81 @@ +/*! + * \brief Widget for the settings. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "DeveloperSettingsWidget.h" +#include "generic/GuiModule.h" + +#include + + +namespace Ui +{ +class SettingsWidget; +} + +namespace governikus +{ + +class SettingsWidget + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + bool mWorkflowRunning; + bool mSettingsChanged; + +#ifndef QT_NO_DEBUG + QScopedPointer mDeveloperTab; +#endif + + void resetSettings(); + void setSettingsChanged(bool pChanged); + void applyAppSettings(); + void setDeveloperTabName(); + + public Q_SLOTS: + void onTabChanged(int pIndex); + + private Q_SLOTS: + void onApplyButtonClicked(); + void onCancelButtonClicked(); + + void onUpdateButtonState(); + void onUpdateApplyButtonText(); + void onSettingsChanged(); + + protected: + virtual void paintEvent(QPaintEvent*) override; + virtual void hideEvent(QHideEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + public: + SettingsWidget(QWidget* pParent = nullptr); + virtual ~SettingsWidget() override; + + void keyPressEvent(QKeyEvent* pEvent) override; + + void workflowStarted(); + void workflowFinished(); + + void switchToGuiModule(GuiModule pModule); + + QString getActiveTabObjectName(); + + bool isSettingsChanged(); + void showSettingsChangedMessage(); + + Q_SIGNALS: + void changePinRequested(); + void diagnosisRequested(); + void settingsDone(); + void fireBackspacePressedOnApply(); +}; + +} /* namespace governikus */ diff --git a/src/widget/SettingsWidget.ui b/src/widget/SettingsWidget.ui new file mode 100644 index 0000000..a914833 --- /dev/null +++ b/src/widget/SettingsWidget.ui @@ -0,0 +1,137 @@ + + + SettingsWidget + + + + 0 + 0 + 400 + 300 + + + + + 20 + + + 20 + + + 20 + + + 20 + + + + + 0 + + + + General + + + + + PIN Management + + + + + Card Readers + + + + + + + + Qt::Vertical + + + + 20 + 121 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Diagnosis... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Apply + + + + + + + + + + + governikus::GeneralSettingsWidget + QWidget +
GeneralSettingsWidget.h
+ 1 +
+ + governikus::PinSettingsWidget + QWidget +
PinSettingsWidget.h
+ 1 +
+ + governikus::ReaderDeviceWidget + QWidget +
ReaderDeviceWidget.h
+ 1 +
+
+ + +
diff --git a/src/widget/SetupAssistantGui.cpp b/src/widget/SetupAssistantGui.cpp new file mode 100644 index 0000000..4abd3fa --- /dev/null +++ b/src/widget/SetupAssistantGui.cpp @@ -0,0 +1,52 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SetupAssistantGui.h" + +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +SetupAssistantGui::SetupAssistantGui(QWidget* pParentWidget) + : QObject(pParentWidget) + , mWizard(nullptr) +{ +} + + +SetupAssistantGui::~SetupAssistantGui() +{ +} + + +void SetupAssistantGui::activate() +{ + if (!mWizard) + { + QWidget* dialogParent = qobject_cast(parent()); + if (!dialogParent) + { + return; + } + + mWizard = new SetupAssistantWizard(dialogParent); + connect(mWizard, &SetupAssistantWizard::fireChangePinButtonClicked, this, &SetupAssistantGui::fireChangePinButtonClicked); + } + + mWizard->exec(); +} + + +void SetupAssistantGui::deactivate() +{ + if (mWizard) + { + mWizard->close(); + } +} diff --git a/src/widget/SetupAssistantGui.h b/src/widget/SetupAssistantGui.h new file mode 100644 index 0000000..ae79247 --- /dev/null +++ b/src/widget/SetupAssistantGui.h @@ -0,0 +1,36 @@ +/*! + * \brief Qt widget based SetupAssistantUi implementation. + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "SetupAssistantWizard.h" + +class QWidget; + +namespace governikus +{ + +class SetupAssistantGui + : public QObject +{ + Q_OBJECT + + private: + QPointer mWizard; + + public: + SetupAssistantGui(QWidget* pParentWidget); + virtual ~SetupAssistantGui(); + + void activate(); + void deactivate(); + + Q_SIGNALS: + void fireChangePinButtonClicked(); + +}; + +} /* namespace governikus */ diff --git a/src/widget/SetupAssistantWizard.cpp b/src/widget/SetupAssistantWizard.cpp new file mode 100644 index 0000000..34bf665 --- /dev/null +++ b/src/widget/SetupAssistantWizard.cpp @@ -0,0 +1,280 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SetupAssistantWizard.h" + +#include "AppSettings.h" +#include "Env.h" +#include "generic/HelpAction.h" +#include "ReaderDeviceWidget.h" +#include "ReaderInfo.h" +#include "ReaderManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace governikus; + +CardReaderPage::CardReaderPage(const QString& pTitle, const QString& pAccessibleName) + : mWidget(new ReaderDeviceWidget(this)) +{ + setTitle(pTitle); + mWidget->prependAccessibleName(pAccessibleName); + + QVBoxLayout* cardReaderPageVLayout = new QVBoxLayout(this); + cardReaderPageVLayout->addWidget(mWidget); +} + + +SetupAssistantWizard::SetupAssistantWizard(QWidget* pParent) + : QWizard(pParent) + , mPageCount(0) + , mNoScriptFinder() + , mSaveHistoryCheckBox(new QCheckBox(this)) + , mChangeTransportPinButton() +{ +#ifdef Q_OS_MACOS + static const int MIN_HEIGHT = 700; +#else + static const int MIN_HEIGHT = 500; +#endif + + setObjectName(QStringLiteral("setupAssistant")); + installEventFilter(this); + setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("setup assistant")); + setMinimumSize(700, MIN_HEIGHT); + setWizardStyle(QWizard::ClassicStyle); + setWindowModality(Qt::WindowModal); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setOption(QWizard::NoCancelButton, false); + setAttribute(Qt::WA_DeleteOnClose); + + mPageCount = 3; + if (mNoScriptFinder.isExtensionFound()) + { + ++mPageCount; + } + + addPage(createWizardInitialPinPage()); + if (mNoScriptFinder.isExtensionFound()) + { + addPage(createWizardNoScriptExtensionPage()); + } + addPage(createWizardCardReaderPage()); + addPage(createConclusionPage()); +} + + +SetupAssistantWizard::~SetupAssistantWizard() +{ +} + + +QString SetupAssistantWizard::createAccessibleName(const QString& pName, const QString& pText) const +{ + const QString& stepIndex = QString::number(pageIds().size() + 1); + const QString& pageCount = QString::number(mPageCount); + + auto result = pName + QStringLiteral(". ") + tr("Step %1 of %2").arg(stepIndex, pageCount) + QStringLiteral(". ") + pText; + return result.remove(QLatin1Char('"')).trimmed(); +} + + +QString SetupAssistantWizard::createTitle(const QString& pName) const +{ + const QString& stepIndex = QString::number(pageIds().size() + 1); + const QString& pageCount = QString::number(mPageCount); + + return QStringLiteral("
") + + tr("Step %1 of %2").arg(stepIndex, pageCount) + + QStringLiteral("
%1
").arg(pName); +} + + +QString SetupAssistantWizard::createDescription(const QString& pTitle, const QString& pSummary) const +{ + return QStringLiteral("
%1

%2").arg(pTitle, pSummary); +} + + +QWizardPage* SetupAssistantWizard::createWizardInitialPinPage() +{ + QWizardPage* initialPinPage = new QWizardPage; + const auto& introduction = tr("Introduction"); + initialPinPage->setTitle(createTitle(introduction)); + + const auto& welcome = tr("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.").arg(mPageCount); + QLabel* label = new QLabel(welcome); + label->setWordWrap(true); + label->setFocusPolicy(Qt::TabFocus); + label->setAccessibleName(createAccessibleName(introduction, welcome)); + + QVBoxLayout* initialPinPageLayout = new QVBoxLayout; + initialPinPageLayout->addWidget(label); + + const auto& historyTitle = tr("History"); + const auto& historySummary = tr("AusweisApp2 offers saving the course of your authentications in a history." + " Subsequently you can activate this option."); + QLabel* historyDescLabel = new QLabel(createDescription(historyTitle, historySummary)); + historyDescLabel->setWordWrap(true); + historyDescLabel->setFocusPolicy(Qt::TabFocus); + historyDescLabel->setAccessibleName(createAccessibleName(historyTitle, historySummary)); + + initialPinPageLayout->addWidget(historyDescLabel); + + QWidget* saveHistoryWidget = new QWidget(this); + + QSizePolicy saveHistorySizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + saveHistorySizePolicy.setHorizontalStretch(0); + saveHistorySizePolicy.setVerticalStretch(0); + saveHistorySizePolicy.setHeightForWidth(saveHistoryWidget->sizePolicy().hasHeightForWidth()); + saveHistoryWidget->setSizePolicy(saveHistorySizePolicy); + + QFormLayout* saveHistoryFormLayout = new QFormLayout(saveHistoryWidget); + saveHistoryFormLayout->setHorizontalSpacing(30); + saveHistoryFormLayout->setContentsMargins(11, 11, 11, 11); + saveHistoryFormLayout->setContentsMargins(0, 5, 0, 20); + + QLabel* saveHistoryLabel = new QLabel(); + saveHistoryLabel->setFocusPolicy(Qt::TabFocus); + saveHistoryLabel->setText(historyTitle + QLatin1Char(':')); + + mSaveHistoryCheckBox->setText(tr("save")); + mSaveHistoryCheckBox->setAccessibleName(tr("save history")); + mSaveHistoryCheckBox->setChecked(AppSettings::getInstance().getHistorySettings().isEnabled()); + + saveHistoryFormLayout->setWidget(0, QFormLayout::LabelRole, saveHistoryLabel); + saveHistoryFormLayout->setWidget(0, QFormLayout::FieldRole, mSaveHistoryCheckBox); + + initialPinPageLayout->addWidget(saveHistoryWidget); + + initialPinPage->setLayout(initialPinPageLayout); + + return initialPinPage; +} + + +QWizardPage* SetupAssistantWizard::createWizardCardReaderPage() +{ + const auto& title = tr("Card Readers"); + const auto& titleField = createTitle(title); + const auto& accessibleField = createAccessibleName(title); + return new CardReaderPage(titleField, accessibleField); +} + + +QWizardPage* SetupAssistantWizard::createWizardNoScriptExtensionPage() +{ + QWizardPage* wizardPage = new QWizardPage; + const auto& title = tr("Firefox extension NoScript"); + wizardPage->setTitle(createTitle(title)); + + QString descriptionText = tr("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.").arg(QCoreApplication::applicationName()); + QLabel* label = new QLabel(descriptionText); + label->setWordWrap(true); + label->setFocusPolicy(Qt::TabFocus); + label->setAccessibleName(createAccessibleName(title, descriptionText)); + + QVBoxLayout* pageLayout = new QVBoxLayout; + pageLayout->addWidget(label); + wizardPage->setLayout(pageLayout); + + return wizardPage; +} + + +QWizardPage* SetupAssistantWizard::createConclusionPage() +{ + QWizardPage* conclusionPage = new QWizardPage; + const auto& almostDone = tr("Almost done!"); + conclusionPage->setTitle(createTitle(almostDone)); + + QVBoxLayout* conclusionPageVLayout = new QVBoxLayout(conclusionPage); + + + const auto& title = tr("Personal 6 - digit PIN"); + const auto& desc = tr("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."); + QLabel* transportPinLabel = new QLabel(createDescription(title, desc)); + transportPinLabel->setWordWrap(true); + transportPinLabel->setFocusPolicy(Qt::TabFocus); + transportPinLabel->setAccessibleName(createAccessibleName(title, desc)); + + conclusionPageVLayout->addWidget(transportPinLabel); + + mChangeTransportPinButton = new QPushButton(conclusionPage); + mChangeTransportPinButton->setText(tr("Change PIN")); + connect(mChangeTransportPinButton.data(), &QAbstractButton::clicked, this, &SetupAssistantWizard::onChangeTransportPinButtonPressed); + + QSizePolicy transportPinSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + transportPinSizePolicy.setHorizontalStretch(0); + transportPinSizePolicy.setVerticalStretch(0); + transportPinSizePolicy.setHeightForWidth(mChangeTransportPinButton->sizePolicy().hasHeightForWidth()); + mChangeTransportPinButton->setSizePolicy(transportPinSizePolicy); + + conclusionPageVLayout->addWidget(mChangeTransportPinButton); + + + const auto conclusionDesc = tr("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."); + QLabel* conclusionDescLabel = new QLabel(QStringLiteral("
") + conclusionDesc); + conclusionDescLabel->setWordWrap(true); + conclusionDescLabel->setFocusPolicy(Qt::TabFocus); + conclusionDescLabel->setAccessibleName(createAccessibleName(almostDone, conclusionDesc)); + + conclusionPageVLayout->addWidget(conclusionDescLabel); + + QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + conclusionPageVLayout->addItem(verticalSpacer); + + return conclusionPage; +} + + +void SetupAssistantWizard::onChangeTransportPinButtonPressed() +{ + auto& historySettings = AppSettings::getInstance().getHistorySettings(); + historySettings.setEnabled(mSaveHistoryCheckBox->isChecked()); + historySettings.save(); + Q_EMIT fireChangePinButtonClicked(); + close(); +} + + +void SetupAssistantWizard::accept() +{ + auto& historySettings = AppSettings::getInstance().getHistorySettings(); + historySettings.setEnabled(mSaveHistoryCheckBox->isChecked()); + historySettings.save(); + hide(); +} + + +bool SetupAssistantWizard::eventFilter(QObject* pObject, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_F1) + { + HelpAction::openContextHelp(objectName()); + return true; + } + } + return QWizard::eventFilter(pObject, pEvent); +} diff --git a/src/widget/SetupAssistantWizard.h b/src/widget/SetupAssistantWizard.h new file mode 100644 index 0000000..f528ef6 --- /dev/null +++ b/src/widget/SetupAssistantWizard.h @@ -0,0 +1,79 @@ +/*! + * \brief Setup assistant wizard before application startup. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "NoScriptFinder.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace governikus +{ + +class ReaderDeviceWidget; +class SetupAssistantWizard; + + +class CardReaderPage + : public QWizardPage +{ + Q_OBJECT + + private: + ReaderDeviceWidget* const mWidget; + + public: + CardReaderPage(const QString& pTitle, const QString& pAccessibleName); + virtual ~CardReaderPage() = default; +}; + + +class SetupAssistantWizard + : public QWizard +{ + Q_OBJECT + + int mPageCount; + NoScriptFinder mNoScriptFinder; + QPointer mSaveHistoryCheckBox; + QPointer mChangeTransportPinButton; + + public: + SetupAssistantWizard(QWidget* pParent = nullptr); + virtual ~SetupAssistantWizard() override; + + virtual void accept() override; + bool isRemindWizardAgain(); + + Q_SIGNALS: + void fireChangePinButtonClicked(); + + private: + QString createAccessibleName(const QString& pName, const QString& pText = QString()) const; + QString createTitle(const QString& pName) const; + QString createDescription(const QString& pTitle, const QString& pSummary) const; + QWizardPage* createWizardInitialPinPage(); + QWizardPage* createWizardCardReaderPage(); + QWizardPage* createWizardNoScriptExtensionPage(); + QWizardPage* createConclusionPage(); + + private Q_SLOTS: + void onChangeTransportPinButtonPressed(); + + protected: + virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override; + +}; + +} /* namespace governikus */ diff --git a/src/widget/UIPlugInWidgets.cpp b/src/widget/UIPlugInWidgets.cpp new file mode 100644 index 0000000..30d37f8 --- /dev/null +++ b/src/widget/UIPlugInWidgets.cpp @@ -0,0 +1,108 @@ +/*! + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "UIPlugInWidgets.h" + +#include "workflow/WorkflowAuthenticateQtGui.h" +#include "workflow/WorkflowChangePinQtGui.h" +#include "workflow/WorkflowSelfInfoQtGui.h" + +using namespace governikus; + +UIPlugInWidgets::UIPlugInWidgets() + : UIPlugIn() + , mGui() +{ + connect(&mGui, &AppQtGui::quitApplicationRequested, this, &UIPlugIn::fireQuitApplicationRequest); + connect(&mGui, &AppQtGui::fireChangePinRequested, this, &UIPlugIn::fireChangePinRequest); + connect(&mGui, &AppQtGui::selfAuthenticationRequested, this, &UIPlugIn::fireSelfAuthenticationRequested); + connect(&mGui, &AppQtGui::fireSwitchToReaderSettingsRequested, this, &UIPlugIn::onSwitchToReaderSettingsRequested); + connect(&mGui, &AppQtGui::fireCloseReminderFinished, this, &UIPlugInWidgets::fireCloseReminderFinished); + connect(this, &UIPlugIn::fireShowUserInformation, &mGui, &AppQtGui::onShowUserInformation); + mGui.init(); +} + + +UIPlugInWidgets::~UIPlugInWidgets() +{ +} + + +void UIPlugInWidgets::doShutdown() +{ + mGui.shutdown(); +} + + +void UIPlugInWidgets::onWorkflowStarted(QSharedPointer pContext) +{ + pContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::REMOTE}); + + QSharedPointer currentWorkflowGui; + if (auto changePinContext = pContext.objectCast()) + { + currentWorkflowGui = mGui.createWorkflowChangePinUi(changePinContext); + mGui.activateWorkflowUi(currentWorkflowGui); + return; + } + + bool allowHideAfterWorklow = true; + if (auto selfAuthContext = pContext.objectCast()) + { + if (mGui.askChangeTransportPinNow()) + { + allowHideAfterWorklow = false; + Q_EMIT pContext->fireCancelWorkflow(); + } + currentWorkflowGui = mGui.createWorkflowSelfInfoUi(selfAuthContext); + } + else if (auto authContext = pContext.objectCast()) + { + if (mGui.askChangeTransportPinNow()) + { + allowHideAfterWorklow = false; + Q_EMIT pContext->fireCancelWorkflow(); + } + currentWorkflowGui = mGui.createWorkflowAuthenticateUi(authContext); + } + + Q_ASSERT(currentWorkflowGui != nullptr); + mGui.activateWorkflowUi(currentWorkflowGui, allowHideAfterWorklow); + pContext->setStateApproved(); +} + + +void UIPlugInWidgets::onWorkflowFinished(QSharedPointer pContext) +{ + Q_UNUSED(pContext) + mGui.deactivateCurrentWorkflowUi(); +} + + +void UIPlugInWidgets::onApplicationStarted() +{ + mGui.onApplicationStarted(); +} + + +void UIPlugInWidgets::onShowUi(UiModule pModule) +{ + mGui.show(pModule); +} + + +void UIPlugInWidgets::onShowReaderSettings() +{ + mGui.switchToReaderSettings(); +} + + +#ifndef QT_NO_NETWORKPROXY +void UIPlugInWidgets::onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) +{ + mGui.onProxyAuthenticationRequired(pProxy, pAuthenticator); +} + + +#endif diff --git a/src/widget/UIPlugInWidgets.h b/src/widget/UIPlugInWidgets.h new file mode 100644 index 0000000..9b49d33 --- /dev/null +++ b/src/widget/UIPlugInWidgets.h @@ -0,0 +1,43 @@ +/*! + * \brief QWidgets implementation of UIPlugIn. + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppQtGui.h" +#include "view/UIPlugIn.h" + +namespace governikus +{ + +class AppQtGui; + +class UIPlugInWidgets + : public UIPlugIn +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "governikus.UIPlugIn" FILE "metadata.json") + Q_INTERFACES(governikus::UIPlugIn) + + private: + AppQtGui mGui; + + public: + UIPlugInWidgets(); + virtual ~UIPlugInWidgets() override; + + public Q_SLOTS: + virtual void doShutdown() override; + virtual void onWorkflowStarted(QSharedPointer pContext) override; + virtual void onWorkflowFinished(QSharedPointer pContext) override; + virtual void onApplicationStarted() override; + virtual void onShowUi(UiModule pModule) override; + virtual void onShowReaderSettings() override; +#ifndef QT_NO_NETWORKPROXY + virtual void onProxyAuthenticationRequired(const QNetworkProxy& pProxy, QAuthenticator* pAuthenticator) override; +#endif +}; + +} /* namespace governikus */ diff --git a/src/widget/UpdateWindow.cpp b/src/widget/UpdateWindow.cpp new file mode 100644 index 0000000..953d876 --- /dev/null +++ b/src/widget/UpdateWindow.cpp @@ -0,0 +1,79 @@ +/*! + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Env.h" +#include "Service.h" +#include "UpdateWindow.h" + +#include "ui_UpdateWindow.h" + +#include +#include + +using namespace governikus; + +UpdateWindow::UpdateWindow(QWidget* pParent) + : QDialog(pParent) + , mUi() + , mUpdateData() +{ + setAttribute(Qt::WA_DeleteOnClose, true); + + mUpdateData = Env::getSingleton()->getUpdateData(); + fillData(); + show(); +} + + +UpdateWindow::~UpdateWindow() +{ +} + + +void UpdateWindow::onUpdateClicked() +{ + const auto& url = mUpdateData.getUrl(); + qDebug() << "Download application update:" << url; + if (!QDesktopServices::openUrl(url)) + { + Q_EMIT fireShowUpdateDialog(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() +{ + Env::getSingleton()->skipVersion(mUpdateData.getVersion()); + close(); +} + + +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(QStringLiteral("%1").arg(mUpdateData.getUrl().toString())); + mUi->releaseNotes->setHtml(mUpdateData.getNotes().isEmpty() ? tr("

Download of release notes failed

") : mUpdateData.getNotes()); + mUi->releaseNotes->setAccessibleName(mUi->releaseNotes->toPlainText()); +} + + +void UpdateWindow::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange && mUi) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/UpdateWindow.h b/src/widget/UpdateWindow.h new file mode 100644 index 0000000..ed9365b --- /dev/null +++ b/src/widget/UpdateWindow.h @@ -0,0 +1,49 @@ +/*! + * \brief Window for application updates + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppUpdateData.h" + +#include +#include + +namespace Ui +{ +class UpdateWindow; +} + +namespace governikus +{ + +class UpdateWindow + : public QDialog +{ + Q_OBJECT + + private: + QScopedPointer mUi; + bool mSilent; + AppUpdateData mUpdateData; + + void fillData(); + + protected: + virtual void changeEvent(QEvent* pEvent) override; + + public: + UpdateWindow(QWidget* pParent = nullptr); + virtual ~UpdateWindow() override; + + private Q_SLOTS: + void onUpdateClicked(); + void onSkipVersionClicked(); + + Q_SIGNALS: + void fireShowUpdateDialog(QMessageBox::Icon pIcon, const QString& pMsg); +}; + +} /* namespace governikus */ diff --git a/src/widget/UpdateWindow.ui b/src/widget/UpdateWindow.ui new file mode 100644 index 0000000..1f67d82 --- /dev/null +++ b/src/widget/UpdateWindow.ui @@ -0,0 +1,182 @@ + + + UpdateWindow + + + Qt::ApplicationModal + + + + 0 + 0 + 600 + 450 + + + + Software Update + + + + :/images/npa.svg:/images/npa.svg + + + + + + + + + 75 + true + + + + Qt::TabFocus + + + A new version of AusweisApp2 is available! + + + + + + + Qt::TabFocus + + + AusweisApp2 %1 is now available - you have %2. Would you like to download it now? + + + + + + + Qt::TabFocus + + + The update file is located at: + + + + + + + Qt::TabFocus + + + LinkLabel + + + true + + + Qt::TextBrowserInteraction + + + + + + + + 75 + true + + + + Qt::TabFocus + + + Release Notes: + + + + + + + 160 + 80 + + + + Qt::WheelFocus + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse + + + + + + + + + + Qt::TabFocus + + + Download this update and close current "AusweisApp2". Install the update and start "AusweisApp2" again. + + + + + + + Qt::TabFocus + + + When you click "Download update", this link will be opened in your browser. + + + + + + + + + Skip update + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Remind me later + + + + + + + Download update + + + true + + + true + + + + + + + + + + + + diff --git a/src/widget/generic/BusyOverlay.cpp b/src/widget/generic/BusyOverlay.cpp new file mode 100644 index 0000000..0560055 --- /dev/null +++ b/src/widget/generic/BusyOverlay.cpp @@ -0,0 +1,86 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "BusyOverlay.h" +#include "ui_BusyOverlay.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + +BusyOverlay::BusyOverlay(bool pStart, QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::BusyOverlay()) + , mMovie(new QMovie(QStringLiteral(":/images/busy_animation.gif"))) +{ + mUi->setupUi(this); + + mUi->busyAnimationLabel->setMovie(mMovie.data()); + + setStyleSheet(QStringLiteral("background-color: white;")); + + QGraphicsOpacityEffect* opacity = new QGraphicsOpacityEffect(this); + opacity->setOpacity(0.9); + setGraphicsEffect(opacity); + + if (pStart) + { + mMovie->start(); + } +} + + +BusyOverlay::~BusyOverlay() +{ +} + + +void BusyOverlay::startAnimation() +{ + if (mMovie->state() != QMovie::Running) + { + mMovie->start(); + } +} + + +void BusyOverlay::stopAnimation() +{ + if (mMovie->state() == QMovie::Running) + { + mMovie->stop(); + } +} + + +QSize BusyOverlay::sizeHint() const +{ + // make square + QSize hint = QWidget::sizeHint(); + int result = std::max(hint.width(), hint.height()); + return QSize(result, result); +} + + +void BusyOverlay::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void BusyOverlay::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/generic/BusyOverlay.h b/src/widget/generic/BusyOverlay.h new file mode 100644 index 0000000..ea6ebe7 --- /dev/null +++ b/src/widget/generic/BusyOverlay.h @@ -0,0 +1,45 @@ +/*! + * \brief Widget for the settings. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class BusyOverlay; +} + +class QMovie; + +namespace governikus +{ + +class BusyOverlay + : public QWidget +{ + Q_OBJECT + + public: + BusyOverlay(bool pStart = true, QWidget* pParent = nullptr); + virtual ~BusyOverlay() override; + + void startAnimation(); + void stopAnimation(); + + virtual QSize sizeHint() const override; + + protected: + void paintEvent(QPaintEvent*) override; + void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + QScopedPointer mMovie; +}; + +} /* namespace governikus */ diff --git a/src/gui/generic/BusyOverlay.ui b/src/widget/generic/BusyOverlay.ui similarity index 100% rename from src/gui/generic/BusyOverlay.ui rename to src/widget/generic/BusyOverlay.ui diff --git a/src/widget/generic/BusyOverlayContainer.cpp b/src/widget/generic/BusyOverlayContainer.cpp new file mode 100644 index 0000000..958fd92 --- /dev/null +++ b/src/widget/generic/BusyOverlayContainer.cpp @@ -0,0 +1,45 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "BusyOverlayContainer.h" + +#include +#include + +#include "BusyOverlay.h" + +using namespace governikus; + +BusyOverlayContainer::BusyOverlayContainer(QWidget* pWidgetToOverlay, bool pStart, QWidget* pParent) + : QStackedWidget(pParent) + , mOverlay(new BusyOverlay(pStart)) +{ + QWidget* busyOverlayContainer = new QWidget; + QBoxLayout* overlayContainerLayout = new QVBoxLayout(busyOverlayContainer); + overlayContainerLayout->addWidget(mOverlay, 0, Qt::AlignHCenter | Qt::AlignVCenter); + + QStackedLayout* stackLayout = qobject_cast(layout()); + stackLayout->setStackingMode(QStackedLayout::StackAll); + + stackLayout->addWidget(pWidgetToOverlay); + stackLayout->addWidget(busyOverlayContainer); + stackLayout->setCurrentIndex(1); +} + + +BusyOverlayContainer::~BusyOverlayContainer() +{ +} + + +void BusyOverlayContainer::startAnimation() +{ + mOverlay->startAnimation(); +} + + +void BusyOverlayContainer::stopAnimation() +{ + mOverlay->stopAnimation(); +} diff --git a/src/widget/generic/BusyOverlayContainer.h b/src/widget/generic/BusyOverlayContainer.h new file mode 100644 index 0000000..f6872de --- /dev/null +++ b/src/widget/generic/BusyOverlayContainer.h @@ -0,0 +1,32 @@ +/*! + * \brief An overlay to show a busy indicator. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class BusyOverlay; + +class BusyOverlayContainer + : public QStackedWidget +{ + Q_OBJECT + + public: + BusyOverlayContainer(QWidget* pWidgetToOverlay, bool pStart = true, QWidget* pParent = nullptr); + virtual ~BusyOverlayContainer(); + + void startAnimation(); + void stopAnimation(); + + private: + BusyOverlay* mOverlay; +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ButtonState.h b/src/widget/generic/ButtonState.h new file mode 100644 index 0000000..04d008f --- /dev/null +++ b/src/widget/generic/ButtonState.h @@ -0,0 +1,27 @@ +/*! + * \brief Defines the ButtonState enum. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +namespace governikus +{ + +enum class ButtonState +{ + /*! Button is visible, enabled, and focussed. */ + FOCUSSED, + + /*! Button is visible and enabled. */ + ENABLED, + + /*! Button is visible and disabled. */ + DISABLED, + + /*! Button is not visible. */ + HIDDEN +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ExclusiveButtonGroup.cpp b/src/widget/generic/ExclusiveButtonGroup.cpp new file mode 100644 index 0000000..920ed67 --- /dev/null +++ b/src/widget/generic/ExclusiveButtonGroup.cpp @@ -0,0 +1,120 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ExclusiveButtonGroup.h" + +#include +#include + +using namespace governikus; + +ExclusiveButtonGroup::ExclusiveButtonGroup(QObject* pParent) + : QObject(pParent) + , mButtons() +{ +} + + +ExclusiveButtonGroup::~ExclusiveButtonGroup() +{ +} + + +void ExclusiveButtonGroup::addButton(QAbstractButton* pButton) +{ + mButtons += pButton; + + pButton->installEventFilter(this); + + connect(pButton, &QAbstractButton::clicked, this, &ExclusiveButtonGroup::onButtonClicked); + connect(pButton, &QAbstractButton::pressed, this, &ExclusiveButtonGroup::onButtonPressed); + connect(pButton, &QAbstractButton::released, this, &ExclusiveButtonGroup::onButtonReleased); + connect(pButton, &QAbstractButton::toggled, this, &ExclusiveButtonGroup::onButtonToggled); +} + + +void ExclusiveButtonGroup::removeButton(QAbstractButton* pButton) +{ + if (mButtons.removeAll(pButton) == 0) + { + return; + } + + pButton->removeEventFilter(this); + + disconnect(pButton, &QAbstractButton::clicked, this, &ExclusiveButtonGroup::onButtonClicked); + disconnect(pButton, &QAbstractButton::pressed, this, &ExclusiveButtonGroup::onButtonPressed); + disconnect(pButton, &QAbstractButton::released, this, &ExclusiveButtonGroup::onButtonReleased); + disconnect(pButton, &QAbstractButton::toggled, this, &ExclusiveButtonGroup::onButtonToggled); +} + + +bool ExclusiveButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) +{ + if (QAbstractButton* button = qobject_cast(pWatched)) + { + if (pEvent->type() == QEvent::MouseButtonPress && button->isChecked()) + { + return true; + } + + if (pEvent->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_Select || keyEvent->key() == Qt::Key_Space) + { + return true; + } + } + } + + return false; +} + + +void ExclusiveButtonGroup::onButtonClicked(bool /*pChecked*/) +{ + if (QAbstractButton* button = qobject_cast(sender())) + { + Q_EMIT buttonClicked(button); + } +} + + +void ExclusiveButtonGroup::onButtonPressed() +{ + if (QAbstractButton* button = qobject_cast(sender())) + { + Q_EMIT buttonPressed(button); + } +} + + +void ExclusiveButtonGroup::onButtonReleased() +{ + if (QAbstractButton* button = qobject_cast(sender())) + { + Q_EMIT buttonReleased(button); + } +} + + +void ExclusiveButtonGroup::onButtonToggled(bool pChecked) +{ + if (QAbstractButton* button = qobject_cast(sender())) + { + if (pChecked) + { + for (auto otherButton : qAsConst(mButtons)) + { + if (otherButton != button && otherButton->isChecked()) + { + otherButton->setChecked(false); + } + } + } + + Q_EMIT buttonToggled(button, pChecked); + } +} diff --git a/src/widget/generic/ExclusiveButtonGroup.h b/src/widget/generic/ExclusiveButtonGroup.h new file mode 100644 index 0000000..f540cc8 --- /dev/null +++ b/src/widget/generic/ExclusiveButtonGroup.h @@ -0,0 +1,56 @@ +/*! + * \brief Rudimentary replacement for QButtonGroup to work around tab navigation issues. + * + * Bug in Qt 5.2.1: Buttons in a QButtonGroup cannot be navigated via the Tab key. This + * class provides a work-around for simple cases. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +class QAbstractButton; + +namespace governikus +{ + +class ExclusiveButtonGroup + : public QObject +{ + Q_OBJECT + + public: + ExclusiveButtonGroup(QObject* pParent = nullptr); + virtual ~ExclusiveButtonGroup() override; + + const QVector& getButtons() const + { + return mButtons; + } + + + void addButton(QAbstractButton* pButton); + void removeButton(QAbstractButton* pButton); + + virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; + + Q_SIGNALS: + void buttonClicked(QAbstractButton* pButton); + void buttonPressed(QAbstractButton* pButton); + void buttonReleased(QAbstractButton* pButton); + void buttonToggled(QAbstractButton* pButton, bool pChecked); + + private Q_SLOTS: + void onButtonClicked(bool pChecked); + void onButtonPressed(); + void onButtonReleased(); + void onButtonToggled(bool pChecked); + + private: + QVector mButtons; +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/GuiModule.h b/src/widget/generic/GuiModule.h new file mode 100644 index 0000000..1636a54 --- /dev/null +++ b/src/widget/generic/GuiModule.h @@ -0,0 +1,21 @@ +/*! + * \brief Defines the GuiModule enum. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +namespace governikus +{ + +enum class GuiModule +{ + START_PAGE, + IDENTIFY, + GENERAL_SETTINGS, + PIN_SETTINGS, + DEVICE_SETTINGS +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/GuiUtils.cpp b/src/widget/generic/GuiUtils.cpp new file mode 100644 index 0000000..b3576bf --- /dev/null +++ b/src/widget/generic/GuiUtils.cpp @@ -0,0 +1,101 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "GuiUtils.h" + +#include +#include +#include +#include + +using namespace governikus; + + +void GuiUtils::showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent) +{ + QMessageBox messageBox(pParent); + QString title; + QString text; + switch (pReturnCode) + { + 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 CardReturnCode::INVALID_PUK: + title = tr("Wrong PUK"); + text = tr("Please enter your PUK again."); + break; + + 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 your" + " competent authority that has issued your ID card for unblocking your PIN."); + break; + + case CardReturnCode::INVALID_PIN: + default: + title = tr("Wrong PIN"); + break; + } + + if (text.isEmpty()) + { + switch (pRetryCounter) + { + case 0: + text = tr("After three wrong entries your PIN is blocked. Using the online identification" + " function is no longer possible.

You can unblock your PIN in the" + " following dialog. The program supports you with the steps now required."); + break; + + case 1: + text = tr("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)."); + break; + + default: + text = tr("The given PIN is not correct. You have %1 tries to enter the correct PIN.").arg(pRetryCounter); + break; + } + } + + messageBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + title); + messageBox.setWindowModality(Qt::WindowModal); + messageBox.setWindowFlags(messageBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); + messageBox.setText(QStringLiteral("

%1

%2

").arg(title, text)); + messageBox.setIconPixmap(QIcon(QStringLiteral(":/images/npa.svg")).pixmap(32, 32)); + messageBox.setStandardButtons(QMessageBox::StandardButton::Ok); + + messageBox.exec(); +} + + +bool GuiUtils::showWrongPinBlockedDialog(QWidget* pParent) +{ + QMessageBox messageBox(pParent); + + QString title = tr("PIN blocked"); + QString text = tr("After three wrong entries your PIN is blocked. Using the online identification" + " function is no longer possible.
You can unblock the PIN as" + " follows:
  1. Select the \"Settings\" function.
  2. Select the \"PIN" + " Management\" tab.
  3. Follow the instructions on the" + " screen.
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 http://www.personalausweisportal.de.
" + "Do you want to unblock the PIN now?"); + messageBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + title); + messageBox.setWindowModality(Qt::WindowModal); + messageBox.setText(QStringLiteral("

%1

%2

").arg(title, text)); + messageBox.setIcon(QMessageBox::Warning); + + messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + return messageBox.exec() == QMessageBox::Yes; +} diff --git a/src/widget/generic/GuiUtils.h b/src/widget/generic/GuiUtils.h new file mode 100644 index 0000000..859d793 --- /dev/null +++ b/src/widget/generic/GuiUtils.h @@ -0,0 +1,29 @@ +/*! + * \brief Gui utility functions. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +#include "CardReturnCode.h" + +class QFrame; + + +namespace governikus +{ + +class GuiUtils + : private QObject +{ + Q_OBJECT + + public: + static void showPinCanPukErrorDialog(CardReturnCode pReturnCode, int pRetryCounter, QWidget* pParent); + static bool showWrongPinBlockedDialog(QWidget* pParent); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/HelpAction.cpp b/src/widget/generic/HelpAction.cpp new file mode 100644 index 0000000..fd817c2 --- /dev/null +++ b/src/widget/generic/HelpAction.cpp @@ -0,0 +1,143 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "HelpAction.h" + +#include "LanguageLoader.h" +#include "SingletonHelper.h" +#include "VersionNumber.h" + +#include +#include +#include +#include +#include +#include +#include + + +using namespace governikus; + +defineSingleton(HelpAction) + +Q_DECLARE_LOGGING_CATEGORY(gui) + +//Mapping object name to help file, \see AppQtMainWidget::onContentActionClicked() +const QMap HelpAction::mHelpMapping = { + {QStringLiteral("setupAssistant"), QStringLiteral("wizard-info.html")}, + {QStringLiteral("ausweisenPage"), QStringLiteral("identify.html")}, + {QStringLiteral("providerPage"), QStringLiteral("provider.html")}, + {QStringLiteral("historyPage"), QStringLiteral("history.html")}, + {QStringLiteral("generalTab"), QStringLiteral("settings-general.html")}, + {QStringLiteral("pinTab"), QStringLiteral("settings-pin-management.html")}, + {QStringLiteral("readerDeviceTab"), QStringLiteral("settings-reader-detection.html")} +}; + + +HelpAction& HelpAction::getInstance() +{ + return *Instance; +} + + +QString HelpAction::getHelpPath(QLocale::Language pLang) const +{ + const QString langDir = QCoreApplication::applicationDirPath() % QStringLiteral("/help/") % QLocale(pLang).bcp47Name().mid(0, 2) % QLatin1Char('/'); + + if (QDir(langDir).exists()) + { + return langDir; + } + + return QString(); +} + + +QLocale::Language HelpAction::getExistingHelpLanguage() const +{ + QLocale::Language lang = LanguageLoader::getInstance().getUsedLocale().language(); + if (!getHelpPath(lang).isNull()) + { + return lang; + } + + lang = LanguageLoader::getInstance().getFallbackLanguage(); + if (!getHelpPath(lang).isNull()) + { + return lang; + } + + return QLocale::AnyLanguage; +} + + +QString HelpAction::getContextMapping(const QString& pObjectName) const +{ + if (mHelpMapping.contains(pObjectName)) + { + return mHelpMapping.value(pObjectName); + } + else + { + qCWarning(gui) << "Cannot find help mapping:" << pObjectName; + } + + return QStringLiteral("index.html"); +} + + +QString HelpAction::getHelpUrl(const QString& pObjectName) const +{ + QLocale::Language lang = getExistingHelpLanguage(); + if (lang == QLocale::AnyLanguage) + { + return getOnlineUrl(); + } + + return QUrl::fromLocalFile(getHelpPath(lang)).toString() + getContextMapping(pObjectName); +} + + +QUrl HelpAction::getHelpUrlWrapper(const QString& pObjectName) const +{ + auto url = getHelpUrl(pObjectName); + if (!url.contains(QLatin1Char('#'))) + { + return url; + } + + QFile file(QDir::tempPath() + QStringLiteral("/AusweisApp2_help.html")); + if (file.open(QIODevice::WriteOnly)) + { + QTextStream stream(&file); + stream << QStringLiteral("").arg(url) << endl; + } + + return QUrl::fromLocalFile(file.fileName()); +} + + +QString HelpAction::getOnlineUrl(const QString& pObjectName) const +{ +#ifdef Q_OS_MACOS + const QLatin1String osPath("macOS"); +#else + const QLatin1String osPath("Windows"); +#endif + + const auto& appVersion = VersionNumber::getApplicationVersion().getVersionNumber(); + const QString ver = QString::number(appVersion.majorVersion()) % QLatin1Char('.') % QString::number(appVersion.minorVersion()); + const QString locale = QLocale(LanguageLoader::getInstance().getUsedLocale().language()).bcp47Name().mid(0, 2); + const QString mapping = getContextMapping(pObjectName); + return QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/handbuch/") % ver % QLatin1Char('/') % locale % QLatin1Char('/') % osPath % QLatin1Char('/') % mapping; +} + + +void HelpAction::openContextHelp(const QString& pObjectName) +{ + //const auto& url = getInstance().getHelpUrlWrapper(pObjectName); + const auto& url = QUrl(getInstance().getOnlineUrl(pObjectName)); + qCDebug(gui) << "Open manual:" << pObjectName << '|' << url; + QDesktopServices::openUrl(url); +} diff --git a/src/widget/generic/HelpAction.h b/src/widget/generic/HelpAction.h new file mode 100644 index 0000000..3166518 --- /dev/null +++ b/src/widget/generic/HelpAction.h @@ -0,0 +1,44 @@ +/*! + * \brief Helper class for mapping object name from f1 widget to help file. + * \see AppQtMainWidget::onContentActionClicked() + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + +class test_HelpAction; + +namespace governikus +{ + +class HelpAction +{ + private: + friend class ::test_HelpAction; + + static const QMap mHelpMapping; + + Q_DISABLE_COPY(HelpAction) + + QLocale::Language getExistingHelpLanguage() const; + QString getContextMapping(const QString& pObjectName) const; + QString getHelpPath(QLocale::Language pLang) const; + QString getHelpUrl(const QString& pObjectName) const; + QUrl getHelpUrlWrapper(const QString& pObjectName) const; + QString getOnlineUrl(const QString& pObjectName = QString()) const; + + protected: + static HelpAction& getInstance(); + HelpAction() = default; + ~HelpAction() = default; + + public: + static void openContextHelp(const QString& pObjectName = QStringLiteral("applicationPage")); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ListCheckItemWidget.cpp b/src/widget/generic/ListCheckItemWidget.cpp new file mode 100644 index 0000000..f7e272b --- /dev/null +++ b/src/widget/generic/ListCheckItemWidget.cpp @@ -0,0 +1,132 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include +#include +#include +#include +#include + +#include "generic/ListCheckItemWidget.h" +#include "ui_ListCheckItemWidget.h" + +using namespace governikus; + + +ListCheckItemWidget::ListCheckItemWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::ListCheckItemWidget()) +{ + mUi->setupUi(this); + mUi->listIcon->hide(); + + connect(mUi->listCheckBox, &QCheckBox::stateChanged, this, &ListCheckItemWidget::onCheckBoxChanged); + + installEventFilter(this); +} + + +ListCheckItemWidget::ListCheckItemWidget(QWidget* pParent, const QPixmap& pPixmap) + : QWidget(pParent) + , mUi(new Ui::ListCheckItemWidget()) +{ + mUi->setupUi(this); + mUi->listIcon->setScaledContents(true); + mUi->listIcon->setPixmap(pPixmap); + + connect(mUi->listCheckBox, &QCheckBox::stateChanged, this, &ListCheckItemWidget::onCheckBoxChanged); + + installEventFilter(this); +} + + +ListCheckItemWidget::~ListCheckItemWidget() +{ +} + + +void ListCheckItemWidget::itemWidgetReleased() +{ + mUi->listItemLayout->setObjectName(QStringLiteral("listItemLayout")); + //qApp->setStyleSheet(qApp->styleSheet()); +} + + +void ListCheckItemWidget::onCheckBoxChanged(int /*pChanged*/) +{ + Q_EMIT listItemWidgetChecked(this); +} + + +void ListCheckItemWidget::itemWidgetPressed() +{ + mUi->listItemLayout->setObjectName(QStringLiteral("listItemLayout_pressed")); + //qApp->setStyleSheet(qApp->styleSheet()); + + Q_EMIT listItemWidgetChecked(this); + +} + + +bool ListCheckItemWidget::eventFilter(QObject* /*pWatched*/, QEvent* pEvent) +{ + switch (pEvent->type()) + { + case QEvent::MouseButtonPress: + itemWidgetPressed(); + return false; + + case QEvent::MouseButtonRelease: + itemWidgetReleased(); + return false; + + default: + return false; + } +} + + +void ListCheckItemWidget::setHeading(const QString& pHeading) +{ + mUi->heading->setText(pHeading); +} + + +void ListCheckItemWidget::setSubHeading(const QString& pSubHeading) +{ + if (!pSubHeading.isNull() || !pSubHeading.isEmpty()) + { + mUi->subHeading->setText(pSubHeading); + } + else + { + mUi->headingFrameLayout->layout()->removeWidget(mUi->subHeading); + delete mUi->subHeading; + } +} + + +void ListCheckItemWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +QCheckBox* ListCheckItemWidget::getListItemCheckBox() +{ + return mUi->listCheckBox; +} + + +void ListCheckItemWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + QWidget::changeEvent(pEvent); + } +} diff --git a/src/widget/generic/ListCheckItemWidget.h b/src/widget/generic/ListCheckItemWidget.h new file mode 100644 index 0000000..084b315 --- /dev/null +++ b/src/widget/generic/ListCheckItemWidget.h @@ -0,0 +1,55 @@ +/*! + * \brief List item widget for list actions. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + +namespace Ui +{ +class ListCheckItemWidget; +} + +namespace governikus +{ + +class ListCheckItemWidget + : public QWidget +{ + Q_OBJECT + + public: + ListCheckItemWidget(QWidget* pParent, const QPixmap& pPixmap); + ListCheckItemWidget(QWidget* pParent); + virtual ~ListCheckItemWidget() override; + + void setHeading(const QString& pHeading); + void setSubHeading(const QString& pSubHeading); + + QCheckBox* getListItemCheckBox(); + + protected: + void changeEvent(QEvent* pEvent) override; + + Q_SIGNALS: + void listItemWidgetChecked(ListCheckItemWidget* pListCheckItemWidget); + + private Q_SLOTS: + void onCheckBoxChanged(int pChanged); + + private: + QScopedPointer mUi; + + virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; + virtual void paintEvent(QPaintEvent*) override; + + void itemWidgetReleased(); + void itemWidgetPressed(); +}; + +} /* namespace governikus */ diff --git a/src/gui/generic/ListCheckItemWidget.ui b/src/widget/generic/ListCheckItemWidget.ui similarity index 100% rename from src/gui/generic/ListCheckItemWidget.ui rename to src/widget/generic/ListCheckItemWidget.ui diff --git a/src/widget/generic/ListItem.cpp b/src/widget/generic/ListItem.cpp new file mode 100644 index 0000000..4ed0de4 --- /dev/null +++ b/src/widget/generic/ListItem.cpp @@ -0,0 +1,29 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ListItem.h" + +#include +#include + +using namespace governikus; + +ListItem::ListItem(QWidget* pParent, Qt::WindowFlags pWindowFlags) + : QWidget(pParent, pWindowFlags) +{ +} + + +ListItem::~ListItem() +{ +} + + +void ListItem::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/src/widget/generic/ListItem.h b/src/widget/generic/ListItem.h new file mode 100644 index 0000000..f1693be --- /dev/null +++ b/src/widget/generic/ListItem.h @@ -0,0 +1,25 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + + +namespace governikus +{ + +class ListItem + : public QWidget +{ + Q_OBJECT + + public: + ListItem(QWidget* pParent = nullptr, Qt::WindowFlags pWindowFlags = 0); + virtual ~ListItem() override; + + void paintEvent(QPaintEvent*) override; +}; + +} diff --git a/src/widget/generic/ListItemIconLeft.cpp b/src/widget/generic/ListItemIconLeft.cpp new file mode 100644 index 0000000..308d87b --- /dev/null +++ b/src/widget/generic/ListItemIconLeft.cpp @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ListItemIconLeft.h" + +using namespace governikus; + +ListItemIconLeft::ListItemIconLeft(QWidget* pParent) + : QLabel(pParent) +{ +} + + +ListItemIconLeft::ListItemIconLeft(const QString& pText, QWidget* pParent) + : QLabel(pText, pParent) +{ +} + + +ListItemIconLeft::~ListItemIconLeft() +{ +} diff --git a/src/widget/generic/ListItemIconLeft.h b/src/widget/generic/ListItemIconLeft.h new file mode 100644 index 0000000..81f873d --- /dev/null +++ b/src/widget/generic/ListItemIconLeft.h @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class ListItemIconLeft + : public QLabel +{ + Q_OBJECT + + public: + ListItemIconLeft(QWidget* pParent = nullptr); + ListItemIconLeft(const QString& pText, QWidget* pParent = nullptr); + virtual ~ListItemIconLeft(); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ListItemIconRight.cpp b/src/widget/generic/ListItemIconRight.cpp new file mode 100644 index 0000000..5618675 --- /dev/null +++ b/src/widget/generic/ListItemIconRight.cpp @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ListItemIconRight.h" + +using namespace governikus; + +ListItemIconRight::ListItemIconRight(QWidget* pParent) + : QLabel(pParent) +{ +} + + +ListItemIconRight::ListItemIconRight(const QString& pText, QWidget* pParent) + : QLabel(pText, pParent) +{ +} + + +ListItemIconRight::~ListItemIconRight() +{ +} diff --git a/src/widget/generic/ListItemIconRight.h b/src/widget/generic/ListItemIconRight.h new file mode 100644 index 0000000..c19ee47 --- /dev/null +++ b/src/widget/generic/ListItemIconRight.h @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class ListItemIconRight + : public QLabel +{ + Q_OBJECT + + public: + ListItemIconRight(QWidget* pParent = nullptr); + ListItemIconRight(const QString& pText, QWidget* pParent = nullptr); + virtual ~ListItemIconRight(); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ListItemSubTitle.cpp b/src/widget/generic/ListItemSubTitle.cpp new file mode 100644 index 0000000..0a4bf81 --- /dev/null +++ b/src/widget/generic/ListItemSubTitle.cpp @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ListItemSubTitle.h" + +using namespace governikus; + +ListItemSubTitle::ListItemSubTitle(QWidget* pParent) + : QLabel(pParent) +{ +} + + +ListItemSubTitle::ListItemSubTitle(const QString& pText, QWidget* pParent) + : QLabel(pText, pParent) +{ +} + + +ListItemSubTitle::~ListItemSubTitle() +{ +} diff --git a/src/widget/generic/ListItemSubTitle.h b/src/widget/generic/ListItemSubTitle.h new file mode 100644 index 0000000..d158f1c --- /dev/null +++ b/src/widget/generic/ListItemSubTitle.h @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class ListItemSubTitle + : public QLabel +{ + Q_OBJECT + + public: + ListItemSubTitle(QWidget* pParent = nullptr); + ListItemSubTitle(const QString& pText, QWidget* pParent = nullptr); + virtual ~ListItemSubTitle(); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/ListItemTitle.cpp b/src/widget/generic/ListItemTitle.cpp new file mode 100644 index 0000000..94de12e --- /dev/null +++ b/src/widget/generic/ListItemTitle.cpp @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ListItemTitle.h" + +using namespace governikus; + +ListItemTitle::ListItemTitle(QWidget* pParent) + : QLabel(pParent) +{ +} + + +ListItemTitle::ListItemTitle(const QString& pText, QWidget* pParent) + : QLabel(pText, pParent) +{ +} + + +ListItemTitle::~ListItemTitle() +{ +} diff --git a/src/widget/generic/ListItemTitle.h b/src/widget/generic/ListItemTitle.h new file mode 100644 index 0000000..debfb48 --- /dev/null +++ b/src/widget/generic/ListItemTitle.h @@ -0,0 +1,23 @@ +/* + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class ListItemTitle + : public QLabel +{ + Q_OBJECT + + public: + ListItemTitle(QWidget* pParent = nullptr); + ListItemTitle(const QString& pText, QWidget* pParent = nullptr); + virtual ~ListItemTitle(); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/PasswordEdit.cpp b/src/widget/generic/PasswordEdit.cpp new file mode 100644 index 0000000..35f7734 --- /dev/null +++ b/src/widget/generic/PasswordEdit.cpp @@ -0,0 +1,187 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "PasswordEdit.h" + +#include "ScopeGuard.h" + +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(gui) + +using namespace governikus; + + +namespace governikus +{ +class RegExValidator + : public QRegularExpressionValidator +{ + Q_OBJECT + + private: + const QString mInvalidValueToolTip; + + public: + RegExValidator(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip, QWidget* pParent) + : QRegularExpressionValidator(pExpression, pParent) + , mInvalidValueToolTip(pInvalidValueToolTip) + { + } + + + virtual QValidator::State validate(QString& pInput, int& pPos) const override + { + QValidator::State state = QRegularExpressionValidator::validate(pInput, pPos); + + if (state == State::Invalid && !mInvalidValueToolTip.isNull()) + { + QWidget* parentWidget = static_cast(parent()); + QToolTip::showText(parentWidget->mapToGlobal(QPoint(0, 0)), mInvalidValueToolTip, parentWidget, QRect(), 3000); + } + + return state; + } + + +}; + +} + + +PasswordEdit::PasswordEdit(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::PasswordEdit()) +{ + mUi->setupUi(this); + mUi->lineEdit->installEventFilter(this); + + connect(mUi->lineEdit, &QLineEdit::textEdited, this, &PasswordEdit::textEdited); + connect(mUi->lineEdit, &QLineEdit::selectionChanged, this, &PasswordEdit::selectionChanged); +} + + +int PasswordEdit::determindeWidth(int pNumChars) +{ + QLineEdit* const lineEdit = mUi->lineEdit; + + const QString currentText = lineEdit->text(); + const ScopeGuard resetText([lineEdit, currentText] { + lineEdit->setText(currentText); + }); + + // get the display text for a password of length pWidth + lineEdit->setText(QString(pNumChars, QLatin1Char('6'))); + const int displayTextWidth = lineEdit->fontMetrics().width(lineEdit->displayText()); + + // in QLineEdit::sizeHint() the width is calculated as + // 17th times the size of 'x' plus some magic margins. + // So we calculate this margin by subtraction to set the content size correctly. + const int widthHint = lineEdit->sizeHint().width(); + const int margin = widthHint - 17 * lineEdit->fontMetrics().width(QLatin1Char('x')); + return margin + displayTextWidth; +} + + +bool PasswordEdit::eventFilter(QObject* pObj, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::KeyPress) + { + const QKeyEvent* const keyEvent = static_cast(pEvent); + if (keyEvent->key() == Qt::Key_Backspace && text().isEmpty()) + { + Q_EMIT fireBackspacePressedAndEmpty(); + } + } + return QObject::eventFilter(pObj, pEvent); +} + + +void PasswordEdit::setMaxLength(int pLength, bool pShrink) +{ + if (pShrink) + { + mUi->lineEdit->setFixedWidth(determindeWidth(pLength)); + } + mUi->lineEdit->setMaxLength(pLength); +} + + +void PasswordEdit::configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip) +{ + mUi->lineEdit->setValidator(new RegExValidator(pExpression, pInvalidValueToolTip, this)); +} + + +void PasswordEdit::removeLastCharacter() +{ + const QString current = mUi->lineEdit->text(); + if (current.isEmpty()) + { + return; + } + mUi->lineEdit->setText(current.left(current.length() - 1)); +} + + +QString PasswordEdit::text() const +{ + return mUi->lineEdit->text(); +} + + +void PasswordEdit::setDigitFieldInvalid(bool pMakeInvalid, const QString& pInvalidMessage) +{ + if (pMakeInvalid) + { + mUi->lineEdit->setStyleSheet(QStringLiteral("background-color: red;")); + QToolTip::showText(mapToGlobal(QPoint(0, 32)), pInvalidMessage, mUi->lineEdit, QRect(), 3000); + } + else + { + mUi->lineEdit->setStyleSheet(QString()); + } +} + + +void PasswordEdit::clear() +{ + mUi->lineEdit->clear(); +} + + +void PasswordEdit::setText(const QString& pText) +{ + mUi->lineEdit->setText(pText); +} + + +void PasswordEdit::setCursorPosition(int pPosition) +{ + mUi->lineEdit->setCursorPosition(pPosition); +} + + +void PasswordEdit::setAccessibleName(const QString& pName) +{ + mUi->lineEdit->setAccessibleName(pName); +} + + +void PasswordEdit::setFocus() +{ + mUi->lineEdit->setFocus(); +} + + +void PasswordEdit::setAlignment(Qt::Alignment pAlignment) +{ + mUi->lineEdit->setAlignment(pAlignment); +} + + +#include "PasswordEdit.moc" diff --git a/src/widget/generic/PasswordEdit.h b/src/widget/generic/PasswordEdit.h new file mode 100644 index 0000000..d8693b6 --- /dev/null +++ b/src/widget/generic/PasswordEdit.h @@ -0,0 +1,56 @@ +/*! + * \brief Widget for entering a password that uses the password echo mode. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "ui_PasswordEdit.h" + + +namespace governikus +{ + +class PasswordEdit + : public QWidget +{ + Q_OBJECT + + private: + QScopedPointer mUi; + + int determindeWidth(int pNumChars); + + protected: + virtual bool eventFilter(QObject* pObj, QEvent* pEvent) override; + + public: + PasswordEdit(QWidget* pParent = nullptr); + + void setMaxLength(int pLength, bool pShrink = true); + void configureValidation(const QRegularExpression& pExpression, const QString& pInvalidValueToolTip); + void removeLastCharacter(); + QString text() const; + void setDigitFieldInvalid(bool pMakeInvalid, const QString& pInvalidMessage); + void clear(); + void setText(const QString& pText); + void setCursorPosition(int pPosition); + void setAccessibleName(const QString& pName); + void setFocus(); + void setAlignment(Qt::Alignment pAlignment); + + Q_SIGNALS: + void textEdited(const QString& pText); + void selectionChanged(); + void fireBackspacePressedAndEmpty(); +}; + +} /* namespace governikus */ diff --git a/src/widget/generic/PasswordEdit.ui b/src/widget/generic/PasswordEdit.ui new file mode 100644 index 0000000..1d4702a --- /dev/null +++ b/src/widget/generic/PasswordEdit.ui @@ -0,0 +1,49 @@ + + + PasswordEdit + + + + 0 + 0 + 152 + 36 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::ImhDigitsOnly|Qt::ImhFormattedNumbersOnly|Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhPreferNumbers|Qt::ImhSensitiveData + + + QLineEdit::Password + + + + + + + + diff --git a/src/widget/generic/TabButtonGroup.cpp b/src/widget/generic/TabButtonGroup.cpp new file mode 100644 index 0000000..d581821 --- /dev/null +++ b/src/widget/generic/TabButtonGroup.cpp @@ -0,0 +1,326 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TabButtonGroup.h" + +#include "ExclusiveButtonGroup.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + +static QAccessibleInterface* createTabButtonInterface(const QString& pKey, QObject* pObject) +{ + if (pObject->isWidgetType() && pKey == QLatin1String("governikus::TabButton")) + { + return new AccessibleTabButton(static_cast(pObject)); + } + + if (pObject->isWidgetType() && pKey == QLatin1String("governikus::TabButtonGroup")) + { + return new AccessibleTabButtonGroup(static_cast(pObject)); + } + + return nullptr; +} + + +static void registerInterfaceFactory() +{ + static bool registered = (QAccessible::installFactory(&createTabButtonInterface), true); + (void) registered; +} + + +TabButton::TabButton(QWidget* pParent) + : QToolButton(pParent) +{ + registerInterfaceFactory(); +} + + +TabButton::~TabButton() +{ +} + + +void TabButton::focusInEvent(QFocusEvent* /*pEvent*/) +{ + setChecked(true); + repaint(); +} + + +void TabButton::nextCheckState() +{ + setChecked(true); +} + + +TabButtonGroup::TabButtonGroup(QWidget* pParent) + : QWidget(pParent) + , mButtonGroup(new ExclusiveButtonGroup(this)) + , mWorkflowActive(false) +{ + registerInterfaceFactory(); + + setFocusPolicy(Qt::TabFocus); + + connect(mButtonGroup, &ExclusiveButtonGroup::buttonToggled, this, &TabButtonGroup::onButtonToggled); +} + + +TabButtonGroup::~TabButtonGroup() +{ +} + + +void TabButtonGroup::addButton(QAbstractButton* pButton) +{ + mButtonGroup->addButton(pButton); + + updateFocusPolicies(); + + if (pButton->parent() != this) + { + pButton->setParent(this); + } + + pButton->installEventFilter(this); +} + + +void TabButtonGroup::setWorkflowActive(bool pWorkflowActiv) +{ + mWorkflowActive = pWorkflowActiv; +} + + +bool TabButtonGroup::eventFilter(QObject* pWatched, QEvent* pEvent) +{ + if (pEvent->type() != QEvent::KeyPress) + { + return false; + } + + QAbstractButton* button = qobject_cast(pWatched); + if (button == nullptr) + { + return false; + } + + // Handle cursor key navigation manually. It doesn't work, since only one + // button is focussable at all. + bool navigate = false; + bool cycle = false; + bool next = true; + + QKeyEvent* keyEvent = static_cast(pEvent); + switch (keyEvent->key()) + { + case Qt::Key_Up: + next = false; + + // fall through + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Down: + { + bool reverse = layoutDirection() == Qt::RightToLeft; + if ((keyEvent->key() == Qt::Key_Left && !reverse) + || (keyEvent->key() == Qt::Key_Right && reverse)) + { + next = false; + } + + navigate = true; + break; + } + + case Qt::Key_Tab: + case Qt::Key_Backtab: + { + Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); + if ((modifiers& Qt::CTRL) != 0 && (modifiers & ~(Qt::CTRL | Qt::SHIFT)) == 0) + { + navigate = true; + cycle = true; + next = keyEvent->key() == Qt::Key_Tab; + } + break; + } + } + + if (!navigate) + { + return false; + } + + pEvent->accept(); + + if (QAbstractButton* nextButton = getNextPrevFocussableButton(button, next, cycle)) + { + if (!mWorkflowActive) + { + nextButton->setChecked(true); + } + } + + return true; +} + + +void TabButtonGroup::onButtonToggled(QAbstractButton* pButton, bool pChecked) +{ + updateFocusPolicies(); + + if (pButton->isChecked()) + { + pButton->setFocus(); + } + + Q_EMIT buttonToggled(pButton, pChecked); +} + + +QAbstractButton* TabButtonGroup::getNextPrevFocussableButton(QAbstractButton* pCurrentButton, bool pNext, bool pCycle) const +{ + const QVector& buttons = mButtonGroup->getButtons(); + int count = buttons.count(); + if (count == 0) + { + return nullptr; + } + + int index; + if (pCurrentButton != nullptr) + { + index = buttons.indexOf(pCurrentButton); + } + else + { + index = pNext ? count - 1 : 0; + } + + if (index < 0) + { + return nullptr; + } + + int direction = pNext ? 1 : -1; + for (;;) + { + index += direction; + if (index < 0 || index >= count) + { + if (!pCycle) + { + return nullptr; + } + + pCycle = false; + index = (index + count) % count; + } + + QAbstractButton* button = buttons.at(index); + if (button->isVisibleTo(this)) + { + return button; + } + } +} + + +void TabButtonGroup::updateFocusPolicies() +{ + bool anyButtonFocussable = false; + const QVector& buttons = mButtonGroup->getButtons(); + for (QAbstractButton* button : buttons) + { + bool buttonFocussable = button->isChecked() && button->isVisibleTo(button->parentWidget()); + anyButtonFocussable |= buttonFocussable; + button->setFocusPolicy(buttonFocussable ? Qt::TabFocus : Qt::NoFocus); + } + + if (anyButtonFocussable) + { + setFocusPolicy(Qt::NoFocus); + } + else + { + setFocusPolicy(Qt::TabFocus); + for (QAbstractButton* button : buttons) + { + if (button->isVisibleTo(button->parentWidget())) + { + button->setFocusPolicy(Qt::TabFocus); + break; + } + } + } +} + + +void TabButtonGroup::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +AccessibleTabButton::AccessibleTabButton(QWidget* pWidget) + : QAccessibleWidget(pWidget, QAccessible::PageTab) +{ +} + + +TabButton* AccessibleTabButton::getTabButton() const +{ + return static_cast(widget()); +} + + +QString AccessibleTabButton::text(QAccessible::Text /*pText*/) const +{ + QString result = getTabButton()->text(); + return result.replace(QLatin1Char('&'), QString()); +} + + +QStringList AccessibleTabButton::actionNames() const +{ + return QStringList(pressAction()); +} + + +void AccessibleTabButton::doAction(const QString& pActionName) +{ + if (pActionName == pressAction()) + { + getTabButton()->setChecked(true); + } +} + + +AccessibleTabButtonGroup::AccessibleTabButtonGroup(QWidget* pWidget) + : QAccessibleWidget(pWidget, QAccessible::PageTabList) +{ +} + + +AccessibleTabButtonGroup::~AccessibleTabButtonGroup() +{ +} + + +TabButtonGroup* AccessibleTabButtonGroup::getTabButtonGroup() const +{ + return static_cast(widget()); +} diff --git a/src/widget/generic/TabButtonGroup.h b/src/widget/generic/TabButtonGroup.h new file mode 100644 index 0000000..618cc47 --- /dev/null +++ b/src/widget/generic/TabButtonGroup.h @@ -0,0 +1,110 @@ +/*! + * \brief Contains the accessibility friendly TabButtonGroup and TabButton classes. + * + * The other classes defined in this header are implementation private. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace governikus +{ + +class ExclusiveButtonGroup; + + +/*! + * \brief A push button that is presented to accessibility clients as a page tab. + */ +class TabButton + : public QToolButton +{ + Q_OBJECT + + public: + TabButton(QWidget* pParent = nullptr); + virtual ~TabButton() override; + + protected: + virtual void focusInEvent(QFocusEvent* pEvent) override; + virtual void nextCheckState() override; +}; + +/*! + * \brief A widget that is presented to accessibility clients as a page tab list, + * but uses TabButtons as tabs. + * + * The class is a regular widget. Buttons (that must be checkable) added via + * addButton() are added to an exclusive button group. Only one button can be + * checked at a time. The focus handling and cursor key navigation is overridden + * so that it works like in the tab row of a regular QTabWidget. + */ +class TabButtonGroup + : public QWidget +{ + Q_OBJECT + + public: + TabButtonGroup(QWidget* pParent = nullptr); + virtual ~TabButtonGroup() override; + + void addButton(QAbstractButton* pButton); + + void setWorkflowActive(bool pWorkflowActiv); + + virtual bool eventFilter(QObject* pWatched, QEvent* pEvent) override; + + private Q_SLOTS: + void onButtonToggled(QAbstractButton* pButton, bool pChecked); + + private: + QAbstractButton* getNextPrevFocussableButton(QAbstractButton* pCurrentButton, bool pNext, bool pCycle) const; + void updateFocusPolicies(); + + private: + ExclusiveButtonGroup* mButtonGroup; + bool mWorkflowActive; + void paintEvent(QPaintEvent*) override; + + Q_SIGNALS: + void buttonToggled(QAbstractButton* pButton, bool pChecked); +}; + +/*! + * \brief Implementation private class providing the accessibility functionality + * for TabButton. + */ +class AccessibleTabButton + : public QAccessibleWidget +{ + public: + AccessibleTabButton(QWidget* pWidget); + + TabButton* getTabButton() const; + + virtual QString text(QAccessible::Text pText) const override; + + virtual QStringList actionNames() const override; + virtual void doAction(const QString& pActionName) override; + +}; + +/*! + * \brief Implementation private class providing the accessibility functionality + * for TabButtonGroup. + */ +class AccessibleTabButtonGroup + : public QAccessibleWidget +{ + public: + AccessibleTabButtonGroup(QWidget* pWidget); + virtual ~AccessibleTabButtonGroup(); + + TabButtonGroup* getTabButtonGroup() const; +}; + +} /* namespace governikus */ diff --git a/src/gui/metadata.json b/src/widget/metadata.json similarity index 100% rename from src/gui/metadata.json rename to src/widget/metadata.json diff --git a/src/widget/step/AuthenticateStepsWidget.cpp b/src/widget/step/AuthenticateStepsWidget.cpp new file mode 100644 index 0000000..a92cdee --- /dev/null +++ b/src/widget/step/AuthenticateStepsWidget.cpp @@ -0,0 +1,59 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AuthenticateStepsWidget.h" +#include "ui_AuthenticateStepsWidget.h" + +#include + +#include "AppStartPage.h" +#include "generic/BusyOverlayContainer.h" + +using namespace governikus; + +AuthenticateStepsWidget::AuthenticateStepsWidget(QWidget* pParent) + : QStackedWidget(pParent) + , mUi(new Ui::AuthenticateStepsWidget()) + , mProcessingPage(new BusyOverlayContainer(new AppStartPage(), false)) +{ + mUi->setupUi(this); + + addWidget(mProcessingPage); +} + + +AuthenticateStepsWidget::~AuthenticateStepsWidget() +{ +} + + +StepAuthenticationEac1Widget* AuthenticateStepsWidget::getEac1Page() const +{ + return mUi->authenticationEac1Page; +} + + +SelfInfoWidget* AuthenticateStepsWidget::getSelfInfoPage() const +{ + return mUi->selfInfoPage; +} + + +void AuthenticateStepsWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void AuthenticateStepsWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/step/AuthenticateStepsWidget.h b/src/widget/step/AuthenticateStepsWidget.h new file mode 100644 index 0000000..c3b2ba4 --- /dev/null +++ b/src/widget/step/AuthenticateStepsWidget.h @@ -0,0 +1,54 @@ +/*! + * \brief A stacked widget containing the widgets for the authentication steps. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +namespace Ui +{ +class AuthenticateStepsWidget; +} + +class QAbstractButton; + +namespace governikus +{ + +class BusyOverlayContainer; +class SelfInfoWidget; +class StepAuthenticationEac1Widget; + +class AuthenticateStepsWidget + : public QStackedWidget +{ + Q_OBJECT + + public: + AuthenticateStepsWidget(QWidget* pParent = nullptr); + virtual ~AuthenticateStepsWidget() override; + + BusyOverlayContainer* getProcessingPage() const + { + return mProcessingPage; + } + + + StepAuthenticationEac1Widget* getEac1Page() const; + + SelfInfoWidget* getSelfInfoPage() const; + + protected: + void paintEvent(QPaintEvent*) override; + void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + BusyOverlayContainer* mProcessingPage; +}; + +} /* namespace governikus */ diff --git a/src/gui/step/AuthenticateStepsWidget.ui b/src/widget/step/AuthenticateStepsWidget.ui similarity index 100% rename from src/gui/step/AuthenticateStepsWidget.ui rename to src/widget/step/AuthenticateStepsWidget.ui diff --git a/src/widget/step/SelfInfoWidget.cpp b/src/widget/step/SelfInfoWidget.cpp new file mode 100644 index 0000000..20a38e4 --- /dev/null +++ b/src/widget/step/SelfInfoWidget.cpp @@ -0,0 +1,135 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SelfInfoWidget.h" + +#include "ui_SelfInfoWidget.h" + +#include "generic/ListItem.h" +#include "generic/ListItemSubTitle.h" +#include "generic/ListItemTitle.h" +#include "PdfExporter.h" + +#include +#include +#include +#include + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +SelfInfoWidget::SelfInfoWidget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::SelfInfoWidget()) + , mSelfAuthenticationData() +{ + mUi->setupUi(this); + layout()->setMargin(20); +} + + +SelfInfoWidget::~SelfInfoWidget() +{ +} + + +void SelfInfoWidget::setInfo(const SelfAuthenticationData& pData) +{ + mSelfAuthenticationData = pData; + fillLayout(); +} + + +void SelfInfoWidget::fillLayout() +{ + //delete old data from ui + QLayout* uiLayout = mUi->dataLayout; + cleanLayout(uiLayout); + cleanLayout(mUi->saveLayout); + + const auto& orderedSelfData = mSelfAuthenticationData.getOrderedSelfData(); + for (const auto& entry : orderedSelfData) + { + QLabel* const tmpLabel = new QLabel(entry.first); + tmpLabel->setFocusPolicy(Qt::TabFocus); + tmpLabel->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); + + QLabel* const tmpField = new QLabel(entry.second); + tmpField->setFocusPolicy(Qt::TabFocus); + tmpField->setWordWrap(true); + + mUi->dataLayout->insertRow(-1, tmpLabel, tmpField); + } + + QPushButton* exportButton = new QPushButton(tr("Save as PDF...")); + exportButton->setAccessibleName(tr("save id card data as pdf")); + + connect(exportButton, &QPushButton::clicked, this, &SelfInfoWidget::onPrintButtonClicked); + + mUi->saveLayout->addWidget(exportButton); + mUi->saveLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); +} + + +void SelfInfoWidget::cleanLayout(QLayout* pLayout) +{ + while (QLayoutItem* child = pLayout->itemAt(0)) + { + if (QWidget* childWidget = child->widget()) + { + pLayout->removeWidget(childWidget); + delete childWidget; + } + else + { + pLayout->removeItem(child); + delete child; + } + } +} + + +void SelfInfoWidget::paintEvent(QPaintEvent*) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + + +void SelfInfoWidget::onPrintButtonClicked() +{ + const auto& selfData = mSelfAuthenticationData.getOrderedSelfData(); + if (!selfData.isEmpty()) + { + const auto& dataTime = mSelfAuthenticationData.getDateTime(); + QString filename = tr("AusweisApp2.Information.%1.pdf").arg(dataTime.toString(QStringLiteral("yyyy-MM-dd"))); + filename = QFileDialog::getSaveFileName(this, + QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Save"), + QDir::homePath() + QLatin1Char('/') + filename, +#ifndef Q_OS_MACOS + tr("PDF Documents") + QStringLiteral(" (*.pdf)")); +#else + tr("PDF Documents") + QStringLiteral(" (*.pdf)"), nullptr, QFileDialog::DontUseNativeDialog); +#endif + + PdfExporter exporter(filename); + exporter.exportSelfInfo(dataTime, selfData); + } +} + + +void SelfInfoWidget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + mUi->retranslateUi(this); + fillLayout(); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/step/SelfInfoWidget.h b/src/widget/step/SelfInfoWidget.h new file mode 100644 index 0000000..15b0e12 --- /dev/null +++ b/src/widget/step/SelfInfoWidget.h @@ -0,0 +1,49 @@ +/*! + * \brief A widget displaying the card data retrieved in the self info workflow. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "SelfAuthenticationData.h" + +#include +#include +#include + +namespace Ui +{ +class SelfInfoWidget; +} + +namespace governikus +{ +class SelfInfoWidget + : public QWidget +{ + Q_OBJECT + + public: + SelfInfoWidget(QWidget* pParent = nullptr); + virtual ~SelfInfoWidget() override; + + void setInfo(const SelfAuthenticationData& pData); + + protected: + void paintEvent(QPaintEvent*) override; + void changeEvent(QEvent* pEvent) override; + + private: + QScopedPointer mUi; + SelfAuthenticationData mSelfAuthenticationData; + + void add(const QString& pKey, const QString& pValue); + void fillLayout(); + void cleanLayout(QLayout* pLayout); + + private Q_SLOTS: + void onPrintButtonClicked(); +}; + +} /* namespace governikus */ diff --git a/src/widget/step/SelfInfoWidget.ui b/src/widget/step/SelfInfoWidget.ui new file mode 100644 index 0000000..92c2cdb --- /dev/null +++ b/src/widget/step/SelfInfoWidget.ui @@ -0,0 +1,160 @@ + + + SelfInfoWidget + + + + 0 + 0 + 515 + 400 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 0 + 20 + + + + + + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 75 + true + + + + Qt::TabFocus + + + The following data has been read out from your ID card: + + + true + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 3 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 0 + 20 + + + + + + + + + + + diff --git a/src/widget/step/StepAdviseUserToRemoveCardGui.cpp b/src/widget/step/StepAdviseUserToRemoveCardGui.cpp new file mode 100644 index 0000000..3583e80 --- /dev/null +++ b/src/widget/step/StepAdviseUserToRemoveCardGui.cpp @@ -0,0 +1,91 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepAdviseUserToRemoveCardGui.h" + +#include "PinSettingsWidget.h" +#include "ReaderManager.h" + +#include +#include + + +using namespace governikus; + + +void StepAdviseUserToRemoveCardGui::onReaderManagerSignal() +{ + if (!ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()).hasCard()) + { + qDebug() << "No more ID cards found -> auto closing card reminder dialog"; + + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + disconnect(&mMessageTimeoutTimer, &QTimer::timeout, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + + mMessageBox->reject(); + } +} + + +StepAdviseUserToRemoveCardGui::StepAdviseUserToRemoveCardGui(QSharedPointer pContext, QWidget* pMainWidget) + : StepGui(pContext) + , mContext(pContext) + , mMainWidget(pMainWidget) + , mMessageBox(nullptr) + , mMessageTimeoutTimer() +{ +} + + +StepAdviseUserToRemoveCardGui::~StepAdviseUserToRemoveCardGui() +{ +} + + +void StepAdviseUserToRemoveCardGui::activate() +{ + setCancelButtonState(ButtonState::HIDDEN); + + const QString selectedReaderName = mContext->getReaderName(); + if (selectedReaderName.isEmpty()) + { + return; + } + + ReaderInfo selectedReader = ReaderManager::getInstance().getReaderInfo(mContext->getReaderName()); + if (selectedReader.isConnected()) + { + if (!selectedReader.hasCard()) + { + return; + } + + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderAdded, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardRemoved, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + } + else + { + mMessageTimeoutTimer.setInterval(3000); + mMessageTimeoutTimer.setSingleShot(true); + connect(&mMessageTimeoutTimer, &QTimer::timeout, this, &StepAdviseUserToRemoveCardGui::onReaderManagerSignal); + mMessageTimeoutTimer.start(); + } + + if (mMessageBox == nullptr) + { + mMessageBox = new QMessageBox(mMainWidget); + mMessageBox->setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Information")); + mMessageBox->setWindowModality(Qt::WindowModal); + 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/widget/step/StepAdviseUserToRemoveCardGui.h b/src/widget/step/StepAdviseUserToRemoveCardGui.h new file mode 100644 index 0000000..b4fbd0a --- /dev/null +++ b/src/widget/step/StepAdviseUserToRemoveCardGui.h @@ -0,0 +1,40 @@ +/*! + * \brief Qt UI for the advise user to remove card step. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "StepGui.h" + +#include +#include +#include + +namespace governikus +{ + +class StepAdviseUserToRemoveCardGui + : public StepGui +{ + Q_OBJECT + + public Q_SLOTS: + void onReaderManagerSignal(); + + public: + StepAdviseUserToRemoveCardGui(QSharedPointer pContext, QWidget* const pMainWidget); + virtual ~StepAdviseUserToRemoveCardGui() override; + + virtual void activate() override; + + private: + QSharedPointer mContext; + QWidget* const mMainWidget; + QMessageBox* mMessageBox; + QTimer mMessageTimeoutTimer; +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepAuthenticationDoneGui.cpp b/src/widget/step/StepAuthenticationDoneGui.cpp new file mode 100644 index 0000000..6817a39 --- /dev/null +++ b/src/widget/step/StepAuthenticationDoneGui.cpp @@ -0,0 +1,24 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepAuthenticationDoneGui.h" + +using namespace governikus; + + +StepAuthenticationDoneGui::StepAuthenticationDoneGui(QSharedPointer pContext) + : StepGui(pContext) +{ +} + + +StepAuthenticationDoneGui::~StepAuthenticationDoneGui() +{ +} + + +void StepAuthenticationDoneGui::forwardStep() +{ + Q_EMIT fireCancelled(); +} diff --git a/src/widget/step/StepAuthenticationDoneGui.h b/src/widget/step/StepAuthenticationDoneGui.h new file mode 100644 index 0000000..79115e0 --- /dev/null +++ b/src/widget/step/StepAuthenticationDoneGui.h @@ -0,0 +1,28 @@ +/*! + * \brief Qt UI for the authentication done step. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "StepGui.h" + + +namespace governikus +{ + +class StepAuthenticationDoneGui + : public StepGui +{ + Q_OBJECT + + public: + StepAuthenticationDoneGui(QSharedPointer pContext); + virtual ~StepAuthenticationDoneGui() override; + + virtual void forwardStep() override; +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepAuthenticationEac1Gui.cpp b/src/widget/step/StepAuthenticationEac1Gui.cpp new file mode 100644 index 0000000..2a2e69e --- /dev/null +++ b/src/widget/step/StepAuthenticationEac1Gui.cpp @@ -0,0 +1,142 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepAuthenticationEac1Gui.h" + +#include "generic/GuiUtils.h" +#include "step/AuthenticateStepsWidget.h" + +#include + +using namespace governikus; + +StepAuthenticationEac1Gui::StepAuthenticationEac1Gui(QSharedPointer pContext, + AuthenticateStepsWidget* pStepsWidget) + : StepGui(pContext) + , mContext(pContext) + , mStepsWidget(pStepsWidget) + , mWidget(nullptr) + , mState(StepAuthenticationEac1Widget::State::EDIT_CHAT) + , mPayAttentionToReaderMsgBox(new QMessageBox(pStepsWidget->window())) + , mActive(false) +{ + mPayAttentionToReaderMsgBox->setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Information")); + mPayAttentionToReaderMsgBox->setText(tr("Please observe the display of your card reader.")); + mPayAttentionToReaderMsgBox->setIcon(QMessageBox::Information); + mPayAttentionToReaderMsgBox->setStandardButtons(QMessageBox::NoButton); +} + + +StepAuthenticationEac1Gui::~StepAuthenticationEac1Gui() +{ +} + + +void StepAuthenticationEac1Gui::activate() +{ + mActive = true; + + mWidget = mStepsWidget->getEac1Page(); + + connect(mWidget, &StepAuthenticationEac1Widget::setForwardButtonState, getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState); + connect(mWidget, &StepAuthenticationEac1Widget::setCancelButtonState, getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState); + + connect(mWidget, &StepAuthenticationEac1Widget::fireCanUpdated, this, &StepAuthenticationEac1Gui::onCanUpdated); + connect(mWidget, &StepAuthenticationEac1Widget::firePinUpdated, this, &StepAuthenticationEac1Gui::onPinUpdated); + + connect(this, &StepAuthenticationEac1Gui::fireUiFinished, this, &StepAuthenticationEac1Gui::onUiFinished); + + mWidget->setContext(mContext); + mWidget->setState(StepAuthenticationEac1Widget::State::INITIAL); + mStepsWidget->setCurrentWidget(mWidget); +} + + +void StepAuthenticationEac1Gui::deactivate() +{ + mWidget->setContext(QSharedPointer()); + + disconnect(mWidget, &StepAuthenticationEac1Widget::setForwardButtonState, getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState); + disconnect(mWidget, &StepAuthenticationEac1Widget::setCancelButtonState, getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState); + + disconnect(mWidget, &StepAuthenticationEac1Widget::fireCanUpdated, this, &StepAuthenticationEac1Gui::onCanUpdated); + disconnect(mWidget, &StepAuthenticationEac1Widget::firePinUpdated, this, &StepAuthenticationEac1Gui::onPinUpdated); + + disconnect(this, &StepAuthenticationEac1Gui::fireUiFinished, this, &StepAuthenticationEac1Gui::onUiFinished); + + mActive = false; +} + + +bool StepAuthenticationEac1Gui::isActive() const +{ + return mActive; +} + + +void StepAuthenticationEac1Gui::setState(StepAuthenticationEac1Widget::State pState) +{ + mState = pState; + + mWidget->setState(pState); + + if (pState == StepAuthenticationEac1Widget::State::FINISHED) + { + forwardStep(); + } +} + + +void StepAuthenticationEac1Gui::incorrectPinError() +{ + mWidget->updateButtonsAndPinWidget(); + + GuiUtils::showPinCanPukErrorDialog(mContext->getLastPaceResult(), mContext->getCardConnection()->getReaderInfo().getRetryCounter(), mStepsWidget->window()); +} + + +void StepAuthenticationEac1Gui::forwardStep() +{ + if (mState == StepAuthenticationEac1Widget::State::FINISHED) + { + Q_EMIT fireUiFinished(); + return; + } + + mWidget->forwardStep(); + + Q_EMIT fireUiFinished(); +} + + +void StepAuthenticationEac1Gui::hidePayAttentionToReader() +{ + mPayAttentionToReaderMsgBox->reject(); +} + + +void StepAuthenticationEac1Gui::onShowPayAttentionToReader() +{ + mPayAttentionToReaderMsgBox->open(); +} + + +void StepAuthenticationEac1Gui::onPinUpdated(const QString& pPin) +{ + mPin = pPin; +} + + +void StepAuthenticationEac1Gui::onCanUpdated(const QString& pCan) +{ + mCan = pCan; +} + + +void StepAuthenticationEac1Gui::onUiFinished() +{ + mContext->setCan(mCan); + mContext->setPin(mPin); + mContext->setStateApproved(); +} diff --git a/src/widget/step/StepAuthenticationEac1Gui.h b/src/widget/step/StepAuthenticationEac1Gui.h new file mode 100644 index 0000000..1b3292c --- /dev/null +++ b/src/widget/step/StepAuthenticationEac1Gui.h @@ -0,0 +1,57 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "step/StepAuthenticationEac1Widget.h" +#include "StepGui.h" + +#include +#include + +namespace governikus +{ + +class AuthenticateStepsWidget; +class StepAuthenticationEac1Widget; + +class StepAuthenticationEac1Gui + : public StepGui +{ + Q_OBJECT + + private: + QSharedPointer mContext; + AuthenticateStepsWidget* mStepsWidget; + StepAuthenticationEac1Widget* mWidget; + StepAuthenticationEac1Widget::State mState; + QPointer mPayAttentionToReaderMsgBox; + QString mPin; + QString mCan; + bool mActive; + + public: + StepAuthenticationEac1Gui(QSharedPointer pContext, AuthenticateStepsWidget* pStepsWidget); + virtual ~StepAuthenticationEac1Gui() override; + + virtual void activate() override; + virtual void deactivate() override; + bool isActive() const; + + virtual void setState(StepAuthenticationEac1Widget::State pState); + virtual void incorrectPinError(); + + virtual void forwardStep() override; + + virtual void hidePayAttentionToReader(); + + public Q_SLOTS: + virtual void onShowPayAttentionToReader(); + void onPinUpdated(const QString& pPin); + void onCanUpdated(const QString& pCan); + void onUiFinished(); +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepAuthenticationEac1Widget.cpp b/src/widget/step/StepAuthenticationEac1Widget.cpp new file mode 100644 index 0000000..8f8853e --- /dev/null +++ b/src/widget/step/StepAuthenticationEac1Widget.cpp @@ -0,0 +1,635 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepAuthenticationEac1Widget.h" +#include "ui_StepAuthenticationEac1Widget.h" + +#include "AppSettings.h" +#include "CardConnection.h" +#include "DetailDialog.h" +#include "generic/PasswordEdit.h" +#include "RandomPinDialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +using namespace governikus; + +Q_DECLARE_LOGGING_CATEGORY(gui) + +StepAuthenticationEac1Widget::StepAuthenticationEac1Widget(QWidget* pParent) + : QWidget(pParent) + , mUi(new Ui::StepAuthenticationEac1Widget()) + , mContext() + , mCANField(nullptr) + , mPINField(nullptr) + , mState(State::INITIAL) + , mProgressBar(nullptr) + , mProgressBarLabel(nullptr) + , mCloseWindowWhenFinished() +#ifdef Q_OS_WIN + , mTaskbarButton(new QWinTaskbarButton(this)) +#endif +{ + mUi->setupUi(this); + setToolTip(); + mUi->listWidgetWest->setAttribute(Qt::WA_MacShowFocusRect, false); + mUi->listWidgetEast->setAttribute(Qt::WA_MacShowFocusRect, false); + + connect(mUi->detailsPushButton, &QPushButton::clicked, this, &StepAuthenticationEac1Widget::onDetailsButtonClicked); +} + + +StepAuthenticationEac1Widget::~StepAuthenticationEac1Widget() +{ +} + + +void StepAuthenticationEac1Widget::setContext(const QSharedPointer& pContext) +{ + mContext = pContext; + +#ifdef Q_OS_WIN + if (mContext) + { + connect(mContext.data(), &AuthContext::fireResultChanged, this, &StepAuthenticationEac1Widget::onResultChanged); + } +#endif +} + + +void StepAuthenticationEac1Widget::setState(State pState) +{ + if (pState != mState) + { + mState = pState; + updateWidget(); + } +} + + +void StepAuthenticationEac1Widget::forwardStep() +{ + Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); + + if (mState == State::EDIT_CHAT) + { + mUi->detailsPushButton->setEnabled(false); + mUi->listWidgetWest->setEnabled(false); + mUi->listWidgetEast->setEnabled(false); + } + else if (mState == State::ENTER_PIN) + { + if (mContext->getCardConnection() != nullptr && mContext->getCardConnection()->getReaderInfo().isBasicReader()) + { + mUi->pinGroupBox->setVisible(false); + + int childCount = mUi->pinWidgetLayout->count(); + for (int i = 0; i < childCount; ++i) + { + QLayoutItem* child = mUi->pinWidgetLayout->itemAt(i); + if (child->widget() != nullptr) + { + child->widget()->setEnabled(false); + } + } + } + else + { + Q_EMIT setCancelButtonState(ButtonState::DISABLED); + } + } + +} + + +void StepAuthenticationEac1Widget::updateButtonsAndPinWidget() +{ + Q_EMIT setCancelButtonState(ButtonState::ENABLED); + + if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) + { + mUi->pinGroupBox->setTitle(tr("Please enter your six-digit card access number (CAN) and your PIN for identification.")); + } + else + { + mUi->pinGroupBox->setTitle(tr("Please enter your six digit PIN for identification")); + } + + if (mContext->getCardConnection()->getReaderInfo().isBasicReader()) + { + clearPinWidgetLayout(); + createBasicReaderWidget(); + focusWidget(); + } + else + { + 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")); +} + + +void StepAuthenticationEac1Widget::clearPinWidgetLayout() +{ + while (QLayoutItem* child = mUi->pinWidgetLayout->itemAt(0)) + { + if (QWidget* childWidget = child->widget()) + { + mUi->pinWidgetLayout->removeWidget(childWidget); + delete childWidget; + } + else + { + mUi->pinWidgetLayout->removeItem(child); + delete child; + } + } + + mProgressBar = nullptr; + mProgressBarLabel = nullptr; +} + + +void StepAuthenticationEac1Widget::onDetailsButtonClicked() +{ + DetailDialog d(this); + + auto eac1 = mContext->getDidAuthenticateEac1(); + CVCertificateBody body = eac1->getCvCertificates().at(0)->getBody(); + QString effectiveDate = body.getCertificateEffectiveDate().toString(Qt::DefaultLocaleShortDate); + QString expirationDate = body.getCertificateExpirationDate().toString(Qt::DefaultLocaleShortDate); + auto certificateDescription = eac1->getCertificateDescription(); + + QString details; + details += tr("Service provider:") + QLatin1Char('\n'); + details += certificateDescription->getSubjectName(); + details += QLatin1Char('\n'); + details += certificateDescription->getSubjectUrl(); + + details += QLatin1String("\n\n"); + details += tr("Certificate issuer:") + QLatin1Char('\n'); + details += certificateDescription->getIssuerName(); + details += QLatin1Char('\n'); + details += certificateDescription->getIssuerUrl(); + + details += QLatin1String("\n\n"); + details += certificateDescription->getTermsOfUsage(); + details += QLatin1String("\n\n"); + details += tr("Validity:\n%1 - %2").arg(effectiveDate, expirationDate); + + // collapse multiple blank lines + details.replace(QRegularExpression(QStringLiteral("\n\n\n*")), QStringLiteral("\n\n")); + + d.setDetails(details); + d.exec(); +} + + +void StepAuthenticationEac1Widget::setToolTip() +{ + const auto& align = QStringLiteral("

%1

"); + + const auto& certDesc = tr("Information on the service provider who wants to read out data from your ID card is given here. For further information press the button \"more...\"."); + mUi->certificateDescriptionGroupBox->setToolTip(align.arg(certDesc)); + + const auto& fieldDesc = tr("Here you can select or deselect data fields to be read out. Mandatory data fields required by the service provider cannot be deselected."); + mUi->groupBox->setToolTip(align.arg(fieldDesc)); +} + + +void StepAuthenticationEac1Widget::updateWidget() +{ + if (!mContext) + { + return; + } + + switch (mState) + { + case State::INITIAL: + break; + + case State::EDIT_CHAT: + setupChatView(); + return; + + case State::ENTER_PIN: + updateButtonsAndPinWidget(); + return; + + case State::AUTHENTICATING_ESERVICE: + Q_EMIT setCancelButtonState(ButtonState::ENABLED); + updateProgressPanel(1, tr("Service provider is verified")); + break; + + case State::AUTHENTICATING_CARD: + updateProgressPanel(2, tr("Card is being verified")); + break; + + case State::READING_CARD_DATA: + updateProgressPanel(3, tr("Reading data")); + break; + + case State::REDIRECTING_BROWSER: + updateProgressPanel(4, tr("Service provider is being verified")); + break; + + case State::FINISHED: + updateProgressPanel(); + Q_EMIT setCancelButtonState(ButtonState::HIDDEN); + Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("OK")); + break; + } +} + + +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() +{ + 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->getOptionalAccessRights().contains(orderedRight)) + { + addChatRightToGui(orderedRight, true, listSize); + } + else if (mContext->getRequiredAccessRights().contains(orderedRight)) + { + addChatRightToGui(orderedRight, false, listSize); + } + } +} + + +void StepAuthenticationEac1Widget::addChatRightToGui(AccessRight pRight, bool pOptional, int pListSize) +{ + QString displayText = AccessRoleAndRightsUtil::toDisplayText(pRight); + if (pRight == AccessRight::AGE_VERIFICATION) + { + displayText += QStringLiteral(" (%1)").arg(mContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + } + QCheckBox* cb = new QCheckBox(displayText); + cb->setEnabled(pOptional); + cb->setChecked(mContext->getEffectiveAccessRights().contains(pRight)); + + mMap.insert(cb, pRight); + + connect(cb, &QCheckBox::stateChanged, this, &StepAuthenticationEac1Widget::checkBoxChanged); + + QListWidgetItem* item = new QListWidgetItem(); + item->setSizeHint(QSize(0, 20)); + if (mUi->listWidgetWest->count() < pListSize) + { + mUi->listWidgetWest->addItem(item); + mUi->listWidgetWest->setItemWidget(item, cb); + } + else + { + mUi->listWidgetEast->addItem(item); + mUi->listWidgetEast->setItemWidget(item, cb); + } +} + + +void StepAuthenticationEac1Widget::createBasicReaderWidget() +{ + QWidget* basicReaderWidget = new QWidget(); + + QHBoxLayout* basicReaderWidgetLayout = new QHBoxLayout(basicReaderWidget); + + AppSettings& appSettings = AppSettings::getInstance(); + + QRegularExpression onlyNumbersExpression(QStringLiteral("[0-9]*")); + if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) + { + mCANField = new PasswordEdit(); + mCANField->setMaxLength(6); + mCANField->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are permitted.")); + connect(mCANField, &PasswordEdit::textEdited, this, &StepAuthenticationEac1Widget::canTextEdited); + + QLabel* canLabel = new QLabel(tr("Card access number (CAN):")); + canLabel->setFocusPolicy(Qt::TabFocus); + basicReaderWidgetLayout->addWidget(canLabel); + basicReaderWidgetLayout->addWidget(mCANField); + + if (appSettings.getGeneralSettings().isUseScreenKeyboard()) + { + QToolButton* button = new QToolButton(); + button->setObjectName(QStringLiteral("canRandomButton")); + button->setAccessibleName(tr("Open on screen password dialog")); + button->setAutoRaise(true); + button->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + button->setIconSize(QSize(44, 26)); + + connect(button, &QAbstractButton::clicked, this, &StepAuthenticationEac1Widget::onRandomButtonClicked); + + basicReaderWidgetLayout->addWidget(button); + } + + } + + mPINField = new PasswordEdit(); + mPINField->setAccessibleName(tr("More information with TAB")); + mPINField->setMaxLength(6); + mPINField->configureValidation(onlyNumbersExpression, tr("Only digits (0-9) are permitted.")); + connect(mPINField, &PasswordEdit::textEdited, this, &StepAuthenticationEac1Widget::pinTextEdited); + + if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) + { + mPINField->setEnabled(false); + } + + QLabel* pinLabel = new QLabel(tr("PIN:")); + pinLabel->setFocusPolicy(Qt::TabFocus); + basicReaderWidgetLayout->addWidget(pinLabel); + basicReaderWidgetLayout->addWidget(mPINField); + + if (appSettings.getGeneralSettings().isUseScreenKeyboard()) + { + QToolButton* button = new QToolButton(); + button->setObjectName(QStringLiteral("pinRandomButton")); + button->setAccessibleName(tr("Open on screen password dialog")); + button->setAutoRaise(true); + button->setIcon(QPixmap(QStringLiteral(":/images/randompin/screen_keyboard.png"))); + button->setIconSize(QSize(44, 26)); + + connect(button, &QAbstractButton::clicked, this, &StepAuthenticationEac1Widget::onRandomButtonClicked); + + basicReaderWidgetLayout->addWidget(button); + } + + + mUi->pinWidgetLayout->invalidate(); + mUi->pinWidgetLayout->addWidget(basicReaderWidget); +} + + +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_WIN + if (mTaskbarButton) + { + auto progress = mTaskbarButton->progress(); + progress->setValue(pProgressValue == 0 ? progress->maximum() : pProgressValue); + } +#endif +} + + +void StepAuthenticationEac1Widget::checkBoxChanged(int pCheckState) +{ + QCheckBox* cb = qobject_cast(sender()); + if (cb != nullptr) + { + if (pCheckState == Qt::Unchecked) + { + QMap::ConstIterator i = qAsConst(mMap).find(cb); + bool success = mContext->removeEffectiveAccessRight(i.value()); + qCDebug(gui) << "Removed from effective chat:" << i.value() << "| success:" << success; + } + else + { + QMap::ConstIterator i = qAsConst(mMap).find(cb); + bool success = mContext->addEffectiveAccessRight(i.value()); + qCDebug(gui) << "Added to effective chat:" << i.value() << "| success:" << success; + } + } +} + + +void StepAuthenticationEac1Widget::onRandomButtonClicked() +{ + RandomPinDialog randomPinDialog(6, mContext->getReaderName(), this); + if (randomPinDialog.exec() == QDialog::Accepted && !randomPinDialog.getPin().isEmpty()) + { + QToolButton* pinButton = qobject_cast(sender()); + if (pinButton == nullptr) + { + qCCritical(gui) << "sender == nullptr"; + } + else if (pinButton->objectName() == QLatin1String("canRandomButton")) + { + canTextEdited(randomPinDialog.getPin()); + } + else if (pinButton->objectName() == QLatin1String("pinRandomButton")) + { + pinTextEdited(randomPinDialog.getPin()); + } + } +} + + +void StepAuthenticationEac1Widget::onResultChanged() +{ +#ifdef Q_OS_WIN + if (mTaskbarButton && (mContext.isNull() || mContext->getStatus().isError())) + { + mTaskbarButton->progress()->stop(); + } +#endif +} + + +void StepAuthenticationEac1Widget::hideEvent(QHideEvent* pEvent) +{ +#ifdef Q_OS_WIN + if (mTaskbarButton) + { + mTaskbarButton->progress()->setVisible(false); + } +#endif + QWidget::hideEvent(pEvent); +} + + +void StepAuthenticationEac1Widget::showEvent(QShowEvent* pEvent) +{ +#ifdef Q_OS_WIN + 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); +} + + +void StepAuthenticationEac1Widget::canTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mCANField->setText(pText); + } + + if (mCANField->text().size() == 6) + { + mPINField->setEnabled(true); + mPINField->setFocus(); + + Q_EMIT fireCanUpdated(mCANField->text()); + } + else + { + mPINField->setEnabled(false); + } + + mPINField->clear(); + pinTextEdited(QString()); +} + + +void StepAuthenticationEac1Widget::pinTextEdited(const QString& pText) +{ + if (!pText.isNull() && !pText.isEmpty()) + { + mPINField->setText(pText); + } + + if (mPINField->text().size() == 6) + { + Q_EMIT setForwardButtonState(ButtonState::FOCUSSED, tr("Identify now")); + Q_EMIT firePinUpdated(mPINField->text()); + } + else + { + Q_EMIT setForwardButtonState(ButtonState::DISABLED, tr("Identify now")); + } +} + + +void StepAuthenticationEac1Widget::focusWidget() +{ + if (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 1) + { + mCANField->setFocus(); + mCANField->setCursorPosition(0); + } + else + { + mPINField->setFocus(); + mPINField->setCursorPosition(0); + } +} + + +void StepAuthenticationEac1Widget::changeEvent(QEvent* pEvent) +{ + if (pEvent->type() == QEvent::LanguageChange) + { + updateWidget(); + mUi->retranslateUi(this); + setToolTip(); + } + QWidget::changeEvent(pEvent); +} diff --git a/src/widget/step/StepAuthenticationEac1Widget.h b/src/widget/step/StepAuthenticationEac1Widget.h new file mode 100644 index 0000000..dd92c6a --- /dev/null +++ b/src/widget/step/StepAuthenticationEac1Widget.h @@ -0,0 +1,114 @@ +/*! + * \brief Widget for the desktop StepAuthenticationEac1Gui. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "generic/ButtonState.h" + +#include + +#ifdef Q_OS_WIN +#include +#endif + +class QLabel; +class QProgressBar; + +namespace Ui +{ +class StepAuthenticationEac1Widget; +} + + +namespace governikus +{ + +class PasswordEdit; + +class StepAuthenticationEac1Widget + : public QWidget +{ + Q_OBJECT + + public: + enum class State + { + INITIAL, + EDIT_CHAT, + ENTER_PIN, + AUTHENTICATING_ESERVICE, + AUTHENTICATING_CARD, + READING_CARD_DATA, + REDIRECTING_BROWSER, + FINISHED, + }; + Q_ENUM(State); + + StepAuthenticationEac1Widget(QWidget* pParent = nullptr); + virtual ~StepAuthenticationEac1Widget() override; + + void setContext(const QSharedPointer& pContext); + + void setState(State pState); + void forwardStep(); + + void updateButtonsAndPinWidget(); + + Q_SIGNALS: + void setForwardButtonState(ButtonState pState, const QString& pText = QString()); + void setCancelButtonState(ButtonState pState); + + void firePinUpdated(const QString& pPin); + void fireCanUpdated(const QString& pCan); + + private Q_SLOTS: + void focusWidget(); + void onDetailsButtonClicked(); + void checkBoxChanged(int pCheckState); + void canTextEdited(const QString& pText); + void pinTextEdited(const QString& pText); + void onRandomButtonClicked(); + void onResultChanged(); + + protected: + virtual void hideEvent(QHideEvent* pEvent) override; + virtual void showEvent(QShowEvent* pEvent) override; + virtual void changeEvent(QEvent* pEvent) override; + + private: + void setToolTip(); + void updateWidget(); + 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(); + + private: + QScopedPointer mUi; + QSharedPointer mContext; + QMap mMap; + + PasswordEdit* mCANField; + PasswordEdit* mPINField; + + State mState; + QProgressBar* mProgressBar; + QLabel* mProgressBarLabel; + + bool mCloseWindowWhenFinished; + + #ifdef Q_OS_WIN + QWinTaskbarButton* mTaskbarButton; + #endif +}; + + +defineEnumOperators(StepAuthenticationEac1Widget::State) + +} /* namespace governikus */ diff --git a/src/widget/step/StepAuthenticationEac1Widget.ui b/src/widget/step/StepAuthenticationEac1Widget.ui new file mode 100644 index 0000000..460cee5 --- /dev/null +++ b/src/widget/step/StepAuthenticationEac1Widget.ui @@ -0,0 +1,392 @@ + + + StepAuthenticationEac1Widget + + + + 0 + 0 + 515 + 448 + + + + + 0 + 0 + + + + AusweisApp2 + + + + + + Qt::TabFocus + + + Service provider + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 6 + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + Purpose for reading out requested data: + + + + + + + Qt::TabFocus + + + true + + + + + + + Qt::TabFocus + + + Name: + + + + + + + Qt::TabFocus + + + true + + + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + details + + + more... + + + false + + + + + + + + + + + + + Qt::TabFocus + + + The following data is required by the service provider. You can deselect the non-mandatory data fields if you do not want this data to be transmitted. + + + true + + + + + + + Qt::TabFocus + + + Data + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + 0 + + + + + true + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + Qt::ScrollBarAsNeeded + + + + + + + true + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + Qt::ScrollBarAsNeeded + + + 0 + + + + + + + + + + + + Qt::TabFocus + + + Important transactional information + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + true + + + + + 0 + 0 + 475 + 69 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::TabFocus + + + background-color: white; + + + + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + + + + + + + + + + + + + + + 0 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + certificateDescriptionGroupBox + subjectNameLabel + subjectName + usageLabel + usage + detailsPushButton + label + groupBox + listWidgetWest + listWidgetEast + transactionInfoGroupBox + + + + diff --git a/src/widget/step/StepChooseCardGui.cpp b/src/widget/step/StepChooseCardGui.cpp new file mode 100644 index 0000000..9cea4fd --- /dev/null +++ b/src/widget/step/StepChooseCardGui.cpp @@ -0,0 +1,251 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepChooseCardGui.h" + +#include "Env.h" +#include "GuiProfile.h" +#include "ReaderConfiguration.h" +#include "step/AuthenticateStepsWidget.h" + +#include +#include +#include +#include +#include + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +StepChooseCardGui::StepChooseCardGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget) + : StepGui(pContext) + , mContext(pContext) + , mWidget(pStepsWidget->getEac1Page()) + , mInformationMessageBox(new QMessageBox(pStepsWidget)) + , mDiagnosisGui(new DiagnosisGui(pStepsWidget)) + , mReaderDeviceGui(new ReaderDeviceGui(pStepsWidget)) + , mCancelButton(nullptr) + , mDeviceButton(nullptr) + , mDiagnosisButton(nullptr) + , mSubDialogOpen(false) +{ + mInformationMessageBox->setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Information")); + mInformationMessageBox->setWindowModality(Qt::WindowModal); + mInformationMessageBox->setWindowFlags(mInformationMessageBox->windowFlags() & ~Qt::WindowContextHelpButtonHint); + mCancelButton = mInformationMessageBox->addButton(tr("Cancel"), QMessageBox::NoRole); + mDiagnosisButton = mInformationMessageBox->addButton(tr("Diagnosis"), QMessageBox::YesRole); + mDeviceButton = mInformationMessageBox->addButton(tr("Settings"), QMessageBox::YesRole); + + connect(mDiagnosisGui, &DiagnosisGui::fireFinished, this, &StepChooseCardGui::onSubDialogFinished); + connect(mReaderDeviceGui, &ReaderDeviceGui::fireFinished, this, &StepChooseCardGui::onSubDialogFinished); + + const QSharedPointer& remoteClient = Env::getSingleton()->getRemoteClient(); + connect(remoteClient.data(), &RemoteClient::fireCertificateRemoved, this, &StepChooseCardGui::onCertificateRemoved); +} + + +StepChooseCardGui::~StepChooseCardGui() +{ +} + + +void StepChooseCardGui::activate() +{ + mWidget->setContext(mContext); + + setCancelButtonState(ButtonState::ENABLED); + + connect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); + onReaderManagerSignal(); +} + + +void StepChooseCardGui::deactivate() +{ + mWidget->setContext(QSharedPointer()); + + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireReaderEvent, this, &StepChooseCardGui::onReaderManagerSignal); +} + + +QString StepChooseCardGui::getCurrentReaderImage(const QVector& pReaderInfos) +{ + if (pReaderInfos.size() == 1) + { + return pReaderInfos.at(0).getReaderConfigurationInfo().getIcon()->lookupPath(); + } + else if (pReaderInfos.size() > 1) + { + return ReaderConfiguration::getMultipleReaderIconPath(); + } + + return ReaderConfiguration::getNoReaderFoundIconPath(); +} + + +QString StepChooseCardGui::formatErrorMessages(const QString& pMessage1, const QString& pMessage2) +{ + const bool oneMessageIsEmpty = pMessage1.isEmpty() || pMessage2.isEmpty(); + + return oneMessageIsEmpty ? pMessage1 + pMessage2 : QStringLiteral("

%1

%2

").arg(pMessage1, pMessage2); +} + + +void StepChooseCardGui::updateErrorMessage(const QString& pTitle, const QString& pMessage1, const QString& pMessage2, bool closeErrorMessage) +{ + if (closeErrorMessage || mContext->getStatus().isError()) + { + mDiagnosisGui->deactivate(); + mReaderDeviceGui->deactivate(); + mInformationMessageBox->done(QMessageBox::InvalidRole); + return; + } + + QString iconPath = getCurrentReaderImage(Env::getSingleton()->getReaderInfos(ReaderFilter::UniqueReaderTypes)); + if (iconPath.isEmpty()) + { + mInformationMessageBox->setIcon(QMessageBox::Information); + } + else + { + mInformationMessageBox->setIconPixmap(QPixmap(iconPath).scaledToWidth(200, Qt::SmoothTransformation)); + } + mInformationMessageBox->setText(QStringLiteral("%1").arg(pTitle)); + mInformationMessageBox->setInformativeText(formatErrorMessages(pMessage1, pMessage2)); + + if (mInformationMessageBox->isVisible() || mSubDialogOpen) + { + return; + } + + if (mInformationMessageBox->exec() != QMessageBox::InvalidRole) + { + if (mInformationMessageBox->clickedButton() == mCancelButton) + { + Q_EMIT fireCancelled(); + return; + } + + mSubDialogOpen = true; + if (mInformationMessageBox->clickedButton() == mDiagnosisButton) + { + mDiagnosisGui->activate(); + } + else if (mInformationMessageBox->clickedButton() == mDeviceButton) + { + Q_EMIT fireCancelled(); + Q_EMIT fireSwitchToReaderSettingsRequested(); + } + } + // else: dialog was closed by an onErrorMessage(..., true) call (i.e. card found) +} + + +void StepChooseCardGui::onSubDialogFinished() +{ + mSubDialogOpen = false; + const QSharedPointer& remoteClient = ReaderManager::getInstance().getRemoteClient(); + remoteClient->startDetection(); + onReaderManagerSignal(); +} + + +void StepChooseCardGui::onReaderManagerSignal() +{ + const auto readers = ReaderManager::getInstance().getReaderInfos(); + + mDeviceButton->setEnabled(readers.isEmpty()); + + bool readerWithInsufficientApduLength = false; + QVector readersWithNpa; + for (const auto& readerInfo : readers) + { + if (!readerInfo.sufficientApduLength()) + { + readerWithInsufficientApduLength = true; + } + if (readerInfo.hasEidCard()) + { + readersWithNpa << readerInfo; + } + } + + if (readers.size() == 0) + { + updateErrorMessage(tr("No card reader detected. Please make sure that a card reader is connected."), + tr("If you would like to set up a local or remote card reader, click on the \"Settings\" button" + " to cancel the current operation and open the reader settings."), + tr("If you need help or have problems with your card reader click on the" + " \"Diagnosis\" button for further information."), + false); + return; + } + + if (readersWithNpa.size() == 0) + { + if (readerWithInsufficientApduLength) + { + if (readers.size() == 1) + { + updateErrorMessage(tr("Extended Length is not supported."), + tr("Your remote reader does not meet the technical requirements (Extended Length not supported)."), + QString(), + false); + return; + } + else + { + updateErrorMessage(tr("Extended Length is not supported."), + tr("At least one of your card readers does not meet the technical requirements (Extended Length not supported). Please place the ID card on a different card reader."), + QString(), + false); + } + } + else + { + updateErrorMessage(tr("Please place an ID card on the card reader."), + tr("If you have already placed an ID card on your card reader, click on \"Diagnosis\"" + " for further information."), + QString(), + false); + } + } + else if (readersWithNpa.size() > 1) + { + updateErrorMessage(tr("Please place only one ID card on the card reader."), + tr("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."), + QString(), + false); + } + else + { + 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 the authority responsible for issuing your identification document to activate the online identification function."), + QString(), + false); + } + else + { + updateErrorMessage(QString(), QString(), QString(), true); + } + } +} + + +void StepChooseCardGui::onCertificateRemoved(QString pDeviceName) +{ + QMessageBox messageBox; + messageBox.setText(tr("The device %1 was unpaired because it does not react to connection attempts. Retry the pairing process if you want to use this device to authenticate yourself.").arg(pDeviceName)); + messageBox.setStandardButtons(QMessageBox::Ok); + messageBox.setDefaultButton(QMessageBox::Ok); + messageBox.exec(); +} diff --git a/src/widget/step/StepChooseCardGui.h b/src/widget/step/StepChooseCardGui.h new file mode 100644 index 0000000..4842bb4 --- /dev/null +++ b/src/widget/step/StepChooseCardGui.h @@ -0,0 +1,61 @@ +/*! + * \brief GUI to select reader/card. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "DiagnosisGui.h" +#include "ReaderDeviceGui.h" +#include "ReaderManager.h" +#include "step/StepAuthenticationEac1Widget.h" +#include "StepGui.h" + +#include + +class QLabel; + +namespace governikus +{ + +class AuthenticateStepsWidget; + +class StepChooseCardGui + : public StepGui +{ + Q_OBJECT + + private: + const QSharedPointer mContext; + StepAuthenticationEac1Widget* const mWidget; + QPointer mInformationMessageBox; + QPointer mDiagnosisGui; + QPointer mReaderDeviceGui; + QPushButton* mCancelButton, * mDeviceButton, * mDiagnosisButton; + bool mSubDialogOpen; + + QString getCurrentReaderImage(const QVector& pReaderInfos); + static QString formatErrorMessages(const QString& pMessage1, const QString& pMessage2); + void updateErrorMessage(const QString& pTitle, const QString& pMessage1, const QString& pMessage2 = QString(), bool closeErrorMessage = false); + + private Q_SLOTS: + void onSubDialogFinished(); + + public Q_SLOTS: + void onReaderManagerSignal(); + void onCertificateRemoved(QString pDeviceName); + + public: + StepChooseCardGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget); + virtual ~StepChooseCardGui() override; + + virtual void activate() override; + virtual void deactivate() override; + + Q_SIGNALS: + void fireSwitchToReaderSettingsRequested(); +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepErrorGui.cpp b/src/widget/step/StepErrorGui.cpp new file mode 100644 index 0000000..516ca52 --- /dev/null +++ b/src/widget/step/StepErrorGui.cpp @@ -0,0 +1,70 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepErrorGui.h" + +#include "AppQtMainWidget.h" +#include "generic/GuiUtils.h" + +#include +#include +#include +#include + + +using namespace governikus; + + +Q_DECLARE_LOGGING_CATEGORY(gui) + + +StepErrorGui::StepErrorGui(QSharedPointer pContext, AppQtMainWidget* const pMainWidget) + : StepGui(pContext) + , mContext(pContext) + , mMainWidget(pMainWidget) +{ +} + + +StepErrorGui::~StepErrorGui() +{ +} + + +void StepErrorGui::reportError() +{ + // Do not close the window automatically in case of errors when the workflow is done. + mMainWidget->setHideWindowAfterWorkflow(false); + + if (mContext->getStatus().is(GlobalStatus::Code::Paos_Error_SAL_Invalid_Key) && !mContext->getCardConnection()->getReaderInfo().getCardInfo().isPinDeactivated()) + { + if (GuiUtils::showWrongPinBlockedDialog(mMainWidget)) + { + mMainWidget->switchToPinSettingsAfterWorkflow(); + Q_EMIT switchedToPinSettings(); + } + else + { + Q_EMIT fireUiFinished(); + } + return; + } + + QString message = mContext->getStatus().toErrorDescription(true); + if (message.isEmpty()) + { + 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() + QStringLiteral(" - ") + tr("Error"), message); + Q_EMIT fireUiFinished(); +} + + +void StepErrorGui::forwardStep() +{ + Q_EMIT fireUiFinished(); +} diff --git a/src/widget/step/StepErrorGui.h b/src/widget/step/StepErrorGui.h new file mode 100644 index 0000000..df9d262 --- /dev/null +++ b/src/widget/step/StepErrorGui.h @@ -0,0 +1,39 @@ +/*! + * \brief GUI for step "Error". + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/WorkflowContext.h" +#include "StepGui.h" + +namespace governikus +{ + +class AppQtMainWidget; + +class StepErrorGui + : public StepGui +{ + Q_OBJECT + + public: + StepErrorGui(QSharedPointer pContext, AppQtMainWidget* const pMainWidget); + virtual ~StepErrorGui() override; + + virtual void reportError(); + + public Q_SLOTS: + virtual void forwardStep() override; + + private: + QSharedPointer mContext; + AppQtMainWidget* const mMainWidget; + + Q_SIGNALS: + void switchedToPinSettings(); +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepGui.cpp b/src/widget/step/StepGui.cpp new file mode 100644 index 0000000..154bd23 --- /dev/null +++ b/src/widget/step/StepGui.cpp @@ -0,0 +1,32 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepGui.h" + +#include "context/WorkflowContext.h" + +using namespace governikus; + +StepGuiDelegate::StepGuiDelegate() + : QObject() +{ +} + + +StepGui::StepGui(const QSharedPointer& pContext) + : mDelegate(new StepGuiDelegate) +{ + connect(this, &StepGui::fireCancelled, pContext.data(), &WorkflowContext::fireCancelWorkflow); +} + + +StepGui::~StepGui() +{ +} + + +void StepGui::forwardStep() +{ + // can be implemented by subclasses +} diff --git a/src/widget/step/StepGui.h b/src/widget/step/StepGui.h new file mode 100644 index 0000000..4519a9e --- /dev/null +++ b/src/widget/step/StepGui.h @@ -0,0 +1,83 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "generic/ButtonState.h" + +#include +#include +#include + +namespace governikus +{ + +class WorkflowContext; + + +class StepGuiDelegate + : public QObject +{ + Q_OBJECT + + public: + StepGuiDelegate(); + + Q_SIGNALS: + void setForwardButtonState(ButtonState pState, const QString& pText); + void setCancelButtonState(ButtonState pState); +}; + + +class StepGui + : public QObject +{ + Q_OBJECT + + public: + StepGui(const QSharedPointer& pContext); + virtual ~StepGui(); + + StepGuiDelegate* getStepGuiDelegate() const + { + return mDelegate.data(); + } + + + virtual void activate() + { + } + + + virtual void deactivate() + { + } + + + virtual void forwardStep(); + + protected: + void setForwardButtonState(ButtonState pState, const QString& pText = QString()) + { + Q_EMIT mDelegate->setForwardButtonState(pState, pText); + } + + + void setCancelButtonState(ButtonState pState) + { + Q_EMIT mDelegate->setCancelButtonState(pState); + } + + + protected: + QScopedPointer mDelegate; + + Q_SIGNALS: + //void fireErrorMessage(QString pTitle, QString pMessage, QVector pReaderInfos, bool closeErrorMessage = false); + void fireUiFinished(); + void fireCancelled(); + +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepProcessingGui.cpp b/src/widget/step/StepProcessingGui.cpp new file mode 100644 index 0000000..be87c60 --- /dev/null +++ b/src/widget/step/StepProcessingGui.cpp @@ -0,0 +1,37 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepProcessingGui.h" + +#include "generic/BusyOverlayContainer.h" +#include "step/AuthenticateStepsWidget.h" + +using namespace governikus; + +StepProcessingGui::StepProcessingGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget) + : StepGui(pContext) + , mStepsWidget(pStepsWidget) +{ +} + + +StepProcessingGui::~StepProcessingGui() +{ +} + + +void StepProcessingGui::activate() +{ + setCancelButtonState(ButtonState::ENABLED); + setForwardButtonState(ButtonState::HIDDEN); + + mStepsWidget->setCurrentWidget(mStepsWidget->getProcessingPage()); + mStepsWidget->getProcessingPage()->startAnimation(); +} + + +void StepProcessingGui::deactivate() +{ + mStepsWidget->getProcessingPage()->stopAnimation(); +} diff --git a/src/widget/step/StepProcessingGui.h b/src/widget/step/StepProcessingGui.h new file mode 100644 index 0000000..9ff2497 --- /dev/null +++ b/src/widget/step/StepProcessingGui.h @@ -0,0 +1,31 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "StepGui.h" + + +namespace governikus +{ + +class AuthenticateStepsWidget; + +class StepProcessingGui + : public StepGui +{ + Q_OBJECT + + public: + StepProcessingGui(const QSharedPointer& pContext, AuthenticateStepsWidget* pStepsWidget); + virtual ~StepProcessingGui() override; + + virtual void activate() override; + virtual void deactivate() override; + + private: + AuthenticateStepsWidget* mStepsWidget; +}; + +} /* namespace governikus */ diff --git a/src/widget/step/StepShowSelfAuthenticationDataGui.cpp b/src/widget/step/StepShowSelfAuthenticationDataGui.cpp new file mode 100644 index 0000000..b626534 --- /dev/null +++ b/src/widget/step/StepShowSelfAuthenticationDataGui.cpp @@ -0,0 +1,45 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "StepShowSelfAuthenticationDataGui.h" + +#include "step/AuthenticateStepsWidget.h" +#include "step/SelfInfoWidget.h" + +using namespace governikus; + +StepShowSelfAuthenticationDataGui::StepShowSelfAuthenticationDataGui(QSharedPointer pContext, + AuthenticateStepsWidget* pStepsWidget) + : StepGui(pContext) + , mContext(pContext) + , mStepsWidget(pStepsWidget) +{ +} + + +StepShowSelfAuthenticationDataGui::~StepShowSelfAuthenticationDataGui() +{ +} + + +void StepShowSelfAuthenticationDataGui::activate() +{ + SelfInfoWidget* selfInfoWidget = mStepsWidget->getSelfInfoPage(); + selfInfoWidget->setInfo(mContext->getSelfAuthenticationData()); + mStepsWidget->setCurrentWidget(selfInfoWidget); + + setForwardButtonState(ButtonState::FOCUSSED, tr("Close")); + setCancelButtonState(ButtonState::HIDDEN); +} + + +void StepShowSelfAuthenticationDataGui::deactivate() +{ +} + + +void StepShowSelfAuthenticationDataGui::forwardStep() +{ + mContext->setStateApproved(); +} diff --git a/src/widget/step/StepShowSelfAuthenticationDataGui.h b/src/widget/step/StepShowSelfAuthenticationDataGui.h new file mode 100644 index 0000000..9fb16b2 --- /dev/null +++ b/src/widget/step/StepShowSelfAuthenticationDataGui.h @@ -0,0 +1,37 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/SelfAuthContext.h" +#include "StepGui.h" + +#include + +namespace governikus +{ + +class AuthenticateStepsWidget; + +class StepShowSelfAuthenticationDataGui + : public StepGui +{ + Q_OBJECT + + public: + StepShowSelfAuthenticationDataGui(QSharedPointer pContext, AuthenticateStepsWidget* pStepsWidget); + virtual ~StepShowSelfAuthenticationDataGui() override; + + virtual void activate() override; + virtual void deactivate() override; + + private Q_SLOTS: + virtual void forwardStep() override; + + private: + QSharedPointer mContext; + AuthenticateStepsWidget* mStepsWidget; +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/GenericWorkflowGui.h b/src/widget/workflow/GenericWorkflowGui.h new file mode 100644 index 0000000..c49b9a1 --- /dev/null +++ b/src/widget/workflow/GenericWorkflowGui.h @@ -0,0 +1,91 @@ +/*! + * \brief Generic base class for Qt based WorkflowUi implementations. + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "AppQtMainWidget.h" +#include "context/WorkflowContext.h" +#include "step/StepGui.h" +#include "WorkflowGui.h" +#include "WorkflowQtWidget.h" + +#include +#include + + +namespace governikus +{ + +template +class GenericWorkflowGui + : public WorkflowGui +{ + protected: + AppQtMainWidget* mParentWidget; + WorkflowQtWidget* mWidget; + QSharedPointer mStepGui; + QSharedPointer mContext; + + public: + GenericWorkflowGui(const QSharedPointer& pContext, AppQtMainWidget* pParentWidget, WorkflowQtWidget* pWidget) + : WorkflowGui() + , mParentWidget(pParentWidget) + , mWidget(pWidget) + , mStepGui(nullptr) + , mContext(pContext.objectCast()) + { + Q_ASSERT(mContext != nullptr); + connect(this, &WorkflowGui::fireUserCancelled, mContext.data(), &WorkflowContext::fireCancelWorkflow); + } + + + virtual void deactivate() override + { + deactivateCurrentStepUi(); + } + + + virtual void activateStepUi(const QSharedPointer& pStepUi) + { + Q_ASSERT(pStepUi); + if (mStepGui == pStepUi) + { + return; + } + + deactivateCurrentStepUi(); + + mStepGui = pStepUi; + if (mWidget != nullptr) + { + QObject::connect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState, mWidget, &WorkflowQtWidget::setForwardButtonState); + QObject::connect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState, mWidget, &WorkflowQtWidget::setCancelButtonState); + } + pStepUi->activate(); + } + + + private: + void deactivateCurrentStepUi() + { + if (mStepGui == nullptr) + { + return; + } + + mStepGui->deactivate(); + if (mWidget != nullptr) + { + QObject::disconnect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setForwardButtonState, mWidget, &WorkflowQtWidget::setForwardButtonState); + QObject::disconnect(mStepGui->getStepGuiDelegate(), &StepGuiDelegate::setCancelButtonState, mWidget, &WorkflowQtWidget::setCancelButtonState); + } + mStepGui.clear(); + } + + +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowAuthenticateQtGui.cpp b/src/widget/workflow/WorkflowAuthenticateQtGui.cpp new file mode 100644 index 0000000..1d7b5bd --- /dev/null +++ b/src/widget/workflow/WorkflowAuthenticateQtGui.cpp @@ -0,0 +1,183 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowAuthenticateQtGui.h" + +#include "AppSettings.h" +#include "generic/GuiUtils.h" +#include "states/FinalState.h" +#include "states/StateCheckRefreshAddress.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/StateSelectReader.h" +#include "states/StateTransmit.h" +#include "states/StateWriteHistory.h" +#include "step/AuthenticateStepsWidget.h" +#include "step/StepAdviseUserToRemoveCardGui.h" +#include "step/StepAuthenticationDoneGui.h" +#include "step/StepAuthenticationEac1Gui.h" +#include "step/StepChooseCardGui.h" +#include "step/StepErrorGui.h" +#include "step/StepProcessingGui.h" +#include "workflow/WorkflowQtWidget.h" + + +using namespace governikus; + + +WorkflowAuthenticateQtGui::WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) + : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) + , mCanEntered(false) + , mAuthenticateStepsWidget(mParentWidget->findChild()) + , 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)) + , mAuthenticationDoneGui(new StepAuthenticationDoneGui(mContext)) +{ + Q_ASSERT(mAuthenticateStepsWidget != nullptr); + connect(mWidget, &WorkflowQtWidget::fireUserCancelled, this, &WorkflowGui::fireUserCancelled); + connect(mWidget, &WorkflowQtWidget::forwardStep, this, &WorkflowAuthenticateQtGui::onForwardStep); + connect(mChooseCardGui.data(), &StepChooseCardGui::fireSwitchToReaderSettingsRequested, this, &WorkflowGui::fireSwitchToReaderSettingsRequested); +} + + +WorkflowAuthenticateQtGui::~WorkflowAuthenticateQtGui() +{ +} + + +void WorkflowAuthenticateQtGui::activate() +{ + activateStepUi(mProcessingGui); + mParentWidget->workflowActivated(WorkflowWidgetParent::Authentication, tr("Identify")); + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &WorkflowAuthenticateQtGui::onStateChanged); +} + + +void WorkflowAuthenticateQtGui::deactivate() +{ + mParentWidget->workflowDeactivated(); +} + + +bool WorkflowAuthenticateQtGui::verifyAbortWorkflow() +{ + QMessageBox msgBox(mParentWidget); + msgBox.setWindowTitle(QCoreApplication::applicationName() + QStringLiteral(" - ") + tr("Cancel")); + msgBox.setWindowModality(Qt::WindowModal); + 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.")); + 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::onForwardStep() +{ + if (mStepGui != nullptr) + { + mStepGui->forwardStep(); + } +} + + +void WorkflowAuthenticateQtGui::onStateChanged(const QString& pNewState) +{ + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) + { + if (!mContext->getStatus().isCancellationByUser()) + { + activateStepUi(mErrorGui); + mErrorGui->reportError(); + } + mContext->setErrorReportedToUser(); + } + + + bool approveNewState = true; + if (AbstractState::isState(pNewState)) + { + activateStepUi(mProcessingGui); + + GeneralSettings& settings = AppSettings::getInstance().getGeneralSettings(); + approveNewState = !settings.isTransportPinReminder(); + } + else if (AbstractState::isState(pNewState)) + { + approveNewState = false; + activateStepUi(mDidAuthenticateGui); + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::EDIT_CHAT); + } + else if (AbstractState::isState(pNewState)) + { + mContext->setStateApproved(true); + activateStepUi(mChooseCardGui); + return; + } + 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(StepAuthenticationEac1Widget::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(); + } + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::AUTHENTICATING_ESERVICE); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::AUTHENTICATING_CARD); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::READING_CARD_DATA); + } + else if (AbstractState::isState(pNewState) && mDidAuthenticateGui->isActive()) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::REDIRECTING_BROWSER); + } + else if (AbstractState::isState(pNewState) && mDidAuthenticateGui->isActive()) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::FINISHED); + } + else if (AbstractState::isState(pNewState)) + { + activateStepUi(mAdviseUserToRemoveCardGui); + activateStepUi(mAuthenticationDoneGui); + } + mContext->setStateApproved(approveNewState); +} diff --git a/src/widget/workflow/WorkflowAuthenticateQtGui.h b/src/widget/workflow/WorkflowAuthenticateQtGui.h new file mode 100644 index 0000000..2a58f8f --- /dev/null +++ b/src/widget/workflow/WorkflowAuthenticateQtGui.h @@ -0,0 +1,53 @@ +/*! + * \brief Qt widget based WorkflowAuthenticateUi implementation. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/AuthContext.h" +#include "GenericWorkflowGui.h" + + +namespace governikus +{ + +class AuthenticateStepsWidget; +class StepAdviseUserToRemoveCardGui; +class StepAuthenticationDoneGui; +class StepAuthenticationEac1Gui; +class StepChooseCardGui; +class StepErrorGui; +class StepProcessingGui; + + +class WorkflowAuthenticateQtGui + : public GenericWorkflowGui +{ + Q_OBJECT + + private: + bool mCanEntered; + AuthenticateStepsWidget* mAuthenticateStepsWidget; + QSharedPointer mAdviseUserToRemoveCardGui; + QSharedPointer mDidAuthenticateGui; + QSharedPointer mChooseCardGui; + QSharedPointer mErrorGui; + QSharedPointer mProcessingGui; + QSharedPointer mAuthenticationDoneGui; + + private Q_SLOTS: + void onForwardStep(); + void onStateChanged(const QString& pNewState); + + public: + WorkflowAuthenticateQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget); + virtual ~WorkflowAuthenticateQtGui() override; + + virtual void activate() override; + virtual void deactivate() override; + virtual bool verifyAbortWorkflow() override; +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowChangePinQtGui.cpp b/src/widget/workflow/WorkflowChangePinQtGui.cpp new file mode 100644 index 0000000..d8fd438 --- /dev/null +++ b/src/widget/workflow/WorkflowChangePinQtGui.cpp @@ -0,0 +1,106 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowChangePinQtGui.h" + +#include "AppQtMainWidget.h" +#include "generic/GuiUtils.h" +#include "PinSettingsWidget.h" +#include "states/StateChangePin.h" +#include "states/StateCleanUpReaderManager.h" +#include "states/StateEstablishPaceCan.h" +#include "states/StateEstablishPacePin.h" +#include "states/StateEstablishPacePuk.h" +#include "states/StateHandleRetryCounter.h" +#include "step/StepErrorGui.h" + +using namespace governikus; + +WorkflowChangePinQtGui::WorkflowChangePinQtGui(QSharedPointer pContext, AppQtMainWidget* const pParentWidget) + : GenericWorkflowGui(pContext, pParentWidget, nullptr) + , mPinSettingsWidget(mParentWidget->findChild()) + , mErrorGui(new StepErrorGui(mContext, mParentWidget)) +{ + Q_ASSERT(mPinSettingsWidget); + connect(mContext.data(), &WorkflowContext::fireStateChanged, this, &WorkflowChangePinQtGui::onStateChanged); +} + + +WorkflowChangePinQtGui::~WorkflowChangePinQtGui() +{ +} + + +void WorkflowChangePinQtGui::activate() +{ + mParentWidget->workflowActivated(WorkflowWidgetParent::SettingsChangePin, QString()); + mPinSettingsWidget->setInProgress(true); +} + + +void WorkflowChangePinQtGui::deactivate() +{ + mPinSettingsWidget->setInProgress(false); + mParentWidget->workflowDeactivated(); +} + + +bool WorkflowChangePinQtGui::verifyAbortWorkflow() +{ + // not really necessary to notify the user + return true; +} + + +void WorkflowChangePinQtGui::onStateChanged(const QString& pNextState) +{ + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) + { + if (!mContext->getStatus().isCancellationByUser()) + { + activateStepUi(mErrorGui); + mErrorGui->reportError(); + } + mContext->setErrorReportedToUser(); + } + + if (AbstractState::isState(pNextState)) + { + if (mContext->getLastPaceResult() != CardReturnCode::OK) + { + auto newRetryCounter = mContext->getCardConnection()->getReaderInfo().getRetryCounter(); + GuiUtils::showPinCanPukErrorDialog(mContext->getLastPaceResult(), newRetryCounter, mPinSettingsWidget); + + /* + * In the desktop version we cancel the workflow after a wrong user input. + * If the user wants to try again, the workflow must be started again. + */ + Q_EMIT mContext->fireCancelWorkflow(); + return; + } + } + else if (AbstractState::isState(pNextState)) + { + mContext->setPin(mPinSettingsWidget->getPin()); + } + else if (AbstractState::isState(pNextState)) + { + mContext->setCan(mPinSettingsWidget->getCan()); + } + else if (AbstractState::isState(pNextState)) + { + mContext->setPuk(mPinSettingsWidget->getPuk()); + } + else if (AbstractState::isState(pNextState)) + { + mContext->setNewPin(mPinSettingsWidget->getNewPin()); + } + else if (AbstractState::isState(pNextState) && mContext->getStatus().isNoError()) + { + bool pinBlocked = (mContext->getCardConnection()->getReaderInfo().getRetryCounter() == 0); + mPinSettingsWidget->setMode(pinBlocked ? PinSettingsWidget::Mode::AfterPinUnblock : PinSettingsWidget::Mode::AfterPinChange); + } + + mContext->setStateApproved(); +} diff --git a/src/widget/workflow/WorkflowChangePinQtGui.h b/src/widget/workflow/WorkflowChangePinQtGui.h new file mode 100644 index 0000000..42f59d7 --- /dev/null +++ b/src/widget/workflow/WorkflowChangePinQtGui.h @@ -0,0 +1,41 @@ +/*! + * \brief Qt widget based WorkflowChangePinUi implementation. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/ChangePinContext.h" +#include "GenericWorkflowGui.h" + +namespace governikus +{ + +class AppQtMainWidget; +class PinSettingsWidget; +class StepErrorGui; + + +class WorkflowChangePinQtGui + : public GenericWorkflowGui +{ + Q_OBJECT + + public: + WorkflowChangePinQtGui(QSharedPointer pContext, AppQtMainWidget* const pParentWidget); + virtual ~WorkflowChangePinQtGui() override; + + virtual void activate() override; + virtual void deactivate() override; + virtual bool verifyAbortWorkflow() override; + + private Q_SLOTS: + void onStateChanged(const QString& pNextState); + + private: + PinSettingsWidget* mPinSettingsWidget; + QSharedPointer mErrorGui; +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowGui.cpp b/src/widget/workflow/WorkflowGui.cpp new file mode 100644 index 0000000..519c67d --- /dev/null +++ b/src/widget/workflow/WorkflowGui.cpp @@ -0,0 +1,24 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowGui.h" + +#include "step/StepGui.h" + +using namespace governikus; + +WorkflowGuiDelegate::WorkflowGuiDelegate() +{ +} + + +WorkflowGui::WorkflowGui() + : mDelegate(new WorkflowGuiDelegate) +{ +} + + +WorkflowGui::~WorkflowGui() +{ +} diff --git a/src/widget/workflow/WorkflowGui.h b/src/widget/workflow/WorkflowGui.h new file mode 100644 index 0000000..5025103 --- /dev/null +++ b/src/widget/workflow/WorkflowGui.h @@ -0,0 +1,70 @@ +/*! + * \brief Base class for Qt based WorkflowUi implementations. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include + +#include "AppQtMainWidget.h" +#include "context/WorkflowContext.h" +#include "step/StepGui.h" +#include "WorkflowQtWidget.h" +#include "WorkflowWidgetParent.h" + +namespace governikus +{ + +class WorkflowQtWidget; + +class WorkflowGuiDelegate + : public QObject +{ + Q_OBJECT + + public: + WorkflowGuiDelegate(); +}; + + +class WorkflowGui + : public QObject +{ + Q_OBJECT + + protected: + QScopedPointer mDelegate; + + public: + WorkflowGui(); + virtual ~WorkflowGui(); + + WorkflowGuiDelegate* getWorkflowGuiDelegate() const + { + return mDelegate.data(); + } + + + virtual bool verifyAbortWorkflow() = 0; + + virtual void activate() + { + } + + + virtual void deactivate() + { + } + + + Q_SIGNALS: + void fireUserCancelled(); + void fireChangePinRequest(); + void fireSwitchToReaderSettingsRequested(); + +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowQtWidget.cpp b/src/widget/workflow/WorkflowQtWidget.cpp new file mode 100644 index 0000000..1ef8069 --- /dev/null +++ b/src/widget/workflow/WorkflowQtWidget.cpp @@ -0,0 +1,118 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowQtWidget.h" + +#include +#include +#include + +using namespace governikus; + +WorkflowQtWidget::WorkflowQtWidget(QWidget* pParent) + : QWidget(pParent) + , mMainLayout(new QVBoxLayout(this)) + , mStepWidgetArea(new QWidget(this)) + , mCancelButton(nullptr) + , mForwardButton(nullptr) +{ + (new QVBoxLayout(mStepWidgetArea))->setMargin(0); + mMainLayout->addWidget(mStepWidgetArea); + mMainLayout->setMargin(0); + + QHBoxLayout* buttonLayout = new QHBoxLayout(); + buttonLayout->setMargin(0); + mMainLayout->addLayout(buttonLayout); + + QSpacerItem* horizontalSpacer = new QSpacerItem(40, 1, QSizePolicy::Expanding, QSizePolicy::Ignored); + + buttonLayout->addItem(horizontalSpacer); + + mCancelButton = new QPushButton(this); + connect(mCancelButton, &QPushButton::clicked, this, &WorkflowQtWidget::onCancelButtonClicked); + mCancelButton->setVisible(false); + buttonLayout->addWidget(mCancelButton); + setCancelButtonState(ButtonState::HIDDEN); + + mForwardButton = new QPushButton(this); + connect(mForwardButton, &QPushButton::clicked, this, &WorkflowQtWidget::forwardStep); + mForwardButton->setVisible(false); + buttonLayout->addWidget(mForwardButton); + setForwardButtonState(ButtonState::HIDDEN); +} + + +WorkflowQtWidget::~WorkflowQtWidget() +{ +} + + +void WorkflowQtWidget::addStepWidget(QWidget* pStepWidget) +{ + mStepWidgetArea->layout()->addWidget(pStepWidget); +} + + +void WorkflowQtWidget::removeStepWidget(QWidget* pStepWidget) +{ + mStepWidgetArea->layout()->removeWidget(pStepWidget); + pStepWidget->setParent(nullptr); // Remove widget from display + // Note: The Step* widgets are deleted in the Step* dtors. +} + + +void WorkflowQtWidget::setForwardButtonState(ButtonState pState, const QString& pText) +{ + setButtonState(mForwardButton, pState, pText.isEmpty() ? tr("Next") : pText); +} + + +void WorkflowQtWidget::setCancelButtonState(ButtonState pState) +{ + setButtonState(mCancelButton, pState, tr("Cancel")); +} + + +void WorkflowQtWidget::onCancelButtonClicked() +{ + setCancelButtonState(ButtonState::DISABLED); + Q_EMIT fireUserCancelled(); +} + + +void WorkflowQtWidget::setButtonState(QAbstractButton* pButton, ButtonState pState, const QString& pText) +{ + pButton->setText(pText); + + switch (pState) + { + case ButtonState::ENABLED: + pButton->setVisible(true); + pButton->setEnabled(true); + break; + + case ButtonState::DISABLED: + pButton->setVisible(true); + pButton->setEnabled(false); + break; + + case ButtonState::HIDDEN: + pButton->setVisible(false); + break; + + case ButtonState::FOCUSSED: + pButton->setVisible(true); + pButton->setEnabled(true); + focusForwardButton(); + break; + } +} + + +void WorkflowQtWidget::focusForwardButton() +{ + mForwardButton->setAutoDefault(true); + mForwardButton->setDefault(true); + mForwardButton->setFocus(); +} diff --git a/src/widget/workflow/WorkflowQtWidget.h b/src/widget/workflow/WorkflowQtWidget.h new file mode 100644 index 0000000..e9d80e3 --- /dev/null +++ b/src/widget/workflow/WorkflowQtWidget.h @@ -0,0 +1,65 @@ +/*! + * \brief Base class for workflow Qt GUI widgets. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include +#include +#include + +#include "step/StepGui.h" + +class QVBoxLayout; + +namespace governikus +{ + +class WorkflowQtWidget + : public QWidget +{ + Q_OBJECT + + public: + WorkflowQtWidget(QWidget* pParent = nullptr); + virtual ~WorkflowQtWidget(); + + QWidget* getStepWidgetArea() const + { + return mStepWidgetArea; + } + + + void addStepWidget(QWidget* widget); + void removeStepWidget(QWidget* widget); + + Q_SIGNALS: + /*! + * This signal is sent when the user presses the "Cancel" button. + */ + void fireUserCancelled(); + + /*! + * This signal is sent when the user presses the "Continue" button. + */ + void forwardStep(); + + public Q_SLOTS: + void onCancelButtonClicked(); + void setForwardButtonState(ButtonState pState, const QString& pText = QString()); + void setCancelButtonState(ButtonState pState); + + private: + void setButtonState(QAbstractButton* pButton, ButtonState pState, const QString& pText); + void focusForwardButton(); + + private: + QVBoxLayout* mMainLayout; + QWidget* mStepWidgetArea; + QPushButton* mCancelButton; + QPushButton* mForwardButton; +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowSelfInfoQtGui.cpp b/src/widget/workflow/WorkflowSelfInfoQtGui.cpp new file mode 100644 index 0000000..fe41361 --- /dev/null +++ b/src/widget/workflow/WorkflowSelfInfoQtGui.cpp @@ -0,0 +1,172 @@ +/*! + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "WorkflowSelfInfoQtGui.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/StateSelectReader.h" +#include "states/StateTransmit.h" +#include "states/StateWriteHistory.h" +#include "step/AuthenticateStepsWidget.h" +#include "step/StepAdviseUserToRemoveCardGui.h" +#include "step/StepAuthenticationEac1Gui.h" +#include "step/StepChooseCardGui.h" +#include "step/StepErrorGui.h" +#include "step/StepProcessingGui.h" +#include "step/StepShowSelfAuthenticationDataGui.h" +#include "workflow/WorkflowQtWidget.h" + + +using namespace governikus; + + +WorkflowSelfInfoQtGui::WorkflowSelfInfoQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget) + : GenericWorkflowGui(pContext, pParentWidget, pParentWidget->getAuthenticationWorkflowWidget()) + , mCanEntered(false) + , mAuthenticateStepsWidget(pParentWidget->findChild()) + , 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(mChooseCardGui.data(), &StepChooseCardGui::fireSwitchToReaderSettingsRequested, this, &WorkflowGui::fireSwitchToReaderSettingsRequested); +} + + +WorkflowSelfInfoQtGui::~WorkflowSelfInfoQtGui() +{ +} + + +void WorkflowSelfInfoQtGui::activate() +{ + activateStepUi(mProcessingGui); + mParentWidget->workflowActivated(WorkflowWidgetParent::SelfAuthentication, tr("Identify")); + connect(mContext.data(), &SelfAuthContext::fireStateChanged, this, &WorkflowSelfInfoQtGui::onStateChanged); +} + + +void WorkflowSelfInfoQtGui::deactivate() +{ + mParentWidget->workflowDeactivated(); +} + + +bool WorkflowSelfInfoQtGui::verifyAbortWorkflow() +{ + // not really necessary to notify the user + return true; +} + + +void WorkflowSelfInfoQtGui::onForwardStep() +{ + if (mStepGui) + { + mStepGui->forwardStep(); + } +} + + +void WorkflowSelfInfoQtGui::onStateChanged(const QString& pNewState) +{ + if (mContext->getStatus().isError() && !mContext->isErrorReportedToUser()) + { + 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(StepAuthenticationEac1Widget::State::EDIT_CHAT); + } + else if (AbstractState::isState(pNewState)) + { + mContext->setStateApproved(true); + activateStepUi(mChooseCardGui); + return; + } + 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(StepAuthenticationEac1Widget::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(); + } + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::AUTHENTICATING_ESERVICE); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::AUTHENTICATING_CARD); + } + else if (AbstractState::isState(pNewState)) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::READING_CARD_DATA); + } + else if (AbstractState::isState(pNewState) && mDidAuthenticateGui->isActive()) + { + mDidAuthenticateGui->setState(StepAuthenticationEac1Widget::State::FINISHED); + } + else if (AbstractState::isState(pNewState)) + { + activateStepUi(mAdviseUserToRemoveCardGui); + if (mContext->getStatus().isNoError()) + { + approveNewState = false; + activateStepUi(mShowSelfAuthenticationDataGui); + } + } + mContext->setStateApproved(approveNewState); +} diff --git a/src/widget/workflow/WorkflowSelfInfoQtGui.h b/src/widget/workflow/WorkflowSelfInfoQtGui.h new file mode 100644 index 0000000..d34d6b8 --- /dev/null +++ b/src/widget/workflow/WorkflowSelfInfoQtGui.h @@ -0,0 +1,51 @@ +/*! + * \brief Qt widget based WorkflowSelfInfoUi implementation. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "context/SelfAuthContext.h" +#include "GenericWorkflowGui.h" + +namespace governikus +{ + +class AuthenticateStepsWidget; +class StepAdviseUserToRemoveCardGui; +class StepShowSelfAuthenticationDataGui; +class StepAuthenticationEac1Gui; +class StepChooseCardGui; +class StepErrorGui; +class StepProcessingGui; + +class WorkflowSelfInfoQtGui + : public GenericWorkflowGui +{ + Q_OBJECT + + private: + bool mCanEntered; + AuthenticateStepsWidget* mAuthenticateStepsWidget; + QSharedPointer mAdviseUserToRemoveCardGui; + QSharedPointer mDidAuthenticateGui; + QSharedPointer mChooseCardGui; + QSharedPointer mErrorGui; + QSharedPointer mProcessingGui; + QSharedPointer mShowSelfAuthenticationDataGui; + + private Q_SLOTS: + void onForwardStep(); + void onStateChanged(const QString& pNewState); + + public: + WorkflowSelfInfoQtGui(const QSharedPointer& pContext, AppQtMainWidget* const pParentWidget); + virtual ~WorkflowSelfInfoQtGui() override; + + virtual void activate() override; + virtual void deactivate() override; + virtual bool verifyAbortWorkflow() override; +}; + +} /* namespace governikus */ diff --git a/src/widget/workflow/WorkflowWidgetParent.h b/src/widget/workflow/WorkflowWidgetParent.h new file mode 100644 index 0000000..e0df2b3 --- /dev/null +++ b/src/widget/workflow/WorkflowWidgetParent.h @@ -0,0 +1,21 @@ +/*! + * \brief Enum identifying the containers in the application GUI which can be + * parent to a workflow widget. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +namespace governikus +{ + +enum class WorkflowWidgetParent +{ + Authentication, + SettingsChangePin, + SelfAuthentication +}; + + +} /* namespace governikus */ diff --git a/src/widgetDesignerPlugin/CMakeLists.txt b/src/widgetDesignerPlugin/CMakeLists.txt new file mode 100644 index 0000000..40a4b5d --- /dev/null +++ b/src/widgetDesignerPlugin/CMakeLists.txt @@ -0,0 +1,3 @@ +ADD_PLATFORM_LIBRARY(AusweisAppWidgetDesignerPlugin) + +TARGET_LINK_LIBRARIES(AusweisAppWidgetDesignerPlugin Qt5::Core Qt5::UiPlugin AusweisAppWidget) diff --git a/src/widgetDesignerPlugin/GovernikusPluginCollection.cpp b/src/widgetDesignerPlugin/GovernikusPluginCollection.cpp new file mode 100644 index 0000000..ad3b983 --- /dev/null +++ b/src/widgetDesignerPlugin/GovernikusPluginCollection.cpp @@ -0,0 +1,35 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "GovernikusPluginCollection.h" + +#include "plugins/GeneralSettingsWidgetDesignerPlugin.h" +#include "plugins/HistoryWidgetDesignerPlugin.h" +#include "plugins/PinSettingsWidgetDesignerPlugin.h" +#include "plugins/ProviderWidgetDesignerPlugin.h" +#include "plugins/SelfInformationWidgetDesignerPlugin.h" +#include "plugins/SettingsWidgetDesignerPlugin.h" + +using namespace governikus; + + +GovernikusPluginCollection::GovernikusPluginCollection(QObject* pParent) + : QObject(pParent) +{ + mWidgets += new SelfInformationWidgetDesignerPlugin(this); + + mWidgets += new ProviderWidgetDesignerPlugin(this); + + mWidgets += new HistoryWidgetDesignerPlugin(this); + + mWidgets += new GeneralSettingsWidgetDesignerPlugin(this); + mWidgets += new PinSettingsWidgetDesignerPlugin(this); + mWidgets += new SettingsWidgetDesignerPlugin(this); +} + + +QList GovernikusPluginCollection::customWidgets() const +{ + return mWidgets; +} diff --git a/src/widgetDesignerPlugin/GovernikusPluginCollection.h b/src/widgetDesignerPlugin/GovernikusPluginCollection.h new file mode 100644 index 0000000..e160d32 --- /dev/null +++ b/src/widgetDesignerPlugin/GovernikusPluginCollection.h @@ -0,0 +1,27 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ +class GovernikusPluginCollection + : public QObject + , public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface") + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + + public: + GovernikusPluginCollection(QObject* pParent = 0); + QList customWidgets() const override; + + private: + QList mWidgets; +}; + +} diff --git a/src/widgetDesignerPlugin/README.rst b/src/widgetDesignerPlugin/README.rst new file mode 100644 index 0000000..c8ea00c --- /dev/null +++ b/src/widgetDesignerPlugin/README.rst @@ -0,0 +1,12 @@ +widgetDesignerPlugin +#################### + +This is a plugin for Qt Designer. It allows the visualization of custom Governikus widgets. +In order to be loaded, the plugin needs to be placed in the Designers plugin path. + +It can be placed there in the following manner: + +:: + + cd /usr/lib/qt/plugins/designer + ln -s /home/user/AusweisApp2.build/src/widgetDesignerPlugin/libAusweisAppWidgetDesignerPlugin.so diff --git a/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..8f3406b --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "GeneralSettingsWidgetDesignerPlugin.h" + +#include "GeneralSettingsWidget.h" + +using namespace governikus; + + +GeneralSettingsWidgetDesignerPlugin::GeneralSettingsWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* GeneralSettingsWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new GeneralSettingsWidget(pParent); +} + + +QString GeneralSettingsWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString GeneralSettingsWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("GeneralSettingsWidget.h"); +} + + +QString GeneralSettingsWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::GeneralSettingsWidget"); +} + + +QString GeneralSettingsWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString GeneralSettingsWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString GeneralSettingsWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool GeneralSettingsWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool GeneralSettingsWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon GeneralSettingsWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void GeneralSettingsWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.h new file mode 100644 index 0000000..de46725 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/GeneralSettingsWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class GeneralSettingsWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + GeneralSettingsWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..ac7ec70 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "HistoryWidgetDesignerPlugin.h" + +#include "HistoryWidget.h" + +using namespace governikus; + + +HistoryWidgetDesignerPlugin::HistoryWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* HistoryWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new HistoryWidget(pParent); +} + + +QString HistoryWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString HistoryWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("HistoryWidget.h"); +} + + +QString HistoryWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::HistoryWidget"); +} + + +QString HistoryWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString HistoryWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString HistoryWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool HistoryWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool HistoryWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon HistoryWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void HistoryWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.h new file mode 100644 index 0000000..3070e46 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/HistoryWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class HistoryWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + HistoryWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..701fa7c --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PinSettingsWidgetDesignerPlugin.h" + +#include "PinSettingsWidget.h" + +using namespace governikus; + + +PinSettingsWidgetDesignerPlugin::PinSettingsWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* PinSettingsWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new PinSettingsWidget(pParent); +} + + +QString PinSettingsWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString PinSettingsWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("PinSettingsWidget.h"); +} + + +QString PinSettingsWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::PinSettingsWidget"); +} + + +QString PinSettingsWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString PinSettingsWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString PinSettingsWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool PinSettingsWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool PinSettingsWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon PinSettingsWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void PinSettingsWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.h new file mode 100644 index 0000000..134b759 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/PinSettingsWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class PinSettingsWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + PinSettingsWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..90139cf --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderWidgetDesignerPlugin.h" + +#include "ProviderWidget.h" + +using namespace governikus; + + +ProviderWidgetDesignerPlugin::ProviderWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* ProviderWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new ProviderWidget(pParent); +} + + +QString ProviderWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString ProviderWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("ProviderWidget.h"); +} + + +QString ProviderWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::ProviderWidget"); +} + + +QString ProviderWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString ProviderWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString ProviderWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool ProviderWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool ProviderWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon ProviderWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void ProviderWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.h new file mode 100644 index 0000000..7a729b5 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/ProviderWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class ProviderWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + ProviderWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..11127a7 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SelfInformationWidgetDesignerPlugin.h" + +#include "SelfInformationWidget.h" + +using namespace governikus; + + +SelfInformationWidgetDesignerPlugin::SelfInformationWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* SelfInformationWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new SelfInformationWidget(pParent); +} + + +QString SelfInformationWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString SelfInformationWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("SelfInformationWidget.h"); +} + + +QString SelfInformationWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::SelfInformationWidget"); +} + + +QString SelfInformationWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString SelfInformationWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString SelfInformationWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool SelfInformationWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool SelfInformationWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon SelfInformationWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void SelfInformationWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.h new file mode 100644 index 0000000..8ade7df --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/SelfInformationWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class SelfInformationWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + SelfInformationWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.cpp b/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.cpp new file mode 100644 index 0000000..40af8b7 --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.cpp @@ -0,0 +1,92 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "SettingsWidgetDesignerPlugin.h" + +#include "SettingsWidget.h" + +using namespace governikus; + + +SettingsWidgetDesignerPlugin::SettingsWidgetDesignerPlugin(QObject* pParent) + : QObject(pParent) + , mInitialized(false) +{ + +} + + +QWidget* SettingsWidgetDesignerPlugin::createWidget(QWidget* pParent) +{ + return new SettingsWidget(pParent); +} + + +QString SettingsWidgetDesignerPlugin::domXml() const +{ + return QStringLiteral( + "\n" + " \n" + " \n" + "\n"); +} + + +QString SettingsWidgetDesignerPlugin::includeFile() const +{ + return QStringLiteral("SettingsWidget.h"); +} + + +QString SettingsWidgetDesignerPlugin::name() const +{ + return QStringLiteral("governikus::SettingsWidget"); +} + + +QString SettingsWidgetDesignerPlugin::group() const +{ + return QStringLiteral("Governikus"); +} + + +QString SettingsWidgetDesignerPlugin::toolTip() const +{ + return QString(); +} + + +QString SettingsWidgetDesignerPlugin::whatsThis() const +{ + return QString(); +} + + +bool SettingsWidgetDesignerPlugin::isContainer() const +{ + return false; +} + + +bool SettingsWidgetDesignerPlugin::isInitialized() const +{ + return mInitialized; +} + + +QIcon SettingsWidgetDesignerPlugin::icon() const +{ + return QIcon(); +} + + +void SettingsWidgetDesignerPlugin::initialize(QDesignerFormEditorInterface*) +{ + if (mInitialized) + { + return; + } + + mInitialized = true; +} diff --git a/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.h b/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.h new file mode 100644 index 0000000..12398dd --- /dev/null +++ b/src/widgetDesignerPlugin/plugins/SettingsWidgetDesignerPlugin.h @@ -0,0 +1,38 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +namespace governikus +{ + +class SettingsWidgetDesignerPlugin + : public QObject + , public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + + private: + bool mInitialized; + + public: + SettingsWidgetDesignerPlugin(QObject* pParent = nullptr); + + QWidget* createWidget(QWidget* pParent) override; + QString domXml() const override; + QString includeFile() const override; + QString name() const override; + QString group() const override; + QString toolTip() const override; + QString whatsThis() const override; + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + void initialize(QDesignerFormEditorInterface*) override; +}; + +} diff --git a/src/windows.rc b/src/windows.rc new file mode 100644 index 0000000..75cef6b --- /dev/null +++ b/src/windows.rc @@ -0,0 +1,49 @@ +// http://msdn.microsoft.com/en-us/library/aa381058(VS.85).aspx +#include +#include "config.h" + +#define EXECUTABLE PRODUCT ".exe" +#define COPYRIGHT "2014-2017 " VENDOR + +IDR_MAINFRAME ICON "..\\resources\\images\\npa.ico" + +1 VERSIONINFO +FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_TWEAK +PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_TWEAK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP + +BEGIN + BLOCK "StringFileInfo" + + BEGIN + BLOCK "040704B0" // LANG_GERMAN/SUBLANG_DEFAULT, Unicode CP + BEGIN + VALUE "CompanyName", VENDOR + VALUE "FileDescription", PRODUCT + VALUE "FileVersion", VERSION + VALUE "InternalName", PRODUCT + VALUE "LegalCopyright", COPYRIGHT + VALUE "OriginalFilename", EXECUTABLE + VALUE "ProductName", PRODUCT + VALUE "ProductVersion", VERSION + END + + BLOCK "040904B0" // LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP + BEGIN + VALUE "CompanyName", VENDOR + VALUE "FileDescription", PRODUCT + VALUE "FileVersion", VERSION + VALUE "InternalName", PRODUCT + VALUE "LegalCopyright", COPYRIGHT + VALUE "OriginalFilename", EXECUTABLE + VALUE "ProductName", PRODUCT + VALUE "ProductVersion", VERSION + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0407, 0x04B0 + END +END diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1a0935f..8b5d7ca 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,7 +12,12 @@ ENDFUNCTION() FUNCTION(GET_TEST_CMDLINE cmdline testname) - IF(NOT WIN32 AND "${testname}" MATCHES "gui" OR "${testname}" MATCHES "\\.qml") + IF(NOT WIN32 + AND ( + "${testname}" MATCHES "export" + OR "${testname}" MATCHES "widget" + OR "${testname}" MATCHES "\\.qml")) + SET(PLATFORM -platform offscreen) ENDIF() diff --git a/test/fixture/core/http/DIDAuthenticateEAC1 b/test/fixture/core/http/DIDAuthenticateEAC1 index 2709a3e..86826ae 100644 --- a/test/fixture/core/http/DIDAuthenticateEAC1 +++ b/test/fixture/core/http/DIDAuthenticateEAC1 @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:40 GMT - -18a7 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:40 GMT + +18a7 @@ -33,6 +33,6 @@ Date: Fri, 25 Apr 2014 11:19:40 GMT - -0 - + +0 + diff --git a/test/fixture/core/http/DIDAuthenticateEAC2 b/test/fixture/core/http/DIDAuthenticateEAC2 index 2f695d5..051a449 100644 --- a/test/fixture/core/http/DIDAuthenticateEAC2 +++ b/test/fixture/core/http/DIDAuthenticateEAC2 @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:44 GMT - -562 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:44 GMT + +562 @@ -28,6 +28,6 @@ Date: Fri, 25 Apr 2014 11:19:44 GMT - -0 - + +0 + diff --git a/test/fixture/core/http/DIDList b/test/fixture/core/http/DIDList index 6fb2c3d..12dcf41 100644 --- a/test/fixture/core/http/DIDList +++ b/test/fixture/core/http/DIDList @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:40 GMT - -31a +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:40 GMT + +31a @@ -22,6 +22,6 @@ Date: Fri, 25 Apr 2014 11:19:40 GMT
- -0 - + +0 + diff --git a/test/fixture/core/http/Disconnect b/test/fixture/core/http/Disconnect index 66b7720..392f6f5 100644 --- a/test/fixture/core/http/Disconnect +++ b/test/fixture/core/http/Disconnect @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:47 GMT - -1c3 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:47 GMT + +1c3 @@ -15,6 +15,6 @@ Date: Fri, 25 Apr 2014 11:19:47 GMT
- -0 - + +0 + diff --git a/test/fixture/core/http/InitializeFramework b/test/fixture/core/http/InitializeFramework index 46afa1e..1529307 100644 --- a/test/fixture/core/http/InitializeFramework +++ b/test/fixture/core/http/InitializeFramework @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:40 GMT - -192 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:40 GMT + +192 @@ -13,6 +13,6 @@ Date: Fri, 25 Apr 2014 11:19:40 GMT - -0 - + +0 + diff --git a/test/fixture/core/http/StartPaosResponse b/test/fixture/core/http/StartPaosResponse index bc0fc9a..f46b22f 100644 --- a/test/fixture/core/http/StartPaosResponse +++ b/test/fixture/core/http/StartPaosResponse @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:47 GMT - -265 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:47 GMT + +265 @@ -17,6 +17,6 @@ Date: Fri, 25 Apr 2014 11:19:47 GMT - -0 - + +0 + diff --git a/test/fixture/core/http/Transmit b/test/fixture/core/http/Transmit index 109fb71..99ddf71 100644 --- a/test/fixture/core/http/Transmit +++ b/test/fixture/core/http/Transmit @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:45 GMT - -aa0 +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:45 GMT + +aa0 @@ -40,6 +40,6 @@ aa0 - -0 - + +0 + diff --git a/test/fixture/core/http/Transmit2 b/test/fixture/core/http/Transmit2 index 228d5b8..2b51c61 100644 --- a/test/fixture/core/http/Transmit2 +++ b/test/fixture/core/http/Transmit2 @@ -1,10 +1,10 @@ -HTTP/1.1 200 OK -Server: Apache-Coyote/1.1 -Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 -Transfer-Encoding: chunked -Date: Fri, 25 Apr 2014 11:19:45 GMT - -8ef +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/vnd.paos+xml;charset=ISO-8859-1 +Transfer-Encoding: chunked +Date: Fri, 25 Apr 2014 11:19:45 GMT + +8ef @@ -63,6 +63,6 @@ Date: Fri, 25 Apr 2014 11:19:45 GMT - -0 - + +0 + diff --git a/test/fixture/core/invalid.keysize.dsa.der b/test/fixture/core/invalid.keysize.dsa.der index 4593f3d..543fa33 100644 --- a/test/fixture/core/invalid.keysize.dsa.der +++ b/test/fixture/core/invalid.keysize.dsa.der @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICgTCCAj2gAwIBAgIERw6x4TANBglghkgBZQMEAwIFADAQMQ4wDAYDVQQDEwVkdW1teTAeFw0x -NTA3MjAxMTU1NDdaFw0yNTA3MTcxMTU1NDdaMBAxDjAMBgNVBAMTBWR1bW15MIIBuDCCASwGByqG -SM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/ -xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue -wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gg -hdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwky -jMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6A -e1UlZAFMO/7PSSoDgYUAAoGBANcEuwTp9hBuY6TdbrIcMI13peNFNtKnehEgM+y+43EVqbdKAb+p -ic6uXoqtrnb8d5pC4AaR+bGHkuC/7zG3KIZZXfO4tnzuT6dFKL6wy3Elg4w+qFb0kvj6VkpQaL5l -H80tSqug6jr0myczl7qIbKsljhpueh1R5lk843sx9VnooyEwHzAdBgNVHQ4EFgQUO/U1g+2b3I7H -0vSIFCt47k8gJ/gwDQYJYIZIAWUDBAMCBQADLwAwLAIUcXCu2XN6AEKlf2z1ucNU6RPOQLECFE/k +MIICgTCCAj2gAwIBAgIERw6x4TANBglghkgBZQMEAwIFADAQMQ4wDAYDVQQDEwVkdW1teTAeFw0x +NTA3MjAxMTU1NDdaFw0yNTA3MTcxMTU1NDdaMBAxDjAMBgNVBAMTBWR1bW15MIIBuDCCASwGByqG +SM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/ +xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue +wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gg +hdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwky +jMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6A +e1UlZAFMO/7PSSoDgYUAAoGBANcEuwTp9hBuY6TdbrIcMI13peNFNtKnehEgM+y+43EVqbdKAb+p +ic6uXoqtrnb8d5pC4AaR+bGHkuC/7zG3KIZZXfO4tnzuT6dFKL6wy3Elg4w+qFb0kvj6VkpQaL5l +H80tSqug6jr0myczl7qIbKsljhpueh1R5lk843sx9VnooyEwHzAdBgNVHQ4EFgQUO/U1g+2b3I7H +0vSIFCt47k8gJ/gwDQYJYIZIAWUDBAMCBQADLwAwLAIUcXCu2XN6AEKlf2z1ucNU6RPOQLECFE/k 4UO+CvdYpZ8YJERbKXUvrrEe -----END CERTIFICATE----- diff --git a/test/fixture/core/invalid.keysize.ec.der b/test/fixture/core/invalid.keysize.ec.der index adb873d..d55d836 100644 --- a/test/fixture/core/invalid.keysize.ec.der +++ b/test/fixture/core/invalid.keysize.ec.der @@ -1,7 +1,7 @@ -----BEGIN CERTIFICATE----- -MIH0MIG4oAMCAQICBE8s7RowDAYIKoZIzj0EAwIFADAQMQ4wDAYDVQQDEwVkdW1teTAeFw0xNTA3 -MjAxMTUyMTBaFw0yNTA3MTcxMTUyMTBaMBAxDjAMBgNVBAMTBWR1bW15MDYwEAYHKoZIzj0CAQYF -K4EEABwDIgAEYy6nYlOsAcHz2e6K9Or3/WuKwXtC2eckSKvHJHOL4l2jITAfMB0GA1UdDgQWBBRZ -+MycZ6qNwG3iiGkBLEZk5STBpzAMBggqhkjOPQQDAgUAAykAMCYCEQCzfIVbvEvXSke3V/kxquT5 +MIH0MIG4oAMCAQICBE8s7RowDAYIKoZIzj0EAwIFADAQMQ4wDAYDVQQDEwVkdW1teTAeFw0xNTA3 +MjAxMTUyMTBaFw0yNTA3MTcxMTUyMTBaMBAxDjAMBgNVBAMTBWR1bW15MDYwEAYHKoZIzj0CAQYF +K4EEABwDIgAEYy6nYlOsAcHz2e6K9Or3/WuKwXtC2eckSKvHJHOL4l2jITAfMB0GA1UdDgQWBBRZ ++MycZ6qNwG3iiGkBLEZk5STBpzAMBggqhkjOPQQDAgUAAykAMCYCEQCzfIVbvEvXSke3V/kxquT5 AhEAnWEaT1WG4W8xqgF8m9awsg== -----END CERTIFICATE----- diff --git a/test/fixture/core/invalid.keysize.rsa.der b/test/fixture/core/invalid.keysize.rsa.der index 4ebbcbe..9e1bd72 100644 --- a/test/fixture/core/invalid.keysize.rsa.der +++ b/test/fixture/core/invalid.keysize.rsa.der @@ -1,10 +1,10 @@ -----BEGIN CERTIFICATE----- -MIIBxDCCAS2gAwIBAgIERAWfFDANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwpkdW1teSBDPURF -MB4XDTE1MDcyMDExMjAyMFoXDTI1MDcxNzExMjAyMFowFTETMBEGA1UEAxMKZHVtbXkgQz1ERTCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAiC7S34NULxMPEXJolj3q1tBnGM+ij04c319qJL3t -cGjuLVTt6BcnbaQ1Ex28IFl87nCMaI6gL6iqxbP+lP/WcNInz9pWi6Yqoe9qyLRX+gyNSQ5CfBC6 -DTo5IBuNWI2tpIjwZ/WgOi1bmQiAB7Ux6YrpsmaFAFAwTSBWzrQvPj8CAwEAAaMhMB8wHQYDVR0O -BBYEFDLPeedrhTiadxcT/y1t7EVXIkPEMA0GCSqGSIb3DQEBCwUAA4GBAEET+KEb4hlugVtISOde -LMh4LXftz+tWXYu2RhxCkGzkOncL+7AXh3UrdWT9Lk1dm4FHvH7SbbK2fXAUSJMNA5zSdvo33/BG +MIIBxDCCAS2gAwIBAgIERAWfFDANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwpkdW1teSBDPURF +MB4XDTE1MDcyMDExMjAyMFoXDTI1MDcxNzExMjAyMFowFTETMBEGA1UEAxMKZHVtbXkgQz1ERTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAiC7S34NULxMPEXJolj3q1tBnGM+ij04c319qJL3t +cGjuLVTt6BcnbaQ1Ex28IFl87nCMaI6gL6iqxbP+lP/WcNInz9pWi6Yqoe9qyLRX+gyNSQ5CfBC6 +DTo5IBuNWI2tpIjwZ/WgOi1bmQiAB7Ux6YrpsmaFAFAwTSBWzrQvPj8CAwEAAaMhMB8wHQYDVR0O +BBYEFDLPeedrhTiadxcT/y1t7EVXIkPEMA0GCSqGSIb3DQEBCwUAA4GBAEET+KEb4hlugVtISOde +LMh4LXftz+tWXYu2RhxCkGzkOncL+7AXh3UrdWT9Lk1dm4FHvH7SbbK2fXAUSJMNA5zSdvo33/BG eoS3B57MUZ4FFoF1cDRghW0e0sEbuUGVTW2MrI345c7ZhANni/nIw9UiyymmCJG7j3wQPE7sy3zS -----END CERTIFICATE----- diff --git a/test/fixture/fixture.qrc b/test/fixture/fixture.qrc index 193348a..59331c7 100644 --- a/test/fixture/fixture.qrc +++ b/test/fixture/fixture.qrc @@ -56,6 +56,7 @@ core/http/Transmit core/http/Transmit2 core/network/CERT_TLS_ESERVICE_1.der + updatable-files/reader/img_ACS_ACR1252U.png tctoken/ok.xml tctoken/broken.xml tctoken/withoutCommunicationErrorAddress.xml diff --git a/test/fixture/paos/DIDAuthenticateEAC1.xml b/test/fixture/paos/DIDAuthenticateEAC1.xml index 54868f9..94a28dd 100644 --- a/test/fixture/paos/DIDAuthenticateEAC1.xml +++ b/test/fixture/paos/DIDAuthenticateEAC1.xml @@ -1,29 +1,29 @@ - - - - - - - -4549445F4946445F434F4E544558545F42415345 -REINER SCT cyberJack RFID komfort USB 52 -0 -4549445F49534F5F32343732375F42415345 -37343139303333612D616163352D343331352D386464392D656166393664636661653361 - - -PIN - -7F218201487F4E8201005F2901004210444544566549444450535430303033337F494F060A04007F00070202020203864104924587075F03DAC4904F6254C5572ED03C172E144BB1B662C1E57B4B8096433EA0DF772DF021740EA7E72CA85A85A21E1606A55FE198BE1D2E4B13C9E469B3C55F200E444544454D4F44455630303032397F4C12060904007F0007030102025305000513FF875F25060103010102075F2406010301020206655E732D060904007F000703010301802012CA9D0A51DF9297EABA7EBE9AB49DF2F4CF83E0DBB02772EFAD89C8AD75FCCD732D060904007F0007030103028020CB1E1940159F11DC96845B87C23B86F9BAA755A789A914BBD5B8FA9784019D1C5F37400928ED768F5FDC26954D305DB93AE3CBAA2624BB8EE82D88CBD4AB937CAB3797115C2871C08B5C9500B0125868FDA65FF260E9647D9F6B2195CD9B6311B9A805 -7F2181E77F4E81A05F290100420E44455445535465494430303030347F494F060A04007F0007020202020386410406A7B04521DD3C8521FF29F46B4CF5DE7D77160ACBE5D769AA29423E744C35BFA0D68A106593850E17DA5B0343BA6B216C05E3116F41B919807F8F5D5AD1A6F65F2010444544566549444450535430303033337F4C12060904007F0007030102025305400513FF875F25060103010002035F24060104000102015F374033982B62342B185B1CEC876549520E6DBD5B538D4041E4224EBA94C08199EB56846C17484CE1CFB2236184651149D1D233F864BB7485F7E5CB5E2707BE082F1D -7F218201B67F4E82016E5F290100420E44455445535465494430303030327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410474FF63AB838C73C303AC003DFEE95CF8BF55F91E8FEBCB7395D942036E47CF1845EC786EC95BB453AAC288AD023B6067913CF9B63F908F49304E5CFC8B3050DD8701015F200E44455445535465494430303030347F4C12060904007F0007030102025305FC0F13FFFF5F25060102000501015F24060105000501015F37405C035A0611B6C58F0B5261FDD009DECAB7DC7A79482D5248CCA119059B7D82B2157CF0C4A499BCF441EFDD35E294A58C0AF19A34A0762159533285ACF170A505 -7F218201B67F4E82016E5F290100420E44455445535465494430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104096EB58BFD86252238EC2652185C43C3A56C320681A21E37A8E69DDC387C0C5F5513856EFE2FDC656E604893212E29449B365E304605AC5413E75BE31E641F128701015F200E44455445535465494430303030327F4C12060904007F0007030102025305FE0F01FFFF5F25060100000902015F24060103000902015F3740141120A0FDFC011A52F3F72B387A3DC7ACA88B4868D5AE9741780B6FF8A0B49E5F55169A2D298EF5CF95935DCA0C3DF3E9D42DC45F74F2066317154961E6C746 -3082022F060A04007F00070301030101A12D0C2B446575747363686520506F737420436F6D2C204765736368C3A466747366656C64205369676E7472757374A2191317687474703A2F2F7777772E7369676E74727573742E6465A3080C06626F73204B47A429132768747470733A2F2F6465762D64656D6F2E676F7665726E696B75732D6569642E64653A38343433A58201580C820154416E736368726966743A0D0A6272656D656E206F6E6C696E6520736572766963657320476D6248202620436F2E204B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E0D0A0D0A452D4D61696C2D416472657373653A0D0A686240626F732D6272656D656E2E64650D0A0D0A5A7765636B20646573204175736C657365766F7267616E67733A0D0A44656D6F6E7374726174696F6E20646573206549442D536572766963650D0A0D0A5A757374C3A46E6469676520446174656E73636875747A61756673696368743A0D0A446965204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656EA74631440420761099A58BFD5334E93A7A78E4F18B760FFCF8F513A4730C8AE9B59BCC0FE8C90420CEABB7E427174BCFFFB3499BF925A5D4A7887AD4FCF7747867912DEBB58D684C -7F4C12060904007F00070301020253050001137C05 -7F4C12060904007F00070301020253050004008302 -67447315060904007F000703010401530831393932313230367315060904007F000703010402530832303133313230367314060904007F000703010403530702760400110000 -this is a test for TransactionInfo - - - - + + + + + + + +4549445F4946445F434F4E544558545F42415345 +REINER SCT cyberJack RFID komfort USB 52 +0 +4549445F49534F5F32343732375F42415345 +37343139303333612D616163352D343331352D386464392D656166393664636661653361 + + +PIN + +7F218201487F4E8201005F2901004210444544566549444450535430303033337F494F060A04007F00070202020203864104924587075F03DAC4904F6254C5572ED03C172E144BB1B662C1E57B4B8096433EA0DF772DF021740EA7E72CA85A85A21E1606A55FE198BE1D2E4B13C9E469B3C55F200E444544454D4F44455630303032397F4C12060904007F0007030102025305000513FF875F25060103010102075F2406010301020206655E732D060904007F000703010301802012CA9D0A51DF9297EABA7EBE9AB49DF2F4CF83E0DBB02772EFAD89C8AD75FCCD732D060904007F0007030103028020CB1E1940159F11DC96845B87C23B86F9BAA755A789A914BBD5B8FA9784019D1C5F37400928ED768F5FDC26954D305DB93AE3CBAA2624BB8EE82D88CBD4AB937CAB3797115C2871C08B5C9500B0125868FDA65FF260E9647D9F6B2195CD9B6311B9A805 +7F2181E77F4E81A05F290100420E44455445535465494430303030347F494F060A04007F0007020202020386410406A7B04521DD3C8521FF29F46B4CF5DE7D77160ACBE5D769AA29423E744C35BFA0D68A106593850E17DA5B0343BA6B216C05E3116F41B919807F8F5D5AD1A6F65F2010444544566549444450535430303033337F4C12060904007F0007030102025305400513FF875F25060103010002035F24060104000102015F374033982B62342B185B1CEC876549520E6DBD5B538D4041E4224EBA94C08199EB56846C17484CE1CFB2236184651149D1D233F864BB7485F7E5CB5E2707BE082F1D +7F218201B67F4E82016E5F290100420E44455445535465494430303030327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410474FF63AB838C73C303AC003DFEE95CF8BF55F91E8FEBCB7395D942036E47CF1845EC786EC95BB453AAC288AD023B6067913CF9B63F908F49304E5CFC8B3050DD8701015F200E44455445535465494430303030347F4C12060904007F0007030102025305FC0F13FFFF5F25060102000501015F24060105000501015F37405C035A0611B6C58F0B5261FDD009DECAB7DC7A79482D5248CCA119059B7D82B2157CF0C4A499BCF441EFDD35E294A58C0AF19A34A0762159533285ACF170A505 +7F218201B67F4E82016E5F290100420E44455445535465494430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104096EB58BFD86252238EC2652185C43C3A56C320681A21E37A8E69DDC387C0C5F5513856EFE2FDC656E604893212E29449B365E304605AC5413E75BE31E641F128701015F200E44455445535465494430303030327F4C12060904007F0007030102025305FE0F01FFFF5F25060100000902015F24060103000902015F3740141120A0FDFC011A52F3F72B387A3DC7ACA88B4868D5AE9741780B6FF8A0B49E5F55169A2D298EF5CF95935DCA0C3DF3E9D42DC45F74F2066317154961E6C746 +3082022F060A04007F00070301030101A12D0C2B446575747363686520506F737420436F6D2C204765736368C3A466747366656C64205369676E7472757374A2191317687474703A2F2F7777772E7369676E74727573742E6465A3080C06626F73204B47A429132768747470733A2F2F6465762D64656D6F2E676F7665726E696B75732D6569642E64653A38343433A58201580C820154416E736368726966743A0D0A6272656D656E206F6E6C696E6520736572766963657320476D6248202620436F2E204B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E0D0A0D0A452D4D61696C2D416472657373653A0D0A686240626F732D6272656D656E2E64650D0A0D0A5A7765636B20646573204175736C657365766F7267616E67733A0D0A44656D6F6E7374726174696F6E20646573206549442D536572766963650D0A0D0A5A757374C3A46E6469676520446174656E73636875747A61756673696368743A0D0A446965204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656EA74631440420761099A58BFD5334E93A7A78E4F18B760FFCF8F513A4730C8AE9B59BCC0FE8C90420CEABB7E427174BCFFFB3499BF925A5D4A7887AD4FCF7747867912DEBB58D684C +7F4C12060904007F00070301020253050001137C05 +7F4C12060904007F00070301020253050004008302 +67447315060904007F000703010401530831393932313230367315060904007F000703010402530832303133313230367314060904007F000703010403530702760400110000 +this is a test for TransactionInfo + + + + diff --git a/test/fixture/paos/DIDAuthenticateEAC2.xml b/test/fixture/paos/DIDAuthenticateEAC2.xml index aad5e33..f5c4ea3 100644 --- a/test/fixture/paos/DIDAuthenticateEAC2.xml +++ b/test/fixture/paos/DIDAuthenticateEAC2.xml @@ -1,23 +1,23 @@ - - - - - - - -4549445F4946445F434F4E544558545F42415345 -REINER SCT cyberJack RFID komfort USB 52 -0 -4549445F49534F5F32343732375F42415345 -34366364653038392D623031322D346664372D386233362D343664346232393537636236 - - -PIN - - -046E35D82A4F370F9B4C7B6415B7FF936B2FE2DAFD8E008037E8B0464918FDACD33AE730BABAE05C45E9567F010A4A40CA3CF04409C2EEBAC0E38B9E36975E2AE1 -2DE1E928C7E6C40F3389BF1973214EAB082F816EB42B6A3C3B36EF4BDD61A2594C7814DDBF7D5A32ADE60188BFCA12BBF7C2FB8DF93A4FE042121015F1FAC7EA - - - - + + + + + + + +4549445F4946445F434F4E544558545F42415345 +REINER SCT cyberJack RFID komfort USB 52 +0 +4549445F49534F5F32343732375F42415345 +34366364653038392D623031322D346664372D386233362D343664346232393537636236 + + +PIN + + +046E35D82A4F370F9B4C7B6415B7FF936B2FE2DAFD8E008037E8B0464918FDACD33AE730BABAE05C45E9567F010A4A40CA3CF04409C2EEBAC0E38B9E36975E2AE1 +2DE1E928C7E6C40F3389BF1973214EAB082F816EB42B6A3C3B36EF4BDD61A2594C7814DDBF7D5A32ADE60188BFCA12BBF7C2FB8DF93A4FE042121015F1FAC7EA + + + + diff --git a/test/fixture/paos/DIDList.xml b/test/fixture/paos/DIDList.xml index cecdbfd..6addf68 100644 --- a/test/fixture/paos/DIDList.xml +++ b/test/fixture/paos/DIDList.xml @@ -1,17 +1,17 @@ - - - - - - - -4549445F4946445F434F4E544558545F42415345 -REINER SCT cyberJack RFID komfort USB 52 -0 -4549445F49534F5F32343732375F42415345 -37343139303333612D616163352D343331352D386464392D656166393664636661653361 - - - - - + + + + + + + +4549445F4946445F434F4E544558545F42415345 +REINER SCT cyberJack RFID komfort USB 52 +0 +4549445F49534F5F32343732375F42415345 +37343139303333612D616163352D343331352D386464392D656166393664636661653361 + + + + + diff --git a/test/fixture/paos/Disconnect.xml b/test/fixture/paos/Disconnect.xml index ff37a56..ab17b09 100644 --- a/test/fixture/paos/Disconnect.xml +++ b/test/fixture/paos/Disconnect.xml @@ -1,10 +1,10 @@ - - - - - - -34366364653038392D623031322D346664372D386233362D343664346232393537636236 - - - + + + + + + +34366364653038392D623031322D346664372D386233362D343664346232393537636236 + + + diff --git a/test/fixture/paos/InitializeFramework.xml b/test/fixture/paos/InitializeFramework.xml index 64add9d..1d6fe88 100644 --- a/test/fixture/paos/InitializeFramework.xml +++ b/test/fixture/paos/InitializeFramework.xml @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/test/fixture/paos/InitializeFramework_withMessageID.xml b/test/fixture/paos/InitializeFramework_withMessageID.xml index 8ea3d0b..6625f89 100644 --- a/test/fixture/paos/InitializeFramework_withMessageID.xml +++ b/test/fixture/paos/InitializeFramework_withMessageID.xml @@ -1,28 +1,28 @@ - - - - urn:liberty:2006-08 - - http://www.projectliberty.org/2006/01/role/paos - - - - urn:uuid:c0f05ac0-1a67-4a0b-acbd-78309fcdb002 - - http://www.bsi.bund.de/ecard/api/1.0/PAOS/GetNextCommand - - - - - + + + + urn:liberty:2006-08 + + http://www.projectliberty.org/2006/01/role/paos + + + + urn:uuid:c0f05ac0-1a67-4a0b-acbd-78309fcdb002 + + http://www.bsi.bund.de/ecard/api/1.0/PAOS/GetNextCommand + + + + + \ No newline at end of file diff --git a/test/fixture/paos/StartPAOSResponse1.xml b/test/fixture/paos/StartPAOSResponse1.xml index 459d43e..49510fb 100644 --- a/test/fixture/paos/StartPAOSResponse1.xml +++ b/test/fixture/paos/StartPAOSResponse1.xml @@ -1,12 +1,12 @@ - - - - - - - -http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok - - - - + + + + + + + +http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok + + + + diff --git a/test/fixture/paos/Transmit.xml b/test/fixture/paos/Transmit.xml index 15dba3d..01c722a 100644 --- a/test/fixture/paos/Transmit.xml +++ b/test/fixture/paos/Transmit.xml @@ -1,35 +1,35 @@ - - - - - - -34366364653038392D623031322D346664372D386233362D343664346232393537636236 - -0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00 - - -8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00 - - -0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00 -9000 - - -0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000 -9001 - - -8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00 - - -0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00 -9002 - - -0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000 -9003 - - - - + + + + + + +34366364653038392D623031322D346664372D386233362D343664346232393537636236 + +0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00 + + +8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00 + + +0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00 +9000 + + +0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000 +9001 + + +8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00 + + +0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00 +9002 + + +0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000 +9003 + + + + diff --git a/test/fixture/paos/Transmit3.xml b/test/fixture/paos/Transmit3.xml index fd8e485..654ec5e 100644 --- a/test/fixture/paos/Transmit3.xml +++ b/test/fixture/paos/Transmit3.xml @@ -1,37 +1,37 @@ - - - - urn:uuid:015c4aba-4b51-463d-95e4-df127c94a5ce - urn:uuid:04b2b166-77ad-42c9-bb7d-0c5e9798d337 - - - -34366364653038392D623031322D346664372D386233362D343664346232393537636236 - -0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00 - - -8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00 - - -0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00 -9000 - - -0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000 -9001 - - -8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00 - - -0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00 -9002 - - -0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000 -9003 - - - - + + + + urn:uuid:015c4aba-4b51-463d-95e4-df127c94a5ce + urn:uuid:04b2b166-77ad-42c9-bb7d-0c5e9798d337 + + + +34366364653038392D623031322D346664372D386233362D343664346232393537636236 + +0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00 + + +8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00 + + +0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00 +9000 + + +0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000 +9001 + + +8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00 + + +0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00 +9002 + + +0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000 +9003 + + + + diff --git a/test/fixture/updatable-files/reader/img_ACS_ACR1252U.png b/test/fixture/updatable-files/reader/img_ACS_ACR1252U.png new file mode 100644 index 0000000..0ddf2ba --- /dev/null +++ b/test/fixture/updatable-files/reader/img_ACS_ACR1252U.png @@ -0,0 +1 @@ +i diff --git a/test/helper/CMakeLists.txt b/test/helper/CMakeLists.txt index c6f70a0..a3944cf 100644 --- a/test/helper/CMakeLists.txt +++ b/test/helper/CMakeLists.txt @@ -1,13 +1,9 @@ ADD_PLATFORM_LIBRARY(AusweisAppTestHelper) -TARGET_INCLUDE_DIRECTORIES(AusweisAppTestHelper SYSTEM PUBLIC ${PCSC_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) -# 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_INCLUDE_DIRECTORIES(AusweisAppTestHelper SYSTEM PUBLIC ${PCSC_INCLUDE_DIRS}) +TARGET_LINK_LIBRARIES(AusweisAppTestHelper Qt5::Network Qt5::Xml Qt5::Test AusweisAppActivation AusweisAppCard AusweisAppCardDrivers AusweisAppCardRemote AusweisAppNetwork AusweisAppCore AusweisAppWebSocket) 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 c87f081..2e31305 100644 --- a/test/helper/CliHelper.cpp +++ b/test/helper/CliHelper.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CliHelper.h" @@ -23,20 +23,20 @@ CliHelper::CliHelper(QObject* pParent) connect(&mTimer, &QTimer::timeout, &mLoop, &QEventLoop::quit); connect(this, &QProcess::readyRead, this, &CliHelper::storeOutput); - QString path = QCoreApplication::applicationDirPath() + "/../../src/"; - QString app = path + "AusweisApp2"; + QString path = QCoreApplication::applicationDirPath() + QStringLiteral("/../../src/"); + QString app = path + QStringLiteral("AusweisApp2"); QStringList args; - args << "--ui" << "cli"; - args << "--port" << "0"; + args << QStringLiteral("--ui") << QStringLiteral("cli"); + args << QStringLiteral("--port") << QStringLiteral("0"); #ifdef Q_OS_WIN app += ".exe"; #else - args << "-platform" << "offscreen"; + args << QStringLiteral("-platform") << QStringLiteral("offscreen"); #endif QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("QT_LOGGING_TO_CONSOLE", "1"); + env.insert(QStringLiteral("QT_LOGGING_TO_CONSOLE"), QStringLiteral("1")); setProcessEnvironment(env); setProgram(app); setArguments(args); @@ -108,7 +108,7 @@ void CliHelper::run() start(); if (waitForStarted(TIMEOUT)) { - waitForOutput("Try to load UI plugin: \"UIPlugInCli\""); + waitForOutput(QStringLiteral("Try to load UI plugin: \"UIPlugInCli\"")); } QCOMPARE(state(), QProcess::Running); @@ -126,8 +126,8 @@ void CliHelper::stop() void CliHelper::waitForPong() { send("ping"); - waitForOutput("^stdinput .*: \"ping\""); - waitForOutput("Pong!"); + waitForOutput(QStringLiteral("^stdinput .*: \"ping\"")); + waitForOutput(QStringLiteral("Pong!")); } @@ -137,7 +137,7 @@ quint16 CliHelper::getServerPort() { send("port"); QRegularExpressionMatch matcher; - waitForOutput("^cli .*: Port: ([0-9]{1,5})$", &matcher); + waitForOutput(QStringLiteral("^cli .*: Port: ([0-9]{1,5})$"), &matcher); if (matcher.hasMatch() && !matcher.captured(1).isNull()) { diff --git a/test/helper/CliHelper.h b/test/helper/CliHelper.h index 162d228..65177ac 100644 --- a/test/helper/CliHelper.h +++ b/test/helper/CliHelper.h @@ -1,7 +1,7 @@ /*! * \brief Helper to test app via CliPlugIn. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/test/helper/MockActivationContext.cpp b/test/helper/MockActivationContext.cpp index 3f5ebbe..72b0707 100644 --- a/test/helper/MockActivationContext.cpp +++ b/test/helper/MockActivationContext.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MockActivationContext.h" diff --git a/test/helper/MockActivationContext.h b/test/helper/MockActivationContext.h index f1c03f9..98d368b 100644 --- a/test/helper/MockActivationContext.h +++ b/test/helper/MockActivationContext.h @@ -1,10 +1,13 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \brief Mocked ActivationContext for unit tests. + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "ActivationContext.h" #include "ActivationHandler.h" @@ -23,7 +26,7 @@ class MockActivationContext public: MockActivationContext(bool pProcessing = false, bool pAlreadyActive = false, bool pErroPage = false, bool pRedirect = false, const QString& pSendError = QString()); - virtual ~MockActivationContext(); + virtual ~MockActivationContext() override; virtual QUrl getActivationURL() const override diff --git a/test/helper/MockCard.cpp b/test/helper/MockCard.cpp index 83e2986..b166c50 100644 --- a/test/helper/MockCard.cpp +++ b/test/helper/MockCard.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MockCard.h" diff --git a/test/helper/MockCard.h b/test/helper/MockCard.h index 377ab0f..c473b40 100644 --- a/test/helper/MockCard.h +++ b/test/helper/MockCard.h @@ -1,9 +1,7 @@ /*! - * MockCard.h - * * \brief Card mock for tests * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -47,7 +45,7 @@ class MockCard public: MockCard(const MockCardConfig& pCardConfig); - virtual ~MockCard(); + virtual ~MockCard() override; CardReturnCode connect() override; CardReturnCode disconnect() override; diff --git a/test/helper/MockDataChannel.cpp b/test/helper/MockDataChannel.cpp index 29e05d4..1dfdbcf 100644 --- a/test/helper/MockDataChannel.cpp +++ b/test/helper/MockDataChannel.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #include "MockDataChannel.h" @@ -8,6 +8,7 @@ using namespace governikus; MockDataChannel::MockDataChannel() + : mReceivedDataBlocks() { } @@ -37,5 +38,13 @@ void MockDataChannel::send(const QByteArray& pDataBlock) void MockDataChannel::onReceived(const QByteArray& pDataBlock) { + mReceivedDataBlocks += pDataBlock; + Q_EMIT fireReceived(pDataBlock); } + + +const QVector& MockDataChannel::getReceivedDataBlocks() const +{ + return mReceivedDataBlocks; +} diff --git a/test/helper/MockDataChannel.h b/test/helper/MockDataChannel.h index d2b0ea1..6432052 100644 --- a/test/helper/MockDataChannel.h +++ b/test/helper/MockDataChannel.h @@ -1,13 +1,16 @@ /*! * \brief Data channel mock for tests. * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include "DataChannel.h" +#include +#include + namespace governikus { @@ -16,14 +19,19 @@ class MockDataChannel { Q_OBJECT + private: + QVector mReceivedDataBlocks; + public: MockDataChannel(); - virtual ~MockDataChannel(); + virtual ~MockDataChannel() override; virtual void send(const QByteArray& pDataBlock) override; virtual void close() override; void closeAbnormal(); + const QVector& getReceivedDataBlocks() const; + public Q_SLOTS: void onReceived(const QByteArray& pDataBlock); diff --git a/test/helper/MockDownloader.cpp b/test/helper/MockDownloader.cpp new file mode 100644 index 0000000..d963845 --- /dev/null +++ b/test/helper/MockDownloader.cpp @@ -0,0 +1,73 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MockDownloader.h" + +using namespace governikus; + + +MockDownloader::MockDownloader(GlobalStatus::Code pErrorCode) + : mErrorCode(pErrorCode) + , mDate(QDate(2017, 7, 15)) + , mTime(QTime(11, 57, 21)) + , mTestData() +{ + +} + + +QDateTime MockDownloader::getTimeStamp() +{ + return QDateTime(mDate, mTime); +} + + +QString MockDownloader::getTimeStampString() +{ + const QString dateFormat = QStringLiteral("yyyyMMddhhmmss"); + return getTimeStamp().toString(dateFormat); +} + + +QByteArray MockDownloader::getTestData(const QUrl& pUrl) +{ + return mTestData.value(pUrl); +} + + +void MockDownloader::download(const QUrl& pUpdateUrl) +{ + if (mErrorCode != GlobalStatus::Code::No_Error) + { + Q_EMIT fireDownloadFailed(pUpdateUrl, mErrorCode); + } + else if (!mTestData.contains(pUpdateUrl)) + { + Q_EMIT fireDownloadFailed(pUpdateUrl, GlobalStatus::Code::Downloader_File_Not_Found); + } + else + { + Q_EMIT fireDownloadSuccess(pUpdateUrl, getTimeStamp(), getTestData(pUpdateUrl)); + } +} + + +void MockDownloader::downloadIfNew(const QUrl& pUpdateUrl, + const QDateTime& pCurrentTimestamp) +{ + Q_UNUSED(pCurrentTimestamp); + download(pUpdateUrl); +} + + +void MockDownloader::setTestData(QUrl& pUrl, const QByteArray& pData) +{ + mTestData[pUrl] = pData; +} + + +void MockDownloader::setError(GlobalStatus::Code pErrorCode) +{ + mErrorCode = pErrorCode; +} diff --git a/test/helper/MockDownloader.h b/test/helper/MockDownloader.h new file mode 100644 index 0000000..7958d1f --- /dev/null +++ b/test/helper/MockDownloader.h @@ -0,0 +1,42 @@ +/*! + * \brief MockDownloader of class Downloader, part of \ref Updater and \ref UpdatableFile tests + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#pragma once + +#include "Downloader.h" +#include "GlobalStatus.h" + +#include + +namespace governikus +{ +class MockDownloader + : public Downloader +{ + Q_OBJECT + + private: + GlobalStatus::Code mErrorCode; + QDate mDate; + QTime mTime; + QMap mTestData; + + public: + MockDownloader(GlobalStatus::Code pErrorCode = GlobalStatus::Code::No_Error); + virtual ~MockDownloader() override = default; + + QDateTime getTimeStamp(); + QString getTimeStampString(); + void setTestData(QUrl& pUrl, const QByteArray& pData); + QByteArray getTestData(const QUrl& pUrl); + void setError(GlobalStatus::Code pErrorCode); + void download(const QUrl& pUpdateUrl) override; + void downloadIfNew(const QUrl& pUpdateUrl, + const QDateTime& pCurrentTimestamp) override; +}; + +} diff --git a/test/helper/MockHttpServer.cpp b/test/helper/MockHttpServer.cpp index 3d24478..8311347 100644 --- a/test/helper/MockHttpServer.cpp +++ b/test/helper/MockHttpServer.cpp @@ -1,10 +1,10 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MockHttpServer.h" -#include "EnvHolder.h" +#include "Env.h" using namespace governikus; @@ -13,7 +13,7 @@ MockHttpServer::MockHttpServer() , mServer() { HttpServer::cPort = 0; - mServer = EnvHolder::shared(); + mServer = Env::getShared(); QVERIFY(mServer); QVERIFY(mServer->isListening()); connect(mServer.data(), &HttpServer::fireNewHttpRequest, this, &MockHttpServer::onNewHttpRequest); diff --git a/test/helper/MockHttpServer.h b/test/helper/MockHttpServer.h index 81757c8..d5358c9 100644 --- a/test/helper/MockHttpServer.h +++ b/test/helper/MockHttpServer.h @@ -1,7 +1,7 @@ /*! * \brief Provide a HTTP-Server for tests * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/test/helper/MockIfdStatus.cpp b/test/helper/MockIfdStatus.cpp new file mode 100644 index 0000000..1121ff1 --- /dev/null +++ b/test/helper/MockIfdStatus.cpp @@ -0,0 +1,62 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MockIfdStatus.h" + + +using namespace governikus; + + +namespace +{ +VALUE_NAME(MSG_TYPE, "msg") +VALUE_NAME(CONTEXT_HANDLE, "ContextHandle") +VALUE_NAME(SLOT_NAME, "SlotName") +VALUE_NAME(PIN_CAPABILITIES, "PINCapabilities") +VALUE_NAME(MAX_APDU_LENGTH, "MaxAPDULength") +VALUE_NAME(CONNECTED_READER, "ConnectedReader") +VALUE_NAME(CARD_AVAILABLE, "CardAvailable") +VALUE_NAME(EF_ATR, "EFATR") +VALUE_NAME(EF_DIR, "EFDIR") +} + + +MockIfdStatus::MockIfdStatus(const QString& pSlotName, + const PaceCapabilities& pPaceCapabilities, + int pMaxApduLength, + bool pConnected, + bool pCardAvailable) + : IfdStatus(createJsonObject( + pSlotName, + pPaceCapabilities, + pMaxApduLength, + pConnected, + pCardAvailable)) +{ +} + + +MockIfdStatus::~MockIfdStatus() +{ +} + + +QJsonObject MockIfdStatus::createJsonObject(const QString& pSlotName, + const PaceCapabilities& pPaceCapabilities, + int pMaxApduLength, + bool pConnectedReader, + bool pCardAvailable) +{ + QJsonObject result; + result[MSG_TYPE()] = getEnumName(RemoteCardMessageType::IFDStatus); + result[CONTEXT_HANDLE()] = QStringLiteral("contextHandle"); + result[SLOT_NAME()] = pSlotName; + result[PIN_CAPABILITIES()] = pPaceCapabilities.toJson(); + result[MAX_APDU_LENGTH()] = pMaxApduLength; + result[CONNECTED_READER()] = pConnectedReader; + result[CARD_AVAILABLE()] = pCardAvailable; + result[EF_ATR()] = QJsonValue(); + result[EF_DIR()] = QJsonValue(); + return result; +} diff --git a/test/helper/MockIfdStatus.h b/test/helper/MockIfdStatus.h new file mode 100644 index 0000000..36ddf3f --- /dev/null +++ b/test/helper/MockIfdStatus.h @@ -0,0 +1,37 @@ +/*! + * \brief IfdStatus mock for tests + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "messages/IfdStatus.h" + + +namespace governikus +{ + +class MockIfdStatus + : public IfdStatus +{ + public: + MockIfdStatus(const QString& pSlotName, + const PaceCapabilities& pPaceCapabilities, + int pMaxApduLength, + bool pConnected, + bool pCardAvailable = false); + ~MockIfdStatus(); + + private: + QJsonObject createJsonObject(const QString& pSlotName, + const PaceCapabilities& pPaceCapabilities, + int pMaxApduLength, + bool pConnectedReader, + bool pCardAvailable); + + +}; + +} /* namespace governikus */ diff --git a/test/helper/MockNetworkManager.cpp b/test/helper/MockNetworkManager.cpp index 8c31e13..8cc4996 100644 --- a/test/helper/MockNetworkManager.cpp +++ b/test/helper/MockNetworkManager.cpp @@ -1,9 +1,11 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "MockNetworkManager.h" +#include "HttpStatusCode.h" + #include using namespace governikus; @@ -12,6 +14,7 @@ using namespace governikus; MockNetworkManager::MockNetworkManager() : mNextReply(nullptr) , mLastReply(nullptr) + , mLastRequest(nullptr) { } @@ -34,15 +37,22 @@ MockNetworkReply* MockNetworkManager::getReply(const QNetworkRequest& pRequest) if (!mFilename.isNull()) { QFile msgFile(mFilename); - msgFile.open(QIODevice::ReadOnly | QIODevice::Text); - content = msgFile.readAll(); - msgFile.close(); - } + if (msgFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + content = msgFile.readAll(); + msgFile.close(); + } - mLastReply = new MockNetworkReply(content); + mLastReply = new MockNetworkReply(content, HttpStatusCode::OK); + } + else + { + mLastReply = new MockNetworkReply(); + } } mLastReply->setRequest(pRequest); + Q_EMIT fireReply(); return mLastReply; } @@ -52,16 +62,27 @@ QNetworkReply* MockNetworkManager::get(QNetworkRequest& pRequest, int pTimeoutIn Q_UNUSED(pRequest); Q_UNUSED(pTimeoutInMilliSeconds); + mLastRequest = &pRequest; + return getReply(pRequest); } -QNetworkReply* MockNetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) +QNetworkReply* MockNetworkManager::paos(QNetworkRequest& pRequest, const QByteArray& pNamespace, const QByteArray& pData, bool pUsePsk, int pTimeoutInMilliSeconds) { Q_UNUSED(pRequest); + Q_UNUSED(pNamespace); Q_UNUSED(pData); Q_UNUSED(pUsePsk); Q_UNUSED(pTimeoutInMilliSeconds); return getReply(pRequest); } + + +bool MockNetworkManager::checkUpdateServerCertificate(const QNetworkReply& pReply) +{ + Q_UNUSED(pReply); + + return true; +} diff --git a/test/helper/MockNetworkManager.h b/test/helper/MockNetworkManager.h index 55fd4fb..a55694f 100644 --- a/test/helper/MockNetworkManager.h +++ b/test/helper/MockNetworkManager.h @@ -1,7 +1,7 @@ /*! * \brief Mock \ref NetworkManager for tests * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -21,14 +21,16 @@ class MockNetworkManager QString mFilename; MockNetworkReply* mNextReply; MockNetworkReply* mLastReply; + QNetworkRequest* mLastRequest; MockNetworkReply* getReply(const QNetworkRequest& pRequest); public: MockNetworkManager(); - virtual ~MockNetworkManager(); + virtual ~MockNetworkManager() override; virtual QNetworkReply* get(QNetworkRequest& pRequest, int pTimeoutInMilliSeconds = 30000) override; - virtual QNetworkReply* paos(QNetworkRequest& pRequest, const QByteArray& pData, bool pUsePsk = true, int pTimeoutInMilliSeconds = 30000) override; + virtual QNetworkReply* paos(QNetworkRequest& pRequest, const QByteArray& pNamespace, const QByteArray& pData, bool pUsePsk = true, int pTimeoutInMilliSeconds = 30000) override; + virtual bool checkUpdateServerCertificate(const QNetworkReply& pReply) override; void setFilename(const QString& pFilename) { @@ -50,6 +52,14 @@ class MockNetworkManager } + QNetworkRequest* getLastRequest() const + { + return mLastRequest; + } + + + Q_SIGNALS: + void fireReply(); }; } /* namespace governikus */ diff --git a/test/helper/MockNetworkReply.cpp b/test/helper/MockNetworkReply.cpp index 00bbe16..e56e1af 100644 --- a/test/helper/MockNetworkReply.cpp +++ b/test/helper/MockNetworkReply.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "MockNetworkReply.h" @@ -7,12 +7,13 @@ using namespace governikus; -MockNetworkReply::MockNetworkReply(const QByteArray& pData, QObject* pParent) +MockNetworkReply::MockNetworkReply(const QByteArray& pData, HttpStatusCode pStatusCode, QObject* pParent) : QNetworkReply(pParent) , mSocket() { mSocket.mReadBuffer = pData; setOpenMode(QIODevice::ReadOnly); + setAttribute(QNetworkRequest::HttpStatusCodeAttribute, QVariant(Enum::getValue(pStatusCode))); } diff --git a/test/helper/MockNetworkReply.h b/test/helper/MockNetworkReply.h index 2b49996..5e215dd 100644 --- a/test/helper/MockNetworkReply.h +++ b/test/helper/MockNetworkReply.h @@ -1,11 +1,12 @@ /*! * \brief Mock a QNetworkReply for tests. * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #pragma once +#include "HttpStatusCode.h" #include "MockSocket.h" #include @@ -22,8 +23,8 @@ class MockNetworkReply MockSocket mSocket; public: - MockNetworkReply(const QByteArray& pData = QByteArray(), QObject* pParent = nullptr); - virtual ~MockNetworkReply(); + MockNetworkReply(const QByteArray& pData = QByteArray(), HttpStatusCode pStatusCode = HttpStatusCode::UNDEFINED, QObject* pParent = nullptr); + virtual ~MockNetworkReply() override; virtual void abort() override { @@ -50,6 +51,12 @@ class MockNetworkReply } + void setFileModificationTimestamp(const QVariant& pTimestamp) + { + setHeader(QNetworkRequest::KnownHeaders::LastModifiedHeader, pTimestamp); + } + + }; } /* namespace governikus */ diff --git a/test/helper/MockReader.cpp b/test/helper/MockReader.cpp index 1d49b32..5903d32 100644 --- a/test/helper/MockReader.cpp +++ b/test/helper/MockReader.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MockReader.h" @@ -30,9 +30,10 @@ MockReader* MockReader::createMockReader(const QVector& pTransmi MockReader::MockReader(const QString& pReaderName) - : Reader(ReaderManagerPlugInType::UNKNOWN, pReaderName, ReaderType::UNKNOWN) + : Reader(ReaderManagerPlugInType::UNKNOWN, pReaderName) , mCard(nullptr) { + mReaderInfo.setConnected(true); mReaderInfo.setBasicReader(true); } diff --git a/test/helper/MockReader.h b/test/helper/MockReader.h index d659f00..45362a9 100644 --- a/test/helper/MockReader.h +++ b/test/helper/MockReader.h @@ -1,9 +1,7 @@ /*! - * MockReader.h - * * \brief Reader mock for tests * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -29,7 +27,7 @@ class MockReader static MockReader* createMockReader(const QVector& pTransmitConfig, const QSharedPointer& pEfCardAccess); MockReader(const QString& pReaderName = QStringLiteral("MockReader")); - virtual ~MockReader(); + virtual ~MockReader() override; Card* getCard() const override diff --git a/test/helper/MockReaderConfiguration.cpp b/test/helper/MockReaderConfiguration.cpp new file mode 100644 index 0000000..9eb87f6 --- /dev/null +++ b/test/helper/MockReaderConfiguration.cpp @@ -0,0 +1,13 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MockReaderConfiguration.h" + +using namespace governikus; + + +void MockReaderConfiguration::clearReaderConfiguration() +{ + mReaderConfigurationInfos.clear(); +} diff --git a/test/helper/MockReaderConfiguration.h b/test/helper/MockReaderConfiguration.h new file mode 100644 index 0000000..faf4aa8 --- /dev/null +++ b/test/helper/MockReaderConfiguration.h @@ -0,0 +1,27 @@ +/*! + * \brief ReaderConfigurationFile mock for tests + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "ReaderConfiguration.h" + +namespace governikus +{ + +class MockReaderConfiguration + : public ReaderConfiguration +{ + Q_OBJECT + + public: + MockReaderConfiguration() = default; + virtual ~MockReaderConfiguration() = default; + + void clearReaderConfiguration(); +}; + +} /* namespace governikus */ diff --git a/test/helper/MockReaderDetector.cpp b/test/helper/MockReaderDetector.cpp new file mode 100644 index 0000000..f40227a --- /dev/null +++ b/test/helper/MockReaderDetector.cpp @@ -0,0 +1,26 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MockReaderDetector.h" + + +using namespace governikus; + + +MockReaderDetector::MockReaderDetector(const QVector& pDevIds) + : ReaderDetector() + , mDevIds(pDevIds) +{ +} + + +MockReaderDetector::~MockReaderDetector() +{ +} + + +QVector MockReaderDetector::attachedDevIds() const +{ + return mDevIds; +} diff --git a/test/helper/MockReaderDetector.h b/test/helper/MockReaderDetector.h new file mode 100644 index 0000000..a7c5ca4 --- /dev/null +++ b/test/helper/MockReaderDetector.h @@ -0,0 +1,32 @@ +/*! + * \brief ReaderDetector mock for tests + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + + +#include "ReaderDetector.h" + + +namespace governikus +{ + +class MockReaderDetector + : public ReaderDetector +{ + Q_OBJECT + + public: + MockReaderDetector(const QVector& pDevIds); + + virtual ~MockReaderDetector() override; + + QVector attachedDevIds() const override; + + private: + const QVector& mDevIds; +}; + +} /* namespace governikus */ diff --git a/test/helper/MockReaderManagerPlugIn.cpp b/test/helper/MockReaderManagerPlugIn.cpp index 95ce530..da26171 100644 --- a/test/helper/MockReaderManagerPlugIn.cpp +++ b/test/helper/MockReaderManagerPlugIn.cpp @@ -1,7 +1,5 @@ /*! - * MockReaderManagerPlugIn.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ @@ -32,7 +30,7 @@ MockReaderManagerPlugIn& MockReaderManagerPlugIn::getInstance() } -QList MockReaderManagerPlugIn::getReader() const +QList MockReaderManagerPlugIn::getReaders() const { QList readers; readers.reserve(mReaders.size()); diff --git a/test/helper/MockReaderManagerPlugIn.h b/test/helper/MockReaderManagerPlugIn.h index 9cfc3a4..440f144 100644 --- a/test/helper/MockReaderManagerPlugIn.h +++ b/test/helper/MockReaderManagerPlugIn.h @@ -1,9 +1,7 @@ /*! - * MockReaderManagerPlugIn.h - * * \brief Mock implementation of ReaderManagerPlugIn * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ @@ -32,7 +30,7 @@ class MockReaderManagerPlugIn static MockReaderManagerPlugIn& getInstance(); - QList getReader() const; + virtual QList getReaders() const override; MockReader* addReader(const QString& pReaderName); diff --git a/test/helper/MockRemoteDispatcher.cpp b/test/helper/MockRemoteDispatcher.cpp new file mode 100644 index 0000000..dea6c3e --- /dev/null +++ b/test/helper/MockRemoteDispatcher.cpp @@ -0,0 +1,110 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "MockRemoteDispatcher.h" + +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" +#include "MockIfdStatus.h" + +#include + + +using namespace governikus; + + +MockRemoteDispatcher::MockRemoteDispatcher(DispatcherState pState) + : mState(pState) + , mId() + , mContextHandle() +{ +} + + +const QString& MockRemoteDispatcher::getId() const +{ + return mId; +} + + +const QString& MockRemoteDispatcher::getContextHandle() const +{ + return mContextHandle; +} + + +void MockRemoteDispatcher::send(const QSharedPointer& pMessage) +{ + QVERIFY(pMessage); + + Q_EMIT fireSend(pMessage); + + if (pMessage->getType() == RemoteCardMessageType::IFDEstablishContext) + { + if (mState == DispatcherState::WithoutReader) + { + return; + } + + bool withCard = (mState == DispatcherState::ReaderWithCard || mState == DispatcherState::ReaderWithCardError); + const QSharedPointer message(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(false), 500, true, withCard)); + Q_EMIT fireReceived(message, sharedFromThis()); + return; + } + + const QString errorMsg = mState == DispatcherState::ReaderWithCardError ? QStringLiteral("Error requested by the test") : QString(); + + if (pMessage->getType() == RemoteCardMessageType::IFDConnect) + { + const QSharedPointer request = pMessage.dynamicCast(); + const QString readerName = request->getSlotName(); + const QSharedPointer message(new IfdConnectResponse(readerName, errorMsg)); + Q_EMIT fireReceived(message, sharedFromThis()); + } + + if (pMessage->getType() == RemoteCardMessageType::IFDTransmit) + { + const QSharedPointer request = pMessage.dynamicCast(); + const QString readerName = request->getSlotHandle(); + const QSharedPointer message(new IfdTransmitResponse(readerName, errorMsg.isEmpty() ? QByteArray("pong") : QByteArray(), errorMsg)); + Q_EMIT fireReceived(message, sharedFromThis()); + } + + if (pMessage->getType() == RemoteCardMessageType::IFDDisconnect) + { + const QSharedPointer request = pMessage.dynamicCast(); + const QString readerName = request->getSlotHandle(); + const QSharedPointer message(new IfdDisconnectResponse(readerName, errorMsg)); + Q_EMIT fireReceived(message, sharedFromThis()); + } +} + + +MockRemoteDispatcher::DispatcherState MockRemoteDispatcher::getState() const +{ + return mState; +} + + +void MockRemoteDispatcher::setState(DispatcherState pState) +{ + mState = pState; +} + + +void MockRemoteDispatcher::onClosed() +{ + Q_EMIT fireClosed(GlobalStatus::Code::RemoteReader_CloseCode_NormalClose, sharedFromThis()); +} + + +void MockRemoteDispatcher::onReceived(const QSharedPointer& pMessage) +{ + Q_EMIT fireReceived(pMessage, sharedFromThis()); +} diff --git a/test/helper/MockRemoteDispatcher.h b/test/helper/MockRemoteDispatcher.h new file mode 100644 index 0000000..17013bf --- /dev/null +++ b/test/helper/MockRemoteDispatcher.h @@ -0,0 +1,54 @@ +/*! + * \brief Remote dispatcher mock for tests. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "RemoteDispatcher.h" + +namespace governikus +{ + +class MockRemoteDispatcher + : public RemoteDispatcher +{ + Q_OBJECT + + public: + enum class DispatcherState + { + WithoutReader, + ReaderWithoutCard, + ReaderWithCard, + ReaderWithCardError + }; + + private: + DispatcherState mState; + QString mId; + QString mContextHandle; + + public: + MockRemoteDispatcher(DispatcherState pState = DispatcherState::WithoutReader); + virtual ~MockRemoteDispatcher() override = default; + + virtual const QString& getId() const override; + virtual const QString& getContextHandle() const override; + virtual void send(const QSharedPointer& pMessage) override; + + DispatcherState getState() const; + void setState(DispatcherState pState); + void onClosed(); + + public Q_SLOTS: + void onReceived(const QSharedPointer& pMessage); + + Q_SIGNALS: + void fireSend(const QSharedPointer& pMessage); + +}; + + +} /* namespace governikus */ diff --git a/test/helper/MockSocket.cpp b/test/helper/MockSocket.cpp index 8e7bea8..0e7d394 100644 --- a/test/helper/MockSocket.cpp +++ b/test/helper/MockSocket.cpp @@ -1,9 +1,11 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MockSocket.h" +#include + using namespace governikus; MockSocket::MockSocket() @@ -13,7 +15,7 @@ MockSocket::MockSocket() , mReaderBufferChunk(-1) , mWriteBuffer() { - open(QIODevice::ReadWrite); + QTcpSocket::open(QIODevice::ReadWrite); } @@ -42,7 +44,7 @@ qint64 MockSocket::readData(char* pDestination, qint64 pMaxSize) int length = data.length(); if (length >= 0) { - qstrncpy(pDestination, data.constData(), static_cast(length)); + memcpy(pDestination, data.constData(), static_cast(length)); mReaderBufferPosition += length; } return length; diff --git a/test/helper/MockSocket.h b/test/helper/MockSocket.h index a0a39b0..d5c604b 100644 --- a/test/helper/MockSocket.h +++ b/test/helper/MockSocket.h @@ -1,7 +1,7 @@ /*! * \brief Mock a QAbstractSocket for tests. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -24,7 +24,7 @@ class MockSocket QByteArray mWriteBuffer; MockSocket(); - virtual ~MockSocket(); + virtual ~MockSocket() override; qint64 bytesAvailable() const override; qint64 readData(char* pDestination, qint64 pMaxSize) override; diff --git a/test/helper/MockWorkflowAuthenticateUi.h b/test/helper/MockWorkflowAuthenticateUi.h index d706c64..b4e43dc 100644 --- a/test/helper/MockWorkflowAuthenticateUi.h +++ b/test/helper/MockWorkflowAuthenticateUi.h @@ -1,9 +1,7 @@ /*! - * TestFileHelper.h - * * \brief Mock implementation of WorkflowAuthenticateUi. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/test/helper/MockWorkflowChangePinUi.h b/test/helper/MockWorkflowChangePinUi.h index 1c8a5ac..8f9a31b 100644 --- a/test/helper/MockWorkflowChangePinUi.h +++ b/test/helper/MockWorkflowChangePinUi.h @@ -1,9 +1,7 @@ /*! - * TestFileHelper.h - * * \brief Mock implementation of WorkflowAuthenticateUi. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/test/helper/PersoSimController.cpp b/test/helper/PersoSimController.cpp index 2adc218..13592e2 100644 --- a/test/helper/PersoSimController.cpp +++ b/test/helper/PersoSimController.cpp @@ -1,172 +1,127 @@ /*! - * PersoSimController.cpp - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "PersoSimController.h" -#include +#include +#include -#include - -#include "testMacros.h" +#ifdef PERSOSIM_EXECUTABLE + #define PERSOSIM_TESTS_ENABLED +#else + #define PERSOSIM_EXECUTABLE "" +#endif -using governikus::PersoSimController; - - -static const char* const sPersoSimPrompt = "PersoSim commandline: "; - -PersoSimController* PersoSimController::sActiveController = nullptr; -bool PersoSimController::sAbortSignalHandlerInstalled = false; - - -// We very much want to clean up the active PersoSimController -- since -// otherwise the PersoSim process keeps running -- so we use a global -// destructor to destroy it. -struct CleanupHelper -{ - ~CleanupHelper() - { - PersoSimController::cleanUpActiveController(); - } - - -}; - -static CleanupHelper sCleanupHelper; +using namespace governikus; PersoSimController::PersoSimController() : QObject() , mProcess(nullptr) - , mEventLoop(nullptr) + , mSocket(new QTcpSocket) { } -PersoSimController::~PersoSimController() +bool PersoSimController::isEnabled() const { - if (sActiveController == this) - { - sActiveController = nullptr; - } +#ifdef PERSOSIM_TESTS_ENABLED + return true; - if (mProcess != nullptr) - { - QCOMPARE(mProcess->write("exit\n"), 5); - mProcess->waitForFinished(-1); - } +#else + return false; + +#endif } bool PersoSimController::init() { -#ifdef PERSOSIM_TESTS_ENABLED + if (!isEnabled()) + { + qDebug() << "PersoSim tests not enabled"; + return false; + } + return startProcess(); - -#else - XSKIP("PersoSim tests not enabled", false); -#endif } -void PersoSimController::cleanUpActiveController() +bool PersoSimController::write(const QByteArray& pData) { - delete sActiveController; - sActiveController = nullptr; + qDebug() << "TO PersoSim:" << pData; + bool success = mSocket->write(pData) == pData.size(); + if (!success) + { + qDebug() << "Write failed"; + } + mSocket->flush(); + return success; } -bool PersoSimController::startProcess() +bool PersoSimController::shutdown() { - XVERIFY(mProcess == nullptr, false); - XVERIFY(sActiveController == nullptr, false); - - mProcess = new QProcess; - mProcess->setProgram(JAVA_EXECUTABLE); - mProcess->setArguments(QStringList() << "-jar" << PERSOSIM_EXECUTABLE << "--consoleOnly"); - mProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel); - - connect(mProcess, &QProcess::readyRead, this, &PersoSimController::inputAvailable); - connect(mProcess, QOverload::of(&QProcess::finished), this, &PersoSimController::processFinished); - - mProcess->start(); - XVERIFY(mProcess->waitForStarted(-1), false); - XCOMPARE(mProcess->state(), QProcess::Running, false); - - sActiveController = this; - installAbortSignalHandler(); - - // wait for PersoSim command line prompt - QEventLoop eventLoop; - mEventLoop = &eventLoop; - - int result = eventLoop.exec(); - mEventLoop = nullptr; - XCOMPARE(result, 0, false); + if (mProcess != nullptr) + { + write("shutdown\n"); + mSocket->close(); + if (!mProcess->waitForFinished(-1)) + { + qDebug() << "Failed:" << mProcess->errorString(); + return false; + } + } return true; } -void PersoSimController::inputAvailable() +bool PersoSimController::startProcess() { - - QByteArray line = mProcess->readLine(); - if (line.isEmpty()) + if (mProcess != nullptr) { - return; + return false; } - if (line.endsWith('\n')) + mProcess = new QProcess; + mProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel); + + connect(mSocket.data(), &QTcpSocket::readyRead, this, &PersoSimController::newData); + + mProcess->start(QStringLiteral(PERSOSIM_EXECUTABLE)); + if (!mProcess->waitForStarted(-1)) { - line.truncate(line.length() - 1); + qDebug() << PERSOSIM_EXECUTABLE; + return false; } - if (line == sPersoSimPrompt) + if (mProcess->state() != QProcess::Running) { - if (mEventLoop != nullptr) + return false; + } + + for (int i = 0; i < 10; i++) + { + mSocket->connectToHost(QHostAddress(QHostAddress::LocalHost), 9091); + if (!mSocket->waitForConnected(500)) { - mEventLoop->exit(0); + qWarning() << "Error(" << i << "):" << mSocket->errorString(); + QThread::msleep(500); + continue; } + + write("select-reader basic\n"); + return true; } - qDebug("PersoSim: %s", line.data()); + return false; } -void PersoSimController::processFinished(int /*pExitCode*/) +void PersoSimController::newData() { - if (mEventLoop != nullptr) - { - mEventLoop->exit(1); - } - - if (sActiveController == this) - { - sActiveController = nullptr; - } -} - - -void PersoSimController::installAbortSignalHandler() -{ - // We very much want to clean up the active PersoSimController -- since - // otherwise the PersoSim process keeps running -- so we install a SIGABRT - // signal handler for the case that something misbehaves (triggering an - // assert or throwing an uncaught exception) and abort() is called. - - if (!sAbortSignalHandlerInstalled) - { - signal(SIGABRT, &abortSignalHandler); - sAbortSignalHandlerInstalled = true; - } -} - - -void PersoSimController::abortSignalHandler(int /*pSignal*/) -{ - cleanUpActiveController(); + qDebug() << "FROM PersoSim:" << mSocket->readAll(); } diff --git a/test/helper/PersoSimController.h b/test/helper/PersoSimController.h index aefd7f1..14e8248 100644 --- a/test/helper/PersoSimController.h +++ b/test/helper/PersoSimController.h @@ -1,9 +1,7 @@ /*! - * PersoSimController.h - * * \brief Controller for an external PersoSim process. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -11,19 +9,7 @@ #include #include #include -#include - -#if defined(PERSOSIM_EXECUTABLE) && defined(JAVA_EXECUTABLE) -# define PERSOSIM_TESTS_ENABLED -# define SKIP_IF_PERSOSIM_DISABLED() do {}\ - while (false) -#else -# define PERSOSIM_EXECUTABLE "" -# define JAVA_EXECUTABLE "" -# define SKIP_IF_PERSOSIM_DISABLED() QSKIP("PersoSim tests not enabled", false); -#endif - -class QEventLoop; +#include namespace governikus { @@ -35,27 +21,21 @@ class PersoSimController public: PersoSimController(); - ~PersoSimController(); + ~PersoSimController() = default; + bool isEnabled() const; bool init(); - - static void cleanUpActiveController(); - - private: - bool startProcess(); - - void inputAvailable(); - void processFinished(int pExitCode); - - static void installAbortSignalHandler(); - static void abortSignalHandler(int pSignal); + bool write(const QByteArray& pData); + bool shutdown(); private: QProcess* mProcess; - QEventLoop* mEventLoop; + const QSharedPointer mSocket; + + bool startProcess(); + void newData(); + - static PersoSimController* sActiveController; - static bool sAbortSignalHandlerInstalled; }; } /* namespace governikus */ diff --git a/test/helper/QmlTestRunner.cpp b/test/helper/QmlTestRunner.cpp deleted file mode 100644 index c4d9546..0000000 --- a/test/helper/QmlTestRunner.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include -#include -QUICK_TEST_MAIN(qml) diff --git a/test/helper/RemoteCardNotificationChecker.cpp b/test/helper/RemoteCardNotificationChecker.cpp deleted file mode 100644 index 76d6727..0000000 --- a/test/helper/RemoteCardNotificationChecker.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*! - * \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 deleted file mode 100644 index c8155e9..0000000 --- a/test/helper/RemoteCardNotificationChecker.h +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * \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/RemoteMessageChecker.cpp b/test/helper/RemoteMessageChecker.cpp new file mode 100644 index 0000000..9e89efb --- /dev/null +++ b/test/helper/RemoteMessageChecker.cpp @@ -0,0 +1,145 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + + +#include "RemoteMessageChecker.h" + +#include "messages/Discovery.h" +#include "messages/GetIfdStatus.h" +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/IfdEstablishPaceChannel.h" +#include "messages/IfdEstablishPaceChannelResponse.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" + +#include +#include + + +using namespace governikus; + + +void RemoteMessageChecker::processDiscovery(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getIfdName(), QStringLiteral("Sony Xperia Z5 compact")); + QCOMPARE(pMessage->getIfdId(), QStringLiteral("0123456789ABCDEF")); + QVERIFY(pMessage->getPort() == static_cast(24728)); + QCOMPARE(pMessage->getSupportedApis(), QStringList({QStringLiteral("IFDInterface_WebSocket_v0"), QStringLiteral("IFDInterface_WebSocket_v2")})); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDEstablishContext); + QCOMPARE(pMessage->getProtocol(), QStringLiteral("IFDInterface_WebSocket_v0")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDEstablishContextResponse); + QCOMPARE(pMessage->resultHasError(), true); + QCOMPARE(pMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDGetStatus); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDStatus); + + QCOMPARE(pMessage->getSlotName(), QStringLiteral("NFC Reader")); + QVERIFY(pMessage->getConnectedReader()); + QCOMPARE(pMessage->getMaxApduLength(), 500); + + const PaceCapabilities paceCapabilities = pMessage->getPaceCapabilities(); + Q_UNUSED(paceCapabilities); + + QVERIFY(!pMessage->getCardAvailable()); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDConnect); + QCOMPARE(pMessage->getSlotName(), QStringLiteral("NFC Reader")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDConnectResponse); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(pMessage->resultHasError(), true); + QCOMPARE(pMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDDisconnect); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDDisconnectResponse); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(pMessage->resultHasError(), true); + QCOMPARE(pMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDError); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(pMessage->resultHasError(), true); + QCOMPARE(pMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDTransmit); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(pMessage->getInputApdu(), QByteArray::fromHex("00A402022F00")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getType(), RemoteCardMessageType::IFDTransmitResponse); + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(pMessage->resultHasError(), true); + QCOMPARE(pMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + QCOMPARE(pMessage->getResponseApdu(), QByteArray::fromHex("9000")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("My little Reader")); + QCOMPARE(pMessage->getInputData(), QByteArray::fromHex("ABCD1234")); +} + + +void RemoteMessageChecker::process(const QSharedPointer& pMessage) +{ + QCOMPARE(pMessage->getSlotHandle(), QStringLiteral("My little Reader")); + QCOMPARE(pMessage->getOutputData(), QByteArray::fromHex("ABCD1234")); +} diff --git a/test/helper/RemoteMessageChecker.h b/test/helper/RemoteMessageChecker.h new file mode 100644 index 0000000..329f11a --- /dev/null +++ b/test/helper/RemoteMessageChecker.h @@ -0,0 +1,41 @@ +/*! + * \brief Helper class to verify the content of remote messages. + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include "messages/MessageReceiver.h" + + +namespace governikus +{ +class Discovery; + + +class RemoteMessageChecker + : public MessageReceiver +{ + public: + RemoteMessageChecker() = default; + virtual ~RemoteMessageChecker() override = default; + + void processDiscovery(const QSharedPointer& pMessage); + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + virtual void process(const QSharedPointer& pMessage) override; + +}; + +} /* namespace governikus */ diff --git a/test/helper/TestAuthContext.cpp b/test/helper/TestAuthContext.cpp index 06666cb..fe5d629 100644 --- a/test/helper/TestAuthContext.cpp +++ b/test/helper/TestAuthContext.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEac1Parser.h" @@ -11,7 +11,7 @@ using namespace governikus; TestAuthContext::TestAuthContext(ActivationContext* pActivationContext, const QString& pFileName) - : AuthContext(pActivationContext) + : AuthContext(QSharedPointer(pActivationContext)) , mDidAuthenticateEac1() { mDidAuthenticateEac1.reset(static_cast(DidAuthenticateEac1Parser().parse(TestFileHelper::readFile(pFileName)))); @@ -38,8 +38,8 @@ void TestAuthContext::setRequiredAccessRights(const QSet& pAccessRi { mDidAuthenticateEac1->mEac1InputType.mRequiredChat.reset(new CHAT(getTerminalCvc()->getBody().getCHAT())); } - mDidAuthenticateEac1->getRequiredChat()->removeAllAccessRights(); - mDidAuthenticateEac1->getRequiredChat()->setAccessRights(pAccessRights); + qSharedPointerConstCast(mDidAuthenticateEac1->getRequiredChat())->removeAllAccessRights(); + qSharedPointerConstCast(mDidAuthenticateEac1->getRequiredChat())->setAccessRights(pAccessRights); } setDidAuthenticateEac1(mDidAuthenticateEac1); setTerminalCvc(mDidAuthenticateEac1->getCvCertificates().at(0)); @@ -58,8 +58,8 @@ void TestAuthContext::setOptionalAccessRights(const QSet& pAccessRi { mDidAuthenticateEac1->mEac1InputType.mOptionalChat.reset(new CHAT(getTerminalCvc()->getBody().getCHAT())); } - mDidAuthenticateEac1->getOptionalChat()->removeAllAccessRights(); - mDidAuthenticateEac1->getOptionalChat()->setAccessRights(pAccessRights); + qSharedPointerConstCast(mDidAuthenticateEac1->getOptionalChat())->removeAllAccessRights(); + qSharedPointerConstCast(mDidAuthenticateEac1->getOptionalChat())->setAccessRights(pAccessRights); } setDidAuthenticateEac1(mDidAuthenticateEac1); setTerminalCvc(mDidAuthenticateEac1->getCvCertificates().at(0)); diff --git a/test/helper/TestAuthContext.h b/test/helper/TestAuthContext.h index 9e18dac..2fdcf0e 100644 --- a/test/helper/TestAuthContext.h +++ b/test/helper/TestAuthContext.h @@ -1,7 +1,7 @@ /*! * \brief Helper to use AuthContext in an easy way. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once diff --git a/test/helper/TestFileHelper.cpp b/test/helper/TestFileHelper.cpp index 10ad3e1..5b35e0c 100644 --- a/test/helper/TestFileHelper.cpp +++ b/test/helper/TestFileHelper.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "TestFileHelper.h" @@ -40,7 +40,11 @@ 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" + QStringLiteral("de_AT"), QStringLiteral("de_DE"), + QStringLiteral("en"), QStringLiteral("fr_FR"), + QStringLiteral("es"), QStringLiteral("defect"), + QStringLiteral("de_fe"), QStringLiteral("en_gb"), + QStringLiteral("it") }); QDir dir(pTranslationDir); @@ -52,7 +56,7 @@ void TestFileHelper::createTranslations(const QString& pTranslationDir) for (const auto& filePart : testFiles) { - QFile file(dir.path() + "/ausweisapp2_" + filePart + ".qm"); + QFile file(dir.path() + QStringLiteral("/ausweisapp2_") + filePart + QStringLiteral(".qm")); QVERIFY(file.open(QIODevice::WriteOnly)); QVERIFY(file.write(reinterpret_cast(qm_magic), sizeof(qm_magic))); QVERIFY(file.write(reinterpret_cast(qm_content), sizeof(qm_content))); @@ -61,7 +65,7 @@ void TestFileHelper::createTranslations(const QString& pTranslationDir) } -bool TestFileHelper::containsLog(const QSignalSpy& pSpy, const QLatin1String& pStr) +bool TestFileHelper::containsLog(const QSignalSpy& pSpy, const QLatin1String pStr) { for (const auto& entry : pSpy) { diff --git a/test/helper/TestFileHelper.h b/test/helper/TestFileHelper.h index 05239cc..780373a 100644 --- a/test/helper/TestFileHelper.h +++ b/test/helper/TestFileHelper.h @@ -1,7 +1,7 @@ /*! * \brief Helper for some file functions. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #pragma once @@ -18,7 +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); + static bool containsLog(const QSignalSpy& pSpy, const QLatin1String pStr); }; } /* namespace governikus */ diff --git a/test/helper/WebSocketHelper.cpp b/test/helper/WebSocketHelper.cpp index 6e015c1..c7b2ea5 100644 --- a/test/helper/WebSocketHelper.cpp +++ b/test/helper/WebSocketHelper.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "WebSocketHelper.h" @@ -19,7 +19,7 @@ void WebSocketHelper::connectWebsocket(int pPort) 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); + const QString address = QStringLiteral("ws://localhost:%1").arg(pPort); mWebSocket.open(QUrl(address)); QTimer timer; diff --git a/test/helper/WebSocketHelper.h b/test/helper/WebSocketHelper.h index e104e35..e03fa88 100644 --- a/test/helper/WebSocketHelper.h +++ b/test/helper/WebSocketHelper.h @@ -1,11 +1,12 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #pragma once #include #include +#include #include namespace governikus @@ -19,7 +20,7 @@ class WebSocketHelper private: const int mConnectionTiemout; QWebSocket mWebSocket; - QVector mInput; + QStringList mInput; void connectWebsocket(int pPort); diff --git a/test/helper/testMacros.h b/test/helper/testMacros.h deleted file mode 100644 index 077a370..0000000 --- a/test/helper/testMacros.h +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#pragma once - -#include - - -// Versions of the Q*() test assertion macros that return an actual value. - - -#define XVERIFY(statement, returnValue)\ - do {\ - if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)){\ - return returnValue;}\ - }\ - while (0) - - -#define XVERIFY2(statement, description, returnValue)\ - do {\ - if (statement){\ - if (!QTest::qVerify(true, #statement, (description), __FILE__, __LINE__)){\ - return returnValue;}\ - }\ - else {\ - if (!QTest::qVerify(false, #statement, (description), __FILE__, __LINE__)){\ - return returnValue;}\ - }\ - }\ - while (0) - - -#define XCOMPARE(actual, expected, returnValue)\ - do {\ - if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)){\ - return returnValue;}\ - }\ - while (0) - - -#define XSKIP(statement, returnValue)\ - do {\ - QTest::qSkip(statement, __FILE__, __LINE__);\ - return returnValue;\ - }\ - while (0) diff --git a/test/qml/CMakeLists.txt b/test/qml/CMakeLists.txt index 8fe3b13..1acbcbb 100644 --- a/test/qml/CMakeLists.txt +++ b/test/qml/CMakeLists.txt @@ -1 +1,4 @@ ADD_QML_TEST_FILES(${RESOURCES_DIR}/qml) + +ADD_EXECUTABLE(QmlTestRunner QmlTestRunner.cpp) +TARGET_LINK_LIBRARIES(QmlTestRunner Qt5::QuickTest Qt5::Gui) diff --git a/test/qml/QmlTestRunner.cpp b/test/qml/QmlTestRunner.cpp new file mode 100644 index 0000000..cd90dac --- /dev/null +++ b/test/qml/QmlTestRunner.cpp @@ -0,0 +1,7 @@ +/* + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include +#include +QUICK_TEST_MAIN(qml) diff --git a/test/qml/test_Utils.qml b/test/qml/test_Utils.qml index 0d171bd..f2d9cad 100644 --- a/test/qml/test_Utils.qml +++ b/test/qml/test_Utils.qml @@ -1,16 +1,16 @@ import QtQuick 2.3 import QtTest 1.0 -import global 1.0 +// import Governikus.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 \"") + // compare(Utils.escapeHtml("a&b"), "a&b", "escape &") + // compare(Utils.escapeHtml("
"), "<br/>", "escape < and >") + // compare(Utils.escapeHtml("\"Hello\""), ""Hello"", "escape \"") } } diff --git a/test/qt/CMakeLists.txt b/test/qt/CMakeLists.txt index 4bbfef4..00fac9f 100644 --- a/test/qt/CMakeLists.txt +++ b/test/qt/CMakeLists.txt @@ -1,16 +1,15 @@ FUNCTION(ADD_TEST_EXECUTABLE testname) - ADD_EXECUTABLE(${testname} - $ - ${ARGN}) + ADD_EXECUTABLE(${testname} ${ARGN}) - 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 AusweisAppGlobal AusweisAppServices AusweisAppSettings AusweisAppNetwork) + TARGET_LINK_LIBRARIES(${testname} Qt5::Network Qt5::Xml Qt5::Test OpenSSL::Crypto) + TARGET_LINK_LIBRARIES(${testname} AusweisAppTestHelper AusweisAppCore AusweisAppCard AusweisAppGlobal AusweisAppCardDrivers AusweisAppServices AusweisAppSettings AusweisAppNetwork) TARGET_LINK_LIBRARIES(${testname} AusweisAppActivationInternal AusweisAppJsonApi AusweisAppAidl AusweisAppQml) - TARGET_LINK_LIBRARIES(${testname} AusweisAppCardRemote) + TARGET_LINK_LIBRARIES(${testname} AusweisAppCardRemote AusweisAppExport) + TARGET_LINK_LIBRARIES(${testname} AusweisAppSecureStorage AusweisAppConfiguration AusweisAppFileProvider) + TARGET_LINK_LIBRARIES(${testname} QRC_FIXTURE_OBJ) IF(DESKTOP) - TARGET_LINK_LIBRARIES(${testname} Qt5::Widgets AusweisAppWidget AusweisAppCardPcsc AusweisAppCardDrivers AusweisAppActivationWebservice) + TARGET_LINK_LIBRARIES(${testname} Qt5::Widgets AusweisAppWidget AusweisAppCardPcsc AusweisAppActivationWebservice) ENDIF() IF(LINUX OR ANDROID OR IOS) @@ -29,11 +28,8 @@ ENDFUNCTION() FUNCTION(ADD_TEST_EXECUTABLE_SUBDIR) SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) - IF(APPLE OR WIN32 OR BSD) - LIST(REMOVE_ITEM SUBDIRS bluetooth) - ENDIF() IF(IOS OR ANDROID) - LIST(REMOVE_ITEM SUBDIRS gui) + LIST(REMOVE_ITEM SUBDIRS widget) LIST(REMOVE_ITEM SUBDIRS cli) LIST(REMOVE_ITEM SUBDIRS pcsc) LIST(REMOVE_ITEM SUBDIRS drivers) @@ -44,11 +40,15 @@ FUNCTION(ADD_TEST_EXECUTABLE_SUBDIR) FILE(GLOB_RECURSE TEST_SUBFILES "${SUBDIR}/*.cpp") FOREACH(sourcefile ${TEST_SUBFILES}) - EXTRACT_TESTNAME(TESTNAME ${sourcefile}) - ADD_TEST_EXECUTABLE(${TESTNAME} ${sourcefile}) - GET_TEST_CMDLINE(TEST_CMDLINE ${TESTNAME}) - ADD_TEST(${TESTNAME} ${TESTNAME} ${TEST_CMDLINE}) - SET_TESTS_PROPERTIES(${TESTNAME} PROPERTIES LABELS "ausweisapp") + STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" sourcefile_relative "${sourcefile}") + IF(NOT (((APPLE OR WIN32 OR BSD) AND "${sourcefile_relative}" MATCHES "card/bluetooth") OR + ((IOS OR ANDROID) AND "${sourcefile_relative}" MATCHES "card/pcsc"))) + EXTRACT_TESTNAME(TESTNAME ${sourcefile}) + ADD_TEST_EXECUTABLE(${TESTNAME} ${sourcefile}) + GET_TEST_CMDLINE(TEST_CMDLINE ${TESTNAME}) + ADD_TEST(${TESTNAME} ${TESTNAME} ${TEST_CMDLINE}) + SET_TESTS_PROPERTIES(${TESTNAME} PROPERTIES LABELS "ausweisapp") + ENDIF() ENDFOREACH() ENDFOREACH() ENDFUNCTION() diff --git a/test/qt/activation_webservice/test_Template.cpp b/test/qt/activation_webservice/test_Template.cpp index 75163e5..d97e65f 100644 --- a/test/qt/activation_webservice/test_Template.cpp +++ b/test/qt/activation_webservice/test_Template.cpp @@ -1,8 +1,7 @@ /*! - * test_Template.cpp * \brief Unit tests for \ref Template * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "Template.h" diff --git a/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp b/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp index befc80f..ea1e563 100644 --- a/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp +++ b/test/qt/activation_webservice/test_WebserviceActivationHandler.cpp @@ -1,8 +1,7 @@ /*! - * test_WebserviceActivationHandler.cpp * \brief Unit tests for \ref WebserviceActivationHandler * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "WebserviceActivationHandler.h" diff --git a/test/qt/aidl/test_PskManager.cpp b/test/qt/aidl/test_PskManager.cpp index 82c361d..434f24d 100644 --- a/test/qt/aidl/test_PskManager.cpp +++ b/test/qt/aidl/test_PskManager.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for PskManager. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "PskManager.h" diff --git a/test/qt/bluetooth/test_BluetoothMessage.cpp b/test/qt/bluetooth/test_BluetoothMessage.cpp deleted file mode 100644 index 0ed852e..0000000 --- a/test/qt/bluetooth/test_BluetoothMessage.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * test_BluetoothMessage.cpp - * \brief Unit tests for \ref BluetoothMessage - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "messages/BluetoothMessageStatusInd.h" -#include -#include - -using namespace governikus; - -class test_BluetoothMessage - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void statusIndCtor() - { - BluetoothMessageStatusInd msg; - QCOMPARE(msg.getBluetoothMsgId(), BluetoothMsgId::StatusInd); - } - - - void statusIndStatusChange() - { - BluetoothMessageParameterStatusChange param(QByteArray(1, Enum::getValue(BluetoothStatusChange::CardRecovered))); - BluetoothMessageStatusInd msg; - msg.copyParameter(param); - - QCOMPARE(msg.getStatusChange(), BluetoothStatusChange::CardRecovered); - } - - -}; - -QTEST_GUILESS_MAIN(test_BluetoothMessage) -#include "test_BluetoothMessage.moc" diff --git a/test/qt/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp b/test/qt/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp deleted file mode 100644 index 87b40e8..0000000 --- a/test/qt/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/*! - * BluetoothMessageParameterMaxMsgSize.cpp - * \brief Unit tests for \ref BluetoothMessageParameterMaxMsgSize * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "messages/parameter/BluetoothMessageParameterMaxMsgSize.h" -#include -#include - -using namespace governikus; - -class test_BluetoothMessageParameterMaxMsgSize - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - /* - * The value is a 2 byte big endian. So perform some tests. - */ - void createWithByteArray() - { - BluetoothMessageParameterMaxMsgSize param(QByteArray::fromHex("0100")); - QCOMPARE(param.getMaxMsgSize(), static_cast(256)); - QCOMPARE(param.getValue(), QByteArray::fromHex("0100")); - } - - - void createWithByteArray_tooBig() - { - BluetoothMessageParameterMaxMsgSize param(QByteArray::fromHex("010000")); - QCOMPARE(param.getMaxMsgSize(), static_cast(0)); - QCOMPARE(param.getValue(), QByteArray("")); - } - - - void createWithInt() - { - BluetoothMessageParameterMaxMsgSize param(256); - QCOMPARE(param.getValue().toHex(), QByteArray("0100")); - QCOMPARE(param.getMaxMsgSize(), static_cast(256)); - } - - - void createWithInt_tooBig() - { - BluetoothMessageParameterMaxMsgSize param(0x010000); - QCOMPARE(param.getValue().toHex(), QByteArray("")); - QCOMPARE(param.getMaxMsgSize(), static_cast(0)); - } - - -}; - -QTEST_GUILESS_MAIN(test_BluetoothMessageParameterMaxMsgSize) -#include "test_BluetoothMessageParameterMaxMsgSize.moc" diff --git a/test/qt/bluetooth/test_BluetoothMessageParser.cpp b/test/qt/bluetooth/test_BluetoothMessageParser.cpp deleted file mode 100644 index f1ae910..0000000 --- a/test/qt/bluetooth/test_BluetoothMessageParser.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/*! - * test_BluetoothMessageParser.cpp - * \brief Unit tests for \ref BluetoothMessageParser - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "messages/BluetoothMessageParser.h" -#include "messages/BluetoothMessageStatusInd.h" -#include "messages/parameter/BluetoothMessageParameterApduResponse.h" -#include "messages/parameter/BluetoothMessageParameterStatusChange.h" -#include -#include - -using namespace governikus; - -class test_BluetoothMessageParser - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void initTestCase() - { - } - - - void transferApduResponse() - { - QByteArray response; - response = - QByteArray::fromHex("060200000200000100000000050000fe3081f9a106040400000000a20404029000a381c43181c1300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020141302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145a42204209ee959c9f063c6e144b463e04fa19ef44da0f5059d817a7db2240bbee8b218a290000000"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 1); - BluetoothMessage::Ptr message = parser1.getMessages().at(0); - - QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::TransferApduResponse); - QCOMPARE(message->mMessageParameter.size(), 2); - - const auto& params = message->mMessageParameter; - QCOMPARE(params.first()->getParameterId(), BluetoothParamId::ResultCode); - QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothResultCode::Ok))); - - const auto param = params.last(); - QCOMPARE(param->getParameterId(), BluetoothParamId::ResponseAPDU); - const auto paramApdu = param.staticCast(); - QCOMPARE(paramApdu->getResponseApdu(), - QByteArray::fromHex("3081f9a106040400000000a20404029000a381c43181c1300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020141302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145a42204209ee959c9f063c6e144b463e04fa19ef44da0f5059d817a7db2240bbee8b218a29000")); - } - - - void messageToStringCasted() - { - QByteArray response; - response = QByteArray::fromHex("110100000800000102000000"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 1); - BluetoothMessage::Ptr message = parser1.getMessages().at(0); - - QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - auto msgInd = message.staticCast(); - QCOMPARE(msgInd->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardNotAccessible")); - QCOMPARE(msgInd->getStatusChange(), BluetoothStatusChange::CardNotAccessible); - } - - - void messageToString() - { - QByteArray response; - response = QByteArray::fromHex("110100000800000104000000110100000800000103000000"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 2); - QCOMPARE(parser1.getMessages().at(0)->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardInserted")); - QCOMPARE(parser1.getMessages().at(1)->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardRemoved")); - } - - - void parseAtrReponse() - { - QByteArray response; - - response = QByteArray::fromHex("0802000002000001000000000600000f4b8a80018031f873f741e08290007500"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 1); - QCOMPARE(parser1.getRemainingBytes().size(), 0); - - QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::TransferAtrResponse); - QCOMPARE(parser1.getMessages()[0]->mMessageParameter.size(), 2); - - 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")); - } - - - void parseCardReaderStatusIndMultipleMessages() - { - QByteArray response; - - response = QByteArray::fromHex("110100000800000104000000110100000800000103000000"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 2); - QCOMPARE(parser1.getRemainingBytes().size(), 0); - - QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - 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]->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))); - } - - - void parseCardReaderStatusInd() - { - QByteArray response; - - response = QByteArray::fromHex("110100000800000104000000"); - BluetoothMessageParser parser1(response); - QCOMPARE(parser1.getMessages().size(), 1); - QCOMPARE(parser1.getRemainingBytes().size(), 0); - QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); - 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]->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))); - } - - - void parseDisconnectResponse() - { - BluetoothMessageParser parser(QByteArray::fromHex("03000000")); - QCOMPARE(parser.getMessages().size(), 1); - QCOMPARE(parser.getMessages().at(0)->getBluetoothMsgId(), BluetoothMsgId::DisconnectResponse); - QVERIFY(parser.getRemainingBytes().isEmpty()); - } - - - void parseMessageParametersAsMultipleOfFour() - { - BluetoothMessageParser parser = BluetoothMessageParser(QByteArray::fromHex("060200000200000100000000050001153082010fa106040400000000a20404029000a381b63181b3300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007")); - QCOMPARE(parser.getMessages().size(), 0); - QCOMPARE(parser.getRemainingBytes().isEmpty(), false); - - parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("02020302020201020201453012060a04007f0007020204020202010202010d301c060904007f00070202"))); - QCOMPARE(parser.getMessages().size(), 0); - QCOMPARE(parser.getRemainingBytes().isEmpty(), false); - - parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0302300c060704007f0007010202010d020141301c060904007f000702020302300c060704007f0007010202010d020145302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369"))); - QCOMPARE(parser.getMessages().size(), 0); - QCOMPARE(parser.getRemainingBytes().isEmpty(), false); - - parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("662f6e70612e786d6ca422042065828281cc36f1bf6056748fa23ae95f7d73c6b52e5a5277d1bf48a66fd9a6c9a510040e4445435643416549443030313033a610040e4445435643416549443030313032900000"))); - QCOMPARE(parser.getMessages().size(), 0); - QCOMPARE(parser.getRemainingBytes().isEmpty(), false); - - parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0000"))); - QCOMPARE(parser.getMessages().size(), 1); - QCOMPARE(parser.getRemainingBytes().isEmpty(), true); - - parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0602000002000001000000000500000a37eb6102ba764d9f90000000"))); - QCOMPARE(parser.getMessages().size(), 1); - QCOMPARE(parser.getRemainingBytes().isEmpty(), true); - } - - -}; - -QTEST_GUILESS_MAIN(test_BluetoothMessageParser) -#include "test_BluetoothMessageParser.moc" diff --git a/test/qt/card/asn1/test_AccessRoleAndRight.cpp b/test/qt/card/asn1/test_AccessRoleAndRight.cpp index 7d34ede..f6f5e3f 100644 --- a/test/qt/card/asn1/test_AccessRoleAndRight.cpp +++ b/test/qt/card/asn1/test_AccessRoleAndRight.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref AccessRoleAndRight * - * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/AccessRoleAndRight.h" diff --git a/test/qt/card/asn1/test_Asn1BCDDateUtil.cpp b/test/qt/card/asn1/test_Asn1BCDDateUtil.cpp index cfa20c1..db8a0d8 100644 --- a/test/qt/card/asn1/test_Asn1BCDDateUtil.cpp +++ b/test/qt/card/asn1/test_Asn1BCDDateUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Asn1BCDDateUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/test/qt/card/asn1/test_Asn1IntegerUtil.cpp b/test/qt/card/asn1/test_Asn1IntegerUtil.cpp index 3a3cc40..666faa3 100644 --- a/test/qt/card/asn1/test_Asn1IntegerUtil.cpp +++ b/test/qt/card/asn1/test_Asn1IntegerUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Asn1IntegerUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/test/qt/card/asn1/test_Asn1ObjectUtil.cpp b/test/qt/card/asn1/test_Asn1ObjectUtil.cpp index 505ae1f..61added 100644 --- a/test/qt/card/asn1/test_Asn1ObjectUtil.cpp +++ b/test/qt/card/asn1/test_Asn1ObjectUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Asn1ObjectUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -27,7 +27,7 @@ class test_Asn1ObjectUtil QVERIFY(asn1Object != nullptr); - QByteArray derEncoding(reinterpret_cast(asn1Object->data), asn1Object->length); + QByteArray derEncoding = Asn1ObjectUtil::getValue(asn1Object); QCOMPARE(derEncoding.toHex(), QByteArray("04008100")); ASN1_OBJECT_free(asn1Object); diff --git a/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp b/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp index 5169f2c..50b455f 100644 --- a/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp +++ b/test/qt/card/asn1/test_Asn1OctetStringUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Asn1OctetStringUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -48,7 +48,7 @@ class test_Asn1OctetStringUtil QCOMPARE(asn1OctetString->length, 15); for (int i = 0; i < 15; i++) { - QCOMPARE(asn1OctetString->data[i], (unsigned char) (i + 1)); + QCOMPARE(asn1OctetString->data[i], uchar(i + 1)); } } diff --git a/test/qt/card/asn1/test_Asn1StringUtil.cpp b/test/qt/card/asn1/test_Asn1StringUtil.cpp index 904c35d..e3f0636 100644 --- a/test/qt/card/asn1/test_Asn1StringUtil.cpp +++ b/test/qt/card/asn1/test_Asn1StringUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Asn1StringUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -27,9 +27,9 @@ class test_Asn1StringUtil Asn1StringUtil::setValue(QString("abc"), asn1String); QCOMPARE(asn1String->length, 3); - QCOMPARE(asn1String->data[0], (unsigned char) 'a'); - QCOMPARE(asn1String->data[1], (unsigned char) 'b'); - QCOMPARE(asn1String->data[2], (unsigned char) 'c'); + QCOMPARE(asn1String->data[0], uchar('a')); + QCOMPARE(asn1String->data[1], uchar('b')); + QCOMPARE(asn1String->data[2], uchar('c')); ASN1_STRING_free(asn1String); } diff --git a/test/qt/card/asn1/test_Asn1TypeUtil.cpp b/test/qt/card/asn1/test_Asn1TypeUtil.cpp index 66c7b42..4093da1 100644 --- a/test/qt/card/asn1/test_Asn1TypeUtil.cpp +++ b/test/qt/card/asn1/test_Asn1TypeUtil.cpp @@ -1,16 +1,14 @@ /*! * \brief Unit tests for \ref Asn1TypeUtil * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" -#include -#include - #include #include +#include using namespace governikus; @@ -34,7 +32,7 @@ class test_Asn1TypeUtil ASN1_TYPE* asn1Type = ASN1_TYPE_new(); ASN1_OCTET_STRING* asn1OctetString = ASN1_OCTET_STRING_new(); QByteArray octetBytes = QByteArray::fromHex("0123456789ABCDEF"); - ASN1_OCTET_STRING_set(asn1OctetString, (unsigned char*) octetBytes.data(), octetBytes.length()); + ASN1_OCTET_STRING_set(asn1OctetString, reinterpret_cast(octetBytes.data()), octetBytes.length()); ASN1_TYPE_set(asn1Type, V_ASN1_OCTET_STRING, asn1OctetString); QCOMPARE(Asn1TypeUtil::encode(asn1Type).toHex(), QByteArray("0408").append(octetBytes.toHex())); diff --git a/test/qt/card/asn1/test_Asn1Util.cpp b/test/qt/card/asn1/test_Asn1Util.cpp index cef8097..f67bcfd 100644 --- a/test/qt/card/asn1/test_Asn1Util.cpp +++ b/test/qt/card/asn1/test_Asn1Util.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/test/qt/card/asn1/test_AuxiliaryAuthenticatedData.cpp b/test/qt/card/asn1/test_AuxiliaryAuthenticatedData.cpp index ebc1ea9..d646cc0 100644 --- a/test/qt/card/asn1/test_AuxiliaryAuthenticatedData.cpp +++ b/test/qt/card/asn1/test_AuxiliaryAuthenticatedData.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref AuxiliaryAuthenticatedData * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" @@ -23,9 +23,10 @@ class test_AuxiliaryAuthenticatedData void parseCrap() { QByteArray hexString("30 8202A4"); - auto auxData = AuthenticatedAuxiliaryData::fromHex(hexString); + QVERIFY(auxData == nullptr); + auxData = AuthenticatedAuxiliaryData::fromHex(QByteArray()); QVERIFY(auxData == nullptr); } @@ -74,6 +75,49 @@ class test_AuxiliaryAuthenticatedData } + void requiredAge_data() + { + // date of birth: 1978-08-16 + QTest::addColumn("age"); + QTest::addColumn("effectiveDate"); + + QTest::newRow("invalid") << QString() << QDate(); + + QTest::newRow("vor der Geburt (1 Jahr, 2 Tage)") << QStringLiteral("-2") << QDate(1977, 8, 14); + QTest::newRow("vor der Geburt (2 Tage)") << QStringLiteral("-1") << QDate(1978, 8, 14); + QTest::newRow("vor der Geburt (1 Tag)") << QStringLiteral("-1") << QDate(1978, 8, 15); + + QTest::newRow("Geburt") << QStringLiteral("0") << QDate(1978, 8, 16); + + QTest::newRow("1 Tag") << QStringLiteral("0") << QDate(1978, 8, 17); + QTest::newRow("Ende des Jahres") << QStringLiteral("0") << QDate(1978, 12, 31); + QTest::newRow("Anfang nächstes Jahr") << QStringLiteral("0") << QDate(1979, 1, 1); + + QTest::newRow("vorm 1. Geburtstag") << QStringLiteral("0") << QDate(1979, 8, 15); + QTest::newRow("1. Geburtstag") << QStringLiteral("1") << QDate(1979, 8, 16); + QTest::newRow("nach 1. Geburtstag") << QStringLiteral("1") << QDate(1979, 8, 17); + QTest::newRow("Ende Monats nach 1. Geburtstag") << QStringLiteral("1") << QDate(1979, 8, 31); + } + + + void requiredAge() + { + QFETCH(QString, age); + QFETCH(QDate, effectiveDate); + + QByteArray hexString("67 17" + "73 15 " + " 06 09 04007F000703010401" + " 53 08 3139373830383136"); + + auto auxData = AuthenticatedAuxiliaryData::fromHex(hexString); + + QVERIFY(auxData); + QVERIFY(auxData->hasAgeVerificationDate()); + QCOMPARE(auxData->getRequiredAge(effectiveDate), age); + } + + void communityID() { QByteArray hexString("67 16" diff --git a/test/qt/card/asn1/test_CVCertificate.cpp b/test/qt/card/asn1/test_CVCertificate.cpp index 62860aa..d98b339 100644 --- a/test/qt/card/asn1/test_CVCertificate.cpp +++ b/test/qt/card/asn1/test_CVCertificate.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref CVCertificate * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ @@ -132,8 +132,18 @@ class test_CVCertificate auto cvca1 = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); auto ecdsaSignature = cvca1->getEcdsaSignature(); - QCOMPARE(valueOf(ecdsaSignature->r).toHex(), QByteArray("9f25ebfaf4b91e4c60a1683754c5dc076a3179753ef97d9f8cb01fe1dcd3b8c8")); - QCOMPARE(valueOf(ecdsaSignature->s).toHex(), QByteArray("3e7a26602ab1f344be5706006d79a9ff6a9716404dc83b9f30e1213b393128a2")); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + const BIGNUM* r = ecdsaSignature->r; + const BIGNUM* s = ecdsaSignature->s; +#else + const BIGNUM* r = nullptr; + const BIGNUM* s = nullptr; + ECDSA_SIG_get0(ecdsaSignature.data(), &r, &s); +#endif + + QCOMPARE(valueOf(r).toHex(), QByteArray("9f25ebfaf4b91e4c60a1683754c5dc076a3179753ef97d9f8cb01fe1dcd3b8c8")); + QCOMPARE(valueOf(s).toHex(), QByteArray("3e7a26602ab1f344be5706006d79a9ff6a9716404dc83b9f30e1213b393128a2")); } @@ -142,20 +152,20 @@ class test_CVCertificate 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")); + 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; + QSharedPointer cvcsNonConst = qSharedPointerConstCast(cvca); + qDebug() << cvcsNonConst; QCOMPARE(spy.count(), 1); param = spy.takeFirst(); QVERIFY(param.at(0).toString().contains(output)); - QVector > cvcsVector({cvca}); + QVector > cvcsVector({cvca}); qDebug() << cvcsVector; QCOMPARE(spy.count(), 1); param = spy.takeFirst(); @@ -171,18 +181,33 @@ class test_CVCertificate 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 = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + QSharedPointer cvca2_const = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + QSharedPointer cvca1 = qSharedPointerConstCast(cvca1_const); + QSharedPointer cvca2 = qSharedPointerConstCast(cvca2_const); - QSharedPointer cvca1_const = cvca1; - QSharedPointer cvca2_const = cvca2; - QVERIFY(cvca1_const == cvca2_const); + QVERIFY(*cvca1 == *cvca2); + QVERIFY(*cvca1_const == *cvca2_const); + QVERIFY(*cvca1 == *cvca2_const); + QVERIFY(*cvca2_const == *cvca1); + QVERIFY(*cvca1_const == *cvca2); + QVERIFY(*cvca2 == *cvca1_const); + } - QVERIFY(cvca1 == cvca2_const); - QVERIFY(cvca2_const == cvca1); - QVERIFY(cvca1_const == cvca2); - QVERIFY(cvca2 == cvca1_const); + + void notEquals() + { + QSharedPointer cvca1_const = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00001.hex")); + QSharedPointer cvca2_const = CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DETESTeID00002.hex")); + QSharedPointer cvca1 = qSharedPointerConstCast(cvca1_const); + QSharedPointer cvca2 = qSharedPointerConstCast(cvca2_const); + + QVERIFY(*cvca1 != *cvca2); + QVERIFY(*cvca1_const != *cvca2_const); + QVERIFY(*cvca1 != *cvca2_const); + QVERIFY(*cvca2_const != *cvca1); + QVERIFY(*cvca1_const != *cvca2); + QVERIFY(*cvca2 != *cvca1_const); } diff --git a/test/qt/card/asn1/test_CVCertificateBody.cpp b/test/qt/card/asn1/test_CVCertificateBody.cpp index bb5df92..6656897 100644 --- a/test/qt/card/asn1/test_CVCertificateBody.cpp +++ b/test/qt/card/asn1/test_CVCertificateBody.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref CVCertificateBody * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -48,8 +48,10 @@ class test_CVCertificateBody QByteArray expectedDescription = QByteArray::fromHex("12CA9D0A51DF9297EABA7EBE9AB49DF2F4CF83E0DBB02772EFAD89C8AD75FCCD"); QByteArray expectedSector = QByteArray::fromHex("CB1E1940159F11DC96845B87C23B86F9BAA755A789A914BBD5B8FA9784019D1C"); - QCOMPARE(cvc->getBody().getExtensions().value(KnownOIDs::CertificateExtensions::id_description), expectedDescription); - QCOMPARE(cvc->getBody().getExtensions().value(KnownOIDs::CertificateExtensions::id_sector), expectedSector); + const auto idDesc = KnownOIDs::CertificateExtensions::ID_DESCRIPTION; + QCOMPARE(cvc->getBody().getExtensions().value(toByteArray(idDesc)), expectedDescription); + const auto idSector = KnownOIDs::CertificateExtensions::ID_SECTOR; + QCOMPARE(cvc->getBody().getExtensions().value(toByteArray(idSector)), expectedSector); } diff --git a/test/qt/card/asn1/test_CVCertificateChainBuilder.cpp b/test/qt/card/asn1/test_CVCertificateChainBuilder.cpp index a0de1ab..d643f15 100644 --- a/test/qt/card/asn1/test_CVCertificateChainBuilder.cpp +++ b/test/qt/card/asn1/test_CVCertificateChainBuilder.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref CVCertificateChain * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -18,18 +18,18 @@ class test_CVCertificateChainBuilder : public QObject { Q_OBJECT - QSharedPointer mCvca_DETESTeID00001; - QSharedPointer mCvca_DETESTeID00002_DETESTeID00001; - QSharedPointer mCvca_DETESTeID00002; - QSharedPointer mCvca_DETESTeID00004_DETESTeID00002; - QSharedPointer mCvca_DETESTeID00004; - QSharedPointer mCvdv_DEDVeIDDPST00035; - QSharedPointer mCvat_DEDEMODEV00038; + QSharedPointer mCvca_DETESTeID00001; + QSharedPointer mCvca_DETESTeID00002_DETESTeID00001; + QSharedPointer mCvca_DETESTeID00002; + QSharedPointer mCvca_DETESTeID00004_DETESTeID00002; + QSharedPointer mCvca_DETESTeID00004; + QSharedPointer mCvdv_DEDVeIDDPST00035; + QSharedPointer mCvat_DEDEMODEV00038; - QSharedPointer mCvca_DETESTeID00005_DETESTeID00004; - QSharedPointer mCvca_DETESTeID00005; - QSharedPointer mCvdv_DEDVtIDGVNK00005; - QSharedPointer mCvat_DEDEVDEMO00020; + QSharedPointer mCvca_DETESTeID00005_DETESTeID00004; + QSharedPointer mCvca_DETESTeID00005; + QSharedPointer mCvdv_DEDVtIDGVNK00005; + QSharedPointer mCvat_DEDEVDEMO00020; QByteArray readFile(const QString& pFileName) @@ -41,7 +41,7 @@ class test_CVCertificateChainBuilder /*! * Creates an object of EstablishPACEChannelOutput with CARcurr, and CARprev equal to */ - static EstablishPACEChannelOutput createPaceOutput(QSharedPointer pCvcCarCurr, QSharedPointer pCvcCarPrev) + static EstablishPACEChannelOutput createPaceOutput(QSharedPointer pCvcCarCurr, QSharedPointer pCvcCarPrev) { EstablishPACEChannelOutput output; if (pCvcCarCurr != nullptr) @@ -108,7 +108,7 @@ class test_CVCertificateChainBuilder void noDV_getChainStartingWith() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -128,7 +128,7 @@ class test_CVCertificateChainBuilder void noDV_getChainForCertificationAuthority() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -148,7 +148,7 @@ class test_CVCertificateChainBuilder void noAT_getChainStartingWith() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -168,7 +168,7 @@ class test_CVCertificateChainBuilder void noAT_getChainForCertificationAuthority() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -188,7 +188,7 @@ class test_CVCertificateChainBuilder void onlyATandDV_getChainStartingWith() { - QVector > list; + QVector > list; // list.append(mCvca_DETESTeID00005); // list.append(mCvca_DETESTeID00005_DETESTeID00004); do not include any CVCA certificates // list.append(mCvca_DETESTeID00004); @@ -208,7 +208,7 @@ class test_CVCertificateChainBuilder void onlyATandDV_getChainForCertificationAuthority() { - QVector > list; + QVector > list; // list.append(mCvca_DETESTeID00005); // list.append(mCvca_DETESTeID00005_DETESTeID00004); do not include any CVCA certificates // list.append(mCvca_DETESTeID00004); @@ -228,7 +228,7 @@ class test_CVCertificateChainBuilder void missingLinkCert_getChainStartingWith() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -253,7 +253,7 @@ class test_CVCertificateChainBuilder void missingLinkCert_getChainForCertificationAuthority() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -291,7 +291,7 @@ class test_CVCertificateChainBuilder */ void match_getChainStartingWith() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -316,7 +316,7 @@ class test_CVCertificateChainBuilder void match_getChainForCertificationAuthority() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -341,7 +341,7 @@ class test_CVCertificateChainBuilder void noMatch_getChainStartingWith() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -361,7 +361,7 @@ class test_CVCertificateChainBuilder void noMatch_getChainForCertificationAuthority() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -381,7 +381,7 @@ class test_CVCertificateChainBuilder void getChainForCertificationAuthority_forCarCurr() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); @@ -404,7 +404,7 @@ class test_CVCertificateChainBuilder void getChainForCertificationAuthority_forCarPrev() { - QVector > list; + QVector > list; list.append(mCvca_DETESTeID00005); list.append(mCvca_DETESTeID00005_DETESTeID00004); list.append(mCvca_DETESTeID00004); diff --git a/test/qt/card/asn1/test_CertificateDescription.cpp b/test/qt/card/asn1/test_CertificateDescription.cpp index f7be159..63949ea 100644 --- a/test/qt/card/asn1/test_CertificateDescription.cpp +++ b/test/qt/card/asn1/test_CertificateDescription.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref CertificateDescription * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -19,22 +19,22 @@ using namespace governikus; namespace { -const QByteArray HEX_STRING("30 8202E0" - " 06 0A 04007F00070301030101" - " A1 0E 0C0C442D547275737420476D6248" - " A2 18 1316687474703A2F2F7777772E642D74727573742E6E6574" - " A3 19 0C17476F7665726E696B757320476D6248202620436F2E4B47" - " A4 1A 131868747470733A2F2F7777772E617574656E746170702E6465" - " A5 820205" - " 0C 820201 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476F7665726E696B757320476D6248202620436F2E4B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E0D0A6B6F6E74616B7440676F7665726E696B75732E636F6D0D0A0D0A4765736368C3A46674737A7765636B3A0D0A53656C6273746175736B756E66740D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A446572204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656E0D0A303432312F3336312D323031300D0A6F666669636540646174656E73636875747A2E6272656D656E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2E6272656D656E2E64650D0A" - " A7 68" - " 31 66" - " 04 20 29F04459C39E4B68C70AA3961FA7B1B40E8A49238446CFE606C56FF8DC0989F4" - " 04 20 3FFF612368211F69D460DFF157F541BEBC96217D7AF6C2D4F57BF6E4A126A86C" - " 04 20 9D8EB0BDF36B19C4AF3147E57401FD792845F0413102A7BD784DF9418098BEBE" - ""); +const char* HEX_STRING("30 8202E0" + " 06 0A 04007F00070301030101" + " A1 0E 0C0C442D547275737420476D6248" + " A2 18 1316687474703A2F2F7777772E642D74727573742E6E6574" + " A3 19 0C17476F7665726E696B757320476D6248202620436F2E4B47" + " A4 1A 131868747470733A2F2F7777772E617574656E746170702E6465" + " A5 820205" + " 0C 820201 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476F7665726E696B757320476D6248202620436F2E4B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E0D0A6B6F6E74616B7440676F7665726E696B75732E636F6D0D0A0D0A4765736368C3A46674737A7765636B3A0D0A53656C6273746175736B756E66740D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A446572204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656E0D0A303432312F3336312D323031300D0A6F666669636540646174656E73636875747A2E6272656D656E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2E6272656D656E2E64650D0A" + " A7 68" + " 31 66" + " 04 20 29F04459C39E4B68C70AA3961FA7B1B40E8A49238446CFE606C56FF8DC0989F4" + " 04 20 3FFF612368211F69D460DFF157F541BEBC96217D7AF6C2D4F57BF6E4A126A86C" + " 04 20 9D8EB0BDF36B19C4AF3147E57401FD792845F0413102A7BD784DF9418098BEBE" + ""); -const QByteArray SELF_AUTH_CERT_2017("308202e6060a04007f00070301030101a10e0c0c442d547275737420476d6248a2181316687474703a2f2f7777772e642d74727573742e6e6574a31a0c18476f7665726e696b757320476d6248202620436f2e204b47a41a131868747470733a2f2f7777772e617574656e746170702e6465a582020a0c820206efbbbf4e616d652c20416e7363687269667420756e6420452d4d61696c2d4164726573736520646573204469656e737465616e626965746572733a0d0a476f7665726e696b757320476d6248202620436f2e204b470d0a416d2046616c6c7475726d20390d0a3238333539204272656d656e0d0a6b6f6e74616b7440676f7665726e696b75732e636f6d0d0a0d0a4765736368c3a46674737a7765636b3a200d0a53656c6273746175736b756e66740d0a0d0a48696e7765697320617566206469652066c3bc722064656e204469656e737465616e626965746572207a757374c3a46e646967656e205374656c6c656e2c20646965206469652045696e68616c74756e672064657220566f7273636872696674656e207a756d20446174656e73636875747a206b6f6e74726f6c6c696572656e3a0d0a446965204c616e64657362656175667472616774652066c3bc7220446174656e73636875747a20756e6420496e666f726d6174696f6e736672656968656974206465722046726569656e2048616e73657374616474204272656d656e0d0a41726e647473747261c39f6520310d0a3237353730204272656d6572686176656e0d0a303432312f3539362d323031300d0a6f666669636540646174656e73636875747a2e6272656d656e2e64650d0a687474703a2f2f7777772e646174656e73636875747a2e6272656d656e2e64650d0aa76831660420a30a9a4617dc153926f731064043bba624b0cdd3b458ed8723c1cda33f1ffdd70420ab9fce5da4ba24d0b2664450fcced618f68fe9cbcdc4ee6e0bb0c59bd2aa86b60420fbf9f26b56b74cdf1c6e5cb1811bec1a8283a174c629b1974de17dc058b31bda"); +const char* SELF_AUTH_CERT_2017 = "308202e6060a04007f00070301030101a10e0c0c442d547275737420476d6248a2181316687474703a2f2f7777772e642d74727573742e6e6574a31a0c18476f7665726e696b757320476d6248202620436f2e204b47a41a131868747470733a2f2f7777772e617574656e746170702e6465a582020a0c820206efbbbf4e616d652c20416e7363687269667420756e6420452d4d61696c2d4164726573736520646573204469656e737465616e626965746572733a0d0a476f7665726e696b757320476d6248202620436f2e204b470d0a416d2046616c6c7475726d20390d0a3238333539204272656d656e0d0a6b6f6e74616b7440676f7665726e696b75732e636f6d0d0a0d0a4765736368c3a46674737a7765636b3a200d0a53656c6273746175736b756e66740d0a0d0a48696e7765697320617566206469652066c3bc722064656e204469656e737465616e626965746572207a757374c3a46e646967656e205374656c6c656e2c20646965206469652045696e68616c74756e672064657220566f7273636872696674656e207a756d20446174656e73636875747a206b6f6e74726f6c6c696572656e3a0d0a446965204c616e64657362656175667472616774652066c3bc7220446174656e73636875747a20756e6420496e666f726d6174696f6e736672656968656974206465722046726569656e2048616e73657374616474204272656d656e0d0a41726e647473747261c39f6520310d0a3237353730204272656d6572686176656e0d0a303432312f3539362d323031300d0a6f666669636540646174656e73636875747a2e6272656d656e2e64650d0a687474703a2f2f7777772e646174656e73636875747a2e6272656d656e2e64650d0aa76831660420a30a9a4617dc153926f731064043bba624b0cdd3b458ed8723c1cda33f1ffdd70420ab9fce5da4ba24d0b2664450fcced618f68fe9cbcdc4ee6e0bb0c59bd2aa86b60420fbf9f26b56b74cdf1c6e5cb1811bec1a8283a174c629b1974de17dc058b31bda"; } @@ -316,7 +316,11 @@ class test_CertificateDescription QVERIFY(byteBuf.contains("Name, Anschrift und E-Mail-Adresse des Diensteanbieters:")); } +#if OPENSSL_VERSION_NUMBER < 0x10100000L certDescr->mCommCertificates = SKM_sk_new(ASN1_OCTET_STRING, 0); +#else + certDescr->mCommCertificates = sk_ASN1_OCTET_STRING_new(0); +#endif QByteArrayList commCertBytes; commCertBytes.append(QByteArray::fromHex("94B0AA7E8114F3E6DFCD52DA9F43E8B13CCB0589B8957E364728198FB4971AE6")); commCertBytes.append(QByteArray::fromHex("E85E1E8A78864E9246C86CF1C2A3810603EEEE75746C70CD51ACB86B5E2655D8")); @@ -326,12 +330,16 @@ class test_CertificateDescription { ASN1_OCTET_STRING* octetString = ASN1_OCTET_STRING_new(); ASN1_OCTET_STRING_set(octetString, reinterpret_cast(commCertByte.constData()), commCertByte.length()); +#if OPENSSL_VERSION_NUMBER < 0x10100000L SKM_sk_push(ASN1_OCTET_STRING, certDescr->mCommCertificates, octetString); +#else + sk_ASN1_OCTET_STRING_push(certDescr->mCommCertificates, octetString); +#endif } { - for (int i = 0; i < certDescr->mCommCertificates->stack.num; i++) + for (int i = 0; i < sk_ASN1_OCTET_STRING_num(certDescr->mCommCertificates); i++) { - ASN1_OCTET_STRING* octetString = SKM_sk_value(ASN1_OCTET_STRING, certDescr->mCommCertificates, i); + ASN1_OCTET_STRING* octetString = sk_ASN1_OCTET_STRING_value(certDescr->mCommCertificates, i); QByteArray byteBuf(reinterpret_cast(octetString->data), octetString->length); QVERIFY(!byteBuf.isEmpty()); } diff --git a/test/qt/card/asn1/test_ChainBuilder.cpp b/test/qt/card/asn1/test_ChainBuilder.cpp index ac16c99..c28164b 100644 --- a/test/qt/card/asn1/test_ChainBuilder.cpp +++ b/test/qt/card/asn1/test_ChainBuilder.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref ChainBuilder * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/asn1/test_Chat.cpp b/test/qt/card/asn1/test_Chat.cpp index 977ae50..8078569 100644 --- a/test/qt/card/asn1/test_Chat.cpp +++ b/test/qt/card/asn1/test_Chat.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref CHAT * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ASN1Util.h" diff --git a/test/qt/card/asn1/test_ChipAuthenticationInfo.cpp b/test/qt/card/asn1/test_ChipAuthenticationInfo.cpp index 973af56..41cad21 100644 --- a/test/qt/card/asn1/test_ChipAuthenticationInfo.cpp +++ b/test/qt/card/asn1/test_ChipAuthenticationInfo.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref ChipAuthenticationInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/asn1/test_EcdsaPublicKey.cpp b/test/qt/card/asn1/test_EcdsaPublicKey.cpp index f50613b..aa616a3 100644 --- a/test/qt/card/asn1/test_EcdsaPublicKey.cpp +++ b/test/qt/card/asn1/test_EcdsaPublicKey.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref EcdsaPublicKey * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/CVCertificate.h" diff --git a/test/qt/card/asn1/test_KnownOIDs.cpp b/test/qt/card/asn1/test_KnownOIDs.cpp new file mode 100644 index 0000000..37bc7dc --- /dev/null +++ b/test/qt/card/asn1/test_KnownOIDs.cpp @@ -0,0 +1,105 @@ +/*! + * \brief Unit tests for \ref KnownOIDs + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "asn1/KnownOIDs.h" + +#include +#include + +using namespace governikus; + +class test_KnownOIDs + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void values_data() + { + QTest::addColumn("id"); + QTest::addColumn("expected"); + + QTest::newRow("base_bsi_de") << toByteArray(KnownOIDs::Base::BSI_DE) << QByteArray("0.4.0.127.0.7"); + QTest::newRow("base_signed_data") << toByteArray(KnownOIDs::Base::SIGNED_DATA) << QByteArray("1.2.840.113549.1.7.2"); + QTest::newRow("base_id_security_object") << toByteArray(KnownOIDs::Base::ID_SECURITY_OBJECT) << QByteArray("0.4.0.127.0.7.3.2.1"); + QTest::newRow("base_id_extensions") << toByteArray(KnownOIDs::Base::ID_EXTENSIONS) << QByteArray("0.4.0.127.0.7.3.1.3"); + + QTest::newRow("id_description") << toByteArray(KnownOIDs::CertificateExtensions::ID_DESCRIPTION) << QByteArray("0.4.0.127.0.7.3.1.3.1"); + QTest::newRow("id_sector") << toByteArray(KnownOIDs::CertificateExtensions::ID_SECTOR) << QByteArray("0.4.0.127.0.7.3.1.3.2"); + + QTest::newRow("id_plainFormat") << toByteArray(KnownOIDs::TermsOfUsageType::ID_PLAIN_FORMAT) << QByteArray("0.4.0.127.0.7.3.1.3.1.1"); + QTest::newRow("id_htmlFormat") << toByteArray(KnownOIDs::TermsOfUsageType::ID_HTML_FORMAT) << QByteArray("0.4.0.127.0.7.3.1.3.1.2"); + QTest::newRow("id_pdfFormat") << toByteArray(KnownOIDs::TermsOfUsageType::ID_PDF_FORMAT) << QByteArray("0.4.0.127.0.7.3.1.3.1.3"); + + QTest::newRow("id_IS") << toByteArray(KnownOIDs::CHATType::ID_IS) << QByteArray("0.4.0.127.0.7.3.1.2.1"); + QTest::newRow("id_AT") << toByteArray(KnownOIDs::CHATType::ID_AT) << QByteArray("0.4.0.127.0.7.3.1.2.2"); + QTest::newRow("id_ST") << toByteArray(KnownOIDs::CHATType::ID_ST) << QByteArray("0.4.0.127.0.7.3.1.2.3"); + + QTest::newRow("id_DateOfBirth") << toByteArray(KnownOIDs::AuxilaryData::ID_DATE_OF_BIRTH) << QByteArray("0.4.0.127.0.7.3.1.4.1"); + QTest::newRow("id_DateOfExpiry") << toByteArray(KnownOIDs::AuxilaryData::ID_DATE_OF_EXPIRY) << QByteArray("0.4.0.127.0.7.3.1.4.2"); + QTest::newRow("id_CommunityID") << toByteArray(KnownOIDs::AuxilaryData::ID_COMMUNITY_ID) << QByteArray("0.4.0.127.0.7.3.1.4.3"); + + QTest::newRow("SecurityProtocol::id_PK") << toByteArray(KnownOIDs::SecurityProtocol::ID_PK) << QByteArray("0.4.0.127.0.7.2.2.1"); + QTest::newRow("SecurityProtocol::id_TA") << toByteArray(KnownOIDs::SecurityProtocol::ID_TA) << QByteArray("0.4.0.127.0.7.2.2.2"); + QTest::newRow("SecurityProtocol::id_CA") << toByteArray(KnownOIDs::SecurityProtocol::ID_CA) << QByteArray("0.4.0.127.0.7.2.2.3"); + QTest::newRow("SecurityProtocol::id_PACE") << toByteArray(KnownOIDs::SecurityProtocol::ID_PACE) << QByteArray("0.4.0.127.0.7.2.2.4"); + + QTest::newRow("id_CA::DH") << toByteArray(KnownOIDs::id_ca::DH) << QByteArray("0.4.0.127.0.7.2.2.3.1"); + QTest::newRow("id_CA::DH_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_ca::DH_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.3.1.1"); + QTest::newRow("id_CA::DH_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_ca::DH_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.3.1.2"); + QTest::newRow("id_CA::DH_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_ca::DH_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.3.1.3"); + QTest::newRow("id_CA::DH_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_ca::DH_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.3.1.4"); + QTest::newRow("id_CA::ECDH") << toByteArray(KnownOIDs::id_ca::ECDH) << QByteArray("0.4.0.127.0.7.2.2.3.2"); + QTest::newRow("id_CA::ECDH_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_ca::ECDH_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.3.2.1"); + QTest::newRow("id_CA::ECDH_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_ca::ECDH_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.3.2.2"); + QTest::newRow("id_CA::ECDH_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_ca::ECDH_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.3.2.3"); + QTest::newRow("id_CA::ECDH_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_ca::ECDH_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.3.2.4"); + + QTest::newRow("id_TA::ECDSA_SHA_1") << toByteArray(KnownOIDs::id_ta::ECDSA_SHA_1) << QByteArray("0.4.0.127.0.7.2.2.2.2.1"); + QTest::newRow("id_TA::ECDSA_SHA_224") << toByteArray(KnownOIDs::id_ta::ECDSA_SHA_224) << QByteArray("0.4.0.127.0.7.2.2.2.2.2"); + QTest::newRow("id_TA::ECDSA_SHA_256") << toByteArray(KnownOIDs::id_ta::ECDSA_SHA_256) << QByteArray("0.4.0.127.0.7.2.2.2.2.3"); + QTest::newRow("id_TA::ECDSA_SHA_384") << toByteArray(KnownOIDs::id_ta::ECDSA_SHA_384) << QByteArray("0.4.0.127.0.7.2.2.2.2.4"); + QTest::newRow("id_TA::ECDSA_SHA_512") << toByteArray(KnownOIDs::id_ta::ECDSA_SHA_512) << QByteArray("0.4.0.127.0.7.2.2.2.2.5"); + + QTest::newRow("id_PK::DH") << toByteArray(KnownOIDs::id_pk::DH) << QByteArray("0.4.0.127.0.7.2.2.1.1"); + QTest::newRow("id_PK::ECDH") << toByteArray(KnownOIDs::id_pk::ECDH) << QByteArray("0.4.0.127.0.7.2.2.1.2"); + + QTest::newRow("id_PACE::DH::GM") << toByteArray(KnownOIDs::id_PACE::DH::GM) << QByteArray("0.4.0.127.0.7.2.2.4.1"); + QTest::newRow("id_PACE::DH::GM_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_PACE::DH::GM_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.4.1.1"); + QTest::newRow("id_PACE::DH::GM_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_PACE::DH::GM_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.4.1.2"); + QTest::newRow("id_PACE::DH::GM_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_PACE::DH::GM_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.4.1.3"); + QTest::newRow("id_PACE::DH::GM_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_PACE::DH::GM_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.4.1.4"); + QTest::newRow("id_PACE::DH::IM") << toByteArray(KnownOIDs::id_PACE::DH::IM) << QByteArray("0.4.0.127.0.7.2.2.4.3"); + QTest::newRow("id_PACE::DH::IM_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_PACE::DH::IM_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.4.3.1"); + QTest::newRow("id_PACE::DH::IM_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_PACE::DH::IM_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.4.3.2"); + QTest::newRow("id_PACE::DH::IM_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_PACE::DH::IM_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.4.3.3"); + QTest::newRow("id_PACE::DH::IM_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_PACE::DH::IM_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.4.3.4"); + + QTest::newRow("id_PACE::ECDH::GM") << toByteArray(KnownOIDs::id_PACE::ECDH::GM) << QByteArray("0.4.0.127.0.7.2.2.4.2"); + QTest::newRow("id_PACE::ECDH::GM_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.4.2.1"); + QTest::newRow("id_PACE::ECDH::GM_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.4.2.2"); + QTest::newRow("id_PACE::ECDH::GM_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.4.2.3"); + QTest::newRow("id_PACE::ECDH::GM_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.4.2.4"); + QTest::newRow("id_PACE::ECDH::IM") << toByteArray(KnownOIDs::id_PACE::ECDH::IM) << QByteArray("0.4.0.127.0.7.2.2.4.4"); + QTest::newRow("id_PACE::ECDH::IM_3DES_CBC_CBC") << toByteArray(KnownOIDs::id_PACE::ECDH::IM_3DES_CBC_CBC) << QByteArray("0.4.0.127.0.7.2.2.4.4.1"); + QTest::newRow("id_PACE::ECDH::IM_AES_CBC_CMAC_128") << toByteArray(KnownOIDs::id_PACE::ECDH::IM_AES_CBC_CMAC_128) << QByteArray("0.4.0.127.0.7.2.2.4.4.2"); + QTest::newRow("id_PACE::ECDH::IM_AES_CBC_CMAC_192") << toByteArray(KnownOIDs::id_PACE::ECDH::IM_AES_CBC_CMAC_192) << QByteArray("0.4.0.127.0.7.2.2.4.4.3"); + QTest::newRow("id_PACE::ECDH::IM_AES_CBC_CMAC_256") << toByteArray(KnownOIDs::id_PACE::ECDH::IM_AES_CBC_CMAC_256) << QByteArray("0.4.0.127.0.7.2.2.4.4.4"); + } + + + void values() + { + QFETCH(QByteArray, id); + QFETCH(QByteArray, expected); + QCOMPARE(id, expected); + } + + +}; + +QTEST_GUILESS_MAIN(test_KnownOIDs) +#include "test_KnownOIDs.moc" diff --git a/test/qt/card/asn1/test_PACEInfo.cpp b/test/qt/card/asn1/test_PACEInfo.cpp index 69bf99b..8221d90 100644 --- a/test/qt/card/asn1/test_PACEInfo.cpp +++ b/test/qt/card/asn1/test_PACEInfo.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref PACEInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -98,15 +98,28 @@ class test_PACEInfo void getVersion() { - QByteArray bytes = QByteArray::fromHex("30 12" - " 06 0A 04007F00070202040202" - " 02 01 02" - " 02 01 08"); + QByteArray bytes; + QSharedPointer paceInfo; - auto paceInfo = PACEInfo::decode(bytes); + bytes = QByteArray::fromHex("30 12" + " 06 0A 04007F00070202040202" + " 02 01 01" + " 02 01 08"); + + paceInfo = PACEInfo::decode(bytes); QVERIFY(paceInfo != nullptr); - QCOMPARE(paceInfo->getVersion(), QByteArray::fromHex("02")); + QCOMPARE(paceInfo->getVersion(), 1); + + bytes = QByteArray::fromHex("30 12" + " 06 0A 04007F00070202040202" + " 02 01 02" + " 02 01 08"); + + paceInfo = PACEInfo::decode(bytes); + + QVERIFY(paceInfo != nullptr); + QCOMPARE(paceInfo->getVersion(), 2); } diff --git a/test/qt/card/asn1/test_SecurityInfo.cpp b/test/qt/card/asn1/test_SecurityInfo.cpp index 643e183..3bb2b68 100644 --- a/test/qt/card/asn1/test_SecurityInfo.cpp +++ b/test/qt/card/asn1/test_SecurityInfo.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref SecurityInfo * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ diff --git a/test/qt/card/asn1/test_SecurityInfos.cpp b/test/qt/card/asn1/test_SecurityInfos.cpp index 7336292..75ef5a4 100644 --- a/test/qt/card/asn1/test_SecurityInfos.cpp +++ b/test/qt/card/asn1/test_SecurityInfos.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref SecurityInfos * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/asn1/test_SignatureChecker.cpp b/test/qt/card/asn1/test_SignatureChecker.cpp index 2af5bb0..22db88d 100644 --- a/test/qt/card/asn1/test_SignatureChecker.cpp +++ b/test/qt/card/asn1/test_SignatureChecker.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref SignatureChecker * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -29,9 +29,9 @@ class test_SignatureChecker { Q_OBJECT - QVector > cvcs; + QVector > cvcs; - static QSharedPointer load(const QString& pName) + static QSharedPointer load(const QString& pName) { QByteArray bytes = TestFileHelper::readFile(pName); return CVCertificate::fromHex(bytes); @@ -52,7 +52,7 @@ class test_SignatureChecker void verifyEmptyList() { - QVector > certs; + QVector > certs; SignatureChecker checker(certs); QVERIFY(!checker.check()); @@ -61,7 +61,7 @@ class test_SignatureChecker void verifyNotSelfSigned() { - QVector > certs(cvcs); + QVector > certs(cvcs); certs.removeAt(0); SignatureChecker checker(certs); @@ -71,7 +71,7 @@ class test_SignatureChecker void verifyNoCertificateWithCurveParameters() { - QVector > certs(cvcs); + QVector > certs(cvcs); certs.removeAt(2); certs.removeAt(1); certs.removeAt(0); @@ -83,7 +83,7 @@ class test_SignatureChecker void verifyNoValidChain() { - QVector > certs(cvcs); + QVector > certs(cvcs); certs.removeAt(2); SignatureChecker checker(certs); diff --git a/test/qt/card/asn1/test_efCardAccess.cpp b/test/qt/card/asn1/test_efCardAccess.cpp index 222d880..f8e8849 100644 --- a/test/qt/card/asn1/test_efCardAccess.cpp +++ b/test/qt/card/asn1/test_efCardAccess.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/ChipAuthenticationInfo.h" diff --git a/test/qt/card/asn1/test_efCardSecurity.cpp b/test/qt/card/asn1/test_efCardSecurity.cpp index b963f62..89b2b48 100644 --- a/test/qt/card/asn1/test_efCardSecurity.cpp +++ b/test/qt/card/asn1/test_efCardSecurity.cpp @@ -1,7 +1,5 @@ /*! - * test_efCardSecurity.cpp - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/EFCardSecurity.h" diff --git a/test/qt/card/base/command/test_BaseCardCommand.cpp b/test/qt/card/base/command/test_BaseCardCommand.cpp index 61b64fd..9a4c0e0 100644 --- a/test/qt/card/base/command/test_BaseCardCommand.cpp +++ b/test/qt/card/base/command/test_BaseCardCommand.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref BaseCardCommand * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "command/BaseCardCommand.h" @@ -26,7 +26,7 @@ class BaseCardCommandDummy } - virtual void internalExecute() + virtual void internalExecute() override { mReturnCode = CardReturnCode::OK; } diff --git a/test/qt/card/base/test_Apdu.cpp b/test/qt/card/base/test_Apdu.cpp new file mode 100644 index 0000000..102bdda --- /dev/null +++ b/test/qt/card/base/test_Apdu.cpp @@ -0,0 +1,70 @@ +/*! + * \brief Unit tests for \ref Apdu + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Apdu.h" + +#include +#include + + +using namespace governikus; + + +class test_Apdu + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void testRetryCounter0() + { + ResponseApdu apdu(QByteArray::fromHex("9000")); + QCOMPARE(apdu.getRetryCounter(), 3); + + apdu.setBuffer(QByteArray::fromHex("63c2")); + QCOMPARE(apdu.getRetryCounter(), 2); + + apdu.setBuffer(QByteArray::fromHex("63c1")); + QCOMPARE(apdu.getRetryCounter(), 1); + + apdu.setBuffer(QByteArray::fromHex("63c0")); + QCOMPARE(apdu.getRetryCounter(), 0); + + apdu.setBuffer(QByteArray::fromHex("6400")); + QCOMPARE(apdu.getRetryCounter(), -1); + + apdu.setBuffer(QByteArray::fromHex("1234")); + QCOMPARE(apdu.getRetryCounter(), -1); + + apdu.setBuffer(QByteArray::fromHex("12")); + QCOMPARE(apdu.getRetryCounter(), -1); + + apdu.setBuffer(QByteArray()); + QCOMPARE(apdu.getRetryCounter(), -1); + } + + + void testReturnCode() + { + ResponseApdu apdu = ResponseApdu(QByteArray()); + QCOMPARE(apdu.getReturnCode(), StatusCode::EMPTY); + + apdu.setBuffer(QByteArray::fromHex("01")); + QCOMPARE(apdu.getReturnCode(), StatusCode::INVALID); + + apdu.setBuffer(QByteArray::fromHex("73c2")); + QCOMPARE(apdu.getReturnCode(), StatusCode::INVALID); + + apdu.setBuffer(QByteArray::fromHex("63c2")); + QCOMPARE(apdu.getReturnCode(), StatusCode::PIN_RETRY_COUNT_2); + } + + +}; + + +QTEST_GUILESS_MAIN(test_Apdu) +#include "test_Apdu.moc" diff --git a/test/qt/card/bluetooth/test_BluetoothMessage.cpp b/test/qt/card/bluetooth/test_BluetoothMessage.cpp new file mode 100644 index 0000000..705a0d1 --- /dev/null +++ b/test/qt/card/bluetooth/test_BluetoothMessage.cpp @@ -0,0 +1,39 @@ +/*! + * \brief Unit tests for \ref BluetoothMessage + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "messages/BluetoothMessageStatusInd.h" +#include +#include + +using namespace governikus; + +class test_BluetoothMessage + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void statusIndCtor() + { + BluetoothMessageStatusInd msg; + QCOMPARE(msg.getBluetoothMsgId(), BluetoothMsgId::StatusInd); + } + + + void statusIndStatusChange() + { + BluetoothMessageParameterStatusChange param(QByteArray(1, Enum::getValue(BluetoothStatusChange::CardRecovered))); + BluetoothMessageStatusInd msg; + msg.copyParameter(param); + + QCOMPARE(msg.getStatusChange(), BluetoothStatusChange::CardRecovered); + } + + +}; + +QTEST_GUILESS_MAIN(test_BluetoothMessage) +#include "test_BluetoothMessage.moc" diff --git a/test/qt/card/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp b/test/qt/card/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp new file mode 100644 index 0000000..8a30a8d --- /dev/null +++ b/test/qt/card/bluetooth/test_BluetoothMessageParameterMaxMsgSize.cpp @@ -0,0 +1,56 @@ +/*! + * \brief Unit tests for \ref BluetoothMessageParameterMaxMsgSize * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "messages/parameter/BluetoothMessageParameterMaxMsgSize.h" +#include +#include + +using namespace governikus; + +class test_BluetoothMessageParameterMaxMsgSize + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + /* + * The value is a 2 byte big endian. So perform some tests. + */ + void createWithByteArray() + { + BluetoothMessageParameterMaxMsgSize param(QByteArray::fromHex("0100")); + QCOMPARE(param.getMaxMsgSize(), static_cast(256)); + QCOMPARE(param.getValue(), QByteArray::fromHex("0100")); + } + + + void createWithByteArray_tooBig() + { + BluetoothMessageParameterMaxMsgSize param(QByteArray::fromHex("010000")); + QCOMPARE(param.getMaxMsgSize(), static_cast(0)); + QCOMPARE(param.getValue(), QByteArray("")); + } + + + void createWithInt() + { + BluetoothMessageParameterMaxMsgSize param(256); + QCOMPARE(param.getValue().toHex(), QByteArray("0100")); + QCOMPARE(param.getMaxMsgSize(), static_cast(256)); + } + + + void createWithInt_tooBig() + { + BluetoothMessageParameterMaxMsgSize param(0x010000); + QCOMPARE(param.getValue().toHex(), QByteArray("")); + QCOMPARE(param.getMaxMsgSize(), static_cast(0)); + } + + +}; + +QTEST_GUILESS_MAIN(test_BluetoothMessageParameterMaxMsgSize) +#include "test_BluetoothMessageParameterMaxMsgSize.moc" diff --git a/test/qt/card/bluetooth/test_BluetoothMessageParser.cpp b/test/qt/card/bluetooth/test_BluetoothMessageParser.cpp new file mode 100644 index 0000000..9f03c31 --- /dev/null +++ b/test/qt/card/bluetooth/test_BluetoothMessageParser.cpp @@ -0,0 +1,194 @@ +/*! + * \brief Unit tests for \ref BluetoothMessageParser + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "messages/BluetoothMessageParser.h" +#include "messages/BluetoothMessageStatusInd.h" +#include "messages/parameter/BluetoothMessageParameterApduResponse.h" +#include "messages/parameter/BluetoothMessageParameterStatusChange.h" +#include +#include + +using namespace governikus; + +class test_BluetoothMessageParser + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + } + + + void transferApduResponse() + { + QByteArray response; + response = + QByteArray::fromHex("060200000200000100000000050000fe3081f9a106040400000000a20404029000a381c43181c1300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020141302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145a42204209ee959c9f063c6e144b463e04fa19ef44da0f5059d817a7db2240bbee8b218a290000000"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 1); + BluetoothMessage::Ptr message = parser1.getMessages().at(0); + + QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::TransferApduResponse); + QCOMPARE(message->mMessageParameter.size(), 2); + + const auto& params = message->mMessageParameter; + QCOMPARE(params.first()->getParameterId(), BluetoothParamId::ResultCode); + QCOMPARE(params.first()->getValue(), QByteArray(1, Enum::getValue(BluetoothResultCode::Ok))); + + const auto param = params.last(); + QCOMPARE(param->getParameterId(), BluetoothParamId::ResponseAPDU); + const auto paramApdu = param.staticCast(); + QCOMPARE(paramApdu->getResponseApdu(), + QByteArray::fromHex("3081f9a106040400000000a20404029000a381c43181c1300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020204020202010202010d301c060904007f000702020302300c060704007f0007010202010d020141302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145a42204209ee959c9f063c6e144b463e04fa19ef44da0f5059d817a7db2240bbee8b218a29000")); + } + + + void messageToStringCasted() + { + QByteArray response; + response = QByteArray::fromHex("110100000800000102000000"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 1); + BluetoothMessage::Ptr message = parser1.getMessages().at(0); + + QCOMPARE(message->getBluetoothMsgId(), BluetoothMsgId::StatusInd); + auto msgInd = message.staticCast(); + QCOMPARE(msgInd->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardNotAccessible")); + QCOMPARE(msgInd->getStatusChange(), BluetoothStatusChange::CardNotAccessible); + } + + + void messageToString() + { + QByteArray response; + response = QByteArray::fromHex("110100000800000104000000110100000800000103000000"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 2); + QCOMPARE(parser1.getMessages().at(0)->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardInserted")); + QCOMPARE(parser1.getMessages().at(1)->toString(), QString("StatusInd | Parameter: StatusChange | Value: CardRemoved")); + } + + + void parseAtrReponse() + { + QByteArray response; + + response = QByteArray::fromHex("0802000002000001000000000600000f4b8a80018031f873f741e08290007500"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 1); + QCOMPARE(parser1.getRemainingBytes().size(), 0); + + QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::TransferAtrResponse); + QCOMPARE(parser1.getMessages()[0]->mMessageParameter.size(), 2); + + 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")); + } + + + void parseCardReaderStatusIndMultipleMessages() + { + QByteArray response; + + response = QByteArray::fromHex("110100000800000104000000110100000800000103000000"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 2); + QCOMPARE(parser1.getRemainingBytes().size(), 0); + + QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); + 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]->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))); + } + + + void parseCardReaderStatusInd() + { + QByteArray response; + + response = QByteArray::fromHex("110100000800000104000000"); + BluetoothMessageParser parser1(response); + QCOMPARE(parser1.getMessages().size(), 1); + QCOMPARE(parser1.getRemainingBytes().size(), 0); + QCOMPARE(parser1.getMessages()[0]->getBluetoothMsgId(), BluetoothMsgId::StatusInd); + 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]->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))); + } + + + void parseDisconnectResponse() + { + BluetoothMessageParser parser(QByteArray::fromHex("03000000")); + QCOMPARE(parser.getMessages().size(), 1); + QCOMPARE(parser.getMessages().at(0)->getBluetoothMsgId(), BluetoothMsgId::DisconnectResponse); + QVERIFY(parser.getRemainingBytes().isEmpty()); + } + + + void parseMessageParametersAsMultipleOfFour() + { + BluetoothMessageParser parser = BluetoothMessageParser(QByteArray::fromHex("060200000200000100000000050001153082010fa106040400000000a20404029000a381b63181b3300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007")); + QCOMPARE(parser.getMessages().size(), 0); + QCOMPARE(parser.getRemainingBytes().isEmpty(), false); + + parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("02020302020201020201453012060a04007f0007020204020202010202010d301c060904007f00070202"))); + QCOMPARE(parser.getMessages().size(), 0); + QCOMPARE(parser.getRemainingBytes().isEmpty(), false); + + parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0302300c060704007f0007010202010d020141301c060904007f000702020302300c060704007f0007010202010d020145302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369"))); + QCOMPARE(parser.getMessages().size(), 0); + QCOMPARE(parser.getRemainingBytes().isEmpty(), false); + + parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("662f6e70612e786d6ca422042065828281cc36f1bf6056748fa23ae95f7d73c6b52e5a5277d1bf48a66fd9a6c9a510040e4445435643416549443030313033a610040e4445435643416549443030313032900000"))); + QCOMPARE(parser.getMessages().size(), 0); + QCOMPARE(parser.getRemainingBytes().isEmpty(), false); + + parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0000"))); + QCOMPARE(parser.getMessages().size(), 1); + QCOMPARE(parser.getRemainingBytes().isEmpty(), true); + + parser = BluetoothMessageParser(QByteArray(parser.getRemainingBytes()).append(QByteArray::fromHex("0602000002000001000000000500000a37eb6102ba764d9f90000000"))); + QCOMPARE(parser.getMessages().size(), 1); + QCOMPARE(parser.getRemainingBytes().isEmpty(), true); + } + + +}; + +QTEST_GUILESS_MAIN(test_BluetoothMessageParser) +#include "test_BluetoothMessageParser.moc" diff --git a/test/qt/card/pace/test_CipherMAC.cpp b/test/qt/card/pace/test_CipherMAC.cpp index 6b848dd..2620645 100644 --- a/test/qt/card/pace/test_CipherMAC.cpp +++ b/test/qt/card/pace/test_CipherMAC.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" @@ -38,7 +38,7 @@ class test_CipherMAC void wrongKeySize() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); QByteArray key("123456"); CipherMac cipherMac(paceAlgo, key); @@ -51,7 +51,7 @@ class test_CipherMAC void tripleDes() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.mac("123456"); CipherMac cipherMac(paceAlgo, key); @@ -65,7 +65,7 @@ class test_CipherMAC void aes128() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.mac("123456"); CipherMac cipherMac(paceAlgo, key); @@ -79,7 +79,7 @@ class test_CipherMAC void aes196() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.mac("123456"); CipherMac cipherMac(paceAlgo, key); @@ -93,7 +93,7 @@ class test_CipherMAC void aes256() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.mac("123456"); CipherMac cipherMac(paceAlgo, key); @@ -107,7 +107,7 @@ class test_CipherMAC void multipleuse() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.mac("123456"); CipherMac cipherMac(paceAlgo, key); diff --git a/test/qt/card/pace/test_EcUtil.cpp b/test/qt/card/pace/test_EcUtil.cpp index 9e2e603..9bba06e 100644 --- a/test/qt/card/pace/test_EcUtil.cpp +++ b/test/qt/card/pace/test_EcUtil.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "pace/ec/EcUtil.h" diff --git a/test/qt/card/pace/test_EcdhKeyAgreement.cpp b/test/qt/card/pace/test_EcdhKeyAgreement.cpp index 3294889..3c058cf 100644 --- a/test/qt/card/pace/test_EcdhKeyAgreement.cpp +++ b/test/qt/card/pace/test_EcdhKeyAgreement.cpp @@ -1,20 +1,21 @@ /*! - * test_EcdhKeyAgreement.cpp - * * \brief Tests for the EcdhKeyAgreement * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "pace/ec/EcdhKeyAgreement.h" #include "asn1/PACEInfo.h" #include "MockReader.h" +#include "pace/ec/EcUtil.h" +#include "pace/ec/EllipticCurveFactory.h" #include "TestFileHelper.h" #include #include + using namespace governikus; @@ -45,7 +46,29 @@ class test_EcdhKeyAgreement KeyAgreementStatus result = keyAgreement->perform("123456"); - QCOMPARE(result, KeyAgreementStatus::PROTOCOLL_ERROR); + QCOMPARE(result, KeyAgreementStatus::PROTOCOL_ERROR); + } + + + void encodeUncompressedPublicKey() + { + QByteArray protocolValue = QByteArray::fromHex("04007F00070202040202"); + QSharedPointer paceInfo = PACEInfo::decode(QByteArray::fromHex("300F060A") + protocolValue + QByteArray::fromHex("020102")); + QSharedPointer ecGroup = EllipticCurveFactory::create(13); + QByteArray ecPointBytes = QByteArray::fromHex("04a9024a1ce8f02db4463cd359be3a6946fa24fdbed7d19b04bea2f0aa2ff63c6d2a05b17a66edbc15875611a209cb87c972a141263bd0843cc64b8b884c52f725"); + QSharedPointer ecPoint = EcUtil::oct2point(ecGroup, ecPointBytes); + + const QByteArray& result = EcdhKeyAgreement::encodeUncompressedPublicKey(paceInfo, ecGroup, ecPoint); + QCOMPARE(result.toHex(), + // ISO 7816 Format in TR 3111 - 5.1.2 + QByteArray("7f49") + + QByteArray("4f") + + QByteArray("06") + + QByteArray("0a") + + protocolValue.toHex() + + QByteArray("86") + + QByteArray("41") + + ecPointBytes.toHex()); } diff --git a/test/qt/card/pace/test_EllipticCurveFactory.cpp b/test/qt/card/pace/test_EllipticCurveFactory.cpp index 553f373..bab510b 100644 --- a/test/qt/card/pace/test_EllipticCurveFactory.cpp +++ b/test/qt/card/pace/test_EllipticCurveFactory.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "pace/ec/EllipticCurveFactory.h" diff --git a/test/qt/card/pace/test_KeyDerivationFunction.cpp b/test/qt/card/pace/test_KeyDerivationFunction.cpp index 7645cb4..b5a0c77 100644 --- a/test/qt/card/pace/test_KeyDerivationFunction.cpp +++ b/test/qt/card/pace/test_KeyDerivationFunction.cpp @@ -1,10 +1,13 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" #include "pace/KeyDerivationFunction.h" +#include "LogHandler.h" +#include "TestFileHelper.h" + #include using namespace governikus; @@ -18,6 +21,18 @@ class test_KeyDerivationFunction Q_OBJECT private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + void unknownAlgorithm() { KeyDerivationFunction kdf("unknown-algorithm"); @@ -31,18 +46,19 @@ class test_KeyDerivationFunction void desKey() { - KeyDerivationFunction kdf(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); - QByteArray key = kdf.pi("123456"); + KeyDerivationFunction kdf = toByteArray(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); - QVERIFY(kdf.isInitialized()); - QCOMPARE(key.toHex(), QByteArray("591468cda83d6521")); + QCOMPARE(spyLog.count(), 1); + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("3DES not supported"))); + QVERIFY(!kdf.isInitialized()); } void aes128Key() { - KeyDerivationFunction kdf(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); + KeyDerivationFunction kdf = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); QByteArray key = kdf.pi("123456"); @@ -53,7 +69,7 @@ class test_KeyDerivationFunction void aes196Key() { - KeyDerivationFunction kdf(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); + KeyDerivationFunction kdf = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); QByteArray key = kdf.pi("123456"); @@ -64,7 +80,7 @@ class test_KeyDerivationFunction void aes256Key() { - KeyDerivationFunction kdf(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + KeyDerivationFunction kdf = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); QByteArray key = kdf.pi("123456"); diff --git a/test/qt/card/pace/test_PaceHandler.cpp b/test/qt/card/pace/test_PaceHandler.cpp index 890da90..d494fc2 100644 --- a/test/qt/card/pace/test_PaceHandler.cpp +++ b/test/qt/card/pace/test_PaceHandler.cpp @@ -1,9 +1,7 @@ /*! - * test_PaceHandler.cpp - * * \brief Tests for the PaceHandler * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "pace/PaceHandler.h" @@ -52,7 +50,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader()); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -64,7 +62,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -76,7 +74,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -88,7 +86,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -100,7 +98,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -112,7 +110,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -124,7 +122,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -136,7 +134,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -148,7 +146,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -160,7 +158,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -172,7 +170,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -184,7 +182,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -196,7 +194,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -208,7 +206,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(QVector(), efCardAccess)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } @@ -223,7 +221,7 @@ class test_PaceHandler QScopedPointer reader(MockReader::createMockReader(transmitConfigs, mEfCardAccessBytes)); QScopedPointer paceHandler(new PaceHandler(reader->createCardConnectionWorker())); - CardReturnCode status = paceHandler->establishPaceChannel(PACE_PIN_ID::PACE_PIN, "123456"); + CardReturnCode status = paceHandler->establishPaceChannel(PACE_PASSWORD_ID::PACE_PIN, "123456"); QCOMPARE(status, CardReturnCode::PROTOCOL_ERROR); } diff --git a/test/qt/card/pace/test_SymmetricCipher.cpp b/test/qt/card/pace/test_SymmetricCipher.cpp index 207d247..1fe00a7 100644 --- a/test/qt/card/pace/test_SymmetricCipher.cpp +++ b/test/qt/card/pace/test_SymmetricCipher.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/KnownOIDs.h" @@ -36,7 +36,7 @@ class test_SymmetricCipher void tripleDes() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_3DES_CBC_CBC); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -49,7 +49,7 @@ class test_SymmetricCipher void wrongKeySize() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); QByteArray key("123456"); SymmetricCipher sc(paceAlgo, key); @@ -61,7 +61,7 @@ class test_SymmetricCipher void noData() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -73,7 +73,7 @@ class test_SymmetricCipher void aes128() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -88,7 +88,7 @@ class test_SymmetricCipher void aes196() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -103,7 +103,7 @@ class test_SymmetricCipher void aes256() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -118,7 +118,7 @@ class test_SymmetricCipher void multipleuse() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); @@ -133,7 +133,7 @@ class test_SymmetricCipher void setIv() { - QByteArray paceAlgo(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); + QByteArray paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256); KeyDerivationFunction kdf(paceAlgo); QByteArray key = kdf.pi("123456"); SymmetricCipher sc(paceAlgo, key); diff --git a/test/qt/card/pcsc/test_PcscUtils.cpp b/test/qt/card/pcsc/test_PcscUtils.cpp new file mode 100644 index 0000000..3bff15c --- /dev/null +++ b/test/qt/card/pcsc/test_PcscUtils.cpp @@ -0,0 +1,54 @@ +/*! + * \brief Unit tests for \ref PcscUtils + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PcscUtils.h" + +#include + +using namespace governikus; + + +class test_PcscUtils + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void checkNames_data() + { + QTest::addColumn("code"); + + QTest::newRow("Scard_S_Success") << PCSC_RETURNCODE(SCARD_S_SUCCESS); + QTest::newRow("Scard_E_Not_Transacted") << PCSC_RETURNCODE(SCARD_E_NOT_TRANSACTED); + QTest::newRow("Scard_E_Insufficient_Buffer") << PCSC_RETURNCODE(SCARD_E_INSUFFICIENT_BUFFER); + QTest::newRow("Scard_E_Timeout") << PCSC_RETURNCODE(SCARD_E_TIMEOUT); + QTest::newRow("Scard_W_Card_Not_Authenticated") << PCSC_RETURNCODE(SCARD_W_CARD_NOT_AUTHENTICATED); + + // Scard_E_Unexpected has the same value as Scard_E_Unsupported_Feature with pcsclite +#ifdef PCSCLITE_VERSION_NUMBER + QTest::newRow("Scard_E_Unsupported_Feature") << PCSC_RETURNCODE(SCARD_E_UNEXPECTED); +#else + QTest::newRow("Scard_E_Unexpected") << PCSC_RETURNCODE(SCARD_E_UNEXPECTED); +#endif + QTest::newRow("Scard_E_Unsupported_Feature") << PCSC_RETURNCODE(SCARD_E_UNSUPPORTED_FEATURE); + + QTest::newRow("UNKNOWN_STATE (0000029a)") << PCSC_RETURNCODE(PCSC_RETURNCODE(666)); + QTest::newRow("Scard_W_Removed_Card") << PCSC_RETURNCODE(PCSC_RETURNCODE(2148532329)); + } + + + void checkNames() + { + QFETCH(PCSC_RETURNCODE, code); + + QCOMPARE(PcscUtils::toString(code), QString::fromLatin1(QTest::currentDataTag())); + } + + +}; + +QTEST_GUILESS_MAIN(test_PcscUtils) +#include "test_PcscUtils.moc" diff --git a/test/qt/card/pcsc/test_pcscReaderFeature.cpp b/test/qt/card/pcsc/test_pcscReaderFeature.cpp new file mode 100644 index 0000000..2d33c12 --- /dev/null +++ b/test/qt/card/pcsc/test_pcscReaderFeature.cpp @@ -0,0 +1,105 @@ +/*! + * \brief Unit tests for \ref PcscReaderFeature + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PcscReaderFeature.h" + +#include "LogHandler.h" +#include "TestFileHelper.h" + +#include +#include + + +using namespace governikus; + + +class test_pcscReaderFeature + : public QObject +{ + Q_OBJECT + + private: + int getFeatureCount(const PcscReaderFeature& pPcscReaderFeature) + { + int count = 0; + for (FeatureID feature : Enum::getList()) + { + if (pPcscReaderFeature.contains(feature)) + { + count++; + } + } + return count; + } + + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void featuresEmpty() + { + PcscReaderFeature readerFeature(nullptr); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << readerFeature; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("()"))); + + QCOMPARE(getFeatureCount(readerFeature), 0); + } + + + void featuresCyberjackBasis() + { + QByteArray featuresTLV = QByteArray::fromHex("120442330012"); + PcscReaderFeature readerFeature(featuresTLV.constData(), static_cast(featuresTLV.length())); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << readerFeature; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("(TLV_PROPERTIES)"))); + + QCOMPARE(getFeatureCount(readerFeature), 1); + QVERIFY(readerFeature.contains(FeatureID::TLV_PROPERTIES)); + QCOMPARE(readerFeature.getValue(FeatureID::TLV_PROPERTIES), PCSC_INT(1110638610)); + } + + + void featuresCyberjackStandard() + { + QByteArray featuresTLV = QByteArray::fromHex("060442000db2070442000db3080442000db4090442000db5200442000dcc"); + PcscReaderFeature readerFeature(featuresTLV.constData(), static_cast(featuresTLV.length())); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << readerFeature; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("(VERIFY_PIN_DIRECT, MODIFY_PIN_DIRECT, MCT_READERDIRECT, MCT_UNIVERSAL, EXECUTE_PACE)"))); + + QCOMPARE(getFeatureCount(readerFeature), 5); + QVERIFY(readerFeature.contains(FeatureID::VERIFY_PIN_DIRECT)); + QVERIFY(readerFeature.contains(FeatureID::MODIFY_PIN_DIRECT)); + QVERIFY(readerFeature.contains(FeatureID::MCT_READERDIRECT)); + QVERIFY(readerFeature.contains(FeatureID::MCT_UNIVERSAL)); + QVERIFY(readerFeature.contains(FeatureID::EXECUTE_PACE)); + QCOMPARE(readerFeature.getValue(FeatureID::VERIFY_PIN_DIRECT), PCSC_INT(1107299762)); + QCOMPARE(readerFeature.getValue(FeatureID::MODIFY_PIN_DIRECT), PCSC_INT(1107299763)); + QCOMPARE(readerFeature.getValue(FeatureID::MCT_READERDIRECT), PCSC_INT(1107299764)); + QCOMPARE(readerFeature.getValue(FeatureID::MCT_UNIVERSAL), PCSC_INT(1107299765)); + QCOMPARE(readerFeature.getValue(FeatureID::EXECUTE_PACE), PCSC_INT(1107299788)); + } + + +}; + +QTEST_GUILESS_MAIN(test_pcscReaderFeature) +#include "test_pcscReaderFeature.moc" diff --git a/test/qt/card/pcsc/test_pcscReaderPaceCapability.cpp b/test/qt/card/pcsc/test_pcscReaderPaceCapability.cpp new file mode 100644 index 0000000..c5bfcfc --- /dev/null +++ b/test/qt/card/pcsc/test_pcscReaderPaceCapability.cpp @@ -0,0 +1,98 @@ +/*! + * \brief Unit tests for \ref PcscReaderPaceCapability + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PcscReaderPaceCapability.h" + +#include "LogHandler.h" +#include "TestFileHelper.h" + +#include +#include + + +using namespace governikus; + + +class test_pcscReaderPaceCapability + : public QObject +{ + Q_OBJECT + + private: + int getCapabilityCount(const PcscReaderPaceCapability& pPcscReaderPaceCapability) + { + int count = 0; + for (PaceCapabilityId capability : Enum::getList()) + { + if (pPcscReaderPaceCapability.contains(capability)) + { + count++; + } + } + return count; + } + + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void capabilitiesEmpty() + { + PcscReaderPaceCapability paceCapa(nullptr); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << paceCapa; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("()"))); + + QCOMPARE(getCapabilityCount(paceCapa), 0); + } + + + void capabilitiesCyberjackStandard() + { + QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010060"); + PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), static_cast(capabilitiesTLV.length())); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << paceCapa; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("(EID, GENERIC)"))); + + QCOMPARE(getCapabilityCount(paceCapa), 2); + QVERIFY(paceCapa.contains(PaceCapabilityId::EID)); + QVERIFY(paceCapa.contains(PaceCapabilityId::GENERIC)); + } + + + void capabilitiesCyberjackKomfort() + { + QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010070"); + PcscReaderPaceCapability paceCapa(capabilitiesTLV.constData(), static_cast(capabilitiesTLV.length())); + + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + qDebug() << paceCapa; + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("(ESIGN, EID, GENERIC)"))); + + QCOMPARE(getCapabilityCount(paceCapa), 3); + QVERIFY(paceCapa.contains(PaceCapabilityId::EID)); + QVERIFY(paceCapa.contains(PaceCapabilityId::ESIGN)); + QVERIFY(paceCapa.contains(PaceCapabilityId::GENERIC)); + } + + +}; + +QTEST_GUILESS_MAIN(test_pcscReaderPaceCapability) +#include "test_pcscReaderPaceCapability.moc" diff --git a/test/qt/card/remote/test_RemoteReaderManagerPlugin.cpp b/test/qt/card/remote/test_RemoteReaderManagerPlugin.cpp new file mode 100644 index 0000000..cf49c1b --- /dev/null +++ b/test/qt/card/remote/test_RemoteReaderManagerPlugin.cpp @@ -0,0 +1,536 @@ +/*! + * \brief Unit tests for \ref RemoteReaderManagerPlugIn + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteReaderManagerPlugIn.h" + +#include "messages/IfdConnect.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/RemoteMessageParser.h" +#include "MockDataChannel.h" +#include "MockIfdStatus.h" +#include "MockRemoteDispatcher.h" +#include "RemoteClient.h" + +#include +#include +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(QSharedPointer ) + + +class MockRemoteClient + : public RemoteClient +{ + Q_OBJECT + + public: + MockRemoteClient() = default; + virtual ~MockRemoteClient() override = default; + + virtual void startDetection() override; + virtual void stopDetection() override; + virtual bool isDetecting() override; + virtual void establishConnection(const QSharedPointer& pEntry, const QString& pPsk) override; + virtual QVector getConnectedDeviceInfos() override; + +}; + + +void MockRemoteClient::startDetection() +{ +} + + +void MockRemoteClient::stopDetection() +{ +} + + +bool MockRemoteClient::isDetecting() +{ + return false; +} + + +void MockRemoteClient::establishConnection(const QSharedPointer& pEntry, const QString& pPsk) +{ + Q_UNUSED(pEntry); + Q_UNUSED(pPsk); +} + + +QVector MockRemoteClient::getConnectedDeviceInfos() +{ + return QVector(); +} + + +class test_RemoteReaderManagerPlugIn + : public QObject +{ + Q_OBJECT + + private: + QThread mNetworkThread; + QSharedPointer mPlugin; + QSharedPointer mRemoteClient; + QSharedPointer mDispatcher1; + QSharedPointer mDispatcher2; + QVector > mClientMessages; + + void waitForSignals(int identifier, QSignalSpy* const pSpy, const int pExpectedCount, const int pTimeoutMs) + { + qDebug() << "waitForSignals:" << identifier; + for (int tryCount = 0; pSpy->count() < pExpectedCount && tryCount < pExpectedCount; ++tryCount) + { + pSpy->wait(pTimeoutMs); + } + QCOMPARE(pSpy->count(), pExpectedCount); + } + + + private Q_SLOTS: + void initTestCase() + { + const RemoteMessageParser parser; + + mNetworkThread.setObjectName(QStringLiteral("NetworkThread")); + + mRemoteClient.reset(new MockRemoteClient); + + mDispatcher1.reset(new MockRemoteDispatcher()); + mDispatcher1->moveToThread(&mNetworkThread); + + mDispatcher2.reset(new MockRemoteDispatcher()); + mDispatcher2->moveToThread(&mNetworkThread); + + mNetworkThread.start(); + + auto m = [&](const char* pJsonByteData) -> QSharedPointer + { + const QByteArray jsonData(pJsonByteData); + return parser.parse(jsonData); + }; + + mClientMessages + << m("{\n" + " \"msg\": \"IFDEstablishContext\",\n" + " \"Protocol\": \"IFDInterface_WebSocket_v0\",\n" + " \"UDName\": \"MAC-MINI\"\n" + "}") + << m("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDGetStatus\",\n" + " \"SlotName\": \"Remote Reader\"\n" + "}") + << m("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"exclusive\": true,\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}") + << m("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDDisconnect\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}") + << m("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDTransmit\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"CommandAPDUs\": [\n" + " {\n" + " \"InputAPDU\": \"00A402022F00\",\n" + " \"AcceptableStatusCodes\": null\n" + " }\n" + " ]\n" + "}") + << m("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"InputData\": \"abcd1234\",\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannel\"\n" + "}\n"); + } + + + void cleanupTestCase() + { + mNetworkThread.quit(); + mNetworkThread.wait(); + } + + + void init() + { + // local + mPlugin.reset(new RemoteReaderManagerPlugIn()); + mPlugin->setRemoteClient(mRemoteClient); + } + + + void cleanup() + { + // local + } + + + void testStandardValues() + { + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + QVERIFY(mPlugin->getReaders().isEmpty()); + + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + waitForSignals(1, &spySend, 1, 1000); + + QVERIFY(mPlugin->getReaders().isEmpty()); + QCOMPARE(spySend.size(), 1); + + QSharedPointer result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDEstablishContext); + } + + + void testSingleDispatcherSingleReaderAddRemoveWithoutCard() + { + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + waitForSignals(2, &spySend, 1, 1000); + spySend.clear(); + + QSharedPointer message; + QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 500, true)); + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 1); + QCOMPARE(spyAdded.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader")); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().isBasicReader(), true); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 500); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 500, false)); + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders().size(), 0); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 500, true)); + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader")); + spyAdded.clear(); + + mDispatcher1->onClosed(); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(mPlugin->getReaders().size(), 0); + } + + + void testSingleDispatcherSingleReaderPaceCapabilities() + { + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + waitForSignals(3, &spySend, 1, 1000); + spySend.clear(); + + QSharedPointer message; + QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(true), 500, true)); + mDispatcher1->onReceived(message); + QCOMPARE(spySend.size(), 0); + QCOMPARE(spyAdded.size(), 1); + QCOMPARE(spyAdded.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader")); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().isBasicReader(), false); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 500); + } + + + void testMultipleDispatcherSingleReaderAddRemoveWithoutCard() + { + QSignalSpy spySend1(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + QSignalSpy spySend2(mDispatcher2.data(), &MockRemoteDispatcher::fireSend); + + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher2); + waitForSignals(4, &spySend1, 1, 1000); + waitForSignals(5, &spySend2, 1, 1000); + spySend1.clear(); + spySend2.clear(); + + QSharedPointer message; + QSignalSpy spyAdded(mPlugin.data(), &ReaderManagerPlugIn::fireReaderAdded); + QSignalSpy spyRemoved(mPlugin.data(), &ReaderManagerPlugIn::fireReaderRemoved); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader 1"), PaceCapabilities(), 500, true)); + mDispatcher1->onReceived(message); + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader 2"), PaceCapabilities(), 500, true)); + mDispatcher2->onReceived(message); + QCOMPARE(spySend1.size(), 0); + QCOMPARE(spySend2.size(), 0); + QCOMPARE(spyAdded.size(), 2); + QCOMPARE(spyAdded.takeFirst()[0].toString(), QStringLiteral("NFC Reader 1")); + QCOMPARE(spyAdded.takeFirst()[0].toString(), QStringLiteral("NFC Reader 2")); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(mPlugin->getReaders().size(), 2); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader 1")); + QCOMPARE(mPlugin->getReaders()[1]->getName(), QStringLiteral("NFC Reader 2")); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader 1"), PaceCapabilities(), 500, false)); + mDispatcher1->onReceived(message); + QCOMPARE(spySend1.size(), 0); + QCOMPARE(spySend2.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader 1")); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader 2")); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader 1"), PaceCapabilities(), 500, true)); + mDispatcher1->onReceived(message); + QCOMPARE(spySend1.size(), 0); + QCOMPARE(spySend2.size(), 0); + QCOMPARE(spyAdded.size(), 1); + QCOMPARE(spyAdded.takeFirst()[0].toString(), QStringLiteral("NFC Reader 1")); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(mPlugin->getReaders().size(), 2); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader 1")); + QCOMPARE(mPlugin->getReaders()[1]->getName(), QStringLiteral("NFC Reader 2")); + + mDispatcher1->onClosed(); + QCOMPARE(spySend1.size(), 0); + QCOMPARE(spySend2.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader 1")); + QCOMPARE(mPlugin->getReaders().size(), 1); + QCOMPARE(mPlugin->getReaders()[0]->getName(), QStringLiteral("NFC Reader 2")); + + mDispatcher2->onClosed(); + QCOMPARE(spySend1.size(), 0); + QCOMPARE(spySend2.size(), 0); + QCOMPARE(spyAdded.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader 2")); + QCOMPARE(mPlugin->getReaders().size(), 0); + } + + + void testSingleDispatcherSingleReaderChangeCard() + { + QSharedPointer result; + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + mDispatcher1->setState(MockRemoteDispatcher::DispatcherState::ReaderWithCardError); + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + + waitForSignals(6, &spySend, 2, 1000); + spySend.takeFirst(); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + + QSharedPointer message; + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 500, true, false)); + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders()[0]->getCard(), nullptr); + + QSignalSpy spyInserted(mPlugin->getReaders()[0], &Reader::fireCardInserted); + QSignalSpy spyRemoved(mPlugin->getReaders()[0], &Reader::fireCardRemoved); + QSignalSpy spyChanged(mPlugin->getReaders()[0], &Reader::fireCardRetryCounterChanged); + QSignalSpy spyUpdated(mPlugin->getReaders()[0], &Reader::fireReaderPropertiesUpdated); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 500, true, true)); + mDispatcher1->onReceived(message); + + waitForSignals(7, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + QVERIFY(mPlugin->getReaders()[0]->getCard() != nullptr); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 500); + QVERIFY(mPlugin->getReaders()[0]->getReaderInfo().hasCard()); + QCOMPARE(spyInserted.size(), 1); + QCOMPARE(spyInserted.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(spyChanged.size(), 0); + QCOMPARE(spyUpdated.size(), 0); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 1, true, true)); + mDispatcher1->onReceived(message); + QVERIFY(mPlugin->getReaders()[0]->getCard() != nullptr); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 1); + QVERIFY(mPlugin->getReaders()[0]->getReaderInfo().hasCard()); + QCOMPARE(spyInserted.size(), 0); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(spyChanged.size(), 0); + QCOMPARE(spyUpdated.size(), 1); + QCOMPARE(spyUpdated.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 1, true, true)); + mDispatcher1->onReceived(message); + QVERIFY(mPlugin->getReaders()[0]->getCard() != nullptr); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 1); + QVERIFY(mPlugin->getReaders()[0]->getReaderInfo().hasCard()); + QCOMPARE(spyInserted.size(), 0); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(spyChanged.size(), 0); + QCOMPARE(spyUpdated.size(), 0); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 1, true, false)); + mDispatcher1->onReceived(message); + QCOMPARE(mPlugin->getReaders()[0]->getCard(), nullptr); + QVERIFY(!mPlugin->getReaders()[0]->getReaderInfo().hasCard()); + QCOMPARE(spyInserted.size(), 0); + QCOMPARE(spyRemoved.size(), 1); + QCOMPARE(spyRemoved.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(spyChanged.size(), 0); + QCOMPARE(spyUpdated.size(), 0); + + message.reset(new MockIfdStatus(QStringLiteral("NFC Reader"), PaceCapabilities(), 1, true, true)); + mDispatcher1->onReceived(message); + waitForSignals(8, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + QVERIFY(mPlugin->getReaders()[0]->getCard() != nullptr); + QCOMPARE(mPlugin->getReaders()[0]->getReaderInfo().getMaxApduLength(), 1); + QVERIFY(mPlugin->getReaders()[0]->getReaderInfo().hasCard()); + QCOMPARE(spyInserted.size(), 1); + QCOMPARE(spyInserted.takeFirst()[0].toString(), QStringLiteral("NFC Reader")); + QCOMPARE(spyRemoved.size(), 0); + QCOMPARE(spyChanged.size(), 0); + QCOMPARE(spyUpdated.size(), 0); + } + + + void testSingleDispatcherSingleReaderCardCommunication() + { + QSharedPointer result; + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + mDispatcher1->setState(MockRemoteDispatcher::DispatcherState::ReaderWithCard); + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + + waitForSignals(9, &spySend, 4, 1000); + spySend.takeFirst(); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDTransmit); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDDisconnect); + + QCOMPARE(mPlugin->getReaders().size(), 1); + Card* card = mPlugin->getReaders()[0]->getCard(); + QVERIFY(card != nullptr); + + QCOMPARE(card->connect(), CardReturnCode::OK); + waitForSignals(10, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + QCOMPARE(static_cast(result.data())->getSlotName(), QStringLiteral("NFC Reader")); + + QCOMPARE(card->disconnect(), CardReturnCode::OK); + waitForSignals(11, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDDisconnect); + QCOMPARE(static_cast(result.data())->getSlotHandle(), QStringLiteral("NFC Reader")); + + CommandApdu cmd(QByteArray("ping")); + ResponseApdu res; + QCOMPARE(card->transmit(cmd, res), CardReturnCode::OK); + waitForSignals(12, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDTransmit); + QCOMPARE(static_cast(result.data())->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(static_cast(result.data())->getInputApdu(), QByteArray("ping")); + QCOMPARE(res.getBuffer(), QByteArray("pong")); + + mDispatcher1->setState(MockRemoteDispatcher::DispatcherState::ReaderWithCardError); + + QCOMPARE(card->connect(), CardReturnCode::COMMAND_FAILED); + waitForSignals(13, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDConnect); + QCOMPARE(static_cast(result.data())->getSlotName(), QStringLiteral("NFC Reader")); + + QCOMPARE(card->disconnect(), CardReturnCode::COMMAND_FAILED); + waitForSignals(14, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDDisconnect); + QCOMPARE(static_cast(result.data())->getSlotHandle(), QStringLiteral("NFC Reader")); + + res.setBuffer(QByteArray()); + QCOMPARE(card->transmit(cmd, res), CardReturnCode::COMMAND_FAILED); + waitForSignals(15, &spySend, 1, 1000); + result = qvariant_cast >(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), RemoteCardMessageType::IFDTransmit); + QCOMPARE(static_cast(result.data())->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(static_cast(result.data())->getInputApdu(), QByteArray("ping")); + QCOMPARE(res.getBuffer(), QByteArray()); + } + + + void testUnexpectedMessagesCauseAnIfdErrorMessage() + { + QSignalSpy spySend(mDispatcher1.data(), &MockRemoteDispatcher::fireSend); + + mDispatcher1->setState(MockRemoteDispatcher::DispatcherState::WithoutReader); + Q_EMIT mRemoteClient->fireNewRemoteDispatcher(mDispatcher1); + waitForSignals(1, &spySend, 1, 1000); + spySend.clear(); + + for (const QSharedPointer& clientMessage : qAsConst(mClientMessages)) + { + QMetaObject::invokeMethod(mDispatcher1.data(), "onReceived", Qt::QueuedConnection, Q_ARG(QSharedPointer, clientMessage)); + waitForSignals(2, &spySend, 1, 1000); + const QList& arguments = spySend.last(); + + const QVariant remoteMessageVariant = arguments.at(0); + QVERIFY(remoteMessageVariant.canConvert >()); + const QSharedPointer message = remoteMessageVariant.value >(); + const QSharedPointer errorMessage = message.dynamicCast(); + + QVERIFY(!errorMessage.isNull()); + QCOMPARE(errorMessage->getType(), RemoteCardMessageType::IFDError); + QCOMPARE(errorMessage->getContextHandle(), QString()); + QCOMPARE(errorMessage->getSlotHandle(), QString()); + QVERIFY(errorMessage->resultHasError()); + QCOMPARE(errorMessage->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownAPIFunction")); + + spySend.clear(); + } + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteReaderManagerPlugIn) +#include "test_RemoteReaderManagerPlugin.moc" diff --git a/test/qt/card/test_Command.cpp b/test/qt/card/test_Command.cpp index 647ed34..6f908a7 100644 --- a/test/qt/card/test_Command.cpp +++ b/test/qt/card/test_Command.cpp @@ -1,9 +1,7 @@ /*! - * test_Command.cpp - * * \brief Tests for card commands * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -26,43 +24,6 @@ class test_Command } - void testToBigEndian_fatInt() - { - QByteArray value = toBigEndian(static_cast(0xFFEE)); - - QCOMPARE(value.size(), 2); - QCOMPARE(value.at(0), char(0xFF)); - QCOMPARE(value.at(1), char(0xEE)); - } - - - void testToBigEndian_int() - { - QByteArray value = toBigEndian(static_cast(0x11)); - - QCOMPARE(value.size(), 1); - QCOMPARE(value.at(0), static_cast(0x11)); - } - - - void testToBigEndian_zero() - { - QByteArray value = toBigEndian(static_cast(0x00)); - - QCOMPARE(value.size(), 1); - QCOMPARE(value.at(0), static_cast(0x00)); - } - - - void testToBigEndian_long() - { - QByteArray value = toBigEndian(static_cast(0x11)); - - QCOMPARE(value.size(), 1); - QCOMPARE(value.at(0), static_cast(0x11)); - } - - void testPinModifyBuilder_createChangeEidPinCommandData() { PinModifyBuilder builder; diff --git a/test/qt/card/test_CommandApdu.cpp b/test/qt/card/test_CommandApdu.cpp index dbe21d6..17351f8 100644 --- a/test/qt/card/test_CommandApdu.cpp +++ b/test/qt/card/test_CommandApdu.cpp @@ -1,9 +1,7 @@ /*! - * test_CommandApdu.cpp - * * \brief Tests for the class CommandApdu. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/test_EstablishPACEChannelBuilder.cpp b/test/qt/card/test_EstablishPACEChannelBuilder.cpp index e3956d8..668e4a1 100644 --- a/test/qt/card/test_EstablishPACEChannelBuilder.cpp +++ b/test/qt/card/test_EstablishPACEChannelBuilder.cpp @@ -1,9 +1,7 @@ /*! - * test_EstablishPACEChannelBuilder.cpp - * * \brief Tests for card EstablishPACEChannelBuilder * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -21,13 +19,13 @@ class test_EstablishPACEChannelBuilder Q_OBJECT private Q_SLOTS: - void setPinId() + void setPasswordId() { QByteArray hexBytes("30 05" " A1 03 02 01 03" ); EstablishPACEChannelBuilder builder; - builder.setPinId(PACE_PIN_ID::PACE_PIN); + builder.setPasswordId(PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(builder.createCommandDataCcid().getData(), QByteArray::fromHex(hexBytes)); } @@ -40,7 +38,7 @@ class test_EstablishPACEChannelBuilder " A3 17 04 15 7F4C 12 060904007F00070301020253050000000F0F" ); EstablishPACEChannelBuilder builder; - builder.setPinId(PACE_PIN_ID::PACE_PIN); + builder.setPasswordId(PACE_PASSWORD_ID::PACE_PIN); builder.setChat(QByteArray::fromHex(" 7F4C12060904007F00070301020253050000000F0F")); QCOMPARE(builder.createCommandDataCcid().getData(), QByteArray::fromHex(hexBytes)); @@ -65,7 +63,7 @@ class test_EstablishPACEChannelBuilder hexBytes = hexBytes.replace("CERTDESCR", certDescriptionHex); EstablishPACEChannelBuilder builder; - builder.setPinId(PACE_PIN_ID::PACE_PIN); + builder.setPasswordId(PACE_PASSWORD_ID::PACE_PIN); builder.setChat(QByteArray::fromHex(" 7F4C12060904007F00070301020253050000000F0F")); builder.setCertificateDescription(QByteArray::fromHex(certDescriptionHex)); diff --git a/test/qt/card/test_EstablishPACEChannelOutput.cpp b/test/qt/card/test_EstablishPACEChannelOutput.cpp index 6e6bb02..d211c0a 100644 --- a/test/qt/card/test_EstablishPACEChannelOutput.cpp +++ b/test/qt/card/test_EstablishPACEChannelOutput.cpp @@ -1,9 +1,7 @@ /*! - * test_EstablishPACEChannelOutput.cpp - * * \brief Tests for card EstablishPACEChannelOutput * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -27,7 +25,7 @@ class test_EstablishPACEChannelOutput QByteArray bytes = QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput.hex")); EstablishPACEChannelOutput channelOutput; - channelOutput.parse(bytes, PACE_PIN_ID::PACE_PIN); + channelOutput.parse(bytes, PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(channelOutput.getCARcurr(), QByteArray("DETESTeID00004")); QVERIFY(channelOutput.getCARprev().isEmpty()); QVERIFY(channelOutput.getEfCardAccess().toHex().startsWith(QByteArray("3181c1300d0608040"))); @@ -39,7 +37,7 @@ class test_EstablishPACEChannelOutput QByteArray bytes = QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput_wrongPIN.hex")); EstablishPACEChannelOutput channelOutput; - channelOutput.parse(bytes, PACE_PIN_ID::PACE_PIN); + channelOutput.parse(bytes, PACE_PASSWORD_ID::PACE_PIN); QVERIFY(channelOutput.getCARcurr().isEmpty()); QVERIFY(channelOutput.getCARprev().isEmpty()); QVERIFY(channelOutput.getEfCardAccess().isEmpty()); @@ -51,7 +49,7 @@ class test_EstablishPACEChannelOutput QByteArray bytes = QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput_fromCcid.hex")); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(bytes, PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(bytes, PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::OK, channelOutput.getPaceReturnCode()); QCOMPARE(channelOutput.getCARcurr(), QByteArray("DECVCAeID00103")); QCOMPARE(channelOutput.getCARprev(), QByteArray("DECVCAeID00102")); @@ -65,7 +63,7 @@ class test_EstablishPACEChannelOutput QByteArray bytes = QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput_fromCcid2.hex")); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(bytes, PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(bytes, PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::OK, channelOutput.getPaceReturnCode()); QVERIFY(channelOutput.getCARcurr().isEmpty()); QVERIFY(channelOutput.getCARprev().isEmpty()); @@ -87,8 +85,9 @@ class test_EstablishPACEChannelOutput ); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::UNKNOWN, channelOutput.getPaceReturnCode()); + QCOMPARE(channelOutput.getMseStatusSetAt(), QByteArray()); QCOMPARE(channelOutput.getCARcurr(), QByteArray()); QCOMPARE(channelOutput.getCARprev(), QByteArray()); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray()); @@ -109,8 +108,9 @@ class test_EstablishPACEChannelOutput ); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); + QCOMPARE(channelOutput.getMseStatusSetAt(), QByteArray::fromHex("9000")); QCOMPARE(channelOutput.getCARcurr(), QByteArray()); QCOMPARE(channelOutput.getCARprev(), QByteArray()); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray::fromHex("3100")); @@ -131,8 +131,9 @@ class test_EstablishPACEChannelOutput ); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::CANCELLATION_BY_USER, channelOutput.getPaceReturnCode()); + QCOMPARE(channelOutput.getMseStatusSetAt(), QByteArray::fromHex("9000")); QCOMPARE(channelOutput.getCARcurr(), QByteArray("DECVCAeID00103")); QCOMPARE(channelOutput.getCARprev(), QByteArray("DECVCAeID00102")); QCOMPARE(channelOutput.getEfCardAccess(), QByteArray::fromHex("3100")); @@ -157,11 +158,81 @@ class test_EstablishPACEChannelOutput "9000" // ReturnCode ); EstablishPACEChannelOutput channelOutput; - channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PIN_ID::PACE_PIN); + channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PASSWORD_ID::PACE_PIN); QCOMPARE(CardReturnCode::INVALID_PIN, channelOutput.getPaceReturnCode()); } + void toCcid() + { + QByteArray hexBytes = QByteArray("30 5A" + " A1 06 04 04 F0200001" + " A2 04 04 02 9000" + " A3 02 31 00" + " A4 22 04 20 24e41d62b8c848226b86fcc6c7657577dca47ad2bf21573617bae84807f85c6b" + " A5 10 04 0e 4445435643416549443030313033" + " A6 10 04 0e 4445435643416549443030313032" + " 9000" // ReturnCode + ); + + EstablishPACEChannelOutput channelOutput; + channelOutput.parseFromCcid(QByteArray::fromHex(hexBytes), PACE_PASSWORD_ID::PACE_PIN); + + EstablishPACEChannelOutput channelOutput2; + channelOutput2.parseFromCcid(channelOutput.toCcid(), PACE_PASSWORD_ID::PACE_PIN); + + QCOMPARE(channelOutput2.getPaceReturnCode(), CardReturnCode::CANCELLATION_BY_USER); + QCOMPARE(channelOutput2.getPaceReturnCode(), channelOutput.getPaceReturnCode()); + + QCOMPARE(channelOutput2.getMseStatusSetAt(), QByteArray::fromHex("9000")); + QCOMPARE(channelOutput2.getMseStatusSetAt(), channelOutput.getMseStatusSetAt()); + + QCOMPARE(channelOutput2.getCARcurr(), QByteArray("DECVCAeID00103")); + QCOMPARE(channelOutput2.getCARcurr(), channelOutput.getCARcurr()); + + QCOMPARE(channelOutput2.getCARprev(), QByteArray("DECVCAeID00102")); + QCOMPARE(channelOutput2.getCARprev(), channelOutput.getCARprev()); + + QCOMPARE(channelOutput2.getEfCardAccess(), QByteArray::fromHex("3100")); + QCOMPARE(channelOutput2.getEfCardAccess(), channelOutput.getEfCardAccess()); + + QCOMPARE(channelOutput2.getIDicc(), QByteArray::fromHex("24e41d62b8c848226b86fcc6c7657577dca47ad2bf21573617bae84807f85c6b")); + QCOMPARE(channelOutput2.getIDicc(), channelOutput.getIDicc()); + } + + + void toCcid_ReturnCode_ErrorCode_data() + { + QTest::addColumn("cardReturnCode"); + QTest::addColumn("pacePasswordId"); + + QTest::newRow("INVALID_CAN") << CardReturnCode::INVALID_CAN << PACE_PASSWORD_ID::PACE_CAN; + QTest::newRow("INVALID_PIN") << CardReturnCode::INVALID_PIN << PACE_PASSWORD_ID::PACE_PIN; + QTest::newRow("INVALID_PUK") << CardReturnCode::INVALID_PUK << PACE_PASSWORD_ID::PACE_PUK; + + QTest::newRow("OK") << CardReturnCode::OK << PACE_PASSWORD_ID::PACE_PIN; + QTest::newRow("CANCELLATION_BY_USER") << CardReturnCode::CANCELLATION_BY_USER << PACE_PASSWORD_ID::PACE_PIN; + QTest::newRow("INPUT_TIME_OUT") << CardReturnCode::INPUT_TIME_OUT << PACE_PASSWORD_ID::PACE_PIN; + QTest::newRow("COMMAND_FAILED") << CardReturnCode::COMMAND_FAILED << PACE_PASSWORD_ID::PACE_PIN; + } + + + void toCcid_ReturnCode_ErrorCode() + { + QFETCH(CardReturnCode, cardReturnCode); + QFETCH(PACE_PASSWORD_ID, pacePasswordId); + + EstablishPACEChannelOutput channelOutput; + channelOutput.setPaceReturnCode(cardReturnCode); + + EstablishPACEChannelOutput channelOutput2; + channelOutput2.parseFromCcid(channelOutput.toCcid(), pacePasswordId); + + QCOMPARE(channelOutput2.getPaceReturnCode(), cardReturnCode); + QCOMPARE(channelOutput2.getPaceReturnCode(), channelOutput.getPaceReturnCode()); + } + + }; QTEST_GUILESS_MAIN(test_EstablishPACEChannelOutput) diff --git a/test/qt/card/test_EstablishPACEChannelParser.cpp b/test/qt/card/test_EstablishPACEChannelParser.cpp new file mode 100644 index 0000000..ae67353 --- /dev/null +++ b/test/qt/card/test_EstablishPACEChannelParser.cpp @@ -0,0 +1,52 @@ +/*! + * \brief Tests for \ref EstablishPACEChannelParser + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "EstablishPACEChannelParser.h" + +#include + +using namespace governikus; + + +class test_EstablishPACEChannelParser + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void buildAndParse() + { + const PACE_PASSWORD_ID pinId(PACE_PASSWORD_ID::PACE_PIN); + const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F"); + const QByteArray certDescription = QByteArray::fromHex("30 8202A4" + " 06 0A 04007F00070301030103" + " A1 0E 0C0C442D547275737420476D6248" + " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E" + " A5 820248" + " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978" + ); + + + EstablishPACEChannelBuilder builder; + builder.setPasswordId(pinId); + builder.setChat(chat); + builder.setCertificateDescription(certDescription); + const auto command = builder.createCommandDataCcid(); + const auto buffer = command.getBuffer(); + + EstablishPACEChannelParser parser = EstablishPACEChannelParser::fromCcid(buffer); + + QCOMPARE(pinId, parser.getPasswordId()); + QCOMPARE(chat, parser.getChat()); + QCOMPARE(certDescription, parser.getCertificateDescription()); + QCOMPARE(command.getData(), parser.getCommandData()); + } + + +}; + +QTEST_GUILESS_MAIN(test_EstablishPACEChannelParser) +#include "test_EstablishPACEChannelParser.moc" diff --git a/test/qt/card/test_GeneralAuthenticateResponse.cpp b/test/qt/card/test_GeneralAuthenticateResponse.cpp index 8054aff..e025a35 100644 --- a/test/qt/card/test_GeneralAuthenticateResponse.cpp +++ b/test/qt/card/test_GeneralAuthenticateResponse.cpp @@ -1,9 +1,7 @@ /*! - * test_GeneralAuthenticateResponse.cpp - * * \brief Tests for GeneralAuthenticate response APDUs * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/test_MSEBuilder.cpp b/test/qt/card/test_MSEBuilder.cpp index e24b17d..6f8b09c 100644 --- a/test/qt/card/test_MSEBuilder.cpp +++ b/test/qt/card/test_MSEBuilder.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "Commands.h" @@ -56,7 +56,7 @@ class test_MSEBuilder void setPublicKeyId() { - PACE_PIN_ID pinId = PACE_PIN_ID::PACE_PIN; + PACE_PASSWORD_ID pinId = PACE_PASSWORD_ID::PACE_PIN; mMseBuilder->setPublicKey(pinId); assertCommandContent(QByteArray::fromHex("8301").append(static_cast(pinId))); } diff --git a/test/qt/card/test_ReaderManager.cpp b/test/qt/card/test_ReaderManager.cpp index 61feb41..7a52904 100644 --- a/test/qt/card/test_ReaderManager.cpp +++ b/test/qt/card/test_ReaderManager.cpp @@ -1,10 +1,10 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "ReaderManager.h" #include "MockReaderManagerPlugIn.h" -#include "ReaderManager.h" #include "ReaderManagerWorker.h" #include @@ -58,7 +58,6 @@ class test_ReaderManager private Q_SLOTS: void initTestCase() { - ReaderManagerWorker::registerMetaTypes(); ReaderManager::getInstance().init(); ReaderManager::getInstance().getPlugInInfos(); // just to wait until initialization finished } @@ -152,6 +151,24 @@ class test_ReaderManager } + void getInvalidReaderInfoWithAndWithoutInitializedReaderManager() + { + { + const auto& readerInfo = ReaderManager::getInstance().getReaderInfo("test dummy"); + QCOMPARE(readerInfo.getPlugInType(), ReaderManagerPlugInType::UNKNOWN); + QCOMPARE(readerInfo.getName(), QStringLiteral("test dummy")); + } + + cleanupTestCase(); + { + const auto& readerInfo = ReaderManager::getInstance().getReaderInfo("test dummy"); + QCOMPARE(readerInfo.getPlugInType(), ReaderManagerPlugInType::UNKNOWN); + QCOMPARE(readerInfo.getName(), QStringLiteral("test dummy")); + } + initTestCase(); + } + + }; QTEST_GUILESS_MAIN(test_ReaderManager) diff --git a/test/qt/card/test_SecureMessaging.cpp b/test/qt/card/test_SecureMessaging.cpp index c65b68d..a2834fa 100644 --- a/test/qt/card/test_SecureMessaging.cpp +++ b/test/qt/card/test_SecureMessaging.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -83,7 +83,7 @@ class test_SecureMessaging private Q_SLOTS: void init() { - auto paceAlgo = KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128; + auto paceAlgo = toByteArray(KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128); QByteArray encKey("F1234567890ABCDE"); QByteArray macKey("1234567890ABCDEF"); mSecureMessaging.reset(new SecureMessaging(paceAlgo, encKey, macKey)); diff --git a/test/qt/card/test_SecureMessagingResponse.cpp b/test/qt/card/test_SecureMessagingResponse.cpp index 3f911cd..1e0a1ec 100644 --- a/test/qt/card/test_SecureMessagingResponse.cpp +++ b/test/qt/card/test_SecureMessagingResponse.cpp @@ -1,9 +1,7 @@ /*! - * test_SecureMessagingResponse.cpp - * * \brief Tests for SecureMessagingResponse * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/card/test_SupportedReaders.cpp b/test/qt/card/test_SupportedReaders.cpp deleted file mode 100644 index 8e64bde..0000000 --- a/test/qt/card/test_SupportedReaders.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * \brief Unit tests for \ref SupportedReaders - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "SupportedReaders.h" - -#include -#include - -using namespace governikus; - - -class test_SupportedReaders - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void isOnWhiteList() - { - const SupportedReaders& reader = SupportedReaders::getInstance(); - QVERIFY(reader.isOnWhiteList("REINER SCT cyberJack RFID komfort")); - QVERIFY(reader.isOnWhiteList("SCM Microsystems Inc. SCL011 Contactless Reader")); - - QVERIFY(!reader.isOnWhiteList("crap")); - } - - - void getPattern() - { - const SupportedReaders& reader = SupportedReaders::getInstance(); - QCOMPARE(reader.getPattern(ReaderType::REINER_cyberJack_RFID_komfort), - QString("REINER SCT cyberJack RFID komfort")); - QCOMPARE(reader.getPattern(ReaderType::REINER_cyberJack_RFID_basis), QString("REINER SCT cyberJack RFID basis")); - QCOMPARE(reader.getPattern(ReaderType::SCM_SCL011_Contactless_Reader), - QString("(SCM Microsystems Inc. )?SCL011 Contactless Reader")); - } - - - void getReader() - { - const SupportedReaders& reader = SupportedReaders::getInstance(); - - QCOMPARE(ReaderType::REINER_cyberJack_RFID_komfort, reader.getReader("REINER SCT cyberJack RFID komfort")); - QCOMPARE(ReaderType::REINER_cyberJack_RFID_standard, reader.getReader("REINER SCT cyberJack RFID standard")); - QCOMPARE(ReaderType::REINER_cyberJack_RFID_basis, reader.getReader("REINER SCT cyberJack RFID basis")); - QCOMPARE(ReaderType::REINER_cyberJack_wave, reader.getReader("REINER SCT cyberJack wave")); - - QCOMPARE(ReaderType::KOBIL_IDToken, reader.getReader("KOBIL Systems IDToken")); - QCOMPARE(ReaderType::KOBIL_IDToken, reader.getReader("KOBIL IDToken")); - - QCOMPARE(ReaderType::SCM_SDI010, reader.getReader("SDI010 USB Contactless Reader")); - QCOMPARE(ReaderType::SCM_SDI010, reader.getReader("SCM Microsystems Inc. SDI010 Smart Card Reader 0")); - QCOMPARE(ReaderType::SCM_SDI010, reader.getReader("SDI010 USB Smart Card Reader [Vendor Interface] (21120837205702) 00 00")); - QCOMPARE(ReaderType::SCM_SDI010, reader.getReader("SCM Microsystems Inc. SDI010 Contactless Reader 0")); - QCOMPARE(ReaderType::SCM_SDI010, reader.getReader("SDI010 USB Contactless Reader")); - - QCOMPARE(ReaderType::SCM_SDI011, reader.getReader("SDI011 USB Contactless Reader")); - - QCOMPARE(ReaderType::SCM_SCL011_Contactless_Reader, reader.getReader("SCM Microsystems Inc. SCL011 Contactless Reader")); - QCOMPARE(ReaderType::SCM_SCL011_Contactless_Reader, reader.getReader("SCL011 Contactless Reader")); - - QCOMPARE(ReaderType::ACS_ACR1281_PICC_Reader, reader.getReader("ACS ACR1281 PICC Reader")); - - QCOMPARE(ReaderType::OMNIKEY_CardMan_5x21_CL, reader.getReader("OMNIKEY CardMan 5x21")); - QCOMPARE(ReaderType::OMNIKEY_CardMan_5x21_CL, reader.getReader("OMNIKEY CardMan 5321")); - - QCOMPARE(ReaderType::FEIG_OBID_myAXXESS_basic, reader.getReader("FEIG ELECTRONIC GmbH OBID myAXXESS basic")); - - QCOMPARE(ReaderType::Gemalto_Prox_SU, reader.getReader("Gemalto Prox SU")); - QCOMPARE(ReaderType::Gemalto_Prox_SU, reader.getReader("Gemalto Prox-SU")); - - QCOMPARE(ReaderType::Gemalto_Prox_DU, reader.getReader("Gemalto Prox-DU")); - QCOMPARE(ReaderType::Gemalto_Prox_DU, reader.getReader("Gemalto Prox Dual")); - - QCOMPARE(ReaderType::UNKNOWN, reader.getReader("crap")); - } - - - void consistency() - { - const SupportedReaders& reader = SupportedReaders::getInstance(); - for (ReaderType readerType : Enum::getList()) - { - if (readerType != ReaderType::UNKNOWN) - { - QVERIFY(!reader.getPattern(readerType).isEmpty()); - } - } - } - - -}; - -QTEST_GUILESS_MAIN(test_SupportedReaders) -#include "test_SupportedReaders.moc" diff --git a/test/qt/cli/test_UIPlugInCli.cpp b/test/qt/cli/test_UIPlugInCli.cpp index 4d8f4ab..70fbe7e 100644 --- a/test/qt/cli/test_UIPlugInCli.cpp +++ b/test/qt/cli/test_UIPlugInCli.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref UIPlugInCli * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "CliHelper.h" @@ -25,7 +25,7 @@ class test_UIPlugInCli QSKIP("Console is not supported at the moment"); #endif - #ifdef Q_OS_OSX + #ifdef Q_OS_MACOS QSKIP("QProcess/CliHelper is flaky on OSX"); #endif diff --git a/test/qt/configuration/test_ProviderConfiguration.cpp b/test/qt/configuration/test_ProviderConfiguration.cpp new file mode 100644 index 0000000..930dce5 --- /dev/null +++ b/test/qt/configuration/test_ProviderConfiguration.cpp @@ -0,0 +1,172 @@ +/*! + * \brief Unit tests for \ref ProviderConfiguration + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderConfiguration.h" + +#include "Env.h" +#include "ResourceLoader.h" + +#include + + +using namespace governikus; + + +class test_ProviderConfiguration + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + ResourceLoader::getInstance().init(); + } + + + void testProviderUrls() + { + const ProviderConfigurationInfo 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 ProviderConfigurationInfo 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 ProviderConfigurationInfo 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 ProviderConfigurationInfo provider4; + QCOMPARE(provider4.getAddressDomain(), QString()); + QCOMPARE(provider4.getHomepageBase(), QString()); + } + + + void testProviderFields() + { + // Add image and icon. + const ProviderConfigurationInfo provider( + /* short name */ QStringLiteral("Provider 1"), + /* long name */ QStringLiteral("Provider 1 - long name"), + /* short description */ QStringLiteral("Provider description short"), + /* long description */ QStringLiteral("Provider description long"), + /* address */ QStringLiteral("https://www.homepage.com/form/"), + /* homepage */ QStringLiteral("https://www.homepage.com/"), + /* category */ QStringLiteral("CategoryA"), + /* phone */ QStringLiteral("0421 123456"), + /* email */ QStringLiteral("abc@def.de"), + /* postal address */ QStringLiteral("Am Fallturm 9\n28359 Bremen"), + /* icon */ QString(), + /* image */ QString(), + /* 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")}) + ); + + QCOMPARE(provider.getShortName().toString(), QStringLiteral("Provider 1")); + QCOMPARE(provider.getLongName().toString(), QStringLiteral("Provider 1 - long name")); + QCOMPARE(provider.getShortDescription().toString(), QStringLiteral("Provider description short")); + QCOMPARE(provider.getLongDescription().toString(), QStringLiteral("Provider description long")); + QCOMPARE(provider.getAddress(), QStringLiteral("https://www.homepage.com/form/")); + QCOMPARE(provider.getHomepage(), QStringLiteral("https://www.homepage.com/")); + QCOMPARE(provider.getCategory(), QStringLiteral("CategoryA")); + QCOMPARE(provider.getPhone(), QStringLiteral("0421 123456")); + QCOMPARE(provider.getEMail(), QStringLiteral("abc@def.de")); + QCOMPARE(provider.getPostalAddress(), QStringLiteral("Am Fallturm 9\n28359 Bremen")); + QVERIFY(provider.getIcon()->lookupPath().endsWith("/CategoryA_button.svg")); + QVERIFY(provider.getImage()->lookupPath().endsWith("/CategoryA_bg.svg")); + QCOMPARE(provider.getTcTokenUrl(), QUrl(QStringLiteral("https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf"))); + QCOMPARE(provider.getClientUrl(), QUrl(QStringLiteral("https://www.bva.bund.de/bafoeg-online/Bafoeg/flow/anmeld"))); + QCOMPARE(provider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1"), QStringLiteral("https://npa.allianz.de/bla1")})); + } + + + void checkPhone() + { + const auto& providers = Env::getSingleton()->getProviderConfigurationInfos(); + for (const auto& provider : providers) + { + QVERIFY(provider.getPhone().isEmpty() || provider.getPhone().startsWith("+49 ")); + } + + } + + + void checkCallCost_data() + { + QTest::addColumn("phone"); + QTest::addColumn("notNull"); + QTest::addColumn("freeSeconds"); + QTest::addColumn("landlineCentsPerMinute"); + QTest::addColumn("landlineCentsPerCall"); + QTest::addColumn("mobileCentsPerMinute"); + QTest::addColumn("mobileCentsPerCall"); + + QTest::newRow("delimeter") << "+49 1-8/05-123456789" << true << 0 << 14.0 << 0.0 << 42.0 << 0.0; + QTest::newRow("notExisting") << "+49 123456" << false << 0 << 0.0 << 0.0 << 0.0 << 0.0; + QTest::newRow("01") << "+49 1371" << true << 0 << 0.0 << 14.0 << 0.0 << 0.0; + QTest::newRow("02") << "+49 1372" << true << 0 << 14.0 << 0.0 << 0.0 << 0.0; + QTest::newRow("03") << "+49 1376" << true << 0 << 0.0 << 25.0 << 0.0 << 0.0; + QTest::newRow("04") << "+49 1377" << true << 0 << 0.0 << 100.0 << 0.0 << 0.0; + QTest::newRow("05") << "+49 1378" << true << 0 << 0.0 << 50.0 << 0.0 << 0.0; + QTest::newRow("06") << "+49 1801" << true << 0 << 3.9 << 0.0 << 42.0 << 0.0; + QTest::newRow("07") << "+49 1802" << true << 0 << 0.0 << 6.0 << 42.0 << 0.0; + QTest::newRow("08") << "+49 1803" << true << 0 << 9.0 << 0.0 << 42.0 << 0.0; + QTest::newRow("09") << "+49 1804" << true << 0 << 0.0 << 20.0 << 42.0 << 0.0; + QTest::newRow("10") << "+49 1805" << true << 0 << 14.0 << 0.0 << 42.0 << 0.0; + QTest::newRow("11") << "+49 1806" << true << 0 << 0.0 << 20.0 << 0.0 << 60.0; + QTest::newRow("12") << "+49 1807" << true << 30 << 14.0 << 0.0 << 42.0 << 0.0; + } + + + void checkCallCost() + { + QFETCH(QString, phone); + QFETCH(bool, notNull); + QFETCH(int, freeSeconds); + QFETCH(double, landlineCentsPerMinute); + QFETCH(double, landlineCentsPerCall); + QFETCH(double, mobileCentsPerMinute); + QFETCH(double, mobileCentsPerCall); + const ProviderConfigurationInfo provider(QString(), QString(), QString(), QString(), QString(), QString(), QString(""), phone); + const CallCost& callCost = Env::getSingleton()->getCallCost(provider); + + QVERIFY(notNull || callCost.isNull()); + QCOMPARE(callCost.getFreeSeconds(), freeSeconds); + QCOMPARE(callCost.getLandlineCentsPerMinute(), landlineCentsPerMinute); + QCOMPARE(callCost.getLandlineCentsPerCall(), landlineCentsPerCall); + QCOMPARE(callCost.getMobileCentsPerMinute(), mobileCentsPerMinute); + QCOMPARE(callCost.getMobileCentsPerCall(), mobileCentsPerCall); + } + + +}; + +QTEST_GUILESS_MAIN(test_ProviderConfiguration) +#include "test_ProviderConfiguration.moc" diff --git a/test/qt/configuration/test_ProviderConfigurationParser.cpp b/test/qt/configuration/test_ProviderConfigurationParser.cpp new file mode 100644 index 0000000..cbd3928 --- /dev/null +++ b/test/qt/configuration/test_ProviderConfigurationParser.cpp @@ -0,0 +1,342 @@ +/*! + * \brief Unit tests for \ref ProviderConfigurationParser + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ProviderConfigurationParser.h" + +#include "ResourceLoader.h" +#include "TestFileHelper.h" + +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(QLatin1String) + + +class test_ProviderConfigurationParser + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + ResourceLoader::getInstance().init(); + } + + + void parseEmpty() + { + QByteArray data = QByteArray("{}"); + + QCOMPARE(ProviderConfigurationParser::parseCallCosts(data).size(), 0); + QCOMPARE(ProviderConfigurationParser::parseProvider(data).size(), 0); + } + + + void parseProviders() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " \"shortName\": {\"\" : \":::(bit)kasten\", \"de\" : \":::(bit)-de-kasten\", \"fr_FR\" : \":::(bit)-fr-kasten\"}," + " \"address\": \"https://www.bitkasten.de/\"," + " \"phone\": \"\"," + " \"email\": \"\"," + " \"postaladdress\": \"\"," + " \"category\": \"other\"" + " }," + " {" + " \"shortName\": {\"\" : \"Allianz Kundenportal\"}," + " \"longName\": {\"\" : \"Allianz Kundenportal - Meine Allianz\"}," + " \"shortDescription\": {\"\" : \"Kundenportal von Allianz\"}," + " \"longDescription\": {\"\" : \"Kundenportal von Allianz - Meine Allianz\"}," + " \"address\": \"https://meine.allianz.de/form\"," + " \"homepage\": \"https://meine.allianz.de\"," + " \"phone\": \"0421 123456\"," + " \"email\": \"abc@def.de\"," + " \"postalAddress\": \"Am Fallturm 9,\n28359 Bremen\"," + " \"category\": \"insurance\"" + " }" + " ]" + "}"); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QCOMPARE(providers.size(), 2); + + auto provider = providers[0]; + QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)kasten")); + + LanguageLoader::getInstance().mUsedLocale = QLocale("om"); + QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)kasten")); + + LanguageLoader::getInstance().mUsedLocale = QLocale("de"); + QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-de-kasten")); + + LanguageLoader::getInstance().mUsedLocale = QLocale("fr"); + QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-fr-kasten")); + + LanguageLoader::getInstance().mUsedLocale = QLocale("fr_FR"); + QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-fr-kasten")); + + QCOMPARE(provider.getLongName().toString(), QString()); + QCOMPARE(provider.getShortDescription().toString(), QString()); + QCOMPARE(provider.getLongDescription().toString(), QString()); + QCOMPARE(provider.getAddress(), QStringLiteral("https://www.bitkasten.de/")); + QCOMPARE(provider.getHomepage(), QString()); + QCOMPARE(provider.getPhone(), QString()); + QCOMPARE(provider.getEMail(), QString()); + QCOMPARE(provider.getPostalAddress(), QString()); + QCOMPARE(provider.getCategory(), QStringLiteral("other")); + QVERIFY(provider.getIcon()->lookupPath().endsWith("/other_button.svg")); + QVERIFY(provider.getImage()->lookupPath().endsWith("/other_bg.svg")); + + provider = providers[1]; + QCOMPARE(provider.getShortName().toString(), QStringLiteral("Allianz Kundenportal")); + QCOMPARE(provider.getLongName().toString(), QStringLiteral("Allianz Kundenportal - Meine Allianz")); + QCOMPARE(provider.getShortDescription().toString(), QStringLiteral("Kundenportal von Allianz")); + QCOMPARE(provider.getLongDescription().toString(), QStringLiteral("Kundenportal von Allianz - Meine Allianz")); + QCOMPARE(provider.getAddress(), QStringLiteral("https://meine.allianz.de/form")); + QCOMPARE(provider.getHomepage(), QStringLiteral("https://meine.allianz.de")); + QCOMPARE(provider.getPhone(), QStringLiteral("0421 123456")); + QCOMPARE(provider.getEMail(), QStringLiteral("abc@def.de")); + QCOMPARE(provider.getPostalAddress(), QStringLiteral("Am Fallturm 9,\n28359 Bremen")); + QCOMPARE(provider.getCategory(), QStringLiteral("insurance")); + QVERIFY(provider.getIcon()->lookupPath().endsWith("/insurance_button.svg")); + QVERIFY(provider.getImage()->lookupPath().endsWith("/insurance_bg.svg")); + } + + + void parseAdditionalData() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " \"shortName\": {\"\" : \":::(bit)kasten\"}," + " \"address\": \"https://www.bitkasten.de/\"," + " \"phone\": \"\"," + " \"email\": \"\"," + " \"postaladdress\": \"\"," + " \"category\": \"other\"," + " \"someNewProperty\": \"blabla\"" + " }" + " ]" + "}"); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QCOMPARE(providers.size(), 1); + auto provider = providers[0]; + QCOMPARE(provider.getShortName().toString(), QString(":::(bit)kasten")); + QCOMPARE(provider.getAddress(), QString("https://www.bitkasten.de/")); + QCOMPARE(provider.getPhone(), QString("")); + QCOMPARE(provider.getEMail(), QString("")); + QCOMPARE(provider.getPostalAddress(), QString("")); + QCOMPARE(provider.getCategory(), QString("other")); + } + + + void parseTcTokenUrl() + { + QByteArray data = QByteArray("{" + " \"provider\": [" + " {" + " }," + " {" + " \"tcTokenUrl\": \"https://npa.allianz.de/azservice/NpaEIDService/nparef/-wnf\"" + " }" + " ]" + "}"); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QCOMPARE(providers.size(), 2); + + auto provider = providers[0]; + QCOMPARE(provider.getTcTokenUrl(), QUrl()); + + provider = providers[1]; + QCOMPARE(provider.getTcTokenUrl(), QUrl(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\"" + " }" + " ]" + "}"); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QCOMPARE(providers.size(), 2); + + auto provider = providers[0]; + QCOMPARE(provider.getTcTokenUrl(), QUrl()); + + provider = providers[1]; + QCOMPARE(provider.getClientUrl(), QUrl(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\"]" + " }" + " ]" + "}"); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QCOMPARE(providers.size(), 4); + + auto provider = providers[0]; + QCOMPARE(provider.getSubjectUrls(), QStringList()); + + provider = providers[1]; + QCOMPARE(provider.getSubjectUrls(), QStringList()); + + provider = providers[2]; + QCOMPARE(provider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1")})); + + provider = providers[3]; + QCOMPARE(provider.getSubjectUrls(), QStringList({QStringLiteral("https://npa.allianz.de/bla1"), QStringLiteral("https://npa.allianz.de/bla2")})); + } + + + void defaultProviders() + { + QByteArray data = TestFileHelper::readFile(QStringLiteral(":/updatable-files/supported-providers.json")); + + const auto providers = ProviderConfigurationParser::parseProvider(data); + + QVERIFY(!providers.isEmpty()); + } + + + void parseCallCosts() + { + QByteArray data = TestFileHelper::readFile(QStringLiteral(":/updatable-files/supported-providers.json")); + + const auto callCosts = ProviderConfigurationParser::parseCallCosts(data); + + QCOMPARE(callCosts.size(), 17); + } + + + void platformCount_data() + { + QTest::addColumn("count"); + + const int desktop = 65; + QTest::newRow("win") << desktop; + QTest::newRow("mac") << desktop; + QTest::newRow("linux") << desktop; + QTest::newRow("android") << desktop - 6; + QTest::newRow("ios") << 14; + } + + + void platformCount() + { + QFETCH(int, count); + + QByteArray data = TestFileHelper::readFile(QStringLiteral(":/updatable-files/supported-providers.json")); + + const auto providers = ProviderConfigurationParser::parseProvider(data, QLatin1String(QTest::currentDataTag())); + + QCOMPARE(providers.size(), count); + } + + + void checkExcludedPlatform_data() + { + QTest::addColumn("content"); + QTest::addColumn("currentOS"); + QTest::addColumn("excluded"); + + QTest::newRow("mobile") + << QByteArray(R"( ["mobile"] )") << QLatin1String("android") << true; + + QTest::newRow("android") + << QByteArray(R"( ["mac", "android"] )") << QLatin1String("android") << true; + + QTest::newRow("desktop_excluded_mac") + << QByteArray(R"( ["android", "desktop"] )") << QLatin1String("mac") << true; + + QTest::newRow("ios") + << QByteArray(R"( ["android", "desktop"] )") << QLatin1String("ios") << false; + + QTest::newRow("ios") + << QByteArray(R"( ["android", "win"] )") << QLatin1String("ios") << false; + + QTest::newRow("mobile_excluded") + << QByteArray(R"( ["win", "mobile"] )") << QLatin1String("android") << true; + + QTest::newRow("mobile_excluded") + << QByteArray(R"( ["mobile", "win"] )") << QLatin1String("ios") << true; + + QTest::newRow("win_excluded") + << QByteArray(R"( ["win"] )") << QLatin1String("win") << true; + + QTest::newRow("desktop_excluded_single") + << QByteArray(R"( ["desktop"] )") << QLatin1String("win") << true; + + QTest::newRow("win") + << QByteArray(R"( ["mac", "bla", "bsd", "linux", "mobile", "ios", "android"] )") << QLatin1String("win") << false; + + QTest::newRow("desktop_excluded_multi") + << QByteArray(R"( ["mac", "bla", "bsd", "linux", "desktop", "ios", "android"] )") << QLatin1String("win") << true; + + QTest::newRow("win_excluded") + << QByteArray(R"( ["mac", "bla", "dummy", "win"] )") << QLatin1String("win") << true; + + QTest::newRow("nothing") + << QByteArray(R"( [] )") << QLatin1String("win") << false; + } + + + void checkExcludedPlatform() + { + QFETCH(QByteArray, content); + QFETCH(QLatin1String, currentOS); + QFETCH(bool, excluded); + + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + QCOMPARE(ProviderConfigurationParser::isExcludedPlatform(doc.array(), currentOS), excluded); + } + + + void checkExcludedPlatformEmpty() + { + QCOMPARE(ProviderConfigurationParser::isExcludedPlatform(QJsonArray(), QLatin1String("ios")), false); + } + + +}; + +QTEST_GUILESS_MAIN(test_ProviderConfigurationParser) +#include "test_ProviderConfigurationParser.moc" diff --git a/test/qt/configuration/test_ReaderConfiguration.cpp b/test/qt/configuration/test_ReaderConfiguration.cpp new file mode 100644 index 0000000..9e51dee --- /dev/null +++ b/test/qt/configuration/test_ReaderConfiguration.cpp @@ -0,0 +1,292 @@ +/*! + * \brief Unit tests for \ref ReaderConfiguration + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfiguration.h" + +#include "FuncUtils.h" +#include "ResourceLoader.h" + +#include +#include +#include + + +using namespace governikus; + + +class test_ReaderConfiguration + : public QObject +{ + Q_OBJECT + + private: + static const int cCardReadersInConfigurationFile; + + private Q_SLOTS: + void initTestCase() + { + ResourceLoader::getInstance().init(); + } + + + void checkDefaultReader() + { + const ReaderConfigurationInfo readerSettingsInfo = ReaderConfiguration::getInstance().getReaderConfigurationInfo("crap"); + QCOMPARE(readerSettingsInfo.getName(), QString("crap")); + QCOMPARE(readerSettingsInfo.getIcon()->getName(), QString("default_reader.png")); + QCOMPARE(readerSettingsInfo.getIconWithNPA()->getName(), QString("default_reader_mit_ausweis.png")); + QCOMPARE(readerSettingsInfo.getPattern(), QString("")); + } + + + void checkReaderData_data() + { + QTest::addColumn("readerName"); + QTest::addColumn("readerViewName"); + QTest::addColumn("readerIcon"); + QTest::addColumn("readerPattern"); + + QTest::newRow("Remote Cardreader") << "NFC-abcdef1234567890" << "Smartphone als Kartenlesegerät" << "img_RemoteReader" << "^NFC.*"; + + QTest::newRow("REINER SCT cyberJack RFID komfort") << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort" << "img_Reiner_SCT_cyberjack_RFID_komfort" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID standard") << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard" << "img_Reiner_SCT_cyberjack_RFID_standard" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID basis") << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis" << "img_Reiner_SCT_cyberjack_RFID_basis" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack wave") << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave" << "img_cyberjack_wave" << "REINER SCT cyberJack wave"; + + QTest::newRow("KOBIL IDToken") << "KOBIL Systems IDToken" << "KOBIL IDToken" << "img_KOBIL_ID_Token" << "KOBIL (Systems )?IDToken"; + + QTest::newRow("SCM SDI011") << "SDI011 Contactless Reader" << "SDI011 Contactless Reader" << "img_Identive_SDI011" << "SDI011 (USB )?(Smart Card|Contactless) Reader"; + QTest::newRow("SCM SCL011") << "SCM Microsystems Inc. SCL011 Contactless Reader" << "SCL01x Contactless Reader" << "img_Identive_SCL011" << "(SCM Microsystems Inc. )?SCL011 Contactless Reader"; + + QTest::newRow("ACS-ACR122U") << "ACS ACR122U" << "ACS ACR122U" << "img_ACS_ACR122U" << "ACS ACR122U"; + QTest::newRow("ACS-ACR1281U") << "ACS ACR1281 PICC Reader" << "ACS ACR1281U" << "img_ACS_ACR1281U" << "ACS ACR1281 PICC Reader"; + QTest::newRow("ACS-ACR1252U") << "ACS ACR1252 Dual Reader" << "ACS ACR1252U" << "img_ACS_ACR1252U" << "ACS ACR1252 Dual Reader|ACS ACR1252 1S CL Reader"; + + QTest::newRow("OMNIKEY 5021") << "OMNIKEY CardMan 5x21-CL 0" << "OMNIKEY 5021-CL" << "img_HID_Omnikey_Mobile_Reader_5021_CL" << "OMNIKEY CardMan 5x21-CL|OMNIKEY CardMan \\(076B:5340\\) 5021 CL"; + QTest::newRow("OMNIKEY 5421") << "OMNIKEY CardMan (076B:5421) 5421(1)" << "OMNIKEY 5421" << "img_HID_Omnikey_5421" << "OMNIKEY CardMan \\(076B:5421\\) 5421|OMNIKEY Smart Card Reader USB"; + + QTest::newRow("FEIG OBID myAXXESS RFID-Reader") << "FEIG ELECTRONIC GmbH OBID myAXXESS basic" << "OBID RFID-Reader" << "img_FEIG_myAXXES_basic" << "FEIG ELECTRONIC GmbH OBID myAXXESS basic"; + + QTest::newRow("Gemalto-Prox-DU") << "Gemalto Prox-DU" << "Prox-DU HID" << "img_Gemalto_Prox_DU" << "Gemalto Prox(-DU| Dual)($| USB| Contactless_)"; + QTest::newRow("Gemalto-Prox-SU") << "Gemalto Prox SU" << "Gemalto Prox-SU Contactless" << "img_Gemalto_Prox_SU" << "Gemalto Prox( |-)SU"; + + QTest::newRow("Identiv-SCL-3711") << "Identiv SCL3711" << "Identiv SCL3711" << "img_Identive_SCL3711" << "SCL3711"; + QTest::newRow("Identiv-Cloud-3700-F") << "CLOUD 3700 F Contactless Reader" << "Identiv Cloud 3700 F" << "img_Identive_Cloud_3700_F" << "(CLOUD 3700 F Contactless Reader|Identiv uTrust 3700 F CL Reader)"; + QTest::newRow("Identiv-Cloud-4700-F") << "Identiv CLOUD 4700 F Contactless Reader 0" << "Identiv Cloud 4700 F" << "img_Identive_Cloud_4700_F" << "(CLOUD 4700 F Contactless Reader|Identiv uTrust 4700 F Dual Interface Reader)"; + QTest::newRow("Identiv-Cloud-4701-F") << "Identiv CLOUD 4701 F Contactless Reader 0" << "Identiv Cloud 4701 F" << "img_Identive_Cloud_4701_F" << "(CLOUD 4701 F Contactless Reader|Identiv uTrust 4701 F Dual Interface Reader)"; + + QTest::newRow("Cherry-TC-1200-data") << "Cherry TC 1200" << "Cherry TC-1200" << "img_Cherry_TC_1200" << "(Cherry TC 1200($|[^-])|TC 12xx-CL 0|Cherry SC Reader \\(046A:0091\\))"; + QTest::newRow("Cherry-TC-1300-data") << "Cherry TC 1300" << "Cherry TC-1300" << "img_Cherry_TC_1300" << "(Cherry TC 1300|Cherry Smartcard Terminal TC 13xx-CL 0|Cherry SC Reader \\(046A:0092\\))"; + } + + + void checkReaderData() + { + QFETCH(QString, readerName); + QFETCH(QString, readerViewName); + QFETCH(QString, readerIcon); + QFETCH(QString, readerPattern); + + const ReaderConfigurationInfo readerSettingsInfo = ReaderConfiguration::getInstance().getReaderConfigurationInfo(readerName); + QCOMPARE(readerSettingsInfo.getName(), readerViewName); + QCOMPARE(readerSettingsInfo.getIcon()->getName(), readerIcon + ".png"); + QCOMPARE(readerSettingsInfo.getIconWithNPA()->getName(), readerIcon + "_mit_ausweis.png"); + QCOMPARE(readerSettingsInfo.getPattern(), readerPattern); + } + + + void checkReaderPattern_data() + { + QTest::addColumn("readerName"); + QTest::addColumn("readerViewName"); + QTest::addColumn("readerIcon"); + QTest::addColumn("readerPattern"); + + QTest::newRow("UU") << "crap" << "crap"; + + QTest::newRow("Remote Cardreader") << "NFC-abcdef1234567890" << "Smartphone als Kartenlesegerät"; + + QTest::newRow("REINER SCT cyberJack RFID komfort-windows-8.1") << "REINER SCT cyberJack RFID komfort USB 1" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID komfort-windows-10") << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID komfort-macosx-10.10") << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID komfort-macosx-10.11") << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID komfort-macosx-10.12") << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; + + QTest::newRow("REINER SCT cyberJack RFID standard-windows-8.1") << "REINER SCT cyberJack RFID standard USB 1" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID standard-windows-10") << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID standard-macosx-10.10") << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID standard-macosx-10.11") << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID standard-macosx-10.12") << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; + + QTest::newRow("REINER SCT cyberJack RFID basis-windows-8.1") << "REINER SCT cyberJack RFID basis 0" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack RFID basis-windows-10") << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack RFID basis-macosx-10.10") << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack RFID basis-macosx-10.11") << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack RFID basis-macosx-10.12") << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; + + QTest::newRow("REINER SCT cyberJack wave-windows-8.1") << "REINER SCT cyberJack wave USB 1" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-windows-10") << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-macosx-10.10") << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-macosx-10.11") << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-macosx-10.12") << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + + QTest::newRow("KOBIL IDToken-windows-8.1") << "KOBIL IDToken 0" << "KOBIL IDToken"; + QTest::newRow("KOBIL IDToken-windows-10") << "KOBIL IDToken 0" << "KOBIL IDToken"; + QTest::newRow("KOBIL IDToken-macosx-10.10") << "KOBIL Systems IDToken" << "KOBIL IDToken"; + QTest::newRow("KOBIL IDToken-macosx-10.11") << "KOBIL IDToken" << "KOBIL IDToken"; + QTest::newRow("KOBIL IDToken-macosx-10.12") << "KOBIL IDToken" << "KOBIL IDToken"; + + QTest::newRow("SCM SDI011-windows-10") << "SDI011 Contactless Reader" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.10-1") << "SCM Microsystems Inc. SDI011 Contactless Reader(1)" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.10-2") << "SCM Microsystems Inc. SDI011 Contactless Reader(2)" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.11-1") << "SCM Microsystems Inc. SDI011 Contactless Reader(1)" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.11-2") << "SCM Microsystems Inc. SDI011 Contactless Reader(2)" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.12-1") << "SCM Microsystems Inc. SDI011 Contactless Reader(1)" << "SDI011 Contactless Reader"; + QTest::newRow("SCM SDI011-macosx-10.12-1") << "SCM Microsystems Inc. SDI011 Contactless Reader(2)" << "SDI011 Contactless Reader"; + + QTest::newRow("SCM SCL011-windows-10") << "SCL011 Contactless Reader" << "SCL01x Contactless Reader"; + QTest::newRow("SCM SCL011-macosx-10.11") << "SCM Microsystems Inc. SCL011 Contactless Reader" << "SCL01x Contactless Reader"; + + QTest::newRow("ACS-ACR122U-windows-8.1") << "ACS ACR122U PICC Interface 0" << "ACS ACR122U"; + QTest::newRow("ACS-ACR122U-windows-10") << "ACS ACR122U PICC Interface 0" << "ACS ACR122U"; + QTest::newRow("ACS-ACR122U-macosx-10.11") << "ACS ACR122U" << "ACS ACR122U"; + QTest::newRow("ACS-ACR122U-macosx-10.12") << "ACS ACR122U PICC Interface" << "ACS ACR122U"; + + QTest::newRow("ACS-ACR1281U-windows-8.1") << "ACS ACR1281 PICC Reader 0" << "ACS ACR1281U"; + QTest::newRow("ACS-ACR1281U-windows-10") << "ACS ACR1281 PICC Reader 0" << "ACS ACR1281U"; + QTest::newRow("ACS-ACR1281U-macosx-10.10") << "ACS ACR1281 PICC Reader" << "ACS ACR1281U"; + QTest::newRow("ACS-ACR1281U-macosx-10.11") << "ACS ACR1281 PICC Reader" << "ACS ACR1281U"; + QTest::newRow("ACS-ACR1281U-macosx-10.12") << "ACS ACR1281 PICC Reader" << "ACS ACR1281U"; + + QTest::newRow("ACS-ACR1252U-windows-8.1-1") << "ACS ACR1252 Dual Reader PICC 0" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-windows-8.1-2") << "ACS ACR1252 Dual Reader SAM 0" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-windows-10") << "ACS ACR1252 Dual Reader" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-macosx-10.11-1") << "ACS ACR1252 1S CL Reader(1)" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-macosx-10.11-2") << "ACS ACR1252 1S CL Reader(2)" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-macosx-10.12-1") << "ACS ACR1252 1S CL Reader(1)" << "ACS ACR1252U"; + QTest::newRow("ACS-ACR1252U-macosx-10.12-2") << "ACS ACR1252 1S CL Reader(2)" << "ACS ACR1252U"; + + QTest::newRow("OMNIKEY 5021-windows-10") << "OMNIKEY CardMan 5x21-CL 0" << "OMNIKEY 5021-CL"; + QTest::newRow("OMNIKEY 5021-macosx-10.11") << "OMNIKEY CardMan (076B:5340) 5021 CL" << "OMNIKEY 5021-CL"; + QTest::newRow("OMNIKEY 5021-macosx-10.12") << "OMNIKEY CardMan (076B:5340) 5021 CL" << "OMNIKEY 5021-CL"; + + QTest::newRow("OMNIKEY 5421-windows-8.1") << "OMNIKEY Smart Card Reader USB 0" << "OMNIKEY 5421"; + QTest::newRow("OMNIKEY 5421-windows-10") << "OMNIKEY Smart Card Reader USB 0" << "OMNIKEY 5421"; + QTest::newRow("OMNIKEY 5421-macosx-10.11-1") << "OMNIKEY CardMan (076B:5421) 5421(1)" << "OMNIKEY 5421"; + QTest::newRow("OMNIKEY 5421-macosx-10.11-2") << "OMNIKEY CardMan (076B:5421) 5421(2)" << "OMNIKEY 5421"; + QTest::newRow("OMNIKEY 5421-macosx-10.12-1") << "OMNIKEY CardMan (076B:5421) 5421(1)" << "OMNIKEY 5421"; + QTest::newRow("OMNIKEY 5421-macosx-10.12-2") << "OMNIKEY CardMan (076B:5421) 5421(2)" << "OMNIKEY 5421"; + + QTest::newRow("FEIG OBID myAXXESS RFID-Reader-windows-8.1") << "FEIG ELECTRONIC GmbH OBID myAXXESS basic Slot:CL 358334430" << "OBID RFID-Reader"; + QTest::newRow("FEIG OBID myAXXESS RFID-Reader-windows-10") << "FEIG ELECTRONIC GmbH OBID myAXXESS basic" << "OBID RFID-Reader"; + + QTest::newRow("Gemalto-Prox-DU-windows-8.1-1") << "Gemalto Prox-DU Contact_10900383 0" << "Gemalto Prox-DU Contact_10900383 0"; + QTest::newRow("Gemalto-Prox-DU-windows-8.1-2") << "Gemalto Prox-DU Contactless_10900383 0" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-10-1") << "Gemalto Prox-DU" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-10-2") << "Gemalto Prox Dual" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.10-1") << "Gemalto Prox Dual USB PC LinkReader(1)" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.10-2") << "Gemalto Prox Dual USB PC LinkReader(2)" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.11-1") << "Gemalto Prox Dual USB PC Link Reader(1)" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.11-2") << "Gemalto Prox Dual USB PC Link Reader(2)" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.12-1") << "Gemalto Prox Dual USB PC Link Reader(1)" << "Prox-DU HID"; + QTest::newRow("Gemalto-Prox-DU-windows-macosx-10.12-2") << "Gemalto Prox Dual USB PC Link Reader(2)" << "Prox-DU HID"; + + QTest::newRow("Gemalto-Prox-SU-windows-8.1") << "Gemalto Prox-SU Contactless_10800004 0" << "Gemalto Prox-SU Contactless"; + QTest::newRow("Gemalto-Prox-SU-windows-10-1") << "Gemalto Prox SU" << "Gemalto Prox-SU Contactless"; + QTest::newRow("Gemalto-Prox-SU-windows-10-2") << "Gemalto Prox-SU" << "Gemalto Prox-SU Contactless"; + + QTest::newRow("Identiv-SCL-3711-windows-8.1") << "SCM Microsystems SCL3711 reader & NFC device 0" << "Identiv SCL3711"; + QTest::newRow("Identiv-SCL-3711-windows-10") << "Identiv SCL3711" << "Identiv SCL3711"; + QTest::newRow("Identiv-SCL-3711-macosx-10.10") << "SCL3711 reader and NFC device" << "Identiv SCL3711"; + + QTest::newRow("Identiv-Cloud-3700-F-windows-8.1") << "Identiv CLOUD 3700 F Contactless Reader 0" << "Identiv Cloud 3700 F"; + QTest::newRow("Identiv-Cloud-3700-F-windows-10-1") << "CLOUD 3700 F Contactless Reader" << "Identiv Cloud 3700 F"; + QTest::newRow("Identiv-Cloud-3700-F-windows-10-2") << "CLOUD 3700 F Contact Reader" << "CLOUD 3700 F Contact Reader"; + QTest::newRow("Identiv-Cloud-3700-F-macosx-10.10") << "Identiv uTrust 3700 F CL Reader" << "Identiv Cloud 3700 F"; + QTest::newRow("Identiv-Cloud-3700-F-macosx-10.11") << "Identiv uTrust 3700 F CL Reader" << "Identiv Cloud 3700 F"; + QTest::newRow("Identiv-Cloud-3700-F-macosx-10.12") << "Identiv uTrust 3700 F CL Reader" << "Identiv Cloud 3700 F"; + + QTest::newRow("Identiv-Cloud-4700-F-windows-8.1-1") << "Identive CLOUD 4700 F Contactless Reader 0" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-windows-8.1-2") << "Identive CLOUD 4700 F Contact Reader 0" << "Identive CLOUD 4700 F Contact Reader 0"; + QTest::newRow("Identiv-Cloud-4700-F-windows-10-1") << "Identiv CLOUD 4700 F Contactless Reader 0" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-windows-10-2") << "Identiv CLOUD 4700 F Contact Reader 0" << "Identiv CLOUD 4700 F Contact Reader 0"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.10-1") << "Identiv uTrust 4700 F Dual Interface Reader(1)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.10-2") << "Identiv uTrust 4700 F Dual Interface Reader(2)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.11-1") << "Identiv uTrust 4700 F Dual Interface Reader(1)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.11-2") << "Identiv uTrust 4700 F Dual Interface Reader(2)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.12-1") << "Identiv uTrust 4700 F Dual Interface Reader(1)" << "Identiv Cloud 4700 F"; + QTest::newRow("Identiv-Cloud-4700-F-macosx-10.12-2") << "Identiv uTrust 4700 F Dual Interface Reader(2)" << "Identiv Cloud 4700 F"; + + QTest::newRow("Identiv-Cloud-4701-F-windows-8.1-1") << "Identiv CLOUD 4701 F Contactless Reader 0" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-windows-8.1-2") << "Identiv CLOUD 4701 F Contact Reader 0" << "Identiv CLOUD 4701 F Contact Reader 0"; + QTest::newRow("Identiv-Cloud-4701-F-windows-10-1") << "Identiv CLOUD 4701 F Contactless Reader 0" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-windows-10-2") << "Identiv CLOUD 4701 F Contact Reader 0" << "Identiv CLOUD 4701 F Contact Reader 0"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.10-1") << "Identiv uTrust 4701 F Dual Interface Reader(1)" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.10-2") << "Identiv uTrust 4701 F Dual Interface Reader(2)" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.11-1") << "Identiv uTrust 4701 F Dual Interface Reader(1)" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.11-2") << "Identiv uTrust 4701 F Dual Interface Reader(2)" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.12-1") << "Identiv uTrust 4701 F Dual Interface Reader(1)" << "Identiv Cloud 4701 F"; + QTest::newRow("Identiv-Cloud-4701-F-macosx-10.12-2") << "Identiv uTrust 4701 F Dual Interface Reader(2)" << "Identiv Cloud 4701 F"; + + QTest::newRow("Cherry-TC-1200-windows-8.1-1") << "Cherry Smartcard Terminal TC 12xx-CL 0" << "Cherry TC-1200"; + QTest::newRow("Cherry-TC-1200-windows-10-1") << "Cherry Smartcard Terminal TC 12xx 0" << "Cherry Smartcard Terminal TC 12xx 0"; + QTest::newRow("Cherry-TC-1200-windows-10-2") << "Cherry Smartcard Terminal TC 12xx-CL 0" << "Cherry TC-1200"; + QTest::newRow("Cherry-TC-1200-macosx-10.11") << "Cherry SC Reader (046A:0091)" << "Cherry TC-1200"; + QTest::newRow("Cherry-TC-1200-macosx-10.12") << "Cherry SC Reader (046A:0091)" << "Cherry TC-1200"; + QTest::newRow("Cherry-TC-1200-linux") << "Cherry TC 1200" << "Cherry TC-1200"; + + QTest::newRow("Cherry-TC-1300-windows-8.1-1") << "Cherry Smartcard Terminal TC 13xx 0" << "Cherry Smartcard Terminal TC 13xx 0"; + QTest::newRow("Cherry-TC-1300-windows-8.1-2") << "Cherry Smartcard Terminal TC 13xx-CL 0" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-windows-10-1") << "Cherry Smartcard Terminal TC 13xx 0" << "Cherry Smartcard Terminal TC 13xx 0"; + QTest::newRow("Cherry-TC-1300-windows-10-2") << "Cherry Smartcard Terminal TC 13xx-CL 0" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-macosx-10.11-1") << "Cherry SC Reader (046A:0092)(1)" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-macosx-10.11-2") << "Cherry SC Reader (046A:0092)(2)" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-macosx-10.12-1") << "Cherry SC Reader (046A:0092)(1)" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-macosx-10.12-2") << "Cherry SC Reader (046A:0092)(2)" << "Cherry TC-1300"; + QTest::newRow("Cherry-TC-1300-linux") << "Cherry TC 1300" << "Cherry TC-1300"; + } + + + void checkReaderPattern() + { + QFETCH(QString, readerName); + QFETCH(QString, readerViewName); + + const ReaderConfigurationInfo readerSettingsInfo = ReaderConfiguration::getInstance().getReaderConfigurationInfo(readerName); + QCOMPARE(readerSettingsInfo.getName(), readerViewName); + } + + + void uniqueNames() + { + QSet readerNames; + for (const auto& readerSettingsInfo : qAsConst(ReaderConfiguration::getInstance().getReaderConfigurationInfos())) + { + readerNames += readerSettingsInfo.getName(); + } + QCOMPARE(readerNames.size(), cCardReadersInConfigurationFile); + } + + + void forbidEmptyFields() + { + for (const auto& readerSettingsInfo : qAsConst(ReaderConfiguration::getInstance().getReaderConfigurationInfos())) + { + QVERIFY(!readerSettingsInfo.getName().isEmpty()); + QVERIFY(!readerSettingsInfo.getPattern().isEmpty()); + QVERIFY(!readerSettingsInfo.getIcon()->getName().isEmpty()); + QVERIFY(!readerSettingsInfo.getIconWithNPA()->getName().isEmpty()); + } + } + + +}; + + +const int test_ReaderConfiguration::cCardReadersInConfigurationFile = 22; + +QTEST_GUILESS_MAIN(test_ReaderConfiguration) +#include "test_ReaderConfiguration.moc" diff --git a/test/qt/configuration/test_ReaderConfigurationEntryParser.cpp b/test/qt/configuration/test_ReaderConfigurationEntryParser.cpp new file mode 100644 index 0000000..475d8f5 --- /dev/null +++ b/test/qt/configuration/test_ReaderConfigurationEntryParser.cpp @@ -0,0 +1,157 @@ +/*! + * \brief Unit tests for \ref ReaderConfigurationParser + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfigurationParser.h" + +#include + +using namespace governikus; + + +class test_ReaderConfigurationEntryParser + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void matchPlatformCurrentSupported() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "win", "min": "6.1"}, {"os": "mac", "min": "10.9"}, {"os": "unknown"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 0))); // Vista + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::Windows7)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::Windows8)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::Windows8_1)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::Windows10)); + + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::Unknown, 1))); // linux + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 9))); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 0))); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 8))); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 1)) + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::MacOSHighSierra)); +#endif + } + + + void matchPlatformOtherOS() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "win"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 0))); // Vista + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::Windows10)); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::Unknown, 1))); // linux + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + } + + + void matchPlatformMinMax() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "mac", "min": "10.10", "max": "10.11"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::Windows10)); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + } + + + void matchPlatformMultipleMinMax() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "mac", "min": "10.10", "max": "10.10"}, {"os": "mac", "min": "10.13", "max": "10.13"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::Windows10)); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13))); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14))); + } + + + void matchPlatformNothing() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "typo"}, {"os": "typo", "min": "10.10", "max": "10.11"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion(QOperatingSystemVersion::Unknown, 1))); // linux + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::Windows10)); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + } + + + void matchPlatformInsideVersion() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "typo"}, {"os": "mac", "min": "10.10", "max": "10.10"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + auto macOs10_10_1 = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10, 1); + QVERIFY(parser.matchPlatform(data, macOs10_10_1)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + } + + + void matchPlatformInsideVersionWithZero() + { + ReaderConfigurationParser::EntryParser parser(QJsonValue::Null); + QByteArray content = R"( [{"os": "typo"}, {"os": "mac", "min": "10.10", "max": "10.10.0"}] )"; + const auto& doc = QJsonDocument::fromJson(content); + QVERIFY(!doc.isNull()); + const auto& data = doc.array(); + + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXMavericks)); + QVERIFY(parser.matchPlatform(data, QOperatingSystemVersion::OSXYosemite)); + auto macOs10_10_1 = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10, 1); + QVERIFY(!parser.matchPlatform(data, macOs10_10_1)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::OSXElCapitan)); + QVERIFY(!parser.matchPlatform(data, QOperatingSystemVersion::MacOSSierra)); + } + + +}; + +QTEST_GUILESS_MAIN(test_ReaderConfigurationEntryParser) +#include "test_ReaderConfigurationEntryParser.moc" diff --git a/test/qt/configuration/test_ReaderConfigurationParser.cpp b/test/qt/configuration/test_ReaderConfigurationParser.cpp new file mode 100644 index 0000000..37ef74a --- /dev/null +++ b/test/qt/configuration/test_ReaderConfigurationParser.cpp @@ -0,0 +1,359 @@ +/*! + * \brief Unit tests for \ref ReaderDetector + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderConfigurationParser.h" + +#include + +using namespace governikus; + + +namespace +{ +#if defined(Q_OS_WIN) +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5"); +#elif defined(Q_OS_MACOS) +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5"); +#else +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304822&q=driver#choice5"); +#endif +} + + +class test_ReaderConfigurationParser + : public QObject +{ + Q_OBJECT + + private: + void verify_REINER_cyberJack_RFID_komfort(const ReaderConfigurationInfo& info) + { + QCOMPARE(info.getVendorId(), static_cast(0x0C4B)); + QCOMPARE(info.getProductId(), static_cast(0x0501)); + QCOMPARE(info.getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); + QCOMPARE(info.getPattern(), QStringLiteral("REINER SCT cyberJack RFID komfort")); + QCOMPARE(info.getUrl(), KOMFORT_DRIVER_URL); + } + + + QStringList incompleteKeyValuePairs(int skipIndex, bool skipOnlyValue) + { + const QStringList keys = { + "ReaderType", "VendorId", "ProductId", "Name", "Drivers" + }; + const QStringList vals = { + "REINER_cyberJack_RFID_komfort", "0x0C4B", "0x0501", + "REINER SCT cyberJack RFID komfort", + " [\n" + " {\n" + " \"Platforms\": [{\"os\": \"win\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"mac\", \"max\": \"10.10\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"mac\", \"min\": \"10.11\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"unknown\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " }\n" + " ]\n" + }; + QStringList result; + for (int index = 0; index < keys.size(); index++) + { + if (index != skipIndex || skipOnlyValue) + { + const QString key = keys.at(index); + const QString val = index != skipIndex ? vals.at(index) : QString(); + result += QString("\"%1\": \"%2\"\n").arg(key, val); + } + } + + return result; + } + + + QString jsonSingleDeviceString(const QStringList& keyValuePairs) + { + const QString dataPrefix = QStringLiteral("\"SupportedDevices\": [ { "); + const QString dataSuffix = QStringLiteral(" } ]"); + + return dataPrefix + keyValuePairs.join(QStringLiteral(",\n")) + dataSuffix; + } + + + QString jsonDataString(const QString& pDevices) + { + return QStringLiteral("{ %1\n}").arg(pDevices); + } + + + private Q_SLOTS: + void invalidJsonDocument_parseReturnsNullDeviceInfo() + { + const QByteArray data = QByteArrayLiteral("INVALID JSON INPUT"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + + void validJsonDocument_parseReturnsNullDeviceInfo() + { + const QByteArray data = QByteArrayLiteral("{ \"SupportedDevices\": [] }"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + + void validJsonDocumentWithInvalidSupportedDevices_parseReturnsNullDeviceInfo() + { + const QByteArray data = QByteArrayLiteral("{ \"SupportedDevices\": \"\" }"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + + void validJsonDocumentWithOneValidEntry_parseOkAndOneCorrectDeviceInfo() + { + const QByteArray data = QByteArrayLiteral("{" + " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " {\n" + " \"Platforms\": [{\"os\": \"win\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"mac\", \"max\": \"10.10\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"mac\", \"min\": \"10.11\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " },\n" + " {\n" + " \"Platforms\": [{\"os\": \"unknown\"}],\n" + " \"URL\": \"https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304822&q=driver#choice5\"\n" + " }\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + const auto configuration = ReaderConfigurationParser::parse(data); + + QCOMPARE(configuration.size(), 1); + verify_REINER_cyberJack_RFID_komfort(configuration.first()); + } + + + void validJsonDocumentWithOneInvalidEntry_parseErrorAndEmptyDeviceInfo() + { + // Check that a missing property is reported as a parse error. + for (int skipIndex = 0; skipIndex < 5; skipIndex++) + { + // Key with index skipIndex is not in the test Json data. + const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, + /* skipOnlyValue */false)); + const QByteArray data = jsonDataString(devicesPair).toUtf8(); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + // Check that a property with an empty value is reported as a parse error. + for (int skipIndex = 0; skipIndex < 5; skipIndex++) + { + // Key with index skipIndex is in the test Json data but has the invalid value "" + const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, + /* skipOnlyValue */true)); + const QByteArray data = jsonDataString(devicesPair).toUtf8(); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + } + + + void parserAcceptsJSONWithValidReaderIdentification() + { + const QByteArray data = QByteArrayLiteral("{" + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"ReaderType\": \"SCM_SDI011\",\n" + " \"VendorId\": \"0x04E6\",\n" + " \"ProductId\": \"0x512B\",\n" + " \"Name\": \"SDI011 Contactless Reader\",\n" + " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 2); + } + + + void parserAcceptsJSONWithMultipleEmptyPatternsInReadersWithDifferentNames() + { + const QByteArray data = QByteArrayLiteral("{" + " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"ReaderType\": \"SCM_SDI011\",\n" + " \"VendorId\": \"0x04E6\",\n" + " \"ProductId\": \"0x512B\",\n" + " \"Name\": \"SDI011 Contactless Reader\",\n" + " \"Pattern\": \"\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 2); + } + + + void parserRejectsJSONDataWithRepeatedUSBId() + { + const QByteArray data = QByteArrayLiteral("{" + " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"ReaderType\": \"SCM_SDI011\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"SDI011 Contactless Reader\",\n" + " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + + void parserRejectsJSONDataWithRepeatedReaderName() + { + const QByteArray data = QByteArrayLiteral("{" + " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"ReaderType\": \"SCM_SDI011\",\n" + " \"VendorId\": \"0x04E6\",\n" + " \"ProductId\": \"0x512B\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"SDI011 (USB )?(Smart Card|Contactless) Reader\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + + void parserRejectsJSONDataWithRepeatedPattern() + { + const QByteArray data = QByteArrayLiteral("{" + " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," + " \"SupportedDevices\":\n" + " [\n" + " {\n" + " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" + " \"VendorId\": \"0x0C4B\",\n" + " \"ProductId\": \"0x0501\",\n" + " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " },\n" + " {\n" + " \"ReaderType\": \"SCM_SDI011\",\n" + " \"VendorId\": \"0x04E6\",\n" + " \"ProductId\": \"0x512B\",\n" + " \"Name\": \"SDI011 Contactless Reader\",\n" + " \"Pattern\": \"REINER SCT cyberJack RFID komfort\",\n" + " \"Drivers\":\n" + " [\n" + " ]\n" + " }\n" + " ]\n" + "}"); + + QCOMPARE(ReaderConfigurationParser::parse(data).size(), 0); + } + + +}; + +QTEST_GUILESS_MAIN(test_ReaderConfigurationParser) +#include "test_ReaderConfigurationParser.moc" diff --git a/test/qt/core/context/test_AuthContext.cpp b/test/qt/core/context/test_AuthContext.cpp index 5b1f918..81b74ab 100644 --- a/test/qt/core/context/test_AuthContext.cpp +++ b/test/qt/core/context/test_AuthContext.cpp @@ -1,12 +1,9 @@ /*! - * test_AuthContext.cpp - * * \brief Test for the chat administration in authentication context. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ -#include "testMacros.h" #include "TestAuthContext.h" #include "TestFileHelper.h" diff --git a/test/qt/core/controller/test_ChangePinController.cpp b/test/qt/core/controller/test_ChangePinController.cpp index 69be90a..e93bf79 100644 --- a/test/qt/core/controller/test_ChangePinController.cpp +++ b/test/qt/core/controller/test_ChangePinController.cpp @@ -1,20 +1,24 @@ /*! - * test_ChangePinController.h - * * \brief Test for the Change PIN functionality. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include +#include "controller/ChangePinController.h" + +#include "context/ChangePinContext.h" +#include "PersoSimController.h" +#include "ReaderManager.h" +#include "states/AbstractState.h" +#include "states/StateUpdateRetryCounter.h" + #include #include -#include "context/AuthContext.h" -#include "controller/ChangePinController.h" -#include "PersoSimController.h" -#include "ReaderManager.h" -#include "testMacros.h" + +#ifdef PERSOSIM_TESTS_ENABLED +Q_IMPORT_PLUGIN(PcscReaderManagerPlugIn) +#endif using namespace governikus; @@ -29,27 +33,86 @@ class test_ChangePinController QScopedPointer mPersoSim; QSharedPointer mChangePinContext; QScopedPointer mChangePinController; + bool mRetryCounterUpdated = false; + + + void onCardInserted(const QString& pReaderName) + { + if (ReaderManager::getInstance().getReaderInfo(pReaderName).hasEidCard()) + { + Q_EMIT fireEidCardInserted(); + } + } + + + void onStateChanged(const QString& pNextState) + { + if (mRetryCounterUpdated) + { + mRetryCounterUpdated = false; + if (mChangePinContext->getLastPaceResult() != CardReturnCode::OK) + { + QCOMPARE(mChangePinContext->getLastPaceResult(), CardReturnCode::INVALID_PIN); + Q_EMIT mChangePinContext->fireCancelWorkflow(); + return; + } + } + + if (AbstractState::isState(pNextState)) + { + mRetryCounterUpdated = true; + } + + mChangePinContext->setStateApproved(); + } + private Q_SLOTS: void initTestCase() { - SKIP_IF_PERSOSIM_DISABLED(); - mPersoSim.reset(new PersoSimController); + if (!mPersoSim->isEnabled()) + { + QSKIP("PersoSim tests not enabled"); + } + QVERIFY(mPersoSim->init()); + QSignalSpy eidCardDetected(this, &test_ChangePinController::fireEidCardInserted); + + connect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &test_ChangePinController::onCardInserted); ReaderManager::getInstance().init(); + + QVERIFY(eidCardDetected.wait(20000)); } void cleanupTestCase() { ReaderManager::getInstance().shutdown(); + disconnect(&ReaderManager::getInstance(), &ReaderManager::fireCardInserted, this, &test_ChangePinController::onCardInserted); + + QVERIFY(mPersoSim->shutdown()); + mPersoSim.reset(); + } + + + void init() + { + mChangePinContext.reset(new ChangePinContext()); + mChangePinContext->setReaderPlugInTypes({ReaderManagerPlugInType::PCSC}); + connect(mChangePinContext.data(), &WorkflowContext::fireStateChanged, this, &test_ChangePinController::onStateChanged); + + mChangePinController.reset(new ChangePinController(mChangePinContext)); + + mRetryCounterUpdated = false; } void cleanup() { + disconnect(mChangePinContext.data(), &WorkflowContext::fireStateChanged, this, &test_ChangePinController::onStateChanged); + mChangePinController.reset(); mChangePinContext.reset(); } @@ -57,61 +120,38 @@ class test_ChangePinController void testSuccess() { - // set up model - //ChangePinParameters parameters(getPersoSimReaderName(), "123456", "123456"); - //mChangePinModel.reset(new ChangePinModel(parameters)); + qDebug() << "START: testSuccess"; - // create and run controller - mChangePinController.reset(new ChangePinController(mChangePinContext)); + mChangePinContext->setPin("123456"); + mChangePinContext->setNewPin("123456"); QSignalSpy controllerFinishedSpy(mChangePinController.data(), &ChangePinController::fireComplete); mChangePinController->run(); - QVERIFY(controllerFinishedSpy.wait(10000)); + QVERIFY(controllerFinishedSpy.wait()); - //QCOMPARE(mChangePinModel->getResult().getMajor(), Result::Major::Ok); + QCOMPARE(mChangePinContext->getStatus().getStatusCode(), GlobalStatus::Code::No_Error); } void testWrongPin() { - // set up model - //ChangePinParameters parameters(getPersoSimReaderName(), "111111", "111111"); - //mChangePinModel.reset(new ChangePinModel(parameters)); - - // create and run controller - mChangePinController.reset(new ChangePinController(mChangePinContext)); + mChangePinContext->setPin("111111"); + mChangePinContext->setNewPin("111111"); QSignalSpy controllerFinishedSpy(mChangePinController.data(), &ChangePinController::fireComplete); mChangePinController->run(); - QVERIFY(controllerFinishedSpy.wait(10000)); + QVERIFY(controllerFinishedSpy.wait()); - //QCOMPARE(mChangePinModel->getResult().getMajor(), Result::Major::Error); - //QCOMPARE(mChangePinModel->getResult().getMinor(), Result::Minor::AL_Internal_Error); + QCOMPARE(mChangePinContext->getStatus().getStatusCode(), GlobalStatus::Code::Workflow_Cancellation_By_User); } - private: - QString getPersoSimReaderName() const - { - QString readerName; - const auto& infos = ReaderManager::getInstance().getReaderInfos(); - for (const ReaderInfo& readerInfo : infos) - { - if (readerInfo.getName().startsWith(QLatin1String("PersoSim"))) - { - XVERIFY2(readerName.isEmpty(), "multiple PersoSim readers", QString()); - readerName = readerInfo.getName(); - } - } - - XVERIFY2(!readerName.isEmpty(), "no PersoSim reader", QString()); - return readerName; - } - + Q_SIGNALS: + void fireEidCardInserted(); }; diff --git a/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC1.cpp b/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC1.cpp index d480eb6..a5a187a 100644 --- a/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC1.cpp +++ b/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC1.cpp @@ -1,12 +1,13 @@ /*! * \brief Unit tests for \ref DidAuthenticateEAC1 * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/DidAuthenticateResponseEac1.h" #include "asn1/CVCertificate.h" +#include "EstablishPACEChannel.h" #include "TestFileHelper.h" #include diff --git a/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC2.cpp b/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC2.cpp index b3aef25..031ea83 100644 --- a/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC2.cpp +++ b/test/qt/core/paos/invoke/test_DidAuthenticateResponseEAC2.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref DidAuthenticateEAC2 * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/DidAuthenticateResponseEac2.h" diff --git a/test/qt/core/paos/invoke/test_DisconnectResponse.cpp b/test/qt/core/paos/invoke/test_DisconnectResponse.cpp index b080962..4e2efff 100644 --- a/test/qt/core/paos/invoke/test_DisconnectResponse.cpp +++ b/test/qt/core/paos/invoke/test_DisconnectResponse.cpp @@ -1,9 +1,10 @@ /*! * \brief Unit tests for \ref DisconnectResponse * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ +#include "CardReturnCode.h" #include "paos/invoke/DisconnectResponse.h" #include diff --git a/test/qt/core/paos/invoke/test_PaosCreator.cpp b/test/qt/core/paos/invoke/test_PaosCreator.cpp index 2d0f521..a5bea98 100644 --- a/test/qt/core/paos/invoke/test_PaosCreator.cpp +++ b/test/qt/core/paos/invoke/test_PaosCreator.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref PaosCreator * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/PaosCreator.h" @@ -21,7 +21,7 @@ struct test_PaosCreatorDummy QString mText; bool mNamespace = false; - virtual QDomElement getDocumentStructure() + virtual QDomElement getDocumentStructure() override { if (mNamespace) { @@ -115,20 +115,6 @@ class test_PaosCreator } - void createResultElementForNonResponseType() - { - QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - test_PaosCreatorDummy creator; - auto elem = creator.createResultElement(); - QByteArray data = creator.getData(elem); - QVERIFY(data.contains("")); - - QCOMPARE(spy.count(), 1); - auto param = spy.takeFirst(); - QVERIFY(param.at(0).toString().contains("Cannot set Result, message is not of type ResponseType")); - } - - }; QTEST_GUILESS_MAIN(test_PaosCreator) diff --git a/test/qt/core/paos/invoke/test_StartPaos.cpp b/test/qt/core/paos/invoke/test_StartPaos.cpp index 8520cf8..3bc385f 100644 --- a/test/qt/core/paos/invoke/test_StartPaos.cpp +++ b/test/qt/core/paos/invoke/test_StartPaos.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref StartPaos * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/StartPaos.h" @@ -60,7 +60,7 @@ class test_StartPaos QVERIFY(elem.contains("1")); QVERIFY(elem.contains("1")); - QVERIFY(elem.contains("4")); + QVERIFY(elem.contains("5")); } @@ -92,7 +92,7 @@ class test_StartPaos elem.setMessageId("dummy"); QCOMPARE(getValue(elem.createSupportedAPIVersionsElement(), "Major"), QString("1")); QCOMPARE(getValue(elem.createSupportedAPIVersionsElement(), "Minor"), QString("1")); - QCOMPARE(getValue(elem.createSupportedAPIVersionsElement(), "Subminor"), QString("4")); + QCOMPARE(getValue(elem.createSupportedAPIVersionsElement(), "Subminor"), QString("5")); } diff --git a/test/qt/core/paos/invoke/test_TransmitResponse.cpp b/test/qt/core/paos/invoke/test_TransmitResponse.cpp index 476013d..2ce2a61 100644 --- a/test/qt/core/paos/invoke/test_TransmitResponse.cpp +++ b/test/qt/core/paos/invoke/test_TransmitResponse.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref TransmitResponse * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/invoke/TransmitResponse.h" diff --git a/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp b/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp index b199a8c..76b6d10 100644 --- a/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp +++ b/test/qt/core/paos/retrieve/test_DidAuthenticateEac1.cpp @@ -1,9 +1,7 @@ /*! - * test_DidAuthenticateEac1.cpp - * * \brief Unit tests for \DidAuthenticateEac1 * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEac1.h" diff --git a/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp b/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp index a836b60..94541cd 100644 --- a/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp +++ b/test/qt/core/paos/retrieve/test_DidAuthenticateEac2.cpp @@ -1,9 +1,7 @@ /*! - * test_DidAuthenticateEac1.cpp - * * \brief Unit tests for \DidAuthenticateEac1 * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEac2.h" diff --git a/test/qt/core/paos/retrieve/test_DidAuthenticateEacAdditional.cpp b/test/qt/core/paos/retrieve/test_DidAuthenticateEacAdditional.cpp index f410c82..107200c 100644 --- a/test/qt/core/paos/retrieve/test_DidAuthenticateEacAdditional.cpp +++ b/test/qt/core/paos/retrieve/test_DidAuthenticateEacAdditional.cpp @@ -1,9 +1,7 @@ /*! - * test_DidAuthenticateEACAdditionalInputType.cpp - * * \brief Unit tests for \DidAuthenticateEACAdditionalInputType * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/DidAuthenticateEacAdditional.h" diff --git a/test/qt/core/paos/retrieve/test_InitializeFramework.cpp b/test/qt/core/paos/retrieve/test_InitializeFramework.cpp index 41dffa6..0c8a6de 100644 --- a/test/qt/core/paos/retrieve/test_InitializeFramework.cpp +++ b/test/qt/core/paos/retrieve/test_InitializeFramework.cpp @@ -1,9 +1,7 @@ /*! - * test_InitializeFramework.cpp - * * \brief Unit tests for \InitializeFramework * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/InitializeFramework.h" diff --git a/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp b/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp index 0b8a223..8439825 100644 --- a/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp +++ b/test/qt/core/paos/retrieve/test_StartPAOSResponse.cpp @@ -1,9 +1,7 @@ /*! - * test_InitializeFramework.cpp - * * \brief Unit tests for \InitializeFramework * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/StartPaosResponse.h" @@ -33,7 +31,7 @@ class test_StartPAOSResponse StartPaosResponse message(content); QCOMPARE(message.getResult().getMajor(), Result::Major::Ok); - QCOMPARE(message.getResult().getMinor(), GlobalStatus::Code::Unknown_Error); + QCOMPARE(message.getResult().getMinor(), GlobalStatus::Code::No_Error); QVERIFY(message.getResult().getMessage().isNull()); } diff --git a/test/qt/core/paos/retrieve/test_transmit.cpp b/test/qt/core/paos/retrieve/test_transmit.cpp index bb96e65..9fcd647 100644 --- a/test/qt/core/paos/retrieve/test_transmit.cpp +++ b/test/qt/core/paos/retrieve/test_transmit.cpp @@ -1,9 +1,7 @@ /*! - * test_transmit.cpp - * * \brief Unit tests for \transmit * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/retrieve/Transmit.h" @@ -36,20 +34,20 @@ class test_transmit QCOMPARE(transmit->getSlotHandle(), QString("34366364653038392D623031322D346664372D386233362D343664346232393537636236")); QCOMPARE(inputApdusInfos.size(), 7); - QCOMPARE(inputApdusInfos[0].getInputApdu(), - QByteArray("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00")); - QCOMPARE(inputApdusInfos[1].getInputApdu(), - QByteArray("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00")); - QCOMPARE(inputApdusInfos[2].getInputApdu(), - QByteArray("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00")); - QCOMPARE(inputApdusInfos[3].getInputApdu(), - QByteArray("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000")); - QCOMPARE(inputApdusInfos[4].getInputApdu(), - QByteArray("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00")); - QCOMPARE(inputApdusInfos[5].getInputApdu(), - QByteArray("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00")); - QCOMPARE(inputApdusInfos[6].getInputApdu(), - QByteArray("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000")); + QCOMPARE(inputApdusInfos[0].getInputApdu().getBuffer(), + QByteArray::fromHex("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00")); + QCOMPARE(inputApdusInfos[1].getInputApdu().getBuffer(), + QByteArray::fromHex("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00")); + QCOMPARE(inputApdusInfos[2].getInputApdu().getBuffer(), + QByteArray::fromHex("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00")); + QCOMPARE(inputApdusInfos[3].getInputApdu().getBuffer(), + QByteArray::fromHex("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000")); + QCOMPARE(inputApdusInfos[4].getInputApdu().getBuffer(), + QByteArray::fromHex("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00")); + QCOMPARE(inputApdusInfos[5].getInputApdu().getBuffer(), + QByteArray::fromHex("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00")); + QCOMPARE(inputApdusInfos[6].getInputApdu().getBuffer(), + QByteArray::fromHex("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000")); const QByteArrayList emptyList; QCOMPARE(inputApdusInfos[0].getAcceptableStatusCodes(), emptyList); @@ -74,20 +72,20 @@ class test_transmit QCOMPARE(transmit->getRelatesTo(), QString("urn:uuid:04b2b166-77ad-42c9-bb7d-0c5e9798d337")); QCOMPARE(inputApdusInfos.size(), 7); - QCOMPARE(inputApdusInfos[0].getInputApdu(), - QByteArray("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00")); - QCOMPARE(inputApdusInfos[1].getInputApdu(), - QByteArray("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00")); - QCOMPARE(inputApdusInfos[2].getInputApdu(), - QByteArray("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00")); - QCOMPARE(inputApdusInfos[3].getInputApdu(), - QByteArray("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000")); - QCOMPARE(inputApdusInfos[4].getInputApdu(), - QByteArray("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00")); - QCOMPARE(inputApdusInfos[5].getInputApdu(), - QByteArray("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00")); - QCOMPARE(inputApdusInfos[6].getInputApdu(), - QByteArray("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000")); + QCOMPARE(inputApdusInfos[0].getInputApdu().getBuffer(), + QByteArray::fromHex("0CA4040C1D871101F31EC827ABAB92AABD958D297AF9CBD38E0891620AC1E4E686DD00")); + QCOMPARE(inputApdusInfos[1].getInputApdu().getBuffer(), + QByteArray::fromHex("8C2080001D871101F8699BC4D3460854255E0333183A22008E08F7F9BC3379E7B3FF00")); + QCOMPARE(inputApdusInfos[2].getInputApdu().getBuffer(), + QByteArray::fromHex("0C2241A41D8711016F4F279D5EA75DADCD5AB76A434593C08E0831D1B9B36C1504FB00")); + QCOMPARE(inputApdusInfos[3].getInputApdu().getBuffer(), + QByteArray::fromHex("0C8600000001428782013101F5441186D79BC429C472D4D0164862F62A92C6058B6D82F770A827765C9F04DF95F6080BEBC87997825A44921C0AC8FB18D322452C0146DC8565B42896E64DFB92708E732B3266B05BA5E4C0056332075B5CC1CCC4E273FA0DDF08E758027A4A337F54F9DBACBE73068376132641FB26D89DDE9625457000469705F33642318E7149C0636559FAC25B1F955C67390D2D47CBB98C36A8CC32260674A7F3F22A75DB976F364112B156B1E450DB000AA6A87A2D9338069D0012E8EBA3E60453E127D5427EBF3753C2A1BBAFFF8C2394FEB83064409F6412D9435A2C06EE016B26601F051073791C066B21D36ED8D5641C0456F69DFB1FA89CC100624C165B536F492AD2157DB89AA4902F04C57B70F0A97F88C92199216C4377AAB36E5793422582FAF181979F6ADB246584A6EF40CE66309701248E08B1FB40851AF2193E0000")); + QCOMPARE(inputApdusInfos[4].getInputApdu().getBuffer(), + QByteArray::fromHex("8C2080001D87110135B2C0DEDCEEF8399F9F0D7D0BD07D658E08FFB266818231747C00")); + QCOMPARE(inputApdusInfos[5].getInputApdu().getBuffer(), + QByteArray::fromHex("0C2241A41D8711010AF39947D7884D60639BA653B2DE18808E081F8D03FF36BB49AF00")); + QCOMPARE(inputApdusInfos[6].getInputApdu().getBuffer(), + QByteArray::fromHex("0C86000000014287820131014B102237A6D2AC0A7873562D14A36A98CEF053674C3CAB4F09FAFB09ED12941F0DDC27655679D4BD86A12FFD6A3F490B73F2DF03EF19C106D4519929A3116B7BD3AF9FE960BD88F301275EAD3FAA9E832BF93991728E378A2848D60596B1C643DA3E5ADBC119EB3EB444A3789367815B600D218C407A4016F8B3A7923EE8DC3CBE0BD8AA91763859E819B325479F605AA50FC8FF6066055678CE6C1A3FD1DB536E55C3A3D131367AD84B78213667F899D059D313CA7F1EC0785F20F4FEF14D1E3D077B620223E75F101B66262642B1D6416C44AA4ED2EFAC88D7E38EA4EE9EFAA3DAD71E70E96C696A137960532807B52C74070EDA3F573939B39725B86AD0A255E62D26A33C54154ADDF871ED06FD5038B38E3E5E42FF680807734385B900833F54350A447DF71F012B0BE59AB4C6F09701248E0826C663CDA8343CBD0000")); const QByteArrayList emptyList; QCOMPARE(inputApdusInfos[0].getAcceptableStatusCodes(), emptyList); @@ -111,37 +109,37 @@ class test_transmit QCOMPARE(inputApduInfos.size(), 26); QByteArrayList expectedInputApdus; - expectedInputApdus.append("0CA4020C1D871101A59030685388957D6E2B5275AC82BB198E08870AED7F394826C000"); - expectedInputApdus.append("0CB0000000000E970200008E080388A41FBC277C680000"); - expectedInputApdus.append("0CA4020C1D8711013EFE77256902B3E2F1715FCA7EEF223A8E08A02C5F476D8E237700"); - expectedInputApdus.append("0CB0000000000E970200008E080AD2AA74759240CE0000"); - expectedInputApdus.append("0CA4020C1D8711014975FAC0882F0BF4C1E1C5CED555B1F58E08D11E50AA47C7CACC00"); - expectedInputApdus.append("0CB0000000000E970200008E08F98D94F3906A49170000"); - expectedInputApdus.append("0CA4020C1D871101C29B19471B3E36927EC6DA64AEF864CD8E08247F32860E4568A600"); - expectedInputApdus.append("0CB0000000000E970200008E08C5C819FB6A0D695E0000"); - expectedInputApdus.append("0CA4020C1D8711018F820CDBAD555652034E626FB37F86138E08CD3315A36561145000"); - expectedInputApdus.append("0CB0000000000E970200008E08DA60F404B079B0420000"); - expectedInputApdus.append("0CA4020C1D8711018540F01B03C3E973C5777D9BB1F04E9E8E08286A94789231A2FC00"); - expectedInputApdus.append("0CB0000000000E970200008E086A0FDF4AD3FC272B0000"); - expectedInputApdus.append("0CA4020C1D87110195BCF8D7ACEA42AD4683947DBE73BE078E0810B17C642A9001BC00"); - expectedInputApdus.append("0CB0000000000E970200008E08DE56082154DF14190000"); - expectedInputApdus.append("0CA4020C1D871101C2C66976E0156AED1CF30DA2310C6A708E088F9C219BC772629100"); - expectedInputApdus.append("0CB0000000000E970200008E080556C2D7E030B48E0000"); - expectedInputApdus.append("0CA4020C1D87110160A2B6BA12D2EE2171251C30FBC039518E085AAC7E6E9DDD37B600"); - expectedInputApdus.append("0CB0000000000E970200008E08F74B2B26F0CDCCE90000"); - expectedInputApdus.append("0CA4020C1D8711014C3A0C102647A46613A18E3D5480C1328E08D4A2D7785C00692E00"); - expectedInputApdus.append("0CB0000000000E970200008E080C2D48357F0D592D0000"); - expectedInputApdus.append("0CA4020C1D8711017EFE5C0C79DE36B538DDF1FFBF25F1488E08680FA5060E8CCD8A00"); - expectedInputApdus.append("0CB0000000000E970200008E08D871CCADC9A53AA40000"); - expectedInputApdus.append("0CA4020C1D87110137B3389C11D89860CD4CEF705249C38C8E08BE08E0801F8C1E2700"); - expectedInputApdus.append("0CB0000000000E970200008E0867726A6E5F4F8E370000"); - expectedInputApdus.append("0CA4020C1D871101B07423F80083EDD818123BF8422ED77C8E089508DEF13CBE6D8600"); - expectedInputApdus.append("0CB0000000000E970200008E0800A7E854CC4A6F780000"); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101A59030685388957D6E2B5275AC82BB198E08870AED7F394826C000")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080388A41FBC277C680000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711013EFE77256902B3E2F1715FCA7EEF223A8E08A02C5F476D8E237700")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080AD2AA74759240CE0000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711014975FAC0882F0BF4C1E1C5CED555B1F58E08D11E50AA47C7CACC00")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08F98D94F3906A49170000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101C29B19471B3E36927EC6DA64AEF864CD8E08247F32860E4568A600")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08C5C819FB6A0D695E0000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711018F820CDBAD555652034E626FB37F86138E08CD3315A36561145000")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08DA60F404B079B0420000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711018540F01B03C3E973C5777D9BB1F04E9E8E08286A94789231A2FC00")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E086A0FDF4AD3FC272B0000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110195BCF8D7ACEA42AD4683947DBE73BE078E0810B17C642A9001BC00")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08DE56082154DF14190000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101C2C66976E0156AED1CF30DA2310C6A708E088F9C219BC772629100")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080556C2D7E030B48E0000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110160A2B6BA12D2EE2171251C30FBC039518E085AAC7E6E9DDD37B600")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08F74B2B26F0CDCCE90000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711014C3A0C102647A46613A18E3D5480C1328E08D4A2D7785C00692E00")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E080C2D48357F0D592D0000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D8711017EFE5C0C79DE36B538DDF1FFBF25F1488E08680FA5060E8CCD8A00")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E08D871CCADC9A53AA40000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D87110137B3389C11D89860CD4CEF705249C38C8E08BE08E0801F8C1E2700")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E0867726A6E5F4F8E370000")); + expectedInputApdus.append(QByteArray::fromHex("0CA4020C1D871101B07423F80083EDD818123BF8422ED77C8E089508DEF13CBE6D8600")); + expectedInputApdus.append(QByteArray::fromHex("0CB0000000000E970200008E0800A7E854CC4A6F780000")); QCOMPARE(expectedInputApdus.size(), 26); for (int i = 0; i < 26; ++i) { - QCOMPARE(inputApduInfos[i].getInputApdu(), expectedInputApdus[i]); + QCOMPARE(inputApduInfos[i].getInputApdu().getBuffer(), expectedInputApdus[i]); QCOMPARE(inputApduInfos[i].getAcceptableStatusCodes(), QByteArrayList()); } } diff --git a/test/qt/core/paos/test_MessageIdHandler.cpp b/test/qt/core/paos/test_MessageIdHandler.cpp index d8ef3e2..4ea7678 100644 --- a/test/qt/core/paos/test_MessageIdHandler.cpp +++ b/test/qt/core/paos/test_MessageIdHandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/core/paos/test_PaosMessage.cpp b/test/qt/core/paos/test_PaosMessage.cpp index 65ee1e4..82592b4 100644 --- a/test/qt/core/paos/test_PaosMessage.cpp +++ b/test/qt/core/paos/test_PaosMessage.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref PaosMessage * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/PaosMessage.h" diff --git a/test/qt/core/paos/test_RequestType.cpp b/test/qt/core/paos/test_RequestType.cpp index 50ddebf..dc61520 100644 --- a/test/qt/core/paos/test_RequestType.cpp +++ b/test/qt/core/paos/test_RequestType.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref RequestType * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/core/paos/test_UserAgent.cpp b/test/qt/core/paos/test_UserAgent.cpp index 25b3c12..962ad40 100644 --- a/test/qt/core/paos/test_UserAgent.cpp +++ b/test/qt/core/paos/test_UserAgent.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref UserAgent * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "paos/element/UserAgent.h" diff --git a/test/qt/core/paos/test_paoshandler.cpp b/test/qt/core/paos/test_paoshandler.cpp index c18ed09..730d92b 100644 --- a/test/qt/core/paos/test_paoshandler.cpp +++ b/test/qt/core/paos/test_paoshandler.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include diff --git a/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp b/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp index e0b13a4..8903d45 100644 --- a/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp +++ b/test/qt/core/states/test_StateCertificateDescriptionCheck.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateCertificateDescriptionCheck.h" @@ -53,7 +53,7 @@ class test_StateCertificateDescriptionCheck mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescription = QSharedPointer(new CertificateDescription()); mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescriptionAsBinary.clear(); - QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireError); + QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -63,10 +63,10 @@ class test_StateCertificateDescriptionCheck void noSubjectUrl() { + const auto& desc = qSharedPointerConstCast(mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescription); + desc->setSubjectUrl(QString()); - mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescription->setSubjectUrl(QString()); - - QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireError); + QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -79,7 +79,7 @@ class test_StateCertificateDescriptionCheck mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescription = QSharedPointer(new CertificateDescription()); mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCertificateDescriptionAsBinary = QByteArray::fromHex("1234567890abcdef"); - QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireError); + QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -89,7 +89,7 @@ class test_StateCertificateDescriptionCheck void matchingDescription() { - QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireSuccess); + QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -101,7 +101,7 @@ class test_StateCertificateDescriptionCheck { mAuthContext->setTcTokenUrl(QUrl("https://dev-demo.governikus-eid.de:8442/Autent-DemoApplication/RequestServlet;jsessionid=14w5aKuENyd2D4ZsMmuaeX2g")); - QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireError); + QSignalSpy spy(mState.data(), &StateCertificateDescriptionCheck::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateCheckRefreshAddress.cpp b/test/qt/core/states/test_StateCheckRefreshAddress.cpp index 6bd1d41..3d76ace 100644 --- a/test/qt/core/states/test_StateCheckRefreshAddress.cpp +++ b/test/qt/core/states/test_StateCheckRefreshAddress.cpp @@ -1,13 +1,16 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateCheckRefreshAddress.h" #include "context/AuthContext.h" +#include "Env.h" #include "MockNetworkManager.h" #include "states/StateBuilder.h" +#include +#include #include #include #include @@ -20,6 +23,7 @@ class test_StateCheckRefreshAddress { Q_OBJECT QScopedPointer mState; + QScopedPointer mMockNetworkManager; QSharedPointer mAuthContext; Q_SIGNALS: @@ -28,8 +32,10 @@ class test_StateCheckRefreshAddress private Q_SLOTS: void init() { + mMockNetworkManager.reset(new MockNetworkManager); + Env::set(NetworkManager::staticMetaObject, mMockNetworkManager.data()); + mAuthContext.reset(new AuthContext(nullptr)); - mAuthContext->setNetworkManager(new MockNetworkManager); mState.reset(StateBuilder::createState(mAuthContext)); connect(this, &test_StateCheckRefreshAddress::fireStateStart, mState.data(), &AbstractState::onEntry, Qt::ConnectionType::DirectConnection); } @@ -39,6 +45,7 @@ class test_StateCheckRefreshAddress { mState.reset(); mAuthContext.reset(); + mMockNetworkManager.reset(); } @@ -78,7 +85,7 @@ class test_StateCheckRefreshAddress void abortIfNotTcToken() { - QSignalSpy spy(mState.data(), &StateCheckRefreshAddress::fireSuccess); + QSignalSpy spy(mState.data(), &StateCheckRefreshAddress::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -102,7 +109,7 @@ class test_StateCheckRefreshAddress "")); mAuthContext->setTcToken(tcToken); - QSignalSpy spy(mState.data(), &StateCheckRefreshAddress::fireSuccess); + QSignalSpy spy(mState.data(), &StateCheckRefreshAddress::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp b/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp index d1dc0a0..176194d 100644 --- a/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp +++ b/test/qt/core/states/test_StateExtractCvcsFromEac1InputType.cpp @@ -1,12 +1,10 @@ /*! - * test_StateExtractCvcsFromEac1InputType.cpp - * * \brief Tests the StateExtractCvcsFromEac1InputType * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "states/StateExtractCvcsFromEac1IntputType.h" +#include "states/StateExtractCvcsFromEac1InputType.h" #include "TestAuthContext.h" #include "TestFileHelper.h" @@ -22,8 +20,8 @@ class test_StateExtractCvcsFromEac1InputType { Q_OBJECT - QVector > mTerminalCvcs, mDvCvcs, mLinkCvcs, mCvcas; - QScopedPointer mState; + QVector > mTerminalCvcs, mDvCvcs, mLinkCvcs, mCvcas; + QScopedPointer mState; QSharedPointer mAuthContext; Q_SIGNALS: @@ -32,13 +30,13 @@ class test_StateExtractCvcsFromEac1InputType private Q_SLOTS: void initTestCase() { - mTerminalCvcs.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvat-DE0000024001HW.hex"))); - mTerminalCvcs.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvat-DEDEMOPAA00079.hex"))); - mDvCvcs.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvdv-DEDVeIDDPST00039.hex"))); - mDvCvcs.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvdv-DEDVeIDDTR101415.hex"))); - mLinkCvcs.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00102_DECVCAeID00103.hex"))); - mCvcas.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00103.hex"))); - mCvcas.append(CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00102.hex"))); + mTerminalCvcs << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvat-DE0000024001HW.hex")); + mTerminalCvcs << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvat-DEDEMOPAA00079.hex")); + mDvCvcs << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvdv-DEDVeIDDPST00039.hex")); + mDvCvcs << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvdv-DEDVeIDDTR101415.hex")); + mLinkCvcs << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00102_DECVCAeID00103.hex")); + mCvcas << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00103.hex")); + mCvcas << CVCertificate::fromHex(TestFileHelper::readFile(":/card/cvca-DECVCAeID00102.hex")); } @@ -46,8 +44,8 @@ class test_StateExtractCvcsFromEac1InputType { mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1_3.xml")); - mState.reset(new StateExtractCvcsFromEac1IntputType(mAuthContext)); - mState->setStateName("StateExtractCvcsFromEac1IntputType"); + mState.reset(new StateExtractCvcsFromEac1InputType(mAuthContext)); + mState->setStateName("StateExtractCvcsFromEac1InputType"); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.clear(); connect(this, &test_StateExtractCvcsFromEac1InputType::fireStateStart, mState.data(), &AbstractState::onEntry, Qt::ConnectionType::DirectConnection); @@ -64,7 +62,7 @@ class test_StateExtractCvcsFromEac1InputType void testNoDvCvc() { mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mTerminalCvcs.at(0)); - QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1IntputType::fireError); + QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1InputType::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -78,7 +76,7 @@ class test_StateExtractCvcsFromEac1InputType mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mTerminalCvcs.at(0)); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mDvCvcs.at(0)); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mDvCvcs.at(1)); - QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1IntputType::fireError); + QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1InputType::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -90,7 +88,7 @@ class test_StateExtractCvcsFromEac1InputType void testNoTerminalCvc() { mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mDvCvcs.at(0)); - QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1IntputType::fireError); + QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1InputType::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -104,7 +102,7 @@ class test_StateExtractCvcsFromEac1InputType mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mDvCvcs.at(0)); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mTerminalCvcs.at(0)); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mTerminalCvcs.at(1)); - QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1IntputType::fireError); + QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1InputType::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -117,7 +115,7 @@ class test_StateExtractCvcsFromEac1InputType { mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mDvCvcs.at(0)); mAuthContext->getDidAuthenticateEac1()->mEac1InputType.mCvCertificates.append(mTerminalCvcs.at(0)); - QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1IntputType::fireSuccess); + QSignalSpy spy(mState.data(), &StateExtractCvcsFromEac1InputType::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateGenericSendReceive.cpp b/test/qt/core/states/test_StateGenericSendReceive.cpp index 7a6fb18..3a76d80 100644 --- a/test/qt/core/states/test_StateGenericSendReceive.cpp +++ b/test/qt/core/states/test_StateGenericSendReceive.cpp @@ -1,20 +1,19 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "controller/AuthController.h" +#include "Env.h" #include "paos/invoke/InitializeFrameworkResponse.h" #include "paos/retrieve/InitializeFramework.h" #include "states/StateBuilder.h" #include "states/StateGenericSendReceive.h" -#include "TestAuthContext.h" #include "MockNetworkManager.h" +#include "TestAuthContext.h" +#include "TestFileHelper.h" -#include -#include -#include -#include +#include using namespace governikus; @@ -36,12 +35,10 @@ class test_StateGenericSendReceive { mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); - QFile tcTokenFile(":/tctoken/ok.xml"); - QVERIFY(tcTokenFile.open(QIODevice::ReadOnly)); - QSharedPointer tcToken(new TcToken(tcTokenFile.readAll())); + QSharedPointer tcToken(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml"))); mAuthContext->setTcToken(tcToken); mNetworkManager = new MockNetworkManager(); - mAuthContext->setNetworkManager(mNetworkManager.data()); + Env::set(NetworkManager::staticMetaObject, mNetworkManager.data()); mState.reset(StateBuilder::createState(mAuthContext)); mState->setStateName("StateSendInitializeFrameworkResponse"); @@ -57,7 +54,7 @@ class test_StateGenericSendReceive QSharedPointer initializeFrameworkResponse(new InitializeFrameworkResponse()); mAuthContext->setInitializeFrameworkResponse(initializeFrameworkResponse); - QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireError); + QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -73,7 +70,7 @@ class test_StateGenericSendReceive QSharedPointer initializeFrameworkResponse(new InitializeFrameworkResponse()); mAuthContext->setInitializeFrameworkResponse(initializeFrameworkResponse); - QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireSuccess); + QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -105,7 +102,7 @@ class test_StateGenericSendReceive QSharedPointer initializeFrameworkResponse(new InitializeFrameworkResponse()); mAuthContext->setInitializeFrameworkResponse(initializeFrameworkResponse); - QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireError); + QSignalSpy spy(mState.data(), &StateGenericSendReceive::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateInitializeFramework.cpp b/test/qt/core/states/test_StateInitializeFramework.cpp index 93a2813..ebadeca 100644 --- a/test/qt/core/states/test_StateInitializeFramework.cpp +++ b/test/qt/core/states/test_StateInitializeFramework.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "controller/AuthController.h" @@ -41,7 +41,7 @@ class test_StateInitializeFramework void run() { - QSignalSpy spy(mState.data(), &StateInitializeFramework::fireSuccess); + QSignalSpy spy(mState.data(), &StateInitializeFramework::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StatePreVerification.cpp b/test/qt/core/states/test_StatePreVerification.cpp index 47129b1..fc3b1e8 100644 --- a/test/qt/core/states/test_StatePreVerification.cpp +++ b/test/qt/core/states/test_StatePreVerification.cpp @@ -1,16 +1,20 @@ /*! * \brief Unit tests for \ref StatePreVerification * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StatePreVerification.h" #include "AppSettings.h" +#include "Env.h" #include "paos/retrieve/DidAuthenticateEac1.h" +#include "SecureStorage.h" #include "TestFileHelper.h" #include "TestAuthContext.h" + +#include #include #include @@ -32,7 +36,6 @@ class test_StatePreVerification void init() { AbstractSettings::mTestDir.clear(); - AppSettings::getInstance().load(); mAuthContext.reset(new TestAuthContext(nullptr, ":/paos/DIDAuthenticateEAC1.xml")); mAuthContext->initCvcChainBuilder(); @@ -52,7 +55,7 @@ class test_StatePreVerification void testNoCertChain() { - QSignalSpy spy(mState.data(), &StatePreVerification::fireError); + QSignalSpy spy(mState.data(), &StatePreVerification::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -62,9 +65,9 @@ class test_StatePreVerification void testCvcaNotTrusted() { - const_cast >*>(&mState->mTrustedCvcas)->clear(); + const_cast >*>(&mState->mTrustedCvcas)->clear(); - QSignalSpy spy(mState.data(), &StatePreVerification::fireError); + QSignalSpy spy(mState.data(), &StatePreVerification::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -75,10 +78,16 @@ class test_StatePreVerification void testSignatureInvalid() { const_cast(&mState->mValidationDateTime)->setDate(QDate(2013, 12, 1)); - BIGNUM* signaturePart = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(0)->getEcdsaSignature()->r; - BN_pseudo_rand(signaturePart, BN_num_bits(signaturePart), 0, 0); + auto signature = mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(0)->getEcdsaSignature(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BIGNUM* signaturePart = signature->r; +#else + const BIGNUM* signaturePart = nullptr; + ECDSA_SIG_get0(signature.data(), &signaturePart, nullptr); +#endif + BN_pseudo_rand(const_cast(signaturePart), BN_num_bits(signaturePart), 0, 0); - QSignalSpy spy(mState.data(), &StatePreVerification::fireError); + QSignalSpy spy(mState.data(), &StatePreVerification::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -90,7 +99,7 @@ class test_StatePreVerification { const_cast(&mState->mValidationDateTime)->setDate(QDate(2013, 11, 1)); - QSignalSpy spy(mState.data(), &StatePreVerification::fireError); + QSignalSpy spy(mState.data(), &StatePreVerification::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -102,7 +111,7 @@ class test_StatePreVerification { const_cast(&mState->mValidationDateTime)->setDate(QDate(2013, 12, 1)); - QSignalSpy spy(mState.data(), &StatePreVerification::fireSuccess); + QSignalSpy spy(mState.data(), &StatePreVerification::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -112,25 +121,42 @@ class test_StatePreVerification void testSaveLinkCertificates() { - PreVerificationSettings settings; - settings.load(); - for (const QByteArray& cvc : settings.getLinkCertificates()) + const auto& remove = [](QVector >& pVector, const QSharedPointer& pCert) + { + QMutableVectorIterator > iter(pVector); + while (iter.hasNext()) + { + iter.next(); + if (*iter.value() == *pCert) + { + iter.remove(); + } + } + }; + + auto& settings = Env::getSingleton()->getPreVerificationSettings(); + const auto& linkCerts = settings.getLinkCertificates(); + for (const QByteArray& cvc : linkCerts) { settings.removeLinkCertificate(cvc); } settings.save(); - const_cast(&mState->mValidationDateTime)->setDate(QDate(2013, 12, 1)); - // remove DETESTeID00002_DETESTeID00001 - const_cast >*>(&mState->mTrustedCvcas)->removeOne(mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(3)); - // remove DETESTeID00004_DETESTeID00002 - const_cast >*>(&mState->mTrustedCvcas)->removeOne(mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(2)); - QSignalSpy spy(mState.data(), &StatePreVerification::fireSuccess); + const int expectedCvcaSize = 10; + QCOMPARE(mState->mTrustedCvcas.size(), expectedCvcaSize); + const_cast(&mState->mValidationDateTime)->setDate(QDate(2013, 12, 1)); + auto& trustedCvcas = const_cast >&>(mState->mTrustedCvcas); + + remove(trustedCvcas, mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(3)); + remove(trustedCvcas, mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.at(2)); + + QCOMPARE(mState->mTrustedCvcas.size(), expectedCvcaSize - 2); + + QSignalSpy spy(mState.data(), &StatePreVerification::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); QCOMPARE(spy.count(), 1); - settings.load(); QCOMPARE(settings.getLinkCertificates().size(), 2); } diff --git a/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp b/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp index daa032a..6cb7629 100644 --- a/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp +++ b/test/qt/core/states/test_StateProcessCertificatesFromEac2.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref StatePreVerification * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateProcessCertificatesFromEac2.h" @@ -37,7 +37,7 @@ class test_StateProcessCertificatesFromEac2 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); + paceOutput.parse(QByteArray::fromHex(TestFileHelper::readFile(":/card/EstablishPACEChannelOutput.hex")), PACE_PASSWORD_ID::PACE_PIN); mAuthContext->setPaceOutputData(paceOutput); mState.reset(new StateProcessCertificatesFromEac2(mAuthContext)); @@ -57,7 +57,7 @@ class test_StateProcessCertificatesFromEac2 { mAuthContext->initCvcChainBuilder(); - QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireSuccess); + QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -73,7 +73,7 @@ class test_StateProcessCertificatesFromEac2 mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.removeAt(0); mAuthContext->initCvcChainBuilder(); - QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireError); + QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -91,7 +91,7 @@ class test_StateProcessCertificatesFromEac2 mAuthContext->mDIDAuthenticateEAC1->mEac1InputType.mCvCertificates.removeAt(1); mAuthContext->initCvcChainBuilder(); - QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireSuccess); + QSignalSpy spy(mState.data(), &StateProcessCertificatesFromEac2::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateRedirectBrowser.cpp b/test/qt/core/states/test_StateRedirectBrowser.cpp index 62b51b1..c824be3 100644 --- a/test/qt/core/states/test_StateRedirectBrowser.cpp +++ b/test/qt/core/states/test_StateRedirectBrowser.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "states/StateRedirectBrowser.h" @@ -44,7 +44,7 @@ class test_StateRedirectBrowser { mAuthContext->setTcTokenNotFound(true); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireSuccess); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -58,7 +58,7 @@ class test_StateRedirectBrowser { mAuthContext->setTcTokenNotFound(true); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true, "send error")); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireError); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -72,7 +72,7 @@ class test_StateRedirectBrowser { mAuthContext->setTcTokenNotFound(false); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireSuccess); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -86,7 +86,7 @@ class test_StateRedirectBrowser { mAuthContext->setTcTokenNotFound(false); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireError); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -101,7 +101,7 @@ class test_StateRedirectBrowser mAuthContext->setTcTokenNotFound(false); mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/withoutCommunicationErrorAddress.xml")))); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireSuccess); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -116,7 +116,7 @@ class test_StateRedirectBrowser mAuthContext->setTcTokenNotFound(false); mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/withoutCommunicationErrorAddress.xml")))); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, false, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireError); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -131,7 +131,7 @@ class test_StateRedirectBrowser mAuthContext->setTcTokenNotFound(false); mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireSuccess); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -146,7 +146,7 @@ class test_StateRedirectBrowser mAuthContext->setTcTokenNotFound(false); mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, false)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireError); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -162,7 +162,7 @@ class test_StateRedirectBrowser mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); mAuthContext->setRefreshUrl(QUrl("https://bla.de")); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, true)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireSuccess); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -178,7 +178,7 @@ class test_StateRedirectBrowser mAuthContext->setTcToken(QSharedPointer(new TcToken(TestFileHelper::readFile(":/tctoken/ok.xml")))); mAuthContext->setRefreshUrl(QUrl("https://bla.de")); mAuthContext->mActivationContext.reset(new MockActivationContext(true, true, true, false)); - QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireError); + QSignalSpy spy(mState.data(), &StateRedirectBrowser::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_StateStartPaosResponse.cpp b/test/qt/core/states/test_StateStartPaosResponse.cpp index ac8f468..c2925ca 100644 --- a/test/qt/core/states/test_StateStartPaosResponse.cpp +++ b/test/qt/core/states/test_StateStartPaosResponse.cpp @@ -1,5 +1,5 @@ /*! - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -41,30 +41,13 @@ class test_StateStartPaosResponse } - void doNotTakeResultFromStartPAOSResponse() + void takeResultFromStartPAOSResponse() { QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse3.xml"))); mAuthContext->setStartPaosResponse(startPAOSResponse); mAuthContext->setStatus(CardReturnCodeUtil::toGlobalStatus(CardReturnCode::CANCELLATION_BY_USER)); - 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_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); + QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -72,16 +55,15 @@ class test_StateStartPaosResponse 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.")); } - void Q_EMITErrorIfResultError() + void emitErrorIfResultError() { QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse3.xml"))); mAuthContext->setStartPaosResponse(startPAOSResponse); - QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireError); + QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireAbort); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); @@ -90,12 +72,12 @@ class test_StateStartPaosResponse } - void Q_EMITSuccessIfResultOk() + void emitSuccessIfResultOk() { QSharedPointer startPAOSResponse(new StartPaosResponse(TestFileHelper::readFile(":/paos/StartPAOSResponse1.xml"))); mAuthContext->setStartPaosResponse(startPAOSResponse); - QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireSuccess); + QSignalSpy spy(mState.data(), &StateStartPaosResponse::fireContinue); Q_EMIT fireStateStart(nullptr); mAuthContext->setStateApproved(); diff --git a/test/qt/core/states/test_TermsOfUsage.cpp b/test/qt/core/states/test_TermsOfUsage.cpp index 9261503..a308881 100644 --- a/test/qt/core/states/test_TermsOfUsage.cpp +++ b/test/qt/core/states/test_TermsOfUsage.cpp @@ -1,7 +1,7 @@ /*! * \brief Tests the Terms of Usage of CertificateDescription * - * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "asn1/CertificateDescription.h" @@ -49,7 +49,7 @@ class test_TermsOfUsage QFETCH(QString, purpose); const auto& filename = QStringLiteral(":/core/step/2014_07_03_cvcDescription%1.bin").arg(QString::fromLatin1(QTest::currentDataTag())); - QSharedPointer certDescr = CertificateDescription::fromHex(TestFileHelper::readFile(filename).toHex()); + QSharedPointer certDescr = CertificateDescription::fromHex(TestFileHelper::readFile(filename).toHex()); QVERIFY(certDescr); QCOMPARE(certDescr->getPurpose(), purpose); } @@ -58,7 +58,7 @@ class test_TermsOfUsage void testGetDescTestAutentServer() { QByteArray hexValue("3082022F060A04007F00070301030101A12D0C2B446575747363686520506F737420436F6D2C204765736368C3A466747366656C64205369676E7472757374A2191317687474703A2F2F7777772E7369676E74727573742E6465A3080C06626F73204B47A429132768747470733A2F2F6465762D64656D6F2E676F7665726E696B75732D6569642E64653A38343433A58201580C820154416E736368726966743A0D0A6272656D656E206F6E6C696E6520736572766963657320476D6248202620436F2E204B470D0A416D2046616C6C7475726D20390D0A3238333539204272656D656E0D0A0D0A452D4D61696C2D416472657373653A0D0A686240626F732D6272656D656E2E64650D0A0D0A5A7765636B20646573204175736C657365766F7267616E67733A0D0A44656D6F6E7374726174696F6E20646573206549442D536572766963650D0A0D0A5A757374C3A46E6469676520446174656E73636875747A61756673696368743A0D0A446965204C616E64657362656175667472616774652066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E736672656968656974206465722046726569656E2048616E73657374616474204272656D656E0D0A41726E647473747261C39F6520310D0A3237353730204272656D6572686176656EA74631440420761099A58BFD5334E93A7A78E4F18B760FFCF8F513A4730C8AE9B59BCC0FE8C90420CEABB7E427174BCFFFB3499BF925A5D4A7887AD4FCF7747867912DEBB58D684C"); - QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); + QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); QVERIFY(certDescr); QCOMPARE(certDescr->getPurpose(), QStringLiteral("Demonstration des eID-Service")); } @@ -67,7 +67,7 @@ class test_TermsOfUsage void testGetDescRlpDirektServer() { QByteArray hexValue("30820312060A04007F00070301030101A10E0C0C442D547275737420476D6248A2181316687474703A2F2F7777772E642D74727573742E6E6574A33E0C3C4B6F6D6D5769732D476573656C6C73636861667420662E204B6F6D6D756E696B6174696F6E20752E2057697373656E737472616E73666572206D6248A416131468747470733A2F2F74626B2E65776F69732E6465A58201F20C8201EEEFBBBF4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E7374616E626965746572733A0D0A4B6F6D6D5769732D476573656C6C73636861667420662E204B6F6D6D756E696B6174696F6E20752E2057697373656E737472616E73666572206D62480D0A48696E64656E62757267706C61747A20330D0A3535313138204D61696E7A0D0A737570706F7274406B6F6D6D7769732E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A41627769636B6C756E6720766F6E2056657277616C74756E67736C65697374756E67656E206D6974204964656E746966696B6174696F6E73626564617266206F686E652052656769737472696572756E6720696D2053696E6E65206465722047656D4F20526865696E6C616E642D5066616C7A0D0A0D0A5A757374C3A46E6469676520446174656E73636875747A626568C3B67264653A0D0A4175667369636874732D20756E64204469656E73746C65697374756E6773646972656B74696F6E2028414444290D0A54726965720D0A57696C6C792D4272616E64742D506C61747A20330D0A35343239302054726965720D0A303635312F393439342D300D0A706F73747374656C6C65406164642E726C702E64650D0A7777772E646174656E73636875747A2E726C702E6465A7818B31818804205B100843E6D2569F2FB5108A2D327D1929ED7EC814531D014B84C2B76B67FE6904209D8EB0BDF36B19C4AF3147E57401FD792845F0413102A7BD784DF9418098BEBE0420DB37C8E02D6D715EFBFB819D9620C0D411BB6D5F8000200148FFCFA3467F71580420EBD2A9610AA53AE1C159B2C7B238451E2C6AF06F7034723BD4B9743196E6A720"); - QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); + QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); QCOMPARE(certDescr->getPurpose(), QStringLiteral("Abwicklung von Verwaltungsleistungen mit Identifikationsbedarf ohne Registrierung im Sinne der GemO Rheinland-Pfalz")); } @@ -75,7 +75,7 @@ class test_TermsOfUsage void testGetDescAgetoServer() { QByteArray hexValue("3082029E060A04007F00070301030101A1140C12414745544F205365727669636520476D6248A2161314687474703A2F2F7777772E616765746F2E6E6574A3170C15414745544F20496E6E6F766174696F6E20476D6248A421131F68747470733A2F2F6569642E73657276696365732E616765746F2E6E65742FA58201DC0C8201D84E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E7374616E626965746572733A0A414745544F20496E6E6F766174696F6E20476D62480A57696E7A65726C616572205374722E20320A3037373435204A656E610A6E706140616765746F2E6E65740A0A5A7765636B2064657220446174656EC3BC6265726D6974746C756E673A0A4964656E746966697A696572756E6720756E642052656769737472696572756E67207A756D2070657273C3B66E6C696368656E204B756E64656E6B6F6E746F0A0A5A757374C3A46E6469676520446174656E73636875747A626568C3B67264653A0A5468C3BC72696E676572204C616E64657376657277616C74756E6773616D740A5265666572617420486F6865697473616E67656C6567656E68656974656E2C20476566616872656E6162776568720A5765696D6172706C61747A20340A3939343233205765696D61720A0A54656C3A20283033203631292033372037332037322035380A4661783A20283033203631292033372037332037332034360A706F73747374656C6C6540746C7677612E7468756572696E67656E2E64650A416E737072656368706172746E65723A204672617520416E6B65204E65756D616E6EA746314404202E78EBFA001EE9D9F02CCE6B5D93535FC8492FA634BE5BDD679EF430C73864000420D9D682F644CDC3685747104A7CA7C1B3302D81D2A17A88607143F664BF23FF90"); - QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); + QSharedPointer certDescr = CertificateDescription::fromHex(hexValue); QVERIFY(certDescr); QCOMPARE(certDescr->getPurpose(), QStringLiteral("Identifizierung und Registrierung zum pers\u00F6nlichen Kundenkonto")); } diff --git a/test/qt/core/test_CertificateChecker.cpp b/test/qt/core/test_CertificateChecker.cpp index cf264e8..98ce20d 100644 --- a/test/qt/core/test_CertificateChecker.cpp +++ b/test/qt/core/test_CertificateChecker.cpp @@ -1,26 +1,22 @@ /*! * \brief Unit tests for \ref CertificateChecker * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ +#include "CertificateChecker.h" + #include "AppSettings.h" #include "context/AuthContext.h" -#include "CertificateChecker.h" -#include "LogHandler.h" #include "SecureStorage.h" #include "MockActivationContext.h" #include "TestFileHelper.h" -#include -#include #include using namespace governikus; -Q_DECLARE_METATYPE(QSsl::KeyAlgorithm) - class test_CertificateChecker : public QObject { @@ -28,209 +24,29 @@ class test_CertificateChecker QVector certs; - static QSslKey createQSslKeyWithHandle(const QByteArray& pPemEncodedEvpPKey) - { - BIO* bio = BIO_new(BIO_s_mem()); - BIO_write(bio, pPemEncodedEvpPKey.constData(), pPemEncodedEvpPKey.length()); - QSslKey key(PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr), QSsl::PublicKey); - BIO_free(bio); - return key; - } - - private Q_SLOTS: void initTestCase() { - LogHandler::getInstance().init(); - AppSettings::getInstance().load(); - certs = AppSettings::getInstance().getSecureStorage().getUpdateCertificates(); + certs = SecureStorage::getInstance().getUpdateCertificates(); QVERIFY(certs.size() > 0); } - void cleanup() - { - LogHandler::getInstance().resetBacklog(); - } - - void validUpdateCert() { - QSharedPointer model(new AuthContext(new MockActivationContext())); + const QSharedPointer model(new AuthContext(QSharedPointer::create())); + std::function saveCertificateFunc = [&model] + (const QUrl& pUrl, const QSslCertificate& pCert) + { + model->addCertificateData(pUrl, pCert); + }; QCOMPARE(model->getCertificateList().size(), 0); - QCOMPARE(CertificateChecker::checkAndSaveCertificate(certs.at(0), QUrl("dummy"), model), CertificateChecker::CertificateStatus::Good); + QCOMPARE(CertificateChecker::checkAndSaveCertificate(certs.at(0), QUrl("dummy"), model->getDidAuthenticateEac1(), model->getDvCvc(), saveCertificateFunc), CertificateChecker::CertificateStatus::Good); QCOMPARE(model->getCertificateList().size(), 1); } - void hasUpdateCertificateKeyLength() - { - for (const auto& cert : qAsConst(certs)) - { - QVERIFY(CertificateChecker::hasValidCertificateKeyLength(cert)); - } - } - - - void hasCertificateKeyLength_data() - { - QTest::addColumn("filename"); - QTest::addColumn("output"); - - 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 hasCertificateKeyLength() - { - 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(), 3); - auto param = spy.takeLast(); - QVERIFY(param.at(0).toString().contains(output)); - } - - - void checkCertificateHash() - { - QVERIFY(!CertificateChecker::checkCertificate(certs.at(0), QCryptographicHash::Algorithm::Sha256, QSet() << "dummy" << "bla bla")); - QVERIFY(CertificateChecker::checkCertificate(certs.at(0), QCryptographicHash::Algorithm::Sha256, QSet() << "dummy" << "4381E8E49218524CB6A59C26379B1234C32DDBCB04A12988DE249C098FF32ED7" << "bla bla")); - } - - - void hasEmptyEphemeralKey() - { - QSslKey key; - QVERIFY(!CertificateChecker::hasValidEphemeralKeyLength(key)); - } - - - 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 ec112("-----BEGIN PUBLIC KEY-----\n" - "MDIwEAYHKoZIzj0CAQYFK4EEAAcDHgAEWo89aCax3oUWJho7rFZ1u70WqghvA7Tf\n" - "SXXiZw==\n" - "-----END PUBLIC KEY-----"); - - QTest::newRow("ec112") << ec112 << QSsl::KeyAlgorithm::Ec << false; - - /* - * 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 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; - - /* - * 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 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; - - /* - * 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 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; - - /* - * openssl genrsa -out rsa1024_key.pem 1024 - * openssl rsa -in rsa1024_key.pem -out rsa1024_pubkey.pem -pubout - */ - 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; - - /* - * openssl genrsa -out rsa2048_key.pem 2048 - * openssl rsa -in rsa2048_key.pem -out rsa2048_pubkey.pem -pubout - */ - 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(!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); - } - - }; QTEST_GUILESS_MAIN(test_CertificateChecker) diff --git a/test/qt/core/test_DeviceInfo.cpp b/test/qt/core/test_DeviceInfo.cpp deleted file mode 100644 index 72f282c..0000000 --- a/test/qt/core/test_DeviceInfo.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * \brief Unit tests for \ref DeviceInfo - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include - -#include "DeviceInfo.h" - - -using namespace governikus; - - -class test_DeviceInfo - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void getter() - { -#ifdef Q_OS_ANDROID - QVERIFY(!DeviceInfo::getPrettyInfo().isEmpty()); - QVERIFY(!DeviceInfo::getFingerprint().isEmpty()); - QVERIFY(!DeviceInfo::getModel().isEmpty()); -#else - QVERIFY(DeviceInfo::getPrettyInfo().isNull()); - QVERIFY(DeviceInfo::getFingerprint().isNull()); - QVERIFY(DeviceInfo::getModel().isNull()); -#endif - } - - -}; - -QTEST_GUILESS_MAIN(test_DeviceInfo) -#include "test_DeviceInfo.moc" diff --git a/test/qt/core/test_SelfAuthenticationData.cpp b/test/qt/core/test_SelfAuthenticationData.cpp index aaf415c..6e93026 100644 --- a/test/qt/core/test_SelfAuthenticationData.cpp +++ b/test/qt/core/test_SelfAuthenticationData.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref SelfAuthenticationData * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "SelfAuthenticationData.h" diff --git a/test/qt/core/test_TcToken.cpp b/test/qt/core/test_TcToken.cpp index 5717f2f..1a90017 100644 --- a/test/qt/core/test_TcToken.cpp +++ b/test/qt/core/test_TcToken.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref TcToken * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "TcToken.h" @@ -48,7 +48,7 @@ class test_TcToken QCOMPARE(token.getPsk(), QByteArray("4BC1A0B5")); token.clearPsk(); - QVERIFY(token.getPsk().isNull()); + QVERIFY(!token.usePsk()); } @@ -71,7 +71,7 @@ class test_TcToken QVERIFY(!token.getServerAddress().isEmpty()); QVERIFY(!token.getRefreshAddress().isEmpty()); QVERIFY(token.getCommunicationErrorAddress().isEmpty()); - QVERIFY(!token.getPsk().isNull()); + QVERIFY(token.usePsk()); } @@ -96,7 +96,7 @@ class test_TcToken QVERIFY(token.getServerAddress().isEmpty()); QVERIFY(token.getRefreshAddress().isEmpty()); QVERIFY(!token.getCommunicationErrorAddress().isEmpty()); - QVERIFY(token.getPsk().isNull()); + QVERIFY(!token.usePsk()); } @@ -121,7 +121,7 @@ class test_TcToken QVERIFY(token.getServerAddress().isEmpty()); QVERIFY(token.getRefreshAddress().isEmpty()); QVERIFY(!token.getCommunicationErrorAddress().isEmpty()); - QVERIFY(token.getPsk().isNull()); + QVERIFY(!token.usePsk()); } @@ -140,7 +140,7 @@ class test_TcToken " " "")); QVERIFY(!token.isValid()); - QVERIFY(!token.getPsk().isNull()); + QVERIFY(token.usePsk()); } @@ -159,7 +159,7 @@ class test_TcToken " " "")); QVERIFY(!token.isValid()); - QVERIFY(!token.getPsk().isNull()); + QVERIFY(token.usePsk()); } @@ -206,10 +206,10 @@ class test_TcToken QVERIFY(token.getServerAddress().isEmpty()); QVERIFY(token.getRefreshAddress().isEmpty()); QVERIFY(token.getCommunicationErrorAddress().isEmpty()); - QVERIFY(token.getPsk().isNull()); + QVERIFY(!token.usePsk()); token.clearPsk(); - QVERIFY(token.getPsk().isNull()); + QVERIFY(!token.usePsk()); } diff --git a/test/qt/drivers/test_ReaderDetector.cpp b/test/qt/drivers/test_ReaderDetector.cpp index 9b40146..01e44b3 100644 --- a/test/qt/drivers/test_ReaderDetector.cpp +++ b/test/qt/drivers/test_ReaderDetector.cpp @@ -1,77 +1,28 @@ /*! * \brief Unit tests for \ref ReaderDetector * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany */ -#include "DriverParser.h" -#include "FileDestination.h" #include "ReaderDetector.h" -#include "TestFileHelper.h" -#include -#include +#include "Env.h" +#include "MockReaderDetector.h" +#include "ResourceLoader.h" + +#include using namespace governikus; -class ReaderDetectorMock - : public ReaderDetector -{ - Q_OBJECT - - public: - ReaderDetectorMock(const QVector >& pDevIds); - - virtual ~ReaderDetectorMock(); - - QVector > attachedDevIds() const override; - - private: - const QVector > mDevIds; - - QSharedPointer loadTestDrivers(); -}; - - -ReaderDetectorMock::ReaderDetectorMock(const QVector >& pDevIds) - : ReaderDetector(loadTestDrivers()), mDevIds(pDevIds) -{ -} - - -ReaderDetectorMock::~ReaderDetectorMock() -{ -} - - -QVector > ReaderDetectorMock::attachedDevIds() const -{ - return mDevIds; -} - - -QSharedPointer ReaderDetectorMock::loadTestDrivers() -{ - QByteArray data = TestFileHelper::readFile(FileDestination::getPath("default-supported-devices.json")); - - DriverParser parser; - return parser.parse(data); -} - - namespace { #if defined(Q_OS_WIN) -static const QString KOMFORT_DRIVER_URL("https://appl.governikus-asp.de/ausweisapp2/driver/bc_7_2_3.exe"); -#elif defined(Q_OS_OSX) -static const QString KOMFORT_DRIVER_URL = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_11 ? - QStringLiteral("https://appl.governikus-asp.de/ausweisapp2/driver/01_pcsc-cyberjack_3.99.5final.SP08-universal-osx10.11-signed.pkg") : - QStringLiteral("https://appl.governikus-asp.de/ausweisapp2/driver/pcsc-cyberjack_3.99.5final.SP07-universal-signed.pkg"); -#elif defined(Q_OS_LINUX) -static const QString KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-komfort-linux.html"); +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304822&q=driver#choice5"); +#elif defined(Q_OS_MACOS) +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304822&q=driver#choice5"); #else -static const QString KOMFORT_DRIVER_URL("SHOULD NOT BE TESTING THIS"); +const QLatin1String KOMFORT_DRIVER_URL("https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304822&q=driver#choice5"); #endif } @@ -82,273 +33,52 @@ class test_ReaderDetector Q_OBJECT private: - void verify_REINER_cyberJack_RFID_komfort(const QSharedPointer& dev) + void verify_REINER_cyberJack_RFID_komfort(const ReaderConfigurationInfo& info) { - QCOMPARE(dev->getReaderType(), ReaderType::REINER_cyberJack_RFID_komfort); - QCOMPARE(dev->getVendorId(), static_cast(0x0C4B)); - QCOMPARE(dev->getProductId(), static_cast(0x0501)); - QCOMPARE(dev->getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); - QCOMPARE(dev->getDriverUrl(), KOMFORT_DRIVER_URL); - } - - - void verify_REINER_cyberJack_RFID_komfort(const QSharedPointer& driver) - { - QCOMPARE(driver->getReaderType(), QStringLiteral("REINER_cyberJack_RFID_komfort")); - QCOMPARE(driver->getVendorId(), static_cast(0x0C4B)); - QCOMPARE(driver->getProductId(), static_cast(0x0501)); - QCOMPARE(driver->getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); - QCOMPARE(driver->getUrl(), KOMFORT_DRIVER_URL); - } - - - QStringList incompleteKeyValuePairs(int skipIndex, bool skipOnlyValue) - { - const QStringList keys = { - "ReaderType", "VendorId", "ProductId", "Name", "Drivers" - }; - const QStringList vals = { - "REINER_cyberJack_RFID_komfort", "0x0C4B", "0x0501", - "REINER SCT cyberJack RFID komfort", - " [\n" - " {\n" - " \"Platforms\": [\"WV_WINDOWS7\", \"WV_WINDOWS8\", \"WV_WINDOWS8_1\", \"WV_WINDOWS10\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/bc_7_2_3.exe\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"MV_10_9\", \"MV_10_10\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/pcsc-cyberjack_3.99.5final.SP07-universal-signed.pkg\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"MV_10_11\", \"MV_10_12\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/01_pcsc-cyberjack_3.99.5final.SP08-universal-osx10.11-signed.pkg\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"LINUX\"],\n" - " \"URL\": \"https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-komfort-linux.html\"\n" - " }\n" - " ]\n" - }; - QStringList result; - for (int index = 0; index < keys.size(); index++) - { - if (index != skipIndex || skipOnlyValue) - { - const QString key = keys.at(index); - const QString val = index != skipIndex ? vals.at(index) : QString(); - result += QString("\"%1\": \"%2\"\n").arg(key, val); - } - } - - return result; - } - - - QString jsonSingleDeviceString(const QStringList& keyValuePairs) - { - const QString dataPrefix = QStringLiteral("\"SupportedDevices\": [ { "); - const QString dataSuffix = QStringLiteral(" } ]"); - - return dataPrefix + keyValuePairs.join(QStringLiteral(",\n")) + dataSuffix; - } - - - QString jsonDataString(const QString& pDateIssued, const QString& pDevices) - { - return QStringLiteral("{ %1, %2\n}").arg(pDateIssued, pDevices); + QCOMPARE(info.getVendorId(), static_cast(0x0C4B)); + QCOMPARE(info.getProductId(), static_cast(0x0501)); + QCOMPARE(info.getName(), QStringLiteral("REINER SCT cyberJack RFID komfort")); + QCOMPARE(info.getPattern(), QStringLiteral("REINER SCT cyberJack RFID komfort")); + QCOMPARE(info.getUrl(), KOMFORT_DRIVER_URL); } private Q_SLOTS: void initTestCase() { -#if !defined(Q_OS_WIN) && !defined(Q_OS_OSX) && !defined(Q_OS_LINUX) - QSKIP("Test only relevant on Windows, MacOsX and Linux platforms"); -#endif + ResourceLoader::getInstance().init(); } void noAttachedDeviceWithVIDAndPID_noAttachedDevicesFound() { - ReaderDetectorMock readerDetector({}); + const QVector pDevIds({}); + MockReaderDetector readerDetector(pDevIds); - QCOMPARE(readerDetector.getAttachedDevices({}).size(), 0); + QCOMPARE(readerDetector.getAttachedSupportedDevices().size(), 0); } void nonSupportedDeviceAttached_noAttachedDevicesFound() { - ReaderDetectorMock readerDetector({ - {0x413C, 0x2107} - }); + const QVector pDevIds({UsbId(0x413C, 0x2107)}); + MockReaderDetector readerDetector(pDevIds); - QCOMPARE(readerDetector.getAttachedDevices({}).size(), 0); + QCOMPARE(readerDetector.getAttachedSupportedDevices().size(), 0); } void supportedDeviceAttachedButNoDriverInstalled_attachedDeviceFound() { - ReaderDetectorMock readerDetector({ - {0x0C4B, 0x0501} - }); - const auto devs = readerDetector.getAttachedDevices({}); + const QVector pDevIds({UsbId(0x0C4B, 0x0501)}); + MockReaderDetector readerDetector(pDevIds); + const auto devs = readerDetector.getAttachedSupportedDevices(); QCOMPARE(devs.size(), 1); - QCOMPARE(devs.first()->hasDriver(), false); verify_REINER_cyberJack_RFID_komfort(devs.first()); } - void supportedDeviceAttachedAndDriverInstalled_attachedDeviceFound() - { - static const QString READER_NAME("REINER SCT cyberJack RFID komfort"); - static const ReaderType READER_TYPE = ReaderType::REINER_cyberJack_RFID_komfort; - static const ReaderManagerPlugInType PLUGIN_TYPE = ReaderManagerPlugInType::UNKNOWN; - - ReaderDetectorMock readerDetector({ - {0x0C4B, 0x0501} - }); - - const auto devs = readerDetector.getAttachedDevices({ReaderInfo(PLUGIN_TYPE, READER_NAME, READER_TYPE)}); - - QCOMPARE(devs.size(), 1); - QCOMPARE(devs.first()->hasDriver(), true); - verify_REINER_cyberJack_RFID_komfort(devs.first()); - } - - - void invalidJsonDocument_parseReturnsNullDeviceInfo() - { - const QByteArray data = QStringLiteral("INVALID JSON INPUT").toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - - void validJsonDocumentWithoutIssueDate_parseReturnsNullDeviceInfo() - { - const QByteArray data = QStringLiteral("{ \"SupportedDevices\": [] }").toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - - void validJsonDocumentWithoutSupportedDevices_parseReturnsNullDeviceInfo() - { - const QByteArray data = QStringLiteral("{ \"IssueDate\": \"2015-11-03T12:00:00+1:00\" }").toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - - void validJsonDocumentWithInvalidIssueDate_parseReturnsNullDeviceInfo() - { - const QString issueDatePair("\"IssueDate\": \"\""); - const QString devicesPair("\"SupportedDevices\": []"); - const QByteArray data = jsonDataString(issueDatePair, devicesPair).toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - - void validJsonDocumentWithInvalidSupportedDevices_parseReturnsNullDeviceInfo() - { - const QString issueDatePair("\"IssueDate\": \"2015-11-03T12:00:00+1:00\""); - const QString devicesPair("\"SupportedDevices\": \"\""); - const QByteArray data = QStringLiteral("{ %1, %2 }").arg(issueDatePair, devicesPair).toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - - void validEmptyJsonData_parseReturnsValidEmptyDriverInfo() - { - const QString dateKey("IssueDate"); - const QString dateVal("2015-11-03T12:00:00+1:00"); - const QString issueDatePair = QStringLiteral("\"%1\": \"%2\"").arg(dateKey, dateVal); - const QString devicesPair("\"SupportedDevices\": []"); - const QByteArray data = jsonDataString(issueDatePair, devicesPair).toUtf8(); - - DriverParser parser; - const auto settings = parser.parse(data); - - QVERIFY(!settings.isNull()); - QCOMPARE(settings->getIssueDate(), QDateTime::fromString(dateVal, Qt::ISODate)); - QCOMPARE(settings->getDrivers().size(), 0); - } - - - void validJsonDocumentWithOneValidEntry_parseOkAndOneCorrectDeviceInfo() - { - const QByteArray data = QStringLiteral("{" - " \"IssueDate\": \"2015-11-03T12:00:00+1:00\"," - " \"SupportedDevices\":\n" - " [\n" - " {\n" - " \"ReaderType\": \"REINER_cyberJack_RFID_komfort\",\n" - " \"VendorId\": \"0x0C4B\",\n" - " \"ProductId\": \"0x0501\",\n" - " \"Name\": \"REINER SCT cyberJack RFID komfort\",\n" - " \"Drivers\":\n" - " [\n" - " {\n" - " \"Platforms\": [\"WV_WINDOWS7\", \"WV_WINDOWS8\", \"WV_WINDOWS8_1\", \"WV_WINDOWS10\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/bc_7_2_3.exe\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"MV_10_9\", \"MV_10_10\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/pcsc-cyberjack_3.99.5final.SP07-universal-signed.pkg\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"MV_10_11\", \"MV_10_12\"],\n" - " \"URL\": \"https://appl.governikus-asp.de/ausweisapp2/driver/01_pcsc-cyberjack_3.99.5final.SP08-universal-osx10.11-signed.pkg\"\n" - " },\n" - " {\n" - " \"Platforms\": [\"LINUX\"],\n" - " \"URL\": \"https://www.reiner-sct.com/support/download/treiber-und-software/cyberjack/rfid-komfort-linux.html\"\n" - " }\n" - " ]\n" - " }\n" - " ]\n" - "}").toUtf8(); - - DriverParser parser; - const auto settings = parser.parse(data); - - QVERIFY(!settings.isNull()); - QCOMPARE(settings->getDrivers().size(), 1); - verify_REINER_cyberJack_RFID_komfort(settings->getDrivers().first()); - } - - - void validJsonDocumentWithOneInvalidEntry_parseErrorAndEmptyDeviceInfo() - { - const QString issueDatePair("\"IssueDate\": \"2015-11-03T12:00:00+1:00\""); - - // Check that a missing property is reported as a parse error. - for (int skipIndex = 0; skipIndex < 5; skipIndex++) - { - // Key with index skipIndex is not in the test Json data. - const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, - /* skipOnlyValue */false)); - const QByteArray data = jsonDataString(issueDatePair, devicesPair).toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - - // Check that a property with an empty value is reported as a parse error. - for (int skipIndex = 0; skipIndex < 5; skipIndex++) - { - // Key with index skipIndex is in the test Json data but has the invalid value "" - const QString devicesPair = jsonSingleDeviceString(incompleteKeyValuePairs(skipIndex, - /* skipOnlyValue */true)); - const QByteArray data = jsonDataString(issueDatePair, devicesPair).toUtf8(); - - QVERIFY(DriverParser().parse(data).isNull()); - } - } - - }; QTEST_GUILESS_MAIN(test_ReaderDetector) diff --git a/test/qt/export/test_PdfExporter.cpp b/test/qt/export/test_PdfExporter.cpp new file mode 100644 index 0000000..2f40ca3 --- /dev/null +++ b/test/qt/export/test_PdfExporter.cpp @@ -0,0 +1,113 @@ +/*! + * \brief Unit tests for \ref PdfExporter + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "PdfExporter.h" + +#include "AppSettings.h" +#include "ResourceLoader.h" + +#include +#include + +using namespace governikus; + +Q_DECLARE_METATYPE(QVector ) +using Pair = QPair; +Q_DECLARE_METATYPE(QVector ) + +class test_PdfExporter + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + ResourceLoader::getInstance().init(); + } + + + void history_data() + { + QTest::addColumn("min"); + QTest::addColumn("max"); + QTest::addColumn >("infos"); + + QVector entries; + + QTest::newRow("empty") << 10000 << 100000 << entries; + + for (int i = 0; i < 100; ++i) + { + entries << HistoryInfo("SubjectName", "SubjectUrl", "Usage", QDateTime::currentDateTime(), "TermOfUsage", "RequestedData"); + } + QTest::newRow("multiple") << 50000 << 350000 << entries; + } + + + void history() + { + QFETCH(int, min); + QFETCH(int, max); + QFETCH(QVector, infos); + + AppSettings::getInstance().getHistorySettings().setHistoryInfos(infos); + AppSettings::getInstance().getHistorySettings().save(); + + QTemporaryFile file; + QVERIFY(file.open()); + + PdfExporter exporter(file.fileName(), false, false); + QVERIFY(exporter.exportHistory()); + const QFileInfo info(file.fileName()); + qDebug() << info.size(); + QVERIFY(info.size() > min); + QVERIFY(info.size() < max); + } + + + void selfInfo_data() + { + QTest::addColumn("min"); + QTest::addColumn("max"); + QTest::addColumn >("data"); + + QVector > data; + + QTest::newRow("empty") << 10000 << 100000 << data; + + for (int i = 0; i < 100; ++i) + { + data << QPair(QString("key"), QString("value")); + } + QTest::newRow("filled") << 25000 << 100000 << data; + } + + + void selfInfo() + { + QFETCH(int, min); + QFETCH(int, max); + QFETCH(QVector, data); + + const auto& now = QDateTime::currentDateTime(); + + QTemporaryFile file; + QVERIFY(file.open()); + + PdfExporter exporter(file.fileName(), false, false); + QVERIFY(exporter.exportSelfInfo(now, data)); + const QFileInfo info(file.fileName()); + qDebug() << info.size(); + QVERIFY(info.size() > min); + QVERIFY(info.size() < max); + } + + +}; + +QTEST_MAIN(test_PdfExporter) +#include "test_PdfExporter.moc" diff --git a/test/qt/file_provider/test_Downloader.cpp b/test/qt/file_provider/test_Downloader.cpp new file mode 100644 index 0000000..708b7eb --- /dev/null +++ b/test/qt/file_provider/test_Downloader.cpp @@ -0,0 +1,182 @@ +/*! + * \brief Unit tests for class \ref Downloader + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Downloader.h" + +#include "Env.h" +#include "MockNetworkManager.h" + +#include + +using namespace governikus; + +class test_Downloader + : public QObject +{ + Q_OBJECT + + private: + QTemporaryDir mCacheDir; + + void verifySuccessReply(const QSignalSpy& pSpy, const QUrl& pUrl, const QDateTime& pTimestamp, const QByteArray& pData) + { + QCOMPARE(pSpy.count(), 1); + + const QList& arguments = pSpy.first(); + const QVariant updateUrlVariant = arguments.at(0); + QVERIFY(updateUrlVariant.userType() == QMetaType::QUrl); + const QUrl url = updateUrlVariant.toUrl(); + QCOMPARE(url, pUrl); + + const QVariant timestampVariant = arguments.at(1); + QVERIFY(timestampVariant.userType() == QMetaType::QDateTime); + QCOMPARE(timestampVariant.toDateTime(), pTimestamp); + + const QVariant dataVariant = arguments.at(2); + QVERIFY(dataVariant.userType() == QMetaType::QByteArray); + QCOMPARE(dataVariant.toByteArray(), pData); + } + + + void verifyFailedReply(const QSignalSpy& pSpy, const QUrl& pUrl, GlobalStatus::Code pErrorCode) + { + QCOMPARE(pSpy.count(), 1); + + const QList& arguments = pSpy.first(); + const QVariant updateUrlVariant = arguments.at(0); + QVERIFY(updateUrlVariant.userType() == QMetaType::QUrl); + const QUrl url = updateUrlVariant.toUrl(); + QCOMPARE(url, pUrl); + + const QVariant errorCodeVariant = arguments.at(1); + QVERIFY(errorCodeVariant.canConvert()); + QCOMPARE(errorCodeVariant.value(), pErrorCode); + } + + + void verifyUnnecessaryDownloadReply(const QSignalSpy& pSpy, const QUrl& pUrl) + { + QCOMPARE(pSpy.count(), 1); + + const QList& arguments = pSpy.first(); + const QVariant updateUrlVariant = arguments.at(0); + QVERIFY(updateUrlVariant.userType() == QMetaType::QUrl); + const QUrl url = updateUrlVariant.toUrl(); + QCOMPARE(url, pUrl); + } + + + private Q_SLOTS: + void initTestCase() + { + mCacheDir.setAutoRemove(true); + } + + + void init() + { + Env::set(NetworkManager::staticMetaObject, std::make_shared()); + } + + + void cleanup() + { + Env::clear(); + } + + + void downloadExistingFile() + { + const QByteArray fileContent("Some icon data"); + const QDateTime timestampOnServer(QDate(2017, 6, 1), QTime(12, 00, 0, 0)); + MockNetworkReply* const reply = new MockNetworkReply(fileContent, HttpStatusCode::OK); + reply->setFileModificationTimestamp(timestampOnServer); + Env::getSingleton()->setNextReply(reply); + + Downloader* const downloader = Env::getSingleton(); + QSignalSpy spy(downloader, &Downloader::fireDownloadSuccess); + + const QUrl url("http://server/reader/icons/icon.png"); + downloader->download(url); + + Env::getSingleton()->fireFinished(); + + verifySuccessReply(spy, url, timestampOnServer, fileContent); + } + + + void downloadNonExistingFile() + { + MockNetworkReply* const reply = new MockNetworkReply(QByteArray(), HttpStatusCode::NOT_FOUND); + Env::getSingleton()->setNextReply(reply); + + Downloader* const downloader = Env::getSingleton(); + QSignalSpy spy(downloader, &Downloader::fireDownloadFailed); + + const QUrl url("http://server/reader/icons/icon.png"); + downloader->download(url); + + Env::getSingleton()->fireFinished(); + + verifyFailedReply(spy, url, GlobalStatus::Code::Downloader_File_Not_Found); + } + + + void conditionalDownloadOfNewerFile() + { + const QByteArray fileContent("Some icon data"); + MockNetworkReply* const reply = new MockNetworkReply(fileContent, HttpStatusCode::OK); + const QDateTime timestampOnServer(QDate(2017, 7, 1), QTime(12, 00, 0, 0)); + reply->setFileModificationTimestamp(timestampOnServer); + Env::getSingleton()->setNextReply(reply); + + Downloader* const downloader = Env::getSingleton(); + QSignalSpy spy(downloader, &Downloader::fireDownloadSuccess); + + const QUrl url("http://server/reader/icons/icon.png"); + const QDateTime timestampInCache(QDate(2017, 6, 1), QTime(12, 00, 0, 0)); + downloader->downloadIfNew(url, timestampInCache); + + Env::getSingleton()->fireFinished(); + + verifySuccessReply(spy, url, timestampOnServer, fileContent); + + QNetworkRequest* const lastRequest = Env::getSingleton()->getLastRequest(); + QVERIFY(lastRequest); + QCOMPARE(lastRequest->rawHeader(QByteArray("If-Modified-Since")), QLocale::c().toString(timestampInCache, QStringLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); + QCOMPARE(lastRequest->rawHeader(QByteArray("If-Modified-Since")), QByteArray("Thu, 01 Jun 2017 12:00:00 GMT")); + } + + + void conditionalDownloadOfOlderFile() + { + MockNetworkReply* const reply = new MockNetworkReply(QByteArray(), HttpStatusCode::NOT_MODIFIED); + const QDateTime timestampOnServer(QDate(2017, 6, 1), QTime(12, 00, 0, 0)); + reply->setFileModificationTimestamp(timestampOnServer); + Env::getSingleton()->setNextReply(reply); + + Downloader* const downloader = Env::getSingleton(); + QSignalSpy spy(downloader, &Downloader::fireDownloadUnnecessary); + + const QUrl url("http://server/reader/icons/icon.png"); + const QDateTime timestampInCache(QDate(2017, 7, 1), QTime(12, 00, 0, 0)); + downloader->downloadIfNew(url, timestampInCache); + + Env::getSingleton()->fireFinished(); + + verifyUnnecessaryDownloadReply(spy, url); + + QNetworkRequest* const lastRequest = Env::getSingleton()->getLastRequest(); + QVERIFY(lastRequest); + QCOMPARE(lastRequest->rawHeader(QByteArray("If-Modified-Since")), QLocale::c().toString(timestampInCache, QStringLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT'")).toLatin1()); + QCOMPARE(lastRequest->rawHeader(QByteArray("If-Modified-Since")), QByteArray("Sat, 01 Jul 2017 12:00:00 GMT")); + } + + +}; + +QTEST_GUILESS_MAIN(test_Downloader) +#include "test_Downloader.moc" diff --git a/test/qt/file_provider/test_FileProvider.cpp b/test/qt/file_provider/test_FileProvider.cpp new file mode 100644 index 0000000..49024d1 --- /dev/null +++ b/test/qt/file_provider/test_FileProvider.cpp @@ -0,0 +1,65 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "FileProvider.h" + +#include + +using namespace governikus; + +class test_FileProvider + : public QObject +{ + Q_OBJECT + + private: + const QString mSection; + const QString mName1; + const QString mName2; + const QString mDefaultPath; + + private Q_SLOTS: + void testProviderReturnsMeaningfulUpdatableFiles() + { + FileProvider& provider = FileProvider::getInstance(); + const QSharedPointer updatableFile1 = provider.getFile(mSection, mName1, mDefaultPath); + QVERIFY(updatableFile1); + QCOMPARE(updatableFile1->lookupPath(), QStringLiteral(":/updatable-files/reader/img_ACS_ACR1252U.png")); + + const QSharedPointer updatableFile2 = provider.getFile(mSection, mName2, mDefaultPath); + QVERIFY(updatableFile2); + QCOMPARE(updatableFile2->lookupPath(), mDefaultPath); + } + + + void testProviderReturnsUniqueUpdatableFiles() + { + FileProvider& provider = FileProvider::getInstance(); + const QSharedPointer updatableFile11 = provider.getFile(mSection, mName1, mDefaultPath); + const QSharedPointer updatableFile12 = provider.getFile(mSection, mName1, mDefaultPath); + const QSharedPointer updatableFile2 = provider.getFile(mSection, mName2, mDefaultPath); + + QVERIFY(updatableFile11); + QVERIFY(updatableFile12); + QVERIFY(updatableFile2); + + QVERIFY(updatableFile11.data() == updatableFile12.data()); + QVERIFY(updatableFile11.data() != updatableFile2.data()); + } + + + public: + test_FileProvider() + : mSection("reader") + , mName1("img_ACS_ACR1252U.png") + , mName2("img_ACS_ACR1252V.png") + , mDefaultPath(":/images/reader/default_no_reader.png") + { + } + + +}; + +QTEST_GUILESS_MAIN(test_FileProvider) +#include "test_FileProvider.moc" diff --git a/test/qt/file_provider/test_UpdatableFile.cpp b/test/qt/file_provider/test_UpdatableFile.cpp new file mode 100644 index 0000000..5b3fb1e --- /dev/null +++ b/test/qt/file_provider/test_UpdatableFile.cpp @@ -0,0 +1,291 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "UpdatableFile.h" + +#include "Downloader.h" +#include "Env.h" +#include "MockDownloader.h" + +#include + +using namespace governikus; + +class test_UpdatableFile + : public QObject +{ + Q_OBJECT + + private: + const QString mSection; + const QChar mSep; + + void verifySectionCacheFolder(UpdatableFile& pUpdatableFile) + { + QDir folder(pUpdatableFile.getSectionCachePath()); + QVERIFY(folder.exists()); + QVERIFY(pUpdatableFile.getSectionCachePath().endsWith(mSection)); + } + + + void touchFileInCache(const QString& pFilename, UpdatableFile& pUpdatableFile) + { + verifySectionCacheFolder(pUpdatableFile); + + const QString filePath = pUpdatableFile.getSectionCachePath() + mSep + pFilename; + QFile file(filePath); + QVERIFY(!file.exists()); + QVERIFY(file.open(QIODevice::WriteOnly)); + file.close(); + QVERIFY(file.exists()); + } + + + void removeFileFromCache(const QString& pFilename, UpdatableFile& pUpdatableFile) + { + verifySectionCacheFolder(pUpdatableFile); + + const QString filePath = pUpdatableFile.getSectionCachePath() + mSep + pFilename; + QFile file(filePath); + QVERIFY(file.exists()); + QVERIFY(file.remove()); + QVERIFY(!file.exists()); + } + + + private Q_SLOTS: + void cleanup() + { + Env::clear(); + } + + + void testFileOnlyInCache() + { + const QString filename("img_ACS_ACR1252V.png"); + const QString filenameInCache = filename + QStringLiteral("_20170601102132"); + const QDate timestampDate(2017, 6, 1); + const QTime timestampTime(10, 21, 32); + const QDateTime timestamp(timestampDate, timestampTime); + UpdatableFile updatableFile(mSection, filename); + touchFileInCache(filenameInCache, updatableFile); + + QCOMPARE(updatableFile.getName(), filename); + QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache); + QCOMPARE(updatableFile.cacheTimestamp(), timestamp); + + removeFileFromCache(filenameInCache, updatableFile); + } + + + void testFileOnlyInBundle() + { + const QString filename("img_ACS_ACR1252U.png"); + UpdatableFile updatableFile(mSection, filename); + + verifySectionCacheFolder(updatableFile); + QCOMPARE(updatableFile.getName(), filename); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral(":/updatable-files/reader/img_ACS_ACR1252U.png")); + QVERIFY(!updatableFile.cacheTimestamp().isValid()); + } + + + void testFileInCacheAndInBundle() + { + const QString filename("img_ACS_ACR1252U.png"); + const QString filenameInCache = filename + QStringLiteral("_20170601102132"); + UpdatableFile updatableFile(mSection, filename); + touchFileInCache(filenameInCache, updatableFile); + + QCOMPARE(updatableFile.getName(), filename); + QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache); + + removeFileFromCache(filenameInCache, updatableFile); + } + + + void testMoreThanOneVersionInCache() + { + const QString filename("img_ACS_ACR1252U.png"); + const QString filenameInCache1 = filename + QStringLiteral("_20170710120015"); + const QString filenameInCache2 = filename + QStringLiteral("_20170601102132"); + UpdatableFile updatableFile(mSection, filename); + touchFileInCache(filenameInCache1, updatableFile); + touchFileInCache(filenameInCache2, updatableFile); + + QCOMPARE(updatableFile.getName(), filename); + QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache1); + + removeFileFromCache(filenameInCache1, updatableFile); + removeFileFromCache(filenameInCache2, updatableFile); + } + + + void testFileNeitherInCacheNorInBundle() + { + const QString filename("img_ACS_ACR1252V.png"); + UpdatableFile updatableFile(mSection, filename, QStringLiteral("DEFAULT_TEST")); + + verifySectionCacheFolder(updatableFile); + QCOMPARE(updatableFile.getName(), filename); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT_TEST")); + } + + + void testIsDirty() + { + const QString filename("img_ACS_ACR1252U.png"); + const QString dirtyFilename = filename + QStringLiteral(".dirty"); + UpdatableFile updatableFile(mSection, filename); + + QVERIFY(!updatableFile.isDirty()); + + touchFileInCache(dirtyFilename, updatableFile); + QVERIFY(updatableFile.isDirty()); + + removeFileFromCache(dirtyFilename, updatableFile); + QVERIFY(!updatableFile.isDirty()); + } + + + void testMarkDirty() + { + const QString filename("img_ACS_ACR1252U.png"); + const QString dirtyFilename = filename + QStringLiteral(".dirty"); + UpdatableFile updatableFile(mSection, filename); + + QVERIFY(!updatableFile.isDirty()); + + updatableFile.markDirty(); + QVERIFY(updatableFile.isDirty()); + + removeFileFromCache(dirtyFilename, updatableFile); + QVERIFY(!updatableFile.isDirty()); + } + + + void testClearDirty() + { + const QString filename("img_ACS_ACR1252U.png"); + const QString dirtyFilename = filename + QStringLiteral(".dirty"); + UpdatableFile updatableFile(mSection, filename); + + touchFileInCache(dirtyFilename, updatableFile); + QVERIFY(updatableFile.isDirty()); + + updatableFile.clearDirty(); + QVERIFY(!updatableFile.isDirty()); + } + + + void testEmptyName() + { + const QString filename; + const QString dirtyFilename = filename + QStringLiteral(".dirty"); + UpdatableFile updatableFile(mSection, filename, QStringLiteral("DEFAULT")); + + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + + updatableFile.markDirty(); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + + updatableFile.clearDirty(); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + + touchFileInCache(dirtyFilename, updatableFile); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + + removeFileFromCache(dirtyFilename, updatableFile); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral("DEFAULT")); + } + + + void testFileIsDownloadedOnDirty() + { + MockDownloader downloader; + Env::set(Downloader::staticMetaObject, &downloader); + + const QString filename("img_ACS_ACR1252U.png"); + const QString filenameInCache = filename + QLatin1Char('_') + downloader.getTimeStampString(); + + UpdatableFile updatableFile(mSection, filename); + QUrl updateUrl = updatableFile.updateUrl(mSection, filename); + QByteArray testData = QByteArray("Testdata"); + downloader.setTestData(updateUrl, testData); + + updatableFile.markDirty(); + + QSignalSpy spy(&updatableFile, &UpdatableFile::fireUpdated); + QCOMPARE(updatableFile.lookupPath(), QStringLiteral(":/updatable-files/reader/img_ACS_ACR1252U.png")); + + QCOMPARE(spy.count(), 1); + QVERIFY(!updatableFile.isDirty()); + QCOMPARE(updatableFile.lookupPath(), updatableFile.getSectionCachePath() + mSep + filenameInCache); + } + + + void testFileIsCreatedAfterUpdate() + { + MockDownloader downloader; + Env::set(Downloader::staticMetaObject, &downloader); + + const QString filename("img_updatetest.png"); + + UpdatableFile updatableFile(mSection, filename); + QSignalSpy spy(&updatableFile, &UpdatableFile::fireUpdated); + QUrl updateUrl = updatableFile.updateUrl(mSection, filename); + QByteArray testData = "Testdata"; + downloader.setTestData(updateUrl, testData); + + updatableFile.update(); + + QCOMPARE(spy.count(), 1); + const QString fileName = updatableFile.getName() + QLatin1Char('_') + downloader.getTimeStampString(); + const QString filePath = updatableFile.getSectionCachePath() + "/" + fileName; + QFile testfile(filePath); + QVERIFY(testfile.exists()); + QVERIFY(testfile.open(QIODevice::ReadOnly)); + QCOMPARE(testfile.readAll(), downloader.getTestData(updateUrl)); + testfile.close(); + + removeFileFromCache(fileName, updatableFile); + } + + + void testNoFileIsCreatedAfterFailedUpdate() + { + MockDownloader downloader(GlobalStatus::Code::Downloader_File_Not_Found); + Env::set(Downloader::staticMetaObject, &downloader); + + const QString filename("img_updatetest.png"); + + UpdatableFile updatableFile(mSection, filename); + QSignalSpy spy(&updatableFile, &UpdatableFile::fireUpdated); + + updatableFile.update(); + + QCOMPARE(spy.count(), 0); + const QString filePath = updatableFile.getSectionCachePath() + "/" + updatableFile.getName() + QLatin1Char('_') + downloader.getTimeStampString(); + QFile testfile(filePath); + QVERIFY(!testfile.exists()); + } + + + public: + test_UpdatableFile() + : mSection("reader") + , mSep('/') + { + } + + +}; + +QTEST_GUILESS_MAIN(test_UpdatableFile) +#include "test_UpdatableFile.moc" diff --git a/test/qt/global/test_BuildHelper.cpp b/test/qt/global/test_BuildHelper.cpp index 9529abe..7eb12e4 100644 --- a/test/qt/global/test_BuildHelper.cpp +++ b/test/qt/global/test_BuildHelper.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref BuildHelper * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "BuildHelper.h" diff --git a/test/qt/global/test_CardReturnCode.cpp b/test/qt/global/test_CardReturnCode.cpp index a1bf96b..088b99c 100644 --- a/test/qt/global/test_CardReturnCode.cpp +++ b/test/qt/global/test_CardReturnCode.cpp @@ -1,15 +1,16 @@ /*! * \brief Unit tests for return codes. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "CardReturnCode.h" +#include "Result.h" + #include #include #include -#include "Result.h" - using namespace governikus; diff --git a/test/qt/global/test_DeviceInfo.cpp b/test/qt/global/test_DeviceInfo.cpp new file mode 100644 index 0000000..2f48d00 --- /dev/null +++ b/test/qt/global/test_DeviceInfo.cpp @@ -0,0 +1,39 @@ +/*! + * \brief Unit tests for \ref DeviceInfo + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include +#include + +#include "DeviceInfo.h" + + +using namespace governikus; + + +class test_DeviceInfo + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void getter() + { +#ifdef Q_OS_ANDROID + QVERIFY(!DeviceInfo::getPrettyInfo().isEmpty()); + QVERIFY(!DeviceInfo::getFingerprint().isEmpty()); + QVERIFY(!DeviceInfo::getName().isEmpty()); +#else + QCOMPARE(DeviceInfo::getPrettyInfo(), QSysInfo::machineHostName() + QStringLiteral(" ()")); + QVERIFY(DeviceInfo::getFingerprint().isNull()); + QCOMPARE(DeviceInfo::getName(), QSysInfo::machineHostName()); +#endif + } + + +}; + +QTEST_GUILESS_MAIN(test_DeviceInfo) +#include "test_DeviceInfo.moc" diff --git a/test/qt/global/test_EnumHelper.cpp b/test/qt/global/test_EnumHelper.cpp index 4d83419..f9fe53a 100644 --- a/test/qt/global/test_EnumHelper.cpp +++ b/test/qt/global/test_EnumHelper.cpp @@ -1,9 +1,7 @@ /*! - * test_EnumHelper.h - * * \brief Unit tests for EnumHelper. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "EnumHelper.h" @@ -13,6 +11,16 @@ #include using namespace governikus; + +namespace +{ +#ifdef Q_OS_WIN +const QLatin1String lineBreak("\r\n"); +#else +const QLatin1Char lineBreak('\n'); +#endif +} + namespace governikus { defineEnumType(TestEnum1, FIRST, SECOND, THIRD) @@ -81,7 +89,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(QStringLiteral("FIRST") + lineBreak)); } @@ -93,10 +101,10 @@ class test_EnumHelper QCOMPARE(Enum::getName(TestEnum1::SECOND), QStringLiteral("SECOND")); QCOMPARE(Enum::getName(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")); + testBadConverion(6, QStringLiteral("UNKNOWN 0x6") + lineBreak); + testBadConverion(255, QStringLiteral("UNKNOWN 0xff") + lineBreak); + testBadConverion(365, QStringLiteral("UNKNOWN 0x16d") + lineBreak); + testBadConverion(2147483647, QStringLiteral("UNKNOWN 0x7fffffff") + lineBreak); QCOMPARE(getEnumName(TestEnum1::SECOND), QStringLiteral("SECOND")); QCOMPARE(getEnumName(EnumTestEnum1::TestEnum1::SECOND), QStringLiteral("SECOND")); @@ -130,7 +138,7 @@ class test_EnumHelper QVERIFY(Enum::isValue(static_cast(0xaa))); QVERIFY(!Enum::isValue(char(999))); - QVERIFY(Enum::isValue(char(0))); + QVERIFY(Enum::isValue('\0')); QVERIFY(!Enum::isValue(char(0xbb))); QVERIFY(Enum::isValue(char(0xff))); diff --git a/test/qt/global/test_Env.cpp b/test/qt/global/test_Env.cpp new file mode 100644 index 0000000..c9f73f2 --- /dev/null +++ b/test/qt/global/test_Env.cpp @@ -0,0 +1,627 @@ +/*! + * \brief Unit tests for \ref Env + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Env.h" + +#include +#include + +using namespace governikus; + +namespace +{ +class AbstractTestPodInstance +{ + public: + virtual ~AbstractTestPodInstance() + { + } + + + virtual QString dummy() = 0; +}; + +class AbstractTestInstance +{ + Q_GADGET + + public: + virtual ~AbstractTestInstance() + { + } + + + virtual QString dummy() = 0; +}; + +class AbstractTestInstanceImpl + : public AbstractTestInstance +{ + Q_GADGET + + public: + virtual QString dummy() override + { + return QStringLiteral("impl"); + } + + +}; + +class MockedAbstractTestInstance + : public AbstractTestInstance +{ + Q_GADGET + + public: + virtual QString dummy() override + { + 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"); + } + + +}; + + +class TestMoveCtorAssign + : public QObject +{ + Q_OBJECT + + private: + QString mData; + + public: + TestMoveCtorAssign(const QString& pData) + : mData(pData) + { + } + + + TestMoveCtorAssign(TestMoveCtorAssign&& pCopy) + { + mData = std::move(pCopy.mData); + } + + + TestMoveCtorAssign& operator=(TestMoveCtorAssign&& pCopy) + { + mData = std::move(pCopy.mData); + return *this; + } + + + QString data() + { + return mData; + } + + +}; + +} + +namespace governikus +{ + +template<> TestAbstractUnmanagedInstance* singleton(bool& pTakeOwnership) +{ + pTakeOwnership = false; + static TestUnmanagedInstance instance; + return &instance; +} + + +template<> AbstractTestInstance* singleton(bool&) +{ + return new AbstractTestInstanceImpl; +} + + +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); +} + + +template<> AbstractTestPodInstance* createNewObject() +{ + return nullptr; +} + + +template<> AbstractTestPodInstance* createNewObject(QString&&) +{ + return nullptr; +} + + +} + + +class test_Env + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void cleanup() + { + Env::clear(); + } + + + void checkOverrideMock() + { + QCOMPARE(Env::getInstance().mInstancesCreator.size(), 0); + + QScopedPointer obj(Env::create()); + QVERIFY(obj); + + const std::function func = [](){ + return nullptr; + }; + Env::setCreator(func); + + QCOMPARE(Env::getInstance().mInstancesCreator.size(), 1); + Env::setCreator(func); + Env::setCreator(func); + Env::setCreator(func); + QCOMPARE(Env::getInstance().mInstancesCreator.size(), 1); + + QCOMPARE(Env::create(), nullptr); + } + + + void mockGet() + { + auto orig = Env::getSingleton(); + QVERIFY(orig); + QCOMPARE(orig->something(), QLatin1String("orig")); + + TestMockedInstance mock; + Env::set(TestInstance::staticMetaObject, &mock); + auto mocked = Env::getSingleton(); + QVERIFY(mocked); + QCOMPARE(mocked->something(), QLatin1String("mocked")); + + Env::set(TestInstance::staticMetaObject); + auto orig_again = Env::getSingleton(); + QVERIFY(orig_again); + QCOMPARE(orig_again->something(), QLatin1String("orig")); + } + + + void mockAbstract() + { + auto impl = Env::getSingleton(); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("impl")); + + auto impl2 = Env::getSingleton(); + QVERIFY(impl == impl2); + + MockedAbstractTestInstance m; + Env::set(AbstractTestInstance::staticMetaObject, &m); + auto mocked = Env::getSingleton(); + QVERIFY(mocked); + QVERIFY(mocked != impl); + QCOMPARE(mocked->dummy(), QLatin1String("mocked")); + } + + + void mockShared() + { + auto orig = Env::getShared(); + QVERIFY(orig); + QCOMPARE(orig->something(), QLatin1String("orig")); + + auto orig2 = Env::getShared(); + QVERIFY(orig == orig2); + + auto mock = QSharedPointer::create(); + Env::setShared(TestSharedInstance::staticMetaObject, mock); + auto mocked = Env::getShared(); + QVERIFY(mocked); + QCOMPARE(mocked->something(), QLatin1String("mocked")); + QVERIFY(mock == mocked); + QVERIFY(orig != mocked); + + Env::setShared(TestSharedInstance::staticMetaObject); + auto orig3 = Env::getShared(); + QVERIFY(orig != orig3); + QCOMPARE(orig3->something(), QLatin1String("orig")); + } + + + void getUnmanagedSingleton() + { + auto first = Env::getSingleton(); + QVERIFY(first); + QCOMPARE(first->something(), QLatin1String("TestUnmanagedInstance")); + + auto second = Env::getSingleton(); + QVERIFY(second); + QVERIFY(first == second); + } + + + void getMockSingleton() + { + MockedAbstractTestInstance m; + Env::set(AbstractTestInstance::staticMetaObject, &m); + MockedAbstractTestInstance* mocked = Env::getSingleton(); + QVERIFY(mocked); + QCOMPARE(mocked->dummy(), QLatin1String("mocked")); + + Env::set(AbstractTestInstance::staticMetaObject); + mocked = Env::getSingleton(); + QVERIFY(!mocked); + + + Env::set(AbstractTestInstance::staticMetaObject, &m); + Env::set(AbstractTestInstance::staticMetaObject, std::make_shared()); + MockedAbstractTestInstance* mocked2 = Env::getSingleton(); + QVERIFY(mocked2); + QCOMPARE(mocked2->dummy(), QLatin1String("mocked")); + + Env::set(AbstractTestInstance::staticMetaObject); + AbstractTestInstance* orig = Env::getSingleton(); + QVERIFY(orig); + QCOMPARE(orig->dummy(), QLatin1String("impl")); + QVERIFY((!Env::getSingleton())); + + Env::set(AbstractTestInstance::staticMetaObject, std::make_shared()); + AbstractTestInstance* mocked3 = Env::getSingleton(); + QVERIFY(mocked3); + QCOMPARE(mocked3->dummy(), QLatin1String("mocked")); + + Env::set(AbstractTestInstance::staticMetaObject, std::shared_ptr()); + mocked3 = Env::getSingleton(); + QVERIFY(mocked3); + QCOMPARE(mocked3->dummy(), QLatin1String("impl")); + } + + + void mockCreateNewInstance() + { + QScopedPointer implOrig(Env::create()); + QVERIFY(implOrig); + QCOMPARE(implOrig->dummy(), QLatin1String("impl")); + implOrig.reset(); + + std::function func = [](){ + class tmp + : public AbstractTestInstanceImpl + { + virtual QString dummy() override + { + return QStringLiteral("lambda"); + } + + + }; + + return new tmp; + }; + + Env::setCreator(func); + + QScopedPointer impl(Env::create()); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("lambda")); + + QScopedPointer impl2(Env::create()); + QVERIFY(impl2); + QCOMPARE(impl2->dummy(), QLatin1String("lambda")); + QVERIFY(impl != impl2); + } + + + void mockArgs() + { + QScopedPointer impl(Env::create(QString("flupp"))); + QVERIFY(impl); + QCOMPARE(impl->dummy(), QLatin1String("flupp")); + impl.reset(); + + std::function funcString = [](const QString& pStr){ + class tmp + : public AbstractTestPodInstance + { + const QString mDummy; + + public: + tmp(const QString& pDummy) + : mDummy(QStringLiteral("YEAH: ") + pDummy) + { + } + + + virtual QString dummy() override + { + return mDummy; + } + + + }; + + return new tmp(pStr); + }; + + std::function funcDefault = [](){ + class tmp + : public AbstractTestPodInstance + { + public: + virtual QString dummy() override + { + return QStringLiteral("default"); + } + + + }; + + return new tmp(); + }; + + Env::setCreator(funcString); + Env::setCreator(funcDefault); + + QScopedPointer catcher(Env::create(QString("bla"))); + QVERIFY(catcher); + QCOMPARE(catcher->dummy(), QLatin1String("YEAH: bla")); + + catcher.reset(Env::create()); + QVERIFY(catcher); + QCOMPARE(catcher->dummy(), QLatin1String("default")); + } + + + void mockCopy() + { + class TestCopyCtor + { + private: + int mData; + + public: + TestCopyCtor(int pData) + : mData(pData) + { + } + + + int data() + { + return mData; + } + + + }; + + auto obj = Env::create(666); + QCOMPARE(obj.data(), 666); + obj = Env::create(1904); + QCOMPARE(obj.data(), 1904); + + std::function func = [](int){ + return TestCopyCtor(1); + }; + Env::setCreator(func); + + obj = Env::create(1982); + QCOMPARE(obj.data(), 1); + } + + + void mockMove() + { + auto obj = Env::create(QString("huhu")); + QCOMPARE(obj.data(), QLatin1String("huhu")); + + std::function func = [](const QString&){ + return TestMoveCtorAssign(QStringLiteral("mocked")); + }; + Env::setCreator(func); + + auto mock = Env::create(QString("huhu")); + QCOMPARE(mock.data(), QLatin1String("mocked")); + QCOMPARE(obj.data(), QLatin1String("huhu")); + + func = [](const QString&){ + return TestMoveCtorAssign(QStringLiteral("mocked2")); + }; + Env::setCreator(func); + mock = Env::create(QString("huhu2")); + QCOMPARE(mock.data(), QLatin1String("mocked2")); + QCOMPARE(obj.data(), QLatin1String("huhu")); + } + + + void mockCounter() + { + struct TestTmp + { + int mData; + TestTmp(int pData = 666) + : mData(pData) + { + } + + + }; + + auto obj = Env::create(); + QCOMPARE(obj.mData, 666); + + obj = Env::create(1904); + QCOMPARE(obj.mData, 1904); + + const std::function func = [](){ + return TestTmp(999); + }; + QCOMPARE(Env::getCounter(), -1); + Env::setCreator(func); + QCOMPARE(Env::getCounter(), 0); + + obj = Env::create(); + QCOMPARE(obj.mData, 999); + QCOMPARE(Env::getCounter(), 1); + + obj = Env::create(123); + QCOMPARE(obj.mData, 123); + QCOMPARE(Env::getCounter(), 1); + + const std::function func2 = [](int){ + return TestTmp(777); + }; + QCOMPARE((Env::getCounter()), -1); + + Env::setCreator(func2); + QCOMPARE(Env::getCounter(), 1); + QCOMPARE((Env::getCounter()), 0); + + obj = Env::create(); + QCOMPARE(obj.mData, 999); + QCOMPARE(Env::getCounter(), 2); + QCOMPARE((Env::getCounter()), 0); + + obj = Env::create(123); + QCOMPARE(obj.mData, 777); + QCOMPARE(Env::getCounter(), 2); + QCOMPARE((Env::getCounter()), 1); + + Env::resetCounter(); + QCOMPARE(Env::getCounter(), 0); + QCOMPARE((Env::getCounter()), 0); + + Env::clear(); + QCOMPARE(Env::getCounter(), -1); + QCOMPARE((Env::getCounter()), -1); + } + + +}; + +QTEST_GUILESS_MAIN(test_Env) +#include "test_Env.moc" diff --git a/test/qt/global/test_EnvHolder.cpp b/test/qt/global/test_EnvHolder.cpp deleted file mode 100644 index ddcbfad..0000000 --- a/test/qt/global/test_EnvHolder.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/*! - * \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_FileDestination.cpp b/test/qt/global/test_FileDestination.cpp index bf0eaa1..09ad034 100644 --- a/test/qt/global/test_FileDestination.cpp +++ b/test/qt/global/test_FileDestination.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref FileDestination * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "FileDestination.h" diff --git a/test/qt/global/test_FuncUtils.cpp b/test/qt/global/test_FuncUtils.cpp new file mode 100644 index 0000000..b98a10f --- /dev/null +++ b/test/qt/global/test_FuncUtils.cpp @@ -0,0 +1,110 @@ +/*! + * \brief Unit tests for \ref FuncUtils + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "FuncUtils.h" + +#include + +using namespace governikus; + +class Reader +{ + private: + QString mName; + bool mConnected; + + public: + Reader(); + Reader(const QString& pName, bool pConnected); + ~Reader() = default; + + const QString& getName() const; + bool isConnected() const; +}; + + +Reader::Reader() + : mName() + , mConnected(false) +{ +} + + +Reader::Reader(const QString& pName, bool pConnected) + : mName(pName) + , mConnected(pConnected) +{ +} + + +const QString& Reader::getName() const +{ + return mName; +} + + +bool Reader::isConnected() const +{ + return mConnected; +} + + +class test_FuncUtils + : public QObject +{ + Q_OBJECT + + private: + QVector mReaders; + + private Q_SLOTS: + void initTestCase() + { + mReaders = QVector({Reader(QStringLiteral("NFC Reader"), true), + Reader(QStringLiteral("Bluetooth Reader"), false), + Reader(QStringLiteral("PCSC Reader"), true)}); + } + + + void testMapWithNonVoid() + { + const QVector readerNamesVector = map([](const Reader& r){ + return r.getName(); + }, mReaders); + + QCOMPARE(readerNamesVector.size(), 3); + QCOMPARE(readerNamesVector.at(0), QStringLiteral("NFC Reader")); + QCOMPARE(readerNamesVector.at(1), QStringLiteral("Bluetooth Reader")); + QCOMPARE(readerNamesVector.at(2), QStringLiteral("PCSC Reader")); + + const QList readerNamesList = map([](const Reader& r){ + return r.getName(); + }, mReaders.toList()); + + QCOMPARE(readerNamesList.size(), 3); + QCOMPARE(readerNamesList.at(0), QStringLiteral("NFC Reader")); + QCOMPARE(readerNamesList.at(1), QStringLiteral("Bluetooth Reader")); + QCOMPARE(readerNamesList.at(2), QStringLiteral("PCSC Reader")); + } + + + void testFilter() + { + const QVector connectedReaders = filter([](const Reader& r){ + return r.isConnected(); + }, mReaders); + + QCOMPARE(connectedReaders.size(), 2); + QCOMPARE(connectedReaders.at(0).getName(), QStringLiteral("NFC Reader")); + QCOMPARE(connectedReaders.at(1).getName(), QStringLiteral("PCSC Reader")); + } + + +}; + + +QTEST_GUILESS_MAIN(test_FuncUtils) +#include "test_FuncUtils.moc" diff --git a/test/qt/global/test_Initializer.cpp b/test/qt/global/test_Initializer.cpp new file mode 100644 index 0000000..b0b6eb8 --- /dev/null +++ b/test/qt/global/test_Initializer.cpp @@ -0,0 +1,69 @@ +/*! + * \brief Unit tests for \ref Initializer + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Initializer.h" + +#include + +using namespace governikus; + +class test_Initializer + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void init() + { + Initializer::getInstance().mRegisteredFunctions.clear(); + } + + + void simpleInit() + { + auto& instance = Initializer::getInstance(); + QCOMPARE(instance.mRegisteredFunctions.size(), size_t(0)); + + bool flipMe = false; + instance.add([&flipMe] { + flipMe = true; + }); + + QCOMPARE(instance.mRegisteredFunctions.size(), size_t(1)); + QVERIFY(flipMe); + } + + + void entryInit() + { + auto& instance = Initializer::getInstance(); + QCOMPARE(instance.mRegisteredFunctions.size(), size_t(0)); + + bool flipMeX = false; + bool flipMeY = false; + Initializer::Entry X([&flipMeX] { + flipMeX = true; + }); + Q_UNUSED(X) + + QCOMPARE(instance.mRegisteredFunctions.size(), size_t(1)); + QVERIFY(flipMeX); + + static Initializer::Entry Y([&flipMeY] { + flipMeY = true; + }); + Q_UNUSED(Y) + + QCOMPARE(instance.mRegisteredFunctions.size(), size_t(2)); + QVERIFY(flipMeX); + QVERIFY(flipMeY); + } + + +}; + +QTEST_GUILESS_MAIN(test_Initializer) +#include "test_Initializer.moc" diff --git a/test/qt/global/test_LanguageLoader.cpp b/test/qt/global/test_LanguageLoader.cpp index d5f0502..c771d3d 100644 --- a/test/qt/global/test_LanguageLoader.cpp +++ b/test/qt/global/test_LanguageLoader.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref LanguageLoader * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "LanguageLoader.h" diff --git a/test/qt/global/test_LogHandler.cpp b/test/qt/global/test_LogHandler.cpp index 97a272b..59bc7e7 100644 --- a/test/qt/global/test_LogHandler.cpp +++ b/test/qt/global/test_LogHandler.cpp @@ -1,9 +1,7 @@ /*! - * test_LogHandler.h - * * \brief Unit tests for \ref LogHandler * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "LogHandler.h" @@ -68,8 +66,15 @@ class test_LogHandler QCOMPARE(spy.count(), 2); auto param1 = spy.takeFirst(); auto param2 = spy.takeLast(); - QVERIFY(param1.at(0).toString().endsWith("hallo\n")); - QVERIFY(param2.at(0).toString().endsWith("test nachricht\n")); + +#ifdef Q_OS_WIN + const QLatin1String lineBreak("\r\n"); +#else + const QLatin1Char lineBreak('\n'); +#endif + + QVERIFY(param1.at(0).toString().endsWith(QStringLiteral("hallo") + lineBreak)); + QVERIFY(param2.at(0).toString().endsWith(QStringLiteral("test nachricht") + lineBreak)); } diff --git a/test/qt/global/test_Randomizer.cpp b/test/qt/global/test_Randomizer.cpp index 5ae6c2c..5572983 100644 --- a/test/qt/global/test_Randomizer.cpp +++ b/test/qt/global/test_Randomizer.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref Randomizer * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "Randomizer.h" diff --git a/test/qt/global/test_ResourceLoader.cpp b/test/qt/global/test_ResourceLoader.cpp index 5cd8859..b60b327 100644 --- a/test/qt/global/test_ResourceLoader.cpp +++ b/test/qt/global/test_ResourceLoader.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref ResourceLoader * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ResourceLoader.h" diff --git a/test/qt/global/test_ScopeGuard.cpp b/test/qt/global/test_ScopeGuard.cpp new file mode 100644 index 0000000..15aca63 --- /dev/null +++ b/test/qt/global/test_ScopeGuard.cpp @@ -0,0 +1,132 @@ +/*! + * \brief Unit tests for \ref ScopeGuard + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ScopeGuard.h" + +#include "LogHandler.h" + +#include + +using namespace governikus; + +class test_ScopeGuard + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void simple() + { + bool flipMe = false; + { + const ScopeGuard obj([&flipMe] { + flipMe = true; + }); + + QVERIFY(obj.mFunction); + QVERIFY(obj.isEnabled()); + QVERIFY(!flipMe); + } + QVERIFY(flipMe); + } + + + void disabled() + { + bool flipMe = false; + { + const ScopeGuard obj([&flipMe] { + flipMe = true; + }, false); + + QVERIFY(obj.mFunction); + QVERIFY(!obj.isEnabled()); + QVERIFY(!flipMe); + } + QVERIFY(!flipMe); + } + + + void disabledAfterCtor() + { + bool flipMe = false; + { + ScopeGuard obj([&flipMe] { + flipMe = true; + }); + + QVERIFY(obj.mFunction); + QVERIFY(obj.isEnabled()); + obj.setEnabled(false); + QVERIFY(!obj.isEnabled()); + QVERIFY(!flipMe); + } + QVERIFY(!flipMe); + } + + + void enabledAfterCtor() + { + bool flipMe = false; + { + ScopeGuard obj([&flipMe] { + flipMe = true; + }, false); + QVERIFY(!obj.isEnabled()); + QVERIFY(obj.mFunction); + + obj.setEnabled(true); + QVERIFY(obj.isEnabled()); + QVERIFY(!flipMe); + } + QVERIFY(flipMe); + } + + + void emptyFunc() + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + + const std::function func; + + { + ScopeGuard obj(func); + QVERIFY(obj.isEnabled()); + QVERIFY(!obj.mFunction); + + obj.setEnabled(true); + QVERIFY(obj.isEnabled()); + } + + QCOMPARE(spy.count(), 1); + auto param = spy.takeFirst(); + +#ifdef Q_OS_WIN + const QLatin1String lineBreak("\r\n"); +#else + const QLatin1Char lineBreak('\n'); +#endif + + QVERIFY(param.at(0).toString().endsWith(QStringLiteral("Cannot call an empty function") + lineBreak)); + } + + +}; + +QTEST_GUILESS_MAIN(test_ScopeGuard) +#include "test_ScopeGuard.moc" diff --git a/test/qt/global/test_VersionInfo.cpp b/test/qt/global/test_VersionInfo.cpp index 5d2d198..fd652f2 100644 --- a/test/qt/global/test_VersionInfo.cpp +++ b/test/qt/global/test_VersionInfo.cpp @@ -1,7 +1,5 @@ /*! - * test_VersionInfo.cpp - * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -50,7 +48,7 @@ class test_VersionInfo QCOMPARE(parseError->error, QJsonParseError::ParseError::NoError); QCOMPARE(obj["Name"].toString(), QLatin1String("Test_global_VersionInfo")); QCOMPARE(obj["Specification-Title"].toString(), QLatin1String("TR-03124")); - QCOMPARE(obj["Specification-Version"].toString(), QLatin1String("1.2")); + QCOMPARE(obj["Specification-Version"].toString(), QLatin1String("1.3")); QCOMPARE(obj["Specification-Vendor"].toString(), QLatin1String("Federal Office for Information Security")); QCOMPARE(obj["Implementation-Title"].toString(), QLatin1String("Test_global_VersionInfo")); QCOMPARE(obj["Implementation-Version"].toString(), QLatin1String("x.y.z")); @@ -102,7 +100,7 @@ class test_VersionInfo QVERIFY(text.contains(QLatin1String("Name: Test_global_VersionInfo"))); QVERIFY(text.contains(QLatin1String("Specification-Title: TR-03124"))); - QVERIFY(text.contains(QLatin1String("Specification-Version: 1.2"))); + QVERIFY(text.contains(QLatin1String("Specification-Version: 1.3"))); QVERIFY(text.contains(QLatin1String("Specification-Vendor: Federal Office for Information Security"))); QVERIFY(text.contains(QLatin1String("Implementation-Title: Test_global_VersionInfo"))); QVERIFY(text.contains(QLatin1String("Implementation-Version: x.y.z"))); diff --git a/test/qt/global/test_VersionNumber.cpp b/test/qt/global/test_VersionNumber.cpp index af7f489..c3d2dae 100644 --- a/test/qt/global/test_VersionNumber.cpp +++ b/test/qt/global/test_VersionNumber.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref VersionNumber. * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "VersionNumber.h" diff --git a/test/qt/global/test_result.cpp b/test/qt/global/test_result.cpp index 5389a85..a9ae426 100644 --- a/test/qt/global/test_result.cpp +++ b/test/qt/global/test_result.cpp @@ -1,11 +1,10 @@ /*! - * test_result.h - * * \brief Unit tests for \ref result * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ +#include "CardReturnCode.h" #include "LogHandler.h" #include "Result.h" @@ -52,6 +51,9 @@ class test_result 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")); + + QCOMPARE(Result::parseMinor(QString()), GlobalStatus::Code::No_Error); + QVERIFY(Result::isMinor(QString())); } @@ -69,7 +71,7 @@ class test_result { Result result = Result::createOk(); QCOMPARE(result.getMajor(), Result::Major::Ok); - QCOMPARE(result.getMinor(), GlobalStatus::Code::Unknown_Error); + QCOMPARE(result.getMinor(), GlobalStatus::Code::No_Error); QCOMPARE(result.getMessage(), QString()); QCOMPARE(result.getMessageLang(), QString("en")); } @@ -121,7 +123,7 @@ class test_result expected = "{\"major\":\"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\"}"; QCOMPARE(bytes(Result::createOk().toJson()), expected); - expected = "{\"description\":\"The operation was aborted due to cancellation by user.\"," + expected = "{\"description\":\"The process was cancelled by the user.\"," "\"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\"}"; diff --git a/test/qt/gui/test_HelpAction.cpp b/test/qt/gui/test_HelpAction.cpp deleted file mode 100644 index 024250f..0000000 --- a/test/qt/gui/test_HelpAction.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/*! - * \brief Unit tests for \ref HelpAction - * - * \copyright Copyright (c) 2015 Governikus GmbH & Co. KG - */ - -#include "TestFileHelper.h" - -#include - -#include "generic/HelpAction.h" -#include "LanguageLoader.h" - -using namespace governikus; - -class test_HelpAction - : public QObject -{ - Q_OBJECT - - QDir helpDir = QCoreApplication::applicationDirPath() + QStringLiteral("/help/"); - QTemporaryDir mTranslationDir; - - void loadLanguage(QLocale::Language pLang) - { - if (LanguageLoader::getInstance().isLoaded()) - { - LanguageLoader::getInstance().unload(); - } - - LanguageLoader::getInstance().load(pLang); - QCOMPARE(LanguageLoader::getInstance().getUsedLocale().language(), pLang); - } - - - QString toWebUrl(const QString& pLang = QStringLiteral("en")) - { - #ifdef Q_OS_OSX - const QString sys = "macOS"; - #else - const QString sys = "Windows"; - #endif - - return QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/handbuch/1.9/%1/%2/index.html").arg(pLang, sys); - } - - - QString toUrl(const char* pStr) - { - return QUrl::fromLocalFile(helpDir.path()).toString() + QString::fromLatin1(pStr); - } - - - private Q_SLOTS: - void init() - { - QCoreApplication::setApplicationVersion(QStringLiteral("1.9")); - QVERIFY(!helpDir.exists()); - } - - - void initTestCase() - { - TestFileHelper::createTranslations(mTranslationDir.path()); - LanguageLoader::getInstance().setPath(mTranslationDir.path()); - } - - - void cleanup() - { - QVERIFY(helpDir.removeRecursively()); - if (LanguageLoader::getInstance().isLoaded()) - { - LanguageLoader::getInstance().unload(); - } - } - - - void escapedMapping() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QVERIFY(helpDir.mkdir("de")); - loadLanguage(QLocale::German); - - QString padding; - if (QSysInfo::prettyProductName().startsWith(QLatin1String("Windows"))) - { - padding = '/'; - } - - QCOMPARE(HelpAction::getInstance().getHelpUrl("generalTab"), "file://" + padding + helpDir.path() + "/de/settings-general.html"); - } - - - void nonExistingHelpDir() - { - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::English); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); - } - - - void existingHelpDir() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::English); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); - } - - - void existingLanguageHelpDir() - { - QVERIFY(helpDir.mkpath(helpDir.path())); - - QVERIFY(helpDir.mkdir("en")); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - QVERIFY(helpDir.mkdir("de")); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - loadLanguage(QLocale::German); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/de/index.html")); - - loadLanguage(QLocale::Italian); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - - LanguageLoader::getInstance().unload(); - QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); - } - - - void contextMap() - { - QCOMPARE(HelpAction::getInstance().getContextMapping(""), QString("index.html")); - - QCOMPARE(HelpAction::getInstance().getContextMapping("pinTab"), QString("settings-pin-management.html")); - QCOMPARE(HelpAction::getInstance().getContextMapping("unknown"), QString("index.html")); - } - - -}; - -QTEST_MAIN(test_HelpAction) -#include "test_HelpAction.moc" diff --git a/test/qt/jsonapi/test_Message.cpp b/test/qt/jsonapi/test_Message.cpp index 8899c6e..4b0ec3e 100644 --- a/test/qt/jsonapi/test_Message.cpp +++ b/test/qt/jsonapi/test_Message.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MessageDispatcher * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "MessageDispatcher.h" @@ -207,7 +207,7 @@ class test_Message void finishAuthContext() { - const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); + const QSharedPointer context(new AuthContext(QSharedPointer::create(QUrl("http://dummy")))); context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://dummy")); MessageDispatcher dispatcher; diff --git a/test/qt/jsonapi/test_MsgContext.cpp b/test/qt/jsonapi/test_MsgContext.cpp index 3f1dc4b..9b19098 100644 --- a/test/qt/jsonapi/test_MsgContext.cpp +++ b/test/qt/jsonapi/test_MsgContext.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgContext * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgContext.h" @@ -68,7 +68,7 @@ class test_MsgContext QVERIFY(!ctx.getAuthContext()); QVERIFY(!readOnly.getWorkflowContext()); - ctx.setWorkflowContext(QSharedPointer(new AuthContext(new InternalActivationContext(QUrl("http://www.bla.de"))))); + ctx.setWorkflowContext(QSharedPointer(new AuthContext(QSharedPointer::create(QUrl("http://www.bla.de"))))); QVERIFY(readOnly.isActiveWorkflow()); QVERIFY(readOnly.getAuthContext()); QVERIFY(ctx.getAuthContext()); diff --git a/test/qt/jsonapi/test_MsgHandler.cpp b/test/qt/jsonapi/test_MsgHandler.cpp index 221e356..8c0f3ba 100644 --- a/test/qt/jsonapi/test_MsgHandler.cpp +++ b/test/qt/jsonapi/test_MsgHandler.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandler * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandler.h" diff --git a/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp b/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp index c951253..b130855 100644 --- a/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp +++ b/test/qt/jsonapi/test_MsgHandlerAccessRights.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerAccessRights * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerAccessRights.h" @@ -36,7 +36,22 @@ class test_MsgHandlerAccessRights } -#define AUX R"({"aux":{"ageVerificationDate":"1992-12-06","communityId":"02760400110000","requiredAge":"24","validityDate":"2013-12-06"},)" + QByteArray getAux() const + { + const QDate today = QDateTime::currentDateTimeUtc().date(); + const QDate ageVerificationDate = QDate(1992, 12, 6); + + const QByteArray age = + (today.month() > ageVerificationDate.month() || (today.month() == ageVerificationDate.month() && today.day() >= ageVerificationDate.day())) + ? QByteArray::number(today.year() - ageVerificationDate.year()) + : QByteArray::number(today.year() - ageVerificationDate.year() - 1); + + QByteArray aux(R"({"aux":{"ageVerificationDate":"%1","communityId":"02760400110000","requiredAge":"%2","validityDate":"2013-12-06"},)"); + aux.replace(QByteArrayLiteral("%1"), ageVerificationDate.toString(Qt::ISODate).toLatin1()); + aux.replace(QByteArrayLiteral("%2"), age); + return aux; + } + private Q_SLOTS: void nonExistingTransactionInfo() @@ -56,7 +71,7 @@ class test_MsgHandlerAccessRights dispatcher.init(getContextWithChat()); QCOMPARE(dispatcher.processStateChange("StateEditAccessRights"), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -83,7 +98,7 @@ class test_MsgHandlerAccessRights QVERIFY(!context->isStateApproved()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "ACCEPT"} )")), QByteArray()); QVERIFY(context->isStateApproved()); @@ -97,7 +112,7 @@ class test_MsgHandlerAccessRights QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -107,28 +122,28 @@ class test_MsgHandlerAccessRights QTest::addColumn("msg"); QTest::newRow("chat_invalid") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["8",11]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data needs to be string","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data needs to be string","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_needs_be_string") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": [8,"11"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_unknown_id") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["y", "123"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is invalid","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_set_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_mixed_valid_and_required") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "GivenNames"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_both_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "FamilyName"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_single_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )") - << QByteArray(AUX R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("chat_disable_optional") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": []} )") - << QByteArray(AUX R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); } @@ -143,7 +158,7 @@ class test_MsgHandlerAccessRights // check original state QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // check cmd QCOMPARE(dispatcher.processCommand(cmd), msg); @@ -158,15 +173,15 @@ class test_MsgHandlerAccessRights // check original state QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "GET_ACCESS_RIGHTS"} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // check cmds QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["FamilyName"]} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); // 11 is not valid, 0 is valid ... we do not accept partial valid values! QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification", "GivenNames"]} )")), - QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Entry in 'chat' data is not available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -180,16 +195,16 @@ class test_MsgHandlerAccessRights QVERIFY(!dispatcher.processStateChange("StateEditAccessRights").isEmpty()); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - QByteArray(AUX R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":[],"required":["Address","GivenNames","DocumentType"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType"],"optional":[],"required":["Address","GivenNames","DocumentType"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); context->setOptionalAccessRights({AccessRight::AGE_VERIFICATION}); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - QByteArray(AUX R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","GivenNames","DocumentType","AgeVerification"],"optional":["AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); context->setRequiredAccessRights({AccessRight::AGE_VERIFICATION, AccessRight::READ_DG17}); context->setOptionalAccessRights({}); QCOMPARE(dispatcher.processCommand(QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": ["AgeVerification"]} )")), - QByteArray(AUX R"("chat":{"effective":["Address","AgeVerification"],"optional":[],"required":["Address","AgeVerification"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); + getAux() + QByteArray(R"("chat":{"effective":["Address","AgeVerification"],"optional":[],"required":["Address","AgeVerification"]},"error":"No optional access rights available","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})")); } @@ -199,10 +214,10 @@ class test_MsgHandlerAccessRights QTest::addColumn("msg"); QTest::newRow("chat_null") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "chat": null} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Invalid 'chat' data","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"Invalid 'chat' data","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); QTest::newRow("CHAT") << QByteArray(R"( {"cmd": "SET_ACCESS_RIGHTS", "CHAT": []} )") - << QByteArray(AUX R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"'chat' cannot be undefined","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); + << getAux() + QByteArray(R"("chat":{"effective":["Address","FamilyName","GivenNames","DocumentType","AgeVerification"],"optional":["FamilyName","AgeVerification"],"required":["Address","GivenNames","DocumentType"]},"error":"'chat' cannot be undefined","msg":"ACCESS_RIGHTS","transactionInfo":"this is a test for TransactionInfo"})"); } diff --git a/test/qt/jsonapi/test_MsgHandlerApiLevel.cpp b/test/qt/jsonapi/test_MsgHandlerApiLevel.cpp index 27a31c4..e40a188 100644 --- a/test/qt/jsonapi/test_MsgHandlerApiLevel.cpp +++ b/test/qt/jsonapi/test_MsgHandlerApiLevel.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerApiLevel * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerApiLevel.h" diff --git a/test/qt/jsonapi/test_MsgHandlerAuth.cpp b/test/qt/jsonapi/test_MsgHandlerAuth.cpp index b172ab8..55d165e 100644 --- a/test/qt/jsonapi/test_MsgHandlerAuth.cpp +++ b/test/qt/jsonapi/test_MsgHandlerAuth.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerAuth * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerAuth.h" @@ -81,7 +81,7 @@ class test_MsgHandlerAuth QCOMPARE(spy.count(), 1); auto param = spy.takeFirst(); - ActivationContext* context = param.at(0).value(); + auto context = param.at(0).value >(); QVERIFY(context); QCOMPARE(context->getActivationURL(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Fwww.governikus.de%2Ftoken%3Fsession%3D123abc")); } @@ -94,7 +94,7 @@ class test_MsgHandlerAuth QCOMPARE(dispatcher.init(context), QByteArray()); QCOMPARE(dispatcher.finish(), QByteArray()); - const QSharedPointer authContext(new AuthContext(new InternalActivationContext(QUrl("http://dummy")))); + const QSharedPointer authContext(new AuthContext(QSharedPointer::create(QUrl("http://dummy")))); QCOMPARE(dispatcher.init(authContext), QByteArray("{\"msg\":\"AUTH\"}")); } @@ -111,7 +111,7 @@ class test_MsgHandlerAuth QCOMPARE(spy.count(), 1); auto param = spy.takeFirst(); - ActivationContext* context = param.at(0).value(); + auto context = param.at(0).value >(); QVERIFY(context); QCOMPARE(context->getActivationURL(), QUrl("http://localhost/?tcTokenURL=https%3A%2F%2Ftest.governikus-eid.de%2Fgov_autent%2Fasync%3FSAMLRequest%3DnVbZsppIGH4Vi7m0lEURsI4nBbIcV1TA7SbF0myy0wj49NMeTXIySWYyueTvf%252FuWrublUxNHnSsoyiBNJhjZJ7AOSOzUCRJvghm63GOxT68vpRlHVDbmK%252BgnO5BXoIQdVJiU48fJBKuKZJyaZVCOEzMG5RjaY41fLcdUnxhnRQpTO42wDl%252BWoIBo1DRNyioGhQaKa2ADY7ecYD6EWTnG8bqu3X50jfsOwJPMvA%252FFgZ3Gn9HHPYAXoMxQPcA6IlokSMx7x2%252F1EAX7XopAJcGlKnsgcO6tUOSzWUGQQNws28TGOjNxgjG2NaBphu3RnEX1hiQDepwzGvVIa8S6nM3ZBHBRZllWYJaU0EzgBKMIctQj2B7J6iQ1HpBjiukTLHPGOpsivQYOKNaIg58Cwjr7L1wjZrAns%252BP3%252FsVHSv%252BdUfMLj9jrT1h7wd9VeXb9qp7UIPB3ncvXF8TJWErsos0gcD7K%252BjXpuQxKfABBwlhl0Leq5J1NMBNxtH6DzPKtkWhC81l3P%252FhaiBTt14N%252BWng4RRAkTgxx5B6U8RfW0dvsSdVD%252Bl8kShGIkXT%252FGInArAD0U6fDR15aBNCPf2OoCUqSYnu2hTzwcPHvbou%252FvjjleAHaWeKmz1qn%252FMVIAie4O06nDLy%252FfuAKNfmfw79n%252B8%252BgF6XZIz%252FTGALyLt00yHxQ3HX7LrA3owq8nqchd%252FChs84FcV%252F7K2XeNSNam7c1zXHmaE01PIgXcC8dVEkwOF9cgKS6Gjw7z%252Fcm301Gy4G2U3ldYZNjokPNXknswARRE1X1eWSDZvgGGUNwzhS6g1yrGsui1cBFSMJwF8Do1rihPLyZPH%252B7haovT4eaFrDbAcB3ah6G24xiVGFr5%252BUlOxlvuORmrFaQuzIHyvE257rT0Qpe9xqlVeAYWIGhioZiWWcoRnVIadR5YbORNmUAawRruznL%252FsUN8GCjjEA7mpmLnAqrZRU5i22Sd91An2blxp2R7IY6VLcisRwhJslgyKjEleEbMO9yF4m4bQapCs8jnWblM6WpFru02fDCevopWnteylL1ZPKCf%252BD%252BQfV3oYccj6SvlxT5BcW%252Bue8HAf%252FMTQ8DPJYQZXuh7SMTD8zuydusrZJf86WxyozjgobSkWfDkMn5S3d7mFJTXKWEkXuKdWKGFnXOQrbYJwodtcXONjyt686N5T4ZCOtpO4PeJiLo0PDieXdIzt11lzLndd4KjLqkY3kqH287U2svdeN6852480LvYm4vTEUXbN0FOKMUtroeXtdRGHOncHqMtZTJcvEircycDWNFy89VumWnqsTBvT7jo60ypUYbLTkt97nbGOvGJm1wahNDk5q3Q93qNVgufWV6s66GlTnbzDVxejiq7ThcNUqs3FyfVmVCYbeOElnXzU0JL7wtIefm1Wwv4%252FQZF%252Bp0mCa6tiVO8qI2Z7kx8KKteIipPN7dToNqFzCU7s9xRStX25wkV3SVpjK1sXTeL%252FRmPuAovBL5dsaTDCFJSnwaDfNhxXXdZq%252BLZ1fGU8GxBHxJweVVONRvvnySDkyOV0P1EOf8fHAEx5vPnzPLSvnB4dJGAhzGbJAJFJnvDFGo9gBuzduaetsf4PHmOJc6APybfPkzDz6N%252Bd%252BPB3Lq85fh46PzJfbxvXn9Gw%253D%253D%26RelayState%3Dfc4b5fad-76fd-49d2-841b-b5cd39568029%26SigAlg%3Dhttp%253A%252F%252Fwww.w3.org%252F2001%252F04%252Fxmldsig-more%2523rsa-sha256%26Signature%3DjEVAVmY1XMMuNt2GJ%252BoaN6FaGj6ACZokOfme1OmkBiCPJyr%252B4rsg%252BrajIyMtSoUbtOoOaH63g1JP%250AqT7Wc%252Bucd%252FLcEYf7qU%252FJKN2uTMvssQblsSKuPHOWLJQUKPZHiSPA67%252F9JZhov8FXYM9uBYSs1Far%250AMRBpM49o1m1pRzwOKx3%252FcwOqc%252BT5mOWM78tNOj37mFFzwDTGuoB9iE2cZCUu1wfBbTPIvRZ2ND8Y%250AVYEO5FdR8W0sLR9LNOVjm64D%252Fl9u%252FjFJXntW4CPRPXiOiCr7TLlnFWVxXOTwywF5LTyLYQR5OjwB%250AK3cWmRPkN6OAejN%252F3Su3nWHDlGttrZuZBYzfag%253D%253D")); } @@ -131,7 +131,7 @@ class test_MsgHandlerAuth void result() { - const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); + const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); 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\"}}")); @@ -140,7 +140,7 @@ class test_MsgHandlerAuth void resultWithUrl() { - const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); + const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); context->setStatus(GlobalStatus::Code::No_Error); context->setRefreshUrl(QUrl("http://www.governikus.de")); MsgHandlerAuth msg(context); @@ -161,7 +161,7 @@ class test_MsgHandlerAuth " \n" ""))); - const QSharedPointer context(new AuthContext(new InternalActivationContext(QUrl()))); + const QSharedPointer context(new AuthContext(QSharedPointer(new InternalActivationContext(QUrl())))); context->setStatus(GlobalStatus::Code::Workflow_Reader_Became_Inaccessible); context->setTcToken(token); MsgHandlerAuth msg(context); diff --git a/test/qt/jsonapi/test_MsgHandlerCertificate.cpp b/test/qt/jsonapi/test_MsgHandlerCertificate.cpp index a1acf75..7d12dd1 100644 --- a/test/qt/jsonapi/test_MsgHandlerCertificate.cpp +++ b/test/qt/jsonapi/test_MsgHandlerCertificate.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerCertificate * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerCertificate.h" diff --git a/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp b/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp index f8e3d9f..cd87429 100644 --- a/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp +++ b/test/qt/jsonapi/test_MsgHandlerEnterCan.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerEnterCan * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerEnterCan.h" diff --git a/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp b/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp index c8db6f5..c8e10ef 100644 --- a/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp +++ b/test/qt/jsonapi/test_MsgHandlerEnterPin.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerEnterPin * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerEnterPin.h" diff --git a/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp b/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp index b6dd2b5..22cb98e 100644 --- a/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp +++ b/test/qt/jsonapi/test_MsgHandlerEnterPuk.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerEnterPuk * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerEnterPuk.h" diff --git a/test/qt/jsonapi/test_MsgHandlerInsertCard.cpp b/test/qt/jsonapi/test_MsgHandlerInsertCard.cpp index d70a71f..0d31a68 100644 --- a/test/qt/jsonapi/test_MsgHandlerInsertCard.cpp +++ b/test/qt/jsonapi/test_MsgHandlerInsertCard.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerInsertCard * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerInsertCard.h" @@ -62,8 +62,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectPcscReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectNfcReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); + QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); } @@ -76,8 +75,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectPcscReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectNfcReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); + QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectReader")), QByteArray("{\"msg\":\"INSERT_CARD\"}")); } @@ -90,8 +88,7 @@ class test_MsgHandlerInsertCard MessageDispatcher dispatcher; setContext(dispatcher); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectPcscReader")), QByteArray()); - QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectNfcReader")), QByteArray()); + QCOMPARE(dispatcher.processStateChange(QStringLiteral("StateSelectReader")), QByteArray()); } diff --git a/test/qt/jsonapi/test_MsgHandlerInternalError.cpp b/test/qt/jsonapi/test_MsgHandlerInternalError.cpp index 47aa4e2..3a5cf2a 100644 --- a/test/qt/jsonapi/test_MsgHandlerInternalError.cpp +++ b/test/qt/jsonapi/test_MsgHandlerInternalError.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerInternalError * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerInternalError.h" diff --git a/test/qt/jsonapi/test_MsgHandlerReader.cpp b/test/qt/jsonapi/test_MsgHandlerReader.cpp index df4e468..4926dca 100644 --- a/test/qt/jsonapi/test_MsgHandlerReader.cpp +++ b/test/qt/jsonapi/test_MsgHandlerReader.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerReader * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerReader.h" diff --git a/test/qt/jsonapi/test_MsgHandlerReaderList.cpp b/test/qt/jsonapi/test_MsgHandlerReaderList.cpp index dd750fe..f4d361a 100644 --- a/test/qt/jsonapi/test_MsgHandlerReaderList.cpp +++ b/test/qt/jsonapi/test_MsgHandlerReaderList.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref MsgHandlerReaderList * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "messages/MsgHandlerReader.h" diff --git a/test/qt/network/test_DatagramHandlerImpl.cpp b/test/qt/network/test_DatagramHandlerImpl.cpp index 029dbe2..a2407db 100644 --- a/test/qt/network/test_DatagramHandlerImpl.cpp +++ b/test/qt/network/test_DatagramHandlerImpl.cpp @@ -1,12 +1,12 @@ /*! * \brief Unit tests for \ref DatagramHandlerImpl * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "DatagramHandlerImpl.h" -#include "EnvHolder.h" +#include "Env.h" #include "LogHandler.h" #include @@ -24,7 +24,6 @@ class test_DatagramHandlerImpl private Q_SLOTS: void initTestCase() { - DatagramHandler::registerMetaTypes(); LogHandler::getInstance().init(); } @@ -44,7 +43,7 @@ class test_DatagramHandlerImpl void startUpShutDown() { QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - QSharedPointer socket(EnvHolder::create()); + QSharedPointer socket(Env::create()); QVERIFY(socket->isBound()); QCOMPARE(spy.count(), 1); @@ -67,7 +66,7 @@ class test_DatagramHandlerImpl DatagramHandlerImpl::cPort = 80; QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - QSharedPointer socket(EnvHolder::create()); + QSharedPointer socket(Env::create()); QVERIFY(!socket->isBound()); QCOMPARE(spy.count(), 1); @@ -78,7 +77,7 @@ class test_DatagramHandlerImpl void getNonJsonDatagram() { - QSharedPointer socket(EnvHolder::create()); + QSharedPointer socket(Env::create()); QVERIFY(socket->isBound()); QSignalSpy spySocket(socket.data(), &DatagramHandler::fireNewMessage); @@ -119,11 +118,10 @@ class test_DatagramHandlerImpl } #endif - QSharedPointer socket(EnvHolder::create()); + QSharedPointer socket(Env::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); @@ -131,13 +129,9 @@ class test_DatagramHandlerImpl QByteArray data("{\"key\":\"value\"}"); auto written = clientSocket.writeDatagram(data, broadcast ? QHostAddress::Broadcast : QHostAddress::LocalHost, socket.staticCast()->mSocket->localPort()); - spy.wait(); + spySocket.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); @@ -166,7 +160,9 @@ class test_DatagramHandlerImpl QVERIFY(receiver.bind()); QSignalSpy spyReceiver(&receiver, &QUdpSocket::readyRead); - QSharedPointer socket(EnvHolder::create()); + QSharedPointer datagramHandlerImpl = QSharedPointer(Env::create()).dynamicCast(); + QVERIFY(datagramHandlerImpl); + DatagramHandlerImpl::cPort = receiver.localPort(); QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); @@ -179,11 +175,11 @@ class test_DatagramHandlerImpl #ifdef Q_OS_FREEBSD QSKIP("FreeBSD does not like that"); #endif - QVERIFY(socket->send(doc)); + QVERIFY(datagramHandlerImpl->send(doc)); } else { - QVERIFY(socket->send(doc, QHostAddress::LocalHost)); + QVERIFY(datagramHandlerImpl->send(doc, QHostAddress::LocalHost)); } spyReceiver.wait(); diff --git a/test/qt/network/test_HttpRequest.cpp b/test/qt/network/test_HttpRequest.cpp index e6793d1..1d49857 100644 --- a/test/qt/network/test_HttpRequest.cpp +++ b/test/qt/network/test_HttpRequest.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref HttpResponse * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpRequest.h" diff --git a/test/qt/network/test_HttpResponse.cpp b/test/qt/network/test_HttpResponse.cpp index 1b154eb..eab4728 100644 --- a/test/qt/network/test_HttpResponse.cpp +++ b/test/qt/network/test_HttpResponse.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref HttpResponse * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpResponse.h" @@ -34,7 +34,7 @@ class test_HttpResponse 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)")); + QVERIFY(msg.contains("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.3)")); QCOMPARE(msg.size(), 158); } @@ -49,7 +49,7 @@ class test_HttpResponse 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("Server: Test_network_HttpResponse/1.2 (TR-03124-1/1.3)")); QVERIFY(msg.contains("\r\n\r\nthis is dummy content")); } diff --git a/test/qt/network/test_HttpServer.cpp b/test/qt/network/test_HttpServer.cpp index cad1a5f..e56c8db 100644 --- a/test/qt/network/test_HttpServer.cpp +++ b/test/qt/network/test_HttpServer.cpp @@ -1,12 +1,12 @@ /*! * \brief Unit tests for \ref HttpResponse * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "HttpServer.h" -#include "EnvHolder.h" +#include "Env.h" #include "LogHandler.h" #include "MockSocket.h" @@ -49,7 +49,7 @@ class test_HttpServer void startUpShutDown() { QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); - auto server = EnvHolder::shared(); + auto server = Env::getShared(); QVERIFY(server->isListening()); QCOMPARE(spy.count(), 1); diff --git a/test/qt/network/test_NetworkManager.cpp b/test/qt/network/test_NetworkManager.cpp index 6262943..34f1642 100644 --- a/test/qt/network/test_NetworkManager.cpp +++ b/test/qt/network/test_NetworkManager.cpp @@ -1,12 +1,18 @@ /*! * \brief Unit tests for \ref NetworkManager * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include "AppSettings.h" +#include "context/SelfAuthContext.h" +#include "controller/SelfAuthController.h" +#include "Env.h" #include "LogHandler.h" #include "NetworkManager.h" +#include "SecureStorage.h" + +#include "MockNetworkManager.h" +#include "MockNetworkReply.h" #include #include @@ -14,6 +20,7 @@ using namespace governikus; +Q_DECLARE_METATYPE(QSharedPointer ) class test_NetworkManager : public QObject @@ -23,7 +30,6 @@ class test_NetworkManager private Q_SLOTS: void initTestCase() { - AppSettings::getInstance().load(); LogHandler::getInstance().init(); } @@ -37,12 +43,17 @@ class test_NetworkManager void paosRequestAttached() { QNetworkRequest request(QUrl("https://dummy")); - NetworkManager manager; - auto reply = manager.paos(request, "content", false, 1); + auto reply = Env::getSingleton()->paos(request, "paosNamespace", "content", false, 1); + QVERIFY(request.hasRawHeader("PAOS")); + QCOMPARE(request.rawHeader("PAOS"), QByteArray("ver=\"paosNamespace\"")); QCOMPARE(reply->request(), request); QCOMPARE(request.sslConfiguration().ellipticCurves().size(), 6); QVERIFY(request.sslConfiguration().ellipticCurves().contains(QSslEllipticCurve::fromLongName("prime256v1"))); +#if OPENSSL_VERSION_NUMBER < 0x10100000L QCOMPARE(request.sslConfiguration().ciphers().size(), 24); +#else + QCOMPARE(request.sslConfiguration().ciphers().size(), 18); +#endif QVERIFY(request.sslConfiguration().ciphers().contains(QSslCipher("ECDHE-RSA-AES256-GCM-SHA384"))); } @@ -50,8 +61,9 @@ class test_NetworkManager void paosRequestPsk() { QNetworkRequest request(QUrl("https://dummy")); - NetworkManager manager; - auto reply = manager.paos(request, "content", true, 1); + auto reply = Env::getSingleton()->paos(request, "paosNamespace", "content", true, 1); + QVERIFY(request.hasRawHeader("PAOS")); + QCOMPARE(request.rawHeader("PAOS"), QByteArray("ver=\"paosNamespace\"")); QCOMPARE(reply->request(), request); QCOMPARE(request.sslConfiguration().ellipticCurves().size(), 0); QCOMPARE(request.sslConfiguration().ciphers().size(), 5); @@ -63,6 +75,77 @@ class test_NetworkManager } + void serviceUnavailableEnums() + { + MockNetworkReply reply; + reply.setNetworkError(QNetworkReply::ServiceUnavailableError, "dummy error msg"); + + QCOMPARE(NetworkManager::toNetworkError(&reply), NetworkManager::NetworkError::ServiceUnavailable); + QCOMPARE(NetworkManager::toTrustedChannelStatus(&reply), GlobalStatus(GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable)); + QCOMPARE(NetworkManager::toStatus(&reply), GlobalStatus(GlobalStatus::Code::Network_ServiceUnavailable)); + } + + + void serviceUnavailable_data() + { + QTest::addColumn >("status"); + QTest::addColumn("param"); + QTest::addColumn("msg"); + + const auto& msg = QStringLiteral("The service is temporarily not available. Please try again later."); + + auto status = QSharedPointer::create(GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable); + QTest::newRow("trustedChannel") << status << true << msg; + QTest::newRow("trustedChannel") << status << false << msg; + + status = QSharedPointer::create(GlobalStatus::Code::Network_ServiceUnavailable); + QTest::newRow("network") << status << true << msg; + QTest::newRow("network") << status << false << msg; + } + + + void serviceUnavailable() + { + QFETCH(QSharedPointer, status); + QFETCH(bool, param); + QFETCH(QString, msg); + + QCOMPARE(status->toErrorDescription(param), msg); + } + + + void serviceUnavailableWorkflow() + { + MockNetworkManager networkManager; + Env::set(NetworkManager::staticMetaObject, &networkManager); + connect(&networkManager, &MockNetworkManager::fireReply, this, [&] { + networkManager.fireFinished(); + }, Qt::QueuedConnection); + + auto reply = new MockNetworkReply; + reply->setNetworkError(QNetworkReply::ServiceUnavailableError, "dummy"); + networkManager.setNextReply(reply); + + + auto context = QSharedPointer::create(); + connect(context.data(), &AuthContext::fireStateChanged, this, [&] { + context->setStateApproved(); + }); + + SelfAuthController controller(context); + QSignalSpy spy(&controller, &WorkflowController::fireComplete); + + controller.run(); + + if (spy.count() == 0) + { + spy.wait(); + } + QCOMPARE(spy.count(), 1); + QCOMPARE(context->getStatus(), GlobalStatus(GlobalStatus::Code::Workflow_TrustedChannel_ServiceUnavailable)); + } + + }; QTEST_GUILESS_MAIN(test_NetworkManager) diff --git a/test/qt/network/test_TlsChecker.cpp b/test/qt/network/test_TlsChecker.cpp new file mode 100644 index 0000000..081bfaf --- /dev/null +++ b/test/qt/network/test_TlsChecker.cpp @@ -0,0 +1,314 @@ +/*! + * \brief Unit tests for \ref CertificateChecker + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TlsChecker.h" + +#include "LogHandler.h" +#include "SecureStorage.h" + +#include "MockNetworkReply.h" +#include "TestFileHelper.h" + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(network) + +using namespace governikus; + +Q_DECLARE_METATYPE(QSsl::KeyAlgorithm) + +class test_TlsChecker + : public QObject +{ + Q_OBJECT + + QVector certs; + + static QSslKey createQSslKeyWithHandle(const QByteArray& pPemEncodedEvpPKey) + { + BIO* bio = BIO_new(BIO_s_mem()); + BIO_write(bio, pPemEncodedEvpPKey.constData(), pPemEncodedEvpPKey.length()); + QSslKey key(PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr), QSsl::PublicKey); + BIO_free(bio); + return key; + } + + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + certs = SecureStorage::getInstance().getUpdateCertificates(); + QVERIFY(certs.size() > 0); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void hasUpdateCertificateKeyLength() + { + for (const auto& cert : qAsConst(certs)) + { + QVERIFY(TlsChecker::hasValidCertificateKeyLength(cert)); + } + } + + + void hasCertificateKeyLength_data() + { + QTest::addColumn("filename"); + QTest::addColumn("output"); + + 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 hasCertificateKeyLength() + { + 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(!TlsChecker::hasValidCertificateKeyLength(invalidCert)); + + QVERIFY(spy.count() > 0); + auto param = spy.takeLast(); + QVERIFY(param.at(0).toString().contains(output)); + } + + + void checkCertificateHash() + { + QVERIFY(!TlsChecker::checkCertificate(certs.at(0), QCryptographicHash::Algorithm::Sha256, QSet() << "dummy" << "bla bla")); + const QString hash = "D06F1E6E5968653E67B4DBE93895C70E9B74B0E28BA5DBCFC3B4540B77F7B88E"; + QVERIFY(TlsChecker::checkCertificate(certs.at(0), QCryptographicHash::Algorithm::Sha256, QSet() << "dummy" << hash << "bla bla")); + } + + + void hasEmptyEphemeralKey() + { + QSslKey key; + QVERIFY(!TlsChecker::hasValidEphemeralKeyLength(key)); + } + + + 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 ec112("-----BEGIN PUBLIC KEY-----\n" + "MDIwEAYHKoZIzj0CAQYFK4EEAAcDHgAEWo89aCax3oUWJho7rFZ1u70WqghvA7Tf\n" + "SXXiZw==\n" + "-----END PUBLIC KEY-----"); + + QTest::newRow("ec112") << ec112 << QSsl::KeyAlgorithm::Ec << false; + + /* + * 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 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; + + /* + * 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 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; + + /* + * 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 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 << false; + + /* + * openssl dsaparam -out dsa2048_param.pem 2048 + * openssl gendsa -out dsa2048_key.pem dsa2048_param.pem + * openssl dsa -in dsa2048_key.pem -pubout -out dsa2048_pubkey.pem + */ + QByteArray dsa2048("-----BEGIN PUBLIC KEY-----\n" + "MIIDSDCCAjoGByqGSM44BAEwggItAoIBAQDZiiMJ3Dmz9N/0DtlMYPDGzHv4EJBr\n" + "jFA7hNwK6ErO53JUnonaSIXoCf+yRuELAjr/O+VQ/kN1C10/czeNR7/zas+3MtEh\n" + "Y6cYHbMbce0ChxyW+GFgVixUwIkwMZVcRHjSGzfo/WXMyo08w6adWTYxMkb48OFl\n" + "Qfu/Z22GQ+lor7lyuOLkyOhgDxbZLuViryeKzYIZd3t5iony6X13a8lcefAac1bN\n" + "QQyBraRIpO8+H9bQkzDDMzYawRpFB8iVLgszGMblX0CxYjb5aUTvuYugYCO1pG83\n" + "5PH9f00W6FVk6sCiGM1sR/ED20fOAvhDDMaF++EB9ue8+rluskTa1EEbAiEAzuTB\n" + "M85eGF0KlXynqkZ3bNDg68Y2S/91KIX7I4LJ2MMCggEBANkPkUAhhIqd++GhuFmB\n" + "+zn3PrPArv9YqjlY+Q3gIcjWmTumDsCokjmW2xbgXTRFPQRX03b2PdQ51HYoSX2H\n" + "sPv65jiuOen9yLR+euMPD4EPaVG6R8v6RjXbzw/0BpMmt3504fwOPTz0diVghxFM\n" + "NAurfrIVupzUCU7uaxDgJDV2/6KZJjfZPYuzh1iCE9JBxdpW3yf7WMhhcgZYlVaj\n" + "ZTzHi9oOob0rQPlLFSXjQ0HQEqGWP7rJv18u1rnSnRLI16OoxNIDl9XC7iIPZd5z\n" + "Sd/tWTWzTuWSTA39njSbgIHCZgmIKzpaMNeLosnTaOcbs8GU01tErw3hJdHqgpNX\n" + "d3cDggEGAAKCAQEAgaqu8eNK8O2VND8xpjMmgxRTHtWQkPNXB5POpQglr1nwyzkn\n" + "VsvC+JM64cJiGH+6XrQguPvIduBpR013/SSYqPu6itdbZKNb7P5+tQrN3GtLeuv6\n" + "5zf6GMc3ZgR6Bp74EBXAnSZZgHNc/EEXuSyP1P3FqaSPsuZuiagVujDZpWKERCCl\n" + "+6qQXvUg41ZA3K0G0Wf6ZJVPMD6vzSrkF+rJ9cgJeFwCBQ+laFc23Mke8lvblyPS\n" + "+wc7yd8AmFxlcif7PKZ+NzsmA53JOFOnNSvMFXXykJnxqJbUA6Iw+Je3mW+4PsD4\n" + "foMYlbwM/IzefL1TD2+eBlyV0unSwMIwrvXPTg==\n" + "-----END PUBLIC KEY-----\n"); + + QTest::newRow("dsa2048") << dsa2048 << QSsl::KeyAlgorithm::Dsa << true; + + /* + * openssl genrsa -out rsa1024_key.pem 1024 + * openssl rsa -in rsa1024_key.pem -out rsa1024_pubkey.pem -pubout + */ + 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; + + /* + * openssl genrsa -out rsa2048_key.pem 2048 + * openssl rsa -in rsa2048_key.pem -out rsa2048_pubkey.pem -pubout + */ + 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(!key.isNull()); + QCOMPARE(key.algorithm(), algorithm); + QCOMPARE(TlsChecker::hasValidEphemeralKeyLength(key), sufficient); + } + + + void containsFatalError() + { + MockNetworkReply reply; + QList errors; + + QVERIFY(!TlsChecker::containsFatalError(&reply, errors)); + + errors.append(QSslError(QSslError::SslError::SelfSignedCertificate)); + QVERIFY(!TlsChecker::containsFatalError(&reply, errors)); + + errors.append(QSslError(QSslError::SslError::SubjectIssuerMismatch)); + QVERIFY(TlsChecker::containsFatalError(&reply, errors)); + } + + + void addUnsupportedCipher() + { + SslCipherList list; + QVERIFY(list.isEmpty()); + list += QStringLiteral("dummy value"); + QVERIFY(list.isEmpty()); + } + + + void addSupportedCipher() + { + SslCipherList list; + QVERIFY(list.isEmpty()); + list += QStringLiteral("ECDHE-ECDSA-AES256-GCM-SHA384"); + QCOMPARE(list.length(), 1); + } + + + void addUnsupportedCurve() + { + SslEllipticCurveVector vector; + QVERIFY(vector.isEmpty()); + vector += QStringLiteral("dummy value"); + QVERIFY(vector.isEmpty()); + } + + + void addSupportedCurve() + { + SslEllipticCurveVector vector; + QVERIFY(vector.isEmpty()); + vector += QStringLiteral("brainpoolP512r1"); + QCOMPARE(vector.length(), 1); + } + + + void sslConfigLog() + { + QSignalSpy spy(&LogHandler::getInstance(), &LogHandler::fireLog); + QSslConfiguration cfg; + TlsChecker::logSslConfig(cfg, qInfo(network)); + + QCOMPARE(spy.count(), 5); + QVERIFY(spy.at(0).at(0).toString().contains("Used session cipher QSslCipher(name=, bits=0, proto=)")); + QVERIFY(spy.at(1).at(0).toString().contains("Used session protocol: \"UnknownProtocol\"")); + QVERIFY(spy.at(2).at(0).toString().contains("Used ephemeral server key:")); + QVERIFY(spy.at(3).at(0).toString().contains("Used peer certificate: QSslCertificate(\"\", \"\", \"1B2M2Y8AsgTpgAmY7PhCfg==\"")); + QVERIFY(spy.at(4).at(0).toString().contains("Handshake of tls connection done!")); + } + + +}; + +QTEST_GUILESS_MAIN(test_TlsChecker) +#include "test_TlsChecker.moc" diff --git a/test/qt/network/test_TlsConfiguration.cpp b/test/qt/network/test_TlsConfiguration.cpp deleted file mode 100644 index 5351821..0000000 --- a/test/qt/network/test_TlsConfiguration.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * \brief Unit tests for \ref TlsConfiguration - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "TlsConfiguration.h" - -#include "AppSettings.h" -#include "MockNetworkReply.h" - -#include - - -using namespace governikus; - -class test_TlsConfiguration - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void initTestCase() - { - AppSettings::getInstance().load(); - } - - - void containsFatalError() - { - MockNetworkReply reply; - QList errors; - - QVERIFY(!TlsConfiguration::containsFatalError(&reply, errors)); - - errors.append(QSslError(QSslError::SslError::SelfSignedCertificate)); - QVERIFY(!TlsConfiguration::containsFatalError(&reply, errors)); - - errors.append(QSslError(QSslError::SslError::SubjectIssuerMismatch)); - QVERIFY(TlsConfiguration::containsFatalError(&reply, errors)); - } - - - void addUnsupportedCipher() - { - SslCipherList list; - QVERIFY(list.isEmpty()); - list += QStringLiteral("dummy value"); - QVERIFY(list.isEmpty()); - } - - - void addSupportedCipher() - { - SslCipherList list; - QVERIFY(list.isEmpty()); - list += QStringLiteral("ECDHE-ECDSA-AES256-GCM-SHA384"); - QCOMPARE(list.length(), 1); - } - - - void addUnsupportedCurve() - { - SslEllipticCurveVector vector; - QVERIFY(vector.isEmpty()); - vector += QStringLiteral("dummy value"); - QVERIFY(vector.isEmpty()); - } - - - void addSupportedCurve() - { - SslEllipticCurveVector vector; - QVERIFY(vector.isEmpty()); - vector += QStringLiteral("brainpoolP512r1"); - QCOMPARE(vector.length(), 1); - } - - -}; - -QTEST_GUILESS_MAIN(test_TlsConfiguration) -#include "test_TlsConfiguration.moc" diff --git a/test/qt/network/test_UrlUtil.cpp b/test/qt/network/test_UrlUtil.cpp index 17e77d0..abb61ee 100644 --- a/test/qt/network/test_UrlUtil.cpp +++ b/test/qt/network/test_UrlUtil.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref test_UrlUtil * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "TestFileHelper.h" diff --git a/test/qt/pcsc/test_pcscReaderFeature.cpp b/test/qt/pcsc/test_pcscReaderFeature.cpp deleted file mode 100644 index c30dc71..0000000 --- a/test/qt/pcsc/test_pcscReaderFeature.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*! - * \brief Unit tests for \ref PcscReaderFeature - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ -#include "PcscReaderFeature.h" -#include -#include - -using namespace governikus; - -class test_pcscReaderFeature - : public QObject -{ - Q_OBJECT - - private Q_SLOTS: - void featuresEmpty() - { - PcscReaderFeature readerFeature(nullptr); - QCOMPARE(readerFeature.toString(), QString("[]")); - QCOMPARE(readerFeature.getFeatures().size(), 0); - } - - - void featuresCyberjackBasis() - { - QByteArray featuresTLV = QByteArray::fromHex("120442330012"); - 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), PCSC_INT(1110638610)); - } - - - void featuresCyberjackStandard() - { - QByteArray featuresTLV = QByteArray::fromHex("060442000db2070442000db3080442000db4090442000db5200442000dcc"); - 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); - - QVERIFY(readerFeature.getFeatures().contains(FeatureID::VERIFY_PIN_DIRECT)); - QVERIFY(readerFeature.getFeatures().contains(FeatureID::MODIFY_PIN_DIRECT)); - QVERIFY(readerFeature.getFeatures().contains(FeatureID::MCT_READERDIRECT)); - QVERIFY(readerFeature.getFeatures().contains(FeatureID::MCT_UNIVERSAL)); - QVERIFY(readerFeature.getFeatures().contains(FeatureID::EXECUTE_PACE)); - - 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)); - } - - - void capabilitiesEmpty() - { - PcscReaderPaceCapability paceCapa(nullptr); - QCOMPARE(paceCapa.toString(), QString("[]")); - QVERIFY(paceCapa.getPaceCapabilities().isEmpty()); - } - - - void capabilitiesCyberjackStandard() - { - QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010060"); - 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)); - QVERIFY(paceCapa.getPaceCapabilities().contains(PaceCapabilityId::GENERIC)); - } - - - void capabilitiesCyberjackKomfort() - { - QByteArray capabilitiesTLV = QByteArray::fromHex("00000000010070"); - 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)); - QVERIFY(paceCapa.getPaceCapabilities().contains(PaceCapabilityId::ESIGN)); - QVERIFY(paceCapa.getPaceCapabilities().contains(PaceCapabilityId::GENERIC)); - } - - -}; - -QTEST_GUILESS_MAIN(test_pcscReaderFeature) -#include "test_pcscReaderFeature.moc" diff --git a/test/qt/qml/test_ProviderModel.cpp b/test/qt/qml/test_ProviderModel.cpp index 284eae2..15323bf 100644 --- a/test/qt/qml/test_ProviderModel.cpp +++ b/test/qt/qml/test_ProviderModel.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref ProviderModel * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "ProviderModel.h" diff --git a/test/qt/remote/test_notificationHandler.cpp b/test/qt/remote/test_notificationHandler.cpp deleted file mode 100644 index ae1759d..0000000 --- a/test/qt/remote/test_notificationHandler.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 9d6751b..0000000 --- a/test/qt/remote/test_notificationParser.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/*! - * \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 deleted file mode 100644 index 60bb045..0000000 --- a/test/qt/remote/test_remoteCardNotifications.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/*! - * \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/remote_device/test_RemoteClientImpl.cpp b/test/qt/remote_device/test_RemoteClientImpl.cpp new file mode 100644 index 0000000..c3cef30 --- /dev/null +++ b/test/qt/remote_device/test_RemoteClientImpl.cpp @@ -0,0 +1,308 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteClientImpl.h" + +#include "DatagramHandler.h" +#include "Env.h" +#include "LogHandler.h" +#include "messages/Discovery.h" +#include "messages/IfdEstablishContext.h" + +#include +#include + + +using namespace governikus; + + +namespace governikus +{ + +class DatagramHandlerMock + : public DatagramHandler +{ + Q_OBJECT + + public: + virtual ~DatagramHandlerMock() override; + + + virtual bool isBound() const override + { + return true; + } + + + virtual bool send(const QJsonDocument&) override + { + return true; + } + + +}; + +DatagramHandlerMock::~DatagramHandlerMock() +{ +} + + +class RemoteDeviceListMock + : public RemoteDeviceList +{ + Q_OBJECT + + public: + RemoteDeviceListMock(int pI1, int pI2) + : RemoteDeviceList(pI1, pI2) + { + + } + + + virtual ~RemoteDeviceListMock() override; + + virtual void update(const RemoteDeviceDescriptor&) override + { + Q_EMIT fireDeviceAppeared(QSharedPointer()); + } + + + virtual void clear() override + { + + } + + +}; + +RemoteDeviceListMock::~RemoteDeviceListMock() +{ + +} + + +class RemoteConnectorMock + : public RemoteConnector +{ + Q_OBJECT + + public Q_SLOTS: + virtual void onConnectRequest(const RemoteDeviceDescriptor& pRemoteDeviceDescriptor, const QString& pPsk) override; + + Q_SIGNALS: + void fireConnectionRequestReceived(); +}; + + +void RemoteConnectorMock::onConnectRequest(const RemoteDeviceDescriptor&, const QString&) +{ + Q_EMIT fireConnectionRequestReceived(); +} + + +} + +class test_RemoteClient + : public QObject +{ + Q_OBJECT + + private: + QPointer mDatagramHandlerMock; + QPointer mRemoteDeviceListMock; + QPointer mRemoteConnectorMock; + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + } + + + void init() + { + Env::setCreator(std::function([&] { + mDatagramHandlerMock = new DatagramHandlerMock; + return mDatagramHandlerMock; + })); + + Env::setCreator(std::function([&] { + mRemoteDeviceListMock = new RemoteDeviceListMock(0, 0); + return mRemoteDeviceListMock; + })); + + Env::setCreator(std::function([&] { + mRemoteConnectorMock = new RemoteConnectorMock; + return mRemoteConnectorMock; + })); + } + + + void cleanup() + { + QVERIFY(Env::getCounter() <= 2); + Env::clear(); + QVERIFY(mDatagramHandlerMock.isNull()); + QVERIFY(mRemoteDeviceListMock.isNull()); + QVERIFY(mRemoteConnectorMock.isNull()); + } + + + void testStartStopDetection() + { + RemoteClientImpl client; + + QVERIFY(mDatagramHandlerMock.isNull()); + + client.startDetection(); + QCOMPARE(Env::getCounter(), 1); + QVERIFY(!mDatagramHandlerMock.isNull()); + + client.stopDetection(); + QVERIFY(mDatagramHandlerMock.isNull()); + + client.startDetection(); + QCOMPARE(Env::getCounter(), 2); + QVERIFY(!mDatagramHandlerMock.isNull()); + + client.stopDetection(); + QVERIFY(mDatagramHandlerMock.isNull()); + } + + + void testReceiveIPv6() + { + QSignalSpy logSpy(&LogHandler::getInstance(), &LogHandler::fireLog); + + const auto& offerJson = QJsonDocument::fromJson("{\n" + " \"deviceName\": \"Sony Xperia Z5 compact\",\n" + " \"encrypted\": true,\n" + " \"port\": 24728,\n" + " \"availableApiLevels\": [1, 2, 3, 4]\n" + "}"); + + RemoteClientImpl client; + QSignalSpy spyAppeared(&client, &RemoteClient::fireDeviceAppeared); + client.startDetection(); + Q_EMIT mDatagramHandlerMock->fireNewMessage(offerJson, QHostAddress("2001:0db8:85a3:08d3:1319:8a2e:0370:7344")); + + QCOMPARE(logSpy.count(), 1); + QVERIFY(logSpy.at(0).at(0).toString().contains("IPv6 not supported")); + QVERIFY(spyAppeared.isEmpty()); + } + + + void testReceiveUnparsable() + { + QSignalSpy logSpy(&LogHandler::getInstance(), &LogHandler::fireLog); + + const auto& unparsableJson = QJsonDocument::fromJson("{\n" + " \"device___Name\": \"Sony Xperia Z5 compact\",\n" + " \"encrypted\": true,\n" + " \"port\": 24728,\n" + " \"availableApiLevels\": [1, 2, 3, 4]\n" + "}"); + + RemoteClientImpl client; + client.startDetection(); + QVERIFY(!mDatagramHandlerMock.isNull()); + + Q_EMIT mDatagramHandlerMock->fireNewMessage(unparsableJson, QHostAddress("192.168.1.88")); + QCOMPARE(logSpy.count(), 2); + QVERIFY(logSpy.at(1).at(0).toString().contains("Discarding unparsable message")); + } + + + void testReceiveUnexpected() + { + QSignalSpy logSpy(&LogHandler::getInstance(), &LogHandler::fireLog); + + RemoteClientImpl client; + client.startDetection(); + QVERIFY(!mDatagramHandlerMock.isNull()); + + Q_EMIT mDatagramHandlerMock->fireNewMessage(IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()).toJson(QStringLiteral("TestContext")), QHostAddress("192.168.1.88")); + QCOMPARE(logSpy.count(), 2); + QVERIFY(logSpy.at(0).at(0).toString().contains("The value of \"IFDName\" should be of type string")); + QVERIFY(logSpy.at(1).at(0).toString().contains("Discarding unparsable message")); + } + + + void testReceive() + { + const auto& offerJson = QJsonDocument::fromJson("{\n" + " \"IFDName\": \"Sony Xperia Z5 compact\",\n" + " \"IFDID\": \"0123456789ABCDEF\",\n" + " \"encrypted\": true,\n" + " \"msg\": \"REMOTE_IFD\",\n" + " \"port\": 24728,\n" + " \"SupportedAPI\": [\"IFDInterface_WebSocket_v0\", \"IFDInterface_WebSocket_v2\"]\n" + "}"); + + RemoteClientImpl client; + client.startDetection(); + QVERIFY(!mDatagramHandlerMock.isNull()); + + QVERIFY(!mRemoteDeviceListMock.isNull()); + QSignalSpy spyAppearedList(mRemoteDeviceListMock.data(), &RemoteDeviceListMock::fireDeviceAppeared); + QSignalSpy spyAppeared(&client, &RemoteClient::fireDeviceAppeared); + + Q_EMIT mDatagramHandlerMock->fireNewMessage(offerJson, QHostAddress("192.168.1.88")); + QCOMPARE(spyAppearedList.count(), 1); + QCOMPARE(spyAppeared.count(), 1); + + QSignalSpy spyVanished(&client, &RemoteClient::fireDeviceVanished); + QCOMPARE(spyVanished.count(), 0); + Q_EMIT mRemoteDeviceListMock->fireDeviceVanished(QSharedPointer()); + QCOMPARE(spyVanished.count(), 1); + } + + + void testRemoteConnectorThread() + { + QScopedPointer client(new RemoteClientImpl); + QCOMPARE(Env::getCounter(), 1); + QVERIFY(!mRemoteConnectorMock.isNull()); + QVERIFY(client->thread() != mRemoteConnectorMock->thread()); + + client.reset(); + QVERIFY(mRemoteConnectorMock.isNull()); + } + + + void testRemoteConnectorEstablish() + { + const auto& offerJson = QJsonDocument::fromJson("{\n" + " \"deviceName\": \"Sony Xperia Z5 compact\",\n" + " \"encrypted\": true,\n" + " \"port\": 24728,\n" + " \"availableApiLevels\": [\"IFDInterface_WebSocket_v0\", \"IFDInterface_WebSocket_v2\"]\n" + "}"); + + RemoteClientImpl client; + client.startDetection(); + QVERIFY(!mDatagramHandlerMock.isNull()); + Q_EMIT mDatagramHandlerMock->fireNewMessage(offerJson, QHostAddress("192.168.1.88")); + + QVERIFY(!mRemoteConnectorMock.isNull()); + QSignalSpy spyConnectionRequest(mRemoteConnectorMock.data(), &RemoteConnectorMock::fireConnectionRequestReceived); + const QSharedPointer msg(new Discovery("", QStringLiteral("0123456789ABCDEF"), 12345, {QStringLiteral("IFDInterface_WebSocket_v0"), QStringLiteral("IFDInterface_WebSocket_v2")})); + const RemoteDeviceDescriptor descr(msg, QHostAddress("192.168.1.88")); + QSharedPointer emptyEntry(new RemoteDeviceListEntry(descr)); + client.establishConnection(emptyEntry, QString("password1")); + + spyConnectionRequest.wait(); + QCOMPARE(spyConnectionRequest.count(), 1); + + QSignalSpy spyConnectionDone(&client, &RemoteClient::fireEstablishConnectionDone); + Q_EMIT mRemoteConnectorMock->fireRemoteDispatcherError(emptyEntry->getRemoteDeviceDescriptor(), RemoteErrorCode::CONNECTION_ERROR); + QCOMPARE(spyConnectionDone.count(), 1); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteClient) +#include "test_RemoteClientImpl.moc" diff --git a/test/qt/remote_device/test_RemoteConnector.cpp b/test/qt/remote_device/test_RemoteConnector.cpp new file mode 100644 index 0000000..ae476b9 --- /dev/null +++ b/test/qt/remote_device/test_RemoteConnector.cpp @@ -0,0 +1,426 @@ +/*! + * \brief Unit tests for \ref RemoteConnector + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteConnectorImpl.h" + +#include "AppSettings.h" +#include "Env.h" +#include "KeyPair.h" +#include "messages/Discovery.h" +#include "MockDataChannel.h" +#include "RemoteHelper.h" +#include "RemoteWebSocketServer.h" +#include "SecureStorage.h" + +#include +#include +#include + +#include + +using namespace governikus; + +Q_DECLARE_METATYPE(RemoteDeviceDescriptor) +Q_DECLARE_METATYPE(QSharedPointer ) +Q_DECLARE_METATYPE(RemoteErrorCode) + + +class test_RemoteConnector + : public QObject +{ + Q_OBJECT + + private: + static const int cConnectTimeoutMs = 500; + static const int cSignalTimeoutMs = 10 * cConnectTimeoutMs; + + void waitForSignals(QSignalSpy* const pSpy, const int pExpectedCount, const int pTimeoutMs) + { + for (int tryCount = 0; pSpy->count() < pExpectedCount && tryCount < pExpectedCount; ++tryCount) + { + pSpy->wait(pTimeoutMs); + } + QCOMPARE(pSpy->count(), pExpectedCount); + } + + + void sendRequest(const QSharedPointer& pConnector, + const QHostAddress& pHostAddress, + const QSharedPointer& pDiscovery, + const QString& pPassword) + { + const RemoteDeviceDescriptor descr(pDiscovery, pHostAddress); + QMetaObject::invokeMethod(pConnector.data(), + "onConnectRequest", + Qt::QueuedConnection, + Q_ARG(RemoteDeviceDescriptor, descr), + Q_ARG(QString, pPassword)); + } + + + void verifySuccessSignal(const QSignalSpy& pSignalSpy, + const quint16 pPort) + { + const static QHostAddress HOST_ADDRESS(QHostAddress::LocalHost); + const static QString IFD_NAME("Smartphone1"); + + bool signalFound = false; + for (const QList& arguments : pSignalSpy) + { + const QVariant remoteDeviceDescriptorVariant = arguments.at(0); + QVERIFY(remoteDeviceDescriptorVariant.canConvert()); + const RemoteDeviceDescriptor descr = remoteDeviceDescriptorVariant.value(); + QVERIFY(!descr.isNull()); + + const QVariant dispatcherVariant = arguments.at(1); + QVERIFY(dispatcherVariant.canConvert >()); + const QSharedPointer dispatcher = dispatcherVariant.value >(); + QVERIFY(dispatcher); + + const QUrl remoteUrl = descr.getUrl(); + const QString remoteAddress = remoteUrl.host(); + const int remotePort = remoteUrl.port(); + const bool signalMatches = remoteAddress == HOST_ADDRESS.toString() && remotePort == pPort && + descr.getIfdName() == IFD_NAME; + if (signalMatches) + { + qDebug() << "Success verified"; + signalFound = true; + break; + } + } + QVERIFY(signalFound); + } + + + void verifyErrorSignal(const QSignalSpy& pSignalSpy, + const QList& pRemoteErrorCodeList, + const quint16 pPort, + const QString& pIfdName, + const bool pExpectingNullDeviceDescriptor = false) + { + const static QHostAddress HOST_ADDRESS(QHostAddress::LocalHost); + + bool signalFound = false; + for (const QList& arguments : pSignalSpy) + { + const QVariant remoteDeviceDescriptorVariant = arguments.at(0); + QVERIFY(remoteDeviceDescriptorVariant.canConvert()); + const RemoteDeviceDescriptor descr = remoteDeviceDescriptorVariant.value(); + + if (pExpectingNullDeviceDescriptor && descr.isNull()) + { + qDebug() << "Error verified"; + signalFound = true; + break; + } + QVERIFY(!descr.isNull()); + + const QVariant errorCodeVariant = arguments.at(1); + QVERIFY(errorCodeVariant.canConvert()); + const RemoteErrorCode errorCode = errorCodeVariant.value(); + + const QUrl remoteUrl = descr.getUrl(); + const QString remoteAddress = remoteUrl.host(); + const int remotePort = remoteUrl.port(); + const bool signalMatches = remoteAddress == HOST_ADDRESS.toString() && + remotePort == pPort && + descr.getIfdName() == pIfdName && + pRemoteErrorCodeList.contains(errorCode); + if (signalMatches) + { + qDebug() << "Error verified"; + signalFound = true; + break; + } + } + QVERIFY(signalFound); + + } + + + private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType("QWebSocketProtocol::CloseCode"); + } + + + void requestWithNoDeviceNameIsRejected() + { + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spySuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // No device name. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QString(), QStringLiteral("0123456789ABCDEF"), 2020, {QStringLiteral("IFDInterface_WebSocket_v0")})); + sendRequest(connector, hostAddress, msg, QString()); + waitForSignals(&spyError, 1, cSignalTimeoutMs); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + + verifyErrorSignal(spyError, {RemoteErrorCode::INVALID_REQUEST}, 2020, QString()); + QCOMPARE(spySuccess.count(), 0); + } + + + void requestWithNoDeviceInfoIsRejected() + { + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spySuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Device information is null. + const QHostAddress hostAddress(QHostAddress::LocalHost); + sendRequest(connector, hostAddress, QSharedPointer(), QStringLiteral("secret")); + waitForSignals(&spyError, 1, cSignalTimeoutMs); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + + verifyErrorSignal(spyError, {RemoteErrorCode::INVALID_REQUEST}, 0, QString(), true); + QCOMPARE(spySuccess.count(), 0); + } + + + void requestWithEncryptedServerAndReconnectFails() + { + QScopedPointer server(Env::create()); + server->listen("dummy"); + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spySuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Password is empty. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QStringLiteral("Smartphone1"), QStringLiteral("0123456789ABCDEF"), server->getServerPort(), {QStringLiteral("IFDInterface_WebSocket_v0")})); + sendRequest(connector, hostAddress, msg, QString()); + waitForSignals(&spyError, 1, cSignalTimeoutMs); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + + verifyErrorSignal(spyError, {RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, server->getServerPort(), QStringLiteral("Smartphone1")); + QCOMPARE(spySuccess.count(), 0); + } + + + void requestWithUnsupportedApiLevelIsRejected() + { + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spySuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Currently, only API level 1 is supported. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QStringLiteral("Smartphone1"), QStringLiteral("0123456789ABCDEF"), 2020, {QStringLiteral("IFDInterface_WebSocket_v2")})); + sendRequest(connector, hostAddress, msg, QStringLiteral("secret")); + waitForSignals(&spyError, 1, cSignalTimeoutMs); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + + verifyErrorSignal(spyError, {RemoteErrorCode::NO_SUPPORTED_API_LEVEL}, 2020, QStringLiteral("Smartphone1")); + QCOMPARE(spySuccess.count(), 0); + } + + + void noServerResponseCausesConnectionErrorOrTimeout() + { + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spySuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Correct request but no server is running. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QStringLiteral("Smartphone1"), QStringLiteral("0123456789ABCDEF"), 2020, {QStringLiteral("IFDInterface_WebSocket_v0")})); + sendRequest(connector, hostAddress, msg, QString("dummy")); + waitForSignals(&spyError, 1, cSignalTimeoutMs); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + +#if !defined(Q_OS_FREEBSD) && !defined(Q_OS_WIN) + verifyErrorSignal(spyError, {RemoteErrorCode::CONNECTION_ERROR}, 2020, QStringLiteral("Smartphone1")); +#else + verifyErrorSignal(spyError, {RemoteErrorCode::CONNECTION_TIMEOUT, RemoteErrorCode::CONNECTION_ERROR}, 2020, QStringLiteral("Smartphone1")); +#endif + + QCOMPARE(spySuccess.count(), 0); + } + + + void encryptedConnectionSucceeds_data() + { + QTest::addColumn("psk"); + QTest::addColumn("sslConfigServer"); + QTest::addColumn >("trustedCertificates"); + + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + QVERIFY(RemoteHelper::checkAndGenerateKey()); + const KeyPair pair = KeyPair::generate(); + QVERIFY(pair.isValid()); + + QSslConfiguration config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + config.setCaCertificates({KeyPair::generate().getCertificate(), settings.getCertificate(), KeyPair::generate().getCertificate()}); + QTest::newRow("paired") << QString() << config << QList({KeyPair::generate().getCertificate(), pair.getCertificate(), KeyPair::generate().getCertificate()}); + + config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + QTest::newRow("unpaired") << QString("123456") << config << QList(); + } + + + void encryptedConnectionSucceeds() + { + QFETCH(QString, psk); + QFETCH(QSslConfiguration, sslConfigServer); + QFETCH(QList, trustedCertificates); + + QWebSocketServer webSocketServer(QStringLiteral("Smartphone1"), QWebSocketServer::SecureMode); + connect(&webSocketServer, &QWebSocketServer::preSharedKeyAuthenticationRequired, this, [&](QSslPreSharedKeyAuthenticator* pAuthenticator){ + pAuthenticator->setPreSharedKey(psk.toLatin1()); + }); + QSignalSpy spySocketError(&webSocketServer, &QWebSocketServer::serverError); + QSignalSpy spySocketSuccess(&webSocketServer, &QWebSocketServer::newConnection); + + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setTrustedCertificates(trustedCertificates); + webSocketServer.setSslConfiguration(sslConfigServer); + +#ifndef QT_NO_NETWORKPROXY + // Listening with proxy leads to socket error QNativeSocketEnginePrivate::InvalidProxyTypeString + webSocketServer.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); +#endif + webSocketServer.listen(QHostAddress(QHostAddress::LocalHost)); + const quint16 serverPort = webSocketServer.serverPort(); + + // Set up client thread. + QThread clientThread; + + // Execute test in internal block so that all relevant smart pointers are released before stopping the client thread. + QSharedPointer remoteDispatcherDestructionSpy; + { + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyConnectorError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spyConnectorSuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Send valid encrypted connect request. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QStringLiteral("Smartphone1"), QStringLiteral("0123456789ABCDEF"), serverPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + sendRequest(connector, hostAddress, msg, psk); + + waitForSignals(&spyConnectorSuccess, 1, cSignalTimeoutMs); + QCOMPARE(spyConnectorError.count(), 0); + verifySuccessSignal(spyConnectorSuccess, serverPort); + + const QVariant dispatcherVariant = spyConnectorSuccess.first().at(1); + QVERIFY(dispatcherVariant.canConvert >()); + const QSharedPointer dispatcher = dispatcherVariant.value >(); + remoteDispatcherDestructionSpy.reset(new QSignalSpy(dispatcher.data(), &QObject::destroyed)); + } + + QCOMPARE(spySocketError.count(), 0); + QCOMPARE(spySocketSuccess.count(), 1); + + waitForSignals(remoteDispatcherDestructionSpy.data(), 1, cSignalTimeoutMs); + QCOMPARE(remoteDispatcherDestructionSpy->count(), 1); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + + // Make sure that no pending web socket events are in the event queue when the test completes. + // Pending events were occasionally delivered after the web socket had been destroyed, leading to a crash. + QCoreApplication::processEvents(); + } + + + void encryptedConnectionWithWrongPasswordFails() + { + QWebSocketServer webSocketServer(QStringLiteral("Smartphone1"), QWebSocketServer::SecureMode); + QObject::connect(&webSocketServer, &QWebSocketServer::preSharedKeyAuthenticationRequired, [](QSslPreSharedKeyAuthenticator* pAuthenticator){ + pAuthenticator->setPreSharedKey(QByteArray("secret")); + }); + QSignalSpy spySocketError(&webSocketServer, &QWebSocketServer::serverError); + QSignalSpy spySocketSuccess(&webSocketServer, &QWebSocketServer::newConnection); + + QSslConfiguration config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + const KeyPair pair = KeyPair::generate(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + webSocketServer.setSslConfiguration(config); + +#ifndef QT_NO_NETWORKPROXY + // Listening with proxy leads to socket error QNativeSocketEnginePrivate::InvalidProxyTypeString + webSocketServer.setProxy(QNetworkProxy(QNetworkProxy::NoProxy)); +#endif + webSocketServer.listen(QHostAddress(QHostAddress::LocalHost)); + const quint16 serverPort = webSocketServer.serverPort(); + + // Set up client thread. + QThread clientThread; + + const QSharedPointer connector(new RemoteConnectorImpl(cConnectTimeoutMs)); + QSignalSpy spyConnectorError(connector.data(), &RemoteConnector::fireRemoteDispatcherError); + QSignalSpy spyConnectorSuccess(connector.data(), &RemoteConnector::fireRemoteDispatcherCreated); + + connector->moveToThread(&clientThread); + clientThread.start(); + + // Send encrypted connect request with wrong psk. + const QHostAddress hostAddress(QHostAddress::LocalHost); + const QSharedPointer msg(new Discovery(QStringLiteral("Smartphone1"), QStringLiteral("0123456789ABCDEF"), serverPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + sendRequest(connector, hostAddress, msg, QStringLiteral("sekret")); + + waitForSignals(&spyConnectorError, 1, cSignalTimeoutMs); + QCOMPARE(spyConnectorSuccess.count(), 0); + verifyErrorSignal(spyConnectorError, {RemoteErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, serverPort, QStringLiteral("Smartphone1")); + + QCOMPARE(spySocketError.count(), 0); + QCOMPARE(spySocketSuccess.count(), 0); + + clientThread.exit(); + QVERIFY(clientThread.wait()); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteConnector) +#include "test_RemoteConnector.moc" diff --git a/test/qt/remote_device/test_RemoteDeviceDescriptor.cpp b/test/qt/remote_device/test_RemoteDeviceDescriptor.cpp new file mode 100644 index 0000000..d61e37d --- /dev/null +++ b/test/qt/remote_device/test_RemoteDeviceDescriptor.cpp @@ -0,0 +1,94 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceDescriptor.h" + +#include "messages/Discovery.h" + +#include + + +using namespace governikus; + + +class test_RemoteDeviceDescriptor + : public QObject +{ + Q_OBJECT + + private: + quint16 mPort; + + private Q_SLOTS: + void initTestCase() + { + mPort = 0; + } + + + void testValidDescriptorIsEqualToItself() + { + const QSharedPointer validMsg(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + const QHostAddress address(QHostAddress::LocalHost); + const RemoteDeviceDescriptor valid(validMsg, address); + + QVERIFY(valid == valid); + } + + + void testDistinctInvalidDescriptorsAreEqual() + { + const QHostAddress address1(QStringLiteral("192.168.1.1")); + const QHostAddress address2(QHostAddress::LocalHost); + + const RemoteDeviceDescriptor invalid1(QSharedPointer(), address1); + const RemoteDeviceDescriptor invalid2(QSharedPointer(), address2); + + QVERIFY(invalid1 == invalid2); + } + + + void testValidDescriptorIsDifferentFromInvalid() + { + const QSharedPointer validMsg(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + const QSharedPointer invalidMsg; + const QHostAddress address(QHostAddress::LocalHost); + + const RemoteDeviceDescriptor valid(validMsg, address); + const RemoteDeviceDescriptor invalid(invalidMsg, address); + + QVERIFY(!(valid == invalid)); + } + + + void testDistinctValidDescriptorsWithDifferentDataAreDifferent() + { + const QSharedPointer validMsg1(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + const QSharedPointer validMsg2(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0"), QStringLiteral("IFDInterface_WebSocket_v2")})); + const QHostAddress address(QHostAddress::LocalHost); + + const RemoteDeviceDescriptor valid1(validMsg1, address); + const RemoteDeviceDescriptor valid2(validMsg2, address); + + QVERIFY(!(valid1 == valid2)); + } + + + void testDistinctValidDescriptorsWithTheSameDataAreEqual() + { + const QSharedPointer validMsg1(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + const QSharedPointer validMsg2(new Discovery(QStringLiteral("Device"), QStringLiteral("0123456789ABCDEF"), mPort, {QStringLiteral("IFDInterface_WebSocket_v0")})); + const QHostAddress address(QHostAddress::LocalHost); + + const RemoteDeviceDescriptor valid1(validMsg1, address); + const RemoteDeviceDescriptor valid2(validMsg2, address); + + QVERIFY(valid1 == valid2); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteDeviceDescriptor) +#include "test_RemoteDeviceDescriptor.moc" diff --git a/test/qt/remote_device/test_RemoteDeviceListImpl.cpp b/test/qt/remote_device/test_RemoteDeviceListImpl.cpp new file mode 100644 index 0000000..4144bdb --- /dev/null +++ b/test/qt/remote_device/test_RemoteDeviceListImpl.cpp @@ -0,0 +1,68 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceList.h" + +#include "messages/Discovery.h" + +#include + + +using namespace governikus; + + +class test_RemoteDeviceListImpl + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void testAddAndRemove() + { + RemoteDeviceListImpl deviceList(10, 1); + QSignalSpy spyVanished(&deviceList, &RemoteDeviceListImpl::fireDeviceVanished); + + QSharedPointer offerMsg1; + QHostAddress addr1; + { + offerMsg1 = QSharedPointer(new Discovery("Dev1", QStringLiteral("0123456789ABCDEF"), 1234, {QStringLiteral("IFDInterface_WebSocket_v0")})); + addr1 = QHostAddress(QString("5.6.7.8")); + const RemoteDeviceDescriptor descr(offerMsg1, addr1); + + QSignalSpy spy(&deviceList, &RemoteDeviceListImpl::fireDeviceAppeared); + deviceList.update(descr); + QCOMPARE(spy.count(), 1); + } + + QSharedPointer offerMsg2; + QHostAddress addr2; + { + offerMsg2 = QSharedPointer(new Discovery("Dev1", QStringLiteral("0123456789ABCDEF"), 1234, {QStringLiteral("IFDInterface_WebSocket_v0")})); + addr2 = QHostAddress(QString("5.6.7.8")); + const RemoteDeviceDescriptor descr(offerMsg1, addr2); + + QSignalSpy spy(&deviceList, &RemoteDeviceListImpl::fireDeviceAppeared); + deviceList.update(descr); + QCOMPARE(spy.count(), 0); + } + + { + offerMsg2 = QSharedPointer(new Discovery("Dev1", QStringLiteral("0123456789ABCDEF"), 1234, {QStringLiteral("IFDInterface_WebSocket_v0")})); + addr2 = QHostAddress(QString("5.6.7.9")); + const RemoteDeviceDescriptor descr(offerMsg1, addr2); + + QSignalSpy spy(&deviceList, &RemoteDeviceListImpl::fireDeviceAppeared); + deviceList.update(descr); + QCOMPARE(spy.count(), 1); + } + + spyVanished.wait(); + QCOMPARE(spyVanished.count(), 2); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteDeviceListImpl) +#include "test_RemoteDeviceListImpl.moc" diff --git a/test/qt/remote_device/test_RemoteDispImpl.cpp b/test/qt/remote_device/test_RemoteDispImpl.cpp new file mode 100644 index 0000000..ba6670f --- /dev/null +++ b/test/qt/remote_device/test_RemoteDispImpl.cpp @@ -0,0 +1,275 @@ +/*! + * \brief Unit tests for \ref RemoteDispatcher + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDispatcherImpl.h" + +#include "messages/IfdConnect.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/IfdTransmit.h" +#include "MockDataChannel.h" +#include "RemoteMessageChecker.h" + +#include +#include + + +using namespace governikus; + + +class RemoteDispatcherSpy + : public QObject +{ + Q_OBJECT + + private: + const QSharedPointer mRemoteDispatcher; + bool mClosed; + GlobalStatus::Code mCloseCode; + QVector > mReceivedMessages; + QVector > mReceivedSignalSenders; + + public: + RemoteDispatcherSpy(const QSharedPointer pRemoteDispatcher); + virtual ~RemoteDispatcherSpy(); + + bool isClosed() const; + GlobalStatus::Code getCloseCode() const; + const QVector >& getReceivedMessages() const; + const QVector >& getReceivedSignalSenders() const; + + private Q_SLOTS: + void onClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pDispatcher); + void onReceived(const QSharedPointer& pMessage, const QSharedPointer& pDispatcher); +}; + + +RemoteDispatcherSpy::RemoteDispatcherSpy(const QSharedPointer pRemoteDispatcher) + : mRemoteDispatcher(pRemoteDispatcher) + , mClosed(false) + , mCloseCode(GlobalStatus::Code::RemoteReader_CloseCode_Undefined) +{ + connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteDispatcherSpy::onClosed); + connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteDispatcherSpy::onReceived); +} + + +RemoteDispatcherSpy::~RemoteDispatcherSpy() +{ + disconnect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteDispatcherSpy::onClosed); + disconnect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteDispatcherSpy::onReceived); +} + + +bool RemoteDispatcherSpy::isClosed() const +{ + return mClosed; +} + + +GlobalStatus::Code RemoteDispatcherSpy::getCloseCode() const +{ + return mCloseCode; +} + + +const QVector >& RemoteDispatcherSpy::getReceivedMessages() const +{ + return mReceivedMessages; +} + + +const QVector >& RemoteDispatcherSpy::getReceivedSignalSenders() const +{ + return mReceivedSignalSenders; +} + + +void RemoteDispatcherSpy::onClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pDispatcher) +{ + mClosed = true; + mCloseCode = pCloseCode; + mReceivedSignalSenders += pDispatcher; +} + + +void RemoteDispatcherSpy::onReceived(const QSharedPointer& pMessage, const QSharedPointer& pDispatcher) +{ + qDebug() << "RemoteDispatcherSpy::onReceived() -" << pMessage->getType(); + mReceivedMessages += pMessage; + mReceivedSignalSenders += pDispatcher; +} + + +class test_RemoteDisp + : public QObject +{ + Q_OBJECT + + private: + RemoteMessageChecker mChecker; + + private Q_SLOTS: + void channelClosedNormally() + { + const QSharedPointer channel(new MockDataChannel()); + const QSharedPointer dispatcher(new RemoteDispatcherImpl(channel)); + RemoteDispatcherSpy spy(dispatcher); + + channel->close(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); + + const QVector >& senders = spy.getReceivedSignalSenders(); + QCOMPARE(senders.size(), 1); + QCOMPARE(senders.first().data(), dispatcher.data()); + } + + + void channelClosedAbnormally() + { + const QSharedPointer channel(new MockDataChannel()); + const QSharedPointer dispatcher(new RemoteDispatcherImpl(channel)); + RemoteDispatcherSpy spy(dispatcher); + + channel->closeAbnormal(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); + + const QVector >& senders = spy.getReceivedSignalSenders(); + QCOMPARE(senders.size(), 1); + QCOMPARE(senders.first().data(), dispatcher.data()); + } + + + void messagesAreDelivered() + { + const QSharedPointer clientChannel(new MockDataChannel()); + const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + + RemoteDispatcherSpy spy(serverDispatcher); + + clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); + clientDispatcher->send(QSharedPointer(new IfdConnect(QStringLiteral("NFC Reader")))); + clientDispatcher->send(QSharedPointer(new IfdTransmit(QStringLiteral("NFC Reader"), QByteArray::fromHex("00A402022F00")))); + clientDispatcher->send(QSharedPointer(new IfdDisconnect(QStringLiteral("NFC Reader")))); + + const QVector > receivedMessages = spy.getReceivedMessages(); + QCOMPARE(receivedMessages.size(), 3); + QCOMPARE(receivedMessages.at(0)->getType(), RemoteCardMessageType::IFDConnect); + mChecker.receive(receivedMessages.at(0)); + + QCOMPARE(receivedMessages.at(1)->getType(), RemoteCardMessageType::IFDTransmit); + mChecker.receive(receivedMessages.at(1)); + + QCOMPARE(receivedMessages.at(2)->getType(), RemoteCardMessageType::IFDDisconnect); + mChecker.receive(receivedMessages.at(2)); + + const QVector >& senders = spy.getReceivedSignalSenders(); + QCOMPARE(senders.size(), 3); + QCOMPARE(senders.at(0).data(), serverDispatcher.data()); + QCOMPARE(senders.at(1).data(), serverDispatcher.data()); + QCOMPARE(senders.at(2).data(), serverDispatcher.data()); + } + + + void channelIsClosedWhenRemoteDispatcherIsDestroyed() + { + const QSharedPointer clientChannel(new MockDataChannel()); + QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + connect(clientChannel.data(), &DataChannel::fireClosed, serverChannel.data(), &DataChannel::close, Qt::DirectConnection); + + RemoteDispatcherSpy spy(serverDispatcher); + QVERIFY(!spy.isClosed()); + // Destroying a remote dispatcher should close the underlying channel. + clientDispatcher.reset(); + QVERIFY(spy.isClosed()); + QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); + + const QVector >& senders = spy.getReceivedSignalSenders(); + QCOMPARE(senders.size(), 1); + QCOMPARE(senders.at(0).data(), serverDispatcher.data()); + } + + + void repeatedIfdEstablishContextGenerateCorrectErrorMessage() + { + const QSharedPointer clientChannel(new MockDataChannel()); + const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + + clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); + clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); + + const QVector& clientReceivedDataBlocks = clientChannel->getReceivedDataBlocks(); + QCOMPARE(clientReceivedDataBlocks.size(), 2); + const QSharedPointer message1 = RemoteMessageParser().parse(clientReceivedDataBlocks.at(0)).dynamicCast(); + QVERIFY(!message1.isNull()); + QCOMPARE(message1->getType(), RemoteCardMessageType::IFDEstablishContextResponse); + QCOMPARE(message1->resultHasError(), false); + QCOMPARE(message1->getResultMinor(), QString()); + + const QSharedPointer message2 = RemoteMessageParser().parse(clientReceivedDataBlocks.at(1)).dynamicCast(); + QVERIFY(!message2.isNull()); + QCOMPARE(message2->getType(), RemoteCardMessageType::IFDEstablishContextResponse); + QCOMPARE(message2->resultHasError(), true); + QCOMPARE(message2->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError")); + } + + + void ifdEstablishContextWithWrongProtocolGeneratesCorrectErrorMessage() + { + const QSharedPointer clientChannel(new MockDataChannel()); + const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); + + const QSharedPointer serverChannel(new MockDataChannel()); + const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); + + connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); + + clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v2"), DeviceInfo::getName()))); + + const QVector& clientReceivedDataBlocks = clientChannel->getReceivedDataBlocks(); + QCOMPARE(clientReceivedDataBlocks.size(), 1); + const QSharedPointer message = RemoteMessageParser().parse(clientReceivedDataBlocks.at(0)); + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDEstablishContextResponse); + const QSharedPointer ifdEstablishContextResponse = message.dynamicCast(); + QVERIFY(!ifdEstablishContextResponse.isNull()); + QCOMPARE(ifdEstablishContextResponse->resultHasError(), true); + QCOMPARE(ifdEstablishContextResponse->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError")); + } + + + public: + test_RemoteDisp() + : mChecker() + { + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteDisp) +#include "test_RemoteDispImpl.moc" diff --git a/test/qt/remote_device/test_RemoteHelper.cpp b/test/qt/remote_device/test_RemoteHelper.cpp new file mode 100644 index 0000000..a9ce4b1 --- /dev/null +++ b/test/qt/remote_device/test_RemoteHelper.cpp @@ -0,0 +1,48 @@ +/*! + * \brief Unit tests for \ref RemoteHelper + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppSettings.h" +#include "RemoteHelper.h" +#include "RemoteServiceSettings.h" + +#include + +using namespace governikus; + +class test_RemoteHelper + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void testCheckAndGenerateKey() + { + auto& settings = AppSettings::getInstance().getRemoteServiceSettings(); + QCOMPARE(settings.getKey(), QSslKey()); + QCOMPARE(settings.getCertificate(), QSslCertificate()); + + QVERIFY(RemoteHelper::checkAndGenerateKey()); + const auto& key = settings.getKey(); + const auto& cert = settings.getCertificate(); + QVERIFY(!key.isNull()); + QVERIFY(!cert.isNull()); + + QVERIFY(RemoteHelper::checkAndGenerateKey()); + QCOMPARE(settings.getKey(), key); + QCOMPARE(settings.getCertificate(), cert); + + QCOMPARE(settings.getCertificate().effectiveDate(), QDateTime::fromString(QStringLiteral("1970-01-01T00:00:00Z"), Qt::ISODate)); + QCOMPARE(settings.getCertificate().expiryDate(), QDateTime::fromString(QStringLiteral("9999-12-31T23:59:59Z"), Qt::ISODate)); + QVERIFY(settings.getCertificate().effectiveDate().isValid()); + QVERIFY(settings.getCertificate().expiryDate().isValid()); + } + + +}; + + +QTEST_GUILESS_MAIN(test_RemoteHelper) +#include "test_RemoteHelper.moc" diff --git a/test/qt/remote_device/test_RemoteMessageParser.cpp b/test/qt/remote_device/test_RemoteMessageParser.cpp new file mode 100644 index 0000000..ca5493c --- /dev/null +++ b/test/qt/remote_device/test_RemoteMessageParser.cpp @@ -0,0 +1,609 @@ +/*! + * \brief Unit tests for \ref RemoteMessageParser + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "messages/RemoteMessageParser.h" + +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmitResponse.h" +#include "messages/RemoteMessage.h" +#include "RemoteMessageChecker.h" + +#include +#include + + +using namespace governikus; + + +class test_RemoteMessageParser + : public QObject +{ + Q_OBJECT + + private: + const RemoteMessageParser mParser; + + RemoteMessageChecker mChecker; + + void parseAndVerify(const char* pJsonByteData, bool isValid = true) + { + const QByteArray jsonData(pJsonByteData); + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + mChecker.receive(message); + QCOMPARE(message->isValid(), isValid); + } + + + private Q_SLOTS: + void invalidJsonInput() + { + const QByteArray jsonData("bla bla"); + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(message.isNull()); + } + + + void discovery() + { + const QByteArray jsonData("{\n" + " \"IFDName\": \"Sony Xperia Z5 compact\",\n" + " \"IFDID\": \"0123456789ABCDEF\",\n" + " \"msg\": \"REMOTE_IFD\",\n" + " \"port\": 24728,\n" + " \"SupportedAPI\": [\"IFDInterface_WebSocket_v0\", \"IFDInterface_WebSocket_v2\"]\n" + "}"); + + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(jsonData, &error); + QVERIFY(error.error == QJsonParseError::NoError); + + const QSharedPointer message = mParser.parseDiscovery(doc); + + QVERIFY(!message.isNull()); + mChecker.processDiscovery(message); + } + + + void discovery_with_missing_msg_field() + { + const QByteArray jsonData("{\n" + " \"IFDName\": \"Sony Xperia Z5 compact\",\n" + " \"IFDID\": \"0123456789ABCDEF\",\n" + " \"port\": 24728,\n" + " \"SupportedAPI\": [\"IFDInterface_WebSocket_v0\", \"IFDInterface_WebSocket_v2\"]\n" + "}"); + + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(jsonData, &error); + QVERIFY(error.error == QJsonParseError::NoError); + + const QSharedPointer message = mParser.parseDiscovery(doc); + + QVERIFY(message.isNull()); + } + + + void discovery_with_invalid_msg_field() + { + const QByteArray jsonData("{\n" + " \"IFDName\": \"Sony Xperia Z5 compact\",\n" + " \"IFDID\": \"0123456789ABCDEF\",\n" + " \"msg\": \"REMOTE\",\n" + " \"port\": 24728,\n" + " \"SupportedAPI\": [\"IFDInterface_WebSocket_v0\", \"IFDInterface_WebSocket_v2\"]\n" + "}"); + + QJsonParseError error; + const QJsonDocument& doc = QJsonDocument::fromJson(jsonData, &error); + QVERIFY(error.error == QJsonParseError::NoError); + + const QSharedPointer message = mParser.parseDiscovery(doc); + + QVERIFY(message.isNull()); + } + + + void ifdEstablishContext() + { + parseAndVerify("{\n" + " \"msg\": \"IFDEstablishContext\",\n" + " \"Protocol\": \"IFDInterface_WebSocket_v0\",\n" + " \"UDName\": \"MAC-MINI\"\n" + "}"); + } + + + void ifdEstablishContextResponse() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"IFDName\": \"IFD Remote Server\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDEstablishContextResponse\"\n" + "}"); + } + + + void getIfdStatus() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDGetStatus\",\n" + " \"SlotName\": \"Remote Reader\"\n" + "}"); + } + + + void ifdStatus() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDStatus\",\n" + " \"ConnectedReader\": true,\n" + " \"IFDName\": \"Remote Reader\",\n" + " \"SlotName\": \"NFC Reader\",\n" + " \"PINCapabilities\": {\n" + " \"Destroy\": false,\n" + " \"PACE\": false,\n" + " \"eID\": false,\n" + " \"eSign\": false\n" + " },\n" + " \"MaxAPDULength\": 500,\n" + " \"CardAvailable\": false\n" + "}"); + } + + + void ifdConnect() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"exclusive\": true,\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}"); + } + + + void ifdConnectWrongContextHandleType() + { + parseAndVerify("{\n" + " \"ContextHandle\": true,\n" + " \"exclusive\": true,\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}", false); + } + + + void ifdConnectMissingContextHandle() + { + parseAndVerify("{\n" + " \"exclusive\": true,\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}", false); + } + + + void ifdConnectWrongExclusvieType() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"exclusive\": \"test\",\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}", false); + } + + + void ifdConnectMissingExclusvie() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDConnect\",\n" + " \"SlotName\": \"NFC Reader\"\n" + "}", false); + } + + + void ifdConnectResponse() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n"); + } + + + void ifdConnectResponseWrongContextHandleType() + { + parseAndVerify("{\n" + " \"ContextHandle\": true,\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n", false); + } + + + void ifdConnectResponseMissingContextHandle() + { + parseAndVerify("{\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n", false); + } + + + void ifdConnectResponseMsg_nullError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"ResultMajor\": null,\n" + " \"ResultMinor\": \"Error message\",\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDConnectResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), true); + QCOMPARE(msg->getResultMinor(), QStringLiteral("Error message")); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QVERIFY(!msg->isValid()); + } + + + void ifdConnectResponseMsg_noError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDConnectResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), false); + QCOMPARE(msg->getResultMinor(), QString()); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QVERIFY(msg->isValid()); + } + + + void ifdDisconnect() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDDisconnect\",\n" + " \"readerName\": \"NFC Reader\"\n" + "}"); + } + + + void ifdDisconnectResponse() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDDisconnectResponse\"\n" + "}\n"); + } + + + void ifdDisconnectResponse_nullError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResultMajor\": null,\n" + " \"ResultMinor\": \"Error message\",\n" + " \"msg\": \"IFDDisconnectResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDDisconnectResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), true); + QCOMPARE(msg->getResultMinor(), QStringLiteral("Error message")); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QVERIFY(!msg->isValid()); + } + + + void ifdDisconnectResponse_noError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDDisconnectResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDDisconnectResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), false); + QCOMPARE(msg->getResultMinor(), QString()); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + } + + + void ifdTransmit() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"msg\": \"IFDTransmit\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"CommandAPDUs\": [\n" + " {\n" + " \"InputAPDU\": \"00A402022F00\",\n" + " \"AcceptableStatusCodes\": null\n" + " }\n" + " ]\n" + "}"); + } + + + void ifdTransmitWrongContextHandleType() + { + parseAndVerify("{\n" + " \"ContextHandle\": true,\n" + " \"msg\": \"IFDTransmit\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"CommandAPDUs\": [\n" + " {\n" + " \"InputAPDU\": \"00A402022F00\",\n" + " \"AcceptableStatusCodes\": null\n" + " }\n" + " ]\n" + "}", false); + } + + + void ifdTransmitMissingContextHandle() + { + parseAndVerify("{\n" + " \"msg\": \"IFDTransmit\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"CommandAPDUs\": [\n" + " {\n" + " \"InputAPDU\": \"00A402022F00\",\n" + " \"AcceptableStatusCodes\": null\n" + " }\n" + " ]\n" + "}", false); + } + + + void transmitResponseMsg() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResponseAPDUs\": [\n" + " \"9000\"\n" + " ],\n" + " \"msg\": \"IFDTransmitResponse\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\"\n" + "}"); + } + + + void transmitResponseMsg_nullError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResponseAPDUs\": [\n" + " \"9000\"\n" + " ],\n" + " \"ResultMajor\": null,\n" + " \"ResultMinor\": \"Error message\",\n" + " \"msg\": \"IFDTransmitResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDTransmitResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), true); + QCOMPARE(msg->getResultMinor(), QStringLiteral("Error message")); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(msg->getResponseApdu(), QByteArray::fromHex("9000")); + QVERIFY(!msg->isValid()); + } + + + void transmitResponseMsg_noError() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResponseAPDUs\": [\n" + " \"9000\"\n" + " ],\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"msg\": \"IFDTransmitResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QVERIFY(message->isValid()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDTransmitResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), false); + QCOMPARE(msg->getResultMinor(), QString()); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(msg->getResponseApdu(), QByteArray::fromHex("9000")); + QVERIFY(msg->isValid()); + } + + + void transmitResponseMsg_noResponseApdu() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResultMajor\": \"/resultmajor#error\",\n" + " \"ResultMinor\": \"Error message\",\n" + " \"msg\": \"IFDTransmitResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QVERIFY(!message->isValid()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDTransmitResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), true); + QCOMPARE(msg->getResultMinor(), QStringLiteral("Error message")); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(msg->getResponseApdu(), QByteArray()); + QVERIFY(!msg->isValid()); + } + + + void transmitResponseMsg_nullResponseApdu() + { + QByteArray jsonData("{\n" + " \"ContextHandle\": \"contextHandle\",\n" + " \"ResponseAPDUs\": null,\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResultMajor\": \"/resultmajor#error\",\n" + " \"ResultMinor\": \"Error message\",\n" + " \"msg\": \"IFDTransmitResponse\"\n" + "}\n"); + + const QSharedPointer message = mParser.parse(jsonData); + + QVERIFY(!message.isNull()); + QCOMPARE(message->getType(), RemoteCardMessageType::IFDTransmitResponse); + const auto& msg = message.staticCast(); + QCOMPARE(msg->resultHasError(), true); + QCOMPARE(msg->getResultMinor(), QStringLiteral("Error message")); + QCOMPARE(msg->getSlotHandle(), QStringLiteral("NFC Reader")); + QCOMPARE(msg->getResponseApdu(), QByteArray()); + QVERIFY(!msg->isValid()); + } + + + void ifdEstablishPaceChannelMsg() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"InputData\": \"abcd1234\",\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannel\"\n" + "}\n"); + } + + + void ifdEstablishPaceChannelMessageResponse() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}\n"); + } + + + void ifdEstablishPaceChannelMessageResponseWithError() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"/resultmajor#error\",\n" + " \"ResultMinor\": \"/resultminor/ifdl/common#timeoutError\",\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}"); + } + + + void ifdEstablishPaceChannelMessageResponseWithErrorMissingMinor() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"/resultmajor#error\",\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}", false); + + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"/resultmajor#error\",\n" + " \"ResultMinor\": null,\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}\n", false); + } + + + void ifdError() + { + parseAndVerify("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDError\"\n" + "}\n"); + } + + + public: + test_RemoteMessageParser() + : mParser() + , mChecker() + { + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteMessageParser) +#include "test_RemoteMessageParser.moc" diff --git a/test/qt/remote_device/test_RemoteMessages.cpp b/test/qt/remote_device/test_RemoteMessages.cpp new file mode 100644 index 0000000..c40ddaf --- /dev/null +++ b/test/qt/remote_device/test_RemoteMessages.cpp @@ -0,0 +1,506 @@ +/*! + * \brief Unit tests for \ref RemoteMessages + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "messages/Discovery.h" +#include "messages/GetIfdStatus.h" +#include "messages/IfdConnect.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdDisconnect.h" +#include "messages/IfdDisconnectResponse.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/IfdEstablishPaceChannel.h" +#include "messages/IfdEstablishPaceChannelResponse.h" +#include "messages/IfdStatus.h" +#include "messages/IfdTransmit.h" +#include "messages/IfdTransmitResponse.h" + +#include "MockIfdStatus.h" +#include "RemoteMessageChecker.h" +#include "TestFileHelper.h" + +#include +#include + + +using namespace governikus; + + +Q_DECLARE_METATYPE(QSharedPointer ) + + +class test_RemoteMessages + : public QObject +{ + Q_OBJECT + + private: + RemoteMessageChecker mChecker; + + private Q_SLOTS: + void discovery() + { + const QSharedPointer message( + new Discovery(QStringLiteral("Sony Xperia Z5 compact"), + QStringLiteral("0123456789ABCDEF"), + 24728, + {QStringLiteral("IFDInterface_WebSocket_v0"), QStringLiteral("IFDInterface_WebSocket_v2")}) + ); + + mChecker.processDiscovery(message); + + const QJsonDocument document = message->toJson(); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("IFDName")).toString(), QStringLiteral("Sony Xperia Z5 compact")); + QCOMPARE(object.value(QLatin1String("IFDID")).toString(), QStringLiteral("0123456789ABCDEF")); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("REMOTE_IFD")); + QCOMPARE(object.value(QLatin1String("port")).toInt(), 24728); + const QJsonValue apiLevels = object.value(QLatin1String("SupportedAPI")); + QVERIFY(apiLevels.isArray()); + QCOMPARE(apiLevels.toArray().size(), 2); + QCOMPARE(apiLevels.toArray().at(0).toString(), QStringLiteral("IFDInterface_WebSocket_v0")); + QCOMPARE(apiLevels.toArray().at(1).toString(), QStringLiteral("IFDInterface_WebSocket_v2")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"IFDID\": \"0123456789ABCDEF\",\n" + " \"IFDName\": \"Sony Xperia Z5 compact\",\n" + " \"SupportedAPI\": [\n" + " \"IFDInterface_WebSocket_v0\",\n" + " \"IFDInterface_WebSocket_v2\"\n" + " ],\n" + " \"msg\": \"REMOTE_IFD\",\n" + " \"port\": 24728\n" + "}\n")); + } + + + void ifdEstablishContext() + { + const QSharedPointer message(new IfdEstablishContext("IFDInterface_WebSocket_v0", "MAC-MINI")); + + mChecker.receive(message); + + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDEstablishContext")); + QCOMPARE(object.value(QLatin1String("Protocol")).toString(), QStringLiteral("IFDInterface_WebSocket_v0")); + QCOMPARE(object.value(QLatin1String("UDName")).toString(), QStringLiteral("MAC-MINI")); + + QByteArray jsonToCompare = + QByteArray("{\n" + " \"Protocol\": \"IFDInterface_WebSocket_v0\",\n" + " \"UDName\": \"MAC-MINI\",\n" + " \"msg\": \"IFDEstablishContext\"\n}" + "\n"); + + QCOMPARE(document.toJson(), jsonToCompare); + } + + + void ifdEstablishContextResponse() + { + const QSharedPointer message(new IfdEstablishContextResponse(QStringLiteral("IFD Reader"), QStringLiteral("/minorResult"))); + + mChecker.receive(message); + + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDEstablishContextResponse")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("IFDName")).toString(), QStringLiteral("IFD Reader")); + QCOMPARE(object.value(QLatin1String("ResultMajor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error")); + QCOMPARE(object.value(QLatin1String("ResultMinor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"IFDName\": \"IFD Reader\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDEstablishContextResponse\"\n" + "}\n")); + } + + + void paceCapabilities_data() + { + QTest::addColumn("pace"); + QTest::addColumn("eid"); + QTest::addColumn("esign"); + QTest::addColumn("destroy"); + + QTest::newRow("false") << false << false << false << false; + QTest::newRow("true") << true << true << true << true; + } + + + void paceCapabilities() + { + QFETCH(bool, pace); + QFETCH(bool, eid); + QFETCH(bool, esign); + QFETCH(bool, destroy); + + PaceCapabilities capabilities(pace, eid, esign, destroy); + + QCOMPARE(capabilities.getPace(), pace); + QCOMPARE(capabilities.getEId(), eid); + QCOMPARE(capabilities.getESign(), esign); + QCOMPARE(capabilities.getDestroy(), destroy); + } + + + void getIfdStatus() + { + const QSharedPointer message(new GetIfdStatus("Remote Reader")); + + mChecker.receive(message); + + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDGetStatus")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotName")).toString(), QStringLiteral("Remote Reader")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"SlotName\": \"Remote Reader\",\n" + " \"msg\": \"IFDGetStatus\"\n" + "}\n")); + } + + + void ifdStatus() + { + const QSharedPointer message(new MockIfdStatus(QStringLiteral("NFC Reader"), + PaceCapabilities(), + 500, + true, + false)); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 9); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDStatus")); + QCOMPARE(object.value(QLatin1String("SlotName")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("ConnectedReader")).toBool(), true); + QCOMPARE(object.value(QLatin1String("MaxAPDULength")).toInt(), 500); + QCOMPARE(object.value(QLatin1String("CardAvailable")).toBool(), false); + + const QJsonValue pinCapVal = object.value(QLatin1String("PINCapabilities")); + QVERIFY(pinCapVal.isObject()); + const QJsonObject pinCapObject = pinCapVal.toObject(); + QCOMPARE(pinCapObject.size(), 4); + QCOMPARE(pinCapObject.value(QLatin1String("PACE")).toBool(), false); + QCOMPARE(pinCapObject.value(QLatin1String("eID")).toBool(), false); + QCOMPARE(pinCapObject.value(QLatin1String("eSign")).toBool(), false); + QCOMPARE(pinCapObject.value(QLatin1String("Destroy")).toBool(), false); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"CardAvailable\": false,\n" + " \"ConnectedReader\": true,\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"EFATR\": null,\n" + " \"EFDIR\": null,\n" + " \"MaxAPDULength\": 500,\n" + " \"PINCapabilities\": {\n" + " \"Destroy\": false,\n" + " \"PACE\": false,\n" + " \"eID\": false,\n" + " \"eSign\": false\n" + " },\n" + " \"SlotName\": \"NFC Reader\",\n" + " \"msg\": \"IFDStatus\"\n" + "}\n")); + } + + + void ifdConnect() + { + const QSharedPointer message(new IfdConnect(QStringLiteral("NFC Reader"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 4); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDConnect")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotName")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("exclusive")).toBool(), true); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"SlotName\": \"NFC Reader\",\n" + " \"exclusive\": true,\n" + " \"msg\": \"IFDConnect\"\n" + "}\n")); + } + + + void ifdConnectResponseMsg() + { + const QSharedPointer message(new IfdConnectResponse(QStringLiteral("NFC Reader"), QStringLiteral("/minorResult"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDConnectResponse")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("ResultMajor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error")); + QCOMPARE(object.value(QLatin1String("ResultMinor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDConnectResponse\"\n" + "}\n")); + } + + + void ifdDisconnectCmd() + { + const QSharedPointer message(new IfdDisconnect(QStringLiteral("NFC Reader"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDDisconnect")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDDisconnect\"\n" + "}\n")); + } + + + void ifdDisconnectResponseMsg() + { + const QSharedPointer message(new IfdDisconnectResponse(QStringLiteral("NFC Reader"), QStringLiteral("/minorResult"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDDisconnectResponse")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("ResultMajor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error")); + QCOMPARE(object.value(QLatin1String("ResultMinor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDDisconnectResponse\"\n" + "}\n")); + } + + + void ifdTransmitCmd() + { + const QSharedPointer message(new IfdTransmit(QStringLiteral("NFC Reader"), QByteArray::fromHex("00A402022F00"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 4); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDTransmit")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + QVERIFY(object.value(QLatin1String("CommandAPDUs")).isArray()); + const auto& commandApduValue = object.value(QLatin1String("CommandAPDUs")).toArray().at(0); + QVERIFY(commandApduValue.isObject()); + const auto& commandApdu = commandApduValue.toObject(); + QCOMPARE(commandApdu.value(QLatin1String("InputAPDU")).toString().toUpper(), QStringLiteral("00A402022F00")); + QVERIFY(commandApdu.value(QLatin1String("AcceptableStatusCodes")).isNull()); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"CommandAPDUs\": [\n" + " {\n" + " \"AcceptableStatusCodes\": null,\n" + " \"InputAPDU\": \"00a402022f00\"\n" + " }\n" + " ],\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDTransmit\"\n" + "}\n")); + } + + + void ifdTransmitResponseMsg() + { + const QSharedPointer message(new IfdTransmitResponse(QStringLiteral("NFC Reader"), + QByteArray::fromHex("9000"), + QStringLiteral("/minorResult"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 6); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDTransmitResponse")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("ResultMajor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error")); + QCOMPARE(object.value(QLatin1String("ResultMinor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + QVERIFY(object.value(QLatin1String("ResponseAPDUs")).isArray()); + QCOMPARE(object.value(QLatin1String("ResponseAPDUs")).toArray().at(0).toString().toUpper(), QStringLiteral("9000")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"ResponseAPDUs\": [\n" + " \"9000\"\n" + " ],\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDTransmitResponse\"\n" + "}\n")); + } + + + void ifdEstablishPaceChannelMessage() + { + const QSharedPointer message(new IfdEstablishPaceChannel( + QStringLiteral("My little Reader"), + QByteArray::fromHex("ABCD1234"))); + + mChecker.receive(message); + + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"InputData\": \"abcd1234\",\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannel\"\n" + "}\n")); + } + + + void ifdEstablishPaceChannelMessageResponse() + { + const QSharedPointer message(new IfdEstablishPaceChannelResponse( + QStringLiteral("My little Reader"), + QByteArray::fromHex("ABCD1234"))); + + mChecker.receive(message); + + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}\n")); + } + + + void ifdErrorMsg() + { + const QSharedPointer message(new IfdError(QStringLiteral("NFC Reader"), QStringLiteral("/minorResult"))); + + mChecker.receive(message); + + // Json + const QJsonDocument document = message->toJson(QStringLiteral("TestContext")); + QVERIFY(document.isObject()); + + const QJsonObject object = document.object(); + QCOMPARE(object.size(), 5); + QCOMPARE(object.value(QLatin1String("msg")).toString(), QStringLiteral("IFDError")); + QCOMPARE(object.value(QLatin1String("ContextHandle")).toString(), QStringLiteral("TestContext")); + QCOMPARE(object.value(QLatin1String("SlotHandle")).toString(), QStringLiteral("NFC Reader")); + QCOMPARE(object.value(QLatin1String("ResultMajor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error")); + QCOMPARE(object.value(QLatin1String("ResultMinor")).toString(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult")); + + QCOMPARE(document.toJson(), + QByteArray("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"msg\": \"IFDError\"\n" + "}\n")); + } + + + public: + test_RemoteMessages() + : mChecker() + { + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteMessages) +#include "test_RemoteMessages.moc" diff --git a/test/qt/remote_device/test_RemoteReaderAdvertiser.cpp b/test/qt/remote_device/test_RemoteReaderAdvertiser.cpp new file mode 100644 index 0000000..ade00ca --- /dev/null +++ b/test/qt/remote_device/test_RemoteReaderAdvertiser.cpp @@ -0,0 +1,116 @@ +/*! + * \brief Unit tests for \ref RemoteReaderAdvertiserImpl + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteReaderAdvertiser.h" + +#include "DatagramHandler.h" +#include "Env.h" +#include "messages/Discovery.h" +#include "messages/RemoteMessageParser.h" + +#include +#include + + +using namespace governikus; + + +class DatagramHandlerMock + : public DatagramHandler +{ + Q_OBJECT + + public: + virtual bool isBound() const override; + + virtual bool send(const QJsonDocument& pData) override + { + Q_EMIT fireSend(pData); + return true; + } + + + Q_SIGNALS: + void fireSend(const QJsonDocument& pData); +}; + + +bool DatagramHandlerMock::isBound() const +{ + return true; +} + + +class test_RemoteReaderAdvertiser + : public QObject +{ + Q_OBJECT + + QPointer mMock; + + private Q_SLOTS: + void init() + { + mMock = new DatagramHandlerMock; + std::function creator = [this](bool){ + return mMock.data(); + }; + Env::setCreator(creator); + } + + + void cleanup() + { + QVERIFY(mMock == nullptr); + } + + + void advertisePeriodically() + { + const QString ifdName("ServerName"); + const QString ifdId("0123456789ABCDEF"); + quint16 port = 12345; + int pTimerInterval = 100; + + QSignalSpy spy(mMock.data(), &DatagramHandlerMock::fireSend); + QScopedPointer advertiser(Env::create(ifdName, ifdId, port, pTimerInterval)); + spy.wait(); + spy.wait(); + spy.wait(); + spy.wait(); + spy.wait(); + + QCOMPARE(spy.count(), 5); + } + + + void checkBroadcast() + { + const QString ifdName("ServerName"); + const QString ifdId("0123456789ABCDEF"); + quint16 port = 12345; + int pTimerInterval = 100; + + QSignalSpy spy(mMock.data(), &DatagramHandlerMock::fireSend); + QScopedPointer advertiser(Env::create(ifdName, ifdId, port, pTimerInterval)); + spy.wait(); + advertiser.reset(); + + const auto& offerMsg = RemoteMessageParser().parseDiscovery(spy.at(0).at(0).toJsonDocument()); + + QCOMPARE(offerMsg->getIfdName(), ifdName); + QCOMPARE(offerMsg->getIfdId(), ifdId); + QCOMPARE(offerMsg->getPort(), port); + QCOMPARE(offerMsg->getSupportedApis(), {QStringLiteral("IFDInterface_WebSocket_v0")}); + } + + +}; + +Q_DECLARE_METATYPE(QHostAddress) + +QTEST_GUILESS_MAIN(test_RemoteReaderAdvertiser) +#include "test_RemoteReaderAdvertiser.moc" diff --git a/test/qt/remote_device/test_RemoteServer.cpp b/test/qt/remote_device/test_RemoteServer.cpp new file mode 100644 index 0000000..84c5258 --- /dev/null +++ b/test/qt/remote_device/test_RemoteServer.cpp @@ -0,0 +1,212 @@ +/*! + * \brief Unit tests for \ref RemoteServerImpl + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "Env.h" +#include "RemoteReaderAdvertiser.h" +#include "RemoteServer.h" +#include "RemoteWebSocketServer.h" + +#include +#include +#include + + +using namespace governikus; + +class RemoteWebSocketServerMock + : public RemoteWebSocketServer +{ + Q_OBJECT + + public: + QString mServerName; + bool mPairing; + bool mListening = false, mConnected = false; + QSharedPointer mEmptyHandler; + + bool isListening() const override + { + return mListening; + } + + + bool isConnected() const override + { + return mConnected; + } + + + void setConnected(bool pConnected) + { + if (mConnected != pConnected) + { + mConnected = pConnected; + Q_EMIT fireConnectedChanged(mConnected); + } + } + + + bool listen(const QString& pServerName) override + { + if (mListening) + { + return false; + } + mServerName = pServerName; + mListening = true; + return true; + } + + + void close() override + { + mListening = false; + mServerName = QString(); + mPairing = false; + } + + + QString getServerName() const override + { + return mServerName; + } + + + quint16 getServerPort() const override + { + return 1; + } + + + void setPairing(bool pEnabled = true) override + { + mPairing = pEnabled; + } + + + QSslCertificate getCurrentCertificate() const override + { + return QSslCertificate(); + } + + + const QSharedPointer& getMessageHandler() const override + { + return mEmptyHandler; + } + + +}; + + +class RemoteReaderAdvertiserMock + : public RemoteReaderAdvertiser +{ + Q_OBJECT + + public: + const QString mIfdName; + const QString mIfdId; + const quint16 mPort; + + RemoteReaderAdvertiserMock(const QString& pIfdName, const QString& pIfdId, quint16 pPort) + : RemoteReaderAdvertiser() + , mIfdName(pIfdName) + , mIfdId(pIfdId) + , mPort(pPort) + { + } + + + virtual ~RemoteReaderAdvertiserMock(); +}; + + +RemoteReaderAdvertiserMock::~RemoteReaderAdvertiserMock() +{ +} + + +class test_RemoteServer + : public QObject +{ + Q_OBJECT + + QPointer mAdvertiserMock; + QPointer mWebSocketMock; + QScopedPointer mServer; + + private Q_SLOTS: + void init() + { + std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort){ + mAdvertiserMock = new RemoteReaderAdvertiserMock(pIfdName, pIfdId, pPort); + return mAdvertiserMock; + }; + Env::setCreator(creator); + std::function creator2 = [this](){ + mWebSocketMock = new RemoteWebSocketServerMock; + return mWebSocketMock; + }; + Env::setCreator(creator2); + mServer.reset(new RemoteServerImpl()); + } + + + void startStop() + { + QVERIFY(!mAdvertiserMock); + QVERIFY(!mWebSocketMock->isListening()); + + QVERIFY(mServer->start(QStringLiteral("ServerName"))); + QVERIFY(mAdvertiserMock); + QVERIFY(mWebSocketMock->isListening()); + + mServer->stop(); + QVERIFY(!mAdvertiserMock); + QVERIFY(!mWebSocketMock->isListening()); + } + + + void serverName() + { + mServer->start(QStringLiteral("ServerName")); + QCOMPARE(mAdvertiserMock->mIfdName, QStringLiteral("ServerName")); + QCOMPARE(mWebSocketMock->mServerName, QStringLiteral("ServerName")); + } + + + void port() + { + mServer->start(QStringLiteral("ServerName")); + QCOMPARE(mAdvertiserMock->mPort, mWebSocketMock->getServerPort()); + } + + + void stopAdvertisingOnConnection() + { + mServer->start(QStringLiteral("ServerName")); + mWebSocketMock->setConnected(true); + + QVERIFY(!mAdvertiserMock); + } + + + void startAdvertisingOnConnectionClosed() + { + mServer->start(QStringLiteral("ServerName")); + mWebSocketMock->setConnected(true); + mWebSocketMock->setConnected(false); + + QVERIFY(mAdvertiserMock); + } + + +}; + + +QTEST_GUILESS_MAIN(test_RemoteServer) +#include "test_RemoteServer.moc" diff --git a/test/qt/remote_device/test_RemoteTlsServer.cpp b/test/qt/remote_device/test_RemoteTlsServer.cpp new file mode 100644 index 0000000..14e41fd --- /dev/null +++ b/test/qt/remote_device/test_RemoteTlsServer.cpp @@ -0,0 +1,262 @@ +/*! + * \brief Unit tests for \ref RemoteTlsServer + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteTlsServer.h" + +#include "AppSettings.h" +#include "Env.h" +#include "KeyPair.h" +#include "RemoteHelper.h" +#include "SecureStorage.h" + +#include +#include +#include + +#if defined(Q_CC_CLANG) && Q_CC_CLANG < 350 +QT_WARNING_DISABLE_CLANG("-Wshadow") // QTRY_COMPARE +#endif + +using namespace governikus; + +Q_DECLARE_METATYPE(SecureStorage::TlsSuite) + +class test_RemoteTlsServer + : public QObject +{ + Q_OBJECT + + private: + QByteArray psk; + const KeyPair pair = KeyPair::generate(); + + private Q_SLOTS: + void checkFailingConnectionOnDifferentMode_data() + { + QTest::addColumn("serverPairing"); + QTest::addColumn("clientConfig"); + + QTest::newRow("server in pairing mode") << true << SecureStorage::TlsSuite::DEFAULT; + QTest::newRow("client in pairing mode") << false << SecureStorage::TlsSuite::PSK; + } + + + void checkFailingConnectionOnDifferentMode() + { + QFETCH(bool, serverPairing); + QFETCH(SecureStorage::TlsSuite, clientConfig); + + auto& settings = AppSettings::getInstance().getRemoteServiceSettings(); + settings.setTrustedCertificates({pair.getCertificate()}); + RemoteTlsServer server; + server.setPairing(serverPairing); + server.listen(); + + auto config = SecureStorage::getInstance().getTlsConfigRemote(clientConfig).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + + QSslSocket client; + client.setSslConfiguration(config); + + qRegisterMetaType("QSslPreSharedKeyAuthenticator*"); + QSignalSpy clientPsk(&client, &QSslSocket::preSharedKeyAuthenticationRequired); + QSignalSpy clientEncrypted(&client, &QSslSocket::encrypted); + QSignalSpy clientErrors(&client, QOverload::of(&QAbstractSocket::error)); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + + QTRY_COMPARE(clientErrors.count(), 1); + QCOMPARE(clientErrors.takeFirst().at(0).value(), QAbstractSocket::SocketError::RemoteHostClosedError); + QCOMPARE(clientEncrypted.count(), 0); + QCOMPARE(clientPsk.count(), 0); + } + + + void requiredPskForPairing() + { + RemoteTlsServer server; + QCOMPARE(server.getCurrentCertificate(), QSslCertificate()); + connect(&server, &RemoteTlsServer::firePskChanged, this, [this](const QByteArray& pPsk){ + psk = pPsk; + }); + server.setPairing(); + server.listen(); + + auto config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + + bool pskSignalFired = false; + QSslSocket client; + client.setSslConfiguration(config); + connect(&client, QOverload&>::of(&QSslSocket::sslErrors), this, [&](const QList& pErrors){ + QList ignoreList; + for (const auto& error : pErrors) + { + if (error.error() == QSslError::SelfSignedCertificate || + error.error() == QSslError::HostNameMismatch) + { + ignoreList << error; + } + } + client.ignoreSslErrors(ignoreList); + }); + + connect(&client, &QSslSocket::preSharedKeyAuthenticationRequired, this, [&](QSslPreSharedKeyAuthenticator* pAuthenticator){ + pAuthenticator->setPreSharedKey(psk); + pskSignalFired = true; + }); + + QTcpSocket* remoteSocket = nullptr; + connect(&server, &RemoteTlsServer::newConnection, this, [&](QTcpSocket* pSocket){ + remoteSocket = pSocket; + }); + + QSignalSpy newConnection(&server, &RemoteTlsServer::newConnection); + QSignalSpy clientEncrypted(&client, &QSslSocket::encrypted); + + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + + QTRY_COMPARE(newConnection.count(), 1); + QVERIFY(pskSignalFired); + QTRY_COMPARE(clientEncrypted.count(), 1); + + QVERIFY(remoteSocket); + const QByteArray sendData("hello world"); + QSignalSpy spyRead(remoteSocket, &QIODevice::readyRead); + client.write(sendData); + QTRY_COMPARE(spyRead.count(), 1); + QCOMPARE(remoteSocket->readAll(), sendData); + QCOMPARE(server.getCurrentCertificate(), pair.getCertificate()); + } + + + void tryReconnectWithoutPairedDeviceAndReconnectedPaired() + { + auto& settings = AppSettings::getInstance().getRemoteServiceSettings(); + settings.setTrustedCertificates({}); + RemoteTlsServer server; + server.listen(); + QSignalSpy newConnection(&server, &RemoteTlsServer::newConnection); + + auto config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + + { + QSslSocket client; + client.setSslConfiguration(config); + client.ignoreSslErrors({QSslError::SelfSignedCertificate, QSslError::HostNameMismatch}); + + QSignalSpy clientFailed(&client, &QAbstractSocket::disconnected); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + QTRY_COMPARE(clientFailed.count(), 1); + QCOMPARE(newConnection.count(), 0); + } + + + QSslSocket clientPaired; + config.setCaCertificates({settings.getCertificate()}); + clientPaired.setSslConfiguration(config); + connect(&clientPaired, QOverload&>::of(&QSslSocket::sslErrors), this, [&](const QList& pErrors){ + QList ignoreList; + for (const auto& error : pErrors) + { + if (error.error() == QSslError::HostNameMismatch) + { + ignoreList << error; + } + } + clientPaired.ignoreSslErrors(ignoreList); + }); + settings.addTrustedCertificate(config.localCertificate()); + + QSignalSpy clientPairedEncrypted(&clientPaired, &QSslSocket::encrypted); + clientPaired.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + QTRY_COMPARE(newConnection.count(), 1); + QTRY_COMPARE(clientPairedEncrypted.count(), 1); + } + + + void pairDeviceAndReconnect() + { + auto& settings = AppSettings::getInstance().getRemoteServiceSettings(); + settings.setTrustedCertificates({}); + requiredPskForPairing(); + QVERIFY(RemoteHelper::checkAndGenerateKey()); + + RemoteTlsServer server; + server.listen(); + + auto config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + config.setCaCertificates({settings.getCertificate()}); + + QSslSocket client; + client.setSslConfiguration(config); + connect(&client, QOverload&>::of(&QSslSocket::sslErrors), this, [&](const QList& pErrors){ + QList ignoreList; + for (const auto& error : pErrors) + { + if (error.error() == QSslError::HostNameMismatch) + { + ignoreList << error; + } + } + client.ignoreSslErrors(ignoreList); + }); + + QSignalSpy clientEncrypted(&client, &QSslSocket::encrypted); + QSignalSpy newConnection(&server, &RemoteTlsServer::newConnection); + + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + QTRY_COMPARE(newConnection.count(), 1); + QTRY_COMPARE(clientEncrypted.count(), 1); + } + + + void setPairing() + { + RemoteTlsServer server; + QSignalSpy pskChanged(&server, &RemoteTlsServer::firePskChanged); + + server.setPairing(false); + QTRY_COMPARE(pskChanged.count(), 0); + + server.setPairing(); + QTRY_COMPARE(pskChanged.count(), 1); + + server.setPairing(); + QTRY_COMPARE(pskChanged.count(), 2); + + server.setPairing(false); + QTRY_COMPARE(pskChanged.count(), 3); + + server.setPairing(false); + QTRY_COMPARE(pskChanged.count(), 3); + } + + + void checkPskSize() + { + RemoteTlsServer server; + QSignalSpy pskChanged(&server, &RemoteTlsServer::firePskChanged); + for (int i = 0; i < 100; ++i) + { + server.setPairing(); + QTRY_COMPARE(pskChanged.count(), 1); + const auto& pin = pskChanged.takeFirst().at(0).toByteArray(); + QCOMPARE(pin.size(), 4); + } + } + + +}; + + +QTEST_GUILESS_MAIN(test_RemoteTlsServer) +#include "test_RemoteTlsServer.moc" diff --git a/test/qt/remote_device/test_RemoteWebSocketServer.cpp b/test/qt/remote_device/test_RemoteWebSocketServer.cpp new file mode 100644 index 0000000..6ef186a --- /dev/null +++ b/test/qt/remote_device/test_RemoteWebSocketServer.cpp @@ -0,0 +1,306 @@ +/*! + * \brief Unit tests for \ref RemoteWebSocketServer + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteWebSocketServer.h" + +#include "AppSettings.h" +#include "Env.h" +#include "KeyPair.h" +#include "NetworkManager.h" +#include "SecureStorage.h" +#include "ServerMessageHandler.h" + +#include +#include +#include + +#if defined(Q_CC_CLANG) && Q_CC_CLANG < 350 +QT_WARNING_DISABLE_CLANG("-Wshadow") // QTRY_COMPARE +#endif + +using namespace governikus; + + +class PskHandler + : public QObject +{ + Q_OBJECT + + public: + QByteArray mPsk; + QWebSocket* mWebSocket; + + PskHandler(QWebSocket* pWebSocket, RemoteWebSocketServer* pServer = nullptr) + : QObject() + , mPsk() + , mWebSocket(pWebSocket) + { + connect(pWebSocket, &QWebSocket::preSharedKeyAuthenticationRequired, this, &PskHandler::onPreSharedKeyAuthenticationRequired); + connect(pWebSocket, &QWebSocket::sslErrors, this, &PskHandler::onSslErrors); + + if (pServer) + { + connect(pServer, &RemoteWebSocketServer::firePskChanged, this, [this](const QByteArray& pPsk){ + mPsk = pPsk; + }); + } + } + + + private Q_SLOTS: + void onPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator* pAuthenticator) + { + qDebug() << "PSK requested on CLIENT:" << mPsk; + pAuthenticator->setPreSharedKey(mPsk); + } + + + void onSslErrors(const QList& pErrors) + { + QList allowedErrors = { + QSslError::HostNameMismatch + }; + + const auto& config = mWebSocket->sslConfiguration(); + const auto& pairingCiphers = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + if (pairingCiphers.contains(config.sessionCipher())) + { + allowedErrors << QSslError::SelfSignedCertificate; + } + + bool ignoreErrors = true; + for (const auto& error : pErrors) + { + if (!allowedErrors.contains(error.error())) + { + ignoreErrors = false; + break; + } + } + + if (ignoreErrors) + { + qDebug() << "Ignore TLS error:" << pErrors; + mWebSocket->ignoreSslErrors(); + return; + } + + qDebug() << "TLS error found:" << pErrors; + } + + +}; + + +class test_RemoteWebSocketServer + : public QObject +{ + Q_OBJECT + + private: + QScopedPointer mServer; + + private Q_SLOTS: + void initTestCase() + { + NetworkManager::setApplicationProxyFactory(); + } + + + void init() + { + mServer.reset(new RemoteWebSocketServerImpl); + } + + + void cleanup() + { + mServer.reset(); + } + + + void isListening() + { + QVERIFY(!mServer->isListening()); + + mServer->listen(QStringLiteral("TestServer")); + QVERIFY(mServer->isListening()); + + mServer->close(); + QVERIFY(!mServer->isListening()); + + mServer->listen(QStringLiteral("TestServer")); + QVERIFY(mServer->isListening()); + } + + + void listen() + { + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + } + + + void listenTwice() + { + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + QVERIFY(!mServer->listen(QStringLiteral("TestServer"))); + } + + + void getServerPort() + { + QVERIFY(mServer->getServerPort() == 0); + mServer->listen(QStringLiteral("TestServer")); + QVERIFY(mServer->getServerPort() != 0); + } + + + void getServerName() + { + mServer->listen(QStringLiteral("TestServer")); + QCOMPARE(mServer->getServerName(), QStringLiteral("TestServer")); + } + + + void pairingToListeningServer() + { + QCOMPARE(mServer->getCurrentCertificate(), QSslCertificate()); + KeyPair pair = KeyPair::generate(); + QWebSocket client; + auto config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + client.setSslConfiguration(config); + QSignalSpy spy(&client, &QWebSocket::connected); + + PskHandler pskHandler(&client, mServer.data()); + mServer->setPairing(); + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + + client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(client.state(), QAbstractSocket::SocketState::ConnectedState); + QCOMPARE(mServer->getCurrentCertificate(), client.sslConfiguration().localCertificate()); + } + + + void reconnectToListeningServer() + { + QCOMPARE(mServer->getCurrentCertificate(), QSslCertificate()); + KeyPair pair = KeyPair::generate(); + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setTrustedCertificates({pair.getCertificate()}); + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + + QWebSocket client; + auto config = SecureStorage::getInstance().getTlsConfigRemote().getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + config.setCaCertificates({settings.getCertificate()}); + client.setSslConfiguration(config); + QSignalSpy spy(&client, &QWebSocket::connected); + + PskHandler pskHandler(&client); + client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(client.state(), QAbstractSocket::SocketState::ConnectedState); + QCOMPARE(mServer->getCurrentCertificate(), client.sslConfiguration().localCertificate()); + } + + + void connectToClosedServer() + { + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + + QUrl serverUrl(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + mServer->close(); + + QWebSocket client; + + QSignalSpy spy(&client, &QWebSocket::connected); + client.open(serverUrl); + + spy.wait(500); + QCOMPARE(spy.count(), 0); + QVERIFY(client.state() != QAbstractSocket::SocketState::ConnectedState); + } + + + void onlyOneConnection() + { + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + + KeyPair pair = KeyPair::generate(); + auto config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + + QWebSocket client1, client2; + client1.setSslConfiguration(config); + client2.setSslConfiguration(config); + + PskHandler pskHandler1(&client1, mServer.data()); + PskHandler pskHandler2(&client2, mServer.data()); + mServer->setPairing(); + + QSignalSpy spy1(&client1, &QWebSocket::connected); + QSignalSpy spy2(&client2, &QWebSocket::disconnected); + + client1.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + QTRY_COMPARE(spy1.count(), 1); + + client2.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + QTRY_COMPARE(spy2.count(), 1); + + QCOMPARE(client1.state(), QAbstractSocket::SocketState::ConnectedState); + QCOMPARE(client2.state(), QAbstractSocket::SocketState::UnconnectedState); + } + + + void isConnected() + { +#if defined(Q_OS_FREEBSD) + QSKIP("Test not supported on this platform"); +#endif + + QVERIFY(!mServer->isConnected()); + QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + QVERIFY(!mServer->isConnected()); + + QSignalSpy serverConnectedSpy(mServer.data(), &RemoteWebSocketServer::fireConnectedChanged); + + KeyPair pair = KeyPair::generate(); + QWebSocket client; + auto config = SecureStorage::getInstance().getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration(); + config.setPrivateKey(pair.getKey()); + config.setLocalCertificate(pair.getCertificate()); + client.setSslConfiguration(config); + + PskHandler pskHandler(&client, mServer.data()); + mServer->setPairing(); + client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + + serverConnectedSpy.wait(); + QCOMPARE(serverConnectedSpy.count(), 1); + QVERIFY(serverConnectedSpy[0][0].toBool()); + QVERIFY(mServer->isConnected()); + + QSignalSpy serverDisconnectedSpy(mServer.data(), &RemoteWebSocketServer::fireConnectedChanged); + client.close(); + + QTRY_COMPARE(serverDisconnectedSpy.count(), 1); + QVERIFY(!serverDisconnectedSpy[0][0].toBool()); + QVERIFY(!mServer->isConnected()); + } + + +}; + + +QTEST_GUILESS_MAIN(test_RemoteWebSocketServer) +#include "test_RemoteWebSocketServer.moc" diff --git a/test/qt/remote_device/test_ServerMessageHandler.cpp b/test/qt/remote_device/test_ServerMessageHandler.cpp new file mode 100644 index 0000000..7d52f11 --- /dev/null +++ b/test/qt/remote_device/test_ServerMessageHandler.cpp @@ -0,0 +1,229 @@ +/*! + * \brief Unit tests for \ref test_ServerMessageHandlerImpl + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ServerMessageHandler.h" + +#include "LogHandler.h" +#include "messages/IfdConnectResponse.h" +#include "messages/IfdError.h" +#include "messages/IfdEstablishContext.h" +#include "messages/IfdEstablishContextResponse.h" +#include "messages/RemoteMessageParser.h" +#include "MockDataChannel.h" +#include "TestFileHelper.h" + +#include +#include + + +using namespace governikus; + + +class test_ServerMessageHandler + : public QObject +{ + Q_OBJECT + + private: + QSharedPointer mDataChannel; + const RemoteMessageParser mParser; + + QVector makeServerMessages(const QByteArray& pContextHandle) + { + QVector serverMessages; + + auto m = [&](const char* pJsonByteData) -> QByteArray + { + QByteArray result(pJsonByteData); + result.replace(QByteArray("contextHandleToReplace"), pContextHandle); + + return result; + }; + + serverMessages + << m("{\n" + " \"ContextHandle\": \"contextHandleToReplace\",\n" + " \"msg\": \"IFDStatus\",\n" + " \"ConnectedReader\": true,\n" + " \"IFDName\": \"Remote Reader\",\n" + " \"SlotName\": \"NFC Reader\",\n" + " \"PINCapabilities\": {\n" + " \"Destroy\": false,\n" + " \"PACE\": false,\n" + " \"eID\": false,\n" + " \"eSign\": false\n" + " },\n" + " \"MaxAPDULength\": 500,\n" + " \"CardAvailable\": false\n" + "}") + << + m("{\n" + " \"ContextHandle\": \"contextHandleToReplace\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDConnectResponse\",\n" + " \"SlotHandle\": \"NFC Reader\"\n" + "}\n") + << + m("{\n" + " \"ContextHandle\": \"contextHandleToReplace\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\",\n" + " \"msg\": \"IFDDisconnectResponse\"\n" + "}\n") + << + m("{\n" + " \"ContextHandle\": \"contextHandleToReplace\",\n" + " \"SlotHandle\": \"NFC Reader\",\n" + " \"ResponseAPDUs\": [\n" + " \"9000\"\n" + " ],\n" + " \"msg\": \"IFDTransmitResponse\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor/resultmajor#error\",\n" + " \"ResultMinor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultminor/minorResult\"\n" + "}") + << + m("{\n" + " \"ContextHandle\": \"contextHandleToReplace\",\n" + " \"OutputData\": \"abcd1234\",\n" + " \"ResultMajor\": \"http://www.bsi.bund.de/ecard/api/1.1/resultmajor/resultmajor#ok\",\n" + " \"ResultMinor\": null,\n" + " \"SlotHandle\": \"My little Reader\",\n" + " \"msg\": \"IFDEstablishPACEChannelResponse\"\n" + "}\n"); + + return serverMessages; + } + + + void waitForSignals(QSignalSpy* const pSpy, const int pExpectedCount, const int pTimeoutMs) + { + for (int tryCount = 0; pSpy->count() < pExpectedCount && tryCount < pExpectedCount; ++tryCount) + { + pSpy->wait(pTimeoutMs); + } + QCOMPARE(pSpy->count(), pExpectedCount); + } + + + private Q_SLOTS: + void initTestCase() + { + LogHandler::getInstance().init(); + + } + + + void init() + { + mDataChannel.reset(new MockDataChannel()); + } + + + void cleanup() + { + LogHandler::getInstance().resetBacklog(); + } + + + void checkLogOnInvalidContext() + { + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + IfdConnectResponse unexpectedMsg(QStringLiteral("RemoteReader")); + + mDataChannel->onReceived(unexpectedMsg.toJson(QStringLiteral("invalidConextHandle")).toJson()); + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("Invalid context handle received"))); + } + + + void checkLogOnUnexpectedMessageWithContext() + { + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + QSignalSpy spyContextHandle(mDataChannel.data(), &MockDataChannel::fireSend); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + + IfdEstablishContext establishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()); + mDataChannel->onReceived(establishContext.toJson(QString()).toJson()); + + const QJsonDocument& doc = QJsonDocument::fromJson(spyContextHandle.at(0).at(0).toByteArray()); + const QString& contextHandle = doc.object().value(QLatin1String("ContextHandle")).toString(); + + IfdConnectResponse unexpectedMsg(QStringLiteral("RemoteReader")); + mDataChannel->onReceived(unexpectedMsg.toJson(contextHandle).toJson()); + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("Received an unexpected message of type: IFDConnectResponse"))); + } + + + void checkLogOnInvalidMessage() + { + QSignalSpy spyLog(&LogHandler::getInstance(), &LogHandler::fireLog); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + + mDataChannel->onReceived("{\n" + " \"ContextHandle\": \"TestContext\",\n" + " \"msg\": \"RANDOM_STUFF\"\n" + "}\n"); + QVERIFY(TestFileHelper::containsLog(spyLog, QLatin1String("Invalid message received"))); + } + + + void testUnexpectedMessagesCauseAnIfdErrorMessage() + { + QSignalSpy sendSpy(mDataChannel.data(), &MockDataChannel::fireSend); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + + const QByteArray establishContextMsg("{\n" + " \"msg\": \"IFDEstablishContext\",\n" + " \"Protocol\": \"IFDInterface_WebSocket_v0\",\n" + " \"UDName\": \"MAC-MINI\"\n" + "}"); + + mDataChannel->onReceived(establishContextMsg); + + waitForSignals(&sendSpy, 1, 1000); + const QList& establishContextResponseArguments = sendSpy.last(); + + const QVariant establishContextResponseVariant = establishContextResponseArguments.at(0); + QVERIFY(establishContextResponseVariant.canConvert()); + const IfdEstablishContextResponse establishContextResponse(RemoteMessage::parseByteArray(establishContextResponseVariant.toByteArray())); + QVERIFY(establishContextResponse.isValid()); + QCOMPARE(establishContextResponse.getType(), RemoteCardMessageType::IFDEstablishContextResponse); + + const QByteArray contextHandle = establishContextResponse.getContextHandle().toUtf8(); + QVERIFY(!contextHandle.isEmpty());\ + + // We have a context handle: send unexpected messages and verify that an error message is sent back. + sendSpy.clear(); + const QVector serverMessages = makeServerMessages(contextHandle); + for (const QByteArray& serverMessage : serverMessages) + { + mDataChannel->onReceived(serverMessage); + waitForSignals(&sendSpy, 1, 1000); + + const QList& errorMessageArguments = sendSpy.last(); + const QVariant errorMessageVariant = errorMessageArguments.at(0); + QVERIFY(errorMessageVariant.canConvert()); + + const IfdError errorMessage(RemoteMessage::parseByteArray(errorMessageVariant.toByteArray())); + QVERIFY(errorMessage.isValid()); + QCOMPARE(errorMessage.getType(), RemoteCardMessageType::IFDError); + QCOMPARE(errorMessage.getContextHandle(), QString::fromUtf8(contextHandle)); + QCOMPARE(errorMessage.getSlotHandle(), QString()); + QVERIFY(errorMessage.resultHasError()); + QCOMPARE(errorMessage.getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownAPIFunction")); + + sendSpy.clear(); + } + } + + +}; + + +QTEST_GUILESS_MAIN(test_ServerMessageHandler) +#include "test_ServerMessageHandler.moc" diff --git a/test/qt/securestorage/test_SecureStorage.cpp b/test/qt/securestorage/test_SecureStorage.cpp new file mode 100644 index 0000000..9270ba6 --- /dev/null +++ b/test/qt/securestorage/test_SecureStorage.cpp @@ -0,0 +1,345 @@ +/*! + * \brief Unit tests for \ref SecureStorage + * + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany + */ + +#include +#include +#include + +#include "FileDestination.h" +#include "SecureStorage.h" + +#include "asn1/CVCertificate.h" + +using namespace governikus; + +class test_SecureStorage + : public QObject +{ + Q_OBJECT + SecureStorage mSecureStorage; + + private: + QStringList loadCommentList(const QString& pCommentName) + { + const QString& path = FileDestination::getPath("config.json"); + if (!QFile::exists(path)) + { + qCritical() << "SecureStorage not found"; + return QStringList(); + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qCritical() << "Wasn't able to open SecureStorage"; + return QStringList(); + } + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(configFile.readAll(), &parseError); + configFile.close(); + if (parseError.error != QJsonParseError::NoError) + { + qCritical() << "Parse error while reading SecureStorage on position " << parseError.offset << ": " << parseError.errorString(); + return QStringList(); + } + + const QJsonValue commentValues = document.object().value(pCommentName); + if (commentValues == QJsonValue::Undefined || !commentValues.isArray()) + { + qCritical() << "Wasn't able to find the array" << pCommentName; + return QStringList(); + } + + QStringList comments; + const auto& commentValueArray = commentValues.toArray(); + for (const QJsonValue& comment : commentValueArray) + { + if (comment.isString()) + { + comments += comment.toString(); + } + else + { + qCritical() << "At least one entry of" << pCommentName << "is not a string"; + return QStringList(); + } + } + + return comments; + } + + + private Q_SLOTS: + void testGetCVRootCertificatesUnique() + { + static const int EXPECTED_CERTIFICATE_COUNT = 10; + + QVector > cvcs = CVCertificate::fromHex(mSecureStorage.getCVRootCertificates(true)) + + CVCertificate::fromHex(mSecureStorage.getCVRootCertificates(false)); + const int count = cvcs.count(); + QCOMPARE(count, EXPECTED_CERTIFICATE_COUNT); + + const QStringList comments = loadCommentList("_comment_2") + loadCommentList("_comment_4"); + QCOMPARE(comments.size(), count); + + // 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() << "Found 2 certificates with the same name with comments:" << comments[j] << comments[i]; + } + + QVERIFY(carI != carJ || chrI != chrJ); + } + } + } + + + void testGetCVRootCertificateNames_data() + { + QTest::addColumn("certificateCount"); + QTest::addColumn("isProductive"); + QTest::addColumn("commentName"); + + QTest::newRow("production") << 3 << true << "_comment_2"; + QTest::newRow("test") << 7 << false << "_comment_4"; + } + + + void testGetCVRootCertificateNames() + { + QFETCH(int, certificateCount); + QFETCH(bool, isProductive); + QFETCH(QString, commentName); + + QVector > cvcs = CVCertificate::fromHex(mSecureStorage.getCVRootCertificates(isProductive)); + QCOMPARE(cvcs.count(), certificateCount); + + const QStringList& comments = loadCommentList(commentName); + QCOMPARE(comments.count(), certificateCount); + + for (int index = 0; index < certificateCount; ++index) + { + const QString commentLine = comments[index]; + + const QStringList carAndChr = commentLine.split(QStringLiteral("_")); + QVERIFY(carAndChr.size() == 1 || carAndChr.size() == 2); + + const QByteArray carInComment = carAndChr.first().toUtf8(); + const QByteArray carInCertificate = cvcs.at(index)->getBody().getCertificationAuthorityReference(); + const QByteArray chrInComment = carAndChr.size() == 1 ? carAndChr.first().toUtf8() : carAndChr.last().toUtf8(); + const QByteArray chrInCertificate = cvcs.at(index)->getBody().getCertificateHolderReference(); + + if (carInComment != carInCertificate || chrInComment != chrInCertificate) + { + qWarning() << "Wrong certificate information at index" << index << "with comment" << commentLine; + } + + QCOMPARE(carInComment, carInCertificate); + QCOMPARE(chrInComment, chrInCertificate); + } + } + + + void testGetUpdateCertificate_data() + { + QTest::addColumn("index"); + QTest::addColumn("subjectInfo"); + QTest::addColumn("issuerInfo"); + QTest::addColumn("expiryDate"); + + QTest::newRow("production") << 0 << "appl.governikus-asp.de" << "TeleSec ServerPass CA 2" << "2018-05-25T23:59:59Z"; + QTest::newRow("ci") << 1 << "*.tf.bos-test.de" << "govkgrootca" << "2018-12-29T09:59:02Z"; + QTest::newRow("production_2020") << 2 << "appl.governikus-asp.de" << "TeleSec ServerPass Class 2 CA" << "2020-12-06T23:59:59Z"; + } + + + void testGetUpdateCertificate() + { + const auto& certificates = mSecureStorage.getUpdateCertificates(); + QCOMPARE(certificates.count(), 3); + + QFETCH(int, index); + QFETCH(QString, subjectInfo); + QFETCH(QString, issuerInfo); + QFETCH(QString, expiryDate); + + QVERIFY(certificates.count() - index > 0); + + const auto& cert = certificates.at(index); + QCOMPARE(cert.subjectInfo(QSslCertificate::CommonName).at(0), subjectInfo); + QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName).at(0), issuerInfo); + QCOMPARE(cert.expiryDate(), QDateTime::fromString(expiryDate, Qt::ISODate)); + } + + + void testGetSelfAuthentication() + { + QVERIFY(mSecureStorage.getSelfAuthenticationUrl(false).isValid()); + QVERIFY(mSecureStorage.getSelfAuthenticationUrl(true).isValid()); + QVERIFY(!mSecureStorage.getSelfAuthenticationCertDescr(false).isEmpty()); + QVERIFY(!mSecureStorage.getSelfAuthenticationCertDescr(true).isEmpty()); + } + + + void testGetUpdateServerBaseUrl() + { + QVERIFY(mSecureStorage.getUpdateServerBaseUrl().isValid()); + } + + + void testAppcast() + { + QCOMPARE(mSecureStorage.getAppcastUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/Appcast.json")); + QCOMPARE(mSecureStorage.getAppcastBetaUpdateUrl(), QUrl("https://appl.governikus-asp.de/ausweisapp2/beta/Appcast.json")); + } + + + void testMinStaticKeySizes() + { + QCOMPARE(mSecureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Rsa), 2000); + QCOMPARE(mSecureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Dsa), 2000); + QCOMPARE(mSecureStorage.getMinimumStaticKeySize(QSsl::KeyAlgorithm::Ec), 224); + } + + + void testMinEphemeralKeySizes() + { + QCOMPARE(mSecureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Rsa), 2000); + QCOMPARE(mSecureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Dsa), 2000); + QCOMPARE(mSecureStorage.getMinimumEphemeralKeySize(QSsl::KeyAlgorithm::Ec), 224); + } + + + void testSignatureAlgorithms() + { + #ifndef GOVERNIKUS_QT + QSKIP("SignatureAlgorithms not supported"); + #endif + + const auto& tlsSettings = mSecureStorage.getTlsConfig(); + 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() + { + #ifndef GOVERNIKUS_QT + QSKIP("SignatureAlgorithms not supported"); + #endif + + const auto& tlsSettings = mSecureStorage.getTlsConfig(SecureStorage::TlsSuite::PSK); + 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 testSignatureAlgorithmsRemoteReader() + { + #ifndef GOVERNIKUS_QT + QSKIP("SignatureAlgorithms not supported"); + #endif + + const auto& config = mSecureStorage.getTlsConfigRemote(); + QCOMPARE(config.getSignatureAlgorithms().size(), 3); + + const auto& configPairing = mSecureStorage.getTlsConfigRemote(); + QCOMPARE(configPairing.getSignatureAlgorithms().size(), 3); + } + + + void orderOfCiphers() + { + const auto& ciphersForwardSecrecy = mSecureStorage.getTlsConfig().getCiphers(); + QCOMPARE(ciphersForwardSecrecy.first(), QSslCipher("ECDHE-ECDSA-AES256-GCM-SHA384")); + QCOMPARE(ciphersForwardSecrecy.last(), QSslCipher("DHE-RSA-AES128-SHA")); + + const auto& ciphersPsk = mSecureStorage.getTlsConfig(SecureStorage::TlsSuite::PSK).getCiphers(); + QCOMPARE(ciphersPsk.count(), 5); + QCOMPARE(ciphersPsk.first(), QSslCipher("RSA-PSK-AES256-GCM-SHA384")); + QCOMPARE(ciphersPsk.last(), QSslCipher("RSA-PSK-AES256-CBC-SHA")); + + const auto& ciphersEc = mSecureStorage.getTlsConfig().getEllipticCurves(); + QCOMPARE(ciphersEc.count(), 6); + QCOMPARE(ciphersEc.first(), QSslEllipticCurve::fromLongName("brainpoolP512r1")); + QCOMPARE(ciphersEc.last(), QSslEllipticCurve::fromLongName("secp224r1")); + + const auto& ciphersEcRemoteReader = mSecureStorage.getTlsConfigRemote().getEllipticCurves(); + QCOMPARE(ciphersEcRemoteReader.count(), 6); + QCOMPARE(ciphersEcRemoteReader.first(), QSslEllipticCurve::fromLongName("brainpoolP512r1")); + QCOMPARE(ciphersEcRemoteReader.last(), QSslEllipticCurve::fromLongName("secp224r1")); + + const auto& ciphersEcRemoteReaderPairing = mSecureStorage.getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getEllipticCurves(); + QCOMPARE(ciphersEcRemoteReaderPairing.count(), 0); + + const auto& ciphersRemoteReader = mSecureStorage.getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getCiphers(); + QCOMPARE(ciphersRemoteReader.count(), 5); + QCOMPARE(ciphersRemoteReader.first(), QSslCipher("RSA-PSK-AES256-GCM-SHA384")); + QCOMPARE(ciphersRemoteReader.last(), QSslCipher("RSA-PSK-AES256-CBC-SHA")); + } + + + void getSslProtocolVersion() + { + QCOMPARE(mSecureStorage.getTlsConfig().getProtocolVersion(), QSsl::SslProtocol::TlsV1_0OrLater); + } + + + void getSslProtocolVersionPsk() + { + QCOMPARE(mSecureStorage.getTlsConfig(SecureStorage::TlsSuite::PSK).getProtocolVersion(), QSsl::SslProtocol::TlsV1_1OrLater); + } + + + void getConfiguration_data() + { + QTest::addColumn("configuration"); + QTest::addColumn("cipherSize"); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + QTest::newRow("ciphers non PSK") << mSecureStorage.getTlsConfig().getConfiguration() << 24; +#else + QTest::newRow("ciphers non PSK") << mSecureStorage.getTlsConfig().getConfiguration() << 18; +#endif + + QTest::newRow("ciphers for PSK") << mSecureStorage.getTlsConfig(SecureStorage::TlsSuite::PSK).getConfiguration() << 5; + QTest::newRow("remote reader") << mSecureStorage.getTlsConfigRemote().getConfiguration() << 7; + QTest::newRow("remote reader pairing") << mSecureStorage.getTlsConfigRemote(SecureStorage::TlsSuite::PSK).getConfiguration() << 5; + } + + + void getConfiguration() + { + QFETCH(QSslConfiguration, configuration); + QFETCH(int, cipherSize); + + QCOMPARE(configuration.ciphers().size(), cipherSize); + } + + +}; + +QTEST_GUILESS_MAIN(test_SecureStorage) +#include "test_SecureStorage.moc" diff --git a/test/qt/securestorage/test_TlsConfiguration.cpp b/test/qt/securestorage/test_TlsConfiguration.cpp new file mode 100644 index 0000000..3714135 --- /dev/null +++ b/test/qt/securestorage/test_TlsConfiguration.cpp @@ -0,0 +1,162 @@ +/*! + * \brief Unit tests for \ref TlsConfiguration + * + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TlsConfiguration.h" + +#include +#include + + +using namespace governikus; + + +class test_TlsConfiguration + : public QObject +{ + Q_OBJECT + TlsConfiguration mTlsConfiguration; + + private Q_SLOTS: + void initTestCase() + { + mTlsConfiguration = TlsConfiguration(); + } + + + void testDefaults() + { + QByteArray config("{}"); + + mTlsConfiguration.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsConfiguration.getProtocolVersion(), QSsl::SecureProtocols); + QCOMPARE(mTlsConfiguration.getCiphers().size(), 0); + QCOMPARE(mTlsConfiguration.getEllipticCurves().size(), 0); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms().size(), 0); + } + + + void testLoadprotocolVersion() + { + QByteArray config("{" + " \"protocolVersion\": \"TlsV1_0OrLater\"" + "}"); + + mTlsConfiguration.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsConfiguration.getProtocolVersion(), QSsl::TlsV1_0OrLater); + } + + + void testLoadCiphers() + { + QByteArray config("{" + " \"ciphers\": [\"ECDHE-ECDSA-AES256-GCM-SHA384\",\"DHE-RSA-AES256-SHA256\"]" + "}"); + + mTlsConfiguration.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsConfiguration.getCiphers().size(), 2); + QCOMPARE(mTlsConfiguration.getCiphers()[0], QSslCipher("ECDHE-ECDSA-AES256-GCM-SHA384")); + QCOMPARE(mTlsConfiguration.getCiphers()[1], QSslCipher("DHE-RSA-AES256-SHA256")); + } + + + void testLoadEllipticCurves() + { + QByteArray config("{" + " \"ellipticCurves\": [\"brainpoolP512r1\", \"brainpoolP384r1\"]" + "}"); + + mTlsConfiguration.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsConfiguration.getEllipticCurves().size(), 2); + QCOMPARE(mTlsConfiguration.getEllipticCurves()[0], QSslEllipticCurve::fromLongName("brainpoolP512r1")); + QCOMPARE(mTlsConfiguration.getEllipticCurves()[1], QSslEllipticCurve::fromLongName("brainpoolP384r1")); + } + + + void testLoadSignatureAlgorithms() + { + #ifndef GOVERNIKUS_QT + QSKIP("SignatureAlgorithms not supported"); + #endif + + QByteArray config("{" + " \"signatureAlgorithms\": [\"Rsa+Sha512\", \"Dsa+Sha384\", \"Ec+Sha256\"]" + "}"); + + mTlsConfiguration.load(QJsonDocument::fromJson(config).object()); + + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms().size(), 3); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms()[0].first, QSsl::Rsa); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms()[0].second, QCryptographicHash::Sha512); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms()[1].first, QSsl::Dsa); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms()[1].second, QCryptographicHash::Sha384); + QCOMPARE(mTlsConfiguration.getSignatureAlgorithms()[2].first, QSsl::Ec); + QCOMPARE(mTlsConfiguration.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\"]," +#ifdef GOVERNIKUS_QT + " \"signatureAlgorithms\": [\"Rsa+Sha512\", \"Dsa+Sha384\", \"Ec+Sha256\"]" +#endif + "}"}); + + 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); + + TlsConfiguration settings1, settings2; + settings1.load(QJsonDocument::fromJson(config1).object()); + settings2.load(QJsonDocument::fromJson(config2).object()); + + QCOMPARE(settings1 == settings2, isEqual); + } + + +}; + +QTEST_GUILESS_MAIN(test_TlsConfiguration) +#include "test_TlsConfiguration.moc" diff --git a/test/qt/services/test_AppService.cpp b/test/qt/services/test_AppService.cpp deleted file mode 100644 index 8de5a63..0000000 --- a/test/qt/services/test_AppService.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/*! - * \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_AppUpdatr.cpp b/test/qt/services/test_AppUpdatr.cpp new file mode 100644 index 0000000..8cc9a1f --- /dev/null +++ b/test/qt/services/test_AppUpdatr.cpp @@ -0,0 +1,275 @@ +/*! + * \brief Unit tests for \ref AppUpdater + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "AppUpdater.h" +#include "Downloader.h" + +#include "Env.h" +#include "GlobalStatus.h" +#include "LogHandler.h" +#include "MockDownloader.h" +#include "SecureStorage.h" +#include "TestFileHelper.h" +#include "VersionNumber.h" + +#include + +namespace +{ +const char* test_jsonData = "{" + " \"items\":" + " [" + " {" + " \"date\": \"2017-10-25T15:20:25\"," + " \"platform\": \"mac\"," + " \"version\": \"1.13.3+284-default-a2f3eafc47e9\"," + " \"url\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+284-default-a2f3eafc47e9.dmg\"," + " \"size\": 16531848," + " \"checksum\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+284-default-a2f3eafc47e9.dmg.sha256\"," + " \"notes\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/ReleaseNotes.html#1.13.3+284-default-a2f3eafc47e9\"" + " }" + ", {" + " \"date\": \"2017-10-25T15:20:25\"," + " \"platform\": \"win\"," + " \"version\": \"1.13.3+285-default-8b1156a4acc5\"," + " \"url\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+285-default-8b1156a4acc5.msi\"," + " \"size\": 17633280," + " \"checksum\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+285-default-8b1156a4acc5.msi.sha256\"," + " \"notes\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/ReleaseNotes.html#1.13.3+285-default-8b1156a4acc5\"" + " }" + ", {" + " \"date\": \"2017-10-25T15:20:25\"," + " \"platform\": \"src\"," + " \"version\": \"1.13.3+277-default-54ea820b42b0.tar.gz\"," + " \"url\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+277-default-54ea820b42b0.tar.gz\"," + " \"size\": 8687552," + " \"checksum\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/AusweisApp2-1.13.3+277-default-54ea820b42b0.tar.gz.sha256\"," + " \"notes\": \"https://vtf-aajenkins.tf.bos-test.de/job/default_Appcast/lastSuccessfulBuild/artifact/build/ReleaseNotes.html#1.13.3+277-default-54ea820b42b0.tar.gz\"" + " }" + "" + " ]" + "}"; +const char* test_releaseNotes = "Release Notes"; +} + +using namespace governikus; + +class test_AppUpdater + : public QObject +{ + Q_OBJECT + + private: + AppUpdater mAppUpdater; + MockDownloader mDownloader; + QUrl mAppCastLocation; + QUrl mReleaseNoteLocation; + QJsonDocument mJsonDocument; + + void checkResult(QSignalSpy& pSpy, bool pSuccess, GlobalStatus::Code pErrorCode) + { + QCOMPARE(pSpy.count(), 1); + + const QList& arguments = pSpy.first(); + const QVariant successVariant = arguments.at(0); + QVERIFY(successVariant.userType() == QMetaType::Bool); + const bool success = successVariant.toBool(); + QCOMPARE(success, pSuccess); + + const QVariant errorCodeVariant = arguments.at(1); + QVERIFY(errorCodeVariant.canConvert()); + GlobalStatus errorCode = errorCodeVariant.value(); + QCOMPARE(errorCode.getStatusCode(), pErrorCode); + } + + + void setJsonItemField(QJsonDocument& pDocument, QString pField, QString pValue) + { + auto itemArray = pDocument.object()["items"].toArray(); + int i = 0; + for (auto item : itemArray) + { + QJsonObject itemObject = item.toObject(); + itemObject[pField] = pValue; + itemArray.replace(i, itemObject); + i++; + } + QJsonObject newRootObject; + newRootObject[QLatin1String("items")] = itemArray; + pDocument.setObject(newRootObject); + } + + + QJsonValue getJsonItemField(QJsonDocument& pDocument, QString pField) + { + #ifdef Q_OS_WIN + QString platform = "win"; + #endif + + #ifdef Q_OS_MACOS + QString platform = "mac"; + #endif + + #if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN) + QString platform = "src"; + #endif + + auto itemArray = pDocument.object()["items"].toArray(); + for (auto item : itemArray) + { + QJsonObject itemObject = item.toObject(); + if (itemObject["platform"] == platform) + { + return itemObject[pField]; + } + } + return QString("NO_INFO"); + } + + + private Q_SLOTS: + void initTestCase() + { + Env::set(Downloader::staticMetaObject, &mDownloader); + + const SecureStorage& secureStorage = SecureStorage::getInstance(); + mAppCastLocation = VersionNumber::getApplicationVersion().isDeveloperVersion() ? secureStorage.getAppcastBetaUpdateUrl() : secureStorage.getAppcastUpdateUrl(); + + mJsonDocument = QJsonDocument::fromJson(test_jsonData); + mReleaseNoteLocation = getJsonItemField(mJsonDocument, "notes").toString(); + } + + + void init() + { + mDownloader.setError(GlobalStatus::Code::No_Error); + mDownloader.setTestData(mAppCastLocation, test_jsonData); + mDownloader.setTestData(mReleaseNoteLocation, test_releaseNotes); + } + + + void cleanup() + { + + } + + + void testNewAppUpdateVersion() + { + QJsonDocument document = QJsonDocument::fromJson(test_jsonData); + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, true, GlobalStatus::Code::No_Error); + AppUpdateData updateData = mAppUpdater.getUpdateData(); + + QCOMPARE(updateData.getDate(), QDateTime::fromString(getJsonItemField(document, "date").toString(), Qt::ISODate)); + QCOMPARE(updateData.getVersion(), getJsonItemField(document, "version").toString()); + QCOMPARE(updateData.getNotesUrl(), QUrl(getJsonItemField(document, "notes").toString())); + QCOMPARE(updateData.getUrl(), QUrl(getJsonItemField(document, "url").toString())); + QCOMPARE(updateData.getChecksumUrl(), QUrl(getJsonItemField(document, "checksum").toString())); + QCOMPARE(updateData.getSize(), getJsonItemField(document, "size").toInt()); + QVERIFY(mAppUpdater.getUpdateData().getNotes() != QString()); + } + + + void testJSONParsingError() + { + QByteArray data("!{no json data]"); + mDownloader.setTestData(mAppCastLocation, data); + + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, false, GlobalStatus::Code::Downloader_Data_Corrupted); + } + + + void testPlatformNotSupported() + { + QByteArray data("{\"items\":[]}"); + mDownloader.setTestData(mAppCastLocation, data); + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, false, GlobalStatus::Code::No_Error); + } + + + void testSkipCurrentVersion() + { + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + mAppUpdater.skipVersion(getJsonItemField(mJsonDocument, "version").toString()); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, false, GlobalStatus::Code::No_Error); + mAppUpdater.skipVersion(""); + } + + + void testSkipCurrentVersionButDoNotRespectIt() + { + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + mAppUpdater.skipVersion(getJsonItemField(mJsonDocument, "version").toString()); + + mAppUpdater.checkAppUpdate(true); + + checkResult(spy, true, GlobalStatus::Code::No_Error); + mAppUpdater.skipVersion(""); + } + + + void testNoNewVersion() + { + QJsonDocument document = QJsonDocument::fromJson(test_jsonData); + setJsonItemField(document, QString("version"), QString(" ")); + QByteArray newJson = document.toJson(); + mDownloader.setTestData(mAppCastLocation, newJson); + + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, false, GlobalStatus::Code::No_Error); + } + + + void testJSONDownloadFailed() + { + mDownloader.setError(GlobalStatus::Code::Downloader_File_Not_Found); + + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, false, GlobalStatus::Code::Downloader_File_Not_Found); + } + + + void testReleaseNoteDownloadFailed() + { + QJsonDocument document = QJsonDocument::fromJson(test_jsonData); + setJsonItemField(document, QString("notes"), QString("httb://notarealurl.org")); + QByteArray newJson = document.toJson(); + mDownloader.setTestData(mAppCastLocation, newJson); + + QSignalSpy spy(&mAppUpdater, &AppUpdater::fireAppUpdateCheckFinished); + + mAppUpdater.checkAppUpdate(); + + checkResult(spy, true, GlobalStatus::Code::No_Error); + QCOMPARE(mAppUpdater.getUpdateData().getNotes(), QString()); + } + + +}; + +QTEST_GUILESS_MAIN(test_AppUpdater) +#include "test_AppUpdatr.moc" diff --git a/test/qt/services/test_ProviderParser.cpp b/test/qt/services/test_ProviderParser.cpp deleted file mode 100644 index efeabf1..0000000 --- a/test/qt/services/test_ProviderParser.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/*! - * \brief Unit tests for \ref ProviderParser - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProviderParser.h" -#include - -#include "TestFileHelper.h" - -using namespace governikus; - -Q_DECLARE_METATYPE(QLatin1String) - -class test_ProviderParser - : public QObject -{ - Q_OBJECT - - ProviderParser parser; - - private Q_SLOTS: - void parseEmpty() - { - QByteArray data = QByteArray("{}"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QVERIFY(providerSettings->getIssueDate().isNull()); - QVERIFY(providerSettings->getProviders().isEmpty()); - } - - - void parseIssueDate() - { - QByteArray data = QByteArray("{" - " \"issueDate\": \"2015-10-29T06:25:00+1:00\"}"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QCOMPARE(providerSettings->getIssueDate(), QDateTime::fromString("2015-10-29T06:25:00+1:00", Qt::ISODate)); - QVERIFY(providerSettings->getProviders().isEmpty()); - } - - - void parseProviders() - { - QByteArray data = QByteArray("{" - " \"provider\": [" - " {" - " \"shortName\": {\"\" : \":::(bit)kasten\", \"de\" : \":::(bit)-de-kasten\", \"fr_FR\" : \":::(bit)-fr-kasten\"}," - " \"address\": \"https://www.bitkasten.de/\"," - " \"phone\": \"\"," - " \"email\": \"\"," - " \"postaladdress\": \"\"," - " \"category\": \"other\"" - " }," - " {" - " \"shortName\": {\"\" : \"Allianz Kundenportal\"}," - " \"longName\": {\"\" : \"Allianz Kundenportal - Meine Allianz\"}," - " \"shortDescription\": {\"\" : \"Kundenportal von Allianz\"}," - " \"longDescription\": {\"\" : \"Kundenportal von Allianz - Meine Allianz\"}," - " \"address\": \"https://meine.allianz.de/form\"," - " \"homepage\": \"https://meine.allianz.de\"," - " \"phone\": \"0421 123456\"," - " \"email\": \"abc@def.de\"," - " \"postalAddress\": \"Am Fallturm 9,\n28359 Bremen\"," - " \"category\": \"insurance\"," - " \"icon\": \"qrc:///images/npa.ico\"," - " \"image\": \"qrc:///images/iOS/Header-Ausweisapp@3x.png\"" - " }" - " ]" - "}"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QVERIFY(providerSettings->getIssueDate().isNull()); - QCOMPARE(providerSettings->getProviders().size(), 2); - - auto provider = providerSettings->getProviders()[0]; - QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)kasten")); - - LanguageLoader::getInstance().mUsedLocale = QLocale("om"); - QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)kasten")); - - LanguageLoader::getInstance().mUsedLocale = QLocale("de"); - QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-de-kasten")); - - LanguageLoader::getInstance().mUsedLocale = QLocale("fr"); - QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-fr-kasten")); - - LanguageLoader::getInstance().mUsedLocale = QLocale("fr_FR"); - QCOMPARE(provider.getShortName().toString(), QStringLiteral(":::(bit)-fr-kasten")); - - QCOMPARE(provider.getLongName().toString(), QString()); - QCOMPARE(provider.getShortDescription().toString(), QString()); - QCOMPARE(provider.getLongDescription().toString(), QString()); - QCOMPARE(provider.getAddress(), QStringLiteral("https://www.bitkasten.de/")); - QCOMPARE(provider.getHomepage(), QString()); - QCOMPARE(provider.getPhone(), QString()); - QCOMPARE(provider.getEMail(), QString()); - QCOMPARE(provider.getPostalAddress(), QString()); - QCOMPARE(provider.getCategory(), QStringLiteral("other")); - QCOMPARE(provider.getIcon(), QString()); - QCOMPARE(provider.getImage(), QString()); - - provider = providerSettings->getProviders()[1]; - QCOMPARE(provider.getShortName().toString(), QStringLiteral("Allianz Kundenportal")); - QCOMPARE(provider.getLongName().toString(), QStringLiteral("Allianz Kundenportal - Meine Allianz")); - QCOMPARE(provider.getShortDescription().toString(), QStringLiteral("Kundenportal von Allianz")); - QCOMPARE(provider.getLongDescription().toString(), QStringLiteral("Kundenportal von Allianz - Meine Allianz")); - QCOMPARE(provider.getAddress(), QStringLiteral("https://meine.allianz.de/form")); - QCOMPARE(provider.getHomepage(), QStringLiteral("https://meine.allianz.de")); - QCOMPARE(provider.getPhone(), QStringLiteral("0421 123456")); - QCOMPARE(provider.getEMail(), QStringLiteral("abc@def.de")); - QCOMPARE(provider.getPostalAddress(), QStringLiteral("Am Fallturm 9,\n28359 Bremen")); - QCOMPARE(provider.getCategory(), QStringLiteral("insurance")); - QCOMPARE(provider.getIcon(), QStringLiteral("qrc:///images/npa.ico")); - QCOMPARE(provider.getImage(), QStringLiteral("qrc:///images/iOS/Header-Ausweisapp@3x.png")); - } - - - void parseAdditionalData() - { - QByteArray data = QByteArray("{" - " \"provider\": [" - " {" - " \"shortName\": {\"\" : \":::(bit)kasten\"}," - " \"address\": \"https://www.bitkasten.de/\"," - " \"phone\": \"\"," - " \"email\": \"\"," - " \"postaladdress\": \"\"," - " \"category\": \"other\"," - " \"someNewProperty\": \"blabla\"" - " }" - " ]" - "}"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QVERIFY(providerSettings->getIssueDate().isNull()); - QCOMPARE(providerSettings->getProviders().size(), 1); - auto provider = providerSettings->getProviders()[0]; - QCOMPARE(provider.getShortName().toString(), QString(":::(bit)kasten")); - QCOMPARE(provider.getAddress(), QString("https://www.bitkasten.de/")); - QCOMPARE(provider.getPhone(), QString("")); - QCOMPARE(provider.getEMail(), QString("")); - QCOMPARE(provider.getPostalAddress(), QString("")); - QCOMPARE(provider.getCategory(), QString("other")); - } - - - 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"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QVERIFY(providerSettings->getIssueDate().isValid()); - QVERIFY(!providerSettings->getProviders().isEmpty()); - } - - - void parseCallCosts() - { - QByteArray data = TestFileHelper::readFile(QCoreApplication::applicationDirPath() + "/default-providers.json"); - - QSharedPointer providerSettings = parser.parse(data); - - QVERIFY(providerSettings); - QCOMPARE(providerSettings->mCallCosts.size(), 17); - } - - - void platformCount_data() - { - QTest::addColumn("count"); - - const int desktop = 66; - QTest::newRow("win") << desktop; - QTest::newRow("mac") << desktop; - QTest::newRow("linux") << desktop; - QTest::newRow("android") << desktop - 1; - QTest::newRow("ios") << 14; - } - - - void platformCount() - { - QFETCH(int, count); - - QByteArray data = TestFileHelper::readFile(QCoreApplication::applicationDirPath() + "/default-providers.json"); - QSharedPointer providerSettings = parser.parse(data, QLatin1String(QTest::currentDataTag())); - - QVERIFY(providerSettings); - QCOMPARE(providerSettings->getProviders().size(), count); - } - - - void checkExcludedPlatform_data() - { - QTest::addColumn("content"); - QTest::addColumn("currentOS"); - QTest::addColumn("excluded"); - - QTest::newRow("mobile") - << QByteArray(R"( ["mobile"] )") << QLatin1String("android") << true; - - QTest::newRow("android") - << QByteArray(R"( ["mac", "android"] )") << QLatin1String("android") << true; - - QTest::newRow("desktop_excluded_mac") - << QByteArray(R"( ["android", "desktop"] )") << QLatin1String("mac") << true; - - QTest::newRow("ios") - << QByteArray(R"( ["android", "desktop"] )") << QLatin1String("ios") << false; - - QTest::newRow("ios") - << QByteArray(R"( ["android", "win"] )") << QLatin1String("ios") << false; - - QTest::newRow("mobile_excluded") - << QByteArray(R"( ["win", "mobile"] )") << QLatin1String("android") << true; - - QTest::newRow("mobile_excluded") - << QByteArray(R"( ["mobile", "win"] )") << QLatin1String("ios") << true; - - QTest::newRow("win_excluded") - << QByteArray(R"( ["win"] )") << QLatin1String("win") << true; - - QTest::newRow("desktop_excluded_single") - << QByteArray(R"( ["desktop"] )") << QLatin1String("win") << true; - - QTest::newRow("win") - << QByteArray(R"( ["mac", "bla", "bsd", "linux", "mobile", "ios", "android"] )") << QLatin1String("win") << false; - - QTest::newRow("desktop_excluded_multi") - << QByteArray(R"( ["mac", "bla", "bsd", "linux", "desktop", "ios", "android"] )") << QLatin1String("win") << true; - - QTest::newRow("win_excluded") - << QByteArray(R"( ["mac", "bla", "dummy", "win"] )") << QLatin1String("win") << true; - - QTest::newRow("nothing") - << QByteArray(R"( [] )") << QLatin1String("win") << false; - } - - - void checkExcludedPlatform() - { - QFETCH(QByteArray, content); - QFETCH(QLatin1String, currentOS); - QFETCH(bool, excluded); - - const auto& doc = QJsonDocument::fromJson(content); - QVERIFY(!doc.isNull()); - QCOMPARE(ProviderParser::isExcludedPlatform(doc.array(), currentOS), excluded); - } - - - void checkExcludedPlatformEmpty() - { - QCOMPARE(ProviderParser::isExcludedPlatform(QJsonArray(), QLatin1String("ios")), false); - } - - -}; - -QTEST_GUILESS_MAIN(test_ProviderParser) -#include "test_ProviderParser.moc" diff --git a/test/qt/settings/test_AppSettings.cpp b/test/qt/settings/test_AppSettings.cpp index dcb28de..26ce0e5 100644 --- a/test/qt/settings/test_AppSettings.cpp +++ b/test/qt/settings/test_AppSettings.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref AppSettings * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -35,41 +35,6 @@ class test_AppSettings } - void testEquals() - { - AppSettings* otherSettings = new AppSettings; - - QVERIFY(*settings == *otherSettings); - - settings->getGeneralSettings().setShowSetupAssistant(!settings->getGeneralSettings().isShowSetupAssistant()); - QVERIFY(*settings != *otherSettings); - otherSettings->getGeneralSettings().setShowSetupAssistant(settings->getGeneralSettings().isShowSetupAssistant()); - QVERIFY(*settings == *otherSettings); - - settings->getPreVerificationSettings().addLinkCertificate(QByteArray("123456")); - QVERIFY(*settings != *otherSettings); - otherSettings->getPreVerificationSettings().addLinkCertificate(QByteArray("123456")); - QVERIFY(*settings == *otherSettings); - - settings->getProviderSettings().setIssueDate(QDateTime(QDate(1989, 11, 9))); - QVERIFY(*settings != *otherSettings); - otherSettings->getProviderSettings().setIssueDate(QDateTime(QDate(1989, 11, 9))); - 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; - } - - }; QTEST_GUILESS_MAIN(test_AppSettings) diff --git a/test/qt/settings/test_GeneralSettings.cpp b/test/qt/settings/test_GeneralSettings.cpp index 41e71b2..8c473c9 100644 --- a/test/qt/settings/test_GeneralSettings.cpp +++ b/test/qt/settings/test_GeneralSettings.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref GeneralSettings * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include @@ -17,102 +17,59 @@ class test_GeneralSettings : public QObject { Q_OBJECT - QScopedPointer settings; + QScopedPointer mSettings; private Q_SLOTS: void init() { AbstractSettings::mTestDir.clear(); - settings.reset(new GeneralSettings()); - } - - - void testEquals() - { - GeneralSettings otherSettings; - otherSettings.load(); - - QVERIFY(*settings == otherSettings); - - settings->setAutoCloseWindowAfterAuthentication(!settings->isAutoCloseWindowAfterAuthentication()); - QVERIFY(*settings != otherSettings); - otherSettings.setAutoCloseWindowAfterAuthentication(settings->isAutoCloseWindowAfterAuthentication()); - QVERIFY(*settings == otherSettings); - - settings->setAutoUpdateCheck(false); - QVERIFY(*settings != otherSettings); - otherSettings.setAutoUpdateCheck(false); - - settings->setAutoStart(!GENERAL_SETTINGS_DEFAULT_AUTOSTART); - QVERIFY(*settings != otherSettings); - otherSettings.setAutoStart(!GENERAL_SETTINGS_DEFAULT_AUTOSTART); - - settings->setUseScreenKeyboard(true); - QVERIFY(*settings != otherSettings); - otherSettings.setUseScreenKeyboard(true); - - settings->setShowSetupAssistant(!settings->isShowSetupAssistant()); - QVERIFY(*settings != otherSettings); - otherSettings.setShowSetupAssistant(settings->isShowSetupAssistant()); - QVERIFY(*settings == otherSettings); - - settings->setRemindUserToClose(!settings->isRemindUserToClose()); - QVERIFY(*settings != otherSettings); - otherSettings.setRemindUserToClose(settings->isRemindUserToClose()); - QVERIFY(*settings == otherSettings); + mSettings.reset(new GeneralSettings()); } void testAutoCloseWindowAfterAuthentication() { - bool initial = settings->isAutoCloseWindowAfterAuthentication(); + bool initial = mSettings->isAutoCloseWindowAfterAuthentication(); bool newValue = !initial; - settings->setAutoCloseWindowAfterAuthentication(newValue); - QCOMPARE(settings->isAutoCloseWindowAfterAuthentication(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setAutoCloseWindowAfterAuthentication(newValue); + QCOMPARE(mSettings->isAutoCloseWindowAfterAuthentication(), newValue); + mSettings->save(); - settings->setAutoCloseWindowAfterAuthentication(initial); - QCOMPARE(settings->isAutoCloseWindowAfterAuthentication(), initial); - settings->save(); + mSettings->setAutoCloseWindowAfterAuthentication(initial); + QCOMPARE(mSettings->isAutoCloseWindowAfterAuthentication(), initial); + mSettings->save(); } void testAutoCheck() { - bool initial = settings->isAutoUpdateCheck(); + bool initial = mSettings->isAutoUpdateCheck(); - settings->setAutoUpdateCheck(!initial); - QCOMPARE(settings->isAutoUpdateCheck(), !initial); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setAutoUpdateCheck(!initial); + QCOMPARE(mSettings->isAutoUpdateCheck(), !initial); + mSettings->save(); - - settings->setAutoUpdateCheck(initial); - QCOMPARE(settings->isAutoUpdateCheck(), initial); - settings->save(); + mSettings->setAutoUpdateCheck(initial); + QCOMPARE(mSettings->isAutoUpdateCheck(), initial); + mSettings->save(); } void testAutoStart() { - #if defined(Q_OS_WIN32) || defined(Q_OS_OSX) - bool initial = settings->isAutoStart(); + #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + bool initial = mSettings->isAutoStart(); - settings->setAutoStart(!initial); - QCOMPARE(settings->isAutoStart(), !initial); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setAutoStart(!initial); + QCOMPARE(mSettings->isAutoStart(), !initial); + mSettings->save(); - settings->setAutoStart(initial); - QCOMPARE(settings->isAutoStart(), initial); - settings->save(); + mSettings->setAutoStart(initial); + QCOMPARE(mSettings->isAutoStart(), initial); + mSettings->save(); #else QSKIP("Autostart currently only on windows and mac os"); @@ -122,70 +79,61 @@ class test_GeneralSettings void testUseScreenKeyboard() { - bool initial = settings->isUseScreenKeyboard(); + bool initial = mSettings->isUseScreenKeyboard(); - settings->setUseScreenKeyboard(!initial); - QCOMPARE(settings->isUseScreenKeyboard(), !initial); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setUseScreenKeyboard(!initial); + QCOMPARE(mSettings->isUseScreenKeyboard(), !initial); + mSettings->save(); - settings->setUseScreenKeyboard(initial); - QCOMPARE(settings->isUseScreenKeyboard(), initial); - settings->save(); + mSettings->setUseScreenKeyboard(initial); + QCOMPARE(mSettings->isUseScreenKeyboard(), initial); + mSettings->save(); } void testDefaultValues() { - GeneralSettings defaultSettings; - QCOMPARE(defaultSettings.isAutoCloseWindowAfterAuthentication(), true); - QCOMPARE(defaultSettings.isAutoStart(), GENERAL_SETTINGS_DEFAULT_AUTOSTART); - QCOMPARE(defaultSettings.isAutoUpdateCheck(), true); - QCOMPARE(defaultSettings.isUseScreenKeyboard(), false); - QCOMPARE(defaultSettings.isShowSetupAssistant(), true); - QCOMPARE(defaultSettings.isRemindUserToClose(), true); - QCOMPARE(defaultSettings.isTransportPinReminder(), true); - QCOMPARE(defaultSettings.getPersistentSettingsVersion(), QString()); - QCOMPARE(defaultSettings.isDeveloperMode(), false); - QCOMPARE(defaultSettings.useSelfauthenticationTestUri(), false); + QCOMPARE(mSettings->isAutoCloseWindowAfterAuthentication(), true); + QCOMPARE(mSettings->isAutoStart(), GENERAL_SETTINGS_DEFAULT_AUTOSTART); + QCOMPARE(mSettings->isAutoUpdateCheck(), true); + QCOMPARE(mSettings->isUseScreenKeyboard(), false); + QCOMPARE(mSettings->isShowSetupAssistant(), true); + QCOMPARE(mSettings->isRemindUserToClose(), true); + QCOMPARE(mSettings->isTransportPinReminder(), true); + QCOMPARE(mSettings->getPersistentSettingsVersion(), QString()); + QCOMPARE(mSettings->isDeveloperMode(), false); + QCOMPARE(mSettings->useSelfAuthTestUri(), false); } void testRemindStartupWizard() { - bool initial = settings->isShowSetupAssistant(); + bool initial = mSettings->isShowSetupAssistant(); bool newValue = !initial; - settings->setShowSetupAssistant(newValue); - QCOMPARE(settings->isShowSetupAssistant(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setShowSetupAssistant(newValue); + QCOMPARE(mSettings->isShowSetupAssistant(), newValue); + mSettings->save(); - settings->setShowSetupAssistant(initial); - QCOMPARE(settings->isShowSetupAssistant(), initial); - QVERIFY(settings->isUnsaved()); - settings->save(); + mSettings->setShowSetupAssistant(initial); + QCOMPARE(mSettings->isShowSetupAssistant(), initial); + mSettings->save(); } void testRemindUserToClose() { - bool initial = settings->isRemindUserToClose(); + bool initial = mSettings->isRemindUserToClose(); bool newValue = !initial; - settings->setRemindUserToClose(newValue); - QCOMPARE(settings->isRemindUserToClose(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + mSettings->setRemindUserToClose(newValue); + QCOMPARE(mSettings->isRemindUserToClose(), newValue); + mSettings->save(); - settings->setRemindUserToClose(initial); - QCOMPARE(settings->isRemindUserToClose(), initial); - QVERIFY(settings->isUnsaved()); - settings->save(); + mSettings->setRemindUserToClose(initial); + QCOMPARE(mSettings->isRemindUserToClose(), initial); + mSettings->save(); } @@ -195,29 +143,41 @@ class test_GeneralSettings // the persistent settings version contains the application version number // last saving the settings --> in this test the settings have // never been saved, so the empty string is expected - QCOMPARE(settings->getPersistentSettingsVersion(), QString()); + QCOMPARE(mSettings->getPersistentSettingsVersion(), QString()); - settings->save(); - QCOMPARE(settings->getPersistentSettingsVersion(), QCoreApplication::applicationVersion()); + mSettings->save(); + QCOMPARE(mSettings->getPersistentSettingsVersion(), QCoreApplication::applicationVersion()); } void testTransportPinReminder() { - bool initialValue = settings->isTransportPinReminder(); + bool initialValue = mSettings->isTransportPinReminder(); bool newValue = !initialValue; - QVERIFY(!settings->isUnsaved()); - settings->setTransportPinReminder(newValue); - QCOMPARE(settings->isTransportPinReminder(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); + mSettings->save(); + mSettings->setTransportPinReminder(newValue); + QCOMPARE(mSettings->isTransportPinReminder(), newValue); + mSettings->save(); - QVERIFY(!settings->isUnsaved()); - settings->setTransportPinReminder(initialValue); - QCOMPARE(settings->isTransportPinReminder(), initialValue); - QVERIFY(settings->isUnsaved()); - settings->save(); + mSettings->setTransportPinReminder(initialValue); + QCOMPARE(mSettings->isTransportPinReminder(), initialValue); + mSettings->save(); + } + + + void testLanguage() + { + const QLocale::Language initialValue = mSettings->getLanguage(); + const QLocale::Language newValue = QLocale::English; + + mSettings->save(); + mSettings->setLanguage(newValue); + QCOMPARE(mSettings->getLanguage(), newValue); + mSettings->save(); + + mSettings->setLanguage(initialValue); + QCOMPARE(mSettings->getLanguage(), initialValue); } diff --git a/test/qt/settings/test_HistorySettings.cpp b/test/qt/settings/test_HistorySettings.cpp index 42fdaeb..bc337df 100644 --- a/test/qt/settings/test_HistorySettings.cpp +++ b/test/qt/settings/test_HistorySettings.cpp @@ -1,12 +1,10 @@ /*! - * test_History.h - * * \brief Unit tests for History. * * All tests ends with _QTEST to be able to identify them later. * All original history entry from AusweisApp2 do not have this. * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ #include "HistorySettings.h" @@ -33,79 +31,52 @@ class test_HistorySettings } - void testEquals() - { - QScopedPointer otherSettings(new HistorySettings()); - - QVERIFY(*settings == *otherSettings); - - settings->setEnabled(!settings->isEnabled()); - QVERIFY(*settings != *otherSettings); - otherSettings->setEnabled(settings->isEnabled()); - QVERIFY(*settings == *otherSettings); - - HistoryEntry entry("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", "pRequestedData"); - settings->addHistoryEntry(entry); - QVERIFY(*settings != *otherSettings); - otherSettings->addHistoryEntry(entry); - QVERIFY(*settings == *otherSettings); - - } - - void testEnabled() { bool initial = settings->isEnabled(); settings->setEnabled(!initial); QCOMPARE(settings->isEnabled(), !initial); - QVERIFY(settings->isUnsaved()); settings->save(); - QVERIFY(!settings->isUnsaved()); settings->setEnabled(initial); QCOMPARE(settings->isEnabled(), initial); - settings->save(); } void testHistoryEntries() { - QVector initial = settings->getHistoryEntries(); - HistoryEntry entry("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", "pRequestedData"); - QVector newValue(initial); - newValue.prepend(entry); // new values will be prepended, so that it appears on top + QVector initial = settings->getHistoryInfos(); + HistoryInfo info("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", "pRequestedData"); + QVector newValue(initial); + newValue.prepend(info); // new values will be prepended, so that it appears on top - settings->addHistoryEntry(entry); - QCOMPARE(settings->getHistoryEntries(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); + settings->addHistoryInfo(info); + QCOMPARE(settings->getHistoryInfos(), newValue); } void testDeleteHistory() { - HistoryEntry entry("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", "pRequestedData"); - settings->addHistoryEntry(entry); + HistoryInfo info("pSubjectName", "pSubjectUrl", "pUsage", QDateTime(), "pTermOfUsage", "pRequestedData"); + settings->addHistoryInfo(info); - QCOMPARE(settings->getHistoryEntries().size(), 1); + QCOMPARE(settings->getHistoryInfos().size(), 1); settings->deleteSettings(); - QCOMPARE(settings->getHistoryEntries().size(), 0); + QCOMPARE(settings->getHistoryInfos().size(), 0); } void testDeleteHistoryFromFile() { - settings->load(); const auto file = AbstractSettings::mTestDir->path() + QStringLiteral("/dummy/Test_settings_HistorySettings.ini"); - HistoryEntry entry("pSubjectXYZ", "pSubjectUrlXYZ", "pUsageXYZ", QDateTime(), "pTermOfUsageXYZ", "pRequestedDataXYZ"); - settings->addHistoryEntry(entry); - settings->addHistoryEntry(entry); - settings->addHistoryEntry(entry); + HistoryInfo info("pSubjectXYZ", "pSubjectUrlXYZ", "pUsageXYZ", QDateTime(), "pTermOfUsageXYZ", "pRequestedDataXYZ"); + settings->addHistoryInfo(info); + settings->addHistoryInfo(info); + settings->addHistoryInfo(info); settings->save(); QVERIFY(QFile::exists(file)); diff --git a/test/qt/settings/test_KeyPair.cpp b/test/qt/settings/test_KeyPair.cpp new file mode 100644 index 0000000..7bef46b --- /dev/null +++ b/test/qt/settings/test_KeyPair.cpp @@ -0,0 +1,94 @@ +/*! + * \brief Unit tests for \ref CertificateGenerator + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "KeyPair.h" + +#include "TlsChecker.h" + +#include +#include + +using namespace governikus; + + +class test_KeyPair + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void validKey() + { + const KeyPair pair = KeyPair::generate(); + QVERIFY(pair.isValid()); + const auto& key = pair.getKey(); + QVERIFY(!key.isNull()); + QCOMPARE(key.length(), 2048); + QCOMPARE(key.algorithm(), QSsl::Rsa); + QCOMPARE(key.type(), QSsl::PrivateKey); + } + + + void multiKey() + { + const KeyPair pair1 = KeyPair::generate(); + QVERIFY(!pair1.getKey().isNull()); + + const KeyPair pair2 = KeyPair::generate(); + QVERIFY(!pair2.getKey().isNull()); + + QVERIFY(pair1.getKey() != pair2.getKey()); + } + + + void validCertificate() + { + const KeyPair pair = KeyPair::generate(); + QVERIFY(pair.isValid()); + const auto& cert = pair.getCertificate(); + QVERIFY(!cert.isNull()); + QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName).size(), 1); + QCOMPARE(cert.issuerInfo(QSslCertificate::CommonName).at(0), QCoreApplication::applicationName()); + QCOMPARE(cert.issuerInfo(QSslCertificate::SerialNumber).size(), 1); + QVERIFY(cert.issuerInfo(QSslCertificate::SerialNumber).at(0).size() > 0); + QVERIFY(cert.extensions().isEmpty()); + QCOMPARE(cert.version(), QByteArray("1")); + QVERIFY(cert.isSelfSigned()); + + X509* rawCert = static_cast(cert.handle()); + const qlonglong serialNumberValue = ASN1_INTEGER_get(X509_get_serialNumber(rawCert)); + QVERIFY(serialNumberValue > 0); + QVERIFY(QByteArray::number(serialNumberValue).size() < 21); + + const auto& key = cert.publicKey(); + QCOMPARE(key.length(), 2048); + QCOMPARE(key.algorithm(), QSsl::Rsa); + QCOMPARE(key.type(), QSsl::PublicKey); + QVERIFY(TlsChecker::hasValidCertificateKeyLength(cert)); + + QVERIFY(cert.expiryDate().isValid()); + QVERIFY(cert.effectiveDate().isValid()); + QVERIFY(cert.expiryDate() > QDateTime::currentDateTime()); + QVERIFY(cert.effectiveDate() <= QDateTime::currentDateTime()); + } + + + void multiCertificate() + { + const KeyPair pair1 = KeyPair::generate(); + QVERIFY(!pair1.getCertificate().isNull()); + + const KeyPair pair2 = KeyPair::generate(); + QVERIFY(!pair2.getCertificate().isNull()); + + QVERIFY(pair1.getCertificate() != pair2.getCertificate()); + } + + +}; + +QTEST_GUILESS_MAIN(test_KeyPair) +#include "test_KeyPair.moc" diff --git a/test/qt/settings/test_PreVerificationSettings.cpp b/test/qt/settings/test_PreVerificationSettings.cpp index 625f91c..d531d6a 100644 --- a/test/qt/settings/test_PreVerificationSettings.cpp +++ b/test/qt/settings/test_PreVerificationSettings.cpp @@ -1,14 +1,17 @@ /*! * \brief Unit tests for \ref PreVerificationSettings * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2014-2017 Governikus GmbH & Co. KG, Germany */ -#include + +#include "PreVerificationSettings.h" #include "asn1/CVCertificate.h" -#include "PreVerificationSettings.h" #include "TestFileHelper.h" +#include +#include + using namespace governikus; @@ -40,11 +43,17 @@ class test_PreVerificationSettings { PreVerificationSettings settings; - QVERIFY(settings.addLinkCertificate(cvcs.at(0))); - QVERIFY(settings.addLinkCertificate(cvcs.at(1))); - QVERIFY(settings.addLinkCertificate(cvcs.at(2))); - QVERIFY(settings.addLinkCertificate(cvcs.at(3))); + settings.addLinkCertificate(cvcs.at(0)); + settings.addLinkCertificate(cvcs.at(1)); + settings.addLinkCertificate(cvcs.at(2)); + settings.addLinkCertificate(cvcs.at(3)); QCOMPARE(settings.getLinkCertificates().size(), 4); + settings.save(); + + QFile testFile(settings.mStore->fileName()); + QVERIFY(testFile.exists()); + QVERIFY(testFile.open(QIODevice::ReadOnly | QIODevice::Text)); + QCOMPARE(testFile.readAll(), QByteArray("[preverification]\nlinkcertificates\\1\\linkcertificate=@ByteArray(7f218201b67f4e82016e5f290100420e44455445535465494430303030317f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7864104096eb58bfd86252238ec2652185c43c3a56c320681a21e37a8e69ddc387c0c5f5513856efe2fdc656e604893212e29449b365e304605ac5413e75be31e641f128701015f200e44455445535465494430303030327f4c12060904007f0007030102025305fe0f01ffff5f25060100000902015f24060103000902015f3740141120a0fdfc011a52f3f72b387a3dc7aca88b4868d5ae9741780b6ff8a0b49e5f55169a2d298ef5cf95935dca0c3df3e9d42dc45f74f2066317154961e6c746)\nlinkcertificates\\2\\linkcertificate=@ByteArray(7f218201b67f4e82016e5f290100420e44455445535465494430303030327f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a786410474ff63ab838c73c303ac003dfee95cf8bf55f91e8febcb7395d942036e47cf1845ec786ec95bb453aac288ad023b6067913cf9b63f908f49304e5cfc8b3050dd8701015f200e44455445535465494430303030347f4c12060904007f0007030102025305fc0f13ffff5f25060102000501015f24060105000501015f37405c035a0611b6c58f0b5261fdd009decab7dc7a79482d5248cca119059b7d82b2157cf0c4a499bcf441efdd35e294a58c0af19a34a0762159533285acf170a505)\nlinkcertificates\\3\\linkcertificate=@ByteArray(7F2181E77F4E81A05F290100420E44455445535465494430303030347F494F060A04007F000702020202038641045B1CB1090D5064FE0AEE21BD95C062AB94C952F7D64274EAF004C2E3DA4ABFDA2D0108B2545CEAF8BAF40BDEA1D161BE8950B3353BFD267F0674EC9ACABA71D05F2010444544566549444450535430303033357F4C12060904007F0007030102025305400513FF875F25060104000201015F24060104000501025F37409389856B8DA9956BA3E9894812BA87F866646660557131EF618349BF145A0826A8FB4A9BE22589CDE868B074C3FDA73DB84F9FDC84B87B3896702E42B4FE86E7)\nlinkcertificates\\4\\linkcertificate=@ByteArray(7F218201487F4E8201005F2901004210444544566549444450535430303033357F494F060A04007F0007020202020386410400C7DEDB2117E45ACF998E9D3ED34883E0617D1614B60430CA1DF1D2ECC96BC214D97451588EF706DEAF7F68163F7C8EAADF9EA028F0F8BF5D0DD67B650907175F200E444544454D4F44455630303033387F4C12060904007F0007030102025305000513FF875F25060104000301035F2406010400040101655E732D060904007F000703010301802012CA9D0A51DF9297EABA7EBE9AB49DF2F4CF83E0DBB02772EFAD89C8AD75FCCD732D060904007F0007030103028020CB1E1940159F11DC96845B87C23B86F9BAA755A789A914BBD5B8FA9784019D1C5F37407AB2B3C8DE4B3F7136F7DA91CCAC25B26AEC5BC35AD0B603FA2FFE50CEA49F785614AD3FB2EFF1719971FBCABC95F95A9F601F9017BD73952B45E645B90B774F)\nlinkcertificates\\size=4\n")); } @@ -52,9 +61,15 @@ class test_PreVerificationSettings { PreVerificationSettings settings; - QVERIFY(settings.addLinkCertificate(cvcs.at(0))); - QVERIFY(!settings.addLinkCertificate(cvcs.at(0))); + settings.addLinkCertificate(cvcs.at(0)); + settings.addLinkCertificate(cvcs.at(0)); QCOMPARE(settings.getLinkCertificates().size(), 1); + settings.save(); + + QFile testFile(settings.mStore->fileName()); + QVERIFY(testFile.exists()); + QVERIFY(testFile.open(QIODevice::ReadOnly | QIODevice::Text)); + QCOMPARE(testFile.readAll(), QByteArray("[preverification]\nlinkcertificates\\1\\linkcertificate=@ByteArray(7f218201b67f4e82016e5f290100420e44455445535465494430303030317f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7864104096eb58bfd86252238ec2652185c43c3a56c320681a21e37a8e69ddc387c0c5f5513856efe2fdc656e604893212e29449b365e304605ac5413e75be31e641f128701015f200e44455445535465494430303030327f4c12060904007f0007030102025305fe0f01ffff5f25060100000902015f24060103000902015f3740141120a0fdfc011a52f3f72b387a3dc7aca88b4868d5ae9741780b6ff8a0b49e5f55169a2d298ef5cf95935dca0c3df3e9d42dc45f74f2066317154961e6c746)\nlinkcertificates\\size=1\n")); } @@ -65,7 +80,6 @@ class test_PreVerificationSettings settings.addLinkCertificate(cvcs.at(1)); settings.addLinkCertificate(cvcs.at(2)); settings.addLinkCertificate(cvcs.at(3)); - QVERIFY(settings.getLinkCertificates().contains(cvcs.at(0))); QVERIFY(settings.getLinkCertificates().contains(cvcs.at(1))); QVERIFY(settings.getLinkCertificates().contains(cvcs.at(2))); @@ -78,9 +92,16 @@ class test_PreVerificationSettings PreVerificationSettings settings; settings.addLinkCertificate(cvcs.at(0)); settings.addLinkCertificate(cvcs.at(1)); + settings.save(); - QVERIFY(settings.removeLinkCertificate(cvcs.at(0))); + settings.removeLinkCertificate(cvcs.at(0)); QCOMPARE(settings.getLinkCertificates().size(), 1); + settings.save(); + + QFile testFile(settings.mStore->fileName()); + QVERIFY(testFile.exists()); + QVERIFY(testFile.open(QIODevice::ReadOnly | QIODevice::Text)); + QCOMPARE(testFile.readAll(), QByteArray("[preverification]\nlinkcertificates\\1\\linkcertificate=@ByteArray(7f218201b67f4e82016e5f290100420e44455445535465494430303030327f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a786410474ff63ab838c73c303ac003dfee95cf8bf55f91e8febcb7395d942036e47cf1845ec786ec95bb453aac288ad023b6067913cf9b63f908f49304e5cfc8b3050dd8701015f200e44455445535465494430303030347f4c12060904007f0007030102025305fc0f13ffff5f25060102000501015f24060105000501015f37405c035a0611b6c58f0b5261fdd009decab7dc7a79482d5248cca119059b7d82b2157cf0c4a499bcf441efdd35e294a58c0af19a34a0762159533285acf170a505)\nlinkcertificates\\size=1\n")); } @@ -90,84 +111,18 @@ class test_PreVerificationSettings settings.addLinkCertificate(cvcs.at(0)); settings.addLinkCertificate(cvcs.at(1)); - QVERIFY(settings.removeLinkCertificate(cvcs.at(0))); - QVERIFY(!settings.removeLinkCertificate(cvcs.at(0))); + settings.removeLinkCertificate(cvcs.at(0)); + settings.removeLinkCertificate(cvcs.at(0)); QCOMPARE(settings.getLinkCertificates().size(), 1); } - void testSaveLoad() - { - PreVerificationSettings settings; - QVERIFY(settings.isEnabled()); - settings.save(); - - settings.addLinkCertificate(cvcs.at(0)); - settings.addLinkCertificate(cvcs.at(1)); - settings.setEnabled(false); - - QVERIFY(settings.isUnsaved()); - settings.save(); - QVERIFY(!settings.isUnsaved()); - - - settings.setEnabled(true); - for (const auto& cert : settings.getLinkCertificates()) - { - settings.removeLinkCertificate(cert); - } - QVERIFY(settings.getLinkCertificates().isEmpty()); - - settings.load(); - QCOMPARE(settings.getLinkCertificates().size(), 2); - QVERIFY(settings.getLinkCertificates().contains(cvcs.at(0))); - QVERIFY(settings.getLinkCertificates().contains(cvcs.at(1))); - QVERIFY(!settings.isEnabled()); - } - - void testEnabled() { PreVerificationSettings settings; QVERIFY(settings.isEnabled()); - settings.load(); - QVERIFY(settings.isEnabled()); - } - - - void testEquals() - { - PreVerificationSettings settings1; - PreVerificationSettings settings2; - - QVERIFY(settings1 == settings2); - - settings1.addLinkCertificate(cvcs.at(0)); - settings2.addLinkCertificate(cvcs.at(3)); - - QVERIFY(settings1 != settings2); - - settings1.addLinkCertificate(cvcs.at(1)); - settings2.addLinkCertificate(cvcs.at(2)); - - QVERIFY(settings1 != settings2); - - settings1.addLinkCertificate(cvcs.at(2)); - settings2.addLinkCertificate(cvcs.at(1)); - - QVERIFY(settings1 != settings2); - - settings1.addLinkCertificate(cvcs.at(3)); - settings2.addLinkCertificate(cvcs.at(0)); - - QVERIFY(settings1 == settings2); - QVERIFY(settings1 == settings1); - QVERIFY(settings2 == settings2); - - settings1.setEnabled(false); - QVERIFY(settings1 != settings2); - settings2.setEnabled(false); - QVERIFY(settings1 == settings2); + settings.setEnabled(false); + QVERIFY(!settings.isEnabled()); } diff --git a/test/qt/settings/test_ProviderSettings.cpp b/test/qt/settings/test_ProviderSettings.cpp deleted file mode 100644 index 52b699b..0000000 --- a/test/qt/settings/test_ProviderSettings.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/*! - * \brief Unit tests for \ref ProviderSettings - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include "ProviderSettings.h" - -#include -#include -#include - -using namespace governikus; - - -class test_ProviderSettings - : public QObject -{ - Q_OBJECT - QScopedPointer settings; - - private Q_SLOTS: - void init() - { - AbstractSettings::mTestDir.clear(); - settings.reset(new ProviderSettings()); - } - - - void testEquals() - { - QScopedPointer otherSettings(new ProviderSettings()); - otherSettings->load(); - - QVERIFY(*settings == *otherSettings); - - settings.reset(new ProviderSettings(settings->getIssueDate().addDays(1), settings->getProviders())); - QVERIFY(*settings != *otherSettings); - otherSettings.reset(new ProviderSettings(settings->getIssueDate(), settings->getProviders())); - QVERIFY(*settings == *otherSettings); - - QVector providers(settings->getProviders()); - providers.append(Provider(QStringLiteral("prov"), QStringLiteral("http://address.de"))); - settings.reset(new ProviderSettings(settings->getIssueDate(), providers)); - QVERIFY(*settings != *otherSettings); - otherSettings.reset(new ProviderSettings(settings->getIssueDate(), settings->getProviders())); - QVERIFY(*settings == *otherSettings); - - providers.removeAt(providers.size() - 1); - providers.append(Provider(QStringLiteral("prov2"), QStringLiteral("http://address2.de"))); - settings.reset(new ProviderSettings(settings->getIssueDate(), providers)); - QVERIFY(*settings != *otherSettings); - otherSettings.reset(new ProviderSettings(settings->getIssueDate(), settings->getProviders())); - QVERIFY(*settings == *otherSettings); - } - - - void testDate() - { - QDateTime initial = settings->getIssueDate(); - QDateTime newValue = QDateTime::currentDateTime().addDays(1); - - QEXPECT_FAIL("", "needs to be different", Continue); - QCOMPARE(settings->getIssueDate(), newValue); - - settings.reset(new ProviderSettings(newValue, settings->getProviders())); - QCOMPARE(settings->getIssueDate(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); - - settings.reset(new ProviderSettings(initial, settings->getProviders())); - QCOMPARE(settings->getIssueDate(), initial); - settings->save(); - } - - - void testProviders() - { - QVector initial = settings->getProviders(); - QVector newValue(initial); - newValue.append(Provider(QStringLiteral("name"), QStringLiteral("https://address.de"))); - - settings.reset(new ProviderSettings(settings->getIssueDate(), newValue)); - QCOMPARE(settings->getProviders(), newValue); - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); - - settings.reset(new ProviderSettings(settings->getIssueDate(), initial)); - QCOMPARE(settings->getProviders(), initial); - settings->save(); - } - - - 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())); - settings->save(); - QVERIFY(!settings->isUnsaved()); - - // Add image and icon. - const Provider provider( - /* short name */ QStringLiteral("Provider 1"), - /* long name */ QStringLiteral("Provider 1 - long name"), - /* short description */ QStringLiteral("Provider description short"), - /* long description */ QStringLiteral("Provider description long"), - /* address */ QStringLiteral("https://www.homepage.com/form/"), - /* homepage */ QStringLiteral("https://www.homepage.com/"), - /* category */ QStringLiteral("Category A"), - /* phone */ QStringLiteral("0421 123456"), - /* 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"), - /* 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 - }; - settings.reset(new ProviderSettings(settings->getIssueDate(), providers)); - - QVERIFY(settings->isUnsaved()); - settings->save(); - QVERIFY(!settings->isUnsaved()); - - QScopedPointer otherSettings(new ProviderSettings()); - otherSettings->load(); - const QVector otherProviders = otherSettings->getProviders(); - QCOMPARE(otherProviders.size(), 1); - - const Provider otherProvider = otherProviders.at(0); - QCOMPARE(otherProvider.getShortName().toString(), QStringLiteral("Provider 1")); - QCOMPARE(otherProvider.getLongName().toString(), QStringLiteral("Provider 1 - long name")); - QCOMPARE(otherProvider.getShortDescription().toString(), QStringLiteral("Provider description short")); - QCOMPARE(otherProvider.getLongDescription().toString(), QStringLiteral("Provider description long")); - QCOMPARE(otherProvider.getAddress(), QStringLiteral("https://www.homepage.com/form/")); - QCOMPARE(otherProvider.getHomepage(), QStringLiteral("https://www.homepage.com/")); - QCOMPARE(otherProvider.getCategory(), QStringLiteral("Category A")); - QCOMPARE(otherProvider.getPhone(), QStringLiteral("0421 123456")); - QCOMPARE(otherProvider.getEMail(), QStringLiteral("abc@def.de")); - 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()); - } - - -}; - -QTEST_GUILESS_MAIN(test_ProviderSettings) -#include "test_ProviderSettings.moc" diff --git a/test/qt/settings/test_RemoteReaderSettings.cpp b/test/qt/settings/test_RemoteReaderSettings.cpp deleted file mode 100644 index 2ca9a04..0000000 --- a/test/qt/settings/test_RemoteReaderSettings.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/*! - * \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_RemoteServiceSettings.cpp b/test/qt/settings/test_RemoteServiceSettings.cpp new file mode 100644 index 0000000..80e2ad9 --- /dev/null +++ b/test/qt/settings/test_RemoteServiceSettings.cpp @@ -0,0 +1,283 @@ +/*! + * \brief Unit tests for \ref RemoteSertviceSettings + * + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteServiceSettings.h" + +#include "DeviceInfo.h" +#include "KeyPair.h" +#include "TestFileHelper.h" + +#include + +using namespace governikus; + + +class test_RemoteServiceSettings + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void init() + { + AbstractSettings::mTestDir.clear(); + } + + + void testStandardValues() + { + RemoteServiceSettings settings; + + QCOMPARE(settings.getServerName(), DeviceInfo::getName()); + } + + + void testServerName() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getServerName(), DeviceInfo::getName()); + settings.save(); + QCOMPARE(settings.getServerName(), DeviceInfo::getName()); + settings.setServerName(QLatin1String("Google Pixel")); + QCOMPARE(settings.getServerName(), QLatin1String("Google Pixel")); + } + + + void testPinPadMode() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getPinPadMode(), false); + settings.save(); + QCOMPARE(settings.getPinPadMode(), false); + settings.setPinPadMode(true); + QCOMPARE(settings.getPinPadMode(), true); + } + + + void testDuplicatedTrustedCertificates() + { + const KeyPair pair1 = KeyPair::generate(); + const KeyPair pair2 = KeyPair::generate(); + const KeyPair pair3 = KeyPair::generate(); + + RemoteServiceSettings settings; + QVERIFY(settings.getTrustedCertificates().isEmpty()); + + const QList certs{ + pair1.getCertificate(), pair1.getCertificate(), pair2.getCertificate() + }; + settings.setTrustedCertificates(certs); + + auto storedCerts = settings.getTrustedCertificates(); + QCOMPARE(storedCerts.size(), 2); + QVERIFY(storedCerts.contains(pair1.getCertificate())); + QVERIFY(storedCerts.contains(pair2.getCertificate())); + + settings.addTrustedCertificate(pair3.getCertificate()); + storedCerts = settings.getTrustedCertificates(); + QCOMPARE(storedCerts.size(), 3); + QVERIFY(storedCerts.contains(pair1.getCertificate())); + QVERIFY(storedCerts.contains(pair2.getCertificate())); + QVERIFY(storedCerts.contains(pair3.getCertificate())); + + settings.addTrustedCertificate(pair3.getCertificate()); + QCOMPARE(storedCerts.size(), 3); + QVERIFY(storedCerts.contains(pair1.getCertificate())); + QVERIFY(storedCerts.contains(pair2.getCertificate())); + QVERIFY(storedCerts.contains(pair3.getCertificate())); + } + + + void testTrustedCertificates() + { + const KeyPair pair1 = KeyPair::generate(); + + RemoteServiceSettings settings; + QVERIFY(settings.getTrustedCertificates().isEmpty()); + QList certs; + certs << QSslCertificate(); + certs << pair1.getCertificate(); + + settings.setTrustedCertificates(certs); + auto storedCerts = settings.getTrustedCertificates(); + QCOMPARE(settings.getTrustedCertificates().size(), 2); + for (const auto& entry : qAsConst(certs)) + { + QVERIFY(storedCerts.contains(entry)); + } + + certs.pop_front(); + QCOMPARE(storedCerts.size(), 2); + + const KeyPair pair2 = KeyPair::generate(); + QVERIFY(!storedCerts.contains(pair2.getCertificate())); + settings.addTrustedCertificate(pair2.getCertificate()); + storedCerts = settings.getTrustedCertificates(); + QCOMPARE(storedCerts.size(), 3); + + certs << pair2.getCertificate(); + for (const auto& entry : qAsConst(certs)) + { + QVERIFY(storedCerts.contains(entry)); + } + + settings.setTrustedCertificates({}); + QCOMPARE(settings.getTrustedCertificates().size(), 0); + } + + + void testRemoveTrustedCertificates() + { + RemoteServiceSettings settings; + QVERIFY(settings.getTrustedCertificates().isEmpty()); + + const KeyPair pair1 = KeyPair::generate(); + const KeyPair pair2 = KeyPair::generate(); + settings.addTrustedCertificate(pair1.getCertificate()); + settings.addTrustedCertificate(pair2.getCertificate()); + QCOMPARE(settings.getTrustedCertificates().size(), 2); + + const auto& fingerprint = QString::fromLatin1(pair1.getCertificate().digest(QCryptographicHash::Sha256).toHex()); + settings.removeTrustedCertificate(fingerprint); + QCOMPARE(settings.getTrustedCertificates().size(), 1); + QCOMPARE(settings.getTrustedCertificates().at(0), pair2.getCertificate()); + } + + + void testKey() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getKey(), QSslKey()); + settings.save(); + QCOMPARE(settings.getKey(), QSslKey()); + + const KeyPair pair = KeyPair::generate(); + settings.setKey(pair.getKey()); + QCOMPARE(settings.getKey(), pair.getKey()); + QVERIFY(!settings.getKey().isNull()); + settings.save(); + } + + + void testCertificate() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getCertificate(), QSslCertificate()); + settings.save(); + QCOMPARE(settings.getCertificate(), QSslCertificate()); + + const KeyPair pair = KeyPair::generate(); + settings.setCertificate(pair.getCertificate()); + QCOMPARE(settings.getCertificate(), pair.getCertificate()); + QVERIFY(!settings.getCertificate().isNull()); + settings.save(); + } + + + void testRemoteInfos() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getRemoteInfos().size(), 0); + + const auto& current = QDateTime::currentDateTime(); + RemoteServiceSettings::RemoteInfo a(QString("a"), current, QString("dummy for A")); + RemoteServiceSettings::RemoteInfo b(QString("b"), current, QString("dummy for B")); + + QVERIFY(a == a); + QVERIFY(b == b); + QVERIFY(a != b); + settings.setRemoteInfos({a, b}); + QCOMPARE(settings.getRemoteInfos().size(), 2); + + auto first = settings.getRemoteInfos().at(0); + auto second = settings.getRemoteInfos().at(1); + QCOMPARE(first, a); + QCOMPARE(second, b); + QCOMPARE(first.getFingerprint(), QString("a")); + QCOMPARE(first.getName(), QString("dummy for A")); + QCOMPARE(first.getLastConnected(), current); + QCOMPARE(second.getFingerprint(), QString("b")); + QCOMPARE(second.getName(), QString("dummy for B")); + QCOMPARE(second.getLastConnected(), current); + + settings.setRemoteInfos({}); + QCOMPARE(settings.getRemoteInfos().size(), 0); + + settings.setRemoteInfos({a, b}); + QCOMPARE(settings.getRemoteInfos().size(), 2); + } + + + void testRemoteInfosUpdates() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getRemoteInfos().size(), 0); + + auto a = KeyPair::generate().getCertificate(); + auto b = KeyPair::generate().getCertificate(); + + settings.addTrustedCertificate(a); + settings.addTrustedCertificate(b); + QCOMPARE(settings.getRemoteInfos().size(), 2); + QCOMPARE(settings.getRemoteInfos().at(0).getName(), QString()); + + auto aInfo = settings.getRemoteInfo(a); + aInfo.setName(QString("dummy")); + QVERIFY(settings.updateRemoteInfo(aInfo)); + QCOMPARE(settings.getRemoteInfos().at(0).getName(), QString("dummy")); + QCOMPARE(settings.getRemoteInfos().size(), 2); + + auto c = KeyPair::generate().getCertificate(); + auto cInfo = settings.getRemoteInfo(c); + QCOMPARE(cInfo.getFingerprint(), QString()); + QCOMPARE(settings.getRemoteInfos().size(), 2); + + settings.addTrustedCertificate(c); + cInfo = settings.getRemoteInfo(c); + cInfo.setName("c"); + settings.updateRemoteInfo(cInfo); + QCOMPARE(settings.getRemoteInfos().size(), 3); + QCOMPARE(settings.getRemoteInfos().at(0).getName(), QString("dummy")); + QCOMPARE(settings.getRemoteInfos().at(1).getName(), QString()); + QCOMPARE(settings.getRemoteInfos().at(2).getName(), QString("c")); + QCOMPARE(settings.getRemoteInfos().at(2).getFingerprint(), + QString::fromLatin1(c.digest(QCryptographicHash::Sha256).toHex())); + } + + + void testRemoteInfosSync() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getRemoteInfos().size(), 0); + QVERIFY(!settings.updateRemoteInfo(RemoteServiceSettings::RemoteInfo())); + + auto a = KeyPair::generate().getCertificate(); + settings.addTrustedCertificate(a); + + auto aInfo = settings.getRemoteInfo(a); + aInfo.setName("hallo"); + QVERIFY(settings.updateRemoteInfo(aInfo)); + + QCOMPARE(settings.getRemoteInfos().size(), 1); + QCOMPARE(settings.getRemoteInfos().at(0).getName(), QString("hallo")); + } + + + void testGenerateFingerprint() + { + QCOMPARE(RemoteServiceSettings::generateFingerprint(QSslCertificate()), QLatin1String()); + auto cert = KeyPair::generate().getCertificate(); + QVERIFY(!cert.isNull()); + const auto& fingerprint = QString::fromLatin1(cert.digest(QCryptographicHash::Sha256).toHex()); + QVERIFY(!fingerprint.isEmpty()); + QCOMPARE(RemoteServiceSettings::generateFingerprint(cert), fingerprint); + } + + +}; + +QTEST_GUILESS_MAIN(test_RemoteServiceSettings) +#include "test_RemoteServiceSettings.moc" diff --git a/test/qt/settings/test_SecureStorage.cpp b/test/qt/settings/test_SecureStorage.cpp deleted file mode 100644 index dfbfb80..0000000 --- a/test/qt/settings/test_SecureStorage.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/*! - * \brief Unit tests for \ref SecureStorage - * - * \copyright Copyright (c) 2014 Governikus GmbH & Co. KG - */ - -#include -#include -#include - -#include "SecureStorage.h" - -#include "asn1/CVCertificate.h" - -using namespace governikus; - -class test_SecureStorage - : public QObject -{ - Q_OBJECT - SecureStorage secureStorage; - - private Q_SLOTS: - void initTestCase() - { - AbstractSettings::mTestDir.clear(); - secureStorage.load(); - } - - - void unloaded() - { - SecureStorage store1; - SecureStorage store2; - QCOMPARE(store1, store2); - store1.load(); - QVERIFY(store1 != store2); - store2.load(); - QCOMPARE(store1, store2); - } - - - void testGetCVRootCertificates() - { - QVector > cvcs = CVCertificate::fromHex(secureStorage.getCVRootCertificates(true)); - cvcs += CVCertificate::fromHex(secureStorage.getCVRootCertificates(false)); - - const int count = cvcs.count(); - QCOMPARE(count, 10); - - // 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); - } - } - } - - - void testGetUpdateCertificate() - { - QVector certificates = secureStorage.getUpdateCertificates(); - QCOMPARE(certificates.count(), 3); - } - - - void testGetSelfAuthentication() - { - QVERIFY(secureStorage.getSelfAuthenticationUrl(false).isValid()); - QVERIFY(secureStorage.getSelfAuthenticationUrl(true).isValid()); - QVERIFY(!secureStorage.getSelfAuthenticationCertDescr(false).isEmpty()); - QVERIFY(!secureStorage.getSelfAuthenticationCertDescr(true).isEmpty()); - } - - - void testGetProvidersUpdateUrl() - { - QVERIFY(secureStorage.getProviderUpdateUrl().isValid()); - } - - - void testAppcast() - { - 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() - { - 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() - { - 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.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.getTlsSettingsPsk().getCiphers(); - QCOMPARE(ciphersPsk.count(), 5); - QCOMPARE(ciphersPsk.first(), QSslCipher("RSA-PSK-AES256-GCM-SHA384")); - QCOMPARE(ciphersPsk.last(), QSslCipher("RSA-PSK-AES256-CBC-SHA")); - - const auto& ciphersEc = secureStorage.getTlsSettings().getEllipticCurves(); - QCOMPARE(ciphersEc.count(), 6); - QCOMPARE(ciphersEc.first(), QSslEllipticCurve::fromLongName("brainpoolP512r1")); - QCOMPARE(ciphersEc.last(), QSslEllipticCurve::fromLongName("secp224r1")); - } - - - void loadChangedFileOnly() - { - QBENCHMARK - { - secureStorage.load(); - } - } - - - void getSslProtocolVersion() - { - QCOMPARE(secureStorage.getTlsSettings().getProtocolVersion(), QSsl::SslProtocol::TlsV1_0OrLater); - } - - - void getSslProtocolVersionPsk() - { - 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); - } - - -}; - -QTEST_GUILESS_MAIN(test_SecureStorage) -#include "test_SecureStorage.moc" diff --git a/test/qt/settings/test_TlsSettings.cpp b/test/qt/settings/test_TlsSettings.cpp deleted file mode 100644 index fb4defd..0000000 --- a/test/qt/settings/test_TlsSettings.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/*! - * \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 index 94a66b0..d44728d 100644 --- a/test/qt/websocket/test_UIPlugInWebSocket.cpp +++ b/test/qt/websocket/test_UIPlugInWebSocket.cpp @@ -1,7 +1,7 @@ /*! * \brief Unit tests for \ref UIPlugInWebSocket * - * \copyright Copyright (c) 2016 Governikus GmbH & Co. KG + * \copyright Copyright (c) 2016-2017 Governikus GmbH & Co. KG, Germany */ #include "UIPlugInWebSocket.h" @@ -33,10 +33,6 @@ class test_UIPlugInWebSocket #ifdef Q_OS_WIN QSKIP("Not supported"); #endif - - #ifdef Q_OS_BSD4 - QSKIP("TODO: Platform plugin seems broken"); - #endif } @@ -124,6 +120,10 @@ class test_UIPlugInWebSocket void tryLocalhostAuth() { + #ifdef Q_OS_FREEBSD + QSKIP("Not supported"); + #endif + mHelper->sendMessage("{\"cmd\": \"RUN_AUTH\", \"tcTokenURL\" : \"https://localhost/\"}"); QVERIFY(mHelper->waitForMessage([](const QJsonObject& pMessage){ return pMessage["msg"] == "AUTH"; diff --git a/test/qt/widget/test_HelpAction.cpp b/test/qt/widget/test_HelpAction.cpp new file mode 100644 index 0000000..fdf93a5 --- /dev/null +++ b/test/qt/widget/test_HelpAction.cpp @@ -0,0 +1,161 @@ +/*! + * \brief Unit tests for \ref HelpAction + * + * \copyright Copyright (c) 2015-2017 Governikus GmbH & Co. KG, Germany + */ + +#include "TestFileHelper.h" + +#include + +#include "generic/HelpAction.h" +#include "LanguageLoader.h" + +using namespace governikus; + +class test_HelpAction + : public QObject +{ + Q_OBJECT + + QDir helpDir = QCoreApplication::applicationDirPath() + QStringLiteral("/help/"); + QTemporaryDir mTranslationDir; + + void loadLanguage(QLocale::Language pLang) + { + if (LanguageLoader::getInstance().isLoaded()) + { + LanguageLoader::getInstance().unload(); + } + + LanguageLoader::getInstance().load(pLang); + QCOMPARE(LanguageLoader::getInstance().getUsedLocale().language(), pLang); + } + + + QString toWebUrl(const QString& pLang = QStringLiteral("en")) + { + #ifdef Q_OS_MACOS + const QString sys = "macOS"; + #else + const QString sys = "Windows"; + #endif + + return QStringLiteral("https://www.ausweisapp.bund.de/ausweisapp2/handbuch/1.9/%1/%2/index.html").arg(pLang, sys); + } + + + QString toUrl(const char* pStr) + { + return QUrl::fromLocalFile(helpDir.path()).toString() + QString::fromLatin1(pStr); + } + + + private Q_SLOTS: + void init() + { + QCoreApplication::setApplicationVersion(QStringLiteral("1.9")); + QVERIFY(!helpDir.exists()); + } + + + void initTestCase() + { + TestFileHelper::createTranslations(mTranslationDir.path()); + LanguageLoader::getInstance().setPath(mTranslationDir.path()); + } + + + void cleanup() + { + QVERIFY(helpDir.removeRecursively()); + if (LanguageLoader::getInstance().isLoaded()) + { + LanguageLoader::getInstance().unload(); + } + } + + + void escapedMapping() + { + QVERIFY(helpDir.mkpath(helpDir.path())); + + QVERIFY(helpDir.mkdir("de")); + loadLanguage(QLocale::German); + + QString padding; + if (QSysInfo::prettyProductName().startsWith(QLatin1String("Windows"))) + { + padding = '/'; + } + + QCOMPARE(HelpAction::getInstance().getHelpUrl("generalTab"), "file://" + padding + helpDir.path() + "/de/settings-general.html"); + } + + + void nonExistingHelpDir() + { + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); + + loadLanguage(QLocale::English); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); + + loadLanguage(QLocale::German); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); + + loadLanguage(QLocale::Italian); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); + } + + + void existingHelpDir() + { + QVERIFY(helpDir.mkpath(helpDir.path())); + + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); + + loadLanguage(QLocale::English); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl()); + + loadLanguage(QLocale::German); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("de")); + + loadLanguage(QLocale::Italian); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toWebUrl("it")); + } + + + void existingLanguageHelpDir() + { + QVERIFY(helpDir.mkpath(helpDir.path())); + + QVERIFY(helpDir.mkdir("en")); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); + + QVERIFY(helpDir.mkdir("de")); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); + + loadLanguage(QLocale::German); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/de/index.html")); + + loadLanguage(QLocale::Italian); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); + + LanguageLoader::getInstance().unload(); + QCOMPARE(HelpAction::getInstance().getHelpUrl(""), toUrl("/en/index.html")); + } + + + void contextMap() + { + QCOMPARE(HelpAction::getInstance().getContextMapping(""), QString("index.html")); + + QCOMPARE(HelpAction::getInstance().getContextMapping("pinTab"), QString("settings-pin-management.html")); + QCOMPARE(HelpAction::getInstance().getContextMapping("unknown"), QString("index.html")); + } + + +}; + +QTEST_MAIN(test_HelpAction) +#include "test_HelpAction.moc" diff --git a/test/qt/widget/test_ReaderDriverModel.cpp b/test/qt/widget/test_ReaderDriverModel.cpp new file mode 100644 index 0000000..35b473d --- /dev/null +++ b/test/qt/widget/test_ReaderDriverModel.cpp @@ -0,0 +1,184 @@ +/*! + * \copyright Copyright (c) 2017 Governikus GmbH & Co. KG, Germany + */ + +#include "ReaderDriverModel.h" + +#include "Env.h" +#include "MockReaderConfiguration.h" +#include "MockReaderDetector.h" +#include "ReaderManager.h" +#include "ResourceLoader.h" + +#include +#include + + +using namespace governikus; + + +class MockReaderManager + : public ReaderManager +{ + Q_OBJECT + + private: + const QVector& mReaderInfos; + + public: + MockReaderManager(const QVector& pReaderInfos); + QVector getReaderInfos(const ReaderFilter& pFilter = ReaderFilter()) const override; +}; + + +MockReaderManager::MockReaderManager(const QVector& pReaderInfos) : + mReaderInfos(pReaderInfos) +{ +} + + +QVector MockReaderManager::getReaderInfos(const ReaderFilter& pFilter) const +{ + Q_UNUSED(pFilter); + return mReaderInfos; +} + + +class test_ReaderDriverModel + : public QObject +{ + Q_OBJECT + + public: + test_ReaderDriverModel() + : mMockReaderConfiguration() + , mUsbIds() + , mMockReaderDetector(mUsbIds) + , mReaderInfos() + , mMockReaderManager(mReaderInfos) + { + Env::set(ReaderDetector::staticMetaObject, &mMockReaderDetector); + Env::set(ReaderManager::staticMetaObject, &mMockReaderManager); + } + + + private: + QScopedPointer mMockReaderConfiguration; + + QVector mUsbIds; + MockReaderDetector mMockReaderDetector; + + QVector mReaderInfos; + MockReaderManager mMockReaderManager; + + private Q_SLOTS: + void initTestCase() + { + ResourceLoader::getInstance().init(); + } + + + void init() + { + mMockReaderConfiguration.reset(new MockReaderConfiguration()); + Env::set(ReaderConfiguration::staticMetaObject, mMockReaderConfiguration.data()); + + mUsbIds.clear(); + mReaderInfos.clear(); + } + + + void cleanup() + { + mMockReaderConfiguration.reset(); + } + + + void test_empty() + { + mMockReaderConfiguration->clearReaderConfiguration(); + + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 0); + } + + + void test_01_settings() + { + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 0); + } + + + void test_02_usbId() + { +#if defined(Q_OS_FREEBSD) + QSKIP("No driver available for UsbId(0x0C4B, 0x0501) on FreeBSD"); +#endif + + mUsbIds += UsbId(0x0C4B, 0x0501); // REINER SCT cyberJack RFID komfort + + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 1); + const auto& index = readerDriverModel.index(0, ReaderDriverModel::ColumnId::ReaderStatus, QModelIndex()); + QCOMPARE(readerDriverModel.data(index).toString(), tr("Connected w/o driver")); + } + + + void test_03_usbId_unknown() + { + mUsbIds += UsbId(0x1, 0x2); // Unknown + + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 0); + } + + + void test_04_usbId_readerManager_equal() + { +#if defined(Q_OS_FREEBSD) + QSKIP("No driver available for UsbId(0x0D46, 0x301D) on FreeBSD"); +#endif + mUsbIds += UsbId(0x0D46, 0x301D); // KOBIL Systems IDToken + mReaderInfos += ReaderInfo("KOBIL Systems IDToken (NS1252PT188E1) 00 00", ReaderManagerPlugInType::PCSC); + + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 1); + const auto& index = readerDriverModel.index(0, ReaderDriverModel::ColumnId::ReaderStatus, QModelIndex()); + QCOMPARE(readerDriverModel.data(index).toString(), tr("Connected w/ driver")); + } + + + void test_05_usbId_readerManager_different() + { +#if defined(Q_OS_FREEBSD) + QSKIP("No driver available for UsbId(0x0C4B, 0x0501) on FreeBSD"); +#endif + mUsbIds += UsbId(0x0C4B, 0x0501); // REINER SCT cyberJack RFID komfort + mUsbIds += UsbId(0x0D46, 0x301D); // KOBIL Systems IDToken + mReaderInfos += ReaderInfo("KOBIL Systems IDToken (NS1252PT188E1) 00 00", ReaderManagerPlugInType::PCSC); + + QModelIndex index; + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 2); + index = readerDriverModel.index(0, ReaderDriverModel::ColumnId::ReaderStatus, QModelIndex()); + QCOMPARE(readerDriverModel.data(index).toString(), tr("Connected w/ driver")); + index = readerDriverModel.index(1, ReaderDriverModel::ColumnId::ReaderStatus, QModelIndex()); + QCOMPARE(readerDriverModel.data(index).toString(), tr("Connected w/o driver")); + } + + + void test_06_settings_readerManager_unknown() + { + mReaderInfos += ReaderInfo("Governikus Special Reader", ReaderManagerPlugInType::PCSC); + + ReaderDriverModel readerDriverModel; + QCOMPARE(readerDriverModel.rowCount(), 0); + } + + +}; + + +QTEST_MAIN(test_ReaderDriverModel) +#include "test_ReaderDriverModel.moc" diff --git a/uncrustify.cfg b/uncrustify.cfg index 34de8e4..9d76576 100644 --- a/uncrustify.cfg +++ b/uncrustify.cfg @@ -1,245 +1,595 @@ -set private Q_SIGNALS -macro-open ASN1_ITEM_TEMPLATE ASN1_SEQUENCE -macro-close ASN1_ITEM_TEMPLATE_END ASN1_SEQUENCE_END -tok_split_gte=false -utf8_byte=false -utf8_force=false -indent_cmt_with_tabs=false -indent_align_string=true -indent_braces=false -indent_braces_no_func=false -indent_braces_no_class=false -indent_braces_no_struct=false -indent_brace_parent=false -indent_namespace=false -indent_extern=false -indent_class=true -indent_class_colon=false -indent_else_if=false -indent_var_def_cont=false -indent_func_call_param=true -indent_func_def_param=true -indent_func_proto_param=false -indent_func_class_param=false -indent_func_ctor_var_param=false -indent_template_param=false -indent_func_param_double=true -indent_relative_single_line_comments=false -indent_col1_comment=true -indent_access_spec_body=true -indent_paren_nl=false -indent_comma_paren=false -indent_bool_paren=false -indent_first_bool_expr=false -indent_square_nl=false -indent_preserve_sql=false -indent_align_assign=true -sp_balance_nested_parens=false -align_keep_tabs=false -align_with_tabs=true -align_on_tabstop=false -align_number_left=false -align_func_params=false -align_same_func_call_params=false -align_var_def_colon=false -align_var_def_attribute=false -align_var_def_inline=false -align_right_cmt_mix=false -align_on_operator=false -align_mix_var_proto=false -align_single_line_func=true -align_single_line_brace=false -align_nl_cont=false -align_left_shift=true -align_oc_decl_colon=false -nl_collapse_empty_body=false -nl_assign_leave_one_liners=false -nl_class_leave_one_liners=false -nl_enum_leave_one_liners=false -nl_getset_leave_one_liners=false -nl_func_leave_one_liners=false -nl_if_leave_one_liners=false -nl_multi_line_cond=false -nl_multi_line_define=false -nl_before_case=true -nl_after_case=true -nl_after_return=true -nl_after_semicolon=true -nl_after_brace_open=true -nl_after_brace_open_cmt=false -nl_after_vbrace_open=false -nl_after_vbrace_open_empty=false -nl_after_brace_close=true -nl_after_vbrace_close=true -nl_define_macro=false -nl_squeeze_ifdef=false -nl_ds_struct_enum_cmt=false -nl_ds_struct_enum_close_brace=false -nl_create_if_one_liner=false -nl_create_for_one_liner=false -nl_create_while_one_liner=false -ls_for_split_full=false -ls_func_split_full=false -nl_after_multiline_comment=false -eat_blanks_after_open_brace=false -eat_blanks_before_close_brace=false -mod_full_brace_if_chain=false -mod_pawn_semicolon=false -mod_full_paren_if_bool=false -mod_remove_extra_semicolon=true -mod_sort_import=true -mod_sort_using=false -mod_sort_include=true -mod_move_case_break=false -mod_remove_empty_return=false -cmt_indent_multi=true -cmt_c_group=false -cmt_c_nl_start=false -cmt_c_nl_end=false -cmt_cpp_group=false -cmt_cpp_nl_start=false -cmt_cpp_nl_end=false -cmt_cpp_to_c=false -cmt_star_cont=false -cmt_multi_check_last=true -cmt_insert_before_preproc=false -pp_indent_at_level=false -pp_region_indent_code=false -pp_if_indent_code=false -pp_define_at_level=false -input_tab_size=4 -output_tab_size=4 -indent_columns=4 -indent_continue=8 -indent_ctor_init=0 -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 -nl_after_class=2 -nl_before_access_spec=2 -nl_after_access_spec=1 -nl_comment_func_def=1 -newlines=lf -utf8_bom=remove -indent_with_tabs=2 -sp_before_for_colon=force -sp_after_for_colon=force -sp_arith=force -sp_assign=force -sp_assign_default=force -sp_before_assign=force -sp_after_assign=force -sp_enum_assign=force -sp_enum_before_assign=force -sp_enum_after_assign=force -sp_pp_concat=remove -sp_pp_stringify=remove -sp_bool=force -sp_compare=force -sp_inside_paren=remove -sp_paren_paren=remove -sp_paren_brace=remove -sp_before_ptr_star=remove -sp_before_unnamed_ptr_star=remove -sp_between_ptr_star=remove -sp_after_ptr_star=force -sp_after_ptr_star_func=force -sp_before_ptr_star_func=remove -sp_before_byref=remove -sp_before_unnamed_byref=remove -sp_after_byref=force -sp_after_byref_func=force -sp_before_byref_func=remove -sp_after_type=force -sp_template_angle=remove -sp_before_angle=remove -sp_inside_angle=remove -sp_after_angle=force -sp_angle_paren=remove -sp_angle_word=force -sp_angle_shift=remove -sp_before_sparen=force -sp_inside_sparen=remove -sp_inside_sparen_close=remove -sp_after_sparen=remove -sp_sparen_brace=remove -sp_special_semi=remove -sp_before_semi=remove -sp_inside_square=remove -sp_after_comma=force -sp_after_class_colon=force -sp_before_class_colon=remove -sp_after_cast=add -sp_cpp_cast_paren=remove -sp_sizeof_paren=remove -sp_after_tag=remove -sp_inside_braces_enum=remove -sp_inside_braces_struct=remove -sp_inside_braces=remove -sp_inside_braces_empty=remove -sp_type_func=remove -sp_func_proto_paren=remove -sp_func_def_paren=remove -sp_inside_fparens=remove -sp_inside_fparen=remove -sp_square_fparen=remove -sp_fparen_brace=remove -sp_func_call_paren=remove -sp_func_call_paren_empty=remove -sp_func_class_paren=remove -sp_return_paren=remove -sp_throw_paren=remove -sp_catch_paren=force -sp_before_dc=remove -sp_after_dc=remove -sp_not=remove -sp_inv=remove -sp_addr=remove -sp_member=remove -sp_deref=remove -sp_sign=remove -sp_incdec=remove -sp_before_nl_cont=remove -sp_after_oc_scope=force -sp_cond_colon=force -sp_cond_question=force -sp_after_new=force -nl_start_of_file=remove -nl_end_of_file=add -nl_assign_brace=remove -nl_enum_brace=force -nl_struct_brace=force -nl_union_brace=force -nl_if_brace=force -nl_brace_else=force -nl_elseif_brace=force -nl_else_brace=force -nl_else_if=remove -nl_brace_finally=force -nl_finally_brace=force -nl_try_brace=force -nl_getset_brace=force -nl_for_brace=force -nl_catch_brace=force -nl_brace_catch=force -nl_while_brace=force -nl_using_brace=force -nl_brace_brace=force -nl_do_brace=force -nl_brace_while=force -nl_switch_brace=force -nl_namespace_brace=force -nl_class_brace=force -nl_class_init_args=force -nl_func_type_name=remove -nl_fdef_brace=force -nl_return_expr=remove -nl_class_colon=force -pos_class_comma=lead -pos_class_colon=lead -mod_full_brace_if=force +# Uncrustify-0.65_f +newlines = lf +input_tab_size = 4 +output_tab_size = 4 +string_escape_char = 92 +string_escape_char2 = 0 +string_replace_tab_chars = false +tok_split_gte = false +disable_processing_cmt = "" +enable_processing_cmt = "" +enable_digraphs = false +utf8_bom = remove +utf8_byte = false +utf8_force = false +sp_arith = force +sp_assign = force +sp_cpp_lambda_assign = ignore +sp_cpp_lambda_paren = ignore +sp_assign_default = force +sp_before_assign = force +sp_after_assign = force +sp_enum_paren = ignore +sp_enum_assign = force +sp_enum_before_assign = force +sp_enum_after_assign = force +sp_enum_colon = force +sp_pp_concat = remove +sp_pp_stringify = remove +sp_before_pp_stringify = ignore +sp_bool = force +sp_compare = force +sp_inside_paren = remove +sp_paren_paren = remove +sp_cparen_oparen = ignore +sp_balance_nested_parens = false +sp_paren_brace = remove +sp_before_ptr_star = remove +sp_before_unnamed_ptr_star = remove +sp_between_ptr_star = remove +sp_after_ptr_star = force +sp_after_ptr_star_qualifier = ignore +sp_after_ptr_star_func = force +sp_ptr_star_paren = ignore +sp_before_ptr_star_func = remove +sp_before_byref = remove +sp_before_unnamed_byref = remove +sp_after_byref = force +sp_after_byref_func = force +sp_before_byref_func = remove +sp_after_type = force +sp_before_template_paren = ignore +sp_template_angle = remove +sp_before_angle = remove +sp_inside_angle = remove +sp_after_angle = force +sp_angle_paren = remove +sp_angle_paren_empty = ignore +sp_angle_word = force +sp_angle_shift = remove +sp_permit_cpp11_shift = false +sp_before_sparen = force +sp_inside_sparen = remove +sp_inside_sparen_close = remove +sp_inside_sparen_open = ignore +sp_after_sparen = remove +sp_sparen_brace = remove +sp_invariant_paren = ignore +sp_after_invariant_paren = ignore +sp_special_semi = remove +sp_before_semi = remove +sp_before_semi_for = ignore +sp_before_semi_for_empty = ignore +sp_after_semi = add +sp_after_semi_for = force +sp_after_semi_for_empty = remove +sp_before_square = ignore +sp_before_squares = ignore +sp_inside_square = remove +sp_after_comma = force +sp_before_comma = remove +sp_after_mdatype_commas = ignore +sp_before_mdatype_commas = ignore +sp_between_mdatype_commas = ignore +sp_paren_comma = force +sp_before_ellipsis = ignore +sp_after_class_colon = force +sp_before_class_colon = remove +sp_after_constr_colon = ignore +sp_before_constr_colon = ignore +sp_before_case_colon = remove +sp_after_operator = ignore +sp_after_operator_sym = ignore +sp_after_operator_sym_empty = ignore +sp_after_cast = add +sp_inside_paren_cast = ignore +sp_cpp_cast_paren = remove +sp_sizeof_paren = remove +sp_after_tag = remove +sp_inside_braces_enum = remove +sp_inside_braces_struct = remove +sp_after_type_brace_init_lst_open = ignore +sp_before_type_brace_init_lst_close = ignore +sp_inside_type_brace_init_lst = ignore +sp_inside_braces = remove +sp_inside_braces_empty = remove +sp_type_func = remove +sp_type_brace_init_lst = ignore +sp_func_proto_paren = remove +sp_func_proto_paren_empty = ignore +sp_func_def_paren = remove +sp_func_def_paren_empty = ignore +sp_inside_fparens = remove +sp_inside_fparen = remove +sp_inside_tparen = ignore +sp_after_tparen_close = ignore +sp_square_fparen = remove +sp_fparen_brace = remove +sp_fparen_dbrace = ignore +sp_func_call_paren = remove +sp_func_call_paren_empty = remove +sp_func_call_user_paren = ignore +sp_func_class_paren = remove +sp_func_class_paren_empty = ignore +sp_return_paren = remove +sp_attribute_paren = ignore +sp_defined_paren = ignore +sp_throw_paren = remove +sp_after_throw = ignore +sp_catch_paren = force +sp_version_paren = ignore +sp_scope_paren = ignore +sp_super_paren = remove +sp_this_paren = remove +sp_macro = ignore +sp_macro_func = ignore +sp_else_brace = ignore +sp_brace_else = ignore +sp_brace_typedef = ignore +sp_catch_brace = ignore +sp_brace_catch = ignore +sp_finally_brace = ignore +sp_brace_finally = ignore +sp_try_brace = ignore +sp_getset_brace = ignore +sp_word_brace = add +sp_word_brace_ns = add +sp_before_dc = remove +sp_after_dc = remove +sp_d_array_colon = ignore +sp_not = remove +sp_inv = remove +sp_addr = remove +sp_member = remove +sp_deref = remove +sp_sign = remove +sp_incdec = remove +sp_before_nl_cont = remove +sp_after_oc_scope = force +sp_after_oc_colon = ignore +sp_before_oc_colon = ignore +sp_after_oc_dict_colon = ignore +sp_before_oc_dict_colon = ignore +sp_after_send_oc_colon = ignore +sp_before_send_oc_colon = ignore +sp_after_oc_type = ignore +sp_after_oc_return_type = ignore +sp_after_oc_at_sel = ignore +sp_after_oc_at_sel_parens = ignore +sp_inside_oc_at_sel_parens = ignore +sp_before_oc_block_caret = ignore +sp_after_oc_block_caret = ignore +sp_after_oc_msg_receiver = ignore +sp_after_oc_property = ignore +sp_cond_colon = force +sp_cond_colon_before = ignore +sp_cond_colon_after = ignore +sp_cond_question = force +sp_cond_question_before = ignore +sp_cond_question_after = ignore +sp_cond_ternary_short = ignore +sp_case_label = ignore +sp_range = ignore +sp_after_for_colon = force +sp_before_for_colon = force +sp_extern_paren = ignore +sp_cmt_cpp_start = ignore +sp_cmt_cpp_doxygen = false +sp_cmt_cpp_qttr = false +sp_endif_cmt = ignore +sp_after_new = force +sp_between_new_paren = ignore +sp_after_newop_paren = ignore +sp_inside_newop_paren = ignore +sp_inside_newop_paren_open = ignore +sp_inside_newop_paren_close = ignore +sp_before_tr_emb_cmt = ignore +sp_num_before_tr_emb_cmt = 0 +sp_annotation_paren = ignore +sp_skip_vbrace_tokens = false +force_tab_after_define = false +indent_columns = 4 +indent_continue = 8 +indent_param = 0 +indent_with_tabs = 2 +indent_cmt_with_tabs = false +indent_align_string = true +indent_xml_string = 0 +indent_brace = 0 +indent_braces = false +indent_braces_no_func = false +indent_braces_no_class = false +indent_braces_no_struct = false +indent_brace_parent = false +indent_paren_open_brace = true +indent_cs_delegate_brace = false +indent_namespace = false +indent_namespace_single_indent = false +indent_namespace_level = 0 +indent_namespace_limit = 0 +indent_extern = false +indent_class = true +indent_class_colon = false +indent_class_on_colon = false +indent_constr_colon = false +indent_ctor_init_leading = 2 +indent_ctor_init = 0 +indent_else_if = false +indent_var_def_blk = 0 +indent_var_def_cont = false +indent_shift = false +indent_func_def_force_col1 = false +indent_func_call_param = true +indent_func_def_param = true +indent_func_proto_param = false +indent_func_class_param = false +indent_func_ctor_var_param = false +indent_template_param = false +indent_func_param_double = true +indent_func_const = 0 +indent_func_throw = 0 +indent_member = 0 +indent_sing_line_comments = 0 +indent_relative_single_line_comments = false +indent_switch_case = 4 +indent_case_shift = 0 +indent_case_brace = 0 +indent_col1_comment = true +indent_label = 1 +indent_access_spec = 0 +indent_access_spec_body = true +indent_paren_nl = false +indent_paren_close = 0 +indent_comma_paren = false +indent_bool_paren = false +indent_first_bool_expr = false +indent_square_nl = false +indent_preserve_sql = false +indent_align_assign = true +indent_oc_block = false +indent_oc_block_msg = 0 +indent_oc_msg_colon = 0 +indent_oc_msg_prioritize_first_colon = true +indent_oc_block_msg_xcode_style = false +indent_oc_block_msg_from_keyword = false +indent_oc_block_msg_from_colon = false +indent_oc_block_msg_from_caret = false +indent_oc_block_msg_from_brace = false +indent_min_vbrace_open = 0 +indent_vbrace_open_on_tabstop = false +indent_token_after_brace = true +indent_cpp_lambda_body = true +indent_using_block = true +indent_ternary_operator = 0 +nl_collapse_empty_body = false +nl_assign_leave_one_liners = false +nl_class_leave_one_liners = false +nl_enum_leave_one_liners = false +nl_getset_leave_one_liners = false +nl_func_leave_one_liners = false +nl_cpp_lambda_leave_one_liners = true +nl_if_leave_one_liners = false +nl_while_leave_one_liners = false +nl_oc_msg_leave_one_liner = false +nl_oc_block_brace = ignore +nl_start_of_file = remove +nl_start_of_file_min = 0 +nl_end_of_file = add +nl_end_of_file_min = 0 +nl_assign_brace = remove +nl_assign_square = ignore +nl_after_square_assign = ignore +nl_func_var_def_blk = 0 +nl_typedef_blk_start = 0 +nl_typedef_blk_end = 0 +nl_typedef_blk_in = 0 +nl_var_def_blk_start = 0 +nl_var_def_blk_end = 0 +nl_var_def_blk_in = 0 +nl_fcall_brace = ignore +nl_enum_brace = force +nl_enum_class = remove +nl_enum_class_identifier = remove +nl_enum_identifier_colon = remove +nl_enum_colon_type = remove +nl_struct_brace = force +nl_union_brace = force +nl_if_brace = force +nl_brace_else = force +nl_elseif_brace = force +nl_else_brace = force +nl_else_if = remove +nl_before_if_closing_paren = ignore +nl_brace_finally = force +nl_finally_brace = force +nl_try_brace = force +nl_getset_brace = force +nl_for_brace = force +nl_catch_brace = force +nl_brace_catch = force +nl_brace_square = ignore +nl_brace_fparen = ignore +nl_while_brace = force +nl_scope_brace = ignore +nl_unittest_brace = ignore +nl_version_brace = ignore +nl_using_brace = force +nl_brace_brace = force +nl_do_brace = force +nl_brace_while = force +nl_switch_brace = force +nl_synchronized_brace = ignore +nl_multi_line_cond = false +nl_multi_line_define = false +nl_before_case = true +nl_before_throw = ignore +nl_after_case = true +nl_case_colon_brace = ignore +nl_namespace_brace = force +nl_template_class = ignore +nl_class_brace = force +nl_class_init_args = force +nl_constr_init_args = ignore +nl_enum_own_lines = ignore +nl_func_type_name = remove +nl_func_type_name_class = ignore +nl_func_class_scope = ignore +nl_func_scope_name = ignore +nl_func_proto_type_name = ignore +nl_func_paren = ignore +nl_func_def_paren = ignore +nl_func_decl_start = ignore +nl_func_def_start = ignore +nl_func_decl_start_single = ignore +nl_func_def_start_single = ignore +nl_func_decl_start_multi_line = false +nl_func_def_start_multi_line = false +nl_func_decl_args = ignore +nl_func_def_args = ignore +nl_func_decl_args_multi_line = false +nl_func_def_args_multi_line = false +nl_func_decl_end = ignore +nl_func_def_end = ignore +nl_func_decl_end_single = ignore +nl_func_def_end_single = ignore +nl_func_decl_end_multi_line = false +nl_func_def_end_multi_line = false +nl_func_decl_empty = ignore +nl_func_def_empty = ignore +nl_func_call_start_multi_line = false +nl_func_call_args_multi_line = false +nl_func_call_end_multi_line = false +nl_oc_msg_args = false +nl_fdef_brace = force +nl_cpp_ldef_brace = ignore +nl_return_expr = remove +nl_after_semicolon = true +nl_paren_dbrace_open = ignore +nl_type_brace_init_lst = ignore +nl_type_brace_init_lst_open = ignore +nl_type_brace_init_lst_close = ignore +nl_after_brace_open = true +nl_after_brace_open_cmt = false +nl_after_vbrace_open = false +nl_after_vbrace_open_empty = false +nl_after_brace_close = true +nl_after_vbrace_close = true +nl_brace_struct_var = ignore +nl_define_macro = false +nl_squeeze_ifdef = false +nl_squeeze_ifdef_top_level = false +nl_before_if = ignore +nl_after_if = ignore +nl_before_for = ignore +nl_after_for = ignore +nl_before_while = ignore +nl_after_while = ignore +nl_before_switch = ignore +nl_after_switch = ignore +nl_before_synchronized = ignore +nl_after_synchronized = ignore +nl_before_do = ignore +nl_after_do = ignore +nl_ds_struct_enum_cmt = false +nl_ds_struct_enum_close_brace = false +nl_before_func_class_def = 0 +nl_before_func_class_proto = 0 +nl_class_colon = force +nl_constr_colon = ignore +nl_create_if_one_liner = false +nl_create_for_one_liner = false +nl_create_while_one_liner = false +nl_split_if_one_liner = false +nl_split_for_one_liner = false +nl_split_while_one_liner = false +nl_max = 3 +nl_max_blank_in_func = 0 +nl_after_func_proto = 0 +nl_after_func_proto_group = 0 +nl_after_func_class_proto = 0 +nl_after_func_class_proto_group = 0 +nl_before_func_body_def = 0 +nl_before_func_body_proto = 0 +nl_after_func_body = 3 +nl_after_func_body_class = 0 +nl_after_func_body_one_liner = 0 +nl_before_block_comment = 2 +nl_before_c_comment = 0 +nl_before_cpp_comment = 0 +nl_after_multiline_comment = false +nl_after_label_colon = false +nl_after_struct = 0 +nl_before_class = 0 +nl_after_class = 2 +nl_before_access_spec = 2 +nl_after_access_spec = 1 +nl_comment_func_def = 1 +nl_after_try_catch_finally = 0 +nl_around_cs_property = 0 +nl_between_get_set = 0 +nl_property_brace = ignore +eat_blanks_after_open_brace = false +eat_blanks_before_close_brace = false +nl_remove_extra_newlines = 0 +nl_before_return = false +nl_after_return = true +nl_after_annotation = ignore +nl_between_annotation = ignore +pos_arith = ignore +pos_assign = ignore +pos_bool = ignore +pos_compare = ignore +pos_conditional = ignore +pos_comma = ignore +pos_enum_comma = ignore +pos_class_comma = lead +pos_constr_comma = ignore +pos_class_colon = lead +pos_constr_colon = ignore +code_width = 0 +ls_for_split_full = false +ls_func_split_full = false +ls_code_width = false +align_keep_tabs = false +align_with_tabs = true +align_on_tabstop = false +align_keep_extra_space = false +align_func_params = false +align_same_func_call_params = false +align_var_def_span = 0 +align_var_def_star_style = 0 +align_var_def_amp_style = 0 +align_var_def_thresh = 0 +align_var_def_gap = 0 +align_var_def_colon = false +align_var_def_colon_gap = 0 +align_var_def_attribute = false +align_var_def_inline = false +align_assign_span = 0 +align_assign_thresh = 0 +align_enum_equ_span = 0 +align_enum_equ_thresh = 0 +align_var_class_span = 0 +align_var_class_thresh = 0 +align_var_class_gap = 0 +align_var_struct_span = 0 +align_var_struct_thresh = 0 +align_var_struct_gap = 0 +align_struct_init_span = 0 +align_typedef_gap = 0 +align_typedef_span = 0 +align_typedef_func = 0 +align_typedef_star_style = 0 +align_typedef_amp_style = 0 +align_right_cmt_span = 0 +align_right_cmt_mix = false +align_right_cmt_gap = 0 +align_right_cmt_at_col = 0 +align_func_proto_span = 0 +align_func_proto_gap = 0 +align_on_operator = false +align_mix_var_proto = false +align_single_line_func = true +align_single_line_brace = false +align_single_line_brace_gap = 0 +align_oc_msg_spec_span = 0 +align_nl_cont = false +align_pp_define_together = false +align_pp_define_gap = 0 +align_pp_define_span = 0 +align_left_shift = true +align_asm_colon = false +align_oc_msg_colon_span = 0 +align_oc_msg_colon_first = false +align_oc_decl_colon = false +cmt_width = 0 +cmt_reflow_mode = 0 +cmt_convert_tab_to_spaces = false +cmt_indent_multi = true +cmt_c_group = false +cmt_c_nl_start = false +cmt_c_nl_end = false +cmt_cpp_group = false +cmt_cpp_nl_start = false +cmt_cpp_nl_end = false +cmt_cpp_to_c = false +cmt_star_cont = false +cmt_sp_before_star_cont = 0 +cmt_sp_after_star_cont = 0 +cmt_multi_check_last = true +cmt_multi_first_len_minimum = 4 +cmt_insert_file_header = "" +cmt_insert_file_footer = "" +cmt_insert_func_header = "" +cmt_insert_class_header = "" +cmt_insert_oc_msg_header = "" +cmt_insert_before_preproc = false +cmt_insert_before_inlines = true +cmt_insert_before_ctor_dtor = false +mod_full_brace_do = ignore +mod_full_brace_for = ignore +mod_full_brace_function = ignore +mod_full_brace_if = force +mod_full_brace_if_chain = false +mod_full_brace_if_chain_only = false +mod_full_brace_nl = 0 +mod_full_brace_nl_block_rem_mlcond = false +mod_full_brace_while = ignore +mod_full_brace_using = ignore +mod_paren_on_return = ignore +mod_pawn_semicolon = false +mod_full_paren_if_bool = false +mod_remove_extra_semicolon = true +mod_add_long_function_closebrace_comment = 0 +mod_add_long_namespace_closebrace_comment = 0 +mod_add_long_class_closebrace_comment = 0 +mod_add_long_switch_closebrace_comment = 0 +mod_add_long_ifdef_endif_comment = 0 +mod_add_long_ifdef_else_comment = 0 +mod_sort_import = true +mod_sort_using = false +mod_sort_include = true +mod_move_case_break = false +mod_case_brace = ignore +mod_remove_empty_return = false +mod_sort_oc_properties = false +mod_sort_oc_property_class_weight = 0 +mod_sort_oc_property_thread_safe_weight = 0 +mod_sort_oc_property_readwrite_weight = 0 +mod_sort_oc_property_reference_weight = 0 +mod_sort_oc_property_getter_weight = 0 +mod_sort_oc_property_setter_weight = 0 +mod_sort_oc_property_nullability_weight = 0 +pp_indent = ignore +pp_indent_at_level = false +pp_indent_count = 1 +pp_space = ignore +pp_space_count = 0 +pp_indent_region = 0 +pp_region_indent_code = false +pp_indent_if = 0 +pp_if_indent_code = false +pp_define_at_level = false +pp_ignore_define_body = false +include_category_0 = "" +include_category_1 = "" +include_category_2 = "" +use_indent_func_call_param = true +use_indent_continue_only_once = false +use_options_overriding_for_qt_macros = true +warn_level_tabs_found_in_verbatim_string_literals = 2 +macro-open ASN1_ITEM_TEMPLATE +macro-close ASN1_ITEM_TEMPLATE_END +set PRIVATE Q_SIGNALS +# option(s) with 'not default' value: 150 +# diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index cc93788..2aebc28 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -6,3 +6,7 @@ ENDIF() IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tlscheck") ADD_SUBDIRECTORY(tlscheck) ENDIF() + +IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/fuzzing") + ADD_SUBDIRECTORY(fuzzing) +ENDIF() diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert new file mode 100644 index 0000000..5dea228 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert.hex new file mode 100644 index 0000000..2167e90 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_2.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104010B0FAC592117B65302BACA1EA38DAC8ECE106FDF318508D647065458B666026716DAD1D5E506957FDA2337B972F333ABD470686C289177AA57A07E32F754748701015F201044454356434165494443544C303430317F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37402B5CE09185600A035372D34EE7FE254C4177B9E187EF70C60ABEF566884C9C81430561E0DE8D29EF008A1BBEED28B372265F2EC4316405EF80890C14F6DD624A \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert new file mode 100644 index 0000000..1334782 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert.hex new file mode 100644 index 0000000..bef3b39 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_3.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046E5EB3B0EF17F41BB78E4A387732BC21DFE223200E3EEF6958A2D3FEC769E92353D1CB375478A1A8E61CA55045EC0A6F02205365B51A53172213A6520AB701D48701015F201044454356434165494443544C303430327F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37401DCEA27703304B3B340370859C8FD3C24A63C958DD543FF1E28F93E2CD5A93AD589D4AE22381B9873D00B2FA419EC75F97ED8AB1294365DDEBE63305337F90AE \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert new file mode 100644 index 0000000..e859bd9 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert.hex new file mode 100644 index 0000000..9e90a86 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_4.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430337F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410408DA7B7D4D4AF28A6DA4F9C6210423FDBB718810394EEEDFF6EF423A4245E8395A5C11DC6288EA564C4D5109E67827B2C722972754E14CE5DAC099EAD5F5947F8701015F201044454356434165494443544C303430337F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37405E92D635A229B1BD14EA61D1904A59CEBD18E656396994B512FD485D0D25DF7451D2A1F81694A0F7F812ED1A51810749797EC12F7C52BAC70290769A5087D9C2 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert new file mode 100644 index 0000000..0e1eb35 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert.hex new file mode 100644 index 0000000..e64a6d6 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_5.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430347F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104458DE59DEB9BE08733CABBE6A752EEA4DC5FC243AF2FEF793C17B6C66B2C96DB679249FFF7EDC48E58E3B72630D2DC46195060DAB832704864E4C95677467A838701015F201044454356434165494443544C303430347F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F374013FC6405BA64752316499DA9BF1A294D383B736388DEED7DB188A448CF406CA18D626315154B2A71D687C48B2C9ED8A14C04B62FE3C06E463022D0B11C5B0413 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert new file mode 100644 index 0000000..86fa4ae Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert.hex new file mode 100644 index 0000000..6a58361 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_6.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430357F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410477C42620CAF69F29913C6D2E23C4C7DC01FEA4BBDEC97F152E76FC2519625CB66E6A48CCE243DE56694F817B4C2047C82C6607C1087043C944EB1B45A4204A668701015F201044454356434165494443544C303430357F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F3740919933BFD2B279FBBAAB68D8D3747417724E77914E0E590B35B6F22A59B14FA418E5312D1A31C9C107CB32B0B84EA33AAFA69ED848D32234FB059060AAE5A823 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert new file mode 100644 index 0000000..c08c1b4 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert.hex new file mode 100644 index 0000000..ce2733b --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_CVCA_4_7.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430367F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641041BDBDC7A309B4B790AF0DDC6D9EF2CF0B73BE9B387350DFB247640F904237BFD2CF39E7C72B3A59513B95C708E150E4EBDB0A12DCC059C4B82D8F236177187E38701015F201044454356434165494443544C303430367F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37404BC4AF8B311C1EDCAD56DC674D6CACD42200C24A978C7EFB6AFE60B94BDF123E4F291F404D6D18A787F2873883F23D9074F9C0D89B867660D0EF0AB6DBACF625 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin new file mode 100644 index 0000000..10d16f6 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin.cv new file mode 100644 index 0000000..619d1d3 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert new file mode 100644 index 0000000..8e396d1 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert.hex new file mode 100644 index 0000000..dd775d9 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F2901004210444543564341654944435430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104010B0FAC592117B65302BACA1EA38DAC8ECE106FDF318508D647065458B666026716DAD1D5E506957FDA2337B972F333ABD470686C289177AA57A07E32F754748701015F201044454356434165494443544C303430317F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37407C62254D60160948DFCDF37BB22630CE809DA3A567A37652FCF88B6C29C098B23C36514BAD3C241A69659484C7A76F39A4CDDAC6DC8CACFA95B8383577B3CC6A \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1_KEY.pkcs8 new file mode 100644 index 0000000..3ed9512 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_1_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin new file mode 100644 index 0000000..4c75820 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin.cv new file mode 100644 index 0000000..8dcc56b Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert new file mode 100644 index 0000000..8186b86 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert.hex new file mode 100644 index 0000000..a2d2088 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046E5EB3B0EF17F41BB78E4A387732BC21DFE223200E3EEF6958A2D3FEC769E92353D1CB375478A1A8E61CA55045EC0A6F02205365B51A53172213A6520AB701D48701015F201044454356434165494443544C303430327F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37405EAABA9B6620286BD40A56F43AFA0ACF87B1F14735BEDCDDA929613E43A3D5AA8D645289FDE4FB00373E49A8D422D3A646BCB3AE580D861E119632607BC55D0C \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2_KEY.pkcs8 new file mode 100644 index 0000000..f44405e Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_2_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin new file mode 100644 index 0000000..f699962 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin.cv new file mode 100644 index 0000000..3a46321 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert new file mode 100644 index 0000000..d99c770 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert.hex new file mode 100644 index 0000000..e249761 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430327F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410408DA7B7D4D4AF28A6DA4F9C6210423FDBB718810394EEEDFF6EF423A4245E8395A5C11DC6288EA564C4D5109E67827B2C722972754E14CE5DAC099EAD5F5947F8701015F201044454356434165494443544C303430337F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37406728218409A24CF0523156C3CA6C188DD4A59CDACA2E52606C976695C646C0AE170A5431DF6472E905828950378CDF74B92915211A22C2EE7B390DF3D1E12A75 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3_KEY.pkcs8 new file mode 100644 index 0000000..2d8712f Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_3_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin new file mode 100644 index 0000000..dfbabde Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin.cv new file mode 100644 index 0000000..f02734e Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert new file mode 100644 index 0000000..d44a71e Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert.hex new file mode 100644 index 0000000..c01950e --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430337F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104458DE59DEB9BE08733CABBE6A752EEA4DC5FC243AF2FEF793C17B6C66B2C96DB679249FFF7EDC48E58E3B72630D2DC46195060DAB832704864E4C95677467A838701015F201044454356434165494443544C303430347F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37402F95D375791871DA7A28D4D3DCD6795238CA801ED9A568D827E762510F772F6046C11E564DED1DEDC9A2037B0EA81A4A8476190D39D669FE20F18E09D7FCF163 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4_KEY.pkcs8 new file mode 100644 index 0000000..3e31694 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_4_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin new file mode 100644 index 0000000..05256d1 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin.cv new file mode 100644 index 0000000..3d88e6b Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert new file mode 100644 index 0000000..e89df7a Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert.hex new file mode 100644 index 0000000..9e70754 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430347F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A786410477C42620CAF69F29913C6D2E23C4C7DC01FEA4BBDEC97F152E76FC2519625CB66E6A48CCE243DE56694F817B4C2047C82C6607C1087043C944EB1B45A4204A668701015F201044454356434165494443544C303430357F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F3740859EA541BACBAD86C18BE4C6E1DA13C0937874B120D8601235B4BB11FE53197A5185148AD4C5AD75B94AAFCD932A561B122A85D95790A155AD717A50E2E56C9F \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5_KEY.pkcs8 new file mode 100644 index 0000000..728535c Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_5_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin new file mode 100644 index 0000000..7744180 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin.cv b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin.cv new file mode 100644 index 0000000..8a381fa Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.bin.cv differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert new file mode 100644 index 0000000..824b00f Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert differ diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert.hex b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert.hex new file mode 100644 index 0000000..f2b0473 --- /dev/null +++ b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F290100421044454356434165494443544C303430357F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641041BDBDC7A309B4B790AF0DDC6D9EF2CF0B73BE9B387350DFB247640F904237BFD2CF39E7C72B3A59513B95C708E150E4EBDB0A12DCC059C4B82D8F236177187E38701015F201044454356434165494443544C303430367F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F374080EA97438956C18ED1D762AFD6E973765A158329FF4D79322D126C7FFA0CF340943F4CCD5661C104B5EE0310E535ADC1E8B9E64B31F269682842618CFE30AF6B \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6_KEY.pkcs8 b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6_KEY.pkcs8 new file mode 100644 index 0000000..f94ee76 Binary files /dev/null and b/utils/testbed/resources/CVCA/CERT_CV_LINK_4_6_KEY.pkcs8 differ diff --git a/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin new file mode 100644 index 0000000..77b506d Binary files /dev/null and b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin differ diff --git a/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin.cv b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin.cv new file mode 100644 index 0000000..0df0201 Binary files /dev/null and b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.bin.cv differ diff --git a/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert new file mode 100644 index 0000000..c1d96a3 Binary files /dev/null and b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert differ diff --git a/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert.hex b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert.hex new file mode 100644 index 0000000..52e9b58 --- /dev/null +++ b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.cvcert.hex @@ -0,0 +1 @@ +7F218201BA7F4E8201725F2901004210444543564341654944435430303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A86AF8DCFDECB1D3093D93B3AEDC29F28EDE13F0AAC59D23AA9715CD299C1D32356289097550E212BD3FD948518430E9DD88BB468DD8ECB833C2F5D16B738E768701015F2010444543564341654944435430303030317F4C12060904007F0007030102025305FE1FFFFFFF5F25060106010200055F24060109010200055F37409DE197127555CFB5E3D0DEF2DE727FFBCBFFF00E4FDD47CD5BEAC3983487C1B904019E6D3680DE4A615016D8A55AB6AC3B71D910F622286F2656AF5839873BE5 \ No newline at end of file diff --git a/utils/testbed/resources/CVCA/DECVCAeIDCT00001.pkcs8 b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.pkcs8 new file mode 100644 index 0000000..f5b1101 Binary files /dev/null and b/utils/testbed/resources/CVCA/DECVCAeIDCT00001.pkcs8 differ