diff --git a/CMakeLists.txt b/CMakeLists.txt index e86afb357..91098986c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ if(UNIX AND NOT IOS) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Required macOS version") endif() -project(AusweisApp2 VERSION 1.26.4 LANGUAGES ${LANGUAGES}) +project(AusweisApp2 VERSION 1.26.5 LANGUAGES ${LANGUAGES}) # Set TWEAK if not defined in PROJECT_VERSION above to # have a valid tweak version without propagating it diff --git a/Dockerfile b/Dockerfile index 932b38267..ab32e67a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG ALPINE_VERSION=3.17 +ARG ALPINE_VERSION=3.18 FROM alpine:$ALPINE_VERSION as builder # Install development stuff diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 79998b2de..73dea883e 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -84,13 +84,16 @@ if(WIN32) endif() if (QT6) - # Workaround for QTBUG-94066 - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") + if(QT_VERSION VERSION_LESS "6.4") + # Workaround for QTBUG-94066 + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") + endif() + FETCH_TARGET_LOCATION(openSslBackend "${Qt}::QTlsBackendOpenSSLPlugin") install(FILES ${openSslBackend} DESTINATION tls COMPONENT Runtime) list(APPEND LIBS ${openSslBackend}) @@ -247,6 +250,7 @@ elseif(ANDROID) foreach(entry ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/background_npa.png DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_background.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/foreground_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_foreground.png) + install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/monochrome_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_monochrome.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_SPLASH_SCREEN_ICON_NAME} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/drawable-${entry} COMPONENT Runtime RENAME splash_npa.png) endforeach() @@ -269,6 +273,8 @@ elseif(ANDROID) set(QML_ROOT_PATH [\"${RESOURCES_DIR}/qml\"]) set(ANDROID_ROOT_LOGGER "") configure_file(${PACKAGING_DIR}/android/fileprovider.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/fileprovider.xml COPYONLY) + configure_file(${PACKAGING_DIR}/android/full_backup_content.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/full_backup_content.xml COPYONLY) + configure_file(${PACKAGING_DIR}/android/data_extraction_rules.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/data_extraction_rules.xml COPYONLY) endif() set(ANDROID_SO_NAME libAusweisApp2_${CMAKE_ANDROID_ARCH_ABI}.so) diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index 6ece9e5d5..8e47744f2 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -49,11 +49,8 @@ if(NOT CONTAINER_SDK) endif() if(NOT INTEGRATED_SDK) - list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2) + list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2 QmlWorkerScript) - if(QT_VERSION VERSION_GREATER_EQUAL "5.14") - list(APPEND QT_COMPONENTS QmlWorkerScript) - endif() if(NOT DESKTOP AND NOT QT6) list(APPEND QT_COMPONENTS QuickShapes) endif() diff --git a/cmake/Messages.cmake b/cmake/Messages.cmake index 0a5e4ecab..e3c63199d 100644 --- a/cmake/Messages.cmake +++ b/cmake/Messages.cmake @@ -25,7 +25,6 @@ if(ANDROID) message(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}") message(STATUS "ANDROID_NDK_REVISION: ${ANDROID_NDK_REVISION}") - message(STATUS "ANDROID_SDK_REVISION: ${ANDROID_SDK_REVISION}") endif() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 461c3b285..f2dfbe911 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -171,7 +171,11 @@ elseif(ANDROID) file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") - if(USE_SMARTEID AND NOT INTEGRATED_SDK) + if(INTEGRATED_SDK) + set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.aar") + file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) + file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") + elseif(USE_SMARTEID) set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.smarteid") file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") diff --git a/cmake/Tools.Libraries.cmake b/cmake/Tools.Libraries.cmake index 7f37aa427..9237c91ca 100644 --- a/cmake/Tools.Libraries.cmake +++ b/cmake/Tools.Libraries.cmake @@ -2,7 +2,7 @@ # So this file will be called two times and the check needs to respect that # with a "VALIDATOR function" or "if(NOT VARIABLE)". -if(NOT QMLFORMAT) +if(NOT TARGET format.qml) set(QMLFORMAT_MIN_VERSION 6) function(qmlformat_validator validator_result binary) execute_process(COMMAND ${binary} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index 2ee0c3ef7..132bfddda 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -228,6 +228,33 @@ if(INKSCAPE) COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 640 -y 0 -o xxxhdpi/foreground_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(npaicons.android.adaptive.monochrome + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 120 -y 0 -o ldpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 160 -y 0 -o mdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 240 -y 0 -o hdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 320 -y 0 -o xhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 480 -y 0 -o xxhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.beta + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 120 -y 0 -o ldpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 160 -y 0 -o mdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 240 -y 0 -o hdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 320 -y 0 -o xhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.preview + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 120 -y 0 -o ldpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 160 -y 0 -o mdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 240 -y 0 -o hdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 320 -y 0 -o xhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(npaicons.android.launchimage COMMAND ${INKSCAPE} npa_release.svg -w 120 -h 120 -y 0 -o android/ldpi/splash_npa.png COMMAND ${INKSCAPE} npa_release.svg -w 180 -h 180 -y 0 -o android/mdpi/splash_npa.png @@ -313,6 +340,9 @@ if(INKSCAPE) npaicons.android.adaptive.foreground npaicons.android.adaptive.foreground.beta npaicons.android.adaptive.foreground.preview + npaicons.android.adaptive.monochrome + npaicons.android.adaptive.monochrome.beta + npaicons.android.adaptive.monochrome.preview npaicons.android.launchimage npaicons.android.launchimage.beta npaicons.android.launchimage.preview @@ -407,6 +437,33 @@ if(PNGQUANT) COMMAND ${PNGQUANT_CMD} xxxhdpi/foreground_npa_preview.png -- xxxhdpi/foreground_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(pngquant.android.adaptive.monochrome + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa.png -- ldpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa.png -- mdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa.png -- hdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa.png -- xhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa.png -- xxhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa.png -- xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.beta + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_beta.png -- ldpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_beta.png -- mdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_beta.png -- hdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_beta.png -- xhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_beta.png -- xxhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_beta.png -- xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.preview + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_preview.png -- ldpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_preview.png -- mdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_preview.png -- hdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_preview.png -- xhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_preview.png -- xxhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_preview.png -- xxxhdpi/monochrome_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + add_custom_target(pngquant.android.launchimage COMMAND ${PNGQUANT_CMD} ldpi/splash_npa.png -- ldpi/splash_npa.png COMMAND ${PNGQUANT_CMD} mdpi/splash_npa.png -- mdpi/splash_npa.png @@ -491,6 +548,9 @@ if(PNGQUANT) pngquant.android.adaptive.foreground pngquant.android.adaptive.foreground.beta pngquant.android.adaptive.foreground.preview + pngquant.android.adaptive.monochrome + pngquant.android.adaptive.monochrome.beta + pngquant.android.adaptive.monochrome.preview pngquant.android.launchimage pngquant.android.launchimage.beta pngquant.android.launchimage.preview diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index c21ea168a..a509852ae 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -52,7 +52,6 @@ if(NOT ANDROID_BUILD_TOOLS_REVISION) endif() READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_NDK}/source.properties") -READ_REVISION(ANDROID_SDK_REVISION ".*Revision=([0-9|\\.]+)" "${ANDROID_SDK}/cmdline-tools/latest/source.properties;${ANDROID_SDK}/tools/source.properties") set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_SYSTEM_NAME Android) @@ -73,10 +72,6 @@ if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") set(CMAKE_ANDROID_ARM_NEON ON) endif() -# Emulate NDK CMake-Variable as Qt 5.14 needs this (Multi-ABI) -set(ANDROID_ABI ${CMAKE_ANDROID_ARCH_ABI}) - - 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/docs/failurecodes/failurecodes.rst b/docs/failurecodes/failurecodes.rst index 1a5fe2024..1e880d5e0 100644 --- a/docs/failurecodes/failurecodes.rst +++ b/docs/failurecodes/failurecodes.rst @@ -157,21 +157,21 @@ Codes the description of the service provider certificate. This condition is not met. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_No_Test_Environment** + - | **Pre_Verification_No_Test_Environment** | Occurs when the development mode of AusweisApp2 is activated and a genuine ID card is used. | **Possible Solutions:** Disable developer mode. The use of genuine ID cards is not permitted with activated developer mode, as this is only intended to facilitate the commissioning of services with test ID cards. - - | **Pre_Verfication_Invalid_Certificate_Chain** + - | **Pre_Verification_Invalid_Certificate_Chain** | A certificate chain was sent from the server that is unknown to AusweisApp2. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_Invalid_Certificate_Signature** + - | **Pre_Verification_Invalid_Certificate_Signature** | At least one signature in the certificate chain used by the server is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_Certificate_Expired** + - | **Pre_Verification_Certificate_Expired** | The certificate chain used by the server is currently not valid. | **Possible Solutions:** Make sure your system time is set correctly. If the problem persists, see :ref:`failure_code_inform_service_provider`. @@ -262,14 +262,14 @@ Codes - | **Generic_Send_Receive_Paos_Unhandled** | A message was sent by the server in the PAOS communication during authentication, that - could be completely processed. + could not be completely processed. | **Possible Solutions:** :ref:`failure_code_contact_support`. - | **Generic_Send_Receive_Network_Error** | A network error has occurred in the PAOS communication during authentication. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - - | **Generic_Send_Receive_Ssl_Error** + - | **Generic_Send_Receive_Tls_Error** | An authentication error occurred in the PAOS communication during the TLS handshake. The TLS certificate is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -318,7 +318,7 @@ Codes did not behave as expected by the server. | **Possible Solutions:** :ref:`failure_code_contact_support`. - - | **Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply** + - | **Check_Refresh_Address_Fatal_Tls_Error_Before_Reply** | An error occurred during the TLS handshake when checking the return address after a successful authentication. The TLS certificate is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -341,7 +341,7 @@ Codes didn't work for checking the return address. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - - | **Check_Refresh_Address_Fatal_Ssl_Error_After_Reply** + - | **Check_Refresh_Address_Fatal_Tls_Error_After_Reply** | When checking the return address after successful authentication, the TLS handshake could not be completed successfully. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. @@ -413,7 +413,7 @@ Codes self-authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Generic_Provider_Communication_Ssl_Error** + - | **Generic_Provider_Communication_Tls_Error** | An error occurred during the TLS handshake when communicating with a service provider. The TLS certificate is incorrect. This only applies to services that are started from AusweisApp2, such as self-authentication. diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po index f99714f26..6f1d212ec 100644 --- a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po +++ b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po @@ -360,7 +360,7 @@ msgstr "" "TLS-Zertifikate in der Beschreibung des Diensteanbieterzertifikats " "enthalten sind. Diese Bedingung ist nicht erfüllt." -msgid "**Pre_Verfication_No_Test_Environment**" +msgid "**Pre_Verification_No_Test_Environment**" msgstr "" msgid "" @@ -380,7 +380,7 @@ msgstr "" "dieser nur die Inbetriebnahme von Diensten mit Testausweisen erleichtern " "soll." -msgid "**Pre_Verfication_Invalid_Certificate_Chain**" +msgid "**Pre_Verification_Invalid_Certificate_Chain**" msgstr "" msgid "" @@ -390,7 +390,7 @@ msgstr "" "Vom Server wurde eine Zertifikatskette gesendet, die der AusweisApp2 " "nicht bekannt ist." -msgid "**Pre_Verfication_Invalid_Certificate_Signature**" +msgid "**Pre_Verification_Invalid_Certificate_Signature**" msgstr "" msgid "" @@ -400,7 +400,7 @@ msgstr "" "Mindestens eine Signatur in der vom Server genutzten Zertifikatskette ist" " nicht korrekt." -msgid "**Pre_Verfication_Certificate_Expired**" +msgid "**Pre_Verification_Certificate_Expired**" msgstr "" msgid "The certificate chain used by the server is currently not valid." @@ -639,7 +639,7 @@ msgstr "" msgid "" "A message was sent by the server in the PAOS communication during " -"authentication, that could be completely processed." +"authentication, that could not be completely processed." msgstr "" "Bei einer Authentisierung ist eine Nachricht vom Server in der PAOS-" "Kommunikation gesendet worden, die nicht vollständig verarbeitet werden " @@ -655,7 +655,7 @@ msgstr "" "Bei einer Authentisierung ist ein Netzwerkfehler in der PAOS-" "Kommunikation aufgetreten." -msgid "**Generic_Send_Receive_Ssl_Error**" +msgid "**Generic_Send_Receive_Tls_Error**" msgstr "" msgid "" @@ -766,7 +766,7 @@ msgstr "" "geliefert. Die AusweisApp2 oder die Karte hat sich nicht entsprechend der" " Erwartung des Servers verhalten." -msgid "**Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply**" +msgid "**Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**" msgstr "" msgid "" @@ -815,7 +815,7 @@ msgstr "" " Proxyserver konfiguriert. Dieser hat für die Überprüfung der " "Rücksprungadresse nicht funktioniert." -msgid "**Check_Refresh_Address_Fatal_Ssl_Error_After_Reply**" +msgid "**Check_Refresh_Address_Fatal_Tls_Error_After_Reply**" msgstr "" msgid "" @@ -976,7 +976,7 @@ msgstr "" "aus der AusweisApp2 heraus gestartet werden, wie zum Beispiel die " "Selbstauskunft." -msgid "**Generic_Provider_Communication_Ssl_Error**" +msgid "**Generic_Provider_Communication_Tls_Error**" msgstr "" msgid "" diff --git a/docs/installation/README.de.rst b/docs/installation/README.de.rst index a1aea8ea2..ae077291b 100644 --- a/docs/installation/README.de.rst +++ b/docs/installation/README.de.rst @@ -173,8 +173,8 @@ dargestellt: remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -183,8 +183,6 @@ dargestellt: proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard @@ -209,12 +207,11 @@ macOS Windows ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD diff --git a/docs/installation/README.en.rst b/docs/installation/README.en.rst index 2f03af350..4ab2cd596 100644 --- a/docs/installation/README.en.rst +++ b/docs/installation/README.en.rst @@ -160,8 +160,8 @@ the file must be "com.governikus.AusweisApp2.plist". The content is shown below: remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -170,8 +170,6 @@ the file must be "com.governikus.AusweisApp2.plist". The content is shown below: proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard @@ -195,12 +193,11 @@ macOS Windows ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD @@ -251,7 +248,7 @@ the requests. Broadcast on UDP port 24727 in the local subnet have to be receivable by the AusweisApp2 to use the "Smartphone as Card Reader" functionality. -It may be necessary to deactive AP isolation on your router. +It may be necessary to deactivate AP isolation on your router. .. _communicationmodel_en: .. figure:: CommunicationModel_en.pdf diff --git a/docs/releasenotes/1.26.5.rst b/docs/releasenotes/1.26.5.rst new file mode 100644 index 000000000..450f414bb --- /dev/null +++ b/docs/releasenotes/1.26.5.rst @@ -0,0 +1,36 @@ +AusweisApp2 1.26.5 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 25. Juli 2023 + + +Anwender +"""""""" +- Überarbeitung des Kopplungsprozesses der Funktion Smartphone als Kartenleser. + Beide an der Kopplung beteiligten Geräte müssen auf Version 1.26.5 aktualisiert werden. + Versionen kleiner als 1.26.5 lassen sich nicht mit einer AusweisApp2 1.26.5 koppeln. + +- Die Anzeige des Fortschritts erfolgt jetzt auch auf einem Smartphone als Kartenleser. + +- Der Tastaturmodus auf einem Smartphone als Kartenleser ist jetzt standardmäßig aktiviert. + +- Bei Nutzung des Tastaturmodus auf einem Smartphone als Kartenleser kann in den Einstellungen eine + erneute Anzeige der Berechtigungen aktiviert werden. + +- Ergänzung eines monochromen Icons unter Android. + +- Berücksichtigung von Command + W unter macOS. + +- Entfernung der Updatefunktion auf macOS zugunsten des Mac App Store. + +- Kleinere Fehlerbehebungen und Optimierungen. + + +Entwickler +"""""""""" +- Die Dokumentation für die Installation in Firmennetzwerken unter macOS für die Einstellung zum + Einrichtungsassistenten wurde korrigiert. + +- Optimierung der Größe des Android SDK. + +- Aktualisierung von OpenSSL auf die Version 3.0.9. diff --git a/docs/releasenotes/announce.rst b/docs/releasenotes/announce.rst index 13d2566ef..f8b914e20 100644 --- a/docs/releasenotes/announce.rst +++ b/docs/releasenotes/announce.rst @@ -5,6 +5,8 @@ Mit der Version 1.28.0 der AusweisApp2 wird die Unterstützung folgender Systeme und Funktionen eingestellt. - macOS Catalina 10.15 +- Android 7 +- iOS 13 - Online-Hilfe - PDF-Export-Funktion der Selbstauskunft diff --git a/docs/releasenotes/appcast.rst b/docs/releasenotes/appcast.rst index 682bc053d..5aee3573d 100644 --- a/docs/releasenotes/appcast.rst +++ b/docs/releasenotes/appcast.rst @@ -4,6 +4,7 @@ Release Notes .. toctree:: :maxdepth: 1 + 1.26.5 1.26.4 1.26.3 1.26.2 diff --git a/docs/releasenotes/issues.rst b/docs/releasenotes/issues.rst index 0ca9b1bd4..9f6d82294 100644 --- a/docs/releasenotes/issues.rst +++ b/docs/releasenotes/issues.rst @@ -38,11 +38,6 @@ Windows / macOS - Die visuelle Hervorhebung des aktiven Elements wird an einigen Stellen fälschlicherwiese auch aktiviert, wenn die Maus benutzt wurde. -- Unter macOS werden im System hinterlegte Proxy-Server nicht erkannt und - damit auch nicht automatisch verwendet. Um manuell einen Proxy-Server in - der AusweisApp2 zu hinterlegen beachten Sie die Anleitung zur Installation - in Firmennetzwerken. - Android / iOS """"""""""""" diff --git a/docs/releasenotes/support.rst b/docs/releasenotes/support.rst index 6a5f4bf21..88faee3ed 100644 --- a/docs/releasenotes/support.rst +++ b/docs/releasenotes/support.rst @@ -54,13 +54,13 @@ und sollte daher mit allen marktüblichen Browsern verwendet werden können. Im Rahmen der Qualitätssicherung werden die folgenden Browserversionen getestet. -- Chrome 112 +- Chrome 115 -- Firefox 112 +- Firefox 115 -- Safari 16.4 (macOS) +- Safari 16.5 (macOS) -- Edge 112 +- Edge 115 @@ -118,13 +118,13 @@ Im mobilen Umfeld ist die Funktionalität jedoch abhängig von der vom Anbieter umgesetzten Aktivierung. Daher empfehlen wir einen der folgenden Browser zu verwenden. -- Chrome 112 (iOS/Android) +- Chrome 115 (iOS/Android) -- Firefox 112 (iOS/Android) +- Firefox 115 (iOS/Android) -- Samsung Internet 20 (Android) +- Samsung Internet 22 (Android) -- Safari 16.4 (iOS) +- Safari 16.5 (iOS) Kartenleser diff --git a/docs/releasenotes/versions.rst b/docs/releasenotes/versions.rst index 67040af81..2eeb00038 100644 --- a/docs/releasenotes/versions.rst +++ b/docs/releasenotes/versions.rst @@ -6,6 +6,7 @@ Versionszweig 1.26 .. toctree:: :maxdepth: 1 + 1.26.5 1.26.4 1.26.3 1.26.2 diff --git a/docs/sdk/messages.rst b/docs/sdk/messages.rst index 8187f0715..d091862e6 100644 --- a/docs/sdk/messages.rst +++ b/docs/sdk/messages.rst @@ -810,6 +810,8 @@ until a card with enabled eID function is inserted. to unblock the PIN. - **deactivated**: True if eID function is deactivated, otherwise false. + The scan dialog on iOS won't be closed if this is True. You need to + send :ref:`interrupt` yourself to show an error message. - **retryCounter**: Count of possible retries for the PIN. If you enter a PIN with command :ref:`set_pin` it will be decreased if PIN was incorrect. diff --git a/docs/sdk/workflow.rst b/docs/sdk/workflow.rst index b5cc87807..a55a97779 100644 --- a/docs/sdk/workflow.rst +++ b/docs/sdk/workflow.rst @@ -24,7 +24,7 @@ into the connected card reader. .. code-block:: json - {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/DEMO"} + {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/AusweisAuskunft/WebServiceRequesterServlet"} {"msg": "AUTH"} diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 4af45b2a6..77505ba7f 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -109,11 +109,7 @@ if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME) endif() ################################## Versions -set(QT 6.4.1) -set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) - -set(OPENSSL 3.0.8) -set(OPENSSL_HASH 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e) +include(Versions.cmake) ################################## Files set(QT_FILE qt-everywhere-src-${QT}.tar.xz) diff --git a/libs/Versions.cmake b/libs/Versions.cmake new file mode 100644 index 000000000..56bc6c003 --- /dev/null +++ b/libs/Versions.cmake @@ -0,0 +1,5 @@ +set(QT 6.4.1) +set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) + +set(OPENSSL 3.0.9) +set(OPENSSL_HASH eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90) diff --git a/libs/patch.cmake.in b/libs/patch.cmake.in index 6f5ded14a..adec3a60a 100644 --- a/libs/patch.cmake.in +++ b/libs/patch.cmake.in @@ -15,11 +15,11 @@ endfunction() function(PATCH_SOURCES _component) set(PATCHES_DIR @PROJECT_SOURCE_DIR@/patches) - file(GLOB PATCHES "${PATCHES_DIR}/${_component}-*.patch") + file(GLOB PATCHES "${PATCHES_DIR}/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES}") if("@CMAKE_BUILD_TYPE@" STREQUAL "DEBUG") - file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}-*.patch") + file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES_DEBUG}") endif() endfunction() diff --git a/libs/patches.cmake b/libs/patches.cmake new file mode 100644 index 000000000..fcedd53b2 --- /dev/null +++ b/libs/patches.cmake @@ -0,0 +1,223 @@ +cmake_minimum_required(VERSION 3.19.0) + +# How to use +# +# Create an empty directory and provide it by -DREPOSITORY_DIR or set +# REPOSITORY_DIR as environment variable. +# +# - Apply existing patches +# $ cmake -DCMD=apply -P libs/patches.cmake +# 1. This will clone all repositores to REPOSITORY_DIR. +# 2. Checkout git tag from Versions.cmake to a new ausweisap_ branch. +# It will delete that branch if it exist. +# 3. Apply all patches to the new branch. +# +# - Generate patches from repositories +# $ cmake -DCMD=generate -P libs/patches.cmake +# 1. All existing patches in "patches" directory will be deleted. +# 2. Branch of current Version on all repositories in REPOSITORY_DIR will be scanned. +# 3. All changesets from the latest tag will be exported to "patches" dir. +# +# If you need a new repository you can clone it into REPOSITORY_DIR. +# Checkout the release tag of used Version.cmake and cherry-pick or add +# changesets to it. It will be exported with "generate". +# If you need to remove patches, just delete the changesets or the whole clone. +# +# - Upgrade Qt or OpenSSL +# 1. Apply all patches with this script and do the following on each repository. +# The version is an example and should be adjusted! +# 2. git checkout ausweisapp_6.4.3 -b ausweisapp_6.6.0 +# 3. git rebase --onto v6.6.0 v6.4.3 HEAD +# 4. Bump version in Versions.cmake and use this script to generate the patches. + +if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT CMD) + message(FATAL_ERROR "Usage: cmake -DCMD=apply|generate -P libs/patches.cmake") +endif() + +find_package(Git REQUIRED) + +if(NOT REPOSITORY_DIR) + set(REPOSITORY_DIR $ENV{REPOSITORY_DIR}) + if(NOT REPOSITORY_DIR) + message(FATAL_ERROR "Define REPOSITORY_DIR for local repositories") + endif() + if(NOT EXISTS "${REPOSITORY_DIR}") + message(FATAL_ERROR "REPOSITORY_DIR ${REPOSITORY_DIR} does not exist") + endif() +endif() + +get_filename_component(libs_dir "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY) +set(patch_dir "${libs_dir}/patches") +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake;${libs_dir}") +include(Versions) + +function(execute_dir dir) + execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN} + WORKING_DIRECTORY "${REPOSITORY_DIR}/${dir}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() +endfunction() + +function(execute) + execute_dir("" ${ARGN}) +endfunction() + +function(git_clone prefix) + if(NOT EXISTS "${REPOSITORY_DIR}/${prefix}") + message(STATUS "Repository not found: ${prefix}") + if(prefix STREQUAL "openssl") + execute(clone "https://github.com/openssl/openssl" "${prefix}") + elseif(prefix MATCHES "qt") + execute(clone "https://code.qt.io/qt/${prefix}.git" "${prefix}") + endif() + endif() +endfunction() + +function(git_checkout prefix) + get_version_branch("${prefix}" version tmp_branch) + execute_dir("${prefix}" fetch) + execute_dir("${prefix}" checkout -q ${version}) + execute_process(COMMAND ${GIT_EXECUTABLE} branch -D ${tmp_branch} WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix}) + execute_process(COMMAND ${GIT_EXECUTABLE} am --abort WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix} OUTPUT_QUIET ERROR_QUIET) + execute_dir("${prefix}" checkout ${version} -b ${tmp_branch}) +endfunction() + +function(get_version_branch prefix _version _branch) + set(tmp_branch ausweisapp) + if(prefix STREQUAL "openssl") + set(version openssl-${OPENSSL}) + set(tmp_branch ${tmp_branch}_${OPENSSL}) + elseif(prefix MATCHES "qt") + set(version v${QT}) + set(tmp_branch ${tmp_branch}_${QT}) + endif() + + set(${_version} "${version}" PARENT_SCOPE) + set(${_branch} "${tmp_branch}" PARENT_SCOPE) +endfunction() + +function(apply_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + string(REGEX MATCH "([a-z|-]+)-[0-9]+.+" _unused "${filename}") + set(prefix ${CMAKE_MATCH_1}) + + list(APPEND prefixes "${prefix}") + list(APPEND "${prefix}" "${patch}") + + if(NOT (prefix STREQUAL "openssl" OR prefix MATCHES "qt")) + message(FATAL_ERROR "Prefix unknown: ${prefix}") + endif() + endforeach() + + list(REMOVE_DUPLICATES prefixes) + foreach(prefix ${prefixes}) + message(STATUS "Apply component: ${prefix}") + git_clone(${prefix}) + git_checkout(${prefix}) + + foreach(patch ${${prefix}}) + if(prefix STREQUAL "openssl") + set(p 1) + elseif(prefix MATCHES "qt") + set(p 2) + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} -E env GIT_COMMITTER_NAME="Governikus" GIT_COMMITTER_EMAIL="" -- + ${GIT_EXECUTABLE} am --whitespace=fix --no-gpg-sign --committer-date-is-author-date -p${p} "${patch}" + WORKING_DIRECTORY "${REPOSITORY_DIR}/${prefix}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "cannot apply patch: ${_result}") + endif() + endforeach() + endforeach() +endfunction() + + +function(get_latest_tag _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(${_result} EQUAL 0) + set(${_out} "${_output}" PARENT_SCOPE) + endif() +endfunction() + +function(get_current_branch _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() + set(${_out} "${_output}" PARENT_SCOPE) +endfunction() + +function(rename_patches component) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + if(filename MATCHES "^[0-9]+.*") + file(RENAME "${patch}" "${patch_dir}/${component}-${filename}") + endif() + endforeach() +endfunction() + +function(generate_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + if(PATCHES) + file(REMOVE ${PATCHES}) + endif() + + list(APPEND prefixes openssl qt) + foreach(prefix ${prefixes}) + file(GLOB REPOS "${REPOSITORY_DIR}/${prefix}*") + foreach(repo ${REPOS}) + get_filename_component(dirname "${repo}" NAME) + get_version_branch("${prefix}" version tmp_branch) + execute_process(COMMAND ${GIT_EXECUTABLE} checkout -q ${tmp_branch} WORKING_DIRECTORY ${repo} OUTPUT_QUIET ERROR_QUIET) + get_current_branch(current_branch "${repo}") + if(current_branch STREQUAL tmp_branch) + get_latest_tag(latesttag "${repo}") + message(STATUS "Generate patches of ${dirname} since tag ${latesttag}") + + if(dirname STREQUAL "openssl") + set(component "") + else() + set(component "${dirname}/") + endif() + + execute_dir("${dirname}" format-patch --no-signature --no-renames --no-binary --src-prefix=x/${component} --dst-prefix=y/${component} -k ${latesttag}..HEAD -o "${patch_dir}") + rename_patches(${dirname}) + else() + message(STATUS "Skip patches of ${dirname} and branch ${current_branch}") + endif() + endforeach() + endforeach() +endfunction() + + + +if(CMD STREQUAL "generate") + message(STATUS "Generate patches!") + generate_patches() +elseif(CMD STREQUAL "apply") + message(STATUS "Apply patches!") + apply_patches() +else() + message(FATAL_ERROR "Unknown CMD: ${CMD}") +endif() diff --git a/libs/patches/openssl-0001-Adjust-iOS-target.patch b/libs/patches/openssl-0001-Adjust-iOS-target.patch index c2345ef24..6f9fcdcc7 100644 --- a/libs/patches/openssl-0001-Adjust-iOS-target.patch +++ b/libs/patches/openssl-0001-Adjust-iOS-target.patch @@ -1,4 +1,4 @@ -From a16972bcfd33b694fd27d19e85754be74daa4430 Mon Sep 17 00:00:00 2001 +From c97e9531a9da0ad5ae3bfb7cec90b03475a58a76 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Fri, 12 Feb 2021 13:15:00 +0100 Subject: Adjust iOS target @@ -8,7 +8,7 @@ Subject: Adjust iOS target 1 file changed, 1 insertion(+), 1 deletion(-) diff --git x/Configurations/15-ios.conf y/Configurations/15-ios.conf -index 54d37f63f4..a4ade8d209 100644 +index 54d37f63f4..7e411b2e3a 100644 --- x/Configurations/15-ios.conf +++ y/Configurations/15-ios.conf @@ -25,7 +25,7 @@ my %targets = ( @@ -20,5 +20,3 @@ index 54d37f63f4..a4ade8d209 100644 bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", asm_arch => 'aarch64', perlasm_scheme => "ios64", --- -2.35.1 diff --git a/libs/patches/openssl-0002-android-shlib_variant.patch b/libs/patches/openssl-0002-android-shlib_variant.patch index 24f251fda..d562c1057 100644 --- a/libs/patches/openssl-0002-android-shlib_variant.patch +++ b/libs/patches/openssl-0002-android-shlib_variant.patch @@ -1,4 +1,4 @@ -From 8e011194bf8b4e4275f51f76b75a1b22e45e9564 Mon Sep 17 00:00:00 2001 +From 8353ce61f188109953e327b4bddf65c95e4baf92 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Tue, 19 Jan 2021 17:07:51 +0100 Subject: android shlib_variant @@ -41,6 +41,3 @@ index 41ad9223e0..f804aeb11b 100644 }, #################################################################### --- -2.35.1 - diff --git a/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch b/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch new file mode 100644 index 000000000..914498ed2 --- /dev/null +++ b/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch @@ -0,0 +1,55 @@ +From 9faa80071777b8a0b9eca1ab59bf69adb4621d9f Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Tue, 4 Jul 2023 17:30:35 +0200 +Subject: Do not ignore empty associated data with AES-SIV mode + +The AES-SIV mode allows for multiple associated data items +authenticated separately with any of these being 0 length. + +The provided implementation ignores such empty associated data +which is incorrect in regards to the RFC 5297 and is also +a security issue because such empty associated data then become +unauthenticated if an application expects to authenticate them. + +Fixes CVE-2023-2975 + +Reviewed-by: Matt Caswell +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/21384) + +(cherry picked from commit c426c281cfc23ab182f7d7d7a35229e7db1494d9) +(cherry picked from commit 00e2f5eea29994d19293ec4e8c8775ba73678598) +--- + .../implementations/ciphers/cipher_aes_siv.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git x/providers/implementations/ciphers/cipher_aes_siv.c y/providers/implementations/ciphers/cipher_aes_siv.c +index 45010b90db..b396c8651a 100644 +--- x/providers/implementations/ciphers/cipher_aes_siv.c ++++ y/providers/implementations/ciphers/cipher_aes_siv.c +@@ -120,14 +120,18 @@ static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + if (!ossl_prov_is_running()) + return 0; + +- if (inl == 0) { +- *outl = 0; +- return 1; +- } ++ /* Ignore just empty encryption/decryption call and not AAD. */ ++ if (out != NULL) { ++ if (inl == 0) { ++ if (outl != NULL) ++ *outl = 0; ++ return 1; ++ } + +- if (outsize < inl) { +- ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); +- return 0; ++ if (outsize < inl) { ++ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); ++ return 0; ++ } + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) diff --git a/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch b/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch new file mode 100644 index 000000000..4582d5309 --- /dev/null +++ b/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch @@ -0,0 +1,72 @@ +From c012334ed713416cc30d6b2ff4dbeca97d1503c3 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Thu, 6 Jul 2023 16:36:35 +0100 +Subject: Fix DH_check() excessive time with over sized modulus + +The DH_check() function checks numerous aspects of the key or parameters +that have been supplied. Some of those checks use the supplied modulus +value even if it is excessively large. + +There is already a maximum DH modulus size (10,000 bits) over which +OpenSSL will not generate or derive keys. DH_check() will however still +perform various tests for validity on such a large modulus. We introduce a +new maximum (32,768) over which DH_check() will just fail. + +An application that calls DH_check() and supplies a key or parameters +obtained from an untrusted source could be vulnerable to a Denial of +Service attack. + +The function DH_check() is itself called by a number of other OpenSSL +functions. An application calling any of those other functions may +similarly be affected. The other functions affected by this are +DH_check_ex() and EVP_PKEY_param_check(). + +CVE-2023-3446 + +Reviewed-by: Paul Dale +Reviewed-by: Tom Cosgrove +Reviewed-by: Bernd Edlinger +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/21451) + +(cherry picked from commit 9e0094e2aa1b3428a12d5095132f133c078d3c3d) +(cherry picked from commit 1fa20cf2f506113c761777127a38bce5068740eb) +--- + crypto/dh/dh_check.c | 6 ++++++ + include/openssl/dh.h | 6 +++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git x/crypto/dh/dh_check.c y/crypto/dh/dh_check.c +index 0b391910d6..84a926998e 100644 +--- x/crypto/dh/dh_check.c ++++ y/crypto/dh/dh_check.c +@@ -152,6 +152,12 @@ int DH_check(const DH *dh, int *ret) + if (nid != NID_undef) + return 1; + ++ /* Don't do any checks at all with an excessively large modulus */ ++ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ++ ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); ++ return 0; ++ } ++ + if (!DH_check_params(dh, ret)) + return 0; + +diff --git x/include/openssl/dh.h y/include/openssl/dh.h +index b97871eca7..36420f51d8 100644 +--- x/include/openssl/dh.h ++++ y/include/openssl/dh.h +@@ -89,7 +89,11 @@ int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm); + # include + + # ifndef OPENSSL_DH_MAX_MODULUS_BITS +-# define OPENSSL_DH_MAX_MODULUS_BITS 10000 ++# define OPENSSL_DH_MAX_MODULUS_BITS 10000 ++# endif ++ ++# ifndef OPENSSL_DH_CHECK_MAX_MODULUS_BITS ++# define OPENSSL_DH_CHECK_MAX_MODULUS_BITS 32768 + # endif + + # define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024 diff --git a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch b/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch deleted file mode 100644 index 86f8eb005..000000000 --- a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c6818d0c25f067bc13198b9aa2ca82776a40ad3b Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Wed, 14 Dec 2022 11:52:12 +0100 -Subject: Revert "Android: Fix QSettings when using content URL" - -This reverts commit 140ca89a3c2b8d78889d27217f977cd4de10041b. ---- - src/corelib/io/qsettings.cpp | 21 +++------------------ - 1 file changed, 3 insertions(+), 18 deletions(-) - -diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp -index 60622e3aaa..a999aa6996 100644 ---- x/qtbase/src/corelib/io/qsettings.cpp -+++ y/qtbase/src/corelib/io/qsettings.cpp -@@ -48,9 +48,8 @@ - #define Q_XDG_PLATFORM - #endif - --#if !defined(QT_NO_STANDARDPATHS) \ -- && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID)) --# define QSETTINGS_USE_QSTANDARDPATHS -+#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT)) -+#define QSETTINGS_USE_QSTANDARDPATHS - #endif - - // ************************************************************************ -@@ -1332,15 +1331,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - } - - #ifndef QT_BOOTSTRAPPED -- QString lockFileName = confFile->name + ".lock"_L1; -- --# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS) -- // On android and if it is a content URL put the lock file in a -- // writable location to prevent permissions issues and invalid paths. -- if (confFile->name.startsWith("content:"_L1)) -- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) -- + QFileInfo(lockFileName).fileName(); --# endif - /* - Use a lockfile in order to protect us against other QSettings instances - trying to write the same settings at the same time. -@@ -1348,7 +1338,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - We only need to lock if we are actually writing as only concurrent writes are a problem. - Concurrent read and write are not a problem because the writing operation is atomic. - */ -- QLockFile lockFile(lockFileName); -+ QLockFile lockFile(confFile->name + ".lock"_L1); - if (!readOnly && !lockFile.lock() && atomicSyncOnly) { - setStatus(QSettings::AccessError); - return; -@@ -1426,11 +1416,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) - QSaveFile sf(confFile->name); - sf.setDirectWriteFallback(!atomicSyncOnly); --# ifdef Q_OS_ANDROID -- // QSaveFile requires direct write when using content scheme URL in Android -- if (confFile->name.startsWith("content:"_L1)) -- sf.setDirectWriteFallback(true); --# endif - #else - QFile sf(confFile->name); - #endif --- -2.39.0 - diff --git a/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch similarity index 95% rename from libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch rename to libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch index 23f53c9c0..8a73295e4 100644 --- a/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch +++ b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch @@ -1,4 +1,4 @@ -From ca3a694221c62131a384cbabd7dc34f91add9eae Mon Sep 17 00:00:00 2001 +From 68bc2e3fae6480d6315f524c2ee9acf3a33a435a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Mon, 25 Jul 2022 17:08:54 +0200 Subject: Revert "Fix usage of logging category on Android" @@ -38,6 +38,3 @@ index 9ac70b3340..737a91dc6e 100644 return true; // Prevent further output to stderr } --- -2.38.1 - diff --git a/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch b/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch new file mode 100644 index 000000000..13641dcee --- /dev/null +++ b/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch @@ -0,0 +1,89 @@ +From bdd9f0e3a243977858df6691b734b7f596a9729b Mon Sep 17 00:00:00 2001 +From: Bartlomiej Moskal +Date: Tue, 30 May 2023 14:17:19 +0200 +Subject: Android: Restore the default QSettings path to the .config directory + +After 140ca89a3c2b8d78889d27217f977cd4de10041b commit, the path of the +QSettings default file location changed. That caused the problem with +updating the app (old settings file is not used anymore). That is why we +should still use old (.config) directory for QSettings file if the file +exists. + +Pick-to: 6.2 6.5 6.6 +Fixes: QTBUG-109405 +Fixes: QTBUG-109369 +Change-Id: I8ce53e0a80e4c2d16802b27b000ab3fbed198628 +Reviewed-by: Assam Boudjelthia +(cherry picked from commit beaaa0bf02fee696b03f2839bea8e0e6bc685a62) +--- + src/corelib/io/qsettings.cpp | 40 +++++++++++++++++++++++++----------- + 1 file changed, 28 insertions(+), 12 deletions(-) + +diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp +index 60622e3aaa..9fb2e0b522 100644 +--- x/qtbase/src/corelib/io/qsettings.cpp ++++ y/qtbase/src/corelib/io/qsettings.cpp +@@ -954,26 +954,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope) + } + + #ifndef Q_OS_WIN +-static QString make_user_path() ++static constexpr QChar sep = u'/'; ++ ++#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID) ++static QString make_user_path_without_qstandard_paths() + { +- static constexpr QChar sep = u'/'; +-#ifndef QSETTINGS_USE_QSTANDARDPATHS +- // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously +- // for some time now. Moving away from that would require migrating existing settings. + QByteArray env = qgetenv("XDG_CONFIG_HOME"); + if (env.isEmpty()) { + return QDir::homePath() + "/.config/"_L1; + } else if (env.startsWith('/')) { + return QFile::decodeName(env) + sep; +- } else { +- return QDir::homePath() + sep + QFile::decodeName(env) + sep; + } ++ ++ return QDir::homePath() + sep + QFile::decodeName(env) + sep; ++} ++#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID ++ ++static QString make_user_path() ++{ ++#ifndef QSETTINGS_USE_QSTANDARDPATHS ++ // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously ++ // for some time now. Moving away from that would require migrating existing settings. ++ // The migration has already been done for Android. ++ return make_user_path_without_qstandard_paths(); + #else +- // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code; +- // it makes the use of test mode from unit tests possible. ++ ++#ifdef Q_OS_ANDROID ++ // If an old settings path exists, use it instead of creating a new one ++ QString ret = make_user_path_without_qstandard_paths(); ++ if (QFile(ret).exists()) ++ return ret; ++#endif // Q_OS_ANDROID ++ ++ // When using a proper XDG platform or Android platform, use QStandardPaths rather than the ++ // above hand-written code. It makes the use of test mode from unit tests possible. + // Ideally all platforms should use this, but see above for the migration issue. + return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep; +-#endif ++#endif // !QSETTINGS_USE_QSTANDARDPATHS + } + #endif // !Q_OS_WIN + +@@ -1338,8 +1355,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) + // On android and if it is a content URL put the lock file in a + // writable location to prevent permissions issues and invalid paths. + if (confFile->name.startsWith("content:"_L1)) +- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +- + QFileInfo(lockFileName).fileName(); ++ lockFileName = make_user_path() + QFileInfo(lockFileName).fileName(); + # endif + /* + Use a lockfile in order to protect us against other QSettings instances diff --git a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch b/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch similarity index 97% rename from libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch rename to libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch index ea17cb1c6..df111949d 100644 --- a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch +++ b/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch @@ -1,4 +1,4 @@ -From 97d4394f85f120724a9cbe518ba2233b87e48c68 Mon Sep 17 00:00:00 2001 +From a7490023e8f11906b30013c93ff991d941efc622 Mon Sep 17 00:00:00 2001 From: Julian Greilich Date: Wed, 4 Jan 2023 16:32:28 +0100 Subject: Android A11Y: Only access the main thread when it is not blocked @@ -61,6 +61,3 @@ index 3067cb178a..8990289dc4 100644 if (!QtAndroid::blockEventLoopsWhenSuspended() || QGuiApplication::applicationState() != Qt::ApplicationSuspended) { QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal); --- -2.39.0 - diff --git a/libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch b/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch similarity index 97% rename from libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch rename to libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch index 29a703777..e9761b1d9 100644 --- a/libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch +++ b/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch @@ -1,4 +1,4 @@ -From bc1b984a5b1a53c0c9eccc44763aaf0c94294fb7 Mon Sep 17 00:00:00 2001 +From 03485e0ca36c615b87b82c6711fbacf0493d02bc Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Mon, 9 Jan 2023 06:54:53 +0100 Subject: Fix warning in q20algorithm.h when xcodebuild is used @@ -44,6 +44,3 @@ index 69dc2d2446..88e8ab08d2 100644 { while (first != last) { if (std::invoke(pred, std::invoke(proj, *first))) --- -2.39.0 - diff --git a/libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch b/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch similarity index 97% rename from libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch rename to libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch index 737430dba..85819c91f 100644 --- a/libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch +++ b/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch @@ -1,4 +1,4 @@ -From d5555d3c62cbc8c061de0ae9e1f0c20374b4004e Mon Sep 17 00:00:00 2001 +From e2402debef95b7ccc2050f331ee9f5076332ae91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 12 Dec 2022 14:33:41 +0100 Subject: macOS: Use NSStatusItem.menu to manage system tray menu @@ -26,7 +26,7 @@ Reviewed-by: Volker Hilsheimer 2 files changed, 24 insertions(+), 15 deletions(-) diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -index 414560e1192..75c33cc5a3f 100644 +index 414560e119..75c33cc5a3 100644 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h @@ -45,12 +45,11 @@ public: @@ -44,7 +44,7 @@ index 414560e1192..75c33cc5a3f 100644 QT_END_NAMESPACE diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index c004cd69b57..2f7f73b4813 100644 +index c004cd69b5..2f7f73b481 100644 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init() @@ -125,6 +125,3 @@ index c004cd69b57..2f7f73b4813 100644 } - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification --- -2.39.2 - diff --git a/libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch b/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch similarity index 93% rename from libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch rename to libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch index b5c1ff9c8..63c2ce919 100644 --- a/libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch +++ b/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch @@ -1,4 +1,4 @@ -From e28710e3f175663b030c00d75ee899a9a7b0cdd2 Mon Sep 17 00:00:00 2001 +From d967022bcd7061771f10e4d36d38ab8ffe5aef98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 15 Dec 2022 16:40:34 +0100 Subject: iOS: Don't assume screens will not be connected before @@ -25,7 +25,7 @@ Reviewed-by: Volker Hilsheimer 1 file changed, 2 insertions(+), 2 deletions(-) diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index f144c00fb0a..3d660189af4 100644 +index f144c00fb0..3d660189af 100644 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm @@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) @@ -39,6 +39,3 @@ index f144c00fb0a..3d660189af4 100644 QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object])); } --- -2.39.2 - diff --git a/libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch b/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch similarity index 95% rename from libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch rename to libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch index 548920794..ff423344e 100644 --- a/libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch +++ b/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch @@ -1,4 +1,4 @@ -From ae857fcf8415daafa6b77999dc8a44cd0e5ede7b Mon Sep 17 00:00:00 2001 +From 6d6832fc530c9296d92dd924f6f6bca0effa6412 Mon Sep 17 00:00:00 2001 From: Jan Moeller Date: Thu, 6 Apr 2023 09:27:16 +0200 Subject: Ignore removed/changed screens if no QIOSIntegration instance exists @@ -29,7 +29,7 @@ Reviewed-by: Lars Schmertmann 1 file changed, 6 insertions(+) diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index 3d660189af4..e0216ce6526 100644 +index 3d660189af..e0216ce652 100644 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm @@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) @@ -52,6 +52,3 @@ index 3d660189af4..e0216ce6526 100644 QIOSScreen *screen = qtPlatformScreenFor([notification object]); Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about"); --- -2.39.2 - diff --git a/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch b/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch new file mode 100644 index 000000000..ba82d2414 --- /dev/null +++ b/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch @@ -0,0 +1,75 @@ +From 25b9264bd6e5a547db3692032dd5c49cb2db0bfd Mon Sep 17 00:00:00 2001 +From: Allan Sandfeld Jensen +Date: Fri, 5 May 2023 09:51:32 +0200 +Subject: Fix specific overflow in qtextlayout + +Adds qAddOverflow and qMulOverflow definitions to QFixed + +Fixes: QTBUG-113337 +Pick-to: 6.5 6.5.1 6.2 5.15 +Change-Id: I13579306defceaccdc0fbb1ec0e9b77c6f8d1af9 +Reviewed-by: Eirik Aavitsland +Reviewed-by: Thiago Macieira +(cherry picked from commit 7b7a01c266b507636eab51a36328c7c72d82d93c) +--- + src/gui/painting/qfixed_p.h | 17 +++++++++++++++++ + src/gui/text/qtextlayout.cpp | 9 ++++++--- + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/gui/painting/qfixed_p.h y/qtbase/src/gui/painting/qfixed_p.h +index f3718a097e..c0a13d057f 100644 +--- x/qtbase/src/gui/painting/qfixed_p.h ++++ y/qtbase/src/gui/painting/qfixed_p.h +@@ -18,6 +18,7 @@ + #include + #include "QtCore/qdebug.h" + #include "QtCore/qpoint.h" ++#include "QtCore/qnumeric.h" + #include "QtCore/qsize.h" + + QT_BEGIN_NAMESPACE +@@ -136,6 +137,22 @@ constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; } + constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); } + // constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; } + ++inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r) ++{ ++ int val; ++ bool result = qAddOverflow(v1.value(), v2.value(), &val); ++ r->setValue(val); ++ return result; ++} ++ ++inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r) ++{ ++ int val; ++ bool result = qMulOverflow(v1.value(), v2.value(), &val); ++ r->setValue(val); ++ return result; ++} ++ + #ifndef QT_NO_DEBUG_STREAM + inline QDebug &operator<<(QDebug &dbg, QFixed f) + { return dbg << f.toReal(); } +diff --git x/qtbase/src/gui/text/qtextlayout.cpp y/qtbase/src/gui/text/qtextlayout.cpp +index 365131f508..6a36b2458a 100644 +--- x/qtbase/src/gui/text/qtextlayout.cpp ++++ y/qtbase/src/gui/text/qtextlayout.cpp +@@ -2105,11 +2105,14 @@ found: + eng->maxWidth = qMax(eng->maxWidth, line.textWidth); + } else { + eng->minWidth = qMax(eng->minWidth, lbh.minw); +- eng->maxWidth += line.textWidth; ++ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; + } + +- if (line.textWidth > 0 && item < eng->layoutData->items.size()) +- eng->maxWidth += lbh.spaceData.textWidth; ++ if (line.textWidth > 0 && item < eng->layoutData->items.size()) { ++ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; ++ } + + line.textWidth += trailingSpace; + if (lbh.spaceData.length) { diff --git a/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch b/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch new file mode 100644 index 000000000..9f1a1ec5b --- /dev/null +++ b/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch @@ -0,0 +1,289 @@ +From 550172c8a2f5e7195e2255bc50cffb2a64b8701c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= +Date: Wed, 10 May 2023 16:43:41 +0200 +Subject: Schannel: Reject certificate not signed by a configured CA + certificate + +Not entirely clear why, but when building the certificate chain for a +peer the system certificate store is searched for root certificates. +General expectation is that after calling +`sslConfiguration.setCaCertificates()` the system certificates will +not be taken into consideration. + +To work around this behavior, we do a manual check that the root of the +chain is part of the configured CA certificates. + +Pick-to: 6.5 6.2 5.15 +Change-Id: I03666a4d9b0eac39ae97e150b4743120611a11b3 +Reviewed-by: Edward Welbourne +Reviewed-by: Volker Hilsheimer +(cherry picked from commit ada2c573c1a25f8d96577734968fe317ddfa292a) +--- + src/plugins/tls/schannel/qtls_schannel.cpp | 21 ++++ + .../network/ssl/client-auth/CMakeLists.txt | 24 ++++ + .../network/ssl/client-auth/certs/.gitignore | 4 + + .../client-auth/certs/accepted-client.conf | 14 +++ + .../network/ssl/client-auth/certs/generate.sh | 33 +++++ + .../tst_manual_ssl_client_auth.cpp | 118 ++++++++++++++++++ + 6 files changed, 214 insertions(+) + create mode 100644 tests/manual/network/ssl/client-auth/CMakeLists.txt + create mode 100644 tests/manual/network/ssl/client-auth/certs/.gitignore + create mode 100644 tests/manual/network/ssl/client-auth/certs/accepted-client.conf + create mode 100755 tests/manual/network/ssl/client-auth/certs/generate.sh + create mode 100644 tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp + +diff --git x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp +index 58e74357d8..c15eab8796 100644 +--- x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp ++++ y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp +@@ -2106,6 +2106,27 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext) + verifyDepth = DWORD(q->peerVerifyDepth()); + + const auto &caCertificates = q->sslConfiguration().caCertificates(); ++ ++ if (!rootCertOnDemandLoadingAllowed() ++ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) ++ && (q->peerVerifyMode() == QSslSocket::VerifyPeer ++ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) { ++ // When verifying a peer Windows "helpfully" builds a chain that ++ // may include roots from the system store. But we don't want that if ++ // the user has set their own CA certificates. ++ // Since Windows claims this is not a partial chain the root is included ++ // and we have to check that it is one of our configured CAs. ++ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1]; ++ QSslCertificate certificate = getCertificateFromChainElement(element); ++ if (!caCertificates.contains(certificate)) { ++ auto error = QSslError(QSslError::CertificateUntrusted, certificate); ++ sslErrors += error; ++ emit q->peerVerifyError(error); ++ if (q->state() != QAbstractSocket::ConnectedState) ++ return false; ++ } ++ } ++ + QList peerCertificateChain; + for (DWORD i = 0; i < verifyDepth; i++) { + CERT_CHAIN_ELEMENT *element = chain->rgpElement[i]; +diff --git x/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt +new file mode 100644 +index 0000000000..67ecc20bf4 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt +@@ -0,0 +1,24 @@ ++# Copyright (C) 2023 The Qt Company Ltd. ++# SPDX-License-Identifier: BSD-3-Clause ++ ++qt_internal_add_manual_test(tst_manual_ssl_client_auth ++ SOURCES ++ tst_manual_ssl_client_auth.cpp ++ LIBRARIES ++ Qt::Network ++) ++ ++qt_internal_add_resource(tst_manual_ssl_client_auth "tst_manual_ssl_client_auth" ++ PREFIX ++ "/" ++ FILES ++ "certs/127.0.0.1.pem" ++ "certs/127.0.0.1-key.pem" ++ "certs/127.0.0.1-client.pem" ++ "certs/127.0.0.1-client-key.pem" ++ "certs/accepted-client.pem" ++ "certs/accepted-client-key.pem" ++ "certs/rootCA.pem" ++ BASE ++ "certs" ++) +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore +new file mode 100644 +index 0000000000..5866f7b609 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore +@@ -0,0 +1,4 @@ ++* ++!/.gitignore ++!/generate.sh ++!/accepted-client.conf +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf +new file mode 100644 +index 0000000000..a88b276efe +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf +@@ -0,0 +1,14 @@ ++[req] ++default_md = sha512 ++basicConstraints = CA:FALSE ++extendedKeyUsage = clientAuth ++[req] ++distinguished_name = client_distinguished_name ++prompt = no ++[client_distinguished_name] ++C = NO ++ST = Oslo ++L = Oslo ++O = The Qt Project ++OU = The Qt Project ++CN = Fake Qt Project Client Certificate +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh +new file mode 100755 +index 0000000000..5dbe3b3712 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++# Copyright (C) 2023 The Qt Company Ltd. ++# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++# Requires mkcert and openssl ++ ++warn () { echo "$@" >&2; } ++die () { warn "$@"; exit 1; } ++ ++ ++command -v mkcert 1>/dev/null 2>&1 || die "Failed to find mkcert" ++command -v openssl 1>/dev/null 2>&1 || die "Failed to find openssl" ++ ++SCRIPT=$(realpath "$0") ++SCRIPTPATH=$(dirname "$SCRIPT") ++ ++pushd "$SCRIPTPATH" || die "Unable to pushd to $SCRIPTPATH" ++mkcert 127.0.0.1 ++mkcert -client 127.0.0.1 ++warn "Remember to run mkcert -install if you haven't already" ++ ++# Generate CA ++openssl genrsa -out ca-key.pem 2048 ++openssl req -new -x509 -noenc -days 365 -key ca-key.pem -out rootCA.pem ++ ++# Generate accepted client certificate ++openssl genrsa -out accepted-client-key.pem 2048 ++openssl req -new -sha512 -nodes -key accepted-client-key.pem -out accepted-client.csr -config accepted-client.conf ++openssl x509 -req -sha512 -days 45 -in accepted-client.csr -CA rootCA.pem -CAkey ca-key.pem -CAcreateserial -out accepted-client.pem ++rm accepted-client.csr ++rm rootCA.srl ++ ++popd || die "Unable to popd" +diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +new file mode 100644 +index 0000000000..2307cbb191 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +@@ -0,0 +1,118 @@ ++// Copyright (C) 2023 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++// Client and/or server presents a certificate signed by a system-trusted CA ++// but the other side presents a certificate signed by a different CA. ++constexpr bool TestServerPresentsIncorrectCa = false; ++constexpr bool TestClientPresentsIncorrectCa = true; ++ ++class ServerThread : public QThread ++{ ++ Q_OBJECT ++public: ++ void run() override ++ { ++ QSslServer server; ++ ++ QSslConfiguration config = server.sslConfiguration(); ++ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); ++ config.setCaCertificates(certs); ++ config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) ++ .first()); ++ QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); ++ if (!keyFile.open(QIODevice::ReadOnly)) ++ qFatal("Failed to open key file"); ++ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ config.setPeerVerifyMode(QSslSocket::VerifyPeer); ++ server.setSslConfiguration(config); ++ ++ connect(&server, &QSslServer::pendingConnectionAvailable, [&server]() { ++ QSslSocket *socket = static_cast(server.nextPendingConnection()); ++ qDebug() << "[s] newConnection" << socket->peerAddress() << socket->peerPort(); ++ socket->disconnectFromHost(); ++ qApp->quit(); ++ }); ++ connect(&server, &QSslServer::startedEncryptionHandshake, [](QSslSocket *socket) { ++ qDebug() << "[s] new handshake" << socket->peerAddress() << socket->peerPort(); ++ }); ++ connect(&server, &QSslServer::errorOccurred, ++ [](QSslSocket *socket, QAbstractSocket::SocketError error) { ++ qDebug() << "[s] errorOccurred" << socket->peerAddress() << socket->peerPort() ++ << error << socket->errorString(); ++ }); ++ connect(&server, &QSslServer::peerVerifyError, ++ [](QSslSocket *socket, const QSslError &error) { ++ qDebug() << "[s] peerVerifyError" << socket->peerAddress() << socket->peerPort() ++ << error; ++ }); ++ server.listen(QHostAddress::LocalHost, 24242); ++ ++ exec(); ++ ++ server.close(); ++ } ++}; ++ ++int main(int argc, char **argv) ++{ ++ QCoreApplication app(argc, argv); ++ ++ using namespace Qt::StringLiterals; ++ ++ if (!QFileInfo(u":/rootCA.pem"_s).exists()) ++ qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); ++ ++ ServerThread serverThread; ++ serverThread.start(); ++ ++ QSslSocket socket; ++ QSslConfiguration config = socket.sslConfiguration(); ++ QString certificatePath; ++ QString keyFileName; ++ if constexpr (TestClientPresentsIncorrectCa) { // true: Present cert signed with incorrect CA: should fail ++ certificatePath = u":/127.0.0.1-client.pem"_s; ++ keyFileName = u":/127.0.0.1-client-key.pem"_s; ++ } else { // false: Use correct CA: should succeed ++ certificatePath = u":/accepted-client.pem"_s; ++ keyFileName = u":/accepted-client-key.pem"_s; ++ } ++ config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); ++ if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail ++ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ QFile keyFile(keyFileName); ++ if (!keyFile.open(QIODevice::ReadOnly)) ++ qFatal("Failed to open key file"); ++ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ socket.setSslConfiguration(config); ++ ++ QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); ++ QObject::connect(&socket, &QSslSocket::errorOccurred, ++ [&socket](QAbstractSocket::SocketError error) { ++ qDebug() << "[c] errorOccurred" << error << socket.errorString(); ++ qApp->quit(); ++ }); ++ QObject::connect(&socket, &QSslSocket::sslErrors, [](const QList &errors) { ++ qDebug() << "[c] sslErrors" << errors; ++ }); ++ QObject::connect(&socket, &QSslSocket::connected, []() { qDebug() << "[c] connected"; }); ++ ++ socket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), 24242); ++ ++ const int res = app.exec(); ++ serverThread.quit(); ++ serverThread.wait(); ++ return res; ++} ++ ++#include "tst_manual_ssl_client_auth.moc" diff --git a/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch b/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch new file mode 100644 index 000000000..84724d31b --- /dev/null +++ b/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch @@ -0,0 +1,110 @@ +From d13e70c1d56a94d64eb68d2f3cba670e58a1a73f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= +Date: Thu, 25 May 2023 14:40:29 +0200 +Subject: Ssl: Copy the on-demand cert loading bool from default config + +Otherwise individual sockets will still load system certificates when +a chain doesn't match against the configured CA certificates. +That's not intended behavior, since specifically setting the CA +certificates means you don't want the system certificates to be used. + +Follow-up to/amends ada2c573c1a25f8d96577734968fe317ddfa292a + +This is potentially a breaking change because now, if you ever add a +CA to the default config, it will disable loading system certificates +on demand for all sockets. And the only way to re-enable it is to +create a null-QSslConfiguration and set it as the new default. + +Pick-to: 6.5 6.2 5.15 +Change-Id: Ic3b2ab125c0cdd58ad654af1cb36173960ce2d1e +Reviewed-by: Timur Pocheptsov +(cherry picked from commit 57ba6260c0801055b7188fdaa1818b940590f5f1) +--- + src/network/ssl/qsslsocket.cpp | 5 ++++ + .../tst_manual_ssl_client_auth.cpp | 24 ++++++++++++++++--- + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp +index cd76517c25..a94f2b79c3 100644 +--- x/qtbase/src/network/ssl/qsslsocket.cpp ++++ y/qtbase/src/network/ssl/qsslsocket.cpp +@@ -1973,6 +1973,10 @@ QSslSocketPrivate::QSslSocketPrivate() + , flushTriggered(false) + { + QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); ++ // If the global configuration doesn't allow root certificates to be loaded ++ // on demand then we have to disable it for this socket as well. ++ if (!configuration.allowRootCertOnDemandLoading) ++ allowRootCertOnDemandLoading = false; + + const auto *tlsBackend = tlsBackendInUse(); + if (!tlsBackend) { +@@ -2281,6 +2285,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri + ptr->sessionProtocol = global->sessionProtocol; + ptr->ciphers = global->ciphers; + ptr->caCertificates = global->caCertificates; ++ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading; + ptr->protocol = global->protocol; + ptr->peerVerifyMode = global->peerVerifyMode; + ptr->peerVerifyDepth = global->peerVerifyDepth; +diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +index 2307cbb191..4d4aaca7e3 100644 +--- x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp ++++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +@@ -16,6 +16,9 @@ + // but the other side presents a certificate signed by a different CA. + constexpr bool TestServerPresentsIncorrectCa = false; + constexpr bool TestClientPresentsIncorrectCa = true; ++// Decides whether or not to put the root CA into the global ssl configuration ++// or into the socket's specific ssl configuration. ++constexpr bool UseGlobalConfiguration = true; + + class ServerThread : public QThread + { +@@ -26,8 +29,10 @@ public: + QSslServer server; + + QSslConfiguration config = server.sslConfiguration(); +- QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); +- config.setCaCertificates(certs); ++ if (!UseGlobalConfiguration) { ++ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); ++ config.setCaCertificates(certs); ++ } + config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) + .first()); + QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); +@@ -73,6 +78,12 @@ int main(int argc, char **argv) + if (!QFileInfo(u":/rootCA.pem"_s).exists()) + qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); + ++ if (UseGlobalConfiguration) { ++ QSslConfiguration config = QSslConfiguration::defaultConfiguration(); ++ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ QSslConfiguration::setDefaultConfiguration(config); ++ } ++ + ServerThread serverThread; + serverThread.start(); + +@@ -88,12 +99,19 @@ int main(int argc, char **argv) + keyFileName = u":/accepted-client-key.pem"_s; + } + config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); +- if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail ++ if (!UseGlobalConfiguration && TestServerPresentsIncorrectCa) { ++ // Verify server using incorrect CA: should fail + config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ } else if (UseGlobalConfiguration && !TestServerPresentsIncorrectCa) { ++ // Verify server using correct CA, we need to explicitly set the ++ // system CAs when the global config is overridden. ++ config.setCaCertificates(QSslConfiguration::systemCaCertificates()); ++ } + QFile keyFile(keyFileName); + if (!keyFile.open(QIODevice::ReadOnly)) + qFatal("Failed to open key file"); + config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ + socket.setSslConfiguration(config); + + QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); diff --git a/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch b/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch new file mode 100644 index 000000000..4dcdca6fe --- /dev/null +++ b/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch @@ -0,0 +1,51 @@ +From bdc4845cd844e674f17161435a11e60dde2769cc Mon Sep 17 00:00:00 2001 +From: Jens Trillmann +Date: Wed, 5 Jul 2023 09:33:03 +0200 +Subject: Improve Intent source app detection + +Activity.getReferrer does not only return app IDs but also URLs if +Intent.EXTRA_REFERRER is set on the Intent. In the case of Chrome the referrer +is set to the website triggering the Intent. To improve the detection of the +calling app we check first if the browser specific +Browser.EXTRAS_APPLICATION_ID is set. If it is not set we fall back to +Intent.getReferrer. + +Pick-to: 6.6 +Change-Id: I33d1edd52de98486d9616713e531ea20ada87bcb +--- + .../qtproject/qt/android/bindings/QtActivity.java | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java +index 9cef8146fd..f862f6aaee 100644 +--- x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java ++++ y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java +@@ -16,6 +16,7 @@ import android.graphics.Canvas; + import android.net.Uri; + import android.os.Build; + import android.os.Bundle; ++import android.provider.Browser; + import android.util.AttributeSet; + import android.view.ActionMode; + import android.view.ActionMode.Callback; +@@ -237,9 +238,17 @@ public class QtActivity extends Activity + return; + + String sourceInformation = ""; +- Uri referrer = getReferrer(); +- if (referrer != null) +- sourceInformation = referrer.toString().replaceFirst("android-app://", ""); ++ String browserApplicationId = intent.getExtras() == null ? "" : intent.getExtras().getString(Browser.EXTRA_APPLICATION_ID); ++ if (!browserApplicationId.isEmpty()) ++ { ++ sourceInformation = browserApplicationId; ++ } ++ else ++ { ++ Uri referrer = getReferrer(); ++ if (referrer != null) ++ sourceInformation = referrer.toString().replaceFirst("android-app://", ""); ++ } + + intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation); + } diff --git a/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch b/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch new file mode 100644 index 000000000..5602a0238 --- /dev/null +++ b/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch @@ -0,0 +1,105 @@ +From f9a1c8668e5f4787e9b0b3136076138f4fda5563 Mon Sep 17 00:00:00 2001 +From: Ahmad Samir +Date: Wed, 12 Apr 2023 13:10:26 +0200 +Subject: QXmlStreamReader: change fastScanName() to take a Value* + +For easier debugging, e.g. to print out value.len and value.prefix. + +Pick-to: 6.6 6.5 6.5.2 6.2 5.15 +Change-Id: Ib0eed38772f899502962f578775d34ea2744fdde +Reviewed-by: Marc Mutz +(cherry picked from commit 1a423ce4372d18a779f3c0d746d5283d9a425839) +--- + src/corelib/serialization/qxmlstream.cpp | 16 ++++++++-------- + src/corelib/serialization/qxmlstream.g | 3 ++- + src/corelib/serialization/qxmlstream_p.h | 2 +- + src/corelib/serialization/qxmlstreamparser_p.h | 3 ++- + 4 files changed, 13 insertions(+), 11 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index a6a2bc41af..f64db47867 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -1243,7 +1243,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() + return n; + } + +-inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) ++inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + { + qsizetype n = 0; + uint c; +@@ -1280,16 +1280,16 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) + case '+': + case '*': + putChar(c); +- if (prefix && *prefix == n+1) { +- *prefix = 0; ++ if (val && val->prefix == n + 1) { ++ val->prefix = 0; + putChar(':'); + --n; + } + return n; + case ':': +- if (prefix) { +- if (*prefix == 0) { +- *prefix = qint16(n + 2); ++ if (val) { ++ if (val->prefix == 0) { ++ val->prefix = qint16(n + 2); + } else { // only one colon allowed according to the namespace spec. + putChar(c); + return n; +@@ -1305,8 +1305,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) + } + } + +- if (prefix) +- *prefix = 0; ++ if (val) ++ val->prefix = 0; + qsizetype pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); +diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g +index d06c371eb8..f3152bff37 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.g ++++ y/qtbase/src/corelib/serialization/qxmlstream.g +@@ -1419,7 +1419,8 @@ space_opt ::= space; + qname ::= LETTER; + /. + case $rule_number: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ val.len += fastScanName(&val); + if (atEnd) { + resume($rule_number); + return false; +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 8e523f9c67..5da1f4aa5a 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -471,7 +471,7 @@ public: + qsizetype fastScanLiteralContent(); + qsizetype fastScanSpace(); + qsizetype fastScanContentCharList(); +- qsizetype fastScanName(qint16 *prefix = nullptr); ++ qsizetype fastScanName(Value *val = nullptr); + inline qsizetype fastScanNMTOKEN(); + + +diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +index e3ae6faa44..59370a9310 100644 +--- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +@@ -947,7 +947,8 @@ bool QXmlStreamReaderPrivate::parse() + break; + + case 262: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ val.len += fastScanName(&val); + if (atEnd) { + resume(262); + return false; diff --git a/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch b/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch new file mode 100644 index 000000000..375a274a4 --- /dev/null +++ b/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch @@ -0,0 +1,270 @@ +From 836d7df23ec9b6cb3dea1bb68b7c8bc75090702e Mon Sep 17 00:00:00 2001 +From: Ahmad Samir +Date: Thu, 22 Jun 2023 15:56:07 +0300 +Subject: QXmlStreamReader: make fastScanName() indicate parsing status to + callers + +This fixes a crash while parsing an XML file with garbage data, the file +starts with '<' then garbage data: +- The loop in the parse() keeps iterating until it hits "case 262:", + which calls fastScanName() +- fastScanName() iterates over the text buffer scanning for the + attribute name (e.g. "xml:lang"), until it finds ':' +- Consider a Value val, fastScanName() is called on it, it would set + val.prefix to a number > val.len, then it would hit the 4096 condition + and return (returned 0, now it returns the equivalent of + std::null_opt), which means that val.len doesn't get modified, making + it smaller than val.prefix +- The code would try constructing an XmlStringRef with negative length, + which would hit an assert in one of QStringView's constructors + +Add an assert to the XmlStringRef constructor. + +Add unittest based on the file from the bug report. + +Later on I will replace FastScanNameResult with std::optional +(std::optional is C++17, which isn't required by Qt 5.15, and we want to +backport this fix). + +Credit to OSS-Fuzz. + +Fixes: QTBUG-109781 +Fixes: QTBUG-114829 +Pick-to: 6.6 6.5 6.2 5.15 +Change-Id: I455a5eeb47870c2ac9ffd0cbcdcd99c1ae2dd374 +Reviewed-by: Allan Sandfeld Jensen +(cherry picked from commit 6326bec46a618c72feba4a2bb994c4d475050aed) +--- + src/corelib/serialization/qxmlstream.cpp | 23 ++++++++--- + src/corelib/serialization/qxmlstream.g | 12 +++++- + src/corelib/serialization/qxmlstream_p.h | 14 ++++++- + .../serialization/qxmlstreamparser_p.h | 12 +++++- + .../qxmlstream/tst_qxmlstream.cpp | 39 +++++++++++++++++++ + 5 files changed, 88 insertions(+), 12 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index f64db47867..34568b7351 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -1243,7 +1243,9 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() + return n; + } + +-inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) ++// Fast scan an XML attribute name (e.g. "xml:lang"). ++inline QXmlStreamReaderPrivate::FastScanNameResult ++QXmlStreamReaderPrivate::fastScanName(Value *val) + { + qsizetype n = 0; + uint c; +@@ -1251,7 +1253,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + if (n >= 4096) { + // This is too long to be a sensible name, and + // can exhaust memory, or the range of decltype(*prefix) +- return 0; ++ raiseNamePrefixTooLongError(); ++ return {}; + } + switch (c) { + case '\n': +@@ -1285,18 +1288,18 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + putChar(':'); + --n; + } +- return n; ++ return FastScanNameResult(n); + case ':': + if (val) { + if (val->prefix == 0) { + val->prefix = qint16(n + 2); + } else { // only one colon allowed according to the namespace spec. + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + } else { + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + Q_FALLTHROUGH(); + default: +@@ -1310,7 +1313,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + qsizetype pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); +- return 0; ++ return FastScanNameResult(0); + } + + enum NameChar { NameBeginning, NameNotBeginning, NotName }; +@@ -1791,6 +1794,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) + raiseError(QXmlStreamReader::NotWellFormedError, message); + } + ++void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError() ++{ ++ // TODO: add a ImplementationLimitsExceededError and use it instead ++ raiseError(QXmlStreamReader::NotWellFormedError, ++ QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB " ++ "characters).")); ++} ++ + void QXmlStreamReaderPrivate::parseError() + { + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g +index f3152bff37..fc122e6681 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.g ++++ y/qtbase/src/corelib/serialization/qxmlstream.g +@@ -1420,7 +1420,11 @@ qname ::= LETTER; + /. + case $rule_number: { + Value &val = sym(1); +- val.len += fastScanName(&val); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +@@ -1431,7 +1435,11 @@ qname ::= LETTER; + name ::= LETTER; + /. + case $rule_number: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 5da1f4aa5a..7925e59014 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -38,7 +38,7 @@ public: + + constexpr XmlStringRef() = default; + constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length) +- : m_string(string), m_pos(pos), m_size(length) ++ : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length)) + { + } + XmlStringRef(const QString *string) +@@ -471,7 +471,16 @@ public: + qsizetype fastScanLiteralContent(); + qsizetype fastScanSpace(); + qsizetype fastScanContentCharList(); +- qsizetype fastScanName(Value *val = nullptr); ++ ++ struct FastScanNameResult { ++ FastScanNameResult() : ok(false) {} ++ explicit FastScanNameResult(qsizetype len) : addToLen(len), ok(true) { } ++ operator bool() { return ok; } ++ qsizetype operator*() { Q_ASSERT(ok); return addToLen; } ++ qsizetype addToLen; ++ bool ok; ++ }; ++ FastScanNameResult fastScanName(Value *val = nullptr); + inline qsizetype fastScanNMTOKEN(); + + +@@ -480,6 +489,7 @@ public: + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +index 59370a9310..afd83381b3 100644 +--- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +@@ -948,7 +948,11 @@ bool QXmlStreamReaderPrivate::parse() + + case 262: { + Value &val = sym(1); +- val.len += fastScanName(&val); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(262); + return false; +@@ -956,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse() + } break; + + case 263: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(263); + return false; +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +index 2799e7a999..7eb0aac5cc 100644 +--- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +@@ -581,6 +581,8 @@ private slots: + void readBack() const; + void roundTrip() const; + void roundTrip_data() const; ++ void test_fastScanName_data() const; ++ void test_fastScanName() const; + + void entityExpansionLimit() const; + +@@ -1753,5 +1755,42 @@ void tst_QXmlStream::roundTrip() const + QCOMPARE(out, in); + } + ++void tst_QXmlStream::test_fastScanName_data() const ++{ ++ QTest::addColumn("data"); ++ QTest::addColumn("errorType"); ++ ++ // 4096 is the limit in QXmlStreamReaderPrivate::fastScanName() ++ ++ QByteArray arr = " +Date: Fri, 2 Sep 2022 16:52:04 +0200 +Subject: QXmlStreamReader: use qOffsetStringArray for storing token types +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Change-Id: I9e58c17d97c44e1b13899d30396f65b452d8600f +Reviewed-by: Mårten Nordheim +(cherry picked from commit d674f3f5454fb39de9405484a8c01fb928523f67) +--- + src/corelib/serialization/qxmlstream.cpp | 67 ++++++------------------ + 1 file changed, 16 insertions(+), 51 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index 34568b7351..535f98a215 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -15,6 +15,8 @@ + #include + #include + ++#include ++ + #include + #include "qxmlstream_p.h" + #include "qxmlstreamparser_p.h" +@@ -640,55 +642,19 @@ void QXmlStreamReader::skipCurrentElement() + } + } + +-/* +- * Use the following Perl script to generate the error string index list: +-===== PERL SCRIPT ==== +-print "static const char QXmlStreamReader_tokenTypeString_string[] =\n"; +-$counter = 0; +-$i = 0; +-while () { +- chomp; +- print " \"$_\\0\"\n"; +- $sizes[$i++] = $counter; +- $counter += length 1 + $_; +-} +-print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n "; +-for ($j = 0; $j < $i; ++$j) { +- printf "$sizes[$j], "; +-} +-print "0\n};\n"; +-===== PERL SCRIPT ==== +- +- * The input data is as follows (copied from qxmlstream.h): +-NoToken +-Invalid +-StartDocument +-EndDocument +-StartElement +-EndElement +-Characters +-Comment +-DTD +-EntityReference +-ProcessingInstruction +-*/ +-static const char QXmlStreamReader_tokenTypeString_string[] = +- "NoToken\0" +- "Invalid\0" +- "StartDocument\0" +- "EndDocument\0" +- "StartElement\0" +- "EndElement\0" +- "Characters\0" +- "Comment\0" +- "DTD\0" +- "EntityReference\0" +- "ProcessingInstruction\0"; +- +-static const short QXmlStreamReader_tokenTypeString_indices[] = { +- 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 +-}; +- ++static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( ++ "NoToken", ++ "Invalid", ++ "StartDocument", ++ "EndDocument", ++ "StartElement", ++ "EndElement", ++ "Characters", ++ "Comment", ++ "DTD", ++ "EntityReference", ++ "ProcessingInstruction" ++); + + /*! + \property QXmlStreamReader::namespaceProcessing +@@ -721,8 +687,7 @@ bool QXmlStreamReader::namespaceProcessing() const + QString QXmlStreamReader::tokenString() const + { + Q_D(const QXmlStreamReader); +- return QLatin1StringView(QXmlStreamReader_tokenTypeString_string + +- QXmlStreamReader_tokenTypeString_indices[d->type]); ++ return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); + } + + #endif // QT_NO_XMLSTREAMREADER diff --git a/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch b/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch new file mode 100644 index 000000000..b9fd729ba --- /dev/null +++ b/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch @@ -0,0 +1,394 @@ +From ce9ffbc726f7a0d90561db7206f3061371126190 Mon Sep 17 00:00:00 2001 +From: Axel Spoerl +Date: Fri, 30 Jun 2023 12:43:59 +0200 +Subject: QXmlStreamReader: Raise error on unexpected tokens + +QXmlStreamReader accepted multiple DOCTYPE elements, containing DTD +fragments in the XML prolog, and in the XML body. +Well-formed but invalid XML files - with multiple DTD fragments in +prolog and body, combined with recursive entity expansions - have +caused infinite loops in QXmlStreamReader. + +This patch implements a token check in QXmlStreamReader. +A stream is allowed to start with an XML prolog. StartDocument +and DOCTYPE elements are only allowed in this prolog, which +may also contain ProcessingInstruction and Comment elements. +As soon as anything else is seen, the prolog ends. +After that, the prolog-specific elements are treated as unexpected. +Furthermore, the prolog can contain at most one DOCTYPE element. + +Update the documentation to reflect the new behavior. +Add an autotest that checks the new error cases are correctly detected, +and no error is raised for legitimate input. + +The original OSS-Fuzz files (see bug reports) are not included in this +patch for file size reasons. They have been tested manually. Each of +them has more than one DOCTYPE element, causing infinite loops in +recursive entity expansions. The newly implemented functionality +detects those invalid DTD fragments. By raising an error, it aborts +stream reading before an infinite loop occurs. + +Thanks to OSS-Fuzz for finding this. + +Fixes: QTBUG-92113 +Fixes: QTBUG-95188 +Change-Id: I0a082b9188b2eee50b396c4d5b1c9e1fd237bbdd +Reviewed-by: Volker Hilsheimer +(cherry picked from commit c4301be7d5f94852e1b17f2c2989d5ca807855d4) +(cherry picked from commit c216c3d9859a20b3aeec985512e89316423fc3a8) +--- + src/corelib/serialization/qxmlstream.cpp | 140 +++++++++++++++++- + src/corelib/serialization/qxmlstream_p.h | 11 ++ + .../qxmlstream/tokenError/dtdInBody.xml | 20 +++ + .../qxmlstream/tokenError/multipleDtd.xml | 20 +++ + .../qxmlstream/tokenError/wellFormed.xml | 15 ++ + .../qxmlstream/tst_qxmlstream.cpp | 39 +++++ + 6 files changed, 237 insertions(+), 8 deletions(-) + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index 535f98a215..050556f463 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -128,7 +128,7 @@ void reversed(const Range &&) = delete; + addData() or by waiting for it to arrive on the device(). + + \value UnexpectedElementError The parser encountered an element +- that was different to those it expected. ++ or token that was different to those it expected. + + */ + +@@ -263,13 +263,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const + + QXmlStreamReader is a well-formed XML 1.0 parser that does \e not + include external parsed entities. As long as no error occurs, the +- application code can thus be assured that the data provided by the +- stream reader satisfies the W3C's criteria for well-formed XML. For +- example, you can be certain that all tags are indeed nested and +- closed properly, that references to internal entities have been +- replaced with the correct replacement text, and that attributes have +- been normalized or added according to the internal subset of the +- DTD. ++ application code can thus be assured, that ++ \list ++ \li the data provided by the stream reader satisfies the W3C's ++ criteria for well-formed XML, ++ \li tokens are provided in a valid order. ++ \endlist ++ ++ Unless QXmlStreamReader raises an error, it guarantees the following: ++ \list ++ \li All tags are nested and closed properly. ++ \li References to internal entities have been replaced with the ++ correct replacement text. ++ \li Attributes have been normalized or added according to the ++ internal subset of the \l DTD. ++ \li Tokens of type \l StartDocument happen before all others, ++ aside from comments and processing instructions. ++ \li At most one DOCTYPE element (a token of type \l DTD) is present. ++ \li If present, the DOCTYPE appears before all other elements, ++ aside from StartDocument, comments and processing instructions. ++ \endlist ++ ++ In particular, once any token of type \l StartElement, \l EndElement, ++ \l Characters, \l EntityReference or \l EndDocument is seen, no ++ tokens of type StartDocument or DTD will be seen. If one is present in ++ the input stream, out of order, an error is raised. ++ ++ \note The token types \l Comment and \l ProcessingInstruction may appear ++ anywhere in the stream. + + If an error occurs while parsing, atEnd() and hasError() return + true, and error() returns the error that occurred. The functions +@@ -572,6 +593,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext() + d->token = -1; + return readNext(); + } ++ d->checkToken(); + return d->type; + } + +@@ -656,6 +678,11 @@ static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( + "ProcessingInstruction" + ); + ++static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray( ++ "Prolog", ++ "Body" ++); ++ + /*! + \property QXmlStreamReader::namespaceProcessing + \brief the namespace-processing flag of the stream reader. +@@ -690,6 +717,15 @@ QString QXmlStreamReader::tokenString() const + return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); + } + ++/*! ++ \internal ++ \return \param loc (Prolog/Body) as a string. ++ */ ++static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt) ++{ ++ return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast(ctxt))); ++} ++ + #endif // QT_NO_XMLSTREAMREADER + + QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack() +@@ -776,6 +812,8 @@ void QXmlStreamReaderPrivate::init() + + type = QXmlStreamReader::NoToken; + error = QXmlStreamReader::NoError; ++ currentContext = XmlContext::Prolog; ++ foundDTD = false; + } + + /* +@@ -3692,6 +3730,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader) + } + } + ++static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type, ++ QXmlStreamReaderPrivate::XmlContext loc) ++{ ++ switch (type) { ++ case QXmlStreamReader::StartDocument: ++ case QXmlStreamReader::DTD: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog; ++ ++ case QXmlStreamReader::StartElement: ++ case QXmlStreamReader::EndElement: ++ case QXmlStreamReader::Characters: ++ case QXmlStreamReader::EntityReference: ++ case QXmlStreamReader::EndDocument: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Body; ++ ++ case QXmlStreamReader::Comment: ++ case QXmlStreamReader::ProcessingInstruction: ++ return true; ++ ++ case QXmlStreamReader::NoToken: ++ case QXmlStreamReader::Invalid: ++ return false; ++ } ++ ++ return false; ++} ++ ++/*! ++ \internal ++ \brief QXmlStreamReader::isValidToken ++ \return \c true if \param type is a valid token type. ++ \return \c false if \param type is an unexpected token, ++ which indicates a non-well-formed or invalid XML stream. ++ */ ++bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type) ++{ ++ // Don't change currentContext, if Invalid or NoToken occur in the prolog ++ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken) ++ return false; ++ ++ // If a token type gets rejected in the body, there is no recovery ++ const bool result = isTokenAllowedInContext(type, currentContext); ++ if (result || currentContext == XmlContext::Body) ++ return result; ++ ++ // First non-Prolog token observed => switch context to body and check again. ++ currentContext = XmlContext::Body; ++ return isTokenAllowedInContext(type, currentContext); ++} ++ ++/*! ++ \internal ++ Checks token type and raises an error, if it is invalid ++ in the current context (prolog/body). ++ */ ++void QXmlStreamReaderPrivate::checkToken() ++{ ++ Q_Q(QXmlStreamReader); ++ ++ // The token type must be consumed, to keep track if the body has been reached. ++ const XmlContext context = currentContext; ++ const bool ok = isValidToken(type); ++ ++ // Do nothing if an error has been raised already (going along with an unexpected token) ++ if (error != QXmlStreamReader::Error::NoError) ++ return; ++ ++ if (!ok) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QObject::tr("Unexpected token type %1 in %2.") ++ .arg(q->tokenString(), contextString(context))); ++ return; ++ } ++ ++ if (type != QXmlStreamReader::DTD) ++ return; ++ ++ // Raise error on multiple DTD tokens ++ if (foundDTD) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QObject::tr("Found second DTD token in %1.").arg(contextString(context))); ++ } else { ++ foundDTD = true; ++ } ++} ++ + /*! + \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const + \since 4.5 +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 7925e59014..c24c74d5c9 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -270,6 +270,17 @@ public: + QStringDecoder decoder; + bool atEnd; + ++ enum class XmlContext ++ { ++ Prolog, ++ Body, ++ }; ++ ++ XmlContext currentContext = XmlContext::Prolog; ++ bool foundDTD = false; ++ bool isValidToken(QXmlStreamReader::TokenType type); ++ void checkToken(); ++ + /*! + \sa setType() + */ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +new file mode 100644 +index 0000000000..1c3ca4e271 +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +@@ -0,0 +1,20 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ ++ ++ ++ ]> ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +new file mode 100644 +index 0000000000..cd398c0f9f +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +@@ -0,0 +1,20 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +new file mode 100644 +index 0000000000..1b61a3f062 +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +@@ -0,0 +1,15 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +index 7eb0aac5cc..ee962d3870 100644 +--- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +@@ -586,6 +586,9 @@ private slots: + + void entityExpansionLimit() const; + ++ void tokenErrorHandling_data() const; ++ void tokenErrorHandling() const; ++ + private: + static QByteArray readFile(const QString &filename); + +@@ -1792,5 +1795,41 @@ void tst_QXmlStream::test_fastScanName() const + QCOMPARE(reader.error(), errorType); + } + ++void tst_QXmlStream::tokenErrorHandling_data() const ++{ ++ QTest::addColumn("fileName"); ++ QTest::addColumn("expectedError"); ++ QTest::addColumn("errorKeyWord"); ++ ++ constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError; ++ constexpr auto valid = QXmlStreamReader::Error::NoError; ++ QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD"; ++ QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD"; ++ QTest::newRow("wellFormed") << "wellFormed.xml" << valid << ""; ++} ++ ++void tst_QXmlStream::tokenErrorHandling() const ++{ ++ QFETCH(const QString, fileName); ++ QFETCH(const QXmlStreamReader::Error, expectedError); ++ QFETCH(const QString, errorKeyWord); ++ ++ const QDir dir(QFINDTESTDATA("tokenError")); ++ QFile file(dir.absoluteFilePath(fileName)); ++ ++ // Cross-compiling: File will be on host only ++ if (!file.exists()) ++ QSKIP("Testfile not found."); ++ ++ file.open(QIODevice::ReadOnly); ++ QXmlStreamReader reader(&file); ++ while (!reader.atEnd()) ++ reader.readNext(); ++ ++ QCOMPARE(reader.error(), expectedError); ++ if (expectedError != QXmlStreamReader::Error::NoError) ++ QVERIFY(reader.errorString().contains(errorKeyWord)); ++} ++ + #include "tst_qxmlstream.moc" + // vim: et:ts=4:sw=4:sts=4 diff --git a/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch b/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch new file mode 100644 index 000000000..9f06617f8 --- /dev/null +++ b/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch @@ -0,0 +1,42 @@ +From e6d25e8d3b67cf7d9601d3fdd07131280f8ff056 Mon Sep 17 00:00:00 2001 +From: Marc Mutz +Date: Sun, 4 Sep 2022 12:31:10 +0200 +Subject: QOffsetStringArray: fix ambiguous qOffsetStringArray overloads + +There are two qOffsetStringArray overloads: one in QT_NAMESPACE, the +other in QT_PREPEND_NAMESPACE(QtPrivate). In TUs which use using +namespace QtPrivate, a call to qOffsetStringArray() may become +ambiguous. + +Fix by renaming the qOffsetStringArray() to makeOffsetStringArray(). + +Pick-to: 6.4 6.3 6.2 +Change-Id: I242a969f363e230d6a8dfb048601a0c024724f6a +Reviewed-by: Thiago Macieira +(cherry picked from commit 21c5eeba673694f865badfd137ee9fc474177ae0) +--- + src/corelib/tools/qoffsetstringarray_p.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +index 3afb5cb731..68afef57d5 100644 +--- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h ++++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +@@ -116,7 +116,7 @@ template struct StaticMapEntry + }; + + template +-constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries) ++constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) + { + constexpr size_t Count = sizeof...(T); + constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); +@@ -140,7 +140,7 @@ template + constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept + { + auto extractString = [](const auto &s) -> decltype(auto) { return s; }; +- return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); ++ return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); + } + + QT_WARNING_POP diff --git a/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch b/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch new file mode 100644 index 000000000..5f23bbb77 --- /dev/null +++ b/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch @@ -0,0 +1,31 @@ +From 72533c561d6952e63f86f11d9e4f0c6ffe8ed5a1 Mon Sep 17 00:00:00 2001 +From: Marc Mutz +Date: Mon, 5 Sep 2022 08:59:23 +0200 +Subject: QOffsetStringArray: fix size_t/qsizetype mismatch + +The sizeof operator returns, and both minifyValue and makeStaticString +accept, size_t. Don't funnel it through a qsizetype variable, then, +but maintain it as a size_t all the way. + +Pick-to: 6.4 6.3 6.2 +Task-number: QTBUG-103533 +Change-Id: I05c6a6c5da3d02daabbf1d25a15531c6f44a80ce +Reviewed-by: Sona Kurazyan +(cherry picked from commit 8932eee9a652d8a325410b147955c9939278f9ed) +--- + src/corelib/tools/qoffsetstringarray_p.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +index 68afef57d5..fbe714aca6 100644 +--- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h ++++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +@@ -119,7 +119,7 @@ template + constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) + { + constexpr size_t Count = sizeof...(T); +- constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); ++ constexpr size_t StringLength = (sizeof(extractString(T{})) + ...); + using MinifiedOffsetType = decltype(QtPrivate::minifyValue()); + + size_t offset = 0; diff --git a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch b/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch similarity index 98% rename from libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch rename to libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch index f7da165bc..c65a9aa3d 100644 --- a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch +++ b/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch @@ -1,4 +1,4 @@ -From 720768b715d432aa084c9c15b994a396a89968a8 Mon Sep 17 00:00:00 2001 +From 37c9240e9d6d295118fcabedbaaf403310af8dba Mon Sep 17 00:00:00 2001 From: Julian Greilich Date: Thu, 26 Jan 2023 19:19:21 +0100 Subject: iOS NFC: Always ensure timeout after session invalidation @@ -135,6 +135,3 @@ index 6aa1574e..b3668ff6 100644 }; --- -2.39.1 - diff --git a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch b/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch similarity index 98% rename from libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch rename to libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch index 7ad14c863..b0a3983d0 100644 --- a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch +++ b/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch @@ -1,4 +1,4 @@ -From f5b5a974f6ad854008c587c9494ae46785e21899 Mon Sep 17 00:00:00 2001 +From 7785342c8d6fe223977958c59cd4102ed417d442 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Wed, 18 Jan 2023 15:36:23 +0100 Subject: qmlformat: fix omitting some comments while reformatting @@ -97,6 +97,3 @@ index 9d7beb23a7..7755095acd 100644 } void TestQmlformat::testFormat() --- -2.39.1 - diff --git a/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch b/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch new file mode 100644 index 000000000..fb4f59031 --- /dev/null +++ b/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch @@ -0,0 +1,119 @@ +From 26cac8dada39c83cfcebd8b0bbcacf92f1ce9e9f Mon Sep 17 00:00:00 2001 +From: Sami Shalayel +Date: Mon, 17 Apr 2023 18:03:09 +0200 +Subject: QQuickItem: item stays pressed after DoubleClicks + +Amends 72651a50f83aa72998822312c7b5c6235d28978f. +This commit decided to ignore double clicks in the virtual +QQuickItem::mouseDoubleClickEvent(). +If a subclass inheriting from QQuickItem wants to not ignore +a double click, it should override mouseDoubleClickEvent() +and handle the double click event accordingly. + +Fix QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) to *not* +call the base implementation in QQuickItem after handling a double +click, because QQuickItem sets that double-click MouseEvent back to +the ignored state. + +This was leading to weird behavior on platforms with touch +screens like Android or IOS where buttons "got stuck" after +a double click. + +Fixes: QTBUG-112434 +Fixes: QTBUG-109393 +Pick-to: 6.5 +Change-Id: I774189fbcb356b07336f35f053e05a12c34ce602 +Reviewed-by: Qt CI Bot +Reviewed-by: Ivan Solovev +(cherry picked from commit d7fac6923a6d4e4ac7dc22458256366968acbdb3) +--- + src/quick/items/qquickmousearea.cpp | 5 ++++ + .../data/doubleClickInMouseArea.qml | 23 +++++++++++++++++++ + .../tst_mousearea_interop.cpp | 21 +++++++++++++++++ + 3 files changed, 49 insertions(+) + create mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml + +diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp +index 75b67d01e3..db338c7ae5 100644 +--- x/qtdeclarative/src/quick/items/qquickmousearea.cpp ++++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp +@@ -795,6 +795,11 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) + d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick); + if (d->pressed) + d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); ++ ++ // do not call the base implementation if the event is accepted ++ // because it will revert the event back to ignored state ++ if (me.isAccepted()) ++ return; + } + QQuickItem::mouseDoubleClickEvent(event); + } +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +new file mode 100644 +index 0000000000..e43a2f3160 +--- /dev/null ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +@@ -0,0 +1,23 @@ ++import QtQuick ++import QtQuick.Controls ++import QtQuick.Window ++ ++Rectangle { ++ width: 200; height: 200 ++ color: mouseArea.pressed ? "red" : "orange" ++ ++ Popup { ++ visible: true ++ closePolicy: Popup.NoAutoClose ++ width: 100 ++ height: 100 ++ contentItem: MouseArea { ++ id: mouseArea ++ ++ anchors.fill: parent ++ } ++ background: Rectangle { ++ color: "green" ++ } ++ } ++} +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +index c4059a1fbd..bc0dfbc736 100644 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +@@ -31,6 +31,7 @@ private slots: + void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); + void hoverHandlerDoesntHoverOnPress(); + void doubleClickInMouseAreaWithDragHandlerInGrandparent(); ++ void doubleClickInMouseArea(); + + private: + void createView(QScopedPointer &window, const char *fileName); +@@ -203,6 +204,26 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() + QCOMPARE(dragActiveSpy.count(), 0); + } + ++void tst_MouseAreaInterop::doubleClickInMouseArea() ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); ++ ++ auto *ma = window.rootObject()->findChild(); ++ QVERIFY(ma); ++ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); ++ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); ++ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); ++ ++ // check with normal double click ++ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); ++ QCOMPARE(doubleClickSpy.count(), 1); ++ ++ // wait enough time for a wrong long press to happen ++ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); ++ QCOMPARE(longPressSpy.count(), 0); ++} ++ + QTEST_MAIN(tst_MouseAreaInterop) + + #include "tst_mousearea_interop.moc" diff --git a/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch b/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch new file mode 100644 index 000000000..c35b19150 --- /dev/null +++ b/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch @@ -0,0 +1,283 @@ +From 65fd0af4aece6028e82e018c50583aed706dd525 Mon Sep 17 00:00:00 2001 +From: Shawn Rutledge +Date: Mon, 12 Jun 2023 22:53:23 +0200 +Subject: MouseArea: don't ignore double-click events + +In 72651a50f83aa72998822312c7b5c6235d28978f +QQuickItem::mouseDoubleClickEvent() started to ignore double-clicks by +default, which is consistent with the fact that it ignores the other +pointer event types. But now we have to worry about subclasses that +override mouseDoubleClickEvent() and call the base class implementation. + +d7fac6923a6d4e4ac7dc22458256366968acbdb3 tried to fix it but neglected +the case when the MouseArea does not have an onDoubleClicked signal +handling script. Since the QQuickMouseEvent object that we emit to QML +won't be accepted if isDoubleClickConnected() is false, and since the +code before 72651a50f83aa72998822312c7b5c6235d28978f was leaving the +event accepted regardless of whether QQuickMouseEvent was accepted, we +should not need to check it now either. Perhaps we should care about the +case when onDoubleClicked sets accepted to false, but so far that +doesn't seem very useful either: if you accept the press, a parent +MouseArea will not see either the press or the double-click; if you +ignore the press, you won't see the double-click, and a parent MouseArea +will see both by default. tst_QQuickMouseArea::clickThrough() tests +accepted = false in onDoubleClicked but not onPressed, and only with +mouse, not touch. + +Added tst_QQuickMouseArea::doubleTap(); also moved the autotest from +d7fac6923a6d4e4ac7dc22458256366968acbdb3 which has nothing to do with +pointer handlers. + +Fixes: QTBUG-112434 +Fixes: QTBUG-109393 +Pick-to: 6.6 6.5 6.5.2 +Change-Id: I426827c20cdb2373e77744987dffba59cd941edc +Reviewed-by: Fabian Kosmale +Reviewed-by: Doris Verria +(cherry picked from commit 35b5511189f0f9dbb8cfd8b3ec97cca2c65b3e2e) +--- + src/quick/items/qquickmousearea.cpp | 6 +- + .../data/doubleClickInMouseArea.qml | 23 -------- + .../tst_mousearea_interop.cpp | 21 ------- + .../qquickmousearea/tst_qquickmousearea.cpp | 56 +++++++++++++++++++ + .../data/doubleClickInMouseArea.qml | 23 ++++++++ + .../qquickpopup/tst_qquickpopup.cpp | 22 ++++++++ + 6 files changed, 103 insertions(+), 48 deletions(-) + delete mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml + create mode 100644 tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml + +diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp +index db338c7ae5..de283672cc 100644 +--- x/qtdeclarative/src/quick/items/qquickmousearea.cpp ++++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp +@@ -796,10 +796,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) + if (d->pressed) + d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); + +- // do not call the base implementation if the event is accepted +- // because it will revert the event back to ignored state +- if (me.isAccepted()) +- return; ++ // Do not call the base implementation: we don't want to call event->ignore(). ++ return; + } + QQuickItem::mouseDoubleClickEvent(event); + } +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +deleted file mode 100644 +index e43a2f3160..0000000000 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml ++++ /dev/null +@@ -1,23 +0,0 @@ +-import QtQuick +-import QtQuick.Controls +-import QtQuick.Window +- +-Rectangle { +- width: 200; height: 200 +- color: mouseArea.pressed ? "red" : "orange" +- +- Popup { +- visible: true +- closePolicy: Popup.NoAutoClose +- width: 100 +- height: 100 +- contentItem: MouseArea { +- id: mouseArea +- +- anchors.fill: parent +- } +- background: Rectangle { +- color: "green" +- } +- } +-} +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +index bc0dfbc736..c4059a1fbd 100644 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +@@ -31,7 +31,6 @@ private slots: + void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); + void hoverHandlerDoesntHoverOnPress(); + void doubleClickInMouseAreaWithDragHandlerInGrandparent(); +- void doubleClickInMouseArea(); + + private: + void createView(QScopedPointer &window, const char *fileName); +@@ -204,26 +203,6 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() + QCOMPARE(dragActiveSpy.count(), 0); + } + +-void tst_MouseAreaInterop::doubleClickInMouseArea() +-{ +- QQuickView window; +- QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); +- +- auto *ma = window.rootObject()->findChild(); +- QVERIFY(ma); +- QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); +- QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); +- QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); +- +- // check with normal double click +- QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); +- QCOMPARE(doubleClickSpy.count(), 1); +- +- // wait enough time for a wrong long press to happen +- QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); +- QCOMPARE(longPressSpy.count(), 0); +-} +- + QTEST_MAIN(tst_MouseAreaInterop) + + #include "tst_mousearea_interop.moc" +diff --git x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +index 7da0913e0c..0c7528320e 100644 +--- x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp ++++ y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +@@ -95,6 +95,7 @@ private slots: + void pressedCanceledOnWindowDeactivate(); + void doubleClick_data() { acceptedButton_data(); } + void doubleClick(); ++ void doubleTap(); + void clickTwice_data() { acceptedButton_data(); } + void clickTwice(); + void invalidClick_data() { rejectedButton_data(); } +@@ -929,6 +930,61 @@ void tst_QQuickMouseArea::doubleClick() + QCOMPARE(window.rootObject()->property("released").toInt(), 2); + } + ++void tst_QQuickMouseArea::doubleTap() // QTBUG-112434 ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleclick.qml"))); ++ ++ QQuickMouseArea *mouseArea = window.rootObject()->findChild("mousearea"); ++ QVERIFY(mouseArea); ++ QPoint p1 = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint(); ++ ++ QTest::touchEvent(&window, device).press(0, p1); ++ QQuickTouchUtils::flush(&window); ++ QTest::touchEvent(&window, device).release(0, p1); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 1); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); ++ ++ p1 += QPoint(1, -1); // movement less than QPlatformTheme::TouchDoubleTapDistance ++ QTest::touchEvent(&window, device).press(1, p1); // touchpoint ID is different the second time ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ // at this time QQuickDeliveryAgentPrivate::deliverTouchAsMouse() synthesizes the double-click event ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); ++ ++ QTest::touchEvent(&window, device).release(1, p1); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 2); ++ QCOMPARE(mouseArea->isPressed(), false); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); ++ ++ // now tap with two fingers simultaneously: only one of them generates synth-mouse ++ QPoint p2 = p1 + QPoint(50, 5); ++ QTest::touchEvent(&window, device).press(2, p1).press(3, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ QTest::touchEvent(&window, device).release(2, p1).release(3, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 3); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); ++ QCOMPARE(mouseArea->isPressed(), false); ++ ++ // tap with two fingers simultaneously again: get another double-click from one point ++ p1 -= QPoint(1, -1); ++ p2 += QPoint(1, -1); ++ QTest::touchEvent(&window, device).press(4, p1).press(5, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ QTest::touchEvent(&window, device).release(4, p1).release(5, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 4); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2); ++ QCOMPARE(mouseArea->isPressed(), false); // make sure it doesn't get stuck ++} ++ + // QTBUG-14832 + void tst_QQuickMouseArea::clickTwice() + { +diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml +new file mode 100644 +index 0000000000..e43a2f3160 +--- /dev/null ++++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml +@@ -0,0 +1,23 @@ ++import QtQuick ++import QtQuick.Controls ++import QtQuick.Window ++ ++Rectangle { ++ width: 200; height: 200 ++ color: mouseArea.pressed ? "red" : "orange" ++ ++ Popup { ++ visible: true ++ closePolicy: Popup.NoAutoClose ++ width: 100 ++ height: 100 ++ contentItem: MouseArea { ++ id: mouseArea ++ ++ anchors.fill: parent ++ } ++ background: Rectangle { ++ color: "green" ++ } ++ } ++} +diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp +index ab20bd71b4..0e8ee05725 100644 +--- x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp ++++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,6 +90,7 @@ private slots: + void dimmerContainmentMask(); + void shrinkPopupThatWasLargerThanWindow_data(); + void shrinkPopupThatWasLargerThanWindow(); ++ void doubleClickInMouseArea(); + + private: + static bool hasWindowActivation(); +@@ -1928,6 +1930,26 @@ void tst_QQuickPopup::shrinkPopupThatWasLargerThanWindow() + .arg(popup->height()).arg(window->height()))); + } + ++void tst_QQuickPopup::doubleClickInMouseArea() ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); ++ ++ auto *ma = window.rootObject()->findChild(); ++ QVERIFY(ma); ++ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); ++ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); ++ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); ++ ++ // check with normal double click ++ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); ++ QCOMPARE(doubleClickSpy.count(), 1); ++ ++ // wait enough time for a wrong long press to happen ++ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); ++ QCOMPARE(longPressSpy.count(), 0); ++} ++ + QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) + + #include "tst_qquickpopup.moc" diff --git a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch b/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch similarity index 84% rename from libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch rename to libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch index d345633b1..362eba137 100644 --- a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch +++ b/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch @@ -1,4 +1,4 @@ -From 5a844a0c1b5e9c1b9fb94831afc0724f5deaa7dd Mon Sep 17 00:00:00 2001 +From abe6296550b5531a129b7d4a21466cdc50dbb2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Tue, 12 Apr 2022 10:21:19 +0200 Subject: Make qtdeclarative optional for CONTAINER_SDK @@ -9,7 +9,7 @@ Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d 1 file changed, 1 insertion(+), 1 deletion(-) diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml -index ee6f92e..7375551 100644 +index ee6f92e0..73755512 100644 --- x/qtscxml/dependencies.yaml +++ y/qtscxml/dependencies.yaml @@ -4,4 +4,4 @@ dependencies: @@ -18,6 +18,3 @@ index ee6f92e..7375551 100644 ref: a514640b2a38391fceaaac3ca01b390ad3d62f31 - required: true + required: false --- -2.38.1 - diff --git a/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch b/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch similarity index 87% rename from libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch rename to libs/patches/qtscxml-0002-Disable-qtscxml-library.patch index c311a71a1..864deee26 100644 --- a/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch +++ b/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch @@ -1,4 +1,4 @@ -From ee68d7d67358f92c87720c2f740322fb03ad8299 Mon Sep 17 00:00:00 2001 +From 2fa2cbc5c55e862cee7fc495edc444c46d4193ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Tue, 12 Apr 2022 11:39:12 +0200 Subject: Disable qtscxml library @@ -9,7 +9,7 @@ Subject: Disable qtscxml library 2 files changed, 3 insertions(+), 3 deletions(-) diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt -index f1b7c2b..7e28acc 100644 +index f1b7c2b9..7e28acc2 100644 --- x/qtscxml/src/CMakeLists.txt +++ y/qtscxml/src/CMakeLists.txt @@ -1,8 +1,8 @@ @@ -24,7 +24,7 @@ index f1b7c2b..7e28acc 100644 endif() add_subdirectory(plugins) diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt -index 9726a78..956f904 100644 +index 9726a783..956f9048 100644 --- x/qtscxml/tools/CMakeLists.txt +++ y/qtscxml/tools/CMakeLists.txt @@ -1,4 +1,4 @@ @@ -33,6 +33,3 @@ index 9726a78..956f904 100644 - add_subdirectory(qscxmlc) + #add_subdirectory(qscxmlc) endif() --- -2.38.1 - diff --git a/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch b/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch new file mode 100644 index 000000000..e8f0d75e6 --- /dev/null +++ b/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch @@ -0,0 +1,56 @@ +From c3b8e687ca723262f15f31b181a3e5db847afb68 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Robert=20L=C3=B6hning?= +Date: Mon, 24 Apr 2023 15:27:17 +0200 +Subject: QSvgFont: Initialize used member, remove unused + +Credit to OSS-Fuzz + +[ChangeLog][QtSvg] Fixed undefined behavior from using uninitialized +variable. + +Pick-to: 6.5 6.2 5.15 +Coverity-Id: 22618 +Change-Id: Id52277bb0e2845f4d342e187dbb8093e9276b70c +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit ff22c3ccf8ccf813fdcfda23f7740ba73ba5ce0a) +--- + src/svg/qsvgfont_p.h | 5 ++--- + src/svg/qsvghandler.cpp | 2 +- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git x/qtsvg/src/svg/qsvgfont_p.h y/qtsvg/src/svg/qsvgfont_p.h +index a7cc98b..9cf3dfe 100644 +--- x/qtsvg/src/svg/qsvgfont_p.h ++++ y/qtsvg/src/svg/qsvgfont_p.h +@@ -38,6 +38,7 @@ public: + class Q_SVG_PRIVATE_EXPORT QSvgFont : public QSvgRefCounted + { + public: ++ static constexpr qreal DEFAULT_UNITS_PER_EM = 1000; + QSvgFont(qreal horizAdvX); + + void setFamilyName(const QString &name); +@@ -50,9 +51,7 @@ public: + void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const; + public: + QString m_familyName; +- qreal m_unitsPerEm; +- qreal m_ascent; +- qreal m_descent; ++ qreal m_unitsPerEm = DEFAULT_UNITS_PER_EM; + qreal m_horizAdvX; + QHash m_glyphs; + }; +diff --git x/qtsvg/src/svg/qsvghandler.cpp y/qtsvg/src/svg/qsvghandler.cpp +index e88e83b..1e2b2fc 100644 +--- x/qtsvg/src/svg/qsvghandler.cpp ++++ y/qtsvg/src/svg/qsvghandler.cpp +@@ -2622,7 +2622,7 @@ static bool parseFontFaceNode(QSvgStyleProperty *parent, + + qreal unitsPerEm = toDouble(unitsPerEmStr); + if (!unitsPerEm) +- unitsPerEm = 1000; ++ unitsPerEm = QSvgFont::DEFAULT_UNITS_PER_EM; + + if (!name.isEmpty()) + font->setFamilyName(name); diff --git a/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch similarity index 92% rename from libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch rename to libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch index 54eda298c..0f8e56d70 100644 --- a/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch +++ b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch @@ -1,4 +1,4 @@ -From 125584904a64497ae50b227ef326e0fc12683a4b Mon Sep 17 00:00:00 2001 +From d52894c2b13954d13ff940ba6b36e5cab7fbf3ac Mon Sep 17 00:00:00 2001 From: Jan Moeller Date: Mon, 14 Feb 2022 13:46:46 +0100 Subject: Disable linguist but keep translation tools @@ -22,6 +22,3 @@ index 16ff9f559..fde23b0c4 100644 # special case begin # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package --- -2.38.1 - diff --git a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch b/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch similarity index 99% rename from libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch rename to libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch index ef7852d63..618650497 100644 --- a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch +++ b/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch @@ -1,4 +1,4 @@ -From d6c550d3ef01a50e100acd4fa44a2d6fbd376cbb Mon Sep 17 00:00:00 2001 +From 2cbc188e4facb12153f37a501f14384ec733c944 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Wed, 9 Nov 2022 09:49:38 +0100 Subject: Revert "Move UiTools and UiPlugin modules to a upper level @@ -15,8 +15,8 @@ Change-Id: I247e2189577b74d813a210ace0b49d672a90975e src/designer/src/uiplugin/customwidget.h | 62 ++ src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++ .../src/uiplugin/qdesignerexportwidget.h | 24 + - src/designer/src/uitools/CMakeLists.txt | 47 + - src/designer/src/uitools/qtuitoolsglobal.h | 24 + + src/designer/src/uitools/CMakeLists.txt | 46 + + src/designer/src/uitools/qtuitoolsglobal.h | 23 + src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++ src/designer/src/uitools/quiloader.h | 61 ++ src/designer/src/uitools/quiloader_p.h | 77 ++ @@ -30,7 +30,7 @@ Change-Id: I247e2189577b74d813a210ace0b49d672a90975e src/uitools/quiloader.h | 61 -- src/uitools/quiloader_p.h | 77 -- sync.profile | 4 +- - 22 files changed, 1511 insertions(+), 1514 deletions(-) + 22 files changed, 1509 insertions(+), 1514 deletions(-) create mode 100644 src/designer/src/uiplugin/CMakeLists.txt create mode 100644 src/designer/src/uiplugin/customwidget.h create mode 100644 src/designer/src/uiplugin/customwidget.qdoc @@ -505,10 +505,10 @@ index 000000000..d90e9b217 +#endif //QDESIGNEREXPORTWIDGET_H diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt new file mode 100644 -index 000000000..5306fcbd5 +index 000000000..6040ac71d --- /dev/null +++ y/qttools/src/designer/src/uitools/CMakeLists.txt -@@ -0,0 +1,47 @@ +@@ -0,0 +1,46 @@ +# Generated from uitools.pro. + +##################################################################### @@ -555,13 +555,12 @@ index 000000000..5306fcbd5 +qt_internal_add_docs(UiTools + doc/qtuitools.qdocconf +) -+ diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h new file mode 100644 -index 000000000..a2f967dee +index 000000000..6874fb15b --- /dev/null +++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -@@ -0,0 +1,24 @@ +@@ -0,0 +1,23 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + @@ -585,7 +584,6 @@ index 000000000..a2f967dee +QT_END_NAMESPACE + +#endif // QTUITOOLSGLOBAL_H -+ diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp new file mode 100644 index 000000000..a06d4717b @@ -3230,6 +3228,3 @@ index caa7ed5ad..de4261afc 100644 "QtDesigner" => "$basedir/src/designer/src/lib", "QtDesignerComponents" => "$basedir/src/designer/src/components/lib", ); --- -2.38.1 - diff --git a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch b/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch similarity index 94% rename from libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch rename to libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch index 0ded83d28..2aa80208d 100644 --- a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch +++ b/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch @@ -1,4 +1,4 @@ -From dfc2918f8d635edf9300512fc5c1a067a89707d1 Mon Sep 17 00:00:00 2001 +From a120b53dcef4aebd5e7bea35bc6fc6c462e748f1 Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Wed, 23 Nov 2022 12:40:45 +0100 Subject: Fix Linux build with CMake versions >= 3.25 @@ -34,6 +34,3 @@ index f485c1b4b..fff76d54a 100644 else() find_package(Ninja 1.7.2) find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT) --- -2.38.1 - diff --git a/resources/ausweisapp_android.qrc b/resources/ausweisapp_android.qrc index e8a5f7821..47d5d95b7 100644 --- a/resources/ausweisapp_android.qrc +++ b/resources/ausweisapp_android.qrc @@ -1,6 +1,5 @@ - images/android/material_phone_android.svg images/android/material_share.svg diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index 02422ee37..90d7d0e66 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -1,6 +1,7 @@ images/macos/appIcon.svg + images/desktop/info_white.svg images/desktop/titlebar_arrow.svg images/desktop/material_assistant.svg images/desktop/material_bug_report.svg @@ -13,6 +14,8 @@ images/desktop/material_question_answer.svg images/desktop/material_highlight.svg images/desktop/material_menu_book.svg + images/desktop/material_menu_book_white.svg + images/desktop/material_settings_white.svg images/desktop/material_open_in_browser.svg images/desktop/material_a11y.svg images/desktop/material_privacy.svg diff --git a/resources/ausweisapp_ios.qrc b/resources/ausweisapp_ios.qrc index 182741824..401170d57 100644 --- a/resources/ausweisapp_ios.qrc +++ b/resources/ausweisapp_ios.qrc @@ -1,6 +1,5 @@ - images/ios/material_phone_iphone.svg images/ios/share.svg diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index a6ba90344..f861f5da0 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -1,224 +1,220 @@ - qtquickcontrols2.conf + images/android/stay_primary_landscape-24px.svg + images/android/stay_primary_portrait-24px.svg + images/ios/material_arrow_left.svg + images/ios/material_cancel.svg + images/ios/material_more_horiz.svg + images/material_add.svg images/mobile/device.svg + images/mobile/generic_id_card.svg images/mobile/icon_nfc.svg - images/mobile/icon_smart.svg images/mobile/icon_remote.svg images/mobile/icon_simulator.svg - images/mobile/material_arrow_right.svg + images/mobile/icon_smart.svg images/mobile/material_arrow_back.svg + images/mobile/material_arrow_right.svg images/mobile/material_backspace.svg - images/mobile/material_view_headline.svg images/mobile/material_home.svg - images/mobile/phone_smart.svg + images/mobile/material_view_headline.svg + images/mobile/phone_card_reader.svg images/mobile/phone_nfc.svg images/mobile/phone_nfc_with_card.svg images/mobile/phone_remote.svg images/mobile/phone_simulator.svg - images/mobile/generic_id_card.svg - images/android/stay_primary_landscape-24px.svg - images/android/stay_primary_portrait-24px.svg - images/ios/material_arrow_left.svg - images/ios/material_cancel.svg - images/ios/material_more_horiz.svg - images/provider/ios/general.svg + images/mobile/phone_smart.svg images/provider/ios/citizen.svg - images/provider/ios/finance.svg - images/provider/ios/insurance.svg - images/provider/ios/other.svg - images/provider/default_bg.svg - images/provider/citizen_button.svg - images/provider/finance_button.svg - images/provider/general_button.svg - images/provider/insurance_button.svg - images/provider/other_button.svg images/provider/citizen_bg.svg + images/provider/citizen_button.svg + images/provider/default_bg.svg + images/provider/ios/finance.svg images/provider/finance_bg.svg + images/provider/finance_button.svg + images/provider/ios/general.svg images/provider/general_bg.svg + images/provider/general_button.svg + images/provider/ios/insurance.svg images/provider/insurance_bg.svg + images/provider/insurance_button.svg + images/provider/ios/other.svg images/provider/other_bg.svg - images/tutorial/main_menu_what_caret.svg - images/tutorial/main_menu_where_caret.svg - images/tutorial/main_menu_how_caret.svg - images/tutorial/main_menu_important_caret.svg - images/tutorial/background_icon_how.svg - images/tutorial/background_icon_where.svg - images/tutorial/background_icon_important.svg - images/tutorial/icon_box.svg - images/tutorial/icon_circle.svg - images/tutorial/icon_diamond.svg - images/tutorial/icon_star.svg + images/provider/other_button.svg images/tutorial/arrow_blue.svg images/tutorial/arrows.svg + images/tutorial/background_icon_how.svg + images/tutorial/background_icon_important.svg + images/tutorial/background_icon_where.svg images/tutorial/button_de.png images/tutorial/button_en.png - images/tutorial/identify.svg - images/tutorial/questionmark.svg - images/tutorial/hint.svg - images/tutorial/thumb_up.svg - images/tutorial/hand.svg - images/tutorial/check.svg - images/tutorial/cross.svg - images/tutorial/click.svg - images/tutorial/save.svg + images/tutorial/button_en.png + images/tutorial/button_en.png images/tutorial/bva.svg - images/tutorial/provider_home.svg - images/tutorial/rectangles.svg - images/tutorial/laptop.svg - images/tutorial/tablet.svg - images/tutorial/tablet-nfc.svg - images/tutorial/tablet-no-nfc.svg - images/tutorial/reader.svg - images/tutorial/desktop.svg - images/tutorial/phone.svg - images/tutorial/phone_border.svg - images/tutorial/phone_list.svg - images/tutorial/phone_screen.svg - images/tutorial/nfc.svg - images/tutorial/no-nfc.svg - images/tutorial/wifi.svg - images/tutorial/letters.svg - images/tutorial/usb.svg + images/tutorial/check.svg images/tutorial/circle-1.svg images/tutorial/circle-2.svg images/tutorial/circle-3.svg images/tutorial/circle-4.svg - images/tutorial/circle-lock.svg images/tutorial/circle-lock-2.svg - images/tutorial/up_icon.svg - images/tutorial/phone_screen_de.png - images/tutorial/phone_screen_en.png - images/tutorial/pin-5@2x.png - images/tutorial/pin-6@2x.png - images/tutorial/user-tine@3x.png - images/tutorial/providericons.png - images/tutorial/play_movie.png - images/tutorial/screenshot_check_id_card_android_de.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_de.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_cert_android_de.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_de.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_providerlist_android_de.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_de.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_de.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_remoteservice_ios_de.png - images/tutorial/screenshot_pairing_de.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_choose_reader_android_de.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_de.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_android_de.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_pin_management_menu_ios_de.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_android_de.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/screenshot_start_ios_de.png - images/tutorial/screenshot_selfauthentication_android_de.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_de.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/section_seperator_what.svg - images/tutorial/section_seperator_where.svg - images/tutorial/section_seperator_how.svg - images/tutorial/section_seperator_important.svg - images/tutorial/where_overview_question.svg - images/tutorial/where_identify_now_de.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_de.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/where_lay_down_id.svg - images/tutorial/where_pin6.svg - images/tutorial/how_questions_everywhere.svg + images/tutorial/circle-lock.svg + images/tutorial/click.svg + images/tutorial/cross.svg + images/tutorial/desktop.svg + images/tutorial/hand.svg + images/tutorial/hint.svg + images/tutorial/how_desktop.svg images/tutorial/how_device_lineup.svg + images/tutorial/how_form_no_fun.svg images/tutorial/how_method_nfc.svg images/tutorial/how_method_sac_desktop.svg images/tutorial/how_method_sac_mobile.svg - images/tutorial/how_form_no_fun.svg - images/tutorial/how_desktop.svg + images/tutorial/how_questions_everywhere.svg + images/tutorial/icon_box.svg + images/tutorial/icon_circle.svg + images/tutorial/icon_diamond.svg + images/tutorial/icon_star.svg + images/tutorial/identify.svg + images/tutorial/important_lets_go.svg images/tutorial/important_pin5.svg images/tutorial/important_pin6.svg - images/tutorial/important_lets_go.svg images/tutorial/important_space_questionmark.svg - images/tutorial/reader_nfc_provider_on_smartphone.svg - images/tutorial/reader_nfc_npa_on_smartphone.svg - images/tutorial/reader_nfc_smartphone_nfc_position.svg + images/tutorial/laptop.svg + images/tutorial/letters.svg + images/tutorial/main_menu_how_caret.svg + images/tutorial/main_menu_important_caret.svg + images/tutorial/main_menu_what_caret.svg + images/tutorial/main_menu_where_caret.svg + images/tutorial/nfc.svg + images/tutorial/no-nfc.svg + images/tutorial/phone.svg + images/tutorial/phone_border.svg + images/tutorial/phone_list.svg + images/tutorial/phone_screen.svg + images/tutorial/phone_screen_de.png + images/tutorial/phone_screen_en.png + images/tutorial/phone_screen_en.png + images/tutorial/phone_screen_en.png + images/tutorial/pin-5@2x.png + images/tutorial/pin-6@2x.png + images/tutorial/play_movie.png + images/tutorial/provider_home.svg + images/tutorial/providericons.png + images/tutorial/questionmark.svg + images/tutorial/reader.svg images/tutorial/reader_nfc_finished.svg + images/tutorial/reader_nfc_npa_on_smartphone.svg images/tutorial/reader_nfc_pin6.svg + images/tutorial/reader_nfc_provider_on_smartphone.svg + images/tutorial/reader_nfc_smartphone_nfc_position.svg images/tutorial/reader_nfc_userdata_example_de.svg images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_provider_on_laptop.svg - images/tutorial/reader_sac_npa_on_laptop.svg + images/tutorial/reader_nfc_userdata_example_en.svg + images/tutorial/reader_nfc_userdata_example_en.svg images/tutorial/reader_sac_aa2_ok.svg images/tutorial/reader_sac_menu_android_de.svg images/tutorial/reader_sac_menu_android_en.svg + images/tutorial/reader_sac_menu_android_en.svg + images/tutorial/reader_sac_menu_android_en.svg images/tutorial/reader_sac_menu_ios_de.svg images/tutorial/reader_sac_menu_ios_en.svg + images/tutorial/reader_sac_menu_ios_en.svg + images/tutorial/reader_sac_menu_ios_en.svg images/tutorial/reader_sac_no_nfc_devices.svg images/tutorial/reader_sac_no_nfc_provider.svg - - - images/tutorial/button_en.png - images/tutorial/phone_screen_en.png + images/tutorial/reader_sac_npa_on_laptop.svg + images/tutorial/reader_sac_provider_on_laptop.svg + images/tutorial/rectangles.svg + images/tutorial/save.svg + images/tutorial/screenshot_cert_android_de.png + images/tutorial/screenshot_cert_android_en.png images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_en.svg - - - images/tutorial/button_en.png - images/tutorial/phone_screen_en.png images/tutorial/screenshot_cert_android_en.png + images/tutorial/screenshot_cert_ios_de.png + images/tutorial/screenshot_cert_ios_en.png + images/tutorial/screenshot_cert_ios_en.png images/tutorial/screenshot_cert_ios_en.png + images/tutorial/screenshot_check_id_card_android_de.png + images/tutorial/screenshot_check_id_card_android_en.png images/tutorial/screenshot_check_id_card_android_en.png + images/tutorial/screenshot_check_id_card_android_en.png + images/tutorial/screenshot_check_id_card_ios_de.png + images/tutorial/screenshot_check_id_card_ios_en.png images/tutorial/screenshot_check_id_card_ios_en.png + images/tutorial/screenshot_check_id_card_ios_en.png + images/tutorial/screenshot_choose_reader_android_de.png + images/tutorial/screenshot_choose_reader_android_en.png + images/tutorial/screenshot_choose_reader_android_en.png images/tutorial/screenshot_choose_reader_android_en.png + images/tutorial/screenshot_choose_reader_ios_de.png + images/tutorial/screenshot_choose_reader_ios_en.png + images/tutorial/screenshot_choose_reader_ios_en.png images/tutorial/screenshot_choose_reader_ios_en.png + images/tutorial/screenshot_pairing_de.png + images/tutorial/screenshot_pairing_en.png + images/tutorial/screenshot_pairing_en.png images/tutorial/screenshot_pairing_en.png + images/tutorial/screenshot_pin_management_menu_android_de.png + images/tutorial/screenshot_pin_management_menu_android_en.png images/tutorial/screenshot_pin_management_menu_android_en.png + images/tutorial/screenshot_pin_management_menu_android_en.png + images/tutorial/screenshot_pin_management_menu_ios_de.png + images/tutorial/screenshot_pin_management_menu_ios_en.png + images/tutorial/screenshot_pin_management_menu_ios_en.png images/tutorial/screenshot_pin_management_menu_ios_en.png + images/tutorial/screenshot_providerlist_android_de.png + images/tutorial/screenshot_providerlist_android_en.png images/tutorial/screenshot_providerlist_android_en.png + images/tutorial/screenshot_providerlist_android_en.png + images/tutorial/screenshot_providerlist_ios_de.png + images/tutorial/screenshot_providerlist_ios_en.png images/tutorial/screenshot_providerlist_ios_en.png + images/tutorial/screenshot_providerlist_ios_en.png + images/tutorial/screenshot_remoteservice_android_de.png + images/tutorial/screenshot_remoteservice_android_en.png + images/tutorial/screenshot_remoteservice_android_en.png images/tutorial/screenshot_remoteservice_android_en.png + images/tutorial/screenshot_remoteservice_ios_de.png + images/tutorial/screenshot_remoteservice_ios_en.png + images/tutorial/screenshot_remoteservice_ios_en.png images/tutorial/screenshot_remoteservice_ios_en.png + images/tutorial/screenshot_selfauthentication_android_de.png + images/tutorial/screenshot_selfauthentication_android_en.png images/tutorial/screenshot_selfauthentication_android_en.png + images/tutorial/screenshot_selfauthentication_android_en.png + images/tutorial/screenshot_selfauthentication_ios_de.png + images/tutorial/screenshot_selfauthentication_ios_en.png images/tutorial/screenshot_selfauthentication_ios_en.png + images/tutorial/screenshot_selfauthentication_ios_en.png + images/tutorial/screenshot_start_android_de.png + images/tutorial/screenshot_start_android_en.png + images/tutorial/screenshot_start_android_en.png images/tutorial/screenshot_start_android_en.png + images/tutorial/screenshot_start_ios_de.png + images/tutorial/screenshot_start_ios_en.png + images/tutorial/screenshot_start_ios_en.png images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg + images/tutorial/section_seperator_how.svg + images/tutorial/section_seperator_important.svg + images/tutorial/section_seperator_what.svg + images/tutorial/section_seperator_where.svg + images/tutorial/tablet-nfc.svg + images/tutorial/tablet-no-nfc.svg + images/tutorial/tablet.svg + images/tutorial/thumb_up.svg + images/tutorial/up_icon.svg + images/tutorial/usb.svg + images/tutorial/user-tine@3x.png + images/tutorial/where_identify_now_de.svg + images/tutorial/where_identify_now_en.svg + images/tutorial/where_identify_now_en.svg images/tutorial/where_identify_now_en.svg + images/tutorial/where_lay_down_id.svg + images/tutorial/where_overview_question.svg + images/tutorial/where_pin6.svg + images/tutorial/where_userdata_example_de.svg + images/tutorial/where_userdata_example_en.svg + images/tutorial/where_userdata_example_en.svg images/tutorial/where_userdata_example_en.svg + images/tutorial/wifi.svg + qtquickcontrols2.conf diff --git a/resources/images/android/adaptive_monochrome_beta.svg b/resources/images/android/adaptive_monochrome_beta.svg new file mode 100644 index 000000000..148445eef --- /dev/null +++ b/resources/images/android/adaptive_monochrome_beta.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_preview.svg b/resources/images/android/adaptive_monochrome_preview.svg new file mode 100644 index 000000000..de08bb3cd --- /dev/null +++ b/resources/images/android/adaptive_monochrome_preview.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_release.svg b/resources/images/android/adaptive_monochrome_release.svg new file mode 100644 index 000000000..6e8057b1f --- /dev/null +++ b/resources/images/android/adaptive_monochrome_release.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/resources/images/android/hdpi/monochrome_npa.png b/resources/images/android/hdpi/monochrome_npa.png new file mode 100644 index 000000000..a1f62c6f5 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_beta.png b/resources/images/android/hdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..0b02ef3eb Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_preview.png b/resources/images/android/hdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..26762f855 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/ldpi/monochrome_npa.png b/resources/images/android/ldpi/monochrome_npa.png new file mode 100644 index 000000000..21d31857a Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_beta.png b/resources/images/android/ldpi/monochrome_npa_beta.png new file mode 100644 index 000000000..cfe226711 Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_preview.png b/resources/images/android/ldpi/monochrome_npa_preview.png new file mode 100644 index 000000000..6f7b4c17d Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/material_phone_android.svg b/resources/images/android/material_phone_android.svg deleted file mode 100644 index b7a256bcb..000000000 --- a/resources/images/android/material_phone_android.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/android/mdpi/monochrome_npa.png b/resources/images/android/mdpi/monochrome_npa.png new file mode 100644 index 000000000..1e08f0def Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_beta.png b/resources/images/android/mdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..cf03b597e Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_preview.png b/resources/images/android/mdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..38a2f986e Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa.png b/resources/images/android/xhdpi/monochrome_npa.png new file mode 100644 index 000000000..e8acb1170 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_beta.png b/resources/images/android/xhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..5cb637325 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_preview.png b/resources/images/android/xhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..ac7309a88 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa.png b/resources/images/android/xxhdpi/monochrome_npa.png new file mode 100644 index 000000000..fd700d694 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_beta.png b/resources/images/android/xxhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..c7647f0ce Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_preview.png b/resources/images/android/xxhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..6866745a8 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa.png b/resources/images/android/xxxhdpi/monochrome_npa.png new file mode 100644 index 000000000..812653d7e Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_beta.png b/resources/images/android/xxxhdpi/monochrome_npa_beta.png new file mode 100644 index 000000000..76abeeb9d Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_preview.png b/resources/images/android/xxxhdpi/monochrome_npa_preview.png new file mode 100644 index 000000000..fc43da6c3 Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/desktop/info_white.svg b/resources/images/desktop/info_white.svg new file mode 100644 index 000000000..6725deeef --- /dev/null +++ b/resources/images/desktop/info_white.svg @@ -0,0 +1,21 @@ + + + + diff --git a/resources/images/desktop/material_a11y.svg b/resources/images/desktop/material_a11y.svg index a87416f2f..3b02dc969 100644 --- a/resources/images/desktop/material_a11y.svg +++ b/resources/images/desktop/material_a11y.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_assistant.svg b/resources/images/desktop/material_assistant.svg index a70334532..fbfd819c1 100644 --- a/resources/images/desktop/material_assistant.svg +++ b/resources/images/desktop/material_assistant.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_bug_report.svg b/resources/images/desktop/material_bug_report.svg index 718f6b36b..fb22e9dfe 100644 --- a/resources/images/desktop/material_bug_report.svg +++ b/resources/images/desktop/material_bug_report.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_highlight.svg b/resources/images/desktop/material_highlight.svg index ae7443060..a9a7692dc 100644 --- a/resources/images/desktop/material_highlight.svg +++ b/resources/images/desktop/material_highlight.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_menu_book.svg b/resources/images/desktop/material_menu_book.svg index 0a9ef46da..e2e3e95b2 100644 --- a/resources/images/desktop/material_menu_book.svg +++ b/resources/images/desktop/material_menu_book.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_menu_book_white.svg b/resources/images/desktop/material_menu_book_white.svg new file mode 100644 index 000000000..0a9ef46da --- /dev/null +++ b/resources/images/desktop/material_menu_book_white.svg @@ -0,0 +1 @@ + diff --git a/resources/images/desktop/material_privacy.svg b/resources/images/desktop/material_privacy.svg index 209018412..75866ac43 100644 --- a/resources/images/desktop/material_privacy.svg +++ b/resources/images/desktop/material_privacy.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_settings_white.svg b/resources/images/desktop/material_settings_white.svg new file mode 100644 index 000000000..f7ca45ae7 --- /dev/null +++ b/resources/images/desktop/material_settings_white.svg @@ -0,0 +1 @@ + diff --git a/resources/images/desktop/material_video.svg b/resources/images/desktop/material_video.svg index 1d5a32eca..a7530621f 100644 --- a/resources/images/desktop/material_video.svg +++ b/resources/images/desktop/material_video.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_view_list.svg b/resources/images/desktop/material_view_list.svg index 550b676c0..d7af03ef2 100644 --- a/resources/images/desktop/material_view_list.svg +++ b/resources/images/desktop/material_view_list.svg @@ -1 +1 @@ - + diff --git a/resources/images/info.svg b/resources/images/info.svg index 6725deeef..81059acf2 100644 --- a/resources/images/info.svg +++ b/resources/images/info.svg @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/resources/images/material_add.svg b/resources/images/material_add.svg new file mode 100644 index 000000000..70898c171 --- /dev/null +++ b/resources/images/material_add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/material_help.svg b/resources/images/material_help.svg index 7677f0ed9..85fb2092a 100644 --- a/resources/images/material_help.svg +++ b/resources/images/material_help.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_history.svg b/resources/images/material_history.svg index 6975ecef2..357da249c 100644 --- a/resources/images/material_history.svg +++ b/resources/images/material_history.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_live_help.svg b/resources/images/material_live_help.svg index 06255c48d..8f975fdda 100644 --- a/resources/images/material_live_help.svg +++ b/resources/images/material_live_help.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_lock.svg b/resources/images/material_lock.svg index cfc8a0c3f..57dd76bc6 100644 --- a/resources/images/material_lock.svg +++ b/resources/images/material_lock.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_settings.svg b/resources/images/material_settings.svg index f7ca45ae7..819864198 100644 --- a/resources/images/material_settings.svg +++ b/resources/images/material_settings.svg @@ -1 +1 @@ - + diff --git a/resources/images/mobile/phone_card_reader.svg b/resources/images/mobile/phone_card_reader.svg new file mode 100644 index 000000000..81d3e8232 --- /dev/null +++ b/resources/images/mobile/phone_card_reader.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/resources/images/mydata.svg b/resources/images/mydata.svg index 4988d8537..8d1a386d1 100644 --- a/resources/images/mydata.svg +++ b/resources/images/mydata.svg @@ -7,5 +7,5 @@ m 0 3 a 1 1 0 0 1 0 -2 h 9 a 1 1 0 0 1 0 2 z M 31.64 35.75 l -3 -6 a 6 6 0 1 1 2 -1 l 3 6 a 1.118 1.118 0 0 1 -2 1 z m -9.64 -11.8 a 5 5 0 0 0 10 0 a 5 5 0 0 0 -10 0 z - m 1.536 2 a 4 4 0 0 1 0 -4 h 6.928 a 4 4 0 0 1 0 4 z" fill="#ffffff"/> + m 1.536 2 a 4 4 0 0 1 0 -4 h 6.928 a 4 4 0 0 1 0 4 z" fill="#164a8c" /> diff --git a/resources/images/provider.svg b/resources/images/provider.svg index e7d8a8f8d..cc58a7752 100644 --- a/resources/images/provider.svg +++ b/resources/images/provider.svg @@ -1,6 +1,6 @@ - + + + + + + + + + + + + + + + + + diff --git a/resources/packaging/android/full_backup_content.xml b/resources/packaging/android/full_backup_content.xml new file mode 100644 index 000000000..a06f20d18 --- /dev/null +++ b/resources/packaging/android/full_backup_content.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/packaging/android/lint.aar.xml b/resources/packaging/android/lint.aar.xml index db3ee1060..3ce203f94 100644 --- a/resources/packaging/android/lint.aar.xml +++ b/resources/packaging/android/lint.aar.xml @@ -1,21 +1,5 @@ - - - - - - - - - - - diff --git a/resources/packaging/android/lint.apk.xml b/resources/packaging/android/lint.apk.xml index 599146f0b..a0b50d4d9 100644 --- a/resources/packaging/android/lint.apk.xml +++ b/resources/packaging/android/lint.apk.xml @@ -1,21 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml b/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml index 4c7b81f35..065d6d9e0 100644 --- a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml +++ b/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml @@ -2,4 +2,5 @@ + diff --git a/resources/qml/+desktop/main.qml b/resources/qml/+desktop/main.qml index 0fa56a380..c5980ac5e 100644 --- a/resources/qml/+desktop/main.qml +++ b/resources/qml/+desktop/main.qml @@ -114,6 +114,11 @@ ApplicationWindow { let initialSize = plugin.initialWindowSize; ApplicationModel.scaleFactor = Math.min(width / initialSize.width, height / initialSize.height); } + function showDetachedLogViewIfPresent() { + if (d.detachedLogView !== null) { + d.detachedLogView.show(); + } + } function showMainWindow() { d.suppressAbortWarning = false; if (active) { @@ -187,6 +192,7 @@ ApplicationWindow { function onFireShowRequest(pModule) { d.showMainWindow(); d.closeOpenDialogs(); + d.showDetachedLogViewIfPresent(); switch (pModule) { case UiModule.CURRENT: break; @@ -236,6 +242,12 @@ ApplicationWindow { onActivated: ApplicationModel.openOnlineHelp(menuBar.rightMostAction.helpTopic) } + Shortcut { + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" + + onActivated: close() + } Image { anchors.centerIn: parent fillMode: Image.PreserveAspectFit @@ -414,6 +426,12 @@ ApplicationWindow { d.detachedLogView = null; } + Shortcut { + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" + + onActivated: close() + } DetachedLogView { anchors.fill: parent focus: true diff --git a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml index 1c077c1c0..390ef5722 100644 --- a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml @@ -31,6 +31,7 @@ SectionPage { Progress, AccessRights, Workflow, + WorkflowError, Password, PasswordInfo, CardPosition, @@ -159,8 +160,24 @@ SectionPage { return Workflow.WaitingFor.None; } + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(AuthView.SubViews.WorkflowError); + } onSettingsRequested: authView.showSettings() } + ResultView { + id: deviceUnpairedView + + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + visible: d.activeView === AuthView.SubViews.WorkflowError + + onNextView: d.view = AuthView.SubViews.Workflow + } EnterPasswordView { id: enterPasswordView //: LABEL DESKTOP A11y button to confirm the PIN and start the provider authentication @@ -286,11 +303,11 @@ SectionPage { header: AuthModel.errorHeader hintButtonText: AuthModel.statusHintActionText hintText: AuthModel.statusHintText + mailButtonVisible: AuthModel.errorIsMasked popupText: AuthModel.errorText //: INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. popupTitle: qsTr("Error code: %1").arg(AuthModel.statusCodeString) resultType: AuthModel.resultString ? ResultView.Type.IsError : ResultView.Type.IsSuccess - supportButtonsVisible: AuthModel.errorIsMasked text: AuthModel.resultString visible: d.activeView === AuthView.SubViews.Result diff --git a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml index d2906ef40..65d8fc50e 100644 --- a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml @@ -105,7 +105,7 @@ SectionPage { id: detailsButton Accessible.description: qsTr("Show more information about the service provider") activeFocusOnTab: true - icon.source: "qrc:///images/info.svg" + icon.source: "qrc:///images/desktop/info_white.svg" //: LABEL DESKTOP text: qsTr("Details about the provider") diff --git a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml index 5129a8f6c..40cbf7922 100644 --- a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml @@ -19,6 +19,8 @@ SectionPage { property alias dataText: dataPasswordText.text property var workflowModel: AuthModel + signal rightsAccepted + //: LABEL IOS_PHONE ANDROID_PHONE title: qsTr("Identify") @@ -119,10 +121,7 @@ SectionPage { qsTr("PIN")) tintIcon: true - onClicked: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } + onClicked: rightsAccepted() } GText { id: dataPasswordText @@ -138,7 +137,7 @@ SectionPage { //: LABEL IOS_PHONE ANDROID_PHONE title: qsTr("Transactional information") - visible: !!AuthModel.transactionInfo || (!writeData.visible && !readData.visible) + visible: !!workflowModel.transactionInfo || (!writeData.visible && !readData.visible) anchors { left: parent.left diff --git a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml index bc13e4615..bbffaadbb 100644 --- a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml @@ -19,6 +19,8 @@ SectionPage { property alias dataText: dataPasswordText.text property var workflowModel: AuthModel + signal rightsAccepted + //: LABEL ANDROID_TABLET IOS_TABLET title: qsTr("Identify") @@ -80,10 +82,7 @@ SectionPage { qsTr("PIN")) tintIcon: true - onClicked: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } + onClicked: rightsAccepted() anchors { right: parent.right diff --git a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml index 941450cc7..89346e3d6 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml @@ -14,6 +14,7 @@ import Governikus.View 1.0 import Governikus.Workflow 1.0 import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.AuthModel 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.LogModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 @@ -81,6 +82,10 @@ ProgressView { Component { id: editRights EditRights { + onRightsAccepted: { + ChatModel.transferAccessRights(); + AuthModel.continueWorkflow(); + } } } Component { diff --git a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml index 3c2391203..82e33d540 100644 --- a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml +++ b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml @@ -22,6 +22,7 @@ SectionPage { enum SubViews { Start, Workflow, + WorkflowError, Password, NoPassword, PasswordInfo, @@ -144,8 +145,24 @@ SectionPage { return Workflow.WaitingFor.None; } + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(ChangePinView.SubViews.WorkflowError); + } onSettingsRequested: baseItem.showSettings() } + ResultView { + id: deviceUnpairedView + + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + visible: d.activeView === ChangePinView.SubViews.WorkflowError + + onNextView: d.view = ChangePinView.SubViews.Workflow + } EnterPasswordView { id: enterPasswordView moreInformationText: infoData.linkText @@ -238,8 +255,8 @@ SectionPage { id: pinResult hintButtonText: ChangePinModel.statusHintActionText hintText: ChangePinModel.statusHintText + mailButtonVisible: ChangePinModel.errorIsMasked resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess - supportButtonsVisible: ChangePinModel.errorIsMasked text: ChangePinModel.resultString visible: d.activeView === ChangePinView.SubViews.Result diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml index 22e9f8e5e..076fd4631 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml @@ -200,7 +200,7 @@ SectionPage { } if (passwordType === PasswordType.REMOTE_PIN) { //: INFO DESKTOP The pairing code needs to be supplied. - return qsTr("Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC)."); + return qsTr("Enter the pairing code shown on your smartphone."); } //: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml index f96c4dd49..6f804921f 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml @@ -63,6 +63,7 @@ Item { enabled: baseItem.deleteEnabled fontScale: 0.75 text: "C" + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } @@ -80,6 +81,7 @@ Item { enabled: baseItem.submitEnabled fontScale: 0.75 text: "OK" + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml index e8a6dab38..4ec9fcbd1 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml @@ -56,6 +56,7 @@ GridLayout { enabled: baseItem.deleteEnabled icon.source: "qrc:///images/mobile/material_backspace.svg" text: qsTr("Delete last digit") + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } @@ -74,6 +75,7 @@ GridLayout { enabled: baseItem.submitEnabled icon.source: "qrc:///images/material_check.svg" text: qsTr("Submit") + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml index 4081d8dcb..69aa028bb 100644 --- a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml +++ b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml @@ -18,7 +18,7 @@ MouseArea { enabled: visible preventStealing: enabled - onPositionChanged: { + onPositionChanged: mouse => { let currentVelocity = mouse.x - previousPosX; velocity = (velocity + currentVelocity) / 2.0; previousPosX = mouse.x; @@ -33,7 +33,7 @@ MouseArea { mouse.accepted = false; } } - onReleased: { + onReleased: mouse => { let swipeDistance = mouse.x - startPosX; if (swipeDistance > minSwipeDistance && velocity > minVelocity) { backGestureTriggered(); diff --git a/resources/qml/Governikus/Global/StatusIcon.qml b/resources/qml/Governikus/Global/StatusIcon.qml index 8fd841f51..14b27c5b3 100644 --- a/resources/qml/Governikus/Global/StatusIcon.qml +++ b/resources/qml/Governikus/Global/StatusIcon.qml @@ -11,8 +11,8 @@ Rectangle { property alias busy: busyIndicator.visible property alias contentBackgroundColor: content.color property alias source: image.source - property alias text: text.text - property alias textStyle: text.textStyle + property alias text: iconText.text + property alias textStyle: iconText.textStyle border.color: borderEnabled ? Style.color.accent : Style.color.transparent border.width: height / 40 @@ -48,7 +48,7 @@ Rectangle { visible: source.toString().length > 0 } GText { - id: text + id: iconText Accessible.ignored: true anchors.centerIn: parent textStyle: Style.text.title_accent diff --git a/resources/qml/Governikus/Global/Utils.qml b/resources/qml/Governikus/Global/Utils.qml index 8a91062d2..916ee9149 100644 --- a/resources/qml/Governikus/Global/Utils.qml +++ b/resources/qml/Governikus/Global/Utils.qml @@ -4,10 +4,11 @@ pragma Singleton import QtQuick 2.15 import Governikus.Type.ApplicationModel 1.0 +import Governikus.Type.SettingsModel 1.0 QtObject { - function escapeHtml(str) { - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + function escapeHtml(pStr) { + return String(pStr).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function helpTopicOf(pComponent, pDefaultHelpTopic) { if (pComponent && typeof (pComponent.helpTopic) !== "undefined") { @@ -16,23 +17,33 @@ QtObject { return pDefaultHelpTopic; } } - function isSameDate(one, another) { - return one.getFullYear() === another.getFullYear() && one.getMonth() === another.getMonth() && one.getDate() === another.getDate(); + function historyDateString(pDate) { + //: LABEL ALL_PLATFORMS + return (isToday(pDate) ? qsTr("today") : + //: LABEL ALL_PLATFORMS + isYesterday(pDate) ? qsTr("yesterday") : + // dddd is without translation because we want the long day name with every language + isThisWeek(pDate) ? pDate.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + pDate.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))); } - function isThisWeek(date) { + function isSameDate(pOne, pAnother) { + return pOne.getFullYear() === pAnother.getFullYear() && pOne.getMonth() === pAnother.getMonth() && pOne.getDate() === pAnother.getDate(); + } + function isThisWeek(pDate) { var monday = new Date; monday.setDate(monday.getDate() - monday.getDay()); - date.setDate(date.getDate() - date.getDay()); - return isSameDate(monday, date); + pDate.setDate(pDate.getDate() - pDate.getDay()); + return isSameDate(monday, pDate); } - function isToday(date) { + function isToday(pDate) { var today = new Date; - return isSameDate(today, date); + return isSameDate(today, pDate); } - function isYesterday(date) { + function isYesterday(pDate) { var yesterday = new Date; yesterday.setDate(yesterday.getDate() - 1); - return isSameDate(yesterday, date); + return isSameDate(yesterday, pDate); } function scrollPageDown(pFlickable) { if (pFlickable.height >= pFlickable.contentHeight) { diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml index 1ea38ea42..1af1d0382 100644 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml +++ b/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml @@ -117,7 +117,7 @@ SectionPage { } sectionDelegate: TabbedPaneDelegateIconAndThreeLineText { footerText: model ? model.purpose : "" - headerText: (model ? (Utils.isToday(model.dateTime) ? qsTr("today") : Utils.isYesterday(model.dateTime) ? qsTr("yesterday") : Utils.isThisWeek(model.dateTime) ? model.dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : model.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) : "") + headerText: model ? Utils.historyDateString(model.dateTime) : "" iconPath: model ? model.providerIcon : "" sectionName: model ? model.subject : "" } diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml index fdc0ea04c..aaa85d4cf 100644 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml +++ b/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml @@ -55,6 +55,7 @@ Item { if (!historyModelItem) { return ""; } + //: LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); } textUppercase: Font.AllUppercase diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml index f44c84cb9..f34fe535e 100644 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml +++ b/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml @@ -10,11 +10,11 @@ import Governikus.Type.SettingsModel 1.0 ListItem { property var historyModelItem + //: LABEL ANDROID IOS Accessible.description: qsTr("Click to view details of history entry.") //: LABEL ANDROID IOS footerText: historyModelItem.purpose !== "" ? historyModelItem.purpose : qsTr("Tap for more details") - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + headerText: Utils.historyDateString(dateTime) height: 72 icon: providerIcon !== "" ? providerIcon : (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown")) text: subject diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml index 99a1b0fa1..e684ef1fa 100644 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml +++ b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml @@ -62,6 +62,7 @@ SectionPage { if (!historyModelItem) { return ""; } + //: LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); } width: parent.width diff --git a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml index 144dfbbbe..64bbeaed9 100644 --- a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml +++ b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml @@ -31,8 +31,8 @@ Item { module: UiModule.PROVIDER } ListElement { - desc: QT_TR_NOOP("Remote") - image: "qrc:///images/mobile/platform_specific_phone.svg" + desc: QT_TR_NOOP("Card reader") + image: "qrc:///images/mobile/phone_card_reader.svg" module: UiModule.REMOTE_SERVICE } ListElement { diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml index 66ec310be..85f434e9b 100644 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml +++ b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml @@ -28,7 +28,7 @@ Item { GText { id: date font.capitalization: Font.AllUppercase - text: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + text: Utils.historyDateString(dateTime) textStyle: Style.text.normal } GridLayout { diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml index 418c62d5f..3a973ca49 100644 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml +++ b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml @@ -23,9 +23,7 @@ ListItem { contentMarginRight: 0 //: LABEL ANDROID IOS footerText: purposeText !== "" ? purposeText : qsTr("Touch for more details") - - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + headerText: Utils.historyDateString(dateTime) height: 72 //: LABEL ANDROID IOS text: (!!providerName ? providerName : qsTr("Touch for more details")) diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml index 1693ad2db..9030c3fb1 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml @@ -8,15 +8,19 @@ import Governikus.Global 1.0 import Governikus.Style 1.0 MouseArea { + id: root + property alias description: descriptionText.text + property bool highlightTitle: false property alias linkInactive: linkQualityItem.inactive property alias linkQuality: linkQualityItem.percent + property alias linkQualityVisible: linkQualityItem.visible property alias title: titleText.text Accessible.name: qsTr("Device %1. %2.").arg(title).arg(description) Accessible.role: Accessible.ListItem - height: content.implicitHeight - width: content.implicitWidth + implicitHeight: content.implicitHeight + implicitWidth: content.implicitWidth Accessible.onPressAction: clicked(null) @@ -35,7 +39,7 @@ MouseArea { Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 - textStyle: Style.text.normal_accent + textStyle: root.highlightTitle ? Style.text.normal_accent_highlight : Style.text.normal_accent } GText { id: descriptionText @@ -44,6 +48,7 @@ MouseArea { elide: Text.ElideRight maximumLineCount: 1 textStyle: Style.text.hint_secondary + visible: text !== "" } } LinkQuality { diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml index 9b4363820..a8de0a7de 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml @@ -13,7 +13,7 @@ Column { GText { horizontalAlignment: Text.AlignHCenter //: INFO IOS Let user know to check the application settings for local network permission - text: qsTr("To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.") + text: qsTr("Ensure that access to the local network is allowed in your settings.") textStyle: Style.text.normal_secondary width: parent.width } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml new file mode 100644 index 000000000..a04e8b112 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Style 1.0 +import Governikus.View 1.0 +import Governikus.Type.ApplicationModel 1.0 + +SectionPage { + property alias text: description.text + + signal navActionClicked + + hiddenNavbarPadding: true + + //: LABEL ANDROID IOS + title: qsTr("Pairing Information") + + content: ColumnLayout { + anchors.left: parent.left + anchors.margins: Constants.pane_padding + anchors.right: parent.right + spacing: Constants.component_spacing + + Image { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Style.dimens.medium_icon_size + Layout.topMargin: Constants.pane_padding + fillMode: Image.PreserveAspectFit + source: "qrc:///images/phone_to_pc.svg" + sourceSize.height: Style.dimens.medium_icon_size + } + GText { + id: description + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + //: LABEL ANDROID IOS + textStyle: Style.text.header_accent + } + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + qsTr("Open %1 on your %2other device%3.").arg(Qt.application.name).arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + qsTr("On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + qsTr("Choose this smartphone in the list to pair it.")] + + RowLayout { + Layout.topMargin: Constants.component_spacing + spacing: Constants.text_spacing + width: parent.width + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: Style.dimens.small_icon_size + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + text: modelData + } + } + } + RemoteServiceWifiInfo { + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + } + } + navigationAction: NavigationAction { + id: navAction + action: NavigationAction.Action.Back + + onClicked: navActionClicked() + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml new file mode 100644 index 000000000..ed089d9e0 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.Style 1.0 +import Governikus.Type.ApplicationModel 1.0 + +ColumnLayout { + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + qsTr("Open %1 on your smartphone as card reader.").arg(Qt.application.name), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + qsTr("On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + qsTr("Choose the smartphone in the list shown here to pair it.")] + + RowLayout { + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + spacing: Constants.text_spacing + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: Style.dimens.small_icon_size + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + text: modelData + } + } + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml index 9c011a0a3..019c2077f 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml @@ -17,7 +17,7 @@ SectionPage { sectionPageFlickable: contentItem //: LABEL ANDROID IOS - title: qsTr("Remote service") + title: qsTr("Card reader") navigationAction: NavigationAction { action: RemoteServiceModel.running ? NavigationAction.Action.Cancel : NavigationAction.Action.None @@ -28,13 +28,9 @@ SectionPage { Connections { function onFireIsRunningChanged() { setLockedAndHidden(RemoteServiceModel.running); - pairingButton.didPairInSaKSession = false; } - function onFirePairingCompleted() { - pairingButton.didPairInSaKSession = true; - } - //: ERROR ANDROID IOS An error occurred while pairing the device. function onFirePairingFailed() { + //: ERROR ANDROID IOS An error occurred while pairing the device. ApplicationModel.showFeedback(qsTr("Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.")); } @@ -55,43 +51,22 @@ SectionPage { when: RemoteServiceModel.running && RemoteServiceModel.isPairing PropertyChanges { - target: pairingCode - visible: true - } - PropertyChanges { - target: wifiInfo - visible: true - } - PropertyChanges { - target: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission - } - }, - State { - name: "UNCONNECTED" - when: RemoteServiceModel.running && !RemoteServiceModel.connectedToPairedDevice - - PropertyChanges { - target: pairingCode + target: knownDevices visible: false } PropertyChanges { - target: wifiInfo + target: pairingCode visible: true } PropertyChanges { - target: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission + target: paringCodeLink + visible: true } }, State { name: "CONNECTED_OR_STOPPED" when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice) - PropertyChanges { - target: pairingCode - visible: false - } PropertyChanges { target: wifiInfo visible: false @@ -125,26 +100,119 @@ SectionPage { //: LABEL ANDROID IOS RemoteServiceModel.connectedToPairedDevice ? qsTr("Card access in progress") : //: LABEL ANDROID IOS - RemoteServiceModel.isPairing || RemoteServiceModel.running ? qsTr("Waiting for connection") : + RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") : //: LABEL ANDROID IOS - qsTr("Remote service ready") + RemoteServiceModel.running ? qsTr("Waiting for connection") : "" textStyle: Style.text.header_accent } GText { + id: infoText + readonly property string currentPin: RemoteServiceModel.psk //: INFO ANDROID IOS - readonly property string enterCodeString: qsTr("Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).") + readonly property string enterCodeString: qsTr("Enter the pairing code %1 in the %2 on your other device.") - Accessible.name: RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) : text + Accessible.name: text Layout.fillWidth: true Layout.topMargin: Constants.text_spacing horizontalAlignment: Text.AlignHCenter - text: !RemoteServiceModel.runnable ? RemoteServiceModel.errorMessage : RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice ? RemoteServiceModel.connectionInfo : RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin).arg(Qt.application.name) : - //: INFO ANDROID IOS - RemoteServiceModel.running ? qsTr("Waiting for connection from a paired device...") : //: INFO ANDROID IOS - qsTr("Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).\n\nIf you have not already paired a device, start the pairing now to set up this smartphone as a card reader.") + text: qsTr("You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.\n\nTo do this you first have to pair that device with this smartphone.").arg(Qt.application.name) textStyle: RemoteServiceModel.runnable ? Style.text.normal_secondary : Style.text.normal_warning + + states: [ + State { + when: !RemoteServiceModel.runnable + + PropertyChanges { + target: infoText + text: RemoteServiceModel.errorMessage + } + }, + State { + when: RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice + + PropertyChanges { + target: infoText + text: RemoteServiceModel.connectionInfo + } + }, + State { + when: RemoteServiceModel.isPairing + + PropertyChanges { + Accessible.name: enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) + target: infoText + text: enterCodeString.arg(currentPin).arg(Qt.application.name) + } + }, + State { + when: !RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.") + } + }, + State { + when: RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Paired devices may use this Smartphone as a card reader now.") + } + }, + State { + when: RemoteServiceModel.running + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Waiting for connection from a paired device...") + } + } + ] + } + ColumnLayout { + id: knownDevices + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.topMargin: Constants.pane_padding + spacing: Constants.text_spacing + visible: RemoteServiceModel.runnable && knownDeviceList.count > 0 + + GText { + //: INFO ANDROID IOS + text: qsTr("Paired Devices") + textStyle: Style.text.header + } + Repeater { + id: knownDeviceList + model: RemoteServiceModel.allDevices + + delegate: DevicesListDelegate { + highlightTitle: isLastAddedDevice + linkQualityVisible: false + title: remoteDeviceName + } + } + GButton { + //: LABEL ANDROID IOS + Accessible.name: qsTr("Start pairing of a new device") + Layout.alignment: Qt.AlignLeft + Layout.topMargin: knownDevices.spacing + buttonColor: Style.color.transparent + icon.source: "qrc:///images/material_add.svg" + padding: 0 + //: LABEL ANDROID IOS + text: qsTr("Pair new device") + textStyle: Style.text.normal_accent_highlight + visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running + + onClicked: RemoteServiceModel.setRunning(!RemoteServiceModel.running, !RemoteServiceModel.isPairing) + } } GText { id: pairingCode @@ -161,82 +229,121 @@ SectionPage { textStyle: Style.text.title_accent visible: false } + MoreInformationLink { + id: paringCodeLink + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + //: LABEL ANDROID IOS + text: qsTr("Where do I enter the pairing code?") + visible: false + + onClicked: push(pairingCodeInfoView) + + Component { + id: pairingCodeInfoView + PairingCodeInfoView { + text: paringCodeLink.text + + onNavActionClicked: pop() + } + } + } GSpacer { Layout.fillHeight: true } - RowLayout { + RemoteServiceWifiInfo { id: wifiInfo Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - spacing: Constants.text_spacing - - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.width: Style.dimens.small_icon_size - tintColor: Style.text.normal_secondary.textColor - } - GText { - Layout.fillWidth: true - - //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - text: qsTr("Both of your devices have to be connected to the same WiFi.") - textStyle: Style.text.normal_secondary - } } LocalNetworkInfo { id: networkPermissionText Layout.bottomMargin: Constants.text_spacing Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - visible: false + visible: RemoteServiceModel.requiresLocalNetworkPermission } - GButton { - id: startButton - - readonly property int minButtonWidth: Math.max(Math.max(pairingButton.implicitWidth, startButton.implicitWidth), parent.width / 2) - - Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth + GProgressBar { + id: progressBar + Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - buttonColor: (!ApplicationModel.wifiEnabled || RemoteServiceModel.canEnableNfc) ? Style.color.button : (RemoteServiceModel.running ? Constants.red : Constants.green) - enabled: (RemoteServiceModel.canEnableNfc || RemoteServiceModel.runnable || RemoteServiceModel.running || !ApplicationModel.wifiEnabled) && !RemoteServiceModel.isStarting - //: LABEL ANDROID IOS - text: !ApplicationModel.wifiEnabled ? qsTr("Enable WiFi") : - //: LABEL ANDROID IOS - RemoteServiceModel.canEnableNfc ? qsTr("Enable NFC") : - //: LABEL ANDROID IOS - RemoteServiceModel.running ? qsTr("Stop remote service") : - //: LABEL ANDROID IOS - qsTr("Start remote service") - - onClicked: { - if (!ApplicationModel.wifiEnabled) { - ApplicationModel.enableWifi(); - } else if (RemoteServiceModel.canEnableNfc) { - ApplicationModel.showSettings(ApplicationModel.SETTING_NFC); - } else { - RemoteServiceModel.setRunning(!RemoteServiceModel.running); - } - } + value: RemoteServiceModel.percentage + visible: progressText.visible + } + GText { + id: progressText + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + text: RemoteServiceModel.displayText + textStyle: Style.text.normal_secondary + visible: text !== "" } GButton { - id: pairingButton - - property bool didPairInSaKSession: false - + id: pairConnectButton Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth Layout.topMargin: Constants.component_spacing - enabled: RemoteServiceModel.runnable && !RemoteServiceModel.connectedToPairedDevice && !RemoteServiceModel.isStarting && !didPairInSaKSession + enabled: !RemoteServiceModel.isStarting + visible: text !== "" - // Set opacity instead of visibility to hide button so it keeps its size - opacity: RemoteServiceModel.connectedToPairedDevice || didPairInSaKSession ? 0 : 1 - text: RemoteServiceModel.isPairing ? - //: LABEL ANDROID IOS - qsTr("Stop pairing") : - //: LABEL ANDROID IOS - qsTr("Start pairing") - visible: RemoteServiceModel.runnable + states: [ + State { + when: !ApplicationModel.wifiEnabled + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable WiFi") + + onClicked: ApplicationModel.enableWifi() + } + }, + State { + when: RemoteServiceModel.canEnableNfc + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable NFC") + + onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running + + PropertyChanges { + buttonColor: Constants.green + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Allow connection") + + onClicked: RemoteServiceModel.setRunning(true) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Pair device") + + onClicked: RemoteServiceModel.setRunning(true, true) + } + }, + State { + when: RemoteServiceModel.isPairing + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Cancel pairing") + visible: true + + onClicked: RemoteServiceModel.setRunning(false, false) + } + } + ] onClicked: RemoteServiceModel.setRunning(true, !RemoteServiceModel.isPairing) } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml index a26871a0c..022420db0 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml @@ -33,6 +33,7 @@ Item { Column { spacing: Constants.component_spacing + visible: availablePairedDeviceList.count > 0 width: parent.usableWidth TitledSeparator { @@ -43,23 +44,49 @@ Item { title: qsTr("Paired devices") width: parent.width } - GText { - Accessible.name: text - Accessible.role: Accessible.StaticText + ListView { + id: availablePairedDeviceList + height: childrenRect.height + interactive: false + model: RemoteServiceModel.availablePairedDevices + spacing: Constants.component_spacing + width: parent.width + + delegate: DevicesListDelegate { + //: LABEL ANDROID IOS + description: qsTr("Available") + linkInactive: !isNetworkVisible + linkQuality: linkQualityInPercent + title: remoteDeviceName + width: availablePairedDeviceList.width + + onClicked: { + deleteDevicePopup.deviceId = deviceId; + deleteDevicePopup.deviceName = remoteDeviceName; + deleteDevicePopup.open(); + } + } + } + } + Column { + spacing: Constants.component_spacing + visible: unavailablePairedDeviceList.count > 0 + width: parent.usableWidth + TitledSeparator { + contentMarginBottom: 0 + contentMarginLeft: 0 + contentMarginRight: 0 //: LABEL ANDROID IOS - text: qsTr("No device is paired.") - textStyle: Style.text.normal_secondary - visible: !knownDeviceList.visible + title: qsTr("Last connected") width: parent.width } ListView { - id: knownDeviceList + id: unavailablePairedDeviceList height: childrenRect.height interactive: false - model: RemoteServiceModel.knownDevices + model: RemoteServiceModel.unavailablePairedDevices spacing: Constants.component_spacing - visible: count > 0 width: parent.width delegate: DevicesListDelegate { @@ -68,7 +95,7 @@ Item { linkInactive: !isNetworkVisible linkQuality: linkQualityInPercent title: remoteDeviceName - width: knownDeviceList.width + width: unavailablePairedDeviceList.width onClicked: { deleteDevicePopup.deviceId = deviceId; @@ -102,19 +129,39 @@ Item { contentMarginBottom: 0 contentMarginLeft: 0 contentMarginRight: 0 - //: LABEL ANDROID IOS - title: qsTr("Available devices") + title: qsTr("Add pairing") width: parent.width } + GListView { + id: searchDeviceList + height: childrenRect.height + model: RemoteServiceModel.availableDevicesInPairingMode + spacing: Constants.component_spacing + visible: ApplicationModel.wifiEnabled && count > 0 + width: parent.width + + delegate: DevicesListDelegate { + //: LABEL ANDROID IOS + description: qsTr("Click to pair") + linkQuality: linkQualityInPercent + title: remoteDeviceName + (isSupported ? "" : (" (" + remoteDeviceStatus + ")")) + width: searchDeviceList.width + + onClicked: { + if (isSupported && RemoteServiceModel.rememberServer(deviceId)) { + d.oldLockedAndHiddenStatus = getLockedAndHidden(); + setLockedAndHidden(); + push(enterPinView); + } + } + } + } GText { - text: ApplicationModel.wifiEnabled ? - //: INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - qsTr("No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi.") : //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. - qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") - textStyle: ApplicationModel.wifiEnabled ? Style.text.normal_secondary : Style.text.normal_warning - visible: !searchDeviceList.visible + text: qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") + textStyle: Style.text.normal_warning + visible: !ApplicationModel.wifiEnabled width: parent.width } GButton { @@ -131,43 +178,14 @@ Item { visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible width: parent.width } - ListView { - id: searchDeviceList - height: childrenRect.height - interactive: false - model: RemoteServiceModel.availableRemoteDevices - spacing: Constants.component_spacing - visible: ApplicationModel.wifiEnabled && count > 0 + PairingProcessInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled + width: parent.width + } + RemoteServiceWifiInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled width: parent.width - - delegate: DevicesListDelegate { - //: LABEL ANDROID IOS - description: qsTr("Click to pair") - linkQuality: linkQualityInPercent - title: remoteDeviceName + (isSupported ? "" : (" (" + remoteDeviceStatus + ")")) - width: searchDeviceList.width - - onClicked: { - if (isSupported && RemoteServiceModel.rememberServer(deviceId)) { - informationPairingPopup.open(); - } - } - } } - } - } - ConfirmationPopup { - id: informationPairingPopup - style: ConfirmationPopup.PopupStyle.OkButton - //: INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - text: qsTr("Start the pairing mode on your smartphone if you haven't done it already.") - //: INFO ANDROID IOS - title: qsTr("Pairing mode") - - onConfirmed: { - d.oldLockedAndHiddenStatus = getLockedAndHidden(); - setLockedAndHidden(); - push(enterPinView); } } PasswordInfoData { diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml new file mode 100644 index 000000000..ab03cc225 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml @@ -0,0 +1,21 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +RowLayout { + spacing: Constants.text_spacing + + TintableIcon { + source: "qrc:/images/info.svg" + sourceSize.width: Style.dimens.small_icon_size + tintColor: Style.text.normal_secondary.textColor + } + GText { + Layout.fillWidth: true + + //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + text: qsTr("Both devices have to be connected to the same WiFi.") + textStyle: Style.text.normal_secondary + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml index 60dedbcb3..d3abf4966 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml @@ -3,17 +3,33 @@ */ import QtQuick 2.15 import QtQuick.Controls 2.15 +import Governikus.AuthView 1.0 import Governikus.EnterPasswordView 1.0 import Governikus.PasswordInfoView 1.0 +import Governikus.Style 1.0 import Governikus.TitleBar 1.0 import Governikus.View 1.0 +import Governikus.Workflow 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 import Governikus.Type.ReaderPlugIn 1.0 import Governikus.Type.RemoteServiceModel 1.0 +import Governikus.Type.SettingsModel 1.0 Controller { id: controller + + readonly property bool enterPasswordShown: stackView.currentItem instanceof EnterPasswordView + readonly property bool workflowShown: stackView.currentItem instanceof GeneralWorkflow + + function requestCard() { + if (RemoteServiceModel.hasCard && workflowShown) { + pop(); + } else if (!RemoteServiceModel.hasCard && !workflowShown) { + push(generalWorkflow); + } + } function requestInput(pState) { if (RemoteServiceModel.isBasicReader && RemoteServiceModel.pinPadModeOn()) { push(enterPinView); @@ -23,6 +39,14 @@ Controller { } Connections { + function onFireConnectedChanged() { + if (RemoteServiceModel.connectedToPairedDevice && !workflowShown) { + RemoteServiceModel.setInitialPluginType(); + requestCard(); + } else if (!RemoteServiceModel.connectedToPairedDevice && workflowShown) { + pop(); + } + } function onFireCurrentStateChanged() { switch (RemoteServiceModel.currentState) { case "Initial": @@ -32,7 +56,16 @@ Controller { RemoteServiceModel.continueWorkflow(); break; case "StateEnterPacePasswordIfd": - requestInput(); + if (SettingsModel.showAccessRights) { + push(editRights); + } else { + requestInput(); + } + break; + case "StateEstablishPaceChannelIfd": + case "StateChangePinIfd": + requestCard(); + RemoteServiceModel.continueWorkflow(); break; case "StateEnterNewPacePinIfd": requestInput(); @@ -45,9 +78,60 @@ Controller { RemoteServiceModel.continueWorkflow(); } } + function onFireHasCardChanged() { + if (!RemoteServiceModel.connectedToPairedDevice) { + return; + } + if (enterPasswordShown) { + return; + } + requestCard(); + } target: RemoteServiceModel } + Component { + id: editRights + EditRights { + //: LABEL ANDROID IOS + actionText: qsTr("You are about to identify yourself towards the following provider using the device \"%1\":").arg(RemoteServiceModel.connectedClientName) + //: LABEL ANDROID IOS + title: qsTr("Card reader") + workflowModel: RemoteServiceModel + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + pop(); + RemoteServiceModel.cancelPasswordRequest(); + } + } + + onRightsAccepted: { + ChatModel.transferAccessRights(); + pop(); + requestInput(); + } + } + } + Component { + id: generalWorkflow + GeneralWorkflow { + titleBarColor: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART ? Style.color.accent_smart : Style.color.accent + workflowModel: RemoteServiceModel + //: LABEL ANDROID IOS + workflowTitle: qsTr("Remote service") + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + RemoteServiceModel.setRunning(false); + } + } + } + } PasswordInfoData { id: infoData contentType: fromPasswordType(NumberModel.passwordType) @@ -70,6 +154,8 @@ Controller { id: passwordView enableTransportPinLink: RemoteServiceModel.enableTransportPinLink moreInformationText: infoData.linkText + //: LABEL ANDROID IOS + title: qsTr("Card reader") navigationAction: NavigationAction { action: NavigationAction.Action.Cancel @@ -85,6 +171,7 @@ Controller { } onPasswordEntered: { pop(); + RemoteServiceModel.startScanExplicitly(); RemoteServiceModel.continueWorkflow(); } onRequestPasswordInfo: push(passwordInfoView) diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml index a419e9d8e..e801577d7 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml @@ -11,7 +11,7 @@ import Governikus.View 1.0 SectionPage { id: rootPage //: LABEL ANDROID IOS - title: qsTr("Configure remote service") + title: qsTr("Manage pairings") content: RemoteServiceViewRemote { width: rootPage.width diff --git a/resources/qml/Governikus/RemoteServiceView/qmldir b/resources/qml/Governikus/RemoteServiceView/qmldir index a4aefd146..a17751a56 100644 --- a/resources/qml/Governikus/RemoteServiceView/qmldir +++ b/resources/qml/Governikus/RemoteServiceView/qmldir @@ -1,8 +1,11 @@ module RemoteServiceView internal DevicesListDelegate DevicesListDelegate.qml +internal PairingCodeInfoView PairingCodeInfoView.qml +internal PairingProcessInfo PairingProcessInfo.qml internal RemoteServiceController RemoteServiceController.qml internal RemoteServiceViewRemote RemoteServiceViewRemote.qml +internal RemoteServiceWifiInfo RemoteServiceWifiInfo.qml LinkQuality 1.0 LinkQuality.qml LocalNetworkInfo 1.0 LocalNetworkInfo.qml diff --git a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml index b724585ba..7447e9df7 100644 --- a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml +++ b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml @@ -25,10 +25,10 @@ SectionPage { property alias header: resultHeader.text property alias hintButtonText: hintItem.buttonText property alias hintText: hintItem.text + property alias mailButtonVisible: mailButton.visible property alias popupText: detailedResultPopup.text property alias popupTitle: detailedResultPopup.title property int resultType: ResultView.Type.IsSuccess - property alias supportButtonsVisible: supportButtonsLayout.visible property alias text: resultText.text signal emailButtonPressed @@ -88,17 +88,18 @@ SectionPage { } } RowLayout { - id: supportButtonsLayout Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true spacing: Constants.component_spacing - visible: false + visible: popupTitle !== "" || popupText !== "" GButton { + id: mailButton icon.source: "qrc:///images/material_mail.svg" //: LABEL DESKTOP text: qsTr("Send email") tintIcon: true + visible: false onClicked: baseItem.emailButtonPressed() } @@ -127,7 +128,7 @@ SectionPage { } } GButton { - icon.source: "qrc:/images/info.svg" + icon.source: "qrc:/images/desktop/info_white.svg" //: LABEL DESKTOP text: qsTr("See details") tintIcon: true diff --git a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml index 0da8356f2..779e0a185 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml @@ -110,8 +110,7 @@ SectionPage { pairingFailedView.errorMessage = pErrorMessage; d.view = ConnectSacView.SubView.PairingFailed; } - function onFirePairingSuccess(pDeviceName) { - ApplicationModel.showFeedback(qsTr("The device \"%1\" has been paired.").arg(pDeviceName)); + function onFirePairingSuccess() { root.closeView(); } diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml index 63647b258..3b092bb3f 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml @@ -50,12 +50,7 @@ Item { } GText { id: subtext - text: { - if (!isPaired) { - return qsTr("Click to pair"); - } - return remoteDeviceStatus; - } + text: remoteDeviceStatus textStyle: Style.text.normal width: parent.width } @@ -75,7 +70,7 @@ Item { source: "qrc:///images/material_delete.svg" sourceSize.height: iconHeight tintColor: Style.color.accent - visible: isPaired + visible: isPaired && !isPairing MouseArea { id: trashMouse @@ -99,7 +94,7 @@ Item { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - visible: !isPaired + visible: !trashMouse.visible onClicked: pairDevice(deviceId) } diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml index 57a6726d2..397f2430c 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml @@ -6,6 +6,7 @@ import QtQuick.Layouts 1.15 import Governikus.Global 1.0 import Governikus.Style 1.0 import Governikus.TitleBar 1.0 +import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.RemoteServiceModel 1.0 import Governikus.Type.ReaderScanEnabler 1.0 @@ -17,7 +18,6 @@ Item { readonly property string helpTopic: "settingsRemoteReader" - signal moreInformation signal pairDevice(string pDeviceId) signal unpairDevice(string pDeviceId) @@ -32,25 +32,50 @@ Item { anchors.fill: parent spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - text: qsTr("Paired remote devices") - textStyle: Style.text.header_accent - visible: knownDevices.count > 0 + Column { + spacing: Constants.component_spacing + visible: availablePairedDevices.count > 0 width: parent.width - FocusFrame { + GText { + activeFocusOnTab: true + text: qsTr("Paired devices") + textStyle: Style.text.header_accent + width: parent.width + + FocusFrame { + } + } + Repeater { + id: availablePairedDevices + model: RemoteServiceModel.availablePairedDevices + + delegate: RemoteReaderDelegate { + width: parent.width + + onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) + } } } Column { + spacing: Constants.component_spacing + visible: unavailablePairedDevices.count > 0 width: parent.width + GText { + activeFocusOnTab: true + text: qsTr("Last connected") + textStyle: Style.text.header_accent + width: parent.width + + FocusFrame { + } + } Repeater { - id: knownDevices - model: RemoteServiceModel.knownDevices + id: unavailablePairedDevices + model: RemoteServiceModel.unavailablePairedDevices delegate: RemoteReaderDelegate { - height: implicitHeight + Constants.pane_padding width: parent.width onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) @@ -58,12 +83,12 @@ Item { } } GSeparator { - visible: knownDevices.count > 0 + visible: availablePairedDevices.count > 0 || unavailablePairedDevices.count > 0 width: parent.width } GText { activeFocusOnTab: true - text: qsTr("Available remote devices") + text: qsTr("Add pairing") textStyle: Style.text.header_accent width: parent.width @@ -73,7 +98,7 @@ Item { GListView { id: availableDevices height: contentHeight - model: RemoteServiceModel.availableRemoteDevices + model: RemoteServiceModel.availableDevicesInPairingMode width: parent.width delegate: RemoteReaderDelegate { @@ -83,22 +108,47 @@ Item { onPairDevice: pDeviceId => root.pairDevice(pDeviceId) } } - GText { - activeFocusOnTab: true - text: RemoteServiceModel.availableRemoteDevices.emptyListDescriptionString - textStyle: Style.text.normal + Column { + spacing: Constants.text_spacing visible: availableDevices.count === 0 width: parent.width - FocusFrame { + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + qsTr("Open the %1 on your Smartphone as card reader.").arg(Qt.application.name), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + qsTr("On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + qsTr("Choose the device in the list to pair it.")] + + RowLayout { + spacing: Constants.component_spacing + width: parent.width + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + activeFocusOnTab: true + text: modelData + + FocusFrame { + } + } + } } } - GSeparator { - width: parent.width - } RowLayout { - id: hint spacing: Constants.text_spacing + visible: availableDevices.count === 0 width: parent.width TintableIcon { @@ -107,11 +157,10 @@ Item { tintColor: Style.color.accent } GText { - id: hintText Layout.alignment: Qt.AlignVCenter Layout.fillWidth: true activeFocusOnTab: true - text: qsTr("Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.") + text: qsTr("Both devices have to be connected to the same WiFi.") textStyle: Style.text.hint verticalAlignment: Text.AlignBottom wrapMode: Text.WordWrap @@ -120,11 +169,5 @@ Item { } } } - GButton { - //: LABEL DESKTOP - text: qsTr("More information") - - onClicked: moreInformation() - } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml index 75517f7b5..229ef7474 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml @@ -83,6 +83,7 @@ ColumnLayout { } GSeparator { Layout.fillWidth: true + visible: SettingsModel.autoUpdateAvailable } GText { activeFocusOnTab: true @@ -90,16 +91,18 @@ ColumnLayout { //: LABEL DESKTOP text: qsTr("Software updates") textStyle: Style.text.header_accent + visible: SettingsModel.autoUpdateAvailable FocusFrame { } } GCheckBox { checked: SettingsModel.autoUpdateCheck - enabled: !SettingsModel.autoUpdateCheckSetByAdmin && SettingsModel.autoUpdateAvailable + enabled: !SettingsModel.autoUpdateCheckSetByAdmin //: LABEL DESKTOP text: qsTr("Check at program start") + visible: SettingsModel.autoUpdateAvailable onCheckedChanged: SettingsModel.autoUpdateCheck = checked } @@ -109,9 +112,9 @@ ColumnLayout { Layout.fillWidth: true spacing: Constants.component_spacing + visible: SettingsModel.autoUpdateAvailable GButton { - enabled: SettingsModel.autoUpdateAvailable text: (parent.updateAvailable ? //: LABEL DESKTOP qsTr("Show update") : diff --git a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml index bd7238ae6..0a8b60764 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml @@ -97,12 +97,6 @@ SectionPage { height: Math.max(implicitHeight, tabbedPane.availableHeight) width: parent.width - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = SettingsView.SubView.ConnectSacView; diff --git a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml index 3f7c6d40f..e91d03cdf 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml @@ -66,12 +66,6 @@ SectionPage { height: Math.max(implicitHeight, tabbedPane.availableHeight) width: parent.width - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = TabbedReaderView.SubView.ConnectSacView; diff --git a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml index 33a375429..e72033ddd 100644 --- a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml @@ -136,12 +136,24 @@ SectionPage { onCheckedChanged: SettingsModel.pinPadMode = checked } + LabeledSwitch { + checked: SettingsModel.showAccessRights + //: LABEL ANDROID IOS + description: qsTr("Show requested rights on this device as well") + enabled: SettingsModel.pinPadMode + + //: LABEL ANDROID IOS + title: qsTr("Show access rights") + width: parent.width + + onCheckedChanged: SettingsModel.showAccessRights = checked + } MenuItem { //: LABEL ANDROID IOS - description: qsTr("Configure remote service for another device") + description: qsTr("Manage paired devices and add new devices") //: LABEL ANDROID IOS - title: qsTr("Remote card reader") + title: qsTr("Manage pairings") width: parent.width onClicked: push(remoteServiceSettings) @@ -396,9 +408,4 @@ SectionPage { } } } - navigationAction: NavigationAction { - action: topLevelPage ? NavigationAction.Action.None : NavigationAction.Action.Back - - onClicked: pop() - } } diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml index 82713d611..4948272db 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml @@ -12,6 +12,7 @@ import Governikus.View 1.0 import Governikus.WhiteListClient 1.0 import Governikus.Workflow 1.0 import Governikus.Type.ConnectivityManager 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 import Governikus.Type.PersonalizationModel 1.0 @@ -269,6 +270,11 @@ Controller { title: qsTr("Set up Smart-eID") titleBarColor: Style.color.accent_smart workflowModel: PersonalizationModel + + onRightsAccepted: { + ChatModel.transferAccessRights(); + PersonalizationModel.continueWorkflow(); + } } } Component { diff --git a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml index 4435138ec..3b7d6b830 100644 --- a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml @@ -4,11 +4,12 @@ import QtQml 2.15 import Governikus.Global 1.0 import Governikus.Type.SettingsModel 1.0 +import QtQuick.Window 2.15 BrandDimensions { readonly property int button_radius: 6 readonly property int corner_radius: 10 - readonly property int header_icon_size: Constants.is_tablet ? 240 : huge_icon_size + readonly property int header_icon_size: Constants.is_tablet ? Math.min(Screen.height / 5, 240) : huge_icon_size readonly property int high_contrast_item_border: 0 readonly property int huge_icon_size: 160 readonly property int icon_size: 48 @@ -33,4 +34,5 @@ BrandDimensions { readonly property int tutorial_component_spacing: 40 readonly property int tutorial_header_font_size: 26 readonly property int tutorial_title_font_size: 60 + readonly property int workflow_progress_indicator_size: 1.5 * header_icon_size } diff --git a/resources/qml/Governikus/Style/TextStyles.qml b/resources/qml/Governikus/Style/TextStyles.qml index 8c1cc9699..e697fce34 100644 --- a/resources/qml/Governikus/Style/TextStyles.qml +++ b/resources/qml/Governikus/Style/TextStyles.qml @@ -100,6 +100,10 @@ PlatformTextStyles { readonly property var normal_accent: TextStyle { textColor: Style.color.accent_text } + readonly property var normal_accent_highlight: TextStyle { + bold: true + textColor: Style.color.accent_text + } readonly property var normal_highlight: TextStyle { bold: true } diff --git a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml index 414e0c70f..bda44945d 100644 --- a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml +++ b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml @@ -24,6 +24,7 @@ Item { GFlickableColumnLayout { anchors.fill: parent spacing: 0 + topMargin: 0 GText { id: title diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml index 61e22e60f..bd5e40354 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml @@ -163,7 +163,7 @@ Item { id: settingsButton Accessible.description: qsTr("Open settings view of %1").arg(Qt.application.name) height: rightTitleBarActions.height - source: "qrc:///images/material_settings.svg" + source: "qrc:///images/desktop/material_settings_white.svg" text: qsTr("Settings") visible: rightMostAction.showSettings @@ -173,7 +173,7 @@ Item { id: helpButton Accessible.description: qsTr("Open online help of %1 in browser").arg(Qt.application.name) height: rightTitleBarActions.height - source: "qrc:///images/desktop/material_menu_book.svg" + source: "qrc:///images/desktop/material_menu_book_white.svg" text: qsTr("Open online help in browser") visible: rightMostAction.showHelp diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml index 3b65a1442..3012cf416 100644 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml +++ b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml @@ -201,7 +201,7 @@ SectionPage { horizontalAlignment: Text.AlignHCenter //: LABEL ANDROID IOS - text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...") + text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") textStyle: Style.text.tutorial_header width: parent.width * 0.9 @@ -240,7 +240,7 @@ SectionPage { animationsDisabled: true //: LABEL ANDROID IOS - text: qsTr("Start pairing") + text: qsTr("Pair device") Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml index 34e5f0478..2b7c1a517 100644 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml +++ b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml @@ -194,7 +194,7 @@ SectionPage { horizontalAlignment: Text.AlignHCenter //: LABEL ANDROID IOS - text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...") + text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") textStyle: Style.text.tutorial_header width: parent.width * 0.9 @@ -233,7 +233,7 @@ SectionPage { animationsDisabled: true //: LABEL ANDROID IOS - text: qsTr("Start pairing") + text: qsTr("Pair device") Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() @@ -343,7 +343,7 @@ SectionPage { horizontalAlignment: Text.AlignHCenter text: (Constants.is_layout_ios ? //: LABEL IOS - qsTr("Now open the AusweisApp2 on your device without NFC and select Configure remote service.") : + qsTr("Now open the AusweisApp2 on your device without NFC and select Manage pairings.") : //: LABEL ANDROID qsTr("Now open the AusweisApp2 on your device without NFC and select Smartphone as card reader.")) textStyle: Style.text.tutorial_header diff --git a/resources/qml/Governikus/View/+mobile/SectionPage.qml b/resources/qml/Governikus/View/+mobile/SectionPage.qml index ff8b43531..3d558d389 100644 --- a/resources/qml/Governikus/View/+mobile/SectionPage.qml +++ b/resources/qml/Governikus/View/+mobile/SectionPage.qml @@ -25,7 +25,6 @@ Controller { property color titleBarColor: Style.color.accent property real titleBarOpacity: 1 property bool titleBarVisible: true - readonly property bool topLevelPage: StackView.index === 0 signal reset diff --git a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml index cb1d6ee3c..583982c7f 100644 --- a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml @@ -19,6 +19,7 @@ SectionPage { property bool isPinChange: false property int waitingFor: 0 + signal deviceUnpaired(var pDeviceName) signal settingsRequested onWaitingForChanged: if (visible) @@ -33,8 +34,7 @@ SectionPage { } Connections { function onFireCertificateRemoved(pDeviceName) { - //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - ApplicationModel.showFeedback(qsTr("The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel diff --git a/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml deleted file mode 100644 index b035a4e6e..000000000 --- a/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 - -Item { - property string image - property alias running: busyIndicator.running - - GBusyIndicator { - id: busyIndicator - anchors.centerIn: parent - factor: 1.2 - height: img.height - running: false - width: height - } - Image { - id: img - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - smooth: true - source: image - width: parent.width - } -} diff --git a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml index f08536b74..884b0c22a 100644 --- a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml @@ -6,6 +6,7 @@ import Governikus.Global 1.0 import Governikus.TechnologyInfo 1.0 import Governikus.TitleBar 1.0 import Governikus.Workflow 1.0 +import Governikus.ResultView 1.0 import Governikus.View 1.0 import Governikus.Type.ReaderPlugIn 1.0 @@ -23,54 +24,60 @@ SectionPage { onClicked: workflowModel.cancelWorkflow() } - NfcWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC - - onStartScanIfNecessary: workflowModel.startScanIfNecessary() - + Item { anchors { - bottom: technologySwitch.top + bottom: technologySwitch.visible ? technologySwitch.top : parent.bottom left: parent.left right: parent.right top: parent.top } - } - SmartWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART - workflowModel: baseItem.workflowModel + NfcWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + onStartScanIfNecessary: workflowModel.startScanExplicitly() } - } - RemoteWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC - - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + SmartWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART + workflowModel: baseItem.workflowModel } - } - SimulatorWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR - workflowModel: baseItem.workflowModel + RemoteWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + onDeviceUnpaired: function (pDeviceName) { + push(deviceUnpairedView, { + "deviceName": pDeviceName + }); + } + + Component { + id: deviceUnpairedView + ResultView { + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + title: workflowTitle + + onCancelClicked: pop() + onContinueClicked: pop() + } + } + } + SimulatorWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR + workflowModel: baseItem.workflowModel } } TechnologySwitch { id: technologySwitch selectedTechnology: workflowModel.readerPlugInType supportedTechnologies: workflowModel.supportedPlugInTypes + visible: workflowModel.supportedPlugInTypes.length > 1 onRequestPluginType: pReaderPlugInType => workflowModel.readerPlugInType = pReaderPlugInType diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml index 85b4bb103..602e6d085 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml @@ -14,6 +14,8 @@ Item { property var cardPosition: null property bool startPositionLeft: true + height: Style.dimens.workflow_progress_indicator_size + states: [ State { name: "off" @@ -156,9 +158,9 @@ Item { anchors.centerIn: parent clip: true desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 opacity: tintEnabled ? 0.7 : 1.0 source: "qrc:///images/mobile/phone_nfc.svg" + sourceSize.height: Style.dimens.header_icon_size z: 0 Image { diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml index bd34b7927..bf22c67bb 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml @@ -8,10 +8,12 @@ import Governikus.TechnologyInfo 1.0 import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.ReaderPlugIn 1.0 import Governikus.Type.NumberModel 1.0 +import Governikus.Type.RemoteServiceModel 1.0 Item { id: baseItem + readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE readonly property int nfcState: visible ? ApplicationModel.nfcState : ApplicationModel.NFC_UNAVAILABLE signal startScanIfNecessary @@ -22,7 +24,6 @@ Item { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - height: baseItem.height / 2 state: nfcState === ApplicationModel.NFC_READY ? "on" : "off" } TechnologyInfo { @@ -52,9 +53,9 @@ Item { //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. qsTr("Please enable NFC in your system settings."); case ApplicationModel.NFC_INACTIVE: - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. return qsTr("NFC scan is not running.") + "
" + - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. qsTr("Please start the NFC scan."); default: return ""; @@ -76,6 +77,10 @@ Item { } } titleText: { + if (isRemoteWorkflow && RemoteServiceModel.connectedClientName !== "") { + //: INFO ANDROID IOS %1 will be replaced with the name of the device. + return qsTr("The device \"%1\" wants to use this smartphone as card reader and connect to your id card.").arg(RemoteServiceModel.connectedClientName); + } switch (nfcState) { case ApplicationModel.NFC_UNAVAILABLE: //: INFO ANDROID IOS diff --git a/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml similarity index 55% rename from resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml rename to resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml index 97314e090..85c3ca2c1 100644 --- a/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml @@ -3,21 +3,23 @@ */ import QtQuick 2.15 import Governikus.Global 1.0 +import Governikus.Style 1.0 Item { id: baseItem - property alias imageIconSource: busyIcon.image - property alias imagePhoneSource: phone.source + property bool foundSelectedReader: false + + height: Style.dimens.workflow_progress_indicator_size TintableIcon { id: phone anchors.centerIn: parent desaturate: true - height: parent.height * 0.5 opacity: tintEnabled ? 0.7 : 1.0 - visible: baseItem.state === "off" - width: height + source: "qrc:///images/mobile/phone_remote.svg" + sourceSize.height: Style.dimens.header_icon_size + visible: !baseItem.foundSelectedReader } Item { id: currentAction @@ -27,20 +29,11 @@ Item { anchors.right: parent.right anchors.top: parent.top - BusyImageIndicator { - id: busyIcon - anchors.centerIn: parent - height: Math.min(parent.height - 40, 2 * pCircle.height) - running: visible - visible: baseItem.state === "one" - width: height - } CardReader { anchors.centerIn: parent - cardAnimation: baseItem.state === "two" height: parent.height pinFieldAnimation: false - visible: baseItem.state === "two" + visible: baseItem.foundSelectedReader } } ProgressCircle { @@ -48,7 +41,7 @@ Item { anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - state: baseItem.state - visible: baseItem.state === "one" || baseItem.state === "two" + state: baseItem.foundSelectedReader ? "two" : "off" + visible: baseItem.foundSelectedReader } } diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml index 2b152f390..0ecf8be70 100644 --- a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml @@ -18,6 +18,8 @@ Item { property bool settingsPushed: remoteServiceSettings.visible property bool wifiEnabled: ApplicationModel.wifiEnabled + signal deviceUnpaired(var pDeviceName) + onFoundSelectedReaderChanged: { if (baseItem.settingsPushed && foundSelectedReader) { remoteServiceSettings.pop(); @@ -26,22 +28,18 @@ Item { Connections { function onFireCertificateRemoved(pDeviceName) { - //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - ApplicationModel.showFeedback(qsTr("The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel } - ProgressIndicator { + RemoteProgressIndicator { id: progressIndicator Accessible.ignored: true anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - height: parent.height / 2 - imageIconSource: "qrc:///images/mobile/icon_remote.svg" - imagePhoneSource: "qrc:///images/mobile/phone_remote.svg" - state: foundSelectedReader ? "two" : "off" + foundSelectedReader: baseItem.foundSelectedReader } TechnologyInfo { id: techInfo @@ -51,7 +49,7 @@ Item { return qsTr("Enable WiFi"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Pair device"); + return qsTr("Manage pairings"); } else { return ""; } @@ -62,7 +60,7 @@ Item { return qsTr("To use the remote service WiFi has to be activated. Please activate WiFi in your device settings."); } else if (!foundSelectedReader) { //: INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - return qsTr("No paired smartphone as card reader (SaC) with activated \"remote service\" available."); + return qsTr("Allow a connection on a paired smartphone or pair a new smartphone."); } else { return ""; } @@ -87,7 +85,7 @@ Item { return qsTr("Wifi disabled"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Waiting for connection"); + return qsTr("No smartphone as card reader connected"); } else { //: LABEL ANDROID IOS return qsTr("Determine card"); diff --git a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml index 47c6b033c..16dac48e2 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml @@ -4,6 +4,7 @@ import QtQuick 2.15 import Governikus.Global 1.0 import Governikus.TechnologyInfo 1.0 +import Governikus.Style 1.0 Item { id: baseItem @@ -12,7 +13,7 @@ Item { Item { id: progressIndicator - height: parent.height / 2 + height: Style.dimens.workflow_progress_indicator_size anchors { left: parent.left @@ -23,8 +24,8 @@ Item { id: icon anchors.centerIn: parent desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 source: "qrc:///images/mobile/phone_simulator.svg" + sourceSize.height: Style.dimens.header_icon_size tintEnabled: false } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml index 9a040a657..d4e385531 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml @@ -3,18 +3,21 @@ */ import QtQuick 2.15 import Governikus.Global 1.0 +import Governikus.Style 1.0 Item { id: baseItem property alias disabled: icon.tintEnabled + height: Style.dimens.workflow_progress_indicator_size + TintableIcon { id: icon anchors.centerIn: parent desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 opacity: tintEnabled ? 0.7 : 1.0 source: "qrc:///images/mobile/phone_smart.svg" + sourceSize.height: Style.dimens.header_icon_size } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml index ce02c0452..1c2a7b5c9 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml @@ -4,6 +4,7 @@ import QtQuick 2.15 import Governikus.Global 1.0 import Governikus.TechnologyInfo 1.0 +import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.SmartModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PersonalizationModel 1.0 @@ -12,6 +13,7 @@ Item { id: baseItem readonly property bool canUseSmart: smartState === SmartModel.SMART_READY && isSmartCardAllowed && SmartModel.isScanRunning + readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE readonly property bool isSmartCardAllowed: workflowModel.isSmartCardAllowed readonly property int smartState: SmartModel.smartState property var workflowModel @@ -20,7 +22,6 @@ Item { id: progressIndicator Accessible.ignored: true disabled: !canUseSmart - height: parent.height / 2 anchors { left: parent.left @@ -55,6 +56,10 @@ Item { } return ""; default: + if (isRemoteWorkflow) { + //: LABEL ANDROID IOS + return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen."); + } //: LABEL ANDROID IOS return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo proceed use your ID card by selecting the NFC interface or choose \"WiFi\" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen."); } diff --git a/resources/qml/Governikus/Workflow/qmldir b/resources/qml/Governikus/Workflow/qmldir index c79470eb0..dbdcf504f 100644 --- a/resources/qml/Governikus/Workflow/qmldir +++ b/resources/qml/Governikus/Workflow/qmldir @@ -1,10 +1,9 @@ module Workflow -internal BusyImageIndicator BusyImageIndicator.qml internal CardReader CardReader.qml internal NfcProgressIndicator NfcProgressIndicator.qml internal ProgressCircle ProgressCircle.qml -internal ProgressIndicator ProgressIndicator.qml +internal RemoteProgressIndicator RemoteProgressIndicator.qml internal RemoteWorkflow RemoteWorkflow.qml internal SmartProgressIndicator SmartProgressIndicator.qml internal TextCircle TextCircle.qml diff --git a/resources/translations/ausweisapp2_de.ts b/resources/translations/ausweisapp2_de.ts index da1d532e1..e40e18354 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Do you know your six-digit ID card PIN? Kennen Sie Ihre sechsstellige Karten-PIN? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Sie haben dreimal eine falsche, sechsstellige Karten-PIN eingegeben, Ihre Karten-PIN ist nun gesperrt. Um die Sperre aufzuheben, muss zunächst die zehnstellige PUK eingegeben werden. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + ChangePinViewContent @@ -984,10 +994,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Das Gerät wird gekoppelt ... - - The device "%1" has been paired. - Das Gerät "%1" wurde gekoppelt. - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. @@ -1468,11 +1474,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Bitte wiederholen Sie die Eingabe Ihrer neuen sechsstelligen Karten-PIN. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Starten Sie die Kopplung auf Ihrem Smartphone und geben Sie den dort angezeigten Kopplungscode ein um Ihr Smartphone als Kartenleser (SaK) zu verwenden. - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS LABEL ANDROID IOS Karten-PIN senden + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Geben Sie den Kopplungscode ein, der auf Ihrem Smartphone angezeigt wird. + GProgressBar @@ -1685,11 +1691,6 @@ LABEL ANDROID IOS GeneralWorkflow - - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. - Attempts LABEL DESKTOP @@ -1753,6 +1754,11 @@ LABEL ANDROID IOS INFO DESKTOP Zu den Einstellungen + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + Hint @@ -1765,20 +1771,8 @@ LABEL ANDROID IOS HistoryListItem Click to view details of history entry. - Zeige Details des Verlaufseintrags. - - - today LABEL ANDROID IOS - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy + Zeige Details des Verlaufseintrags. Tap for more details @@ -1859,18 +1853,6 @@ LABEL ANDROID IOS LABEL DESKTOP Im Verlauf suchen - - today - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - Clear history LABEL DESKTOP @@ -1959,6 +1941,9 @@ LABEL ANDROID IOS dd.MM.yyyy + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy @@ -2052,16 +2037,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Um Ihr Smartphone als Kartenleser (SaK) nutzen zu können, stellen Sie bitte sicher, dass der Zugriff auf das lokale Netzwerk erlaubt ist. - Go to application settings INFO IOS Link to application settings Zu den Anwendungseinstellungen + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + In den Einstellungen muss der Zugriff auf das lokale Netzwerk erlaubt sein. + LogTitleBarControls @@ -2576,10 +2561,6 @@ LABEL ANDROID IOS Provider Anbieter - - Remote - Fernzugriff - Settings Einstellungen @@ -2588,6 +2569,10 @@ LABEL ANDROID IOS Help Hilfe + + Card reader + Kartenleser + NfcWorkflow @@ -2623,12 +2608,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Der NFC-Scan ist nicht aktiv. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Bitte starten Sie den NFC-Scan. @@ -2666,6 +2651,11 @@ LABEL ANDROID IOS INFO ANDROID The ID card may be inserted, the authentication process may be started. Bitte platzieren Sie Ihren Ausweis direkt an der Geräterückseite.<br/><br/>Die genaue Position des Ausweises ist modellabhängig. Die Animationen zeigen Ihnen mögliche Positionen. Halten Sie jede Position einige Sekunden, bevor Sie eine andere ausprobieren und bewegen Sie den Ausweis nicht mehr, sobald der Kontakt hergestellt wurde. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Das Gerät "%1" möchte dieses Smartphone als Kartenleser nutzen und sich mit Ihrem Ausweis verbinden. + NumberField @@ -2727,6 +2717,52 @@ LABEL ANDROID IOS Deaktiviert + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Informationen zur Kopplung + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Öffnen Sie auf Ihrem %2anderen Gerät%3 die %1. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Gehen Sie dort in die %1Einstellungen%2 und dann zu %1Smartphone als Kartenleser%2 bzw. %1Kopplungen verwalten%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Wählen Sie in der angezeigten Liste dieses Smartphone aus, um es zu koppeln. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. + + PasswordInfoContent @@ -3315,19 +3351,6 @@ INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. ProviderDetailHistoryItem - - today - LABEL ANDROID IOS - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - Service: LABEL DESKTOP @@ -3590,10 +3613,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Drücken Sie die Leertaste um das Smartphone "%1" zu koppeln. - - Click to pair - Klicken zum Koppeln - Remove remote device Entferne das Gerät @@ -3602,38 +3621,70 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - Gekoppelte Netzwerkgeräte + Paired devices + Gekoppelte Geräte - Available remote devices - Verfügbare Netzwerkgeräte + Add pairing + Kopplung hinzufügen - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Nur Geräte die bereits gekoppelt wurden, oder sich mit aktiviertem Fernzugriff im selben WLAN-Netz befinden, werden hier angezeigt. + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. - More information - LABEL DESKTOP - Mehr Informationen + Both devices have to be connected to the same WiFi. + Beide Geräte müssen mit demselben WLAN verbunden sein. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Last connected + Zuletzt verbunden + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. - RemoteServiceSettings + RemoteServiceController - Configure remote service + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS - Fernzugriff konfigurieren + Sie möchten sich mit dem Gerät %1 bei folgendem Anbieter ausweisen: + + + Card reader + LABEL ANDROID IOS + Kartenleser - - - RemoteServiceView Remote service LABEL ANDROID IOS Fernzugriff + + + RemoteServiceSettings + + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten + + + + RemoteServiceView Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3664,35 +3715,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Warte auf Verbindung - - Remote service ready - LABEL ANDROID IOS - Fernzugriff startbereit - Waiting for connection from a paired device... INFO ANDROID IOS Warte auf eine Verbindung eines gekoppelten Gerätes... - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Starten Sie den Fernzugriff, um dieses Smartphone sichtbar und damit als Kartenleser (SaK) nutzbar zu machen. - -Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um dieses Smartphone als Kartenleser einzurichten. - Pairing code: <b>%1</b> LABEL ANDROID IOS Kopplungscode: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Ihre beiden Geräte müssen mit dem selben WLAN-Netz verbunden sein. - Enable WiFi LABEL ANDROID IOS @@ -3704,48 +3736,77 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d NFC aktivieren - Stop remote service + Pair device LABEL ANDROID IOS - Fernzugriff stoppen + Gerät koppeln - Start remote service + Allow connection LABEL ANDROID IOS - Fernzugriff starten + Verbindung erlauben - Stop pairing - LABEL ANDROID IOS - Kopplung stoppen + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Sie können dieses Smartphone als Kartenleser für die %1 auf einem anderen Gerät, z.B. Ihrem Laptop, nutzen. + +Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppeln. - Start pairing + Card reader LABEL ANDROID IOS - Kopplung starten + Kartenleser - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). + Paired Devices INFO ANDROID IOS - Geben Sie den Code %1 in der %2 auf Ihrem anderen Gerät ein, um Ihr Smartphone als Kartenleser (SaK) zu verwenden. + Gekoppelte Geräte - - - RemoteServiceViewRemote - Paired devices + Pair new device LABEL ANDROID IOS - Gekoppelte Geräte + Neues Gerät koppeln - No device is paired. + Waiting for pairing LABEL ANDROID IOS - Kein Gerät gekoppelt. + Warte auf Kopplung - Click to remove device + Start pairing of a new device LABEL ANDROID IOS - Klicken, um das Gerät zu entfernen + Kopplung mit einem neuen Gerät starten. + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Wo gebe ich den Kopplungscode ein? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Geben Sie den Kopplungscode %1 in der %2 auf Ihrem anderen Gerät ein. + + + Cancel pairing + LABEL ANDROID IOS + Kopplung abbrechen + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Erlauben Sie eine Verbindung mit gekoppelten Geräten, um dieses Smartphone als Kartenleser zu nutzen oder koppeln Sie weitere Geräte. + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Gekoppelte Geräte können dieses Smartphone jetzt als Kartenleser nutzen. + + + + RemoteServiceViewRemote Remove pairing INFO ANDROID IOS @@ -3761,16 +3822,6 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d INFO ANDROID IOS Entfernen - - Available devices - LABEL ANDROID IOS - Verfügbare Geräte - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Kein ungekoppeltes Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3782,63 +3833,66 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d WLAN aktivieren - Click to pair + Pairing code LABEL ANDROID IOS - Klicken zum Koppeln + Kopplungscode - Pairing mode - INFO ANDROID IOS - Kopplungsmodus + Add pairing + LABEL ANDROID IOS + Kopplung hinzufügen + + + Click to remove device + LABEL ANDROID IOS + Klicken, um das Gerät zu entfernen - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Starten Sie den Kopplungsmodus auf Ihrem Smartphone, falls noch nicht geschehen. + Last connected + LABEL ANDROID IOS + Zuletzt verbunden - Pairing code + Available LABEL ANDROID IOS - Kopplungscode + Verfügbar + + + Paired devices + LABEL ANDROID IOS + Gekoppelte Geräte + + + Click to pair + LABEL ANDROID IOS + Klicken zum Koppeln - RemoteWorkflow + RemoteServiceWifiInfo - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Beide Geräte müssen mit demselben WLAN verbunden sein. + + + RemoteWorkflow Enable WiFi LABEL ANDROID IOS WLAN aktivieren - - Pair device - LABEL ANDROID IOS - Gerät koppeln - To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Um den Fernzugriff zu nutzen, muss WLAN aktiviert werden. Bitte aktivieren Sie WLAN in Ihren Einstellungen. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Kein gekoppeltes Smartphone als Kartenleser mit aktiviertem "Fernzugriff" verfügbar. - Wifi disabled LABEL ANDROID IOS WLAN ist deaktiviert - - Waiting for connection - LABEL ANDROID IOS - Warte auf Verbindung - Determine card LABEL ANDROID IOS @@ -3854,6 +3908,21 @@ Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um d INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Verbunden mit %1. Bitte platzieren Sie das Smartphone mit der NFC-Schnittstelle auf Ihrem Ausweis. + + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten + + + No smartphone as card reader connected + LABEL ANDROID IOS + Kein Smartphone als Kartenleser verbunden + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Erlauben Sie die Verbindung auf einem bereits gekoppelten Smartphone oder koppeln Sie ein neues Smartphone. + ResultErrorView @@ -4248,16 +4317,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS PIN-Eingabe auf diesem Gerät - - Remote card reader - LABEL ANDROID IOS - Smartphone als Kartenleser - - - Configure remote service for another device - LABEL ANDROID IOS - Ein anderes Gerät für den Fernzugriff konfigurieren - Save history LABEL ANDROID IOS @@ -4375,6 +4434,26 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS 15 Tage alte Protokolldatei + + Show requested rights on this device as well + LABEL ANDROID IOS + Angefragte Berechtigung auch auf diesem Gerät anzeigen + + + Show access rights + LABEL ANDROID IOS + Berechtigungsanzeige + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Gekoppelte Geräte verwalten und neue Geräte hinzufügen + + + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten + SetupAssistantView @@ -4758,6 +4837,15 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Continue Weiter + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Sie haben noch keine Smart-eID eingerichtet oder diese ist nicht mehr nutzbar. + +Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle auswählen. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID-Einrichtung vom Startbildschirm. + StoreFeedbackPopup @@ -5325,9 +5413,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Beide Geräte müssen im selben WLAN sein - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Fernzugriff"... + Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Kartenleser"... Now @@ -5335,9 +5423,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Jetzt - Start pairing + Pair device LABEL ANDROID IOS - Kopplung starten + Gerät koppeln Pairing code @@ -5483,9 +5571,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Beide Geräte müssen im selben WLAN sein - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Fernzugriff"... + Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Kartenleser"... Now @@ -5493,9 +5581,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Jetzt - Start pairing + Pair device LABEL ANDROID IOS - Kopplung starten + Gerät koppeln Pairing code @@ -5513,9 +5601,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Bei der ersten Verwendung des Smartphones als Kartenleser (SaK) bittet iOS Sie um Ihre Erlaubnis um auf das lokale Netzwerk zugreifen zu dürfen. Diese Berechtigung ist erforderlich, um Ihr SaK zu finden und eine Verbindung zu ihm herzustellen. Nach der ersten Anfrage können Sie jederzeit auf die Berechtigung in den iOS-Einstellungen für diese App zugreifen. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Fernzugriff konfigurieren</b> aus. + Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Kopplungen verwalten</b> aus. Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. @@ -5925,6 +6013,24 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Link zur Prüfsumme: + + Utils + + today + LABEL ALL_PLATFORMS + heute + + + yesterday + LABEL ALL_PLATFORMS + gestern + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy + + VersionInformation @@ -6318,7 +6424,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d. MMMM yyyy, HH:mm:ss 'Uhr' @@ -6528,7 +6634,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy, hh:mm:ss @@ -6793,9 +6899,9 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Die Authentisierung ist fehlgeschlagen. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Die Länge der an den Ausweis gesendeten Daten wurde nicht akzeptiert. Entweder sind die Daten fehlerhaft oder Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. No certificate description available. @@ -7095,6 +7201,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au governikus::HistoryModelSearchFilter dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy @@ -7147,6 +7254,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy hh:mm:ss + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm:ss @@ -7206,6 +7314,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au governikus::NotificationModel hh:mm:ss + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm:ss @@ -7299,7 +7408,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy HH:mm @@ -7324,12 +7433,12 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm @@ -7475,6 +7584,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm:ss @@ -7530,11 +7640,6 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au LABEL ALL_PLATFORMS Gekoppelt, aber nicht unterstützt - - Paired, but unavailable - LABEL ALL_PLATFORMS - Gekoppelt, aber nicht verfügbar - Unsupported LABEL ALL_PLATFORMS @@ -7547,6 +7652,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy HH:mm @@ -7559,6 +7665,16 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Kein Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind. Informationen zur Verwendung finden Sie in der %1. + + Unavailable + LABEL ALL_PLATFORMS + Nicht verfügbar + + + Click to pair + LABEL ALL_PLATFORMS + Klicken zum Koppeln + governikus::RemoteServiceModel @@ -7590,6 +7706,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu können. + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Die Kopplung mit %1 war erfolgreich. + governikus::RemoteServiceSettings @@ -7613,14 +7734,17 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy xx.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day xx.MM.yyyy xx.xx.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month xx.xx.yyyy @@ -7763,6 +7887,14 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu k Zugriff verweigert. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Der sichere Kanal wird geöffnet + + governikus::StateFinalizePersonalization diff --git a/resources/translations/ausweisapp2_ru.ts b/resources/translations/ausweisapp2_ru.ts index 79350d56a..43dbdadcc 100644 --- a/resources/translations/ausweisapp2_ru.ts +++ b/resources/translations/ausweisapp2_ru.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Do you know your six-digit ID card PIN? Вы знаете 6-значный PIN-код идентификационной карты? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Вы трижды ввели неправильный 6-значный PIN-код идентификационной карты, PIN-код идентификационной карты заблокирован. Для разблокировки введите 10-значный PUK-код. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + ChangePinViewContent @@ -504,11 +514,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL ALL_PLATFORMS Какой у вас PIN-код? + + Six-digit PIN + LABEL ALL_PLATFORMS + 6-значный PIN-код + Set by yourself LABEL ALL_PLATFORMS Создается пользователем самостоятельно + + Five-digit Transport PIN + LABEL ALL_PLATFORMS + 5-значный временный PIN-код + Received by mail in PIN letter LABEL ALL_PLATFORMS @@ -524,16 +544,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL ALL_PLATFORMS Утерян, забыт или не получен вовсе - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значный PIN-код - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значный временный PIN-код - CheckConnectivityView @@ -665,7 +675,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы также можете использовать другой смартфон в качестве устройства чтения карт для онлайн-идентификации.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы можете воспользоваться функцией eID на другом смартфоне, используемом в качестве устройства чтения карт.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. Open website @@ -695,7 +705,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. %1 не имеет какого-либо влияния на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. ID card access failed @@ -725,7 +735,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The ID card PIN has been entered incorrectly twice in a row. This is why you must first enter the six-digit Card Access Number (CAN) for the next identification process. You can find it at the bottom right of the front of your ID card.<br><br>You may now try the function: "See my personal data". There you can also use the CAN to unblock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он расположен внизу справа на передней стороне идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он указан внизу справа на передней стороне вашей идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. Continue @@ -740,7 +750,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The ID card PIN has been entered incorrectly thrice. Therefore, you must first enter the ten-digit PUK during the next authentication process. You can find it in the PIN letter you received after applying for your ID card.<br><br>You may now try the function: "See my personal data". Have your PUK ready to unlock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. @@ -984,10 +994,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Сопряжение устройства… - - The device "%1" has been paired. - Устройство «%1» сопряжено. - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. @@ -1468,11 +1474,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Подтвердите новый 6-значный PIN-код идентификационной карты. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Запустите сопряжение на смартфоне и введите указанный в смартфоне код сопряжения для использования смартфона в качестве устройства чтения карт (SaC). - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS LABEL ANDROID IOS Отправить PIN-код идентификационной карты + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Введите указанный в смартфоне код сопряжения. + GProgressBar @@ -1685,11 +1691,6 @@ LABEL ANDROID IOS GeneralWorkflow - - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. - Attempts LABEL DESKTOP @@ -1753,6 +1754,11 @@ LABEL ANDROID IOS INFO DESKTOP Перейти к настройкам устройства чтения карт + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + Hint @@ -1765,20 +1771,8 @@ LABEL ANDROID IOS HistoryListItem Click to view details of history entry. - Щелкните, чтобы просмотреть подробную информацию о записи журнала. - - - today LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг + Щелкните, чтобы просмотреть подробную информацию о записи журнала. Tap for more details @@ -1859,18 +1853,6 @@ LABEL ANDROID IOS LABEL DESKTOP Поиск в журнале - - today - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг - Clear history LABEL DESKTOP @@ -1959,7 +1941,10 @@ LABEL ANDROID IOS dd.MM.yyyy - дд.ММ.гггг + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy Write access (update) @@ -2052,16 +2037,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Чтобы использовать смартфон в качестве устройства чтения карт (SaC), убедитесь в наличии доступа к локальной сети. - Go to application settings INFO IOS Link to application settings Перейти к настройкам приложения + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Убедитесь в наличии доступа к локальной сети. + LogTitleBarControls @@ -2163,20 +2148,20 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r LABEL ANDROID IOS Фильтр - - Currently there are no log entries matching your filter. - INFO ANDROID IOS No log entries, placeholder text. - В настоящее время отсутствуют записи журнала, соответствующие вашему фильтру. - Level LABEL ANDROID IOS - Уровень + Уровень Category LABEL ANDROID IOS - Категория + Категория + + + Currently there are no log entries matching your filter. + INFO ANDROID IOS No log entries, placeholder text. + В настоящее время отсутствуют записи журнала, соответствующие вашему фильтру. @@ -2576,10 +2561,6 @@ LABEL ANDROID IOS Provider Провайдер - - Remote - Удаленный доступ - Settings Настройки @@ -2588,6 +2569,10 @@ LABEL ANDROID IOS Help Справка + + Card reader + Устройство чтения карт + NfcWorkflow @@ -2623,12 +2608,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. NFC-сканирование не выполняется. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Запустите NFC-сканирование. @@ -2666,6 +2651,11 @@ LABEL ANDROID IOS INFO ANDROID The ID card may be inserted, the authentication process may be started. Расположите идентификационную карту непосредственно на задней стороне устройства.<br/><br/>Точное положение идентификационной карты зависит от устройства. Возможное положение показано в анимации. Удерживайте идентификационную карту в одном положении несколько секунд, прежде чем поменять положение, и не смещайте ее после установки соединения. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Устройство «%1» планирует использовать данный смартфон в качестве устройства чтения карт и установить соединение с вашей идентификационной картой. + NumberField @@ -2727,6 +2717,52 @@ LABEL ANDROID IOS Деактивировано + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Информация о сопряжении + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Откройте %1 в другом %2вашем устройстве%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + В данном устройстве перейдите в меню %1Настройки%2, а затем %1Смартфон в качестве устройства чтения карт%2 и в соответствующее меню %1Управлять сопряжениями%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Чтобы выполнить сопряжение, выберите данный смартфон в списке. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + В данном устройстве выберите %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите смартфон в приведенном списке. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. + + PasswordInfoContent @@ -2747,16 +2783,36 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Информация о PIN-коде + + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID. + Where can I find the card PIN? LABEL ALL_PLATFORMS Где найти PIN-код карты? + + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' + Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID. + How do I choose a secure PIN? LABEL ALL_PLATFORMS Как выбрать безопасный PIN-код? + + For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 + Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, «123456», дату своего рождения или любые другие цифры с идентификационной карты). + + + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 + Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код. + Keep your PIN secret and change it if another person becomes aware of it. INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 @@ -2772,6 +2828,16 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Информация о временном PIN-коде + + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 + 5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту. + + + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 + Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода. + Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 @@ -2802,6 +2868,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Информация о PUK-коде + + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' + PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту. + Why is the PUK required? LABEL ALL_PLATFORMS @@ -2857,6 +2928,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Где найти CAN-код? + + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' + CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты. + The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). INFO ALL_PLATFORMS Description text of CAN-allowed authentication @@ -2889,6 +2965,11 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Знаете ли вы свой PIN-код? + + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? + INFO ALL_PLATFORMS + Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код? + You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS @@ -2904,105 +2985,60 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Типы PIN-кодов - - This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - Этот PIN-код позволяет в режиме онлайн подтвердить то, что идентификационная карта принадлежит именно вам. Никто не сможет использовать вашу идентификационную карту в режиме онлайн без этого PIN-кода. - - - You can use the PIN Reset Service to request a new card PIN free of charge. - LABEL ALL_PLATFORMS - Вы можете воспользоваться службой сброса PIN-кода, чтобы бесплатно запросить новый PIN-код карты. - - - If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. - LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. - Если вы не знаете ни своего временного PIN-кода, ни PIN-кода карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. - - - If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. - LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. - Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. - - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID. - - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID. - - - For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 - Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, 123456, дату своего рождения или любые другие цифры с идентификационной карты). - - - You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код. - - - The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - 5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту. - - - If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода. - - - The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту. - - - The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты. - Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. INFO ALL_PLATFORMS Description text explaining the PINs 1/6 - К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить 6-значным PIN-кодом (его вы выберете сами). + К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить на 6-значным PIN-кодом (его вы выберете сами). Five-digit Transport PIN LABEL ALL_PLATFORMS - 5-значный временный PIN-код + 5-значный временный PIN-код The five-digit Transport PIN was sent to you by post after you applied for your ID card. INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. + 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами. + Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами. Six-digit PIN LABEL ALL_PLATFORMS - 6-значный PIN-код + 6-значный PIN-код This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. + Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. + + + This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 5/6 + Этот PIN-код позволяет в режиме онлайн подтвердить то, что идентификационная карта принадлежит именно вам. Никто не сможет использовать вашу идентификационную карту в режиме онлайн без этого PIN-кода. You can change your six-digit PIN at any time in AusweisApp2. INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2. + Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2. - You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? - INFO ALL_PLATFORMS - Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код? + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS + Вы можете воспользоваться службой сброса PIN-кода, чтобы бесплатно запросить новый PIN-код карты. + + + If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Если вы не знаете ни своего временного PIN-кода, ни PIN-кода карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. + + + If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. @@ -3315,19 +3351,6 @@ INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. ProviderDetailHistoryItem - - today - LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг - Service: LABEL DESKTOP @@ -3387,7 +3410,7 @@ INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. See details under "more..." LABEL DESKTOP - Подробнее см. в пункте «Дополнительные сведения» + Подробнее см. в пункте «Дополнительные сведения». @@ -3590,10 +3613,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Нажмите пробел для сопряжения смартфона «%1». - - Click to pair - Нажмите для сопряжения - Remove remote device Удалить дистанционное устройство @@ -3602,38 +3621,70 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - Сопряженные дистанционные устройства + Paired devices + Сопряженные устройства - Available remote devices - Доступные дистанционные устройства + Add pairing + Добавить сопряжение - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Здесь отображаются только уже сопряженные или подключенные к той же сети Wi-Fi устройства с активированной удаленной службой. + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. - More information - LABEL DESKTOP - Дополнительные сведения + Both devices have to be connected to the same WiFi. + Оба устройства должны быть подключены к одной сети Wi-Fi. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + В данном устройстве перейдите в меню %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и в соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите устройство в списке. + + + Last connected + Последние подключенные + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. - RemoteServiceSettings + RemoteServiceController - Configure remote service + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS - Сконфигурировать удаленную службу + Вы собираетесь пройти самоидентификацию для следующего провайдера, используя устройство «%1»: + + + Card reader + LABEL ANDROID IOS + Устройство чтения карт - - - RemoteServiceView Remote service LABEL ANDROID IOS Удаленная служба + + + RemoteServiceSettings + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + + + + RemoteServiceView Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3664,35 +3715,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Ожидание соединения - - Remote service ready - LABEL ANDROID IOS - Удаленная служба готова к работе - Waiting for connection from a paired device... INFO ANDROID IOS Ожидание соединения сопряженного устройства… - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Запустите удаленный доступ, чтобы смартфон стал видимым и его можно было использовать как устройство чтения карт (SaC). - -Если сопряженных устройств еще нет, запустите сопряжение, чтобы настроить смартфон как устройство чтения карт. - Pairing code: <b>%1</b> LABEL ANDROID IOS Код сопряжения: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Оба устройства должны быть подключены к одной сети Wi-Fi. - Enable WiFi LABEL ANDROID IOS @@ -3704,48 +3736,77 @@ If you have not already paired a device, start the pairing now to set up this sm Активировать NFC - Stop remote service + Pair device LABEL ANDROID IOS - Остановить удаленную службу + Выполнить сопряжение устройства - Start remote service + Allow connection LABEL ANDROID IOS - Запустить удаленную службу + Разрешить подключение - Stop pairing - LABEL ANDROID IOS - Остановить сопряжение + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Можно использовать данный смартфон в качестве устройства чтения карт для %1 в других устройствах, например в ноутбуке. + +Для этого сначала следует выполнить сопряжение данного устройства с этим смартфоном. - Start pairing + Card reader LABEL ANDROID IOS - Запустить сопряжение + Устройство чтения карт - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). + Paired Devices INFO ANDROID IOS - Введите код %1 в %2 на другом вашем устройстве, чтобы использовать смартфон в качестве устройства чтения карт (SaC). + Сопряженные устройства - - - RemoteServiceViewRemote - Paired devices + Pair new device LABEL ANDROID IOS - Сопряженные устройства + Выполнить сопряжение нового устройства - No device is paired. + Waiting for pairing LABEL ANDROID IOS - Нет сопряженных устройств. + Ожидание сопряжения - Click to remove device + Start pairing of a new device LABEL ANDROID IOS - Нажмите для удаления устройства + Начать сопряжение нового устройства + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Где следует вводить код сопряжения? + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введите код сопряжения %1 в поле %2 в другом вашем устройстве. + + + Cancel pairing + LABEL ANDROID IOS + Отменить сопряжение + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Разрешите подключение к сопряженным устройствам, чтобы использовать этот смартфон в качестве устройства чтения карт, а также для сопряжения с другим устройством. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Теперь сопряженные устройства могут использовать этот смартфон в качестве устройства чтения карт. + + + + RemoteServiceViewRemote Remove pairing INFO ANDROID IOS @@ -3761,16 +3822,6 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS Удалить - - Available devices - LABEL ANDROID IOS - Доступные устройства - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Нет доступных сопряженных смартфонов, используемых как устройство чтения карт (SaC). Убедитесь в том, что смартфон активирован в AusweisApp2 на другом устройстве в качестве устройства чтения карт (SaC) и оба устройства подключены к одной сети Wi-Fi. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3782,63 +3833,66 @@ If you have not already paired a device, start the pairing now to set up this sm Активировать Wi-Fi - Click to pair + Pairing code LABEL ANDROID IOS - Нажмите для сопряжения + Код сопряжения - Pairing mode - INFO ANDROID IOS - Режим сопряжения + Add pairing + LABEL ANDROID IOS + Добавить сопряжение - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустите режим сопряжения на смартфоне, если вы еще не сделали это. + Click to remove device + LABEL ANDROID IOS + Нажмите для удаления устройства - Pairing code + Last connected LABEL ANDROID IOS - Код сопряжения + Последние подключенные + + + Available + LABEL ANDROID IOS + Доступно + + + Paired devices + LABEL ANDROID IOS + Сопряженные устройства + + + Click to pair + LABEL ANDROID IOS + Нажмите для сопряжения - RemoteWorkflow + RemoteServiceWifiInfo - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Оба устройства должны быть подключены к одной сети Wi-Fi. + + + RemoteWorkflow Enable WiFi LABEL ANDROID IOS Активировать Wi-Fi - - Pair device - LABEL ANDROID IOS - Выполнить сопряжение устройства - To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Для использования удаленной службы необходимо активировать Wi-Fi. Активируйте Wi-Fi в настройках устройства. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC), с активированной удаленной службой. - Wifi disabled LABEL ANDROID IOS Wi-Fi деактивирован - - Waiting for connection - LABEL ANDROID IOS - Ожидание соединения - Determine card LABEL ANDROID IOS @@ -3854,6 +3908,21 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Подключено к %1. Разместите интерфейс NFC смартфона на идентификационной карте. + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + + + No smartphone as card reader connected + LABEL ANDROID IOS + Смартфон в качестве устройства чтения карт не подключен + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Разрешите подключение к сопряженному смартфону или выполните сопряжение нового смартфона. + ResultErrorView @@ -4248,16 +4317,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Ввести PIN-код на этом устройстве - - Remote card reader - LABEL ANDROID IOS - Удаленное устройство чтения карт - - - Configure remote service for another device - LABEL ANDROID IOS - Сконфигурировать удаленную службу для другого устройства - Save history LABEL ANDROID IOS @@ -4375,6 +4434,26 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Файл журнала, созданный 15 дней назад + + Show requested rights on this device as well + LABEL ANDROID IOS + Показывать запрошенные права также и в этом устройстве + + + Show access rights + LABEL ANDROID IOS + Показывать права доступа + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Управление сопряженными устройствами и добавление новых устройств + + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + SetupAssistantView @@ -4758,6 +4837,15 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Continue Продолжить + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. + +Для продолжения используйте вашу идентификационную карту, выбрав интерфейс NFC. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. + StoreFeedbackPopup @@ -5015,7 +5103,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& App on Android smartphone <b>with</b> NFC chip as card reader - Приложение на смартфоне с ОС Android <b>с</b> чипсетом NFC в качестве устройства чтения карт + Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт Smartphone as card reader tutorial @@ -5158,7 +5246,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& You can read our <b>FAQs</b> or <b>write</b> to us... LABEL ANDROID IOS - Прочитайте раздел <b>Часто задаваемые вопросы</b> или <b>напишите</b> нам… + Прочитайте раздел «Часто задаваемые вопросы» или <b>напишите</b> нам… or @@ -5204,7 +5292,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& App on Android smartphone <b>with</b> NFC chip as card reader LABEL ANDROID - Приложение на смартфоне с ОС Android <b>с</b> чипсетом NFC в качестве устройства чтения карт + Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт Click link on the website of the provider. @@ -5325,9 +5413,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Оба устройства должны быть подключены к одной сети Wi-Fi. - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… Now @@ -5335,9 +5423,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& сейчас - Start pairing + Pair device LABEL ANDROID IOS - Запустить сопряжение + Выполнить сопряжение устройства Pairing code @@ -5362,7 +5450,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Select the <b>Smartphone as card reader</b> tab. LABEL ANDROID IOS - Выберите вкладку <b>Смартфон в качестве устройства чтения карт</b>. + Выберите вкладку «Смартфон в качестве устройства чтения карт». Select smartphone from list @@ -5483,9 +5571,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Оба устройства должны быть подключены к одной сети Wi-Fi. - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… Now @@ -5493,9 +5581,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& сейчас - Start pairing + Pair device LABEL ANDROID IOS - Запустить сопряжение + Выполнить сопряжение устройства Pairing code @@ -5513,19 +5601,19 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& При первом использовании смартфона в качестве устройства чтения карт (SaC) iOS запрашивает разрешение на доступ к локальной сети. Разрешение необходимо, чтобы обнаружить ваш SaC и подключиться к нему. После первого запроса вы всегда можете отменить разрешение в настройках iOS для этого приложения. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите <b>Сконфигурировать удаленную службу</b>. + Теперь откройте приложение AusweisApp2 в своем устройстве <b>без</b> NFC и выберите меню «Управление сопряжениями». Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. LABEL ANDROID - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите <b>Смартфон в качестве устройства чтения карт</b>. + Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите «Смартфон в качестве устройства чтения карт». Now select <b>Settings</b>. LABEL ANDROID IOS - Далее выберите <b>Настройки</b>. + Далее выберите «Настройки». Choose smartphone from list @@ -5681,7 +5769,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& On every authentication you get displayed <b>who</b> wants to access <b>which</b> data LABEL ANDROID IOS - При каждой аутентификации отображается, <b>кто</b> и к <b>каким</b> данным запрашивает доступ, + При каждой аутентификации отображается, <b>кто</b> и к <b>каким</b> данным запрашивает доступ. and you consent to the request with your six-digit PIN. @@ -5925,6 +6013,24 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Ссылка для контрольной суммы: + + Utils + + today + LABEL ALL_PLATFORMS + сегодня + + + yesterday + LABEL ALL_PLATFORMS + вчера + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy + + VersionInformation @@ -6318,7 +6424,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy г., hh:mm:ss @@ -6528,8 +6634,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp - дд.ММ.гггг, чч:мм:сс + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy, hh:mm:ss Last connection: %1 @@ -6793,9 +6899,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Сбой аутентификации. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Размер данных, отправленных на идентификационную карту, не был принят. Либо данные неверны, либо ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. No certificate description available. @@ -7095,7 +7201,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::HistoryModelSearchFilter dd.MM.yyyy - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -7147,6 +7254,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm:ss + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy, hh:mm:ss @@ -7206,7 +7314,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::NotificationModel hh:mm:ss - чч:мм:сс + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + hh:mm:ss @@ -7277,7 +7386,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security. LABEL ALL_PLATFORMS - AusweisApp2 является продуктом компании Governikus GmbH & Co. KG — по заказу Федерального управления по информационной безопасности. + AusweisApp2 является продуктом компании Governikus GmbH Co. KG — по заказу Федерального управления по информационной безопасности. For further information, please see %1 @@ -7299,7 +7408,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7324,12 +7433,12 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy - LABEL ALL_PLATFORMS - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm @@ -7475,6 +7584,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm:ss @@ -7530,11 +7640,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ALL_PLATFORMS Сопряжено, но не поддерживается - - Paired, but unavailable - LABEL ALL_PLATFORMS - Сопряжено, но недоступно - Unsupported LABEL ALL_PLATFORMS @@ -7547,6 +7652,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7559,6 +7665,16 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC). Убедитесь в том, что удаленная служба активирована на вашем смартфоне и оба устройства подключены к одной сети Wi-Fi. Подробную информацию об использовании см. здесь: %1. + + Unavailable + LABEL ALL_PLATFORMS + Недоступно + + + Click to pair + LABEL ALL_PLATFORMS + Нажмите для сопряжения + governikus::RemoteServiceModel @@ -7590,6 +7706,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). Активируйте NFC, чтобы использовать смартфон в качестве устройства чтения карт (SaC). + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Сопряжение с %1 выполнено успешно. + governikus::RemoteServiceSettings @@ -7613,15 +7734,18 @@ Please enable NFC to use your smartphone as a card reader (SaC). dd.MM.yyyy - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy xx.MM.yyyy - хх.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day + xx.MM.yyyy xx.xx.yyyy - хх.хх.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month + xx.xx.yyyy Family name @@ -7763,6 +7887,14 @@ Please enable NFC to use your smartphone as a card reader (SaC). Доступ отклонен. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Защищенный канал открыт + + governikus::StateFinalizePersonalization @@ -8096,7 +8228,7 @@ Please enable NFC to use your smartphone as a card reader (SaC). The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. - Программа по-прежнему доступна через значок на панели задач. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. + Программа по-прежнему доступна через значок в строке меню. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. diff --git a/resources/translations/ausweisapp2_uk.ts b/resources/translations/ausweisapp2_uk.ts index b701b72b8..4fdae1f4e 100644 --- a/resources/translations/ausweisapp2_uk.ts +++ b/resources/translations/ausweisapp2_uk.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ LABEL ANDROID IOS A11y button to confirm the PIN and start the provider authenti Do you know your six-digit ID card PIN? Ви знаєте шестизначний PIN-код своєї ID-картки? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Ви тричі ввели неправильний шестизначний PIN-код ID-картки. Тепер PIN-код вашої ID-картки заблоковано. Щоб видалити блокування, потрібно спочатку ввести десятизначний PUK-код. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + ChangePinViewContent @@ -504,11 +514,21 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL ALL_PLATFORMS Якого типу ваш PIN-код? + + Six-digit PIN + LABEL ALL_PLATFORMS + Шестизначний PIN-код + Set by yourself LABEL ALL_PLATFORMS Встановлений вами самостійно + + Five-digit Transport PIN + LABEL ALL_PLATFORMS + П’ятизначний транспортний PIN-код + Received by mail in PIN letter LABEL ALL_PLATFORMS @@ -524,16 +544,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL ALL_PLATFORMS Загубили, забули або ніколи його не отримували - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значний PIN-код - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значний транспортний PIN-код - CheckConnectivityView @@ -665,7 +675,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію онлайн-ідентифікації.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію eID.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. Open website @@ -695,7 +705,7 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не впливає на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. ID card access failed @@ -984,10 +994,6 @@ INFO ANDROID IOS The ID card has just been unblocked and the user can now contin LABEL DESKTOP Створення пари з пристроєм… - - The device "%1" has been paired. - Пару з пристроєм «%1» створено. - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. @@ -1468,11 +1474,6 @@ INFO ANDROID IOS A new six-digit ID card PIN needs to be supplied. Підтвердьте новий шестизначний PIN-код ID-картки. - - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Щоб використовувати смартфон як пристрій читання карток (SaC), почніть на ньому створення пари та введіть показаний на його екрані код створення пари. - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS LABEL ANDROID IOS Надіслати PIN-код ID-картки + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Введіть код створення пари, який відображається на вашому смартфоні. + GProgressBar @@ -1685,11 +1691,6 @@ LABEL ANDROID IOS GeneralWorkflow - - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. - Attempts LABEL DESKTOP @@ -1753,6 +1754,11 @@ LABEL ANDROID IOS INFO DESKTOP Перейти до параметрів пристрою читання + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + Hint @@ -1765,20 +1771,8 @@ LABEL ANDROID IOS HistoryListItem Click to view details of history entry. - Натисніть, щоб переглянути відомості про запис в історії. - - - today LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр + Натисніть, щоб переглянути відомості про запис в історії. Tap for more details @@ -1859,18 +1853,6 @@ LABEL ANDROID IOS LABEL DESKTOP Пошук в історії - - today - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр - Clear history LABEL DESKTOP @@ -1959,7 +1941,10 @@ LABEL ANDROID IOS dd.MM.yyyy - дд.ММ.рррр + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy Write access (update) @@ -2052,16 +2037,16 @@ LABEL ANDROID IOS LocalNetworkInfo - - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Щоб мати можливість використовувати свій смартфон як пристрій читання карток (SaC), переконайтеся, що доступ до локальної мережі дозволено. - Go to application settings INFO IOS Link to application settings Перейти до параметрів програми + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Переконайтеся, що доступ до локальної мережі дозволено. + LogTitleBarControls @@ -2163,20 +2148,20 @@ INFO ANDROID IOS The current logfile is about to be removed, user confirmation r LABEL ANDROID IOS Фільтр - - Currently there are no log entries matching your filter. - INFO ANDROID IOS No log entries, placeholder text. - Наразі немає жодних записів журналу, що відповідають цьому фільтру. - Level LABEL ANDROID IOS - Рівень + Рівень Category LABEL ANDROID IOS - Категорію + Категорія + + + Currently there are no log entries matching your filter. + INFO ANDROID IOS No log entries, placeholder text. + Наразі немає жодних записів журналу, що відповідають цьому фільтру. @@ -2576,10 +2561,6 @@ LABEL ANDROID IOS Provider Постачальник - - Remote - Віддалений доступ - Settings Параметри @@ -2588,6 +2569,10 @@ LABEL ANDROID IOS Help Довідка + + Card reader + Пристрій читання карток + NfcWorkflow @@ -2623,12 +2608,12 @@ LABEL ANDROID IOS NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Сканування NFC не виконується. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Почніть сканування NFC. @@ -2666,6 +2651,11 @@ LABEL ANDROID IOS INFO ANDROID The ID card may be inserted, the authentication process may be started. Покладіть ID-картку безпосередньо на задній бік пристрою.<br/><br/>Точне положення ID-картки залежить від пристрою. На анімації показано можливі положення. Утримуйте ID-картку в одному положенні кілька секунд, перш ніж спробувати інше, і не переміщайте її після встановлення контакту. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Пристрій «%1» намагається використовувати цей смартфон як пристрій читання карток і встановити з’єднання з вашою ID-карткою. + NumberField @@ -2727,6 +2717,52 @@ LABEL ANDROID IOS Вимкнено + + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Інформація про створення пари + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Відкрийте %1 на своєму %2іншому пристрої%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Перейдіть на тому пристрої до розділу %1Параметри%2, а тоді виберіть %1Смартфон як пристрій читання карток%2 і %1Керування створенням пари%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Виберіть цей смартфон у переліку, щоб створити з ним пару. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Виберіть на тому пристрої %1Пристрій читання карток%2, а тоді — %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + У наведеному тут переліку виберіть смартфон, щоб створити з ним пару. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. + + PasswordInfoContent @@ -2747,16 +2783,36 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Інформація про PIN-код + + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + PIN-код картки – це шестизначний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID. + Where can I find the card PIN? LABEL ALL_PLATFORMS Де я можу дізнатися PIN-код картки? + + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' + Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою п’ятизначного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення шестизначного PIN-коду. + How do I choose a secure PIN? LABEL ALL_PLATFORMS Як вибрати безпечний PIN-код? + + For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 + Для свого шестизначного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці. + + + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 + Ви можете змінювати свій шестизначний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код. + Keep your PIN secret and change it if another person becomes aware of it. INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 3/3 @@ -2772,6 +2828,16 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Інформація про транспортний PIN-код + + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 + П’ятизначний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки. + + + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 + Якщо ви не встановили самостійно обраний шестизначний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду. + Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 @@ -2802,6 +2868,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Інформація про PUK-код + + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' + PUK-код – це десятизначний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки. + Why is the PUK required? LABEL ALL_PLATFORMS @@ -2857,6 +2928,11 @@ LABEL ANDROID IOS LABEL ALL_PLATFORMS Де я можу дізнатися CAN-код картки? + + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' + CAN-код – це шестизначний номер, який можна знайти в нижній правій частині лицьового боку ID-картки. + The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). INFO ALL_PLATFORMS Description text of CAN-allowed authentication @@ -2889,6 +2965,11 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Ви не знаєте свій PIN-код? + + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? + INFO ALL_PLATFORMS + Ви ще не встановили шестизначний PIN-код картки й не можете знайти лист із транспортним PIN-кодом? + You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS @@ -2904,105 +2985,60 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Типи PIN-кодів - - This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 5/6 - Цей PIN-код дозволяє вам підтверджувати онлайн, що ID-картка належить саме вам. Без цього PIN-коду ніхто не зможе скористатися вашою ID-карткою в Інтернеті. - - - You can use the PIN Reset Service to request a new card PIN free of charge. - LABEL ALL_PLATFORMS - Ви можете скористатися службою скидання PIN-коду, щоб безкоштовно надіслати запит на новий PIN-код картки. - - - If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. - LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. - Якщо ви не знаєте ні транспортний PIN-код, ні PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. - - - If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. - LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. - Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. - - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код картки – це 6-значний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID. - - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою 5-значного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення 6-значного PIN-коду. - - - For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 - Для свого 6-значного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці. - - - You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - Ви можете змінювати свій 6-значний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код. - - - The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - 5-значний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки. - - - If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - Якщо ви не встановили самостійно обраний 6-значний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду. - - - The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - PUK-код – це 10-значний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки. - - - The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - CAN-код – це 6-значний номер, який можна знайти в нижній правій частині лицьового боку ID-картки. - Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. INFO ALL_PLATFORMS Description text explaining the PINs 1/6 - До вашої ID-картки додається 5-значний «транспортний PIN-код», який вам потрібно змінити на 6-значний PIN-код, який ви обираєте самостійно. + До вашої ID-картки додається п’ятизначний « PIN-код», який вам потрібно змінити на шестизначний PIN-код, який ви обираєте самостійно. Five-digit Transport PIN LABEL ALL_PLATFORMS - 5-значний транспортний PIN-код + П’ятизначний транспортний PIN-код The five-digit Transport PIN was sent to you by post after you applied for your ID card. INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - 5-значний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. + П’ятизначний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей 5-значний PIN-код на 6-значний PIN-код, який ви оберете самостійно. + Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей п’ятизначний PIN-код на шестизначний PIN-код, який ви оберете самостійно. Six-digit PIN LABEL ALL_PLATFORMS - 6-значний PIN-код + Шестизначний PIN-код This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш 5-значний транспортний PIN-код. + Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш п’ятизначний транспортний PIN-код. + + + This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 5/6 + Цей PIN-код дозволяє вам підтверджувати онлайн, що ID-картка належить саме вам. Без цього PIN-коду ніхто не зможе скористатися вашою ID-карткою в Інтернеті. You can change your six-digit PIN at any time in AusweisApp2. INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Ви можете в будь-який момент змінити свій 6-значний PIN-код у додатку AusweisApp2. + Ви можете в будь-який момент змінити свій шестизначний PIN-код у додатку AusweisApp2. - You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? - INFO ALL_PLATFORMS - Ви ще не встановили 6-значний PIN-код картки й не можете знайти лист із транспортним PIN-кодом? + You can use the PIN Reset Service to request a new card PIN free of charge. + LABEL ALL_PLATFORMS + Ви можете скористатися службою скидання PIN-коду, щоб безкоштовно надіслати запит на новий PIN-код картки. + + + If you do not know either your Transport PIN or your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for requested Transport PIN but both, Transport PIN and PIN, are not known. + Якщо ви не знаєте ні транспортний PIN-код, ні PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. + + + If you have forgotten your card PIN, you can request a new PIN free of charge using the PIN Reset Service. + LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. + Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. @@ -3315,19 +3351,6 @@ INFO ANDROID_TABLET IOS_TABLET No authentication history, placeholder text. ProviderDetailHistoryItem - - today - LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр - Service: LABEL DESKTOP @@ -3590,10 +3613,6 @@ LABEL ANDROID IOS Press space to pair the smartphone "%1". Натисніть пробіл, щоб створити пару зі смартфоном «%1». - - Click to pair - Натисніть, щоб створити пару - Remove remote device Видаліть віддалений пристрій @@ -3602,38 +3621,70 @@ LABEL ANDROID IOS RemoteReaderView - Paired remote devices - З’єднані віддалені пристрої + Paired devices + З’єднані пристрої - Available remote devices - Доступні віддалені пристрої + Add pairing + Додавання пари - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Тут відображаються лише пристрої, які вже з’єднано або підключено до однієї мережі Wi-Fi і для яких увімкнено віддалену службу. + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. - More information - LABEL DESKTOP - Додаткова інформація + Both devices have to be connected to the same WiFi. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Перейдіть на тому пристрої до розділу %1Пристрій читання карток%2, а тоді виберіть %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Виберіть пристрій у переліку, щоб створити з ним пару. + + + Last connected + Останнє з’єднання + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. - RemoteServiceSettings + RemoteServiceController - Configure remote service + You are about to identify yourself towards the following provider using the device "%1": LABEL ANDROID IOS - Налаштувати віддалену службу + Ви збираєтеся ідентифікувати себе за допомогою пристрою «%1» для такого постачальника: + + + Card reader + LABEL ANDROID IOS + Пристрій читання карток - - - RemoteServiceView Remote service LABEL ANDROID IOS Віддалена служба + + + RemoteServiceSettings + + Manage pairings + LABEL ANDROID IOS + Керування створенням пари + + + + RemoteServiceView Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3664,35 +3715,16 @@ LABEL ANDROID IOS LABEL ANDROID IOS Очікування підключення - - Remote service ready - LABEL ANDROID IOS - Віддалена служба готова - Waiting for connection from a paired device... INFO ANDROID IOS Очікування підключення від пристрою, з яким створено пару… - - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). - -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. - INFO ANDROID IOS - Запустіть віддалений доступ, щоб зробити цей смартфон видимим і використовувати його як пристрій читання карток (SaC). - -Якщо ви ще не створили пару для пристрою, почніть створення пари зараз, щоб налаштувати цей смартфон як пристрій читання карток. - Pairing code: <b>%1</b> LABEL ANDROID IOS Код створення пари: <b>%1</b> - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Обидва ваші пристрої має бути підключено до однієї мережі Wi-Fi. - Enable WiFi LABEL ANDROID IOS @@ -3704,48 +3736,77 @@ If you have not already paired a device, start the pairing now to set up this sm Увімкнути NFC - Stop remote service + Pair device LABEL ANDROID IOS - Зупинити віддалену службу + Створити пару з пристроєм - Start remote service + Allow connection LABEL ANDROID IOS - Запустити віддалену службу + Дозволити з’єднання - Stop pairing - LABEL ANDROID IOS - Зупинити створення пари + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. + +To do this you first have to pair that device with this smartphone. + INFO ANDROID IOS + Ви можете використовувати цей смартфон як пристрій читання карток для %1 на інших пристроях, наприклад, на ноутбуці. + +Для цього вам потрібно спочатку створити пару між таким пристроєм і цим смартфоном. - Start pairing + Card reader LABEL ANDROID IOS - Почати створення пари + Пристрій читання карток - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). + Paired Devices INFO ANDROID IOS - Введіть код %1 у %2 на своєму іншому пристрої, щоб використовувати свій смартфон як пристрій читання карток (SaC). + З’єднані пристрої - - - RemoteServiceViewRemote - Paired devices + Pair new device LABEL ANDROID IOS - З’єднані пристрої + Створення пари з новим пристроєм - No device is paired. + Waiting for pairing LABEL ANDROID IOS - Із жодним пристроєм не створено пару. + Очікування на створення пари - Click to remove device + Start pairing of a new device LABEL ANDROID IOS - Натисніть, щоб видалити пристрій + Почати створення пари з новим пристроєм + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Куди вводити код створення пари? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введіть код створення пари %1 у %2 на своєму іншому пристрої. + + + Cancel pairing + LABEL ANDROID IOS + Скасувати створення пари + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Надайте дозвіл на встановлення зв’язку зі з’єднаними пристроями, щоб використовувати цей смартфон як пристрій читання карток або створити пару з іншим пристроєм. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Тепер з’єднані пристрої можуть використовувати цей смартфон як пристрій читання карток. + + + RemoteServiceViewRemote Remove pairing INFO ANDROID IOS @@ -3761,16 +3822,6 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS Видалити - - Available devices - LABEL ANDROID IOS - Доступні пристрої - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC). Переконайтеся, що функцію смартфона як пристрою для читання карток (SaC) активовано в програмі AusweisApp2 на вашому іншому пристрої і що обидва пристрої підключено до однієї мережі Wi-Fi. - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. @@ -3782,63 +3833,66 @@ If you have not already paired a device, start the pairing now to set up this sm Увімкнути Wi-Fi - Click to pair + Pairing code LABEL ANDROID IOS - Натисніть, щоб створити пару + Код створення пари - Pairing mode - INFO ANDROID IOS - Режим створення пари + Add pairing + LABEL ANDROID IOS + Додавання пари - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустіть режим створення пари на своєму смартфоні, якщо ви ще цього не зробили. + Click to remove device + LABEL ANDROID IOS + Натисніть, щоб видалити пристрій - Pairing code + Last connected LABEL ANDROID IOS - Код створення пари + Останнє з’єднання + + + Available + LABEL ANDROID IOS + Доступно + + + Paired devices + LABEL ANDROID IOS + З’єднані пристрої + + + Click to pair + LABEL ANDROID IOS + Натисніть, щоб створити пару - RemoteWorkflow + RemoteServiceWifiInfo - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. + + + RemoteWorkflow Enable WiFi LABEL ANDROID IOS Увімкнути Wi-Fi - - Pair device - LABEL ANDROID IOS - Створити пару з пристроєм - To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. INFO ANDROID IOS The WiFi module needs to be enabled in the system settings to use the remote service. Для використання віддаленої служби має бути активовано Wi-Fi. Активуйте Wi-Fi у параметрах пристрою. - - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC) з активованою «віддаленою службою». - Wifi disabled LABEL ANDROID IOS Wi-Fi вимкнено - - Waiting for connection - LABEL ANDROID IOS - Очікування підключення - Determine card LABEL ANDROID IOS @@ -3854,6 +3908,21 @@ If you have not already paired a device, start the pairing now to set up this sm INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Підключено до %1. Розташуйте інтерфейс NFC смартфона на своїй ID-картці. + + Manage pairings + LABEL ANDROID IOS + Керування створенням пари + + + No smartphone as card reader connected + LABEL ANDROID IOS + Не з’єднано жоден смартфон як пристрій читання карток + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Надайте дозвіл на встановлення зв’язку на з’єднаному смартфоні або створіть пару з новим смартфоном. + ResultErrorView @@ -4248,16 +4317,6 @@ LABEL ANDROID IOS LABEL ANDROID IOS Введіть PIN-код на цьому пристрої - - Remote card reader - LABEL ANDROID IOS - Віддалений пристрій читання карток - - - Configure remote service for another device - LABEL ANDROID IOS - Налаштувати віддалену службу для іншого пристрою - Save history LABEL ANDROID IOS @@ -4375,6 +4434,26 @@ LABEL ALL_PLATFORMS LABEL ALL_PLATFORMS Файл журналу строком 15 днів + + Show requested rights on this device as well + LABEL ANDROID IOS + Показати запит на права також на цьому пристрої + + + Show access rights + LABEL ANDROID IOS + Показати права доступу + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Керування з’єднаними пристроями й додавання нових пристроїв + + + Manage pairings + LABEL ANDROID IOS + Керування створенням пари + SetupAssistantView @@ -4758,6 +4837,15 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Continue Продовжити + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Ви ще не налаштували Smart-eID або він більше не придатний для використання. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. + StoreFeedbackPopup @@ -5158,7 +5246,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& You can read our <b>FAQs</b> or <b>write</b> to us... LABEL ANDROID IOS - Ознайомтеся з розділом <b>«Запитання й відповіді»</b> або <b>напишіть</b> нам… + Ознайомтеся з розділом «Запитання й відповіді» або <b>напишіть</b> нам… or @@ -5325,9 +5413,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Обидва пристрої має бути підключено до однієї мережі Wi-Fi - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… + Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… Now @@ -5335,9 +5423,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Зараз - Start pairing + Pair device LABEL ANDROID IOS - Почати створення пари + Створити пару з пристроєм Pairing code @@ -5362,7 +5450,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Select the <b>Smartphone as card reader</b> tab. LABEL ANDROID IOS - Виберіть вкладку <b>Смартфон як пристрій читання карток</b>. + Виберіть вкладку «Смартфон як пристрій читання карток». Select smartphone from list @@ -5475,7 +5563,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. LABEL ANDROID IOS - Установіть програму AusweisApp2 на пристрої без NFC <b>та</b> смартфоні з функцією NFC. + Установіть програму AusweisApp2 на пристрої <b>без</b> NFC та смартфоні з функцією NFC. Both devices have to be connected to the same WiFi network @@ -5483,9 +5571,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Обидва пристрої має бути підключено до однієї мережі Wi-Fi - Now choose "Remote" in the AusweisApp2 on your smartphone... + Now choose "Card reader" in the AusweisApp2 on your smartphone... LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… + Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… Now @@ -5493,9 +5581,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Зараз - Start pairing + Pair device LABEL ANDROID IOS - Почати створення пари + Створити пару з пристроєм Pairing code @@ -5513,19 +5601,19 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Під час першого використання смартфона як пристрою читання карток (SaC) iOS запитає вашого дозволу на доступ до локальної мережі. Цей дозвіл потрібен для пошуку вашого SaC та підключення до нього. Після першого запиту ви завжди можете отримати доступ до дозволу в параметрах iOS для цієї програми. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть <b>Налаштувати віддалену службу</b>. + Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Керування створенням пари». Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. LABEL ANDROID - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть <b>Смартфон як пристрій читання карток</b>. + Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Смартфон як пристрій читання карток». Now select <b>Settings</b>. LABEL ANDROID IOS - Тепер виберіть <b>Параметри</b>. + Тепер виберіть «Параметри». Choose smartphone from list @@ -5681,7 +5769,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& On every authentication you get displayed <b>who</b> wants to access <b>which</b> data LABEL ANDROID IOS - Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних, + Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних. and you consent to the request with your six-digit PIN. @@ -5744,7 +5832,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. LABEL ANDROID IOS - Служба <b>вбудованої самоавтентифікації</b> – це спеціальна служба для перегляду даних, збережених на ID-картці. + <b>Служба вбудованої самоавтентифікації</b> – це спеціальна служба для перегляду даних, збережених на ID-картці. And this is how it works @@ -5925,6 +6013,24 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Посилання на контрольну суму: + + Utils + + today + LABEL ALL_PLATFORMS + сьогодні + + + yesterday + LABEL ALL_PLATFORMS + вчора + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy + + VersionInformation @@ -6318,7 +6424,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy р., hh:mm:ss @@ -6528,8 +6634,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp - дд.ММ.рррр, гг:хх:сс + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy, hh:mm:ss Last connection: %1 @@ -6793,9 +6899,9 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& Не вдалося виконати автентифікацію. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Довжину даних, надісланих на ID-картку, відхилено. Дані неправильні або ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. No certificate description available. @@ -7095,7 +7201,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::HistoryModelSearchFilter dd.MM.yyyy - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -7147,7 +7254,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm:ss - дд.ММ.рррр гг:хх:сс + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy hh:mm:ss The logfile is disabled. @@ -7206,7 +7314,8 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& governikus::NotificationModel hh:mm:ss - гг:хх:сс + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + hh:mm:ss @@ -7299,7 +7408,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7324,12 +7433,12 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy - LABEL ALL_PLATFORMS - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm @@ -7475,6 +7584,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm:ss @@ -7530,11 +7640,6 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& LABEL ALL_PLATFORMS З’єднаний, але не підтримується - - Paired, but unavailable - LABEL ALL_PLATFORMS - З’єднаний, але недоступний - Unsupported LABEL ALL_PLATFORMS @@ -7547,6 +7652,7 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7559,6 +7665,16 @@ To proceed use your ID card by selecting the NFC interface or choose "WiFi& INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Немає жодного смартфона як пристрою читання карток (SaC). Переконайтеся, що ви активували «віддалену службу» на своєму смартфоні та підключили обидва пристрої до однієї мережі Wi-Fi. Відомості про використання див. в розділі %1. + + Unavailable + LABEL ALL_PLATFORMS + Недоступно + + + Click to pair + LABEL ALL_PLATFORMS + Натисніть, щоб створити пару + governikus::RemoteServiceModel @@ -7590,6 +7706,11 @@ Please enable NFC to use your smartphone as a card reader (SaC). Увімкніть NFC, щоб використовувати свій смартфон як пристрій читання карток (SaC). + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Створено пару з %1. + governikus::RemoteServiceSettings @@ -7613,15 +7734,18 @@ Please enable NFC to use your smartphone as a card reader (SaC). dd.MM.yyyy - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy xx.MM.yyyy - xx.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day + xx.MM.yyyy xx.xx.yyyy - xx.xx.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month + xx.xx.yyyy Family name @@ -7763,6 +7887,14 @@ Please enable NFC to use your smartphone as a card reader (SaC). Немає доступу. + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Захищений канал відкрито + + governikus::StateFinalizePersonalization @@ -8096,7 +8228,7 @@ Please enable NFC to use your smartphone as a card reader (SaC). The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. - Програма залишається доступною через піктограму в системному лотку. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. + Програма залишається доступною через піктограму на панелі меню. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. diff --git a/resources/updatable-files/supported-providers.json b/resources/updatable-files/supported-providers.json index 132632cb1..5ed26ee79 100644 --- a/resources/updatable-files/supported-providers.json +++ b/resources/updatable-files/supported-providers.json @@ -219,18 +219,16 @@ "": "Auskunft aus den Zentralen Registern des Kraftfahrt-Bundesamtes" }, "longDescription": { - "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
  • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ereignissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
  • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
  • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
  • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
" + "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
  • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
  • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ergebnissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
  • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
  • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
" }, - "address": "https://www.kba-online.de/registerauskunft/ora/web", + "address": "https://www.kba-online.de/registerauskunft/app", "homepage": "https://www.kba.de", "phone": "+49 461 316 0", "email": "kba@kba.de", "postalAddress": "Kraftfahrt-Bundesamt
Fördestraße 16
24944 Flensburg", - "icon": "KraftfahrtBundesamt_icon.png", + "icon": "KraftfahrtBundesamt_icon.svg", "category": "citizen", - "subjectUrls": [ - "https://www.kba-online.de" - ] + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -289,9 +287,7 @@ "postalAddress": "Ministerium für Wissenschaft, Energie, Klimaschutz und Umwelt des Landes Sachsen-Anhalt
Leipziger Straße 58
39112 Magdeburg", "icon": "BafoegDigital_icon.svg", "category": "citizen", - "subjectUrls": [ - "https://id.bund.de" - ] + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -461,24 +457,6 @@ "category": "citizen", "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." }, - { - "shortName": { - "": "Stadt Magdeburg - iKFZ" - }, - "longName": { - "": "Stadt Magdeburg - Internetbasierte Fahrzeugzulassung" - }, - "longDescription": { - "": "Die internetbasierte Außerbetriebsetzung und Wiederzulassung eines Kraftfahrzeuges können über das Portal der Landeshauptstadt Magdeburg beantragt werden." - }, - "address": "https://www.magdeburg.de/loadDocument.phtml?ObjSvrID=37&ObjID=27929", - "homepage": "https://www.magdeburg.de/Start/B%C3%BCrger-Stadt/Verwaltung-Service/B%C3%BCrgerService", - "phone": "+49 391 54 00", - "email": "info@magdeburg.de", - "postalAddress": "Landeshauptstadt Magdeburg
Alter Markt 6
39104 Magdeburg", - "category": "citizen", - "subjectUrlInfo": "Using service from Serviceportal Sachsen-Anhalt (https://bk.sachsen-anhalt-connect.de)" - }, { "shortName": { "": "Stadt Netphen" @@ -656,7 +634,8 @@ "category": "citizen", "subjectUrls": [ "https://www.buergerserviceportal.de", - "https://bayernid.freistaat.bayern" + "https://bayernid.freistaat.bayern", + "https://id.bayernportal.de" ] }, { @@ -2129,20 +2108,22 @@ }, { "shortName": { - "": "Online-Bürgerdienste Nürnberg" + "": "Mein Nürnberg" }, "longName": { - "": "Online-Bürgerdienste der Stadt Nürnberg" + "": "Mein Nürnberg - Die digitale Serviceplattform der Stadt Nürnberg" }, "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
" + "": "Über die Serviceplattform 'Mein Nürnberg' können Sie schnell, einfach und von zuhause aus Ihre Behördengänge erledigen! Kein langes Anstehen, Warten oder Nummer Ziehen. Mit einem persönlichen 'Mein Nürnberg'-Account bleiben Sie bequem zuhause und erledigen alles von dort - und das rund um die Uhr. Sie sparen sich nicht nur den Weg in die Behörde, sondern können auch den aktuellen Status Ihres Antrages einsehen. Melden Sie sich jetzt an! Das Angebot an Online-Diensten wird ständig erweitert. Ob Sie Ihr Anliegen bereits digital erledigen können, finden Sie über den Behördenwegweiser Nürnberg oder direkt über die Internetseiten der jeweiligen Ämter heraus." }, - "address": "https://www.nuernberg.de/internet/onlinedienste", - "homepage": "https://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", + "address": "https://www.nuernberg.de/internet/mein_nuernberg", + "homepage": "https://www.nuernberg.de/internet/stadtportal", + "phone": "+49 9 11 2 31 4 50 00", + "email": "online-services@stadt.nuernberg.de", + "postalAddress": "Stadt Nürnberg
Amt für Digitalisierung und Prozessorganisation Rathausplatz 2
90403 Nürnberg", "category": "citizen", + "image": "MeinNuernberg_image.jpg", + "icon": "MeinNuernberg_icon.png", "subjectUrls": [ "https://meinkonto.nuernberg.de" ] @@ -2345,6 +2326,159 @@ "subjectUrls": [ "https://www.foerderportal-zeus.de" ] + }, + { + "shortName": { + "": "Landkreis Elbe-Elster" + }, + "longName": { + "": "Landkreis Elbe-Elster - Online Dienste" + }, + "longDescription": { + "": "Bürgerinnen und Bürger im Landkreis Elbe-Elster können viele Behördengänge digital erledigen.
Je nach Anforderung der jeweiligen Verwaltungsleistung benötigen Sie ein kostenloses Bürgerkonto 'BundID'. Damit können Sie sich elektronisch identifizieren. Sie weisen sich also online gegenüber diesen Leistungen aus." + }, + "address": "https://www.lkee.de/Service-Verwaltung/Online-Dienste", + "homepage": "https://www.lkee.de", + "phone": "+49 3535 460", + "email": "eap@lkee.de", + "postalAddress": "Landkreis Elbe-Elster
Der Landrat
Ludwig-Jahn-Str. 2
04916 Herzberg / Elster", + "image": "lkee_image.jpg", + "icon": "lkee_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)." + }, + { + "shortName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longDescription": { + "": "Die Landeshauptstadt München verfügt über eine Vielzahl an Online-Services. Diese können Sie hier einsehen und nutzen." + }, + "address": "https://stadt.muenchen.de/infos/online-services.html", + "homepage": "https://www.muenchen.de", + "email": "rathaus@muenchen.de", + "postalAddress": "Landeshauptstadt München
80313 München", + "image": "LandeshauptstadtMuenchen_image.png", + "icon": "LandeshauptstadtMuenchen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longDescription": { + "": "Den Antrag auf Elterngeld können Sie in Bayern bei der Landesbehörde Zentrum Bayern Familie und Soziales (ZBFS) stellen. Die Abfragen im Online-Verfahren werden individuell auf Ihre Angaben abgestimmt und Sie erhalten eine Checkliste mit den benötigten Unterlagen. Der Antrag kann digital unterschieben werden." + }, + "address": "https://www.elterngeld.bayern.de/onlineantrag/default.aspx", + "homepage": "https://www.zbfs.bayern.de", + "email": "poststelle@zbfs.bayern.de", + "postalAddress": "Zentrum Bayern Familie und Soziales
95440 Bayreuth", + "icon": "ZBFS_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "bundID" + }, + "longName": { + "": "bundID - Ihr Zugang zur digitalen Verwaltung. Einfach. Sicher." + }, + "address": "https://id.bund.de", + "homepage": "https://id.bund.de", + "longDescription": { + "": " Die BundID bietet Ihnen ein zentrales Konto zur Identifizierung für alle Ihre Online-Anträge (z. B. mit einem Online-Ausweis). Sie können das Formular Ihres Online-Antrags durch das Hinterlegen Ihrer persönlichen Daten vorausfüllen lassen. Das spart Zeit, ist sicher und bewahrt Sie vor Tippfehlern.

Sie erhalten alle Bescheide und Nachrichten in Bezug auf den Online-Antrag bequem in Ihr elektronisches Postfach in Ihrem BundID-Konto." + }, + "postalAddress": "Bundesministerium des Innern und für Heimat
Alt-Moabit 140
10557 Berlin", + "category": "citizen", + "subjectUrls": [ + "https://id.bund.de" + ] + }, + { + "shortName": { + "": "Stadt Oberhausen" + }, + "longName": { + "": "Stadt Oberhausen" + }, + "address": "https://serviceportal.oberhausen.de/home", + "homepage": "https://www.oberhausen.de", + "email": "info@oberhausen.de", + "longDescription": { + "": "Im Serviceportal der Stadt Oberhausen finden Sie alle Online-Leistungen der Stadtverwaltung, von der Beantragung einer Personenstandsurkunde über die Anmeldung eines Autos bis zur Beantragung eines Bewohnerparkausweises. Einzelne Leistungen erfordern hierbei auch die Authentifizierung mit dem elektronischen Personalausweis und der AusweisApp2." + }, + "postalAddress": "Stadt Oberhausen
Schwartzstraße 72
46042 Oberhausen", + "icon": "StadtOberhausen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." + }, + { + "shortName": { + "": "Digitale Rentenübersicht" + }, + "longName": { + "": "Digitale Rentenübersicht - Zentrale Stelle für die Digitale Rentenübersicht (Deutsche Rentenversicherung Bund)" + }, + "address": "https://app.rentenuebersicht.de", + "homepage": "https://www.rentenuebersicht.de", + "phone": "+49 800 1000 787", + "email": "digitalerentenuebersicht@drv-bund.de", + "longDescription": { + "": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...
  • Ihre individuellen Altersvorsorge-Ansprüche der gesetzlichen, betrieblichen und privaten Altersvorsorge bequem digital abrufen und
  • die Informationen zum Stand Ihrer Altersvorsorge-Ansprüche als Grundlage für eine weitere unabhängige Beratung herunterladen.
" + }, + "postalAddress": "Deutsche Rentenversicherung Bund Zentrale Stelle für die Digitale Rentenübersicht
10868 Berlin", + "icon": "DigitaleRentenuebersicht_icon.svg", + "category": "citizen", + "subjectUrls": [ + "https://login.deutsche-rentenversicherung.de" + ] + }, + { + "shortName": { + "": "Zoll-Portal" + }, + "longName": { + "": "Zoll-Portal" + }, + "address": "https://www.zoll-portal.de", + "homepage": "https://www.zoll-portal.de", + "email": "Zoll-Portal@zoll.bund.de", + "longDescription": { + "": "Das Zoll-Portal bietet Ihnen einen einfachen und effizienten Zugang zu den Dienstleistungen des Zolls (z.B. Kraftfahrzeugsteuer, Agrardieselvergütung oder Energiesteuer). Nach einmaliger Registrierung können Sie Anträge online abwickeln und Bescheide rechtssicher abrufen. Verwenden Sie für die Registrierung und den Login Ihre Online-Ausweisfunktion und Sie können alle Dienstleistungen und Features uneingeschränkt in Anspruch nehmen." + }, + "postalAddress": "Generalzolldirektion
Am Propsthof 78a
53121 Bonn", + "icon": "ZollPortal_icon.svg", + "image": "ZollPortal_image.svg", + "category": "citizen", + "subjectUrls": [ + "https://www.zoll-portal.de" + ] + }, + { + "shortName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "longName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "address": "https://www.augsburg.de/online-services", + "homepage": "https://www.augsburg.de", + "email": "augsburg@augsburg.de", + "longDescription": { + "": "Für viele Leistungen ist der Weg ins Amt nicht nötig: Sie können zahlreiche Leistungen online beantragen und falls nötig bequem von zu Hause aus bezahlen. Eine Liste der Online-Services finden Sie auf der Webseite der Stadt Augsburg.

Voraussetzung für einige Online-Services ist die BayernID. Zur Registrierung können Sie Ihren Online-Ausweis mit dazugehöriger PIN, einem geeigneten Smartphone oder Tablet und der installierten AusweisApp2 nutzen.

Informationen zur Registrierung in der BayernID können Sie nachlesen (https://id.bayernportal.de/).

Ein Beispiel ist die internetbasierte Fahrzeugzulassung und Fahrzeugabmeldung, die von der Kfz-Zulassungsbehörde in Augsburg angeboten wird. Weitere Informationen finden Sie auf der Internetseite der Online-Zulassungsbehörde." + }, + "postalAddress": "Stadt Augsburg
Rathausplatz 1
86150 Augsburg", + "icon": "StadtAugsburg_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." } ] } diff --git a/src/android/MainActivity.java b/src/android/MainActivity.java index b4d2d6002..4ad65b3e6 100644 --- a/src/android/MainActivity.java +++ b/src/android/MainActivity.java @@ -207,11 +207,22 @@ public static boolean isStartedByAuth() } + private void convertChromeOsIntent(Intent pIntent) + { + if (pIntent != null && pIntent.getAction().equals("org.chromium.arc.intent.action.VIEW")) + { + LogHandler.getLogger().info("Convert Intent action " + pIntent.getAction() + " to " + Intent.ACTION_VIEW); + pIntent.setAction(Intent.ACTION_VIEW); + } + } + + @Override public void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppTheme); + convertChromeOsIntent(getIntent()); LogHandler.getLogger().info("onCreate: " + getIntent()); super.onCreate(savedInstanceState); @@ -256,6 +267,7 @@ public void onCreate(Bundle savedInstanceState) @Override protected void onNewIntent(Intent newIntent) { + convertChromeOsIntent(newIntent); cIntent = newIntent; setIntent(newIntent); LogHandler.getLogger().info("onNewIntent: " + newIntent); diff --git a/src/card/base/CardConnectionWorker.cpp b/src/card/base/CardConnectionWorker.cpp index bb159fecb..37aaa89db 100644 --- a/src/card/base/CardConnectionWorker.cpp +++ b/src/card/base/CardConnectionWorker.cpp @@ -133,7 +133,7 @@ ResponseApduResult CardConnectionWorker::transmit(const CommandApdu& pCommandApd ResponseApduResult result = card->transmit(commandApdu); if (result.mResponseApdu.getStatusCode() == StatusCode::WRONG_LENGTH) { - return {CardReturnCode::EXTENDED_LENGTH_MISSING}; + return {CardReturnCode::WRONG_LENGTH}; } if (mSecureMessaging) @@ -141,7 +141,7 @@ ResponseApduResult CardConnectionWorker::transmit(const CommandApdu& pCommandApd result.mResponseApdu = mSecureMessaging->decrypt(result.mResponseApdu); if (result.mResponseApdu.isEmpty()) { - qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must no be re-used."; + qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must not be re-used."; stopSecureMessaging(); return {CardReturnCode::COMMAND_FAILED}; diff --git a/src/card/base/apdu/CommandApdu.cpp b/src/card/base/apdu/CommandApdu.cpp index 7ad0b9b28..24b3e56dd 100644 --- a/src/card/base/apdu/CommandApdu.cpp +++ b/src/card/base/apdu/CommandApdu.cpp @@ -13,13 +13,6 @@ using namespace governikus; Q_DECLARE_LOGGING_CATEGORY(card) -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - - constexpr std::byte CLA {0x00}; constexpr std::byte CLA_PROPRIETARY {0x80}; constexpr std::byte CLA_COMMAND_CHAINING {0x10}; @@ -128,12 +121,12 @@ CommandApdu::CommandApdu(const QByteArray& pHeader, const QByteArray& pData, int if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -148,12 +141,12 @@ CommandApdu::CommandApdu(Ins pIns, uchar pP1, uchar pP2, const QByteArray& pData { if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -210,7 +203,7 @@ Ins CommandApdu::getINS() const return Ins(mIns); } - qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << HEX << mIns; + qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << Qt::hex << mIns; return Ins::UNKNOWN; } diff --git a/src/card/base/command/DidAuthenticateEAC2Command.cpp b/src/card/base/command/DidAuthenticateEAC2Command.cpp index b4936f8c0..cea6160e8 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC2Command.cpp @@ -190,7 +190,7 @@ CardReturnCode DidAuthenticateEAC2Command::putCertificateChain(const CVCertifica break; case StatusCode::WRONG_LENGTH: - return CardReturnCode::EXTENDED_LENGTH_MISSING; + return CardReturnCode::WRONG_LENGTH; default: qCWarning(card) << "TA PSO:Verify Certificate failed:" << psoResult.getStatusCode(); diff --git a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp index d2e66356b..57f66e209 100644 --- a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp +++ b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp @@ -115,7 +115,7 @@ EstablishPaceChannelErrorCode EstablishPaceChannelOutput::generateReturnCode(Car case CardReturnCode::PUK_INOPERATIVE: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: return EstablishPaceChannelErrorCode::UnexpectedDataInInput; case CardReturnCode::INVALID_CAN: diff --git a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp index 43afb959a..38f0cc2ee 100644 --- a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp +++ b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp @@ -60,9 +60,12 @@ void SimulatorReaderManagerPlugIn::stopScan(const QString& pError) if (mSimulatorReader) { mSimulatorReader->disconnectReader(pError); + + auto info = mSimulatorReader->getReaderInfo(); + mSimulatorReader.reset(); + Q_EMIT fireReaderRemoved(info); } ReaderManagerPlugIn::stopScan(pError); - mSimulatorReader.reset(); } diff --git a/src/card/smart/SmartManager.cpp b/src/card/smart/SmartManager.cpp index 06e7bcb14..62edfb1ab 100644 --- a/src/card/smart/SmartManager.cpp +++ b/src/card/smart/SmartManager.cpp @@ -395,13 +395,6 @@ void SmartManager::abortSDKWorkflow() const } -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - - QDebug operator<<(QDebug pDbg, const EidStatus& pStatus) { const auto& toString = [](const EidStatus& status){ @@ -430,7 +423,7 @@ QDebug operator<<(QDebug pDbg, const EidStatus& pStatus) }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pStatus) << " 0x" << HEX << static_cast(pStatus); + pDbg.nospace() << toString(pStatus) << " 0x" << Qt::hex << static_cast(pStatus); return pDbg; } @@ -460,7 +453,7 @@ QDebug operator<<(QDebug pDbg, const EidUpdateInfo& pInfo) }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pInfo) << " 0x" << HEX << static_cast(pInfo); + pDbg.nospace() << toString(pInfo) << " 0x" << Qt::hex << static_cast(pInfo); return pDbg; } @@ -493,6 +486,6 @@ QDebug operator<<(QDebug pDbg, const EidServiceResult& pResult) }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pResult) << " 0x" << HEX << static_cast(pResult); + pDbg.nospace() << toString(pResult) << " 0x" << Qt::hex << static_cast(pResult); return pDbg; } diff --git a/src/diagnosis/DiagnosisConnectionTest.cpp b/src/diagnosis/DiagnosisConnectionTest.cpp index b4f1be915..93d7e61e9 100644 --- a/src/diagnosis/DiagnosisConnectionTest.cpp +++ b/src/diagnosis/DiagnosisConnectionTest.cpp @@ -159,7 +159,14 @@ void DiagnosisConnectionTest::startConnectionTest() mConnectionTestWithProxyDone = false; mConnectionTestWithoutProxyDone = false; - const auto& proxy = QNetworkProxy::applicationProxy(); + const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); + const auto& proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(testUrl)); + const auto& proxy = proxies.constFirst(); + if (proxies.size() > 1) + { + qDebug() << "More than one proxy found, using first proxy:" << proxy; + } + if (proxy.type() == QNetworkProxy::ProxyType::NoProxy) { mIsProxySet = false; @@ -175,7 +182,6 @@ void DiagnosisConnectionTest::startConnectionTest() mProxyCapabilities = getProxyCapabilitiesAsQString(proxy.capabilities()); } - const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); if (mIsProxySet) { mPingSocketToProxy.reset(); diff --git a/src/diagnosis/DiagnosisModel.cpp b/src/diagnosis/DiagnosisModel.cpp index bb2f13a68..d6f4315b7 100644 --- a/src/diagnosis/DiagnosisModel.cpp +++ b/src/diagnosis/DiagnosisModel.cpp @@ -339,7 +339,7 @@ void DiagnosisModel::onTimestampChanged() QDateTime timestampValue = mContext->getTimestamp(); if (timestampValue.isValid()) { - //: LABEL DESKTOP Timestamp, formatted according to the selected language + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString QString timestamp = LanguageLoader::getInstance().getUsedLocale().toString(timestampValue, tr("d. MMMM yyyy, hh:mm:ss AP")); //: LABEL DESKTOP mTimestampSection << ContentItem(tr("Time of diagnosis"), timestamp); @@ -706,7 +706,7 @@ void DiagnosisModel::onRemoteInfosChanged() if (!info.getFingerprint().isEmpty()) { - //: LABEL DESKTOP Timestamp + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const QString& timestamp = LanguageLoader::getInstance().getUsedLocale().toString(info.getLastConnected(), tr("dd.MM.yyyy, hh:mm:ss")); //: LABEL DESKTOP mRemoteDeviceSection << ContentItem(info.getNameEscaped(), tr("Last connection: %1").arg(timestamp)); diff --git a/src/export/PdfExporter.cpp b/src/export/PdfExporter.cpp index c22ccd03f..8cbc97cf7 100644 --- a/src/export/PdfExporter.cpp +++ b/src/export/PdfExporter.cpp @@ -113,7 +113,7 @@ bool PdfExporter::exportHistory() {tr("Date"), //: LABEL ALL_PLATFORMS tr("Details")}); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); const auto& infos = Env::getSingleton()->getHistorySettings().getHistoryInfos(); for (const auto& entry : infos) @@ -142,9 +142,9 @@ bool PdfExporter::exportHistory() closeTable(); const auto& now = QDateTime::currentDateTime(); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString QString date = locale.toString(now, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString QString time = locale.toString(now, tr("hh:mm AP")); //: LABEL ALL_PLATFORMS const auto& headline = tr("At %1 %2 the following data were saved:").arg(date, time); @@ -181,9 +181,9 @@ bool PdfExporter::exportSelfInfo(const QDateTime& pDate, const QVector 0) { - function = function.mid(function.lastIndexOf(' ') + 1); + function = function.mid(index); + if (!function.isEmpty() && function.at(0) == '*') + { + function.remove(0, 1); + } } // Trim function name diff --git a/src/ifd/base/ConnectRequest.cpp b/src/ifd/base/ConnectRequest.cpp index 27845ae97..eee296f52 100644 --- a/src/ifd/base/ConnectRequest.cpp +++ b/src/ifd/base/ConnectRequest.cpp @@ -160,7 +160,8 @@ void ConnectRequest::onError(QAbstractSocket::SocketError pError) qCWarning(ifd) << "Connection error:" << pError; mTimer.stop(); - if (pError == QAbstractSocket::SocketError::RemoteHostClosedError) + if (pError == QAbstractSocket::SocketError::RemoteHostClosedError + || pError == QAbstractSocket::SocketError::SslHandshakeFailedError) { Q_EMIT fireConnectionError(mIfdDescriptor, IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION); } diff --git a/src/ifd/base/DataChannel.h b/src/ifd/base/DataChannel.h index 6ed4d37ac..39c91302d 100644 --- a/src/ifd/base/DataChannel.h +++ b/src/ifd/base/DataChannel.h @@ -27,6 +27,7 @@ class DataChannel Q_INVOKABLE virtual void send(const QByteArray& pDataBlock) = 0; Q_INVOKABLE virtual void close() = 0; + [[nodiscard]] virtual bool isPairingConnection() const = 0; [[nodiscard]] virtual const QString& getId() const = 0; Q_SIGNALS: diff --git a/src/ifd/base/IfdDescriptor.cpp b/src/ifd/base/IfdDescriptor.cpp index dc1e76226..9ecc362d1 100644 --- a/src/ifd/base/IfdDescriptor.cpp +++ b/src/ifd/base/IfdDescriptor.cpp @@ -38,11 +38,13 @@ QUrl urlFromMsgAndHost(const Discovery& pDiscovery, IfdDescriptor::IfdDescriptorData::IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pRemoteUrl, bool pIsLocalIfd) : mIfdName(pIfdName) , mIfdId(pIfdId) , mApiVersions(pApiVersions) + , mIsPairingAnnounced(pIsPairingAnnounced) , mUrl(pRemoteUrl) , mIsLocalIfd(pIsLocalIfd) { @@ -57,6 +59,7 @@ bool IfdDescriptor::IfdDescriptorData::operator==(const IfdDescriptorData& pOthe return mIfdName == pOther.mIfdName && mIfdId == pOther.mIfdId && mApiVersions == pOther.mApiVersions && + mIsPairingAnnounced == pOther.mIsPairingAnnounced && mUrl == pOther.mUrl; } @@ -79,7 +82,8 @@ IfdDescriptor::IfdDescriptor(const Discovery& pDiscovery, const QHostAddress& pH const QString& ifdName = pDiscovery.getIfdName(); const QString& ifdId = pDiscovery.getIfdId(); const QVector& supportedApis = pDiscovery.getSupportedApis(); - d = new IfdDescriptorData(ifdName, ifdId, supportedApis, url, pLocalIfd); + const bool isPairing = pDiscovery.getPairing(); + d = new IfdDescriptorData(ifdName, ifdId, supportedApis, isPairing, url, pLocalIfd); } @@ -113,6 +117,12 @@ bool IfdDescriptor::isSupported() const } +bool IfdDescriptor::isPairingAnnounced() const +{ + return !isNull() && d->mIsPairingAnnounced; +} + + const QUrl& IfdDescriptor::getUrl() const { static const QUrl EMPTY_URL; diff --git a/src/ifd/base/IfdDescriptor.h b/src/ifd/base/IfdDescriptor.h index db9129310..9020c50d1 100644 --- a/src/ifd/base/IfdDescriptor.h +++ b/src/ifd/base/IfdDescriptor.h @@ -30,6 +30,7 @@ class IfdDescriptor IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pUrl, bool pIsLocalIfd); @@ -38,6 +39,7 @@ class IfdDescriptor const QString mIfdName; const QString mIfdId; const QVector mApiVersions; + const bool mIsPairingAnnounced; const QUrl mUrl; const bool mIsLocalIfd; @@ -57,6 +59,7 @@ class IfdDescriptor [[nodiscard]] const QString& getIfdId() const; [[nodiscard]] const QVector& getApiVersions() const; [[nodiscard]] bool isSupported() const; + [[nodiscard]] bool isPairingAnnounced() const; [[nodiscard]] const QUrl& getUrl() const; [[nodiscard]] bool isNull() const; [[nodiscard]] bool isLocalIfd() const; diff --git a/src/ifd/base/IfdDispatcher.cpp b/src/ifd/base/IfdDispatcher.cpp index f76821450..32e206a1b 100644 --- a/src/ifd/base/IfdDispatcher.cpp +++ b/src/ifd/base/IfdDispatcher.cpp @@ -89,6 +89,17 @@ void IfdDispatcher::setVersion(IfdVersion::Version pVersion) } +bool IfdDispatcher::isPairingConnection() const +{ + if (!mDataChannel) + { + return false; + } + + return mDataChannel->isPairingConnection(); +} + + QString IfdDispatcher::getId() const { if (!mDataChannel) diff --git a/src/ifd/base/IfdDispatcher.h b/src/ifd/base/IfdDispatcher.h index cf195160e..883d8e8cc 100644 --- a/src/ifd/base/IfdDispatcher.h +++ b/src/ifd/base/IfdDispatcher.h @@ -46,6 +46,7 @@ class IfdDispatcher explicit IfdDispatcher(IfdVersion::Version pVersion, const QSharedPointer& pDataChannel); ~IfdDispatcher() override; + [[nodiscard]] virtual bool isPairingConnection() const; [[nodiscard]] virtual QString getId() const; [[nodiscard]] virtual const QString& getContextHandle() const; [[nodiscard]] IfdVersion::Version getVersion() const; diff --git a/src/ifd/base/IfdReaderManagerPlugIn.cpp b/src/ifd/base/IfdReaderManagerPlugIn.cpp index 6f1a77690..bc2b9b45f 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.cpp +++ b/src/ifd/base/IfdReaderManagerPlugIn.cpp @@ -108,17 +108,21 @@ void IfdReaderManagerPlugIn::handleIFDStatus(const QJsonObject& pJsonObject, con void IfdReaderManagerPlugIn::onContextEstablished(const QString& pIfdName, const QString& pId) { const auto& dispatcher = mDispatcherList.value(pId); - if (isInitialPairing(pIfdName, pId)) - { - QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); - } - else + + if (getInfo().getPlugInType() == ReaderManagerPlugInType::REMOTE_IFD) { - QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { - const QSharedPointer& ifdGetStatus = QSharedPointer::create(); - dispatcher->send(ifdGetStatus); - }, Qt::QueuedConnection); + dispatcher->saveRemoteNameInSettings(pIfdName); + if (dispatcher->isPairingConnection()) + { + QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); + return; + } } + + QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { + const QSharedPointer& ifdGetStatus = QSharedPointer::create(); + dispatcher->send(ifdGetStatus); + }, Qt::QueuedConnection); } diff --git a/src/ifd/base/IfdReaderManagerPlugIn.h b/src/ifd/base/IfdReaderManagerPlugIn.h index 97774b0eb..07e5546f6 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.h +++ b/src/ifd/base/IfdReaderManagerPlugIn.h @@ -13,6 +13,10 @@ #include #include + +class test_RemoteIfdReaderManagerPlugIn; + + namespace governikus { @@ -21,6 +25,7 @@ class IfdReaderManagerPlugIn : public ReaderManagerPlugIn { Q_OBJECT + friend class ::test_RemoteIfdReaderManagerPlugIn; private: QMultiMap mReadersForDispatcher; @@ -40,7 +45,6 @@ class IfdReaderManagerPlugIn void removeDispatcher(const QString& pId); [[nodiscard]] const QMap>& getDispatchers() const; - virtual bool isInitialPairing(const QString& pIfdName, const QString& pId) = 0; virtual IfdClient* getIfdClient() = 0; public: diff --git a/src/ifd/base/IfdServer.h b/src/ifd/base/IfdServer.h index c736f9402..6814f14fd 100644 --- a/src/ifd/base/IfdServer.h +++ b/src/ifd/base/IfdServer.h @@ -45,7 +45,7 @@ class IfdServer void firePskChanged(const QByteArray& pPsk); void fireConnectedChanged(bool pConnected); void fireIsRunningChanged(); - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; } // namespace governikus diff --git a/src/ifd/base/ServerMessageHandler.h b/src/ifd/base/ServerMessageHandler.h index f08fd50a4..26b3c701f 100644 --- a/src/ifd/base/ServerMessageHandler.h +++ b/src/ifd/base/ServerMessageHandler.h @@ -35,9 +35,11 @@ class ServerMessageHandler virtual void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput&) = 0; virtual void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) = 0; + virtual void setAllowedCardTypes(const QVector& pAllowedCardTypes) = 0; Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); + void fireDisplayTextChanged(const QString& pDisplayText); void fireEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireCardDisconnected(const QSharedPointer& pConnection); diff --git a/src/ifd/base/ServerMessageHandlerImpl.cpp b/src/ifd/base/ServerMessageHandlerImpl.cpp index 077963138..2c142aad4 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.cpp +++ b/src/ifd/base/ServerMessageHandlerImpl.cpp @@ -40,10 +40,12 @@ template<> ServerMessageHandler* createNewObject& pDataChannel, const QVector& pAllowedPlugInTypes) +ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, + const QVector& pAllowedTypes) : ServerMessageHandler() , mDispatcher(Env::create(pDataChannel), &QObject::deleteLater) - , mAllowedPlugInTypes(pAllowedPlugInTypes) + , mAllowedPlugInTypes(pAllowedTypes) + , mAllowedCardTypes(pAllowedTypes) , mCardConnections() { connect(mDispatcher.data(), &IfdDispatcherServer::fireReceived, this, &ServerMessageHandlerImpl::onMessage); @@ -216,6 +218,7 @@ void ServerMessageHandlerImpl::handleIfdTransmit(const QJsonObject& pJsonObject) if (!progressMessage.isNull()) { cardConnection->setProgressMessage(progressMessage); + Q_EMIT fireDisplayTextChanged(progressMessage); } qCDebug(ifd) << "Transmit card APDU for" << slotHandle; @@ -337,6 +340,12 @@ void ServerMessageHandlerImpl::sendModifyPinResponse(const QString& pSlotHandle, } +void ServerMessageHandlerImpl::setAllowedCardTypes(const QVector& pAllowedCardTypes) +{ + mAllowedCardTypes = pAllowedCardTypes; +} + + void ServerMessageHandlerImpl::onTransmitCardCommandDone(QSharedPointer pCommand) { auto transmitCommand = pCommand.staticCast(); @@ -444,7 +453,7 @@ void ServerMessageHandlerImpl::onReaderChanged(const ReaderInfo& pInfo) } } - mDispatcher->send(QSharedPointer::create(pInfo)); + mDispatcher->send(QSharedPointer::create(pInfo, mAllowedCardTypes.contains(pInfo.getPlugInType()))); } diff --git a/src/ifd/base/ServerMessageHandlerImpl.h b/src/ifd/base/ServerMessageHandlerImpl.h index b6f21a250..b52f534cc 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.h +++ b/src/ifd/base/ServerMessageHandlerImpl.h @@ -33,6 +33,7 @@ class ServerMessageHandlerImpl private: const QSharedPointer mDispatcher; QVector mAllowedPlugInTypes; + QVector mAllowedCardTypes; QMap> mCardConnections; [[nodiscard]] QString slotHandleForReaderName(const QString& pReaderName) const; @@ -54,10 +55,11 @@ class ServerMessageHandlerImpl public: explicit ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, - const QVector& pAllowedPlugInTypes = Enum::getList()); + const QVector& pAllowedTypes = Enum::getList()); void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput& pChannelOutput) override; void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) override; + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override; }; diff --git a/src/ifd/base/TlsServer.cpp b/src/ifd/base/TlsServer.cpp index b369c115e..18d9c7336 100644 --- a/src/ifd/base/TlsServer.cpp +++ b/src/ifd/base/TlsServer.cpp @@ -48,6 +48,12 @@ void TlsServer::stopListening() } +bool TlsServer::hasPsk() const +{ + return !mPsk.isEmpty(); +} + + void TlsServer::incomingConnection(qintptr pSocketDescriptor) { if (mSocket.isNull()) diff --git a/src/ifd/base/TlsServer.h b/src/ifd/base/TlsServer.h index 4df443c36..9022fdec8 100644 --- a/src/ifd/base/TlsServer.h +++ b/src/ifd/base/TlsServer.h @@ -44,6 +44,7 @@ class TlsServer void setPsk(const QByteArray& pPsk); void stopListening(); virtual bool startListening(quint16 pPort) = 0; + [[nodiscard]] bool hasPsk() const; Q_SIGNALS: void fireNewConnection(QTcpSocket* pSocket); diff --git a/src/ifd/base/WebSocketChannel.cpp b/src/ifd/base/WebSocketChannel.cpp index 855d29832..35c209222 100644 --- a/src/ifd/base/WebSocketChannel.cpp +++ b/src/ifd/base/WebSocketChannel.cpp @@ -5,6 +5,7 @@ #include "WebSocketChannel.h" #include "RemoteServiceSettings.h" +#include "SecureStorage.h" #include #include @@ -94,6 +95,13 @@ void WebSocketChannel::close() } +bool WebSocketChannel::isPairingConnection() const +{ + const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); + return pairingCiphers.contains(mConnection->sslConfiguration().sessionCipher()); +} + + const QString& WebSocketChannel::getId() const { return mId; diff --git a/src/ifd/base/WebSocketChannel.h b/src/ifd/base/WebSocketChannel.h index 40214b8cb..8ae639994 100644 --- a/src/ifd/base/WebSocketChannel.h +++ b/src/ifd/base/WebSocketChannel.h @@ -35,6 +35,7 @@ class WebSocketChannel void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; private Q_SLOTS: diff --git a/src/ifd/base/messages/IfdStatus.cpp b/src/ifd/base/messages/IfdStatus.cpp index 6b33e1e3c..8679ef26e 100644 --- a/src/ifd/base/messages/IfdStatus.cpp +++ b/src/ifd/base/messages/IfdStatus.cpp @@ -81,13 +81,13 @@ void IfdStatus::parsePinPad(const QJsonObject& pMessageObject) } -IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo) +IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard) : IfdMessage(IfdMessageType::IFDStatus) , mSlotName(pReaderInfo.getName()) , mHasPinPad(!pReaderInfo.isBasicReader()) , mMaxApduLength(pReaderInfo.getMaxApduLength()) , mConnectedReader(pReaderInfo.isValid()) - , mCardAvailable(pReaderInfo.hasCard()) + , mCardAvailable(pReaderInfo.hasCard() && pPublishCard) { if (!mHasPinPad && pReaderInfo.getPlugInType() == ReaderManagerPlugInType::NFC) { diff --git a/src/ifd/base/messages/IfdStatus.h b/src/ifd/base/messages/IfdStatus.h index 885db639c..0acdfdc03 100644 --- a/src/ifd/base/messages/IfdStatus.h +++ b/src/ifd/base/messages/IfdStatus.h @@ -33,7 +33,7 @@ class IfdStatus void parsePinPad(const QJsonObject& pMessageObject); public: - explicit IfdStatus(const ReaderInfo& pReaderInfo); + explicit IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard = true); explicit IfdStatus(const QJsonObject& pMessageObject); ~IfdStatus() override = default; diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp index 3a43d5f3f..c5f7f65e7 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp @@ -97,14 +97,6 @@ void LocalIfdReaderManagerPlugIn::onLocalIfdConnectionClosed(GlobalStatus::Code } -bool LocalIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - Q_UNUSED(pIfdName) - Q_UNUSED(pId) - return false; -} - - bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() { if (mServiceConnected) diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.h b/src/ifd/local/LocalIfdReaderManagerPlugIn.h index ea816126b..7e68ebed7 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.h +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.h @@ -36,7 +36,6 @@ class LocalIfdReaderManagerPlugIn void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; LocalIfdClient* getIfdClient() override; void addDispatcher(const QSharedPointer& pDispatcher) override; diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp index 837ae7355..3ceede969 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp @@ -40,12 +40,13 @@ void RemoteIfdReaderManagerPlugIn::continueConnectToPairedReaders(const QVector< const RemoteServiceSettings& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); for (const QSharedPointer& remoteDevice : pRemoteDevices) { - if (!remoteDevice->getIfdDescriptor().isSupported()) + const auto& ifdDescriptor = remoteDevice->getIfdDescriptor(); + if (!ifdDescriptor.isSupported() || ifdDescriptor.isPairingAnnounced()) { continue; } - const QString ifdId = remoteDevice->getIfdDescriptor().getIfdId(); + const QString ifdId = ifdDescriptor.getIfdId(); // If already connected: skip. if (getDispatchers().contains(ifdId)) @@ -106,19 +107,3 @@ IfdClient* RemoteIfdReaderManagerPlugIn::getIfdClient() { return Env::getSingleton(); } - - -bool RemoteIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); - auto info = settings.getRemoteInfo(pId); - bool initialPairing = false; - if (info.getNameEscaped().isEmpty()) - { - initialPairing = true; - } - info.setNameUnescaped(pIfdName); - settings.updateRemoteInfo(info); - - return initialPairing; -} diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h index 68bbb35bc..47104fd8e 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h @@ -40,7 +40,6 @@ class RemoteIfdReaderManagerPlugIn void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; IfdClient* getIfdClient() override; }; diff --git a/src/ifd/remote/RemoteIfdServer.cpp b/src/ifd/remote/RemoteIfdServer.cpp index 16c81a0bb..f9f6d6001 100644 --- a/src/ifd/remote/RemoteIfdServer.cpp +++ b/src/ifd/remote/RemoteIfdServer.cpp @@ -32,7 +32,8 @@ void RemoteIfdServer::onConnectedChanged(bool pConnected) const auto& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); const auto& ifdId = QString::fromLatin1(remoteServiceSettings.getCertificate().toPem()); quint16 port = mWebSocketServer->getServerPort(); - mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port)); + bool isPairing = mWebSocketServer->isPairingAnnounced(); + mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port, isPairing)); } Q_EMIT fireConnectedChanged(pConnected); diff --git a/src/ifd/remote/RemoteReaderAdvertiser.cpp b/src/ifd/remote/RemoteReaderAdvertiser.cpp index d49fa85e7..91e8ecd19 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.cpp +++ b/src/ifd/remote/RemoteReaderAdvertiser.cpp @@ -18,9 +18,9 @@ Q_DECLARE_LOGGING_CATEGORY(ifd) namespace governikus { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool& pIsPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pIsPairing); } @@ -51,7 +51,7 @@ RemoteReaderAdvertiserImpl::~RemoteReaderAdvertiserImpl() } -RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval, bool pPairing) +RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing, int pTimerInterval) : RemoteReaderAdvertiser() , mHandler(Env::create(false)) , mTimerId(startTimer(pTimerInterval)) diff --git a/src/ifd/remote/RemoteReaderAdvertiser.h b/src/ifd/remote/RemoteReaderAdvertiser.h index bd7134077..1c5dd0e03 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.h +++ b/src/ifd/remote/RemoteReaderAdvertiser.h @@ -53,7 +53,7 @@ class RemoteReaderAdvertiserImpl public: ~RemoteReaderAdvertiserImpl() override; - RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval = 1000, bool pPairing = false); + RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing = false, int pTimerInterval = 1000); void setPairing(bool pEnabled) override; }; diff --git a/src/ifd/remote/RemoteTlsServer.cpp b/src/ifd/remote/RemoteTlsServer.cpp index 9ce2daac6..68290891d 100644 --- a/src/ifd/remote/RemoteTlsServer.cpp +++ b/src/ifd/remote/RemoteTlsServer.cpp @@ -110,10 +110,11 @@ void RemoteTlsServer::onEncrypted() const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); if (pairingCiphers.contains(cfg.sessionCipher())) { - qCDebug(ifd) << "Pairing completed | Add certificate:" << cfg.peerCertificate(); - settings.addTrustedCertificate(cfg.peerCertificate()); + const auto& sslCertificate = cfg.peerCertificate(); + qCDebug(ifd) << "Pairing completed | Add certificate:" << sslCertificate; + settings.addTrustedCertificate(sslCertificate); setPairing(false); - Q_EMIT firePairingCompleted(); + Q_EMIT firePairingCompleted(sslCertificate); } else { diff --git a/src/ifd/remote/RemoteTlsServer.h b/src/ifd/remote/RemoteTlsServer.h index 39fc7a10f..648b5574d 100644 --- a/src/ifd/remote/RemoteTlsServer.h +++ b/src/ifd/remote/RemoteTlsServer.h @@ -32,7 +32,7 @@ class RemoteTlsServer void onSslErrors(const QList& pErrors) override; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; } // namespace governikus diff --git a/src/ifd/remote/RemoteWebSocketServer.h b/src/ifd/remote/RemoteWebSocketServer.h index 91a614bd2..938f3c5aa 100644 --- a/src/ifd/remote/RemoteWebSocketServer.h +++ b/src/ifd/remote/RemoteWebSocketServer.h @@ -22,11 +22,12 @@ class RemoteWebSocketServer ~RemoteWebSocketServer() override; [[nodiscard]] virtual bool isPairingConnection() const = 0; + [[nodiscard]] virtual bool isPairingAnnounced() const = 0; virtual void setPairing(bool pEnable = true) = 0; [[nodiscard]] virtual QSslCertificate getCurrentCertificate() const = 0; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.cpp b/src/ifd/remote/RemoteWebSocketServerImpl.cpp index da8b91309..963ea8392 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.cpp +++ b/src/ifd/remote/RemoteWebSocketServerImpl.cpp @@ -103,6 +103,12 @@ bool RemoteWebSocketServerImpl::isPairingConnection() const } +bool RemoteWebSocketServerImpl::isPairingAnnounced() const +{ + return mRemoteTlsServer->hasPsk(); +} + + void RemoteWebSocketServerImpl::setPairing(bool pEnable) { mRemoteTlsServer->setPairing(pEnable); diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.h b/src/ifd/remote/RemoteWebSocketServerImpl.h index 6089f00fe..ba7d8bf4a 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.h +++ b/src/ifd/remote/RemoteWebSocketServerImpl.h @@ -45,6 +45,7 @@ class RemoteWebSocketServerImpl const QSharedPointer& getMessageHandler() const override; [[nodiscard]] bool isPairingConnection() const override; + [[nodiscard]] bool isPairingAnnounced() const override; void setPairing(bool pEnable = true) override; [[nodiscard]] QSslCertificate getCurrentCertificate() const override; }; diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp index 369fc8bf2..bd935afd8 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -5,11 +5,8 @@ #include "NetworkManager.h" #include "AppSettings.h" -#include "NetworkReplyError.h" -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #include "NetworkReplyTimeout.h" -#endif #include "LogHandler.h" +#include "NetworkReplyError.h" #include "SecureStorage.h" #include "TlsChecker.h" #include "VersionInfo.h" @@ -335,10 +332,6 @@ QSharedPointer NetworkManager::trackConnection(QNetworkReply* pRe --mOpenConnectionCount; }); connect(this, &NetworkManager::fireShutdown, pResponse, &QNetworkReply::abort, Qt::QueuedConnection); - -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - NetworkReplyTimeout::setTimeout(this, pResponse, 30000); -#endif } return QSharedPointer(pResponse, &QObject::deleteLater); diff --git a/src/network/NetworkReplyTimeout.cpp b/src/network/NetworkReplyTimeout.cpp deleted file mode 100644 index 14acf8d46..000000000 --- a/src/network/NetworkReplyTimeout.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "NetworkReplyTimeout.h" - -#include - -using namespace governikus; - -NetworkReplyTimeout::NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout) - : QObject(pReply) -{ - Q_ASSERT(pReply); - if (pReply == nullptr) - { - return; - } - - connect(&mTimer, &QTimer::timeout, this, &NetworkReplyTimeout::onTimeout); - mTimer.setSingleShot(true); - mTimer.setInterval(pTimeout); - mTimer.start(); -} - - -void NetworkReplyTimeout::onTimeout() -{ - auto* reply = static_cast(parent()); - if (reply != nullptr && reply->isRunning()) - { - reply->abort(); - } -} - - -void NetworkReplyTimeout::onShutdown() -{ - mTimer.stop(); - onTimeout(); -} - - -void NetworkReplyTimeout::setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeout) -{ - // since the QNetworkReply is set as parent, we don't need to care about destruction - const auto* timeout = new NetworkReplyTimeout(pReply, pTimeout); - connect(pManager, &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown); -} diff --git a/src/network/NetworkReplyTimeout.h b/src/network/NetworkReplyTimeout.h deleted file mode 100644 index 729e46d15..000000000 --- a/src/network/NetworkReplyTimeout.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Utility class to set a timeout on a QNetworkReply - */ - -#pragma once - -#include "NetworkManager.h" - -#include -#include - -namespace governikus -{ - -class NetworkReplyTimeout - : public QObject -{ - Q_OBJECT - - private: - QTimer mTimer; - - NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout); - - private Q_SLOTS: - void onTimeout(); - void onShutdown(); - - public: - /*! - * Set the timeout in milli-seconds on the specified QNetworkReply. - */ - static void setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeoutMilliSeconds); -}; - -} // namespace governikus diff --git a/src/services/Service.cpp b/src/services/Service.cpp index eab8254ac..2b6ad7d69 100644 --- a/src/services/Service.cpp +++ b/src/services/Service.cpp @@ -25,14 +25,16 @@ void Service::doAppUpdate(UpdateType pType, bool pForceUpdate) { case UpdateType::APPCAST: mExplicitSuccessMessage = pForceUpdate; -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - mTimer.start(mOneDayInMs); - if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + if (Env::getSingleton()->getGeneralSettings().isAutoUpdateAvailable()) { - Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) - break; + mTimer.start(mOneDayInMs); + if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + { + Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) + break; + } } -#endif + Q_FALLTHROUGH(); case UpdateType::PROVIDER: diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index 4e5cbc7bd..c0ac3dc1f 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -447,7 +447,7 @@ void GeneralSettings::setLastReaderPluginType(const QString& pLastReaderPluginTy bool GeneralSettings::isAutoUpdateAvailable() const { -#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) || defined(Q_OS_MACOS) +#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) return true; #else diff --git a/src/settings/RemoteServiceSettings.cpp b/src/settings/RemoteServiceSettings.cpp index a105833bf..6edd21af0 100644 --- a/src/settings/RemoteServiceSettings.cpp +++ b/src/settings/RemoteServiceSettings.cpp @@ -29,6 +29,7 @@ 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_NAME_SHOW_ACCESS_RIGHTS, "showAccessRights") SETTINGS_NAME(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES, "trustedCertificates") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM, "certificate") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_REMOTE_INFO, "trustedRemoteInfo") @@ -84,7 +85,7 @@ void RemoteServiceSettings::setServerName(const QString& pName) bool RemoteServiceSettings::getPinPadMode() const { - return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), false).toBool(); + return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), true).toBool(); } @@ -95,6 +96,19 @@ void RemoteServiceSettings::setPinPadMode(bool pPinPadMode) } +bool RemoteServiceSettings::getShowAccessRights() const +{ + return mStore->value(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), false).toBool(); +} + + +void RemoteServiceSettings::setShowAccessRights(bool pShowAccessRights) +{ + mStore->setValue(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), pShowAccessRights); + save(mStore); +} + + QList RemoteServiceSettings::getTrustedCertificates() const { const int itemCount = mStore->beginReadArray(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES()); @@ -229,6 +243,11 @@ void RemoteServiceSettings::setKey(const QSslKey& pKey) const RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QSslCertificate& pCertificate) const { + if (pCertificate.isNull()) + { + return RemoteInfo(); + } + return getRemoteInfo(generateFingerprint(pCertificate)); } @@ -322,8 +341,13 @@ bool RemoteServiceSettings::updateRemoteInfo(const RemoteInfo& pInfo) iter.next(); if (iter.value().getFingerprint() == pInfo.getFingerprint()) { + const bool hadNoNameYet = iter.value().mName.isEmpty(); iter.setValue(pInfo); setRemoteInfos(infos); + if (hadNoNameYet) + { + Q_EMIT fireInitialDeviceNameSet(pInfo.getNameEscaped()); + } return true; } } diff --git a/src/settings/RemoteServiceSettings.h b/src/settings/RemoteServiceSettings.h index 97f2bb993..658973cd7 100644 --- a/src/settings/RemoteServiceSettings.h +++ b/src/settings/RemoteServiceSettings.h @@ -89,6 +89,9 @@ class RemoteServiceSettings [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); + [[nodiscard]] QList getTrustedCertificates() const; void addTrustedCertificate(const QSslCertificate& pCertificate); void removeTrustedCertificate(const QSslCertificate& pCertificate); @@ -112,6 +115,7 @@ class RemoteServiceSettings Q_SIGNALS: void fireTrustedCertificatesChanged(); void fireTrustedRemoteInfosChanged(); + void fireInitialDeviceNameSet(const QString& pName); }; diff --git a/src/ui/json/MessageDispatcher.cpp b/src/ui/json/MessageDispatcher.cpp index 03bb84f33..45e5930f1 100644 --- a/src/ui/json/MessageDispatcher.cpp +++ b/src/ui/json/MessageDispatcher.cpp @@ -387,9 +387,10 @@ MsgHandler MessageDispatcher::interrupt() #ifdef Q_OS_IOS { const auto allowedStates = {MsgType::ENTER_PIN, MsgType::ENTER_CAN, MsgType::ENTER_PUK, MsgType::ENTER_NEW_PIN}; - const auto lastPaceResult = mContext.getContext()->getLastPaceResult(); - return handleCurrentState(cmdType, allowedStates, [lastPaceResult] { - switch (lastPaceResult) + const auto& workflowContext = mContext.getContext(); + return handleCurrentState(cmdType, allowedStates, [&workflowContext] { + workflowContext->setInterruptRequested(true); + switch (workflowContext->getLastPaceResult()) { case CardReturnCode::OK: case CardReturnCode::OK_PUK: diff --git a/src/ui/qml/ApplicationModel.cpp b/src/ui/qml/ApplicationModel.cpp index dcc7c906d..88eb64b24 100644 --- a/src/ui/qml/ApplicationModel.cpp +++ b/src/ui/qml/ApplicationModel.cpp @@ -6,6 +6,7 @@ #include "context/AuthContext.h" #include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" #include "BuildHelper.h" @@ -226,6 +227,10 @@ ApplicationModel::Workflow ApplicationModel::getCurrentWorkflow() const { return Workflow::WORKFLOW_AUTHENTICATION; } + if (mContext.objectCast()) + { + return Workflow::WORKFLOW_REMOTE_SERVICE; + } return Workflow::WORKFLOW_NONE; } diff --git a/src/ui/qml/ApplicationModel.h b/src/ui/qml/ApplicationModel.h index 472499d5a..d028710f2 100644 --- a/src/ui/qml/ApplicationModel.h +++ b/src/ui/qml/ApplicationModel.h @@ -97,6 +97,7 @@ class ApplicationModel WORKFLOW_SELF_AUTHENTICATION, WORKFLOW_AUTHENTICATION, WORKFLOW_SMART, + WORKFLOW_REMOTE_SERVICE, WORKFLOW_NONE }; Q_ENUM(Workflow) diff --git a/src/ui/qml/CertificateDescriptionModel.cpp b/src/ui/qml/CertificateDescriptionModel.cpp index 10df26852..adecdd9a5 100644 --- a/src/ui/qml/CertificateDescriptionModel.cpp +++ b/src/ui/qml/CertificateDescriptionModel.cpp @@ -5,6 +5,8 @@ #include "CertificateDescriptionModel.h" #include "LanguageLoader.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" using namespace governikus; @@ -21,9 +23,14 @@ CertificateDescriptionModel::CertificateDescriptionModel() QSharedPointer CertificateDescriptionModel::getCertificateDescription() const { - if (mContext && mContext->getDidAuthenticateEac1()) + if (const auto authContext = mContext.objectCast(); authContext && authContext->getDidAuthenticateEac1()) { - return mContext->getDidAuthenticateEac1()->getCertificateDescription(); + return authContext->getDidAuthenticateEac1()->getCertificateDescription(); + } + + if (const auto ifdContext = mContext.objectCast(); ifdContext && ifdContext->getCertificateDescription()) + { + return ifdContext->getCertificateDescription(); } return QSharedPointer(); @@ -85,13 +92,17 @@ void CertificateDescriptionModel::initModelData(const QSharedPointer& pContext) +void CertificateDescriptionModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; - if (mContext) + if (auto authContext = pContext.objectCast()) + { + connect(authContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + } + else if (auto ifdContext = pContext.objectCast()) { - connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); - connect(mContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); } onDidAuthenticateEac1Changed(); @@ -121,9 +132,9 @@ QString CertificateDescriptionModel::getPurpose() const QString CertificateDescriptionModel::getValidity() const { - if (mContext && mContext->getAccessRightManager() && mContext->getAccessRightManager()->getTerminalCvc()) + if (const auto authContext = mContext.objectCast(); authContext&& authContext->getAccessRightManager() && authContext->getAccessRightManager()->getTerminalCvc()) { - const CVCertificateBody body = mContext->getAccessRightManager()->getTerminalCvc()->getBody(); + const CVCertificateBody body = authContext->getAccessRightManager()->getTerminalCvc()->getBody(); const auto locale = LanguageLoader::getInstance().getUsedLocale(); const auto effectiveDate = locale.toString(body.getCertificateEffectiveDate(), QLocale::ShortFormat); const auto expirationDate = locale.toString(body.getCertificateExpirationDate(), QLocale::ShortFormat); diff --git a/src/ui/qml/CertificateDescriptionModel.h b/src/ui/qml/CertificateDescriptionModel.h index c2adc3a2f..00735db83 100644 --- a/src/ui/qml/CertificateDescriptionModel.h +++ b/src/ui/qml/CertificateDescriptionModel.h @@ -10,7 +10,7 @@ #include "Env.h" #include "asn1/CertificateDescription.h" -#include "context/AuthContext.h" +#include "context/WorkflowContext.h" #include #include @@ -32,7 +32,7 @@ class CertificateDescriptionModel private: QVector> mData; - QSharedPointer mContext; + QSharedPointer mContext; CertificateDescriptionModel(); ~CertificateDescriptionModel()override = default; @@ -54,7 +54,7 @@ class CertificateDescriptionModel TEXT }; - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] QString getSubjectName() const; [[nodiscard]] QString getSubjectUrl() const; diff --git a/src/ui/qml/ChatModel.cpp b/src/ui/qml/ChatModel.cpp index e658a4863..dfc78a623 100644 --- a/src/ui/qml/ChatModel.cpp +++ b/src/ui/qml/ChatModel.cpp @@ -11,13 +11,15 @@ #include "AppSettings.h" #include "asn1/AccessRoleAndRight.h" #include "asn1/CVCertificate.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" using namespace governikus; ChatModel::ChatModel() : QAbstractListModel() - , mAuthContext() + , mContext() , mAllRights() , mOptionalRights() , mSelectedRights() @@ -49,9 +51,9 @@ void ChatModel::initFilterModel(QSortFilterProxyModel& pModel, QAbstractItemMode } -void ChatModel::resetContext(const QSharedPointer& pContext) +void ChatModel::resetContext(const QSharedPointer& pContext) { - mAuthContext = pContext; + mContext = pContext; beginResetModel(); @@ -61,9 +63,13 @@ void ChatModel::resetContext(const QSharedPointer& pContext) endResetModel(); - if (!pContext.isNull()) + if (auto authContext = pContext.objectCast()) { - connect(pContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + } + else if (auto ifdContext = pContext.objectCast()) + { + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); } } @@ -113,32 +119,41 @@ int ChatModel::rowCount(const QModelIndex&) const QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const { - if (pIndex.isValid() && pIndex.row() < rowCount()) + if (!pIndex.isValid() || pIndex.row() >= rowCount()) { - auto right = mAllRights.at(pIndex.row()); - if (pRole == Qt::DisplayRole || pRole == NAME_ROLE) + return QVariant(); + } + + const auto& right = mAllRights.at(pIndex.row()); + switch (pRole) + { + case Qt::DisplayRole: + case NAME_ROLE: { QString displayText = AccessRoleAndRightsUtil::toDisplayText(right); if (right == AccessRight::AGE_VERIFICATION) { - displayText += QStringLiteral(" (%1)").arg(mAuthContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + if (auto authContext = mContext.objectCast()) + { + displayText += QStringLiteral(" (%1)").arg(authContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + } } return displayText; } - if (pRole == OPTIONAL_ROLE) - { + + case OPTIONAL_ROLE: return mOptionalRights.contains(right); - } - if (pRole == SELECTED_ROLE) - { + + case SELECTED_ROLE: return mSelectedRights.contains(right); - } - if (pRole == WRITE_RIGHT) - { + + case WRITE_RIGHT: return AccessRoleAndRightsUtil::isWriteAccessRight(right); - } + + default: + Q_UNREACHABLE(); + return QVariant(); } - return QVariant(); } @@ -185,9 +200,11 @@ bool ChatModel::setData(const QModelIndex& pIndex, const QVariant& pValue, int p void ChatModel::transferAccessRights() { - Q_ASSERT(mAuthContext->getAccessRightManager()); - - *mAuthContext->getAccessRightManager() = mSelectedRights; + if (auto authContext = mContext.objectCast()) + { + Q_ASSERT(authContext->getAccessRightManager()); + *authContext->getAccessRightManager() = mSelectedRights; + } } diff --git a/src/ui/qml/ChatModel.h b/src/ui/qml/ChatModel.h index cf2dc05d6..f50db1001 100644 --- a/src/ui/qml/ChatModel.h +++ b/src/ui/qml/ChatModel.h @@ -15,7 +15,8 @@ #include #include "Env.h" -#include "context/AuthContext.h" +#include "context/AccessRightManager.h" +#include "context/WorkflowContext.h" class test_ChatModel; @@ -36,7 +37,7 @@ class ChatModel Q_PROPERTY(QSortFilterProxyModel * write READ getFilterWriteModel CONSTANT) private: - QSharedPointer mAuthContext; + QSharedPointer mContext; QList mAllRights; QSet mOptionalRights; QSet mSelectedRights; @@ -63,7 +64,7 @@ class ChatModel void onAuthenticationDataChanged(QSharedPointer pAccessRightManager); public: - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; diff --git a/src/ui/qml/HistoryModelSearchFilter.cpp b/src/ui/qml/HistoryModelSearchFilter.cpp index 1acf6d801..2a7bed308 100644 --- a/src/ui/qml/HistoryModelSearchFilter.cpp +++ b/src/ui/qml/HistoryModelSearchFilter.cpp @@ -25,6 +25,7 @@ bool HistoryModelSearchFilter::filterAcceptsRow(int pSourceRow, const QModelInde } const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0); + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString 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) diff --git a/src/ui/qml/LogModel.cpp b/src/ui/qml/LogModel.cpp index dd6782d19..d5d1095c4 100644 --- a/src/ui/qml/LogModel.cpp +++ b/src/ui/qml/LogModel.cpp @@ -125,6 +125,7 @@ QStringList LogModel::getLogFileNames() const { if (!entry.isEmpty()) { + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString logFileNames += LanguageLoader::getInstance().getUsedLocale().toString(LogHandler::getFileDate(QFileInfo(entry)), tr("dd.MM.yyyy hh:mm:ss")); } } diff --git a/src/ui/qml/NotificationModel.cpp b/src/ui/qml/NotificationModel.cpp index ad03e0252..f5074c7a2 100644 --- a/src/ui/qml/NotificationModel.cpp +++ b/src/ui/qml/NotificationModel.cpp @@ -41,6 +41,7 @@ void NotificationModel::onNewLogMsg(const QString& pMsg, const QString& pCategor } beginInsertRows(QModelIndex(), mNotificationEntries.size(), mNotificationEntries.size()); + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString const auto& time = QTime::currentTime().toString(tr("hh:mm:ss")); mNotificationEntries.append({pCategoryName, time, pMsg}); endInsertRows(); diff --git a/src/ui/qml/PinResetInformationModel.cpp b/src/ui/qml/PinResetInformationModel.cpp index 160903ced..0a0af91ae 100644 --- a/src/ui/qml/PinResetInformationModel.cpp +++ b/src/ui/qml/PinResetInformationModel.cpp @@ -4,10 +4,13 @@ #include "PinResetInformationModel.h" +#include "LanguageLoader.h" #include "ProviderConfiguration.h" + using namespace governikus; + PinResetInformationModel::PinResetInformationModel() : QObject() { @@ -27,6 +30,11 @@ QUrl PinResetInformationModel::getPinResetUrl() const return tr("https://www.personalausweisportal.de/EN"); } + if (LanguageLoader::getLocaleCode() != QStringLiteral("de")) + { + return homepage + QStringLiteral("/en"); + } + return homepage; } diff --git a/src/ui/qml/ReaderModel.cpp b/src/ui/qml/ReaderModel.cpp index bb603488d..19b65e4b5 100644 --- a/src/ui/qml/ReaderModel.cpp +++ b/src/ui/qml/ReaderModel.cpp @@ -255,6 +255,7 @@ QString ReaderModel::getLastUpdatedInformation() const return QString(); } + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP")); //: LABEL ALL_PLATFORMS return tr("The list of card readers was last updated at %1.").arg(updateTime); diff --git a/src/ui/qml/RemoteDeviceFilterModel.cpp b/src/ui/qml/RemoteDeviceFilterModel.cpp new file mode 100644 index 000000000..8a8e7ff14 --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.cpp @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +using namespace governikus; +using namespace std::placeholders; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction) + : QSortFilterProxyModel() + , mFilterToApply(pFilterFunction) +{ + QSortFilterProxyModel::setSourceModel(pSourceModel); +} + + +RemoteDeviceFilterModel::ShowAvailableAndPaired RemoteDeviceFilterModel::showAvailableAndPaired = {}; +RemoteDeviceFilterModel::ShowUnavailableAndPaired RemoteDeviceFilterModel::showUnavailableAndPaired = {}; +RemoteDeviceFilterModel::ShowActivePairingMode RemoteDeviceFilterModel::showActivePairingMode = {}; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::availableNotPairing, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::unavailableAndPaired, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::isPairing, this, _1, _2)) +{ +} + + +bool RemoteDeviceFilterModel::available(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + const bool isNetworkVisible = sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE).toBool(); + return isNetworkVisible; +} + + +bool RemoteDeviceFilterModel::isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED).toBool(); +} + + +bool RemoteDeviceFilterModel::availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return available(pSourceRow, pSourceParent) && !isPairing(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return !available(pSourceRow, pSourceParent) && isDevicePaired(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::isPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING).toBool(); +} + + +bool RemoteDeviceFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return mFilterToApply(pSourceRow, pSourceParent); +} diff --git a/src/ui/qml/RemoteDeviceFilterModel.h b/src/ui/qml/RemoteDeviceFilterModel.h new file mode 100644 index 000000000..b9ab5b544 --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class test_RemoteDeviceFilterModel; + +namespace governikus +{ + +class RemoteDeviceFilterModel + : public QSortFilterProxyModel +{ + friend class ::test_RemoteDeviceFilterModel; + + private: + using FilterFunctionType = std::function; + FilterFunctionType mFilterToApply; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction); + + public: + struct ShowAvailableAndPaired {}; + struct ShowUnavailableAndPaired {}; + struct ShowActivePairingMode {}; + + static ShowAvailableAndPaired showAvailableAndPaired; + static ShowUnavailableAndPaired showUnavailableAndPaired; + static ShowActivePairingMode showActivePairingMode; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode); + + ~RemoteDeviceFilterModel() override = default; + + private: + [[nodiscard]] bool available(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const; + + [[nodiscard]] bool availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + + protected: + [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; +}; + +} // namespace governikus diff --git a/src/ui/qml/RemoteDeviceModel.cpp b/src/ui/qml/RemoteDeviceModel.cpp index e994d425d..06406ed7c 100644 --- a/src/ui/qml/RemoteDeviceModel.cpp +++ b/src/ui/qml/RemoteDeviceModel.cpp @@ -16,17 +16,16 @@ using namespace governikus; -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& pId, - const QSharedPointer& pRemoteDeviceListEntry) - : mDeviceName(pDeviceNameEscaped) - , mId(pId) +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QSharedPointer& pListEntry) + : mDeviceName(RemoteServiceSettings::escapeDeviceName(pListEntry->getIfdDescriptor().getIfdName())) + , mId(pListEntry->getIfdDescriptor().getIfdId()) , mPaired(false) + , mIsPairing(pListEntry->getIfdDescriptor().isPairingAnnounced()) , mNetworkVisible(false) , mConnected(false) - , mSupported(pRemoteDeviceListEntry->getIfdDescriptor().isSupported()) + , mSupported(pListEntry->getIfdDescriptor().isSupported()) , mLastConnected() - , mRemoteDeviceListEntry(pRemoteDeviceListEntry) + , mRemoteDeviceListEntry(pListEntry) { Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); } @@ -37,11 +36,13 @@ RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped bool pNetworkVisible, bool pConnected, bool pSupported, + bool pIsPairing, const QDateTime& pLastConnected, const QSharedPointer& pRemoteDeviceListEntry) : mDeviceName(pDeviceNameEscaped) , mId(pId) , mPaired(true) + , mIsPairing(pIsPairing) , mNetworkVisible(pNetworkVisible) , mConnected(pConnected) , mSupported(pSupported) @@ -56,6 +57,7 @@ RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped : mDeviceName(pDeviceNameEscaped) , mId() , mPaired(false) + , mIsPairing(false) , mNetworkVisible(false) , mConnected(false) , mSupported(false) @@ -90,6 +92,18 @@ void RemoteDeviceModelEntry::setPaired(bool pPaired) } +bool RemoteDeviceModelEntry::isPairing() const +{ + return mIsPairing; +} + + +void RemoteDeviceModelEntry::setIsPairing(bool pIsPairing) +{ + mIsPairing = pIsPairing; +} + + const QString& RemoteDeviceModelEntry::getId() const { return mId; @@ -191,7 +205,9 @@ QHash RemoteDeviceModel::roleNames() const roles.insert(IS_NETWORK_VISIBLE, QByteArrayLiteral("isNetworkVisible")); roles.insert(IS_SUPPORTED, QByteArrayLiteral("isSupported")); roles.insert(IS_PAIRED, QByteArrayLiteral("isPaired")); + roles.insert(IS_PAIRING, QByteArrayLiteral("isPairing")); roles.insert(LINK_QUALITY, QByteArrayLiteral("linkQualityInPercent")); + roles.insert(IS_LAST_ADDED_DEVICE, QByteArrayLiteral("isLastAddedDevice")); return roles; } @@ -222,6 +238,12 @@ QString RemoteDeviceModel::getStatus(const RemoteDeviceModelEntry& pRemoteDevice return tr("Not connected"); } + if (pRemoteDeviceModelEntry.isPairing()) + { + //: LABEL ALL_PLATFORMS + return tr("Click to pair"); + } + if (pRemoteDeviceModelEntry.isPaired()) { if (pRemoteDeviceModelEntry.isNetworkVisible()) @@ -235,7 +257,7 @@ QString RemoteDeviceModel::getStatus(const RemoteDeviceModelEntry& pRemoteDevice return tr("Paired, but unsupported"); } //: LABEL ALL_PLATFORMS - return tr("Paired, but unavailable"); + return tr("Unavailable"); } if (!pRemoteDeviceModelEntry.isSupported()) @@ -259,6 +281,7 @@ void RemoteDeviceModel::updatePairedReaders() bool visible = false; bool connected = false; bool supported = true; + bool isPairing = false; QSharedPointer deviceListEntry; for (const auto& availableReader : availableReaders) { @@ -267,6 +290,7 @@ void RemoteDeviceModel::updatePairedReaders() visible = true; connected = connectedDeviceIDs.contains(availableReader.getId()); supported = availableReader.isSupported(); + isPairing = availableReader.isPairing(); deviceListEntry = availableReader.getRemoteDeviceListEntry(); break; } @@ -284,6 +308,7 @@ void RemoteDeviceModel::updatePairedReaders() visible, connected, supported, + isPairing, pairedReader.getLastConnected(), deviceListEntry); addOrUpdateReader(modelEntry); @@ -336,10 +361,9 @@ QVector RemoteDeviceModel::presentReaders() const const auto& announcingRemoteDevices = Env::getSingleton()->getAnnouncingRemoteDevices(); QVector presentReaders; - for (auto deviceListEntry : announcingRemoteDevices) + for (auto& deviceListEntry : announcingRemoteDevices) { - const auto& deviceDescriptor = deviceListEntry->getIfdDescriptor(); - auto modelEntry = RemoteDeviceModelEntry(RemoteServiceSettings::escapeDeviceName(deviceDescriptor.getIfdName()), deviceDescriptor.getIfdId(), deviceListEntry); + auto modelEntry = RemoteDeviceModelEntry(deviceListEntry); presentReaders.append(modelEntry); } @@ -382,6 +406,7 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const const auto& reader = mAllRemoteReaders.at(pIndex.row()); switch (pRole) { + case Qt::DisplayRole: case REMOTE_DEVICE_NAME: return reader.getDeviceNameEscaped(); @@ -391,6 +416,8 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const case LAST_CONNECTED: { const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); return locale.toString(reader.getLastConnected(), dateTimeFormat); } @@ -407,8 +434,14 @@ QVariant RemoteDeviceModel::data(const QModelIndex& pIndex, int pRole) const case IS_PAIRED: return isPaired(pIndex); + case IS_PAIRING: + return isPairing(pIndex); + case LINK_QUALITY: return reader.getLinkQuality(); + + case IS_LAST_ADDED_DEVICE: + return mLastPairedDevice.getFingerprint() == reader.getId(); } return QVariant(); @@ -451,6 +484,17 @@ bool RemoteDeviceModel::isPaired(const QModelIndex& pIndex) const } +bool RemoteDeviceModel::isPairing(const QModelIndex& pIndex) const +{ + if (!indexIsValid(pIndex)) + { + return false; + } + + return mAllRemoteReaders.at(pIndex.row()).isPairing(); +} + + bool RemoteDeviceModel::isSupported(const QModelIndex& pIndex) const { if (!indexIsValid(pIndex)) @@ -585,6 +629,14 @@ QString RemoteDeviceModel::getEmptyListDescriptionString() const } +void RemoteDeviceModel::setLastPairedReader(const QSslCertificate& pCert) +{ + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + mLastPairedDevice = settings.getRemoteInfo(pCert); + Q_EMIT dataChanged(index(0), index(rowCount() - 1), {IS_LAST_ADDED_DEVICE}); +} + + void RemoteDeviceModel::onDeviceDisconnected(GlobalStatus::Code pCloseCode, const QString& pId) { Q_UNUSED(pCloseCode) diff --git a/src/ui/qml/RemoteDeviceModel.h b/src/ui/qml/RemoteDeviceModel.h index 5fe5a91a5..a0528886d 100644 --- a/src/ui/qml/RemoteDeviceModel.h +++ b/src/ui/qml/RemoteDeviceModel.h @@ -21,6 +21,7 @@ #include class test_RemoteDeviceModel; +class test_RemoteDeviceFilterModel; namespace governikus { @@ -33,6 +34,7 @@ class RemoteDeviceModelEntry QString mDeviceName; QString mId; bool mPaired; + bool mIsPairing; bool mNetworkVisible; bool mConnected; bool mSupported; @@ -40,20 +42,21 @@ class RemoteDeviceModelEntry QSharedPointer mRemoteDeviceListEntry; public: - RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& mId, - const QSharedPointer& pRemoteDeviceListEntry); + explicit RemoteDeviceModelEntry(const QSharedPointer& pListEntry); RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, const QString& mId, bool pNetworkVisible, bool pConnected, bool pSupported, + bool pIsPairing, const QDateTime& pLastConnected, const QSharedPointer& pRemoteDeviceListEntry); explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader")); [[nodiscard]] bool isPaired() const; void setPaired(bool pPaired); + [[nodiscard]] bool isPairing() const; + void setIsPairing(bool pIsPairing); [[nodiscard]] const QString& getId() const; void setId(const QString& pId); [[nodiscard]] bool isNetworkVisible() const; @@ -75,10 +78,12 @@ class RemoteDeviceModel Q_OBJECT Q_PROPERTY(QString emptyListDescriptionString READ getEmptyListDescriptionString NOTIFY fireModelChanged) friend class ::test_RemoteDeviceModel; + friend class ::test_RemoteDeviceFilterModel; private: QMap mPairedReaders; QVector mAllRemoteReaders; + RemoteServiceSettings::RemoteInfo mLastPairedDevice; const bool mShowPairedReaders; const bool mShowUnpairedReaders; QTimer mTimer; @@ -112,7 +117,9 @@ class RemoteDeviceModel IS_NETWORK_VISIBLE, IS_SUPPORTED, IS_PAIRED, - LINK_QUALITY + IS_PAIRING, + LINK_QUALITY, + IS_LAST_ADDED_DEVICE }; RemoteDeviceModel(QObject* pParent = nullptr, bool pShowPairedReaders = true, bool pShowUnpairedReaders = true); @@ -124,12 +131,15 @@ class RemoteDeviceModel [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QModelIndex& pIndex) const; [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QString& pDeviceId) const; [[nodiscard]] bool isPaired(const QModelIndex& pIndex) const; + [[nodiscard]] bool isPairing(const QModelIndex& pIndex) const; [[nodiscard]] bool isSupported(const QModelIndex& pIndex) const; void forgetDevice(const QModelIndex& pIndex); void forgetDevice(const QString& pDeviceId); [[nodiscard]] QString getEmptyListDescriptionString() const; + void setLastPairedReader(const QSslCertificate& pCert); + public Q_SLOTS: void setDetectRemoteDevices(bool pNewStatus); void onKnownRemoteReadersChanged(); diff --git a/src/ui/qml/RemoteServiceModel.cpp b/src/ui/qml/RemoteServiceModel.cpp index 1daf0816e..ad4e0707b 100644 --- a/src/ui/qml/RemoteServiceModel.cpp +++ b/src/ui/qml/RemoteServiceModel.cpp @@ -19,6 +19,12 @@ using namespace governikus; +namespace +{ +const QRegularExpression percentMatcher = QRegularExpression(QStringLiteral("(\\s|^)(100|\\d{1,2}) ?%")); +} // namespace + + RemoteServiceModel::RemoteServiceModel() : WorkflowModel() , mContext() @@ -28,8 +34,10 @@ RemoteServiceModel::RemoteServiceModel() , mPairingRequested(false) , mErrorMessage() , mPsk() - , mAvailableRemoteDevices(this, false, true) - , mKnownDevices(this, true, false) + , mAllDevices(this, true, true) + , mAvailableDevicesInPairingMode(&mAllDevices, RemoteDeviceFilterModel::showActivePairingMode) + , mAvailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showAvailableAndPaired) + , mUnavailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showUnavailableAndPaired) , mConnectionInfo() , mConnectedServerDeviceNames() , mRememberedServerEntry() @@ -42,6 +50,11 @@ RemoteServiceModel::RemoteServiceModel() , mRequiresLocalNetworkPermission(false) #endif { + QQmlEngine::setObjectOwnership(&mAllDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailableDevicesInPairingMode, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailablePairedDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mUnavailablePairedDevices, QQmlEngine::CppOwnership); + const auto readerManager = Env::getSingleton(); connect(readerManager, &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged); connect(readerManager, &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged); @@ -59,6 +72,14 @@ RemoteServiceModel::RemoteServiceModel() connect(ifdClient, &IfdClient::fireDeviceVanished, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged); connect(ifdClient, &IfdClient::fireCertificateRemoved, this, &RemoteServiceModel::fireCertificateRemoved); + connect(this, &WorkflowModel::fireReaderPlugInTypeChanged, this, &RemoteServiceModel::onReaderPlugInTypesChanged); + + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + connect(&settings, &RemoteServiceSettings::fireInitialDeviceNameSet, this, [](const QString& pName){ + //: LABEL ALL_PLATFORMS + Env::getSingleton()->showFeedback(tr("Pairing with %1 successful.").arg(pName)); + }); + QMetaObject::invokeMethod(this, &RemoteServiceModel::onEnvironmentChanged, Qt::QueuedConnection); } @@ -114,12 +135,44 @@ void RemoteServiceModel::onApplicationStateChanged(bool pIsAppInForeground) } +void RemoteServiceModel::onPairingCompleted(const QSslCertificate& pCertificate) +{ + mAllDevices.setLastPairedReader(pCertificate); + Q_EMIT firePairingCompleted(); +} + + void RemoteServiceModel::onTranslationChanged() { onEnvironmentChanged(); } +void RemoteServiceModel::onReaderPlugInTypesChanged(bool pExplicitStart) +{ + if (!mContext) + { + return; + } + + const auto& plugInType = getReaderPlugInType(); + if (mContext->getIfdServer() && mContext->getIfdServer()->getMessageHandler()) + { + mContext->getIfdServer()->getMessageHandler()->setAllowedCardTypes({plugInType}); + } + auto* readerManager = Env::getSingleton(); + readerManager->stopScanAll(); +#ifdef Q_OS_IOS + if (plugInType != ReaderManagerPlugInType::NFC || pExplicitStart) +#else + Q_UNUSED(pExplicitStart) +#endif + { + readerManager->startScan(plugInType); + } +} + + bool RemoteServiceModel::isRunning() const { return mContext ? mContext->isRunning() : false; @@ -170,22 +223,33 @@ bool RemoteServiceModel::isStarting() const } -RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices() +RemoteDeviceModel* RemoteServiceModel::getAllDevices() +{ + return &mAllDevices; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getAvailablePairedDevices() +{ + return &mAvailablePairedDevices; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getAvailableDevicesInPairingMode() { - return &mAvailableRemoteDevices; + return &mAvailableDevicesInPairingMode; } -RemoteDeviceModel* RemoteServiceModel::getKnownDevices() +RemoteDeviceFilterModel* RemoteServiceModel::getUnavailablePairedDevices() { - return &mKnownDevices; + return &mUnavailablePairedDevices; } void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus) { - mAvailableRemoteDevices.setDetectRemoteDevices(pNewStatus); - mKnownDevices.setDetectRemoteDevices(pNewStatus); + mAllDevices.setDetectRemoteDevices(pNewStatus); } @@ -208,9 +272,21 @@ void RemoteServiceModel::connectToRememberedServer(const QString& pServerPsk) } +QVector RemoteServiceModel::getSupportedReaderPlugInTypes() const +{ +#if __has_include("SmartManager.h") + return {ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SMART}; + +#else + return {ReaderManagerPlugInType::NFC}; + +#endif +} + + bool RemoteServiceModel::rememberServer(const QString& pDeviceId) { - mRememberedServerEntry = mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId); + mRememberedServerEntry = mAllDevices.getRemoteDeviceListEntry(pDeviceId); return !mRememberedServerEntry.isNull(); } @@ -227,7 +303,7 @@ void RemoteServiceModel::onEstablishConnectionDone(const QSharedPointer()->getRemoteServiceSettings(); - const QString peerName = settings.getRemoteInfo(mContext->getIfdServer()->getCurrentCertificate()).getNameEscaped(); //: INFO ANDROID IOS The smartphone is connected as card reader (SaK) and currently processing an authentication request. The user is asked to pay attention the its screen. - mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(peerName); + mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(getConnectedClientName()); Q_EMIT fireConnectionInfoChanged(); } + else if (mContext) + { + mContext->setReaderPlugInTypes({}); + } Q_EMIT fireConnectedChanged(); } @@ -275,8 +353,9 @@ void RemoteServiceModel::resetRemoteServiceContext(const QSharedPointergetIfdServer().data(), &IfdServer::firePskChanged, this, &RemoteServiceModel::firePskChanged); + connect(mContext.data(), &IfdServiceContext::fireDisplayTextChanged, this, &RemoteServiceModel::fireDisplayTextChanged); connect(mContext->getIfdServer().data(), &IfdServer::fireConnectedChanged, this, &RemoteServiceModel::onConnectionInfoChanged); - connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::firePairingCompleted); + connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::onPairingCompleted); connect(mContext.data(), &IfdServiceContext::fireCardConnected, this, &RemoteServiceModel::onCardConnected); connect(mContext.data(), &IfdServiceContext::fireCardDisconnected, this, &RemoteServiceModel::onCardDisconnected); connect(mContext.data(), &IfdServiceContext::fireEstablishPaceChannelUpdated, this, &RemoteServiceModel::fireEstablishPaceChannelUpdated); @@ -357,6 +436,20 @@ QByteArray RemoteServiceModel::getPsk() const } +QString RemoteServiceModel::getDisplayText() const +{ + QString displayText = mContext ? mContext->getDisplayText() : QString(); + return displayText.remove(percentMatcher); +} + + +int RemoteServiceModel::getPercentage() const +{ + QString displayText = mContext ? mContext->getDisplayText() : QString(); + return percentMatcher.match(displayText).captured(2).toInt(); +} + + QString RemoteServiceModel::getConnectionInfo() const { return mConnectionInfo; @@ -375,6 +468,25 @@ bool RemoteServiceModel::getRemoteReaderVisible() const } +QString RemoteServiceModel::getTransactionInfo() const +{ + return QString(); +} + + +QString RemoteServiceModel::getConnectedClientName() const +{ + if (mContext) + { + const auto& sslCertificate = mContext->getIfdServer()->getCurrentCertificate(); + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + return settings.getRemoteInfo(sslCertificate).getNameEscaped(); + } + + return QString(); +} + + bool RemoteServiceModel::pinPadModeOn() const { return Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); @@ -405,7 +517,7 @@ QString RemoteServiceModel::getErrorMessage(bool pNfcPluginAvailable, bool pNfcP void RemoteServiceModel::forgetDevice(const QString& pId) { - mKnownDevices.forgetDevice(pId); + mAllDevices.forgetDevice(pId); } diff --git a/src/ui/qml/RemoteServiceModel.h b/src/ui/qml/RemoteServiceModel.h index 6b1741e86..efc04af01 100644 --- a/src/ui/qml/RemoteServiceModel.h +++ b/src/ui/qml/RemoteServiceModel.h @@ -10,6 +10,7 @@ #include "Env.h" #include "ReaderManager.h" +#include "RemoteDeviceFilterModel.h" #include "RemoteDeviceModel.h" #include "WorkflowModel.h" #include "WorkflowRequest.h" @@ -34,15 +35,21 @@ class RemoteServiceModel Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY fireEnvironmentChanged) Q_PROPERTY(bool isPairing READ isPairing NOTIFY firePskChanged) Q_PROPERTY(QByteArray psk READ getPsk NOTIFY firePskChanged) + Q_PROPERTY(QString displayText READ getDisplayText NOTIFY fireDisplayTextChanged) + Q_PROPERTY(int percentage READ getPercentage NOTIFY fireDisplayTextChanged) Q_PROPERTY(bool connectedToPairedDevice READ isConnectedToPairedDevice NOTIFY fireConnectedChanged) Q_PROPERTY(QString connectionInfo READ getConnectionInfo NOTIFY fireConnectionInfoChanged) Q_PROPERTY(QString connectedServerDeviceNames READ getConnectedServerDeviceNames NOTIFY fireConnectedServerDeviceNamesChanged) - Q_PROPERTY(RemoteDeviceModel * availableRemoteDevices READ getAvailableRemoteDevices CONSTANT) - Q_PROPERTY(RemoteDeviceModel * knownDevices READ getKnownDevices CONSTANT) + Q_PROPERTY(RemoteDeviceModel * allDevices READ getAllDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availableDevicesInPairingMode READ getAvailableDevicesInPairingMode CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availablePairedDevices READ getAvailablePairedDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * unavailablePairedDevices READ getUnavailablePairedDevices CONSTANT) Q_PROPERTY(bool detectRemoteDevices READ detectRemoteDevices WRITE setDetectRemoteDevices NOTIFY fireDetectionChanged) Q_PROPERTY(bool enableTransportPinLink READ enableTransportPinLink NOTIFY fireEstablishPaceChannelUpdated) Q_PROPERTY(bool remoteReaderVisible READ getRemoteReaderVisible NOTIFY fireRemoteReaderVisibleChanged) Q_PROPERTY(bool requiresLocalNetworkPermission MEMBER mRequiresLocalNetworkPermission CONSTANT) + Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged) + Q_PROPERTY(QString connectedClientName READ getConnectedClientName NOTIFY fireConnectionInfoChanged) private: QSharedPointer mContext; @@ -52,8 +59,10 @@ class RemoteServiceModel bool mPairingRequested; QString mErrorMessage; QByteArray mPsk; - RemoteDeviceModel mAvailableRemoteDevices; - RemoteDeviceModel mKnownDevices; + RemoteDeviceModel mAllDevices; + RemoteDeviceFilterModel mAvailableDevicesInPairingMode; + RemoteDeviceFilterModel mAvailablePairedDevices; + RemoteDeviceFilterModel mUnavailablePairedDevices; QString mConnectionInfo; QString mConnectedServerDeviceNames; QSharedPointer mRememberedServerEntry; @@ -78,21 +87,27 @@ class RemoteServiceModel void onConnectedDevicesChanged(); void onEnvironmentChanged(); void onApplicationStateChanged(const bool pIsAppInForeground); + void onPairingCompleted(const QSslCertificate& pCertificate); public Q_SLOTS: void onTranslationChanged(); + void onReaderPlugInTypesChanged(bool pExplicitStart); public: [[nodiscard]] bool isRunning() const; Q_INVOKABLE void setRunning(bool pState, bool pEnablePairing = false); [[nodiscard]] bool isStarting() const; - [[nodiscard]] RemoteDeviceModel* getAvailableRemoteDevices(); - [[nodiscard]] RemoteDeviceModel* getKnownDevices(); + + [[nodiscard]] RemoteDeviceModel* getAllDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailableDevicesInPairingMode(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailablePairedDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getUnavailablePairedDevices(); void setDetectRemoteDevices(bool pNewStatus); [[nodiscard]] bool detectRemoteDevices() const; Q_INVOKABLE bool rememberServer(const QString& pDeviceId); Q_INVOKABLE void connectToRememberedServer(const QString& pServerPsk); + [[nodiscard]] QVector getSupportedReaderPlugInTypes() const override; void resetRemoteServiceContext(const QSharedPointer& pContext = QSharedPointer()); void setPairing(bool pEnabled); @@ -103,9 +118,13 @@ class RemoteServiceModel [[nodiscard]] bool isCanEnableNfc() const; [[nodiscard]] QString getErrorMessage() const; [[nodiscard]] QByteArray getPsk() const; + [[nodiscard]] QString getDisplayText() const; + [[nodiscard]] int getPercentage() const; [[nodiscard]] QString getConnectionInfo() const; [[nodiscard]] QString getConnectedServerDeviceNames() const; [[nodiscard]] bool getRemoteReaderVisible() const; + [[nodiscard]] QString getTransactionInfo() const; + [[nodiscard]] QString getConnectedClientName() const; [[nodiscard]] Q_INVOKABLE bool pinPadModeOn() const; Q_INVOKABLE void forgetDevice(const QString& pId); @@ -118,17 +137,19 @@ class RemoteServiceModel void fireIsRunningChanged(); void fireEnvironmentChanged(); void firePskChanged(const QByteArray& pPsk); + void fireDisplayTextChanged(); void fireConnectedChanged(); void fireServerPskChanged(); void fireDetectionChanged(); void firePairingFailed(const QString& pDeviceName, const QString& pErrorMessage); - void firePairingSuccess(const QString& pDeviceName); + void firePairingSuccess(); void firePairingCompleted(); void fireConnectionInfoChanged(); void fireConnectedServerDeviceNamesChanged(); void fireRemoteReaderVisibleChanged(); void fireEstablishPaceChannelUpdated(); void fireCertificateRemoved(const QString& pDeviceName); + void fireTransactionInfoChanged(); }; diff --git a/src/ui/qml/SettingsModel.cpp b/src/ui/qml/SettingsModel.cpp index 95e89d402..fb1ce3b60 100644 --- a/src/ui/qml/SettingsModel.cpp +++ b/src/ui/qml/SettingsModel.cpp @@ -165,8 +165,29 @@ bool SettingsModel::getPinPadMode() const void SettingsModel::setPinPadMode(bool pPinPadMode) { - auto& settings = Env::getSingleton()->getRemoteServiceSettings(); - settings.setPinPadMode(pPinPadMode); + if (getPinPadMode() != pPinPadMode) + { + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setPinPadMode(pPinPadMode); + Q_EMIT firePinPadModeChanged(); + } +} + + +bool SettingsModel::getShowAccessRights() const +{ + return Env::getSingleton()->getRemoteServiceSettings().getShowAccessRights(); +} + + +void SettingsModel::setShowAccessRights(bool pShowAccessRights) +{ + if (getShowAccessRights() != pShowAccessRights) + { + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setShowAccessRights(pShowAccessRights); + Q_EMIT fireShowAccessRightsChanged(); + } } diff --git a/src/ui/qml/SettingsModel.h b/src/ui/qml/SettingsModel.h index 77c8096f9..374de486c 100644 --- a/src/ui/qml/SettingsModel.h +++ b/src/ui/qml/SettingsModel.h @@ -31,6 +31,7 @@ class SettingsModel Q_PROPERTY(bool showBetaTesting MEMBER mShowBetaTesting NOTIFY fireDeveloperOptionsChanged) Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireDeveloperOptionsChanged) Q_PROPERTY(bool pinPadMode READ getPinPadMode WRITE setPinPadMode NOTIFY firePinPadModeChanged) + Q_PROPERTY(bool showAccessRights READ getShowAccessRights WRITE setShowAccessRights NOTIFY fireShowAccessRightsChanged) Q_PROPERTY(QString serverName READ getServerName WRITE setServerName NOTIFY fireDeviceNameChanged) Q_PROPERTY(bool historyEnabled READ isHistoryEnabled WRITE setHistoryEnabled NOTIFY fireHistoryEnabledChanged) Q_PROPERTY(bool useScreenKeyboard READ isUseScreenKeyboard WRITE setUseScreenKeyboard NOTIFY fireScreenKeyboardChanged) @@ -89,6 +90,9 @@ class SettingsModel [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); + [[nodiscard]] bool isHistoryEnabled() const; void setHistoryEnabled(bool pEnabled); @@ -156,6 +160,7 @@ class SettingsModel void fireDeveloperOptionsChanged(); void fireDeviceNameChanged(); void firePinPadModeChanged(); + void fireShowAccessRightsChanged(); void fireHistoryEnabledChanged(); void fireScreenKeyboardChanged(); void fireCanAllowedChanged(); diff --git a/src/ui/qml/UIPlugInQml.cpp b/src/ui/qml/UIPlugInQml.cpp index 7bbce886e..527fde531 100644 --- a/src/ui/qml/UIPlugInQml.cpp +++ b/src/ui/qml/UIPlugInQml.cpp @@ -407,6 +407,8 @@ void UIPlugInQml::onWorkflowStarted(QSharedPointer pContext) if (auto remoteServiceContext = pContext.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(remoteServiceContext); + Env::getSingleton()->resetContext(remoteServiceContext); + Env::getSingleton()->resetContext(remoteServiceContext); } } @@ -456,6 +458,8 @@ void UIPlugInQml::onWorkflowFinished(QSharedPointer pContext) if (pContext.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(); + Env::getSingleton()->resetContext(); + Env::getSingleton()->resetContext(); } #if __has_include("context/PersonalizationContext.h") diff --git a/src/ui/qml/WorkflowModel.cpp b/src/ui/qml/WorkflowModel.cpp index 081c4638c..d37c06f71 100644 --- a/src/ui/qml/WorkflowModel.cpp +++ b/src/ui/qml/WorkflowModel.cpp @@ -56,6 +56,7 @@ void WorkflowModel::resetWorkflowContext(const QSharedPointer& connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &WorkflowModel::fireResultChanged); connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireReaderPlugInTypeChanged); connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireSelectedReaderChanged); + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireHasCardChanged); connect(mContext.data(), &WorkflowContext::fireIsSmartCardAllowedChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged); connect(mContext.data(), &WorkflowContext::fireNextWorkflowPending, this, &WorkflowModel::fireNextWorkflowPendingChanged); connect(mContext.data(), &WorkflowContext::fireRemoveCardFeedbackChanged, this, &WorkflowModel::fireRemoveCardFeedbackChanged); @@ -159,11 +160,11 @@ void WorkflowModel::cancelWorkflow() } -void WorkflowModel::startScanIfNecessary() +void WorkflowModel::startScanExplicitly() { if (mContext) { - Q_EMIT mContext->fireReaderPlugInTypesChanged(); + Q_EMIT mContext->fireReaderPlugInTypesChanged(true); } } @@ -190,6 +191,19 @@ bool WorkflowModel::isRemoteReader() const } +bool WorkflowModel::hasCard() const +{ + if (!mContext) + { + return false; + } + + const auto& readerInfos = Env::getSingleton()->getReaderInfos(ReaderFilter({getReaderPlugInType()})); + const auto& readersWithEid = filter([](const ReaderInfo& i){return i.hasEid();}, readerInfos); + return !readersWithEid.isEmpty(); +} + + bool WorkflowModel::isSmartCardAllowed() const { if (!mContext) @@ -465,4 +479,6 @@ void WorkflowModel::onReaderManagerSignal() mReaderImage = newReaderImage; Q_EMIT fireReaderImageChanged(); } + + Q_EMIT fireHasCardChanged(); } diff --git a/src/ui/qml/WorkflowModel.h b/src/ui/qml/WorkflowModel.h index 287818f16..9012e6dba 100644 --- a/src/ui/qml/WorkflowModel.h +++ b/src/ui/qml/WorkflowModel.h @@ -39,6 +39,7 @@ class WorkflowModel Q_PROPERTY(QString statusHintText READ getStatusHintText NOTIFY fireResultChanged) Q_PROPERTY(QString statusHintActionText READ getStatusHintActionText NOTIFY fireResultChanged) Q_PROPERTY(bool showRemoveCardFeedback READ showRemoveCardFeedback WRITE setRemoveCardFeedback NOTIFY fireRemoveCardFeedbackChanged) + Q_PROPERTY(bool hasCard READ hasCard NOTIFY fireHasCardChanged) friend class ::test_WorkflowModel; private: @@ -65,6 +66,7 @@ class WorkflowModel [[nodiscard]] bool isBasicReader() const; [[nodiscard]] bool isRemoteReader() const; + [[nodiscard]] bool hasCard() const; [[nodiscard]] bool isSmartCardAllowed() const; @@ -86,7 +88,7 @@ class WorkflowModel Q_INVOKABLE void insertSmartCard(); Q_INVOKABLE void insertSimulator(); Q_INVOKABLE void cancelWorkflow(); - Q_INVOKABLE void startScanIfNecessary(); + Q_INVOKABLE void startScanExplicitly(); Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void setInitialPluginType(); [[nodiscard]] Q_INVOKABLE bool shouldSkipResultView() const; @@ -104,13 +106,14 @@ class WorkflowModel Q_SIGNALS: void fireCurrentStateChanged(const QString& pState); void fireResultChanged(); - void fireReaderPlugInTypeChanged(); + void fireReaderPlugInTypeChanged(bool pExplicitStart = false); void fireSelectedReaderChanged(); void fireIsSmartCardAllowedChanged(); void fireReaderImageChanged(); void fireNextWorkflowPendingChanged(); void fireSupportedPlugInTypesChanged(); void fireRemoveCardFeedbackChanged(); + void fireHasCardChanged(); }; diff --git a/src/workflows/base/context/AccessRightManager.cpp b/src/workflows/base/context/AccessRightManager.cpp index bb2051208..ac12beee0 100644 --- a/src/workflows/base/context/AccessRightManager.cpp +++ b/src/workflows/base/context/AccessRightManager.cpp @@ -71,6 +71,18 @@ AccessRightManager::AccessRightManager(QSharedPointer pDIDA } +AccessRightManager::AccessRightManager(QSharedPointer pRequiredChat) + : QObject() + , mTerminalCvc() + , mDIDAuthenticateEAC1() + , mOptionalAccessRights() + , mEffectiveAccessRights(pRequiredChat->getAccessRights()) + , mRequiredAccessRights(pRequiredChat->getAccessRights()) +{ + +} + + void AccessRightManager::removeForbiddenAccessRights(QSet& pAccessRights) { if (!mTerminalCvc) diff --git a/src/workflows/base/context/AccessRightManager.h b/src/workflows/base/context/AccessRightManager.h index 564bdfd70..b866fdbdc 100644 --- a/src/workflows/base/context/AccessRightManager.h +++ b/src/workflows/base/context/AccessRightManager.h @@ -29,6 +29,7 @@ class AccessRightManager public: explicit AccessRightManager(QSharedPointer pDIDAuthenticateEAC1, QSharedPointer pTerminalCvc); + explicit AccessRightManager(QSharedPointer pRequiredChat); [[nodiscard]] const QSharedPointer& getTerminalCvc() const diff --git a/src/workflows/base/context/WorkflowContext.cpp b/src/workflows/base/context/WorkflowContext.cpp index 26ee92ffe..21568799c 100644 --- a/src/workflows/base/context/WorkflowContext.cpp +++ b/src/workflows/base/context/WorkflowContext.cpp @@ -47,6 +47,7 @@ WorkflowContext::WorkflowContext(const Action pAction) , mProgressMessage() , mShowRemoveCardFeedback(false) , mClaimedBy() + , mInterruptRequested(false) { connect(this, &WorkflowContext::fireCancelWorkflow, this, &WorkflowContext::onWorkflowCancelled); } @@ -596,3 +597,15 @@ bool WorkflowContext::isPhysicalCardRequired() const || acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED) || acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE)); } + + +bool WorkflowContext::interruptRequested() const +{ + return mInterruptRequested; +} + + +void WorkflowContext::setInterruptRequested(bool pInterruptRequested) +{ + mInterruptRequested = pInterruptRequested; +} diff --git a/src/workflows/base/context/WorkflowContext.h b/src/workflows/base/context/WorkflowContext.h index cb439639f..c0e221316 100644 --- a/src/workflows/base/context/WorkflowContext.h +++ b/src/workflows/base/context/WorkflowContext.h @@ -66,6 +66,7 @@ class WorkflowContext QString mProgressMessage; bool mShowRemoveCardFeedback; QString mClaimedBy; + bool mInterruptRequested; private Q_SLOTS: void onWorkflowCancelled(); @@ -73,7 +74,7 @@ class WorkflowContext Q_SIGNALS: void fireStateApprovedChanged(bool pApproved); void fireStateChanged(const QString& pNewState); - void fireReaderPlugInTypesChanged(); + void fireReaderPlugInTypesChanged(bool pExplicitStart = false); void fireReaderInfoChanged(); void fireReaderNameChanged(); void fireCardConnectionChanged(); @@ -220,6 +221,9 @@ class WorkflowContext [[nodiscard]] virtual QVector getAcceptedEidTypes() const = 0; bool isPhysicalCardRequired() const; + + [[nodiscard]] bool interruptRequested() const; + void setInterruptRequested(bool pInterruptRequested); }; } // namespace governikus diff --git a/src/workflows/base/states/AbstractState.cpp b/src/workflows/base/states/AbstractState.cpp index b2bcf9279..05f8cab85 100644 --- a/src/workflows/base/states/AbstractState.cpp +++ b/src/workflows/base/states/AbstractState.cpp @@ -195,17 +195,6 @@ bool AbstractState::isStartStopEnabled() const } -void AbstractState::startNfcScanIfNecessary() -{ -#if defined(Q_OS_IOS) - if (isStartStopEnabled()) - { - Env::getSingleton()->startScan(ReaderManagerPlugInType::NFC); - } -#endif -} - - void AbstractState::stopNfcScanIfNecessary(const QString& pError) { #if defined(Q_OS_IOS) diff --git a/src/workflows/base/states/AbstractState.h b/src/workflows/base/states/AbstractState.h index afb6035bd..876aa1076 100644 --- a/src/workflows/base/states/AbstractState.h +++ b/src/workflows/base/states/AbstractState.h @@ -47,7 +47,6 @@ class AbstractState void updateStatus(const GlobalStatus& pStatus); void updateStartPaosResult(const ECardApiResult& pStartPaosResult); - void startNfcScanIfNecessary(); void stopNfcScanIfNecessary(const QString& pError = QString()); public: diff --git a/src/workflows/base/states/StateCheckRefreshAddress.cpp b/src/workflows/base/states/StateCheckRefreshAddress.cpp index 76dc288fc..c2cfddfe5 100644 --- a/src/workflows/base/states/StateCheckRefreshAddress.cpp +++ b/src/workflows/base/states/StateCheckRefreshAddress.cpp @@ -173,7 +173,7 @@ void StateCheckRefreshAddress::onSslErrors(const QList& pErrors) if (TlsChecker::containsFatalError(mReply, pErrors)) { reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_Before_Reply); } } @@ -273,7 +273,7 @@ void StateCheckRefreshAddress::onNetworkReply() case NetworkManager::NetworkError::SecurityError: reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_After_Reply, mReply->errorString()); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_After_Reply, mReply->errorString()); break; case NetworkManager::NetworkError::OtherError: diff --git a/src/workflows/base/states/StateCleanUpReaderManager.cpp b/src/workflows/base/states/StateCleanUpReaderManager.cpp index d1a979dcd..039f85c00 100644 --- a/src/workflows/base/states/StateCleanUpReaderManager.cpp +++ b/src/workflows/base/states/StateCleanUpReaderManager.cpp @@ -21,9 +21,7 @@ StateCleanUpReaderManager::StateCleanUpReaderManager(const QSharedPointer context = getContext(); - - const auto& reader = context->getReaderName(); - if (!reader.isEmpty() && !context->getStatus().isError()) + if (const auto& reader = context->getReaderName(); !reader.isEmpty()) { const auto& readerInfo = Env::getSingleton()->getReaderInfo(reader); if (readerInfo.hasCard() && readerInfo.getCardInfo().getCardType() != CardType::SMART_EID) diff --git a/src/workflows/base/states/StateDidAuthenticateEac2.cpp b/src/workflows/base/states/StateDidAuthenticateEac2.cpp index f8dfbae4d..0737a6961 100644 --- a/src/workflows/base/states/StateDidAuthenticateEac2.cpp +++ b/src/workflows/base/states/StateDidAuthenticateEac2.cpp @@ -62,8 +62,8 @@ void StateDidAuthenticateEac2::onCardCommandDone(QSharedPointer newStatus = GlobalStatus::Code::Workflow_Card_Removed; break; - case CardReturnCode::EXTENDED_LENGTH_MISSING: - newStatus = GlobalStatus::Code::Workflow_No_Extended_Length_Error; + case CardReturnCode::WRONG_LENGTH: + newStatus = GlobalStatus::Code::Workflow_Wrong_Length_Error; break; default: diff --git a/src/workflows/base/states/StateEnterPacePassword.cpp b/src/workflows/base/states/StateEnterPacePassword.cpp index 8811ae385..be4ef387f 100644 --- a/src/workflows/base/states/StateEnterPacePassword.cpp +++ b/src/workflows/base/states/StateEnterPacePassword.cpp @@ -4,6 +4,7 @@ #include "StateEnterPacePassword.h" +#include "ReaderManager.h" #include "VolatileSettings.h" @@ -14,6 +15,9 @@ StateEnterPacePassword::StateEnterPacePassword(const QSharedPointer(); + mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateEnterPacePassword::onReaderStatusChanged); + setKeepCardConnectionAlive(); } @@ -49,3 +53,29 @@ void StateEnterPacePassword::onEntry(QEvent* pEvent) AbstractState::onEntry(pEvent); } + + +void StateEnterPacePassword::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const +{ +#if defined(Q_OS_IOS) + const auto& volatileSettings = Env::getSingleton(); + if (!volatileSettings->isUsedAsSDK() || pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) + { + return; + } + + if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) + { + if (getContext()->interruptRequested()) + { + getContext()->setInterruptRequested(false); + } + else + { + Q_EMIT getContext()->fireCancelWorkflow(); + } + } +#else + Q_UNUSED(pInfo) +#endif +} diff --git a/src/workflows/base/states/StateEnterPacePassword.h b/src/workflows/base/states/StateEnterPacePassword.h index f2743e14a..869348d24 100644 --- a/src/workflows/base/states/StateEnterPacePassword.h +++ b/src/workflows/base/states/StateEnterPacePassword.h @@ -25,6 +25,9 @@ class StateEnterPacePassword explicit StateEnterPacePassword(const QSharedPointer& pContext); void run() override; + private Q_SLOTS: + void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const; + public: void onEntry(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateEstablishPaceChannel.cpp b/src/workflows/base/states/StateEstablishPaceChannel.cpp index 5eee4101f..52b7609d1 100644 --- a/src/workflows/base/states/StateEstablishPaceChannel.cpp +++ b/src/workflows/base/states/StateEstablishPaceChannel.cpp @@ -22,21 +22,24 @@ StateEstablishPaceChannel::StateEstablishPaceChannel(const QSharedPointergetStatus().isError()) + const auto& context = getContext(); + Q_ASSERT(context); + + if (context->getStatus().isError()) { - Q_ASSERT(getContext()->getFailureCode().has_value()); + Q_ASSERT(context->getFailureCode().has_value()); Q_EMIT firePaceChannelFailed(); return; } QByteArray effectiveChat; QByteArray certificateDescription; - auto authContext = getContext().objectCast(); - mPasswordId = getContext()->getEstablishPaceChannelType(); + const auto& authContext = context.objectCast(); + mPasswordId = context->getEstablishPaceChannelType(); Q_ASSERT(mPasswordId != PacePasswordId::UNKNOWN); if (mPasswordId == PacePasswordId::PACE_PIN || - (mPasswordId == PacePasswordId::PACE_CAN && getContext()->isCanAllowedMode())) + (mPasswordId == PacePasswordId::PACE_CAN && context->isCanAllowedMode())) { if (authContext && authContext->getDidAuthenticateEac1()) { @@ -55,15 +58,15 @@ void StateEstablishPaceChannel::run() switch (mPasswordId) { case PacePasswordId::PACE_CAN: - password = getContext()->getCan().toLatin1(); + password = context->getCan().toLatin1(); break; case PacePasswordId::PACE_PIN: - password = getContext()->getPin().toLatin1(); + password = context->getPin().toLatin1(); break; case PacePasswordId::PACE_PUK: - password = getContext()->getPuk().toLatin1(); + password = context->getPuk().toLatin1(); break; case PacePasswordId::UNKNOWN: @@ -72,11 +75,11 @@ void StateEstablishPaceChannel::run() break; } - auto cardConnection = getContext()->getCardConnection(); + auto cardConnection = context->getCardConnection(); if (!cardConnection) { qCDebug(statemachine) << "No card connection available."; - getContext()->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND); + context->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND); Q_EMIT fireNoCardConnection(); return; } @@ -91,12 +94,15 @@ void StateEstablishPaceChannel::run() return; } + //: INFO ALL_PLATFORMS First status message after the PIN was entered. + context->setProgress(0, tr("The secure channel is opened")); + qDebug() << "Establish connection using" << mPasswordId; Q_ASSERT(!password.isEmpty() || !cardConnection->getReaderInfo().isBasicReader()); if (mPasswordId == PacePasswordId::PACE_PIN && !cardConnection->getReaderInfo().isBasicReader()) { - const auto pinContext = getContext().objectCast(); + const auto pinContext = context.objectCast(); if (pinContext && pinContext->isRequestTransportPin()) { password = QByteArray(5, 0); diff --git a/src/workflows/base/states/StateGenericProviderCommunication.cpp b/src/workflows/base/states/StateGenericProviderCommunication.cpp index 50c5b4214..ce66842f8 100644 --- a/src/workflows/base/states/StateGenericProviderCommunication.cpp +++ b/src/workflows/base/states/StateGenericProviderCommunication.cpp @@ -124,7 +124,7 @@ void StateGenericProviderCommunication::onSslErrors(const QList& pErr } const GlobalStatus& status = {GlobalStatus::Code::Network_Ssl_Establishment_Error, infoMap}; - const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Ssl_Error, + const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Tls_Error, { {FailureCode::Info::Network_Error, mReply->errorString()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)}, diff --git a/src/workflows/base/states/StateGenericSendReceive.cpp b/src/workflows/base/states/StateGenericSendReceive.cpp index 9e4f6b5ef..3289ffb08 100644 --- a/src/workflows/base/states/StateGenericSendReceive.cpp +++ b/src/workflows/base/states/StateGenericSendReceive.cpp @@ -102,7 +102,7 @@ void StateGenericSendReceive::onSslErrors(const QList& pErrors) {FailureCode::Info::State_Name, getStateName()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)} }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Ssl_Error, infoMap}); + Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Tls_Error, infoMap}); } } diff --git a/src/workflows/base/states/StateMaintainCardConnection.cpp b/src/workflows/base/states/StateMaintainCardConnection.cpp index e66d70d90..62e2392db 100644 --- a/src/workflows/base/states/StateMaintainCardConnection.cpp +++ b/src/workflows/base/states/StateMaintainCardConnection.cpp @@ -42,7 +42,7 @@ void StateMaintainCardConnection::run() case CardReturnCode::UNDEFINED: case CardReturnCode::COMMAND_FAILED: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: { Q_ASSERT(!CardReturnCodeUtil::equalsWrongPacePassword(lastPaceResult)); diff --git a/src/workflows/base/states/StatePreVerification.cpp b/src/workflows/base/states/StatePreVerification.cpp index 4e203d6da..5576dfa44 100644 --- a/src/workflows/base/states/StatePreVerification.cpp +++ b/src/workflows/base/states/StatePreVerification.cpp @@ -53,7 +53,7 @@ void StatePreVerification::run() { qCritical() << "Using the developer mode is only allowed in a test environment"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_No_Test_Environment); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_No_Test_Environment); return; } @@ -68,14 +68,14 @@ void StatePreVerification::run() { qCritical() << "Pre-verification failed: cannot build certificate chain"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); return; } else if (!SignatureChecker(certificateChain).check()) { qCritical() << "Pre-verification failed: signature check failed"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); return; } else if (!isValid(certificateChain)) @@ -88,7 +88,7 @@ void StatePreVerification::run() { qCritical() << "Pre-verification failed: certificate not valid"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Certificate_Expired); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Certificate_Expired); return; } } diff --git a/src/workflows/ifd/context/IfdServiceContext.cpp b/src/workflows/ifd/context/IfdServiceContext.cpp index cc7145c83..ca3d059a9 100644 --- a/src/workflows/ifd/context/IfdServiceContext.cpp +++ b/src/workflows/ifd/context/IfdServiceContext.cpp @@ -28,10 +28,12 @@ IfdServiceContext::IfdServiceContext(const QSharedPointer& pIfdServer , mIfdServer(pIfdServer) , mNewPin() , mSlotHandle() + , mDisplayText() , mEstablishPaceChannel() , mRequestTransportPin(false) , mAllowToChangePinLength(false) , mEstablishPaceChannelOutput() + , mAccessRightManager() , mModifyPinMessage() , mModifyPinMessageResponseApdu() { @@ -116,10 +118,18 @@ void IfdServiceContext::setEstablishPaceChannel(const QSharedPointergetInputData(); mRequestTransportPin = pMessage->getExpectedPinLength() == 5; mAllowToChangePinLength = isPinChangeWorkflow() && pMessage->getExpectedPinLength() == 0; + const auto& chat = mEstablishPaceChannel.getChat(); + if (!chat.isEmpty()) + { + const auto& requiredChat = CHAT::decode(chat); + mAccessRightManager = QSharedPointer::create(requiredChat); + Q_EMIT fireAccessRightManagerCreated(mAccessRightManager); + } } else { mSlotHandle.clear(); + mAccessRightManager.clear(); mEstablishPaceChannel = EstablishPaceChannel(); mRequestTransportPin = false; mAllowToChangePinLength = false; @@ -139,12 +149,46 @@ const QString& IfdServiceContext::getSlotHandle() const } +void IfdServiceContext::setDisplayText(const QString& pDisplayText) +{ + if (mDisplayText != pDisplayText) + { + mDisplayText = pDisplayText; + Q_EMIT fireDisplayTextChanged(); + } +} + + +const QString& IfdServiceContext::getDisplayText() const +{ + return mDisplayText; +} + + const EstablishPaceChannel& IfdServiceContext::getEstablishPaceChannel() const { return mEstablishPaceChannel; } +QSharedPointer IfdServiceContext::getAccessRightManager() const +{ + return mAccessRightManager; +} + + +QSharedPointer IfdServiceContext::getCertificateDescription() const +{ + const auto& certDescription = mEstablishPaceChannel.getCertificateDescription(); + if (certDescription.isEmpty()) + { + return QSharedPointer(); + } + + return CertificateDescription::decode(certDescription); +} + + void IfdServiceContext::changePinLength() { if (isPinChangeWorkflow()) @@ -232,9 +276,5 @@ void IfdServiceContext::reset() [[nodiscard]] QVector IfdServiceContext::getAcceptedEidTypes() const { - if (mIfdServer->isLocal()) - { - return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; - } - return {AcceptedEidType::CARD_CERTIFIED}; + return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; } diff --git a/src/workflows/ifd/context/IfdServiceContext.h b/src/workflows/ifd/context/IfdServiceContext.h index 986ee691c..25430d601 100644 --- a/src/workflows/ifd/context/IfdServiceContext.h +++ b/src/workflows/ifd/context/IfdServiceContext.h @@ -9,6 +9,8 @@ #pragma once #include "IfdServer.h" +#include "asn1/CertificateDescription.h" +#include "context/AccessRightManager.h" #include "context/WorkflowContext.h" #include "messages/IfdEstablishPaceChannel.h" #include "messages/IfdModifyPin.h" @@ -32,10 +34,12 @@ class IfdServiceContext QString mNewPin; QString mSlotHandle; + QString mDisplayText; EstablishPaceChannel mEstablishPaceChannel; bool mRequestTransportPin; bool mAllowToChangePinLength; EstablishPaceChannelOutput mEstablishPaceChannelOutput; + QSharedPointer mAccessRightManager; QSharedPointer mModifyPinMessage; ResponseApdu mModifyPinMessageResponseApdu; @@ -47,10 +51,12 @@ class IfdServiceContext Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); + void fireDisplayTextChanged(); void fireCardDisconnected(const QSharedPointer& pConnection); void fireCancelPasswordRequest(); void fireEstablishPaceChannelUpdated(); void fireIsRunningChanged(); + void fireAccessRightManagerCreated(QSharedPointer pAccessRightManager); public: explicit IfdServiceContext(const QSharedPointer& pIfdServer); @@ -70,7 +76,11 @@ class IfdServiceContext void setEstablishPaceChannel(const QSharedPointer& pMessage); [[nodiscard]] const QString& getSlotHandle() const; + void setDisplayText(const QString& pDisplayText); + [[nodiscard]] const QString& getDisplayText() const; [[nodiscard]] const EstablishPaceChannel& getEstablishPaceChannel() const; + [[nodiscard]] QSharedPointer getAccessRightManager() const; + [[nodiscard]] QSharedPointer getCertificateDescription() const; void changePinLength(); [[nodiscard]] bool allowToChangePinLength() const; diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.cpp b/src/workflows/ifd/states/StateProcessIfdMessages.cpp index e94515f26..a0b405141 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.cpp +++ b/src/workflows/ifd/states/StateProcessIfdMessages.cpp @@ -29,10 +29,7 @@ void StateProcessIfdMessages::run() const QSharedPointer server = context->getIfdServer(); Q_ASSERT(server); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireStatusChanged, this, &StateProcessIfdMessages::onReaderStatusChanged); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireReaderPropertiesUpdated, this, &StateProcessIfdMessages::onReaderPropertiesUpdated); mConnections += connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded); - mConnections += connect(server.data(), &IfdServer::fireConnectedChanged, this, &StateProcessIfdMessages::onConnectedChanged); const auto messageHandler = server->getMessageHandler(); if (messageHandler) @@ -54,6 +51,7 @@ void StateProcessIfdMessages::onMessageHandlerAdded(const QSharedPointergetIfdServer()->isPairingConnection()) - { - startNfcScanIfNecessary(); - Env::getSingleton()->startScan(ReaderManagerPlugInType::SMART); - } - else - { - stopNfcScanIfNecessary(); - Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); - } -} - - void StateProcessIfdMessages::onClosed() { qCDebug(statemachine) << "ServerMessageHandler closed"; @@ -90,42 +73,15 @@ void StateProcessIfdMessages::onClosed() } -void StateProcessIfdMessages::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) -{ - if (pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) - { - return; - } - - if (Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) - { - return; - } - - const auto& context = getContext(); - if (context->getIfdServer()->isConnected()) - { - qCDebug(statemachine) << "Stopping IfdService because NFC was disabled."; - Q_EMIT fireContinue(); - } -} - - -void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo) +void StateProcessIfdMessages::onCardConnected() { - if (Env::getSingleton()->isUsedAsSDK()) - { - if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE) - { - Env::getSingleton()->insert(pInfo); - } - } + mResetContextOnDisconnect = false; } -void StateProcessIfdMessages::onCardConnected() +void StateProcessIfdMessages::onDisplayTextChanged(const QString& pDisplayText) const { - mResetContextOnDisconnect = false; + getContext()->setDisplayText(pDisplayText); } @@ -158,6 +114,7 @@ void StateProcessIfdMessages::onModifyPin(const QSharedPointersetDisplayText(QString()); if (mResetContextOnDisconnect) { getContext()->reset(); @@ -165,14 +122,6 @@ void StateProcessIfdMessages::onCardDisconnected() } -void StateProcessIfdMessages::onEntry(QEvent* pEvent) -{ - onConnectedChanged(getContext()->getIfdServer()->isConnected()); - - AbstractState::onEntry(pEvent); -} - - void StateProcessIfdMessages::onExit(QEvent* pEvent) { for (const auto& connection : std::as_const(mMessageConnections)) diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.h b/src/workflows/ifd/states/StateProcessIfdMessages.h index cbf89918e..8bd63b714 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.h +++ b/src/workflows/ifd/states/StateProcessIfdMessages.h @@ -10,7 +10,6 @@ #pragma once -#include "ReaderManager.h" #include "context/IfdServiceContext.h" #include "states/AbstractState.h" #include "states/GenericContextContainer.h" @@ -38,16 +37,13 @@ class StateProcessIfdMessages private Q_SLOTS: void onMessageHandlerAdded(const QSharedPointer& pHandler); void onClosed(); - void onConnectedChanged(bool pConnected); - void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo); - void onReaderPropertiesUpdated(const ReaderInfo& pInfo); void onCardConnected(); + void onDisplayTextChanged(const QString& pDisplayText) const; void onModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void onCardDisconnected(); protected: - void onEntry(QEvent* pEvent) override; void onExit(QEvent* pEvent) override; public: diff --git a/src/workflows/selfauth/SelfAuthenticationData.cpp b/src/workflows/selfauth/SelfAuthenticationData.cpp index 0d2b80abf..9d6b930c0 100644 --- a/src/workflows/selfauth/SelfAuthenticationData.cpp +++ b/src/workflows/selfauth/SelfAuthenticationData.cpp @@ -248,8 +248,11 @@ void SelfAuthenticationData::SelfData::addAddress(OrderedSelfData& pSelfData) co QString SelfAuthenticationData::SelfData::formatDate(const QString& pDate) { static const QVector> formattingPattern({ + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString qMakePair(QStringLiteral("yyyy-MM-dd+hh:mm"), QLatin1String(QT_TR_NOOP("dd.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day qMakePair(QStringLiteral("yyyy-MM"), QLatin1String(QT_TR_NOOP("xx.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month qMakePair(QStringLiteral("yyyy"), QLatin1String(QT_TR_NOOP("xx.xx.yyyy"))), }); diff --git a/test/helper/ifd/MockDataChannel.cpp b/test/helper/ifd/MockDataChannel.cpp index 1668e8848..22fc30071 100644 --- a/test/helper/ifd/MockDataChannel.cpp +++ b/test/helper/ifd/MockDataChannel.cpp @@ -10,8 +10,9 @@ using namespace governikus; -MockDataChannel::MockDataChannel() - : mId(QUuid::createUuid().toString()) +MockDataChannel::MockDataChannel(bool pPairing) + : mPairing(pPairing) + , mId(QUuid::createUuid().toString()) , mReceivedDataBlocks() { } @@ -28,6 +29,12 @@ void MockDataChannel::close() } +bool MockDataChannel::isPairingConnection() const +{ + return mPairing; +} + + const QString& MockDataChannel::getId() const { return mId; diff --git a/test/helper/ifd/MockDataChannel.h b/test/helper/ifd/MockDataChannel.h index 24e4e4b46..ecb615eed 100644 --- a/test/helper/ifd/MockDataChannel.h +++ b/test/helper/ifd/MockDataChannel.h @@ -22,15 +22,17 @@ class MockDataChannel Q_OBJECT private: + bool mPairing; QString mId; QVector mReceivedDataBlocks; public: - MockDataChannel(); + explicit MockDataChannel(bool pPairing = false); ~MockDataChannel() override; void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; void closeAbnormal(); diff --git a/test/helper/ifd/MockIfdDispatcher.cpp b/test/helper/ifd/MockIfdDispatcher.cpp index 480fa1ff4..065286cba 100644 --- a/test/helper/ifd/MockIfdDispatcher.cpp +++ b/test/helper/ifd/MockIfdDispatcher.cpp @@ -24,12 +24,25 @@ using namespace governikus; MockIfdDispatcher::MockIfdDispatcher(DispatcherState pState) : IfdDispatcherClient(IfdVersion::Version::v2, QSharedPointer::create()) , mState(pState) + , mPairing(false) , mId(QUuid::createUuid().toString()) , mContextHandle(QStringLiteral("#TestContext")) { } +void MockIfdDispatcher::setPairingConnection(bool pPairing) +{ + mPairing = pPairing; +} + + +bool MockIfdDispatcher::isPairingConnection() const +{ + return mPairing; +} + + QString MockIfdDispatcher::getId() const { return mId; diff --git a/test/helper/ifd/MockIfdDispatcher.h b/test/helper/ifd/MockIfdDispatcher.h index 47580fea2..c4a89614b 100644 --- a/test/helper/ifd/MockIfdDispatcher.h +++ b/test/helper/ifd/MockIfdDispatcher.h @@ -30,12 +30,15 @@ class MockIfdDispatcher private: DispatcherState mState; + bool mPairing; QString mId; QString mContextHandle; public: MockIfdDispatcher(DispatcherState pState = DispatcherState::WithoutReader); + void setPairingConnection(bool pPairing); + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] QString getId() const override; [[nodiscard]] const QString& getContextHandle() const override; Q_INVOKABLE void send(const QSharedPointer& pMessage) override; diff --git a/test/qml/Global/test_GButton.qml b/test/qml/Global/test_GButton.qml index a66b7ad40..48538e0e7 100644 --- a/test/qml/Global/test_GButton.qml +++ b/test/qml/Global/test_GButton.qml @@ -32,17 +32,13 @@ TestCase { } function test_size(data) { let button = createTemporaryQmlObject("import Governikus.Global 1.0; GButton {icon.source: \"" + data.icon + "\"; text: \"" + data.text + "\"}", testCase); - waitForRendering(button); - compare(button.height, data.height); - compare(button.width, data.width); + tryCompare(button, "height", data.height); + tryCompare(button, "width", data.width); } function test_size_data() { - if (Qt.platform.os !== "osx") { - skip(); - } let text = createTemporaryQmlObject("import Governikus.Global 1.0; import Governikus.Style 1.0; GText {textStyle: Style.text.button; text: \"test test test test test test\"}", testCase); - waitForRendering(text); - let longTextWidth = Math.round(text.width + 0.1); + verify(waitForRendering(text)); + let longTextWidth = Math.ceil(text.width); return [{ "tag": "noIconNoText", "icon": "", @@ -72,7 +68,7 @@ TestCase { "icon": "qrc:///images/identify.svg", "text": "t", "height": Constants.is_desktop ? 39 : 40, - "width": Constants.is_desktop ? 59 : 112 + "width": Constants.is_desktop ? (Qt.platform.os === "linux" ? 64 : 59) : 112 }, { "tag": "withIconLongText", "icon": "qrc:///images/identify.svg", diff --git a/test/qt/configuration/test_ProviderConfiguration.cpp b/test/qt/configuration/test_ProviderConfiguration.cpp index 9bc73f3a5..45a15dd50 100644 --- a/test/qt/configuration/test_ProviderConfiguration.cpp +++ b/test/qt/configuration/test_ProviderConfiguration.cpp @@ -302,7 +302,7 @@ class test_ProviderConfiguration } } - QCOMPARE(attachedEidCounter, 20); + QCOMPARE(attachedEidCounter, 21); } diff --git a/test/qt/configuration/test_ProviderConfigurationParser.cpp b/test/qt/configuration/test_ProviderConfigurationParser.cpp index 447c0c4e6..ea39abd2d 100644 --- a/test/qt/configuration/test_ProviderConfigurationParser.cpp +++ b/test/qt/configuration/test_ProviderConfigurationParser.cpp @@ -224,8 +224,8 @@ class test_ProviderConfigurationParser QTest::addColumn("majorVersion"); QTest::addColumn("count"); - const int all = 113; - const int withEidSupport = 91; + const int all = 120; + const int withEidSupport = 98; QTest::newRow("win") << QOperatingSystemVersion::Windows << -1 << all; QTest::newRow("mac") << QOperatingSystemVersion::MacOS << -1 << all; QTest::newRow("linux") << QOperatingSystemVersion::Unknown << -1 << all; diff --git a/test/qt/global/test_LogHandler.cpp b/test/qt/global/test_LogHandler.cpp index cb6dfe095..a003cfecb 100644 --- a/test/qt/global/test_LogHandler.cpp +++ b/test/qt/global/test_LogHandler.cpp @@ -447,6 +447,12 @@ class test_LogHandler QTest::newRow("createSingleton") << QByteArray("T* governikus::Env::createSingleton() [with T = governikus::AppUpdater]") << QByteArray("Env::createSingleton"); + QTest::newRow("createSingletonPtr") << QByteArray("T *governikus::Env::createSingleton() [T = governikus::NetworkManager]") + << QByteArray("Env::createSingleton"); + + QTest::newRow("processUpdaterRequest") << QByteArray("auto governikus::NetworkManager::processUpdaterRequest(QNetworkRequest &, const std::function (QNetworkRequest &)> &)::(anonymous class)::operator()() const") + << QByteArray("NetworkManager::processUpdaterRequest"); + QTest::newRow("printInfo") << QByteArray("void printInfo()") << QByteArray("printInfo"); @@ -466,6 +472,8 @@ class test_LogHandler QTest::newRow("UILoader::load") << QByteArray("std::enable_if_t::value, bool> governikus::UILoader::load() const [with T = governikus::UIPlugInJson; std::enable_if_t::value, bool> = bool]") << QByteArray("UILoader::load"); + QTest::newRow("anonymous") << QByteArray("virtual QList (anonymous namespace)::SystemProxyFactory::queryProxy(const QNetworkProxyQuery &)") + << QByteArray("SystemProxyFactory::queryProxy"); } @@ -481,6 +489,15 @@ class test_LogHandler } + void formatFunctionNullptr() + { + const auto* handler = Env::getSingleton(); + const auto& formattedFunction = handler->formatFunction(nullptr, QByteArray(), 1811); + + QCOMPARE(formattedFunction, QByteArray()); + } + + }; QTEST_GUILESS_MAIN(test_LogHandler) diff --git a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp index 4b2e81f5b..ac743d157 100644 --- a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp @@ -111,9 +111,11 @@ class test_RemoteIfdReaderManagerPlugIn Env::set(RemoteIfdClient::staticMetaObject, mIfdClient.data()); mDispatcher1.reset(new MockIfdDispatcher()); + mDispatcher1->setPairingConnection(false); mDispatcher1->moveToThread(&mNetworkThread); mDispatcher2.reset(new MockIfdDispatcher()); + mDispatcher2->setPairingConnection(true); mDispatcher2->moveToThread(&mNetworkThread); mPlugin.reset(new RemoteIfdReaderManagerPlugIn()); @@ -525,6 +527,34 @@ class test_RemoteIfdReaderManagerPlugIn } + void testKeepNormalConnection() + { + QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher1); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + spySend.clear(); + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher1->getId()); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + QSharedPointer result = qvariant_cast>(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), IfdMessageType::IFDGetStatus); + } + + + void testClosePairingConnection() + { + QSignalSpy spySend(mDispatcher2.data(), &MockIfdDispatcher::fireSend); + QSignalSpy spyClosed(mDispatcher2.data(), &MockIfdDispatcher::fireClosed); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher2); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher2->getId()); + QTRY_COMPARE(spyClosed.count(), 1); // clazy:exclude=qstring-allocations + } + + }; QTEST_GUILESS_MAIN(test_RemoteIfdReaderManagerPlugIn) diff --git a/test/qt/ifd/remote/test_RemoteIfdServer.cpp b/test/qt/ifd/remote/test_RemoteIfdServer.cpp index 9ae1000b3..ea6488b87 100644 --- a/test/qt/ifd/remote/test_RemoteIfdServer.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdServer.cpp @@ -98,6 +98,12 @@ class RemoteWebSocketServerMock } + [[nodiscard]] bool isPairingAnnounced() const override + { + return mPairing; + } + + void setPairing(bool pEnabled = true) override { mPairing = pEnabled; @@ -159,11 +165,11 @@ class test_RemoteIfdServer private Q_SLOTS: void init() { - std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort){ + std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool&){ mAdvertiserMock = new RemoteReaderAdvertiserMock(pIfdName, pIfdId, pPort); return mAdvertiserMock; }; - Env::setCreator(creator); + Env::setCreator(creator); std::function creator2 = [this](){ mWebSocketMock = new RemoteWebSocketServerMock(); return mWebSocketMock; diff --git a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp index e1cd78291..09ad044b5 100644 --- a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp +++ b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp @@ -19,9 +19,9 @@ namespace governikus { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pTimerInterval, bool& pPairing) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pInterval, bool& pPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pTimerInterval, pPairing); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pPairing, pInterval); } diff --git a/test/qt/ifd/remote/test_RemoteTlsServer.cpp b/test/qt/ifd/remote/test_RemoteTlsServer.cpp index 6e431255c..d8ad1eb2c 100644 --- a/test/qt/ifd/remote/test_RemoteTlsServer.cpp +++ b/test/qt/ifd/remote/test_RemoteTlsServer.cpp @@ -57,6 +57,7 @@ class test_RemoteTlsServer RemoteTlsServer server; server.setPairing(serverPairing); server.startListening(0); + QCOMPARE(server.hasPsk(), serverPairing); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(clientConfig).getConfiguration(); config.setPrivateKey(pair.getKey()); @@ -91,6 +92,7 @@ class test_RemoteTlsServer }); server.setPairing(); server.startListening(0); + QVERIFY(server.hasPsk()); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getConfiguration(); config.setPrivateKey(pair.getKey()); diff --git a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp index 7cd8b282c..0b9f3fcc0 100644 --- a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp +++ b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp @@ -176,6 +176,7 @@ class test_RemoteWebSocketServer PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + QVERIFY(mServer->isPairingAnnounced()); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); @@ -279,6 +280,7 @@ class test_RemoteWebSocketServer PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + QVERIFY(mServer->isPairingAnnounced()); QTRY_COMPARE(newConnectionSpy.count(), 1); // clazy:exclude=qstring-allocations QTRY_COMPARE(serverConnectedSpy.count(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/ifd/test_IfdConnector.cpp b/test/qt/ifd/test_IfdConnector.cpp index a3ce401c6..dc2b7e7ab 100644 --- a/test/qt/ifd/test_IfdConnector.cpp +++ b/test/qt/ifd/test_IfdConnector.cpp @@ -427,11 +427,7 @@ class test_IfdConnector QTRY_COMPARE(spyConnectorError.count(), 1); // clazy:exclude=qstring-allocations QCOMPARE(spyConnectorSuccess.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - verifyErrorSignal(spyConnectorError, {IfdErrorCode::CONNECTION_ERROR}, serverPort, QStringLiteral("Smartphone1")); -#else verifyErrorSignal(spyConnectorError, {IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, serverPort, QStringLiteral("Smartphone1")); -#endif QCOMPARE(spySocketError.count(), 0); QCOMPARE(spySocketSuccess.count(), 0); diff --git a/test/qt/ifd/test_IfdDispatcher.cpp b/test/qt/ifd/test_IfdDispatcher.cpp index 412ed370c..1cb2bd052 100644 --- a/test/qt/ifd/test_IfdDispatcher.cpp +++ b/test/qt/ifd/test_IfdDispatcher.cpp @@ -338,6 +338,22 @@ class test_IfdDispatcher } + void isNormalConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(false)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(!clientDispatcher->isPairingConnection()); + } + + + void isPairingConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(true)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(clientDispatcher->isPairingConnection()); + } + + }; QTEST_GUILESS_MAIN(test_IfdDispatcher) diff --git a/test/qt/ifd/test_ServerMessageHandler.cpp b/test/qt/ifd/test_ServerMessageHandler.cpp index 0bae9449f..cb9f07ddf 100644 --- a/test/qt/ifd/test_ServerMessageHandler.cpp +++ b/test/qt/ifd/test_ServerMessageHandler.cpp @@ -603,6 +603,82 @@ class test_ServerMessageHandler } + void ifdTransmit_data() + { + QTest::addColumn("sendProgressMessage"); + + QTest::newRow("Send message") << true; + QTest::newRow("Don't send message") << false; + } + + + void ifdTransmit() + { + QFETCH(bool, sendProgressMessage); + + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + QString contextHandle; + ensureContext(contextHandle); + + QSignalSpy sendSpy(mDataChannel.data(), &MockDataChannel::fireSend); + + MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("test-reader"); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + reader->setCard(MockCardConfig({ + {CardReturnCode::OK, QByteArray("9000")} + })); + QTRY_COMPARE(sendSpy.count(), 2); // clazy:exclude=qstring-allocations + const CardInfo cardInfo(CardType::EID_CARD, QSharedPointer(), 3, true); + ReaderInfo info = reader->getReaderInfo(); + info.setCardInfo(cardInfo); + reader->setReaderInfo(info); + QTRY_COMPARE(sendSpy.count(), 3); // clazy:exclude=qstring-allocations + sendSpy.clear(); + + const QByteArray ifdConnectMsg = IfdConnect(QStringLiteral("test-reader"), true).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdConnectMsg); + + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& connectResponseArguments = sendSpy.last(); + const QVariant connectResponseVariant = connectResponseArguments.at(0); + QVERIFY(connectResponseVariant.canConvert()); + + const IfdConnectResponse connectResponse(IfdMessage::parseByteArray(connectResponseVariant.toByteArray())); + QVERIFY(!connectResponse.isIncomplete()); + QCOMPARE(connectResponse.getType(), IfdMessageType::IFDConnectResponse); + QCOMPARE(connectResponse.getContextHandle(), contextHandle); + QVERIFY(!connectResponse.getSlotHandle().isEmpty()); + + QVERIFY(!connectResponse.resultHasError()); + QCOMPARE(connectResponse.getResultMinor(), ECardApiResult::Minor::null); + + sendSpy.clear(); + + QSignalSpy displayTextSpy(&serverMessageHandler, &ServerMessageHandler::fireDisplayTextChanged); + // Card connected, try to provoke message. + const QByteArray ifdTransmitMsg = IfdTransmit(connectResponse.getSlotHandle(), QByteArray("ABCDEF"), sendProgressMessage ? QStringLiteral("DummyText") : QString()).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdTransmitMsg); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& transmitResponseArguments = sendSpy.last(); + const QVariant transmitResponseVariant = transmitResponseArguments.at(0); + QVERIFY(transmitResponseVariant.canConvert()); + + const IfdTransmitResponse transmitResponse(IfdMessage::parseByteArray(transmitResponseVariant.toByteArray())); + QVERIFY(!transmitResponse.isIncomplete()); + QCOMPARE(transmitResponse.getType(), IfdMessageType::IFDTransmitResponse); + QCOMPARE(transmitResponse.getContextHandle(), contextHandle); + QCOMPARE(transmitResponse.getSlotHandle(), connectResponse.getSlotHandle()); + QVERIFY(!transmitResponse.resultHasError()); + QCOMPARE(transmitResponse.getResultMinor(), ECardApiResult::Minor::null); + QCOMPARE(displayTextSpy.count(), sendProgressMessage ? 1 : 0); + + removeReaderAndConsumeMessages(QStringLiteral("test-reader")); + } + + void ifdEstablishPACEChannelWithBasicReaderNameSendsAL_Unknown_Error() { const bool pinpadModeToSave = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); diff --git a/test/qt/settings/test_RemoteServiceSettings.cpp b/test/qt/settings/test_RemoteServiceSettings.cpp index 8dbe07f30..168c8097a 100644 --- a/test/qt/settings/test_RemoteServiceSettings.cpp +++ b/test/qt/settings/test_RemoteServiceSettings.cpp @@ -71,8 +71,16 @@ class test_RemoteServiceSettings void testPinPadMode() { RemoteServiceSettings settings; + QCOMPARE(settings.getPinPadMode(), true); + settings.setPinPadMode(false); QCOMPARE(settings.getPinPadMode(), false); - QCOMPARE(settings.getPinPadMode(), false); + } + + + void testShowAccessRights() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getShowAccessRights(), false); settings.setPinPadMode(true); QCOMPARE(settings.getPinPadMode(), true); } diff --git a/test/qt/ui/qml/test_ApplicationModel.cpp b/test/qt/ui/qml/test_ApplicationModel.cpp index 339ba8617..530822245 100644 --- a/test/qt/ui/qml/test_ApplicationModel.cpp +++ b/test/qt/ui/qml/test_ApplicationModel.cpp @@ -9,8 +9,10 @@ #include "ApplicationModel.h" #include "MockActivationContext.h" +#include "MockIfdServer.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" #if __has_include("context/PersonalizationContext.h") #include "context/PersonalizationContext.h" @@ -58,6 +60,7 @@ class test_ApplicationModel QTest::addRow("No Context") << QSharedPointer() << ApplicationModel::Workflow::WORKFLOW_NONE; QTest::addRow("AuthContext") << QSharedPointer(new AuthContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_AUTHENTICATION; QTest::addRow("ChangePinContext") << QSharedPointer(new ChangePinContext()) << ApplicationModel::Workflow::WORKFLOW_CHANGE_PIN; + QTest::addRow("IfdServiceContext") << QSharedPointer(new IfdServiceContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_REMOTE_SERVICE; QTest::addRow("SelfAuthContext") << QSharedPointer(new SelfAuthContext()) << ApplicationModel::Workflow::WORKFLOW_SELF_AUTHENTICATION; #if __has_include("context/PersonalizationContext.h") QTest::addRow("PersonalizationContext") << QSharedPointer(new PersonalizationContext(QString())) << ApplicationModel::Workflow::WORKFLOW_SMART; diff --git a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp index 8c52fd113..44281f789 100644 --- a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp +++ b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp @@ -8,8 +8,10 @@ #include "CertificateDescriptionModel.h" +#include "MockIfdServer.h" #include "TestAuthContext.h" #include "TestFileHelper.h" +#include "context/IfdServiceContext.h" #include #include @@ -27,6 +29,19 @@ class test_CertificateDescriptionModel CertificateDescriptionModel* mModel = nullptr; QSharedPointer mContext; + static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) + { + 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"); + + return EstablishPaceChannel(pinId, chat, certDescription); + } + private Q_SLOTS: void init() { @@ -98,6 +113,21 @@ class test_CertificateDescriptionModel } + void test_IfdContext() + { + auto ifdContext = QSharedPointer::create(QSharedPointer::create()); + mModel->resetContext(ifdContext); + const auto& establishPaceChannel = createDataToParse(PacePasswordId::PACE_PIN); + ifdContext->setEstablishPaceChannel(QSharedPointer::create(QString(), establishPaceChannel, 6)); + + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider")); + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::TEXT), QString("Gesamtverband der deutschen Versicherungswirtschaft e.V.\n")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::LABEL), QString("Certificate issuer")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::TEXT), QString("D-Trust GmbH\n")); + QCOMPARE(mModel->data(mModel->index(2), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider information")); + } + + }; QTEST_GUILESS_MAIN(test_CertificateDescriptionModel) diff --git a/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp new file mode 100644 index 000000000..4d505f3e5 --- /dev/null +++ b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Unit tests for \ref RemoteDeviceModel + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +#include + + +using namespace governikus; + + +class test_RemoteDeviceFilterModel + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void test_FilterAcceptsRow() + { + QSharedPointer sourceModel = QSharedPointer::create(); + QSharedPointer filterModelAvail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showAvailableAndPaired); + QSharedPointer filterModelUnavail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showUnavailableAndPaired); + QSharedPointer filterModelAvailPair = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showActivePairingMode); + + const RemoteDeviceModelEntry availableEntry(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry unavailableEntry(QString("reader 2"), QString("test id"), false, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry availablePairingEntry(QString("reader 2"), QString("test id"), true, false, true, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + + sourceModel->mAllRemoteReaders.insert(0, availableEntry); + sourceModel->mAllRemoteReaders.insert(1, unavailableEntry); + sourceModel->mAllRemoteReaders.insert(2, availablePairingEntry); + + QCOMPARE(filterModelAvail->filterAcceptsRow(0, QModelIndex()), true); + QCOMPARE(filterModelAvail->filterAcceptsRow(1, QModelIndex()), false); + + QCOMPARE(filterModelUnavail->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelUnavail->filterAcceptsRow(1, QModelIndex()), true); + + QCOMPARE(filterModelAvailPair->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(1, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(2, QModelIndex()), true); + } + + +}; + +QTEST_MAIN(test_RemoteDeviceFilterModel) +#include "test_RemoteDeviceFilterModel.moc" diff --git a/test/qt/ui/qml/test_RemoteDeviceModel.cpp b/test/qt/ui/qml/test_RemoteDeviceModel.cpp index 73fe79908..0c806363b 100644 --- a/test/qt/ui/qml/test_RemoteDeviceModel.cpp +++ b/test/qt/ui/qml/test_RemoteDeviceModel.cpp @@ -2,6 +2,8 @@ * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ +#include "AppSettings.h" +#include "IfdDescriptor.h" #include "RemoteDeviceModel.h" #include @@ -42,6 +44,14 @@ class test_RemoteDeviceModel } + void test_IsPairing() + { + QVERIFY(!mEntry->isPairing()); + mEntry->setIsPairing(true); + QVERIFY(mEntry->isPairing()); + } + + void test_DeviceNameEscaped() { QCOMPARE(mEntry->getDeviceNameEscaped(), mName); @@ -76,7 +86,7 @@ class test_RemoteDeviceModel RemoteDeviceModelEntry entry1(name); const IfdDescriptor descriptor = IfdDescriptor(); QSharedPointer pointer(new IfdListEntry(descriptor)); - RemoteDeviceModelEntry entry2(name, id, true, true, true, time, pointer); + RemoteDeviceModelEntry entry2(name, id, true, true, true, true, time, pointer); QVERIFY(!entry1.isSupported()); QVERIFY(entry2.isSupported()); @@ -86,15 +96,23 @@ class test_RemoteDeviceModel void test_RemoteDeviceListEntry() { const QString name = QStringLiteral("name"); - + const QString id = QStringLiteral("id"); RemoteDeviceModelEntry entry1(name); QCOMPARE(entry1.getRemoteDeviceListEntry(), nullptr); - const IfdDescriptor descriptor = IfdDescriptor(); - QSharedPointer pointer(new IfdListEntry(descriptor)); - const QString id = QStringLiteral("id"); - RemoteDeviceModelEntry entry2(name, id, pointer); - QCOMPARE(entry2.getRemoteDeviceListEntry(), pointer); + const IfdDescriptor defaultDescriptor = IfdDescriptor(); + QSharedPointer listEntry1(new IfdListEntry(defaultDescriptor)); + RemoteDeviceModelEntry entry2(listEntry1); + QCOMPARE(entry2.getRemoteDeviceListEntry(), listEntry1); + + const Discovery discovery = Discovery(name, id, 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry2(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry3(listEntry2); + QCOMPARE(entry3.getRemoteDeviceListEntry(), listEntry2); + QCOMPARE(entry3.getId(), id); + QCOMPARE(entry3.getDeviceNameEscaped(), name); + QVERIFY(entry3.isSupported()); } @@ -111,17 +129,27 @@ class test_RemoteDeviceModel void test_RoleNames() { - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED)); QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_STATUS)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME)); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceName"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceStatus"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("lastConnected"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("deviceId"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isNetworkVisible"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isSupported"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPaired"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPairing"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("linkQualityInPercent"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isLastAddedDevice"))); } @@ -139,13 +167,18 @@ class test_RemoteDeviceModel QCOMPARE(mModel->getStatus(entry), QString("Not paired")); entry.setPaired(true); - QCOMPARE(mModel->getStatus(entry), QString("Paired, but unavailable")); + QCOMPARE(mModel->getStatus(entry), QString("Unavailable")); entry.setNetworkVisible(true); QCOMPARE(mModel->getStatus(entry), QString("Available")); entry.mSupported = false; QCOMPARE(mModel->getStatus(entry), QString("Paired, but unsupported")); + + entry.setNetworkVisible(true); + entry.mSupported = true; + entry.mIsPairing = true; + QCOMPARE(mModel->getStatus(entry), QString("Click to pair")); } @@ -166,8 +199,11 @@ class test_RemoteDeviceModel void test_GetRemoteDeviceListEntryModelIndex() { - QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - RemoteDeviceModelEntry entry1(QString("entry 1"), QStringLiteral("01"), listEntry); + const Discovery discovery = Discovery(QStringLiteral("entry 1"), QStringLiteral("01"), 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry1(listEntry); + RemoteDeviceModelEntry entry2(QString("entry 2")); mModel->mAllRemoteReaders << entry1 << entry2; @@ -193,7 +229,9 @@ class test_RemoteDeviceModel QTest::newRow("network visible") << RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE << 1 << 0 << QVariant(bool(false)); QTest::newRow("supported") << RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED << 0 << 0 << QVariant(bool(true)); QTest::newRow("paired") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); + QTest::newRow("is pairing") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); QTest::newRow("link quality") << RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY << 0 << 0 << QVariant(int(0)); + QTest::newRow("is last added device") << RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE << 0 << 0 << QVariant(bool(false)); } @@ -206,7 +244,7 @@ class test_RemoteDeviceModel QVector readers; QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); + const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); const RemoteDeviceModelEntry entry2(QString("reader 2")); readers << entry1 << entry2; mModel->mAllRemoteReaders = readers; @@ -215,6 +253,28 @@ class test_RemoteDeviceModel } + void test_SetLastPairedReader() + { + const auto cert = QSslCertificate(); + + RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.addTrustedCertificate(cert); + + const auto dName = QStringLiteral("myDeviceName"); + const auto dId = QStringLiteral("myDeviceId"); + const auto disco = Discovery(dName, dId, 12345, {IfdVersion::Version::latest}, false); + const auto ifdDesc = IfdDescriptor(disco, QHostAddress(QStringLiteral("127.0.0.1"))); + const QSharedPointer remoteDeviceListEntry(new IfdListEntry(ifdDesc)); + + mModel->addOrUpdateReader(RemoteDeviceModelEntry(remoteDeviceListEntry)); + + QSignalSpy spy(mModel.get(), &RemoteDeviceModel::dataChanged); + mModel->setLastPairedReader(cert); + QTRY_COMPARE(spy.size(), 1); + QVERIFY(mModel->data(mModel->index(0), RemoteDeviceModel::IS_LAST_ADDED_DEVICE).toBool()); + } + + }; QTEST_MAIN(test_RemoteDeviceModel) diff --git a/test/qt/ui/qml/test_RemoteServiceModel.cpp b/test/qt/ui/qml/test_RemoteServiceModel.cpp index 17bb04396..c3673bed1 100644 --- a/test/qt/ui/qml/test_RemoteServiceModel.cpp +++ b/test/qt/ui/qml/test_RemoteServiceModel.cpp @@ -28,19 +28,6 @@ class test_RemoteServiceModel RemoteServiceModel* mModel = nullptr; QSharedPointer mContext; - static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) - { - 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"); - - return EstablishPaceChannel(pinId, chat, certDescription); - } - private Q_SLOTS: void initTestCase() { @@ -153,6 +140,86 @@ class test_RemoteServiceModel } + void test_TransactionInfo() + { + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(mModel->getTransactionInfo(), QString()); + } + + + void test_getSupportedReaderPlugInTypes() + { + QVector supportedPlugIns {ReaderManagerPlugInType::NFC}; +#if __has_include("SmartManager.h") + supportedPlugIns << ReaderManagerPlugInType::SMART; +#endif + QCOMPARE(mModel->getSupportedReaderPlugInTypes(), supportedPlugIns); + } + + + void test_DisplayText_data() + { + QTest::addColumn("inputText"); + QTest::addColumn("outputText"); + QTest::addColumn("expectedPercentage"); + + QTest::newRow("positive two digits") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("positive two digits with space") << "Dummy Text\n15 %" << "Dummy Text" << 15; + QTest::newRow("negative two digits") << "Dummy Text\n-15%" << "Dummy Text\n-15%" << 0; + QTest::newRow("positive two digits with percentage") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("Whitespace input") << " " << " " << 0; + QTest::newRow("Special characters") << "!@#$%^&*()" << "!@#$%^&*()" << 0; + QTest::newRow("Digits only") << "12345" << "12345" << 0; + QTest::newRow("Single Digit") << "Dummy Text\n1%" << "Dummy Text" << 1; + QTest::newRow("Triple Digit") << "Dummy Text\n111%" << "Dummy Text\n111%" << 0; + QTest::newRow("100 Percent") << "Dummy Text\n100%" << "Dummy Text" << 100; + QTest::newRow("Quadruple Digit") << "Dummy Text\n1111%" << "Dummy Text\n1111%" << 0; + QTest::newRow("Real Number") << "Dummy Text\n11.1%" << "Dummy Text\n11.1%" << 0; + QTest::newRow("Zero Digit without Space") << "%" << "%" << 0; + QTest::newRow("Single Digit without Space") << "1%" << "" << 1; + QTest::newRow("Double Digit without Space") << "42%" << "" << 42; + QTest::newRow("Triple Digit without Space") << "100%" << "" << 100; + QTest::newRow("Zero Digit with Space") << " %" << " %" << 0; + QTest::newRow("Single Digit with Space") << "1 %" << "" << 1; + QTest::newRow("Double Digit with Space") << "42 %" << "" << 42; + QTest::newRow("Triple Digit with Space") << "100 %" << "" << 100; + + } + + + void test_DisplayText() + { + QFETCH(QString, inputText); + QFETCH(QString, outputText); + QFETCH(int, expectedPercentage); + + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + mModel->resetRemoteServiceContext(mContext); + mContext->setDisplayText(inputText); + QCOMPARE(spyDisplayTextChanged.count(), 1); + QCOMPARE(mModel->getDisplayText(), outputText); + QCOMPARE(mModel->getPercentage(), expectedPercentage); + } + + + void test_DisplayTextSignals() + { + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + QCOMPARE(mModel->getDisplayText(), ""); + QCOMPARE(mModel->getPercentage(), 0); + + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(spyDisplayTextChanged.count(), 0); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + + } + + }; QTEST_MAIN(test_RemoteServiceModel) diff --git a/test/qt/ui/qml/test_WorkflowModel.cpp b/test/qt/ui/qml/test_WorkflowModel.cpp index 25e8a3e3c..dfee3571a 100644 --- a/test/qt/ui/qml/test_WorkflowModel.cpp +++ b/test/qt/ui/qml/test_WorkflowModel.cpp @@ -8,12 +8,16 @@ #include "WorkflowModel.h" +#include "Env.h" #include "MockCardConnectionWorker.h" +#include "MockReaderManagerPlugIn.h" +#include "ReaderManager.h" #include "TestWorkflowContext.h" #include #include +Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) using namespace governikus; @@ -109,6 +113,46 @@ class test_WorkflowModel } + void test_startScanExplicitly() + { + const auto readerManager = Env::getSingleton(); + readerManager->init(); + readerManager->isScanRunning(); // just to wait until initialization finished + + QSharedPointer context(new TestWorkflowContext()); + QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged); + + WorkflowModel model; + model.resetWorkflowContext(context); + + model.startScanExplicitly(); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).toBool(), true); + } + + + void test_hasCard() + { + const auto readerManager = Env::getSingleton(); + readerManager->init(); + readerManager->isScanRunning(); // just to wait until initialization finished + + WorkflowModel model; + QCOMPARE(model.hasCard(), false); + + QSharedPointer context(new TestWorkflowContext()); + model.resetWorkflowContext(context); + QCOMPARE(model.hasCard(), false); + + auto mockReader = MockReaderManagerPlugIn::getInstance().addReader("SomeReaderWithCard"); + auto info = mockReader->getReaderInfo(); + info.setCardInfo(CardInfo(CardType::EID_CARD, QSharedPointer(), 3, false, false, false)); + mockReader->setReaderInfo(info); + model.setReaderPlugInType(ReaderManagerPlugInType::MOCK); + QCOMPARE(model.hasCard(), true); + } + + }; QTEST_MAIN(test_WorkflowModel) diff --git a/test/qt/workflows/context/test_WorkflowContext.cpp b/test/qt/workflows/context/test_WorkflowContext.cpp index f5bee5ae9..7d9344a49 100644 --- a/test/qt/workflows/context/test_WorkflowContext.cpp +++ b/test/qt/workflows/context/test_WorkflowContext.cpp @@ -273,6 +273,18 @@ class test_WorkflowContext } + void test_setInterruptRequested() + { + QVERIFY(!mContext->interruptRequested()); + + mContext->setInterruptRequested(true); + QVERIFY(mContext->interruptRequested()); + + mContext->setInterruptRequested(false); + QVERIFY(!mContext->interruptRequested()); + } + + }; QTEST_GUILESS_MAIN(test_WorkflowContext) diff --git a/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp index f6467ef3b..7c4d9456d 100644 --- a/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp +++ b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp @@ -41,6 +41,12 @@ class MockServerMsgHandler } + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override + { + Q_UNUSED(pAllowedCardTypes) + } + + QString getResponse() { return mResponse; diff --git a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp index 5d533913b..dba2e1cd3 100644 --- a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp +++ b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp @@ -35,8 +35,8 @@ class test_StateProcessIfdMessages const QSharedPointer context(new IfdServiceContext(mIfdServer)); StateProcessIfdMessages state(context); state.run(); - QCOMPARE(state.mConnections.size(), 4); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mConnections.size(), 1); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -50,7 +50,7 @@ class test_StateProcessIfdMessages QCOMPARE(state.mMessageConnections.size(), 0); state.onMessageHandlerAdded(messageHandler); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -115,6 +115,21 @@ class test_StateProcessIfdMessages } + void test_OnDisplayTextChanged() + { + const QSharedPointer context(new IfdServiceContext(mIfdServer)); + StateProcessIfdMessages state(context); + QSignalSpy spy(context.data(), &IfdServiceContext::fireDisplayTextChanged); + + state.onDisplayTextChanged(QStringLiteral("dummy text")); + QCOMPARE(spy.count(), 1); + QCOMPARE(context->getDisplayText(), QStringLiteral("dummy text")); + state.onCardDisconnected(); + QCOMPARE(spy.count(), 2); + QCOMPARE(context->getDisplayText(), QStringLiteral("")); + } + + }; QTEST_GUILESS_MAIN(test_StateProcessIfdMessages) diff --git a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp index a9dc2eea9..270835dac 100644 --- a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp +++ b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp @@ -97,10 +97,14 @@ class test_StateEstablishPaceChannel mAuthContext->setCardConnection(connection); mAuthContext->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); + QCOMPARE(mAuthContext->getProgressValue(), 0); + QCOMPARE(mAuthContext->getProgressMessage(), QString()); QTest::ignoreMessage(QtDebugMsg, "Establish connection using PACE_PIN"); mState->run(); QCOMPARE(mAuthContext->getEstablishPaceChannelType(), PacePasswordId::PACE_PIN); QCOMPARE(mState->mPasswordId, PacePasswordId::PACE_PIN); + QCOMPARE(mAuthContext->getProgressValue(), 0); + QCOMPARE(mAuthContext->getProgressMessage(), tr("The secure channel is opened")); } diff --git a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp index 32d3121c4..dfed18a54 100644 --- a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp +++ b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp @@ -131,7 +131,7 @@ class test_StateGenericProviderCommunication QCOMPARE(spy.count(), 1); const auto& failureCode = mState->getContext()->getFailureCode(); - QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Ssl_Error); + QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Tls_Error); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Network_Error], mState->mReply->errorString()); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Ssl_Errors], TlsChecker::sslErrorsToString(errorList)); } diff --git a/test/qt/workflows/states/test_StatePreVerification.cpp b/test/qt/workflows/states/test_StatePreVerification.cpp index 4ba263363..9e4da35fc 100644 --- a/test/qt/workflows/states/test_StatePreVerification.cpp +++ b/test/qt/workflows/states/test_StatePreVerification.cpp @@ -91,7 +91,7 @@ class test_StatePreVerification QTRY_COMPARE(spyAbort.count(), isValid ? 0 : 1); // clazy:exclude=qstring-allocations if (!isValid) { - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } } @@ -104,7 +104,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } @@ -116,7 +116,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); } @@ -136,7 +136,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); } @@ -148,7 +148,7 @@ class test_StatePreVerification mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); }