diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..2d01d71c9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/CI_build.yml b/.github/workflows/CI_build.yml new file mode 100644 index 000000000..c5201b0c9 --- /dev/null +++ b/.github/workflows/CI_build.yml @@ -0,0 +1,118 @@ +name: CI_build + +on: [push, pull_request] + +jobs: + + build_windows: + + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Ninja"] + + steps: + + - name: Install openssl dev + run: | + choco install openssl --version=3.3.2 + choco install ninja + + - name: Add nmake + uses: ilammy/msvc-dev-cmd@v1 + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '6.7.*' + modules: 'qtscxml qtwebsockets qtshadertools qtconnectivity qtimageformats' + setup-python: 'false' + + - name: generate cmake + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B _build + + - name: build cmake + run: | + cmake --build _build --config ${{ matrix.build_configuration }} --target package + cmake --install _build + + - name: run ctest + run: | + ctest --test-dir _build --output-on-failure -C "${{ matrix.build_configuration }}" + + build_linux: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Unix Makefiles"] + + steps: + - uses: actions/checkout@v4 + + - name: Install packages via apt + run: | + sudo apt update -qq && sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libgl1-mesa-dev qt6-l10n-tools + + # ubuntu 22.04 comes just with QT 6.2.4 and Qt >= 6.4 is required + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '6.7.2' + modules: 'qtscxml qtwebsockets qtshadertools qtconnectivity' + setup-python: 'false' + + - name: generate cmake + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B _build + + - name: build cmake + run: | + cmake --build _build --config ${{ matrix.build_configuration }} --target package + sudo cmake --install _build + + - name: run ctest + run: | + ctest --test-dir _build --output-on-failure -C "${{ matrix.build_configuration }}" + + build_macos: + + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Unix Makefiles"] + + steps: + - uses: actions/checkout@v4 + + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '6.7.2' + modules: 'qtscxml qtwebsockets qtshadertools qtconnectivity qtimageformats' + + - name: generate cmake + run: | + export OPENSSL_ROOT=/usr/local/opt/openssl/bin + export LDFLAGS=-L/usr/local/opt/openssl/lib + export CPPFLAGS=-I/usr/local/opt/openssl/include + export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig/ + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B _build + + - name: build cmake + run: | + cmake --build _build --config ${{ matrix.build_configuration }} + + - name: run ctest + run: | + ctest --test-dir _build --output-on-failure -C "${{ matrix.build_configuration }}" diff --git a/.github/workflows/CI_build_combined.yml b/.github/workflows/CI_build_combined.yml new file mode 100644 index 000000000..4eeba15c0 --- /dev/null +++ b/.github/workflows/CI_build_combined.yml @@ -0,0 +1,171 @@ +name: CI_build_combined + +on: [push, pull_request] + +env: + BUILD_DIR_LIBS_WIN: "c:/_build_libs" + BUILD_DIR_APP_WIN: "c:/_build" + BUILD_DIR_LIBS: "_build_libs" + BUILD_DIR_APP: "_build" + + +jobs: + build_windows: + + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Ninja"] + + steps: + + - name: Install nmake replacement jom, ninja + run: | + choco install jom ninja + + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Add nmake + uses: ilammy/msvc-dev-cmd@v1 + + - name: generate cmake libs + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B "${{ env.BUILD_DIR_LIBS_WIN }}" D:\a\AusweisApp\AusweisApp\libs + + - name: build cmake libs + run: | + cmake --build "${{ env.BUILD_DIR_LIBS_WIN }}" --config ${{ matrix.build_configuration }} + + - name: generate cmake + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B "${{ env.BUILD_DIR_APP_WIN }}" -DCMAKE_PREFIX_PATH=c:\_build_libs\dist D:\a\AusweisApp\AusweisApp + + - name: build cmake + run: | + cmake --build "${{ env.BUILD_DIR_APP_WIN }}" --config ${{ matrix.build_configuration }} --target package + cmake --install "${{ env.BUILD_DIR_APP_WIN }}" + + - name: run ctest + run: | + ctest --test-dir "${{ env.BUILD_DIR_APP_WIN }}" --output-on-failure -C "${{ matrix.build_configuration }}" + + + + build_linux: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Ninja"] + + steps: + - uses: actions/checkout@v4 + + - name: Install packages via apt + run: | + sudo apt-get update -qq && sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libgl1-mesa-dev libdbus-1-dev libclang-15-dev libclang-14-dev libclang-13-dev ninja-build + + - name: generate cmake libs + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B ${{ env.BUILD_DIR_LIBS }} ./libs + + - name: build cmake libs + run: | + cmake --build ${{ env.BUILD_DIR_LIBS }} --config ${{ matrix.build_configuration }} + + - name: generate cmake + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B ${{ env.BUILD_DIR_APP }} -DCMAKE_PREFIX_PATH=./_build_libs/dist + + - name: build cmake + run: | + cmake --build ${{ env.BUILD_DIR_APP }} --config ${{ matrix.build_configuration }} + sudo cmake --install ${{ env.BUILD_DIR_APP }} + + - name: run ctest + run: | + ctest --test-dir ${{ env.BUILD_DIR_APP }} --output-on-failure -C "${{ matrix.build_configuration }}" + + + build_linux_android: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Unix Makefiles"] + + steps: + - uses: actions/checkout@v4 + + - name: Install packages via apt + run: | + sudo apt-get update -qq && sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libgl1-mesa-dev libdbus-1-dev libclang-15-dev libclang-14-dev libclang-13-dev ninja-build + sudo apt -y remove firefox microsoft-edge-stable google-chrome-stable kotlin libmono* mono-runtime + + - name: generate cmake libs + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -DCMAKE_TOOLCHAIN_FILE=../cmake/android.toolchain.cmake -B ${{ env.BUILD_DIR_LIBS }} ./libs + + - name: build cmake libs + run: | + cmake --build ${{ env.BUILD_DIR_LIBS }} --config ${{ matrix.build_configuration }} + cmake --install ${{ env.BUILD_DIR_LIBS }} + + build_macos: + + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Ninja"] + + steps: + - uses: actions/checkout@v4 + + - name: install ninja + run: | + brew install ninja + + - name: generate cmake libs + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -B ${{ env.BUILD_DIR_LIBS }} ./libs + + - name: build cmake libs + run: | + cmake --build ${{ env.BUILD_DIR_LIBS }} --config ${{ matrix.build_configuration }} + + - name: generate cmake + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -DCMAKE_PREFIX_PATH=./_build_libs/dist -B ${{ env.BUILD_DIR_APP }} + + build_ios: + + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + build_configuration: [Release] + build_platform: ["Unix Makefiles"] + + steps: + - uses: actions/checkout@v4 + + - name: install ninja + run: | + brew install ninja + + - name: generate cmake libs + run: | + cmake -G "${{ matrix.build_platform }}" -DCMAKE_BUILD_TYPE="${{ matrix.build_configuration }}" -DCMAKE_TOOLCHAIN_FILE=../cmake/iOS.toolchain.cmake -B ${{ env.BUILD_DIR_LIBS }} ./libs + + - name: build cmake libs + run: | + cmake --build ${{ env.BUILD_DIR_LIBS }} --config ${{ matrix.build_configuration }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c1de2b2a0..3eb6b5491 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,10 +24,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality @@ -35,10 +35,18 @@ jobs: - name: Install dependencies run: sudo apt update -qq && sudo apt install -y cmake pkg-config libssl-dev libudev-dev libhttp-parser-dev libpcsclite-dev libqt6svg6-dev libqt6websockets6-dev qt6-base-dev qt6-base-private-dev qt6-declarative-dev qt6-connectivity-dev qt6-scxml-dev qt6-tools-dev qt6-tools-dev-tools libqt6opengl6-dev libqt6shadertools6-dev libgl1-mesa-dev qt6-l10n-tools + #QT > 6.4 is required but ubuntu 22.04 just has 6.2.4, so additional installation is needed + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '6.7.2' + modules: 'qtscxml qtwebsockets qtshadertools qtconnectivity' + setup-python: 'false' + - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" diff --git a/.qmlformat.ini b/.qmlformat.ini new file mode 100644 index 000000000..3144a533e --- /dev/null +++ b/.qmlformat.ini @@ -0,0 +1,5 @@ +[General] +UseTabs=true +IndentWidth=4 +NewlineType=unix +NormalizeOrder=true diff --git a/CMakeLists.txt b/CMakeLists.txt index 8208c0900..d48e3b935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ if(isMultiConfig) endif() endif() -project(AusweisApp VERSION 2.2.1 LANGUAGES ${LANGUAGES}) +project(AusweisApp VERSION 2.2.2 LANGUAGES ${LANGUAGES}) if(ANDROID AND NOT GOVERNIKUS_TOOLCHAIN_FILE) message(FATAL_ERROR "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_DIR}/android.toolchain.cmake is required") diff --git a/Dockerfile b/Dockerfile index 24da7ebd7..588bb3a7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG ALPINE_VERSION=3.20 -FROM alpine:$ALPINE_VERSION as builder +FROM alpine:$ALPINE_VERSION AS builder # Install development stuff RUN apk --no-cache upgrade -a && \ apk --no-cache add patch cmake ccache make ninja g++ pkgconf pcsc-lite-dev binutils-gold eudev-libs perl python3 linux-headers diff --git a/appveyor.yml b/appveyor.yml index 2bd2d5429..324275ff7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,14 +5,14 @@ environment: - PlatformToolset: mingw-w64 platform: mingw-w64 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - QTPath: C:\Qt\6.3.1\mingw_64 - OPENSSLPath: C:\OpenSSL-v30-Win64\bin + QTPath: C:\Qt\6.7\mingw_64 + OPENSSLPath: C:\OpenSSL-v33-Win64\bin - PlatformToolset: v142 platform: x64 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - QTPath: C:\Qt\6.3.1\msvc2019_64 - OPENSSLPath: C:\OpenSSL-v30-Win64\bin + QTPath: C:\Qt\6.7\msvc2019_64 + OPENSSLPath: C:\OpenSSL-v33-Win64\bin ARCHI: amd64 configuration: diff --git a/ci.cmake b/ci.cmake new file mode 100644 index 000000000..6d810ccf1 --- /dev/null +++ b/ci.cmake @@ -0,0 +1,280 @@ +cmake_minimum_required(VERSION 3.19) + +########################################### +#### Usage: cmake -P ci.cmake -- cmake args +########################################### + +if(NOT CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "Script mode is required") +endif() + +get_filename_component(CMAKE_SOURCE_DIR "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY) +message(STATUS "CMAKE_VERSION: ${CMAKE_VERSION}") +message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}") +message(STATUS "CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}") + +set(CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake") +set(CMAKE_MODULE_PATH "${CMAKE_DIR}/ci") + +if(CMAKE_COMMAND MATCHES " ") + set(CMAKE_COMMAND cmake) +endif() +if(CMAKE_CTEST_COMMAND MATCHES " ") + set(CMAKE_CTEST_COMMAND ctest) +endif() + +set(IMPORT_PY ${CMAKE_SOURCE_DIR}/resources/jenkins/import.py) + + +function(GET_PARAMS _params _definitions) + foreach(_arg RANGE ${CMAKE_ARGC}) + if("${CMAKE_ARGV${_arg}}" STREQUAL "--") + math(EXPR delimiter "${_arg}+1") + break() + elseif("${CMAKE_ARGV${_arg}}" MATCHES "^-D") + list(APPEND definition ${CMAKE_ARGV${_arg}}) + endif() + endforeach() + + if(DEFINED delimiter) + foreach(_arg RANGE ${delimiter} ${CMAKE_ARGC}) + list(APPEND param ${CMAKE_ARGV${_arg}}) + endforeach() + set(${_params} "${param}" PARENT_SCOPE) + endif() + + if(DEFINED definition) + set(${_definitions} "${definition}" PARENT_SCOPE) + endif() +endfunction() + + +function(CALC_CHECKSUM _out_checksum _out_repatch) + set(CHECKSUM_FILES ${CMAKE_SCRIPT_MODE_FILE} ${IMPORT_PY}) + foreach(file ${CHECKSUM_FILES}) + file(MD5 "${file}" _hash) + string(MD5 hashes "${_hash}${hashes}") + endforeach() + + if((NOT DEFINED SPLITTED OR SPLITTED) AND PATCHED AND NOT ${_out_checksum} STREQUAL hashes) + set(${_out_repatch} ON PARENT_SCOPE) + endif() + + set(${_out_checksum} ${hashes} PARENT_SCOPE) +endfunction() + + +function(IMPORT_PATCH _out) + message(STATUS "Import patch(es)...") + find_package(Python REQUIRED) + step(${Python_EXECUTABLE} ${IMPORT_PY} ${ARGN} NO_ECHO OUTPUT output CHDIR ${CMAKE_SOURCE_DIR}) + if(output MATCHES "Pending patch: (.+)") + string(STRIP "${CMAKE_MATCH_1}" PENDING_PATCH) + set(${_out} "${PENDING_PATCH}" PARENT_SCOPE) + endif() +endfunction() + + +function(STEP) + set(options NO_ECHO) + set(oneValueArgs CHDIR OUTPUT RESULT PATH) + set(multiValueArgs ENV) + cmake_parse_arguments(_PARAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(_PARAM_ENV) + set(ENV_CMD ${CMAKE_COMMAND} -E env) + foreach(env ${_PARAM_ENV}) + if(env MATCHES "^PATH=") + message(FATAL_ERROR "Use explicit PATH parameter") + endif() + list(APPEND ENV_CMD "${env}") + endforeach() + list(APPEND ENV_CMD --) + endif() + + if(NOT _PARAM_CHDIR) + set(_PARAM_CHDIR ${CMAKE_BINARY_DIR}) + endif() + + if(_PARAM_OUTPUT) + set(OUTPUT_OPTION OUTPUT_VARIABLE) + set(OUTPUT _output) + endif() + + if(_PARAM_NO_ECHO OR NOT ECHO) + set(COMMAND_ECHO STDOUT) + else() + set(ECHO_CMD ${CMAKE_COMMAND} -E echo) + set(COMMAND_ECHO NONE) + endif() + + if(_PARAM_PATH) + set(TMP_PATH "$ENV{PATH}") + if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") + set(SEP ";") + else() + set(SEP ":") + endif() + set(ENV{PATH} "${_PARAM_PATH}${SEP}$ENV{PATH}") + endif() + execute_process(COMMAND ${ECHO_CMD} ${ENV_CMD} ${_PARAM_UNPARSED_ARGUMENTS} + RESULT_VARIABLE _result + ${OUTPUT_OPTION} ${OUTPUT} + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${_PARAM_CHDIR} + COMMAND_ECHO ${COMMAND_ECHO}) + if(TMP_PATH) + set(ENV{PATH} "${TMP_PATH}") + unset(TMP_PATH) + endif() + + if(NOT ${_result} EQUAL 0) + if(_PARAM_RESULT) + set(${_PARAM_RESULT} ${_result} PARENT_SCOPE) + else() + message(FATAL_ERROR "Process failed: ${_result}") + endif() + endif() + + if(_PARAM_OUTPUT) + set(${_PARAM_OUTPUT} ${${OUTPUT}} PARENT_SCOPE) + endif() +endfunction() + + +function(CALL_SCRIPT) + if(NOT SCRIPT) + message(FATAL_ERROR "SCRIPT is undefined") + endif() + + SET_TEMPLATES() + if(EXISTS ${T_BUILD_DIR}) + step(${CMAKE_COMMAND} -E rm -r ${T_BUILD_DIR}) + endif() + + message(STATUS "Use SCRIPT: ${SCRIPT}") + include(${SCRIPT}) +endfunction() + + +macro(PARSE_FROM_NAME) + if(DEFINED ENV{JOB_NAME} AND NOT NAME) + set(NAME $ENV{JOB_NAME}) + endif() + + if(NAME) + message(STATUS "Use NAME: ${NAME}") + + if(NAME MATCHES "^Release_" AND NOT DEFINED RELEASE) + set(RELEASE ON) + elseif(NAME MATCHES "_Review_" AND NOT DEFINED REVIEW) + set(REVIEW ON) + endif() + + if(NOT SCRIPT) + file(GLOB scripts "${CMAKE_MODULE_PATH}/*.cmake") + foreach(entry ${scripts}) + get_filename_component(entry "${entry}" NAME_WLE) + if(NAME MATCHES "_${entry}") + set(SCRIPT ${entry}) + break() + endif() + endforeach() + endif() + endif() + + if(NOT REVIEW AND NOT RELEASE) + set(DAILY ON) + endif() +endmacro() + + +macro(SET_TEMPLATES) # Provide some base templates for SCRIPTs + if(DEFINED ENV{WORKSPACE}) + set(WORKSPACE $ENV{WORKSPACE}) + else() + set(WORKSPACE ${CMAKE_BINARY_DIR}) + endif() + + set(T_BUILD_DIR build) + set(T_DIST_DIR ${T_BUILD_DIR}/dist) + set(T_BUILD ${CMAKE_COMMAND} --build ${T_BUILD_DIR}) + set(T_TARGET ${T_BUILD} --target) + set(T_CTEST ${CMAKE_CTEST_COMMAND} --test-dir ${T_BUILD_DIR} --output-on-failure) + set(T_CFG ${CMAKE_COMMAND} -S ${CMAKE_SOURCE_DIR} -B ${T_BUILD_DIR} ${PARAMS}) +endmacro() + + +function(RESPAWN_PATCHED) + if(NOT DEFINED SPLITTED OR SPLITTED) + set(SPLITTED_PARAM --splitted) + endif() + if(NOT PATCHED) + set(CLEAN_PARAM --clean) + endif() + if(DEFINED PENDING AND NOT PENDING AND SPLITTED_PARAM) + set(PENDING_PARAM --no-pending) + endif() + if(REPATCH) + set(REPATCH_PARAM --repatch) + endif() + + if(NOT PATCHED OR SPLITTED_PARAM) + unset(PENDING_PATCH CACHE) + IMPORT_PATCH(PENDING_PATCH ${SPLITTED_PARAM} ${CLEAN_PARAM} ${PENDING_PARAM} ${REPATCH_PARAM}) + + if(PENDING_PATCH OR NOT PATCHED) + set(PATCHED_OPTION "-DPATCHED=ON") + if(NOT PATCHED_OPTION IN_LIST DEFINITIONS) + list(APPEND DEFINITIONS ${PATCHED_OPTION}) + endif() + + set(PENDING_PATCH_OPTION "-DPENDING_PATCH") + list(FILTER DEFINITIONS EXCLUDE REGEX "${PENDING_PATCH_OPTION}") + if(PENDING_PATCH) + list(APPEND DEFINITIONS "${PENDING_PATCH_OPTION}=${PENDING_PATCH}") + endif() + + set(CHECKSUM_OPTION "-DCHECKSUM") + list(FILTER DEFINITIONS EXCLUDE REGEX "${CHECKSUM_OPTION}") + list(APPEND DEFINITIONS "${CHECKSUM_OPTION}=${CHECKSUM}") + + if(NOT PATCHED AND SPLITTED_PARAM) + set(INITIAL_RUNNER INITIAL_RUNNER_FAILED) + endif() + + message(STATUS "script runner: respawn") + step(${CMAKE_COMMAND} ${DEFINITIONS} -P ${CMAKE_SCRIPT_MODE_FILE} -- ${PARAMS} NO_ECHO RESULT ${INITIAL_RUNNER}) + if(INITIAL_RUNNER) + IMPORT_PATCH(_unused --clean-only) + if(INITIAL_RUNNER_FAILED) + message(FATAL_ERROR "script runner: failed") + else() + message(STATUS "script runner: done") + endif() + endif() + endif() + endif() +endfunction() + + +function(RUN) + PARSE_FROM_NAME() + GET_PARAMS(PARAMS DEFINITIONS) + CALC_CHECKSUM(CHECKSUM REPATCH) + + if(NOT REPATCH AND (NOT REVIEW OR PATCHED)) + CALL_SCRIPT() + endif() + + if(REVIEW) + RESPAWN_PATCHED() + endif() +endfunction() + + +if(PATCH_ONLY) + IMPORT_PATCH(_unused --clean) +else() + RUN() +endif() diff --git a/cmake/Merge.cmake b/cmake/Merge.cmake new file mode 100644 index 000000000..31f2a7110 --- /dev/null +++ b/cmake/Merge.cmake @@ -0,0 +1,185 @@ +cmake_minimum_required(VERSION 3.21) + +if(NOT CMAKE_SCRIPT_MODE_FILE) + message(FATAL_ERROR "Usage: cmake -P cmake/Merge.cmake") +endif() + +set(prefix ausweisapp) +set(extension .aar) + +set(XML_LOAD_LOCAL_LIBS "") +set(XML_QT_LIBS "") +set(XML_END_TAG "") + +function(remove_arch filename output) + list(APPEND ARCHS x86_64 x86 armeabi-v7a arm64-v8a) + foreach(arch ${ARCHS}) + string(REPLACE "-${arch}" "" filename "${filename}") + endforeach() + set(${output} ${filename} PARENT_SCOPE) +endfunction() + +function(get_version_filename _files _output) + foreach(filename ${_files}) + message(STATUS "Check AAR: ${filename}") + get_filename_component(filename ${filename} NAME) + remove_arch(${filename} filenameWithoutArch) + if(filename STREQUAL filenameWithoutArch) + message(STATUS "Ignore merged AAR: ${filename}") + continue() + else() + set(filename ${filenameWithoutArch}) + endif() + + # Check that any AAR has same version + string(REPLACE "${extension}" "" aar_version "${filename}") + string(REPLACE "${prefix}-" "" aar_version "${aar_version}") + if(APP_NAME_VERSION AND NOT APP_NAME_VERSION STREQUAL aar_version) + message(STATUS "Different package version: ${APP_NAME_VERSION} / ${aar_version}") + set(APP_NAME_VERSION version-mismatch) + else() + set(APP_NAME_VERSION ${aar_version}) + endif() + endforeach() + + set(${_output} ${APP_NAME_VERSION} PARENT_SCOPE) +endfunction() + +function(extract_aars _files _dir _dir_values) + foreach(filename ${_files}) + if(NOT EXISTS "${filename}") + continue() + endif() + + # Extract the .aar file to package the merged aar itself + if(EXISTS "${_dir}") + set(patterns "jni") + else() + set(patterns "") + endif() + + file(ARCHIVE_EXTRACT INPUT "${filename}" DESTINATION "${_dir}" PATTERNS ${patterns}) + get_filename_component(dirname ${filename} NAME) + file(ARCHIVE_EXTRACT INPUT "${filename}" DESTINATION "${_dir_values}/${dirname}" PATTERNS "res/values/values.xml") + endforeach() +endfunction() + +function(append_value _line) + cmake_parse_arguments(_PARAM "NOLF" "" "" ${ARGN}) + if(NOT _PARAM_NOLF) + set(LF "\n") + endif() + file(APPEND "${VALUES_XML}" "${_line}${LF}") +endfunction() + +function(read_values _all_values _out_local_libs _out_qt_libs) + foreach(valueFile ${_all_values}) + set(addLineLocalLibs FALSE) + set(addLineQtLibs FALSE) + file(STRINGS "${valueFile}" filecontent) + foreach(line ${filecontent}) + if(line MATCHES "${XML_LOAD_LOCAL_LIBS}") + set(addLineLocalLibs TRUE) + continue() + elseif(line MATCHES "${XML_QT_LIBS}") + set(addLineQtLibs TRUE) + continue() + elseif(line MATCHES "${XML_END_TAG}") + set(addLineLocalLibs FALSE) + set(addLineQtLibs FALSE) + endif() + + if(addLineLocalLibs) + string(APPEND LOCAL_LIBS "${line}\n") + endif() + if(addLineQtLibs) + string(APPEND QT_LIBS "${line}\n") + endif() + endforeach() + endforeach() + + set(${_out_local_libs} "${LOCAL_LIBS}" PARENT_SCOPE) + set(${_out_qt_libs} "${QT_LIBS}" PARENT_SCOPE) +endfunction() + +function(merge_values _dir _all_values) + set(VALUES_XML "${_dir}/res/values/values.xml") + if(NOT EXISTS "${VALUES_XML}") + message(FATAL_ERROR "Cannot find ${VALUES_XML}") + endif() + + read_values("${_all_values}" LOCAL_LIBS QT_LIBS) + + set(writeLine TRUE) + file(STRINGS "${VALUES_XML}" filecontent) + file(WRITE "${VALUES_XML}" "") + foreach(line ${filecontent}) + if(line MATCHES "${XML_LOAD_LOCAL_LIBS}") + set(writeLine FALSE) + append_value("${line}") + append_value("${LOCAL_LIBS}" NOLF) + elseif(line MATCHES "${XML_QT_LIBS}") + set(writeLine FALSE) + append_value("${line}") + append_value("${QT_LIBS}" NOLF) + elseif(line MATCHES "${XML_END_TAG}") + set(writeLine TRUE) + endif() + + if(writeLine) + append_value("${line}") + endif() + endforeach() +endfunction() + +function(copy_file _extension _destination) + file(GLOB files "${CMAKE_BINARY_DIR}/*.${_extension}") + if(files) + list(GET files 0 file) + message(STATUS "Copy ${file} to ${_destination}") + file(COPY_FILE "${file}" "${_destination}" ONLY_IF_DIFFERENT) + else() + message(WARNING "Missing files(s) (${_extension}) in: ${CMAKE_BINARY_DIR}") + endif() +endfunction() + +file(GLOB AAR_FILES "${CMAKE_BINARY_DIR}/*${extension}") +if(NOT AAR_FILES) + message(FATAL_ERROR "Missing AAR(s) in: ${CMAKE_BINARY_DIR}") +endif() + +get_version_filename("${AAR_FILES}" VERSION) +set(AAR_TMP_DIR ${CMAKE_BINARY_DIR}/${VERSION}) +set(AAR_VALUES_TMP_DIR ${AAR_TMP_DIR}-values) +if(DIST_DIR) + get_filename_component(DIST_DIR "${DIST_DIR}" ABSOLUTE) +else() + set(DIST_DIR ${CMAKE_BINARY_DIR}/dist) +endif() +set(BASE_NAME ${DIST_DIR}/${prefix}-${VERSION}) +set(AAR ${BASE_NAME}${extension}) +if(EXISTS "${AAR_TMP_DIR}") + file(REMOVE_RECURSE "${AAR_TMP_DIR}") +endif() +if(EXISTS "${AAR_VALUES_TMP_DIR}") + file(REMOVE_RECURSE "${AAR_VALUES_TMP_DIR}") +endif() +if(EXISTS "${AAR}") + message(STATUS "Remove AAR: ${AAR}") + file(REMOVE "${AAR}") +endif() +if(NOT EXISTS "${DIST_DIR}") + file(MAKE_DIRECTORY ${DIST_DIR}) +endif() + +extract_aars("${AAR_FILES}" "${AAR_TMP_DIR}" "${AAR_VALUES_TMP_DIR}") +file(GLOB_RECURSE ALL_VALUES_XML "${AAR_VALUES_TMP_DIR}/values.xml") +merge_values("${AAR_TMP_DIR}" "${ALL_VALUES_XML}") + +message(STATUS "Create AAR: ${AAR}") +execute_process(COMMAND ${CMAKE_COMMAND} -E tar cf "${AAR}" --format=zip . WORKING_DIRECTORY "${AAR_TMP_DIR}") +file(REMOVE_RECURSE "${AAR_TMP_DIR}") +file(REMOVE_RECURSE "${AAR_VALUES_TMP_DIR}") + +copy_file("pom" "${BASE_NAME}.pom") +copy_file("jar" "${BASE_NAME}-sources.jar") diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index dd5b2771c..7923a754a 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -3,7 +3,7 @@ set(PACKAGE_VERSION ${PROJECT_VERSION}) -if(ANDROID AND NOT INTEGRATED_SDK) +if(ANDROID) set(PACKAGE_VERSION ${PACKAGE_VERSION}-${CMAKE_ANDROID_ARCH_ABI}) endif() diff --git a/cmake/SwiftPackage.cmake b/cmake/SwiftPackage.cmake index ac65ab2af..ebe52ee28 100644 --- a/cmake/SwiftPackage.cmake +++ b/cmake/SwiftPackage.cmake @@ -66,7 +66,16 @@ get_filename_component(SCRIPT_DIR "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY) set(PACKAGING_DIR "${SCRIPT_DIR}/../resources/packaging") configure_file("${PACKAGING_DIR}/ios/Package.swift" "${CMAKE_BINARY_DIR}/Package.swift" COPYONLY) -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dist) -set(dist_filename dist/${prefix}-${APP_NAME_VERSION}${APP_MISMATCH}.swiftpackage.zip) +if(DIST_DIR) + get_filename_component(DIST_DIR "${DIST_DIR}" ABSOLUTE) +else() + set(DIST_DIR ${CMAKE_BINARY_DIR}/dist) +endif() + +if(NOT EXISTS "${DIST_DIR}") + file(MAKE_DIRECTORY ${DIST_DIR}) +endif() + +set(dist_filename ${DIST_DIR}/${prefix}-${APP_NAME_VERSION}${APP_MISMATCH}.swiftpackage.zip) message(STATUS "Create package: ${dist_filename}") execute_process(COMMAND ${CMAKE_COMMAND} -E tar cf "${dist_filename}" --format=zip ${prefix}.xcframework Package.swift) diff --git a/cmake/Tools.Libraries.cmake b/cmake/Tools.Libraries.cmake index 9f1727405..73f02d7cd 100644 --- a/cmake/Tools.Libraries.cmake +++ b/cmake/Tools.Libraries.cmake @@ -26,7 +26,6 @@ if(NOT TARGET format.qml) unset(QMLFORMAT CACHE) # let's retry later else() file(GLOB_RECURSE FILES_QML ${PROJECT_SOURCE_DIR}/*.qml) - set(QMLFORMAT_CMD ${QMLFORMAT} -i -n -l unix -t -w 4) set(FORMATTING_FILE ${PROJECT_BINARY_DIR}/formatting.files.qml) file(WRITE ${FORMATTING_FILE} "") @@ -36,8 +35,8 @@ if(NOT TARGET format.qml) endforeach() add_custom_target(format.qml - COMMAND ${CMAKE_COMMAND} -E echo Calling ${QMLFORMAT_CMD} in version ${QMLFORMAT_VERSION} - COMMAND ${QMLFORMAT_CMD} -F ${FORMATTING_FILE} SOURCES ${FILES_QML}) + COMMAND ${CMAKE_COMMAND} -E echo Calling ${QMLFORMAT} in version ${QMLFORMAT_VERSION} + COMMAND ${QMLFORMAT} -F ${FORMATTING_FILE} SOURCES ${FILES_QML}) add_dependencies(format format.qml) endif() endif() diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index dda2b8296..bfaf2131c 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -80,11 +80,7 @@ set(ANDROID_TARGET_SDK_VERSION 35) set(CMAKE_ANDROID_STL_TYPE c++_shared) if(NOT CMAKE_ANDROID_ARCH_ABI) - if(INTEGRATED_SDK) - set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) - else() - set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a) - endif() + set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a) endif() # Only required by CMake < 3.30.3 with Android NDK 27 when diff --git a/cmake/ci/Android.cmake b/cmake/ci/Android.cmake new file mode 100644 index 000000000..6016522e4 --- /dev/null +++ b/cmake/ci/Android.cmake @@ -0,0 +1,41 @@ +if(NAME MATCHES "_APK_") + set(APK ON) + set(PRESET ci-android-apk) +elseif(NAME MATCHES "_AAR_") + set(AAR ON) + set(PRESET ci-android-aar) +else() + step(${CMAKE_COMMAND} -DDIST_DIR=${T_DIST_DIR} -P ${CMAKE_DIR}/Merge.cmake) + + if(RELEASE) + set(files *-sources.jar *.aar *.pom) + foreach(file ${files}) + file(GLOB file "${T_DIST_DIR}/${file}") + step(gpg --batch --passphrase $ENV{GPG_PSW} --pinentry-mode loopback -a --detach-sig -u $ENV{GPG_ID} ${file}) + endforeach() + endif() + + if(NOT REVIEW) + step(${CMAKE_COMMAND} -DCMD=DEPLOY_NEXUS -DPUBLISH=$ENV{PUBLISH} -P ${CMAKE_DIR}/cmd.cmake CHDIR ${T_DIST_DIR}) + endif() + return() +endif() + +if(REVIEW) + set(PRESET ${PRESET}-review) +endif() + +step(${T_CFG} --preset ${PRESET}) +step(${T_BUILD}) + +if(APK) + step(${T_TARGET} apk) + step(${T_TARGET} verify.signature) + step(${T_TARGET} dump.apk) +elseif(AAR) + step(${T_TARGET} aar) +endif() + +if(NOT RELEASE) + step(${T_CTEST}) +endif() diff --git a/cmake/ci/Configuration.cmake b/cmake/ci/Configuration.cmake new file mode 100644 index 000000000..bc4b74fab --- /dev/null +++ b/cmake/ci/Configuration.cmake @@ -0,0 +1,4 @@ +step(${T_CFG} --preset ci-linux) +step(${T_TARGET} ALL_Test_configuration) +step(${T_CTEST} -R Test_configuration ENV QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins) +step(${T_CTEST} -L json) diff --git a/cmake/ci/Container.cmake b/cmake/ci/Container.cmake new file mode 100644 index 000000000..ef3c81d4b --- /dev/null +++ b/cmake/ci/Container.cmake @@ -0,0 +1,65 @@ +if(NAME MATCHES "VNC") + set(TARGET vnc) + set(Dockerfile -f ${CMAKE_SOURCE_DIR}/resources/jenkins/docker/Dockerfile) +else() + set(TARGET sdk) +endif() + +if(RELEASE) + set(TAG $ENV{changeset}) + set(FILE_TAG ${TAG}) +elseif(REVIEW) + set(TAG $ENV{BUILD_TAG}) + set(FILE_TAG ${TAG}) +else() + set(TAG dev-$ENV{MERCURIAL_REVISION_BRANCH}) + string(REPLACE "-default" "" TAG "${TAG}") + set(FILE_TAG $ENV{MERCURIAL_REVISION_SHORT}) +endif() + +if(NOT EXISTS ${T_BUILD_DIR}) + step(${CMAKE_COMMAND} -E make_directory ${T_BUILD_DIR}) +endif() + +if(NOT VNC) + step(docker container prune -f) +endif() + +step(docker build --pull + -t dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG} + --build-arg CCACHE_REMOTE_STORAGE=redis://$ENV{CCACHE_REMOTE_STORAGE_HOST} + ${Dockerfile} + ${CMAKE_SOURCE_DIR} +) + +step(docker run --rm dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG} AusweisApp --help) + +step(docker save -o ${T_BUILD_DIR}/AusweisApp-${FILE_TAG}.tar dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG}) + +if(REVIEW) + step(docker rmi -f dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG}) +else() + step(docker push dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG}) +endif() + + +if(DAILY AND NOT VNC) + step(docker images --filter "dangling=true" -q OUTPUT IMAGES) + if(IMAGES) + string(STRIP "${IMAGES}" IMAGES) + string(REPLACE "\n" ";" IMAGES "${IMAGES}") + list(REVERSE IMAGES) + list(SUBLIST IMAGES 0 50 IMAGES) + foreach(entry ${IMAGES}) + step(docker rmi -f ${entry}) + endforeach() + endif() +endif() + + +if(RELEASE AND DEFINED ENV{LATEST}) + if($ENV{LATEST}) + step(docker tag dev-docker.govkg.de/ausweisapp/${TARGET}:${TAG} dev-docker.govkg.de/ausweisapp/${TARGET}:latest) + step(docker push dev-docker.govkg.de/ausweisapp/${TARGET}:latest) + endif() +endif() diff --git a/cmake/ci/Docker.cmake b/cmake/ci/Docker.cmake new file mode 100644 index 000000000..38d73c309 --- /dev/null +++ b/cmake/ci/Docker.cmake @@ -0,0 +1 @@ +include(Container) diff --git a/cmake/ci/Docs.cmake b/cmake/ci/Docs.cmake new file mode 100644 index 000000000..3959d673a --- /dev/null +++ b/cmake/ci/Docs.cmake @@ -0,0 +1,20 @@ +step(${T_CFG} --preset ci-tools) + +step(${T_TARGET} notes) +step(${T_TARGET} notes.latex.pdf) +step(${CMAKE_COMMAND} -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz . CHDIR ${T_BUILD_DIR}/docs/notes) + +step(${T_TARGET} sdk) +step(${T_TARGET} sdk.latex.pdf) +step(${CMAKE_COMMAND} -E tar cfJ ../AusweisApp_SDK.tar.xz . CHDIR ${T_BUILD_DIR}/docs/sdk/html) + +step(${T_TARGET} failurecodes) +step(${T_TARGET} failurecodes.latex.pdf) + +step(${T_TARGET} installation_integration.latex.pdf) + +step(${T_TARGET} license) + +if(NOT RELEASE) + step(${T_TARGET} doc8) +endif() diff --git a/cmake/ci/Formatting.cmake b/cmake/ci/Formatting.cmake new file mode 100644 index 000000000..966ea5f80 --- /dev/null +++ b/cmake/ci/Formatting.cmake @@ -0,0 +1,3 @@ +step(${T_CFG} --preset ci-tools-with-libs) +step(${CMAKE_SOURCE_DIR}/resources/jenkins/check_formatting.sh ${PENDING_PATCH} CHDIR ${CMAKE_SOURCE_DIR}) +step(${CMAKE_COMMAND} -DCMD=CHECK_FAILURE_CODES -P ${CMAKE_DIR}/cmd.cmake CHDIR ${CMAKE_SOURCE_DIR}) diff --git a/cmake/ci/FreeBSD.cmake b/cmake/ci/FreeBSD.cmake new file mode 100644 index 000000000..5e028311f --- /dev/null +++ b/cmake/ci/FreeBSD.cmake @@ -0,0 +1,5 @@ +set(LD_ENV LD_LIBRARY_PATH=${WORKSPACE}/libs/dist/lib) + +step(${T_CFG} --preset ci-bsd) +step(${T_BUILD} ENV ${LD_ENV}) +step(${T_CTEST} ENV ${LD_ENV} QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml) diff --git a/cmake/ci/Linux.cmake b/cmake/ci/Linux.cmake new file mode 100644 index 000000000..ec3dd3247 --- /dev/null +++ b/cmake/ci/Linux.cmake @@ -0,0 +1,22 @@ +if(NAME MATCHES "Integrated") + set(INTEGRATED ON) +endif() + +if(INTEGRATED) + set(PRESET ci-integrated) +else() + set(PRESET ci-linux) +endif() + +step(${T_CFG} --preset ${PRESET}) +step(${T_BUILD}) +step(${T_CTEST} ENV QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml) + +if(NOT INTEGRATED) + step(${CMAKE_COMMAND} --install ${T_BUILD_DIR} ENV DESTDIR=${WORKSPACE}/install) +endif() + +if(DAILY AND NOT INTEGRATED) + step(${T_TARGET} gcovr) + step(${T_TARGET} cloc.report) +endif() diff --git a/cmake/ci/MacOS.cmake b/cmake/ci/MacOS.cmake new file mode 100644 index 000000000..ccaf84e6e --- /dev/null +++ b/cmake/ci/MacOS.cmake @@ -0,0 +1,53 @@ +if(NAME MATCHES "Integrated") + set(INTEGRATED ON) +endif() + +if(NAME MATCHES "DMG_PKG" OR RELEASE) + set(PACKAGES ON) +endif() + +if(PACKAGES) + set(PRESET ci-macos-release) +elseif(INTEGRATED) + set(PRESET ci-macos-integrated) +else() + set(PRESET ci-macos) + set(CTEST_CFG -C Debug) +endif() + +step(security unlock-keychain $ENV{KEYCHAIN_CREDENTIALS} $ENV{HOME}/Library/Keychains/login.keychain-db) + +step(${T_CFG} --preset ${PRESET}) + +if(PACKAGES) + step(${T_TARGET} package --config MinSizeRel) + step(${CMAKE_COMMAND} -E tar cf ../../AusweisApp.app.dSYM.zip --format=zip AusweisApp.app.dSYM CHDIR ${T_BUILD_DIR}/src/MinSizeRel) + + file(GLOB_RECURSE apps LIST_DIRECTORIES ON "${T_BUILD_DIR}/_CPack_Packages/Darwin") + list(FILTER apps INCLUDE REGEX "\\.app$") + set(dragndrop ${apps}) + list(FILTER dragndrop INCLUDE REGEX "/DragNDrop/") + if(NOT dragndrop OR NOT apps) + message(FATAL_ERROR "no *.app directory found") + endif() + foreach(app ${apps}) + step(codesign -vvvv ${app}) + endforeach() + foreach(app ${dragndrop}) + step(spctl -a -vv ${app}) + endforeach() + + if(NOT REVIEW) + step(${CMAKE_COMMAND} -P ${CMAKE_DIR}/Notarization.cmake CHDIR ${T_BUILD_DIR}) + endif() +else() + step(${T_BUILD}) + step(${T_CTEST} ${CTEST_CFG} ENV QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml) +endif() + +if(RELEASE AND DEFINED ENV{USE_DISTRIBUTION_PROFILE}) + if($ENV{USE_DISTRIBUTION_PROFILE}) + file(GLOB pkgfile "${T_BUILD_DIR}/*.pkg") + step(xcrun altool -t osx --upload-app -u "ausweisapp@governikus.com" -p @env:PASSWORD -f ${pkgfile}) + endif() +endif() diff --git a/cmake/ci/SonarQube.cmake b/cmake/ci/SonarQube.cmake new file mode 100644 index 000000000..36bda2960 --- /dev/null +++ b/cmake/ci/SonarQube.cmake @@ -0,0 +1,49 @@ +set(CACHE_DIR cache) +if(NOT EXISTS ${CACHE_DIR}) + step(${CMAKE_COMMAND} -E make_directory ${CACHE_DIR}) +endif() + +set(SONARPATH ${WORKSPACE}/sonarqubetools) + +step(${CMAKE_COMMAND} -P ${CMAKE_DIR}/prepare_sonarqube_env.cmake) + +step(${T_CFG} --preset ci-linux) + +step(${SONARPATH}/dependency-check/bin/dependency-check.sh + --enableExperimental -f HTML -f JSON --scan ${CMAKE_DIR} --noupdate + --connectionString=jdbc:mariadb://dependency-check-db.govkg.de/dependencycheck + --dbUser=$ENV{DEPENDENCY_CHECK_USER} + --dbPassword=$ENV{DEPENDENCY_CHECK_PASSWORD} + --dbDriverName=org.mariadb.jdbc.Driver + CHDIR ${T_BUILD_DIR} +) + +step(${SONARPATH}/sonar-build-wrapper/build-wrapper-linux-x86-64 --out-dir ${T_BUILD_DIR} ${T_BUILD}) + +step(${T_CTEST} -LE qml -E Test_ui_qml_Qml) + +step(${T_TARGET} gcovr.sonar) + + + +if(REVIEW) + set(SONAR_CMDLINE + -Dsonar.pullrequest.key=$ENV{REVIEWBOARD_REVIEW_ID} + -Dsonar.pullrequest.branch=$ENV{REVIEWBOARD_REVIEW_ID} + -Dsonar.pullrequest.base=$ENV{MERCURIAL_REVISION_BRANCH} + ) +else() + set(SONAR_CMDLINE + -Dsonar.branch.name=$ENV{MERCURIAL_REVISION_BRANCH} + ) +endif() + +step( + ${SONARPATH}/sonar-scanner/bin/sonar-scanner + -Dsonar.scanner.metadataFilePath=${WORKSPACE}/tmp/sonar-metadata.txt + ${SONAR_CMDLINE} + -Dsonar.token=$ENV{SONARQUBE_TOKEN} + -Dsonar.qualitygate.wait=true + -Dsonar.qualitygate.timeout=90 + CHDIR ${T_BUILD_DIR} +) diff --git a/cmake/ci/Source.cmake b/cmake/ci/Source.cmake new file mode 100644 index 000000000..c25da4f19 --- /dev/null +++ b/cmake/ci/Source.cmake @@ -0,0 +1,7 @@ +step(${T_CFG} --preset ci-tools) +step(${T_TARGET} package_source) + +if(RELEASE) + file(GLOB TARBALL "${T_BUILD_DIR}/*.tar.gz") + step(gpg --batch --passphrase $ENV{GPG_PSW} --pinentry-mode loopback -a --detach-sig -u $ENV{GPG_ID} ${TARBALL}) +endif() diff --git a/cmake/ci/Win.cmake b/cmake/ci/Win.cmake new file mode 100644 index 000000000..83b5f596c --- /dev/null +++ b/cmake/ci/Win.cmake @@ -0,0 +1,37 @@ +if(NAME MATCHES "MSI") + set(PACKAGES ON) +endif() + +if(NAME MATCHES "GNU") + set(GNU ON) +elseif(NAME MATCHES "clang" AND DEFINED ENV{LLVM}) + set(PATH "$ENV{LLVM}") +endif() + +if(NOT GNU) + set(VCVARS cmd /c vcvarsall.bat amd64 && call) +endif() + +if(NAME MATCHES "_dev") + set(PRESET ci-win-debug) +elseif(PACKAGES) + set(PRESET ci-win-release) +else() + set(PRESET ci-win) +endif() + +step(${VCVARS} ${T_CFG} --preset ${PRESET} PATH "${PATH}") + +if(PACKAGES) + step(${VCVARS} ${T_TARGET} package) + step(${VCVARS} ${T_TARGET} package.sign) + if(NOT RELEASE) + step(${CMAKE_COMMAND} -DCMD=CHECK_WIX_WARNING -DFILE=${T_BUILD_DIR}/_CPack_Packages/win64/WIX/wix.log -P ${CMAKE_DIR}/cmd.cmake) + endif() +else() + step(${VCVARS} ${T_BUILD}) +endif() + +if(NOT RELEASE AND NOT PACKAGES) + step(${T_CTEST} ENV QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml PATH "${WORKSPACE}/libs/dist/bin") +endif() diff --git a/cmake/ci/iOS.cmake b/cmake/ci/iOS.cmake new file mode 100644 index 000000000..1fa4b0c29 --- /dev/null +++ b/cmake/ci/iOS.cmake @@ -0,0 +1,48 @@ +if(NAME MATCHES "IPA") + set(IPA ON) + set(TARGET ipa) + set(PRESET ci-ios) +elseif(NAME MATCHES "Framework") + set(TARGET zip) + + if(NAME MATCHES "Simulator_arm64_Framework") + set(PRESET ci-ios-framework-simulator-arm64) + elseif(NAME MATCHES "Simulator_Framework") + set(PRESET ci-ios-framework-simulator) + else() + set(PRESET ci-ios-framework) + endif() +elseif(NAME MATCHES "SwiftPackage") + step(${CMAKE_COMMAND} -DDIST_DIR=${T_DIST_DIR} -P ${CMAKE_DIR}/SwiftPackage.cmake) + return() +endif() + +step(security unlock-keychain $ENV{KEYCHAIN_CREDENTIALS} $ENV{HOME}/Library/Keychains/login.keychain-db) + +step(${T_CFG} --preset ${PRESET}) + +if(IPA AND NOT REVIEW) + step(xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive CHDIR ${T_BUILD_DIR}) + step(xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath . CHDIR ${T_BUILD_DIR}) +else() + step(xcodebuild -configuration MinSizeRel CHDIR ${T_BUILD_DIR}) +endif() + +if(RELEASE) + step(${CMAKE_COMMAND} -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build) +endif() + +step(xcodebuild -configuration MinSizeRel -target ${TARGET} CHDIR ${T_BUILD_DIR}) + +if(IPA AND NOT RELEASE) + step(${T_CTEST} -C MinSizeRel) +endif() + +if(IPA AND RELEASE AND DEFINED ENV{USE_DISTRIBUTION_PROFILE}) + if($ENV{USE_DISTRIBUTION_PROFILE}) + set(USER "ausweisapp@governikus.com") + file(GLOB ipafile "${T_BUILD_DIR}/*.ipa") + step(xcrun altool -t ios --validate-app --verbose -u "${USER}" -p @env:PASSWORD -f ${ipafile}) + step(xcrun altool -t ios --upload-app -u "${USER}" -p @env:PASSWORD -f ${ipafile}) + endif() +endif() diff --git a/cmake/cmd.cmake b/cmake/cmd.cmake index 20208b335..5b87d3510 100644 --- a/cmake/cmd.cmake +++ b/cmake/cmd.cmake @@ -1,15 +1,11 @@ -cmake_minimum_required(VERSION 3.13.0) -cmake_policy(SET CMP0057 NEW) +cmake_minimum_required(VERSION 3.19) ########################################### #### Usage: cmake -DCMD= -P cmake/cmd.cmake ########################################### function(EXECUTE) - execute_process(COMMAND ${ARGV} RESULT_VARIABLE _result) - if(NOT ${_result} EQUAL 0) - message(FATAL_ERROR "Process failed: ${_result}") - endif() + execute_process(COMMAND ${ARGV} COMMAND_ECHO STDOUT COMMAND_ERROR_IS_FATAL ANY) endfunction(EXECUTE) function(MESSAGE type) @@ -21,7 +17,7 @@ function(MESSAGE type) endfunction() -function(CREATE_HASH) +function(HASH) if(NOT FILES) message(FATAL_ERROR "You need to specify 'FILES'") endif() @@ -85,33 +81,26 @@ function(CHECK_WIX_WARNING) endfunction() -function(IMPORT_PATCH) - message(STATUS "Import patch...") - find_package(Python REQUIRED) - EXECUTE(${Python_EXECUTABLE} "${CMAKE_BINARY_DIR}/resources/jenkins/import.py") -endfunction() - - function(DEPLOY_NEXUS) - if(NOT DEFINED ENV{NEXUS_USERNAME} OR NOT DEFINED ENV{NEXUS_PSW}) - message(FATAL_ERROR "Please provide environment variable NEXUS_USERNAME and NEXUS_PSW") - endif() - - set(GNUPG_KEY 699BF3055B0A49224EFDE7C72D7479A531451088) - if(DEFINED ENV${GNUPG_KEY}) - set(GNUPG_KEY ENV${GNUPG_KEY}) - endif() - find_program(MVN_BIN mvn) if(NOT MVN_BIN) message(FATAL_ERROR "Cannot find mvn") endif() - set(SETTINGS_XML " - nexus - \${env.NEXUS_USERNAME} - \${env.NEXUS_PSW} - ") + set(SETTINGS_XML " + + + nexus + \${env.NEXUS_USERNAME} + \${env.NEXUS_PSW} + + + central + \${env.CENTRAL_USERNAME} + \${env.CENTRAL_PSW} + + + ") file(WRITE settings.xml "${SETTINGS_XML}") function(get_file _suffix _out_var) @@ -121,7 +110,7 @@ function(DEPLOY_NEXUS) if(list_length GREATER 1) message(FATAL_ERROR "Found more than one entry: ${file}") elseif(asc_length EQUAL 0) - message(FATAL_ERROR "File ${file} not found. Maybe signature is missing?: gpg -a -u ${GNUPG_KEY} --detach-sig") + message(FATAL_ERROR "File ${file} not found. Maybe signature is missing?") endif() set(${_out_var} ${file} PARENT_SCOPE) @@ -135,22 +124,22 @@ function(DEPLOY_NEXUS) if(is_snapshot) set(NEXUS_URL https://repo.govkg.de/repository/ausweisapp-snapshots) else() - if(PUBLIC) - set(NEXUS_URL https://s01.oss.sonatype.org/service/local/staging/deploy/maven2) - else() - set(NEXUS_URL https://repo.govkg.de/repository/ausweisapp-releases) - endif() + set(NEXUS_URL https://repo.govkg.de/repository/ausweisapp-releases) endif() - EXECUTE(${MVN_BIN} deploy:deploy-file -Dfile=${FILE_AAR} -DpomFile=${FILE_POM} -Dsources=${FILE_JAR} -DrepositoryId=nexus -Durl=${NEXUS_URL} --settings settings.xml) + set(MVN_CMD ${MVN_BIN} deploy:3.1.3:deploy-file -Dfile=${FILE_AAR} -DpomFile=${FILE_POM} -Dsources=${FILE_JAR} --settings settings.xml) + EXECUTE(${MVN_CMD} -DrepositoryId=nexus -Durl=${NEXUS_URL}) + + if(PUBLISH AND NOT is_snapshot) + set(CENTRAL_PARAMS -DrepositoryId=central -Durl=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2) + EXECUTE(${MVN_CMD} ${CENTRAL_PARAMS}) - if(PUBLIC) get_file("*.aar.asc" FILE_AAR_ASC) get_file("*.pom.asc" FILE_POM_ASC) get_file("*-sources.jar.asc" FILE_SOURCES_ASC) function(mvn_upload _file _packaging _classifier) - EXECUTE(${MVN_BIN} deploy:deploy-file -Dfile=${_file} -Dpackaging=${_packaging} -Dclassifier=${_classifier} -DpomFile=${FILE_POM} -DrepositoryId=nexus -Durl=${NEXUS_URL} --settings settings.xml) + EXECUTE(${MVN_BIN} deploy:3.1.3:deploy-file -Dfile=${_file} -Dpackaging=${_packaging} -Dclassifier=${_classifier} -DpomFile=${FILE_POM} ${CENTRAL_PARAMS} --settings settings.xml) endfunction() mvn_upload("${FILE_AAR_ASC}" "aar.asc" "") @@ -315,24 +304,13 @@ function(CHECK_QMLTYPES) endif() endfunction() + if(NOT CMD) message(FATAL_ERROR "You need to specify 'CMD'") endif() -if(CMD STREQUAL "HASH") - CREATE_HASH() -elseif(CMD STREQUAL "CHECK_WIX_WARNING") - CHECK_WIX_WARNING() -elseif(CMD STREQUAL "IMPORT_PATCH") - IMPORT_PATCH() -elseif(CMD STREQUAL "DEPLOY_NEXUS") - DEPLOY_NEXUS() -elseif(CMD STREQUAL "CHECK_FAILURE_CODES") - CHECK_FAILURE_CODES() -elseif(CMD STREQUAL "CHECK_QMLDIR") - CHECK_QMLDIR() -elseif(CMD STREQUAL "CHECK_QMLTYPES") - CHECK_QMLTYPES() +if(COMMAND "${CMD}") + cmake_language(CALL ${CMD}) else() message(FATAL_ERROR "Unknown CMD: ${CMD}") endif() diff --git a/docs/releasenotes/2.2.2.rst b/docs/releasenotes/2.2.2.rst new file mode 100644 index 000000000..00e5e5af6 --- /dev/null +++ b/docs/releasenotes/2.2.2.rst @@ -0,0 +1,16 @@ +AusweisApp 2.2.2 +^^^^^^^^^^^^^^^^ + +**Releasedatum:** 23. Oktober 2024 + + +Anwender +"""""""" +- Visuelle Anpassungen und Optimierungen der grafischen Oberfläche. + +- Optimierung der Barrierearmut und Tastaturbedienbarkeit. + + +Entwickler +"""""""""" +- Ergänzung der Android-ABIs armeabi-v7a und x86_64 zusätzlich zu arm64-v8a im SDK. diff --git a/docs/releasenotes/appcast.rst b/docs/releasenotes/appcast.rst index bcefbe3f8..1439c4aff 100644 --- a/docs/releasenotes/appcast.rst +++ b/docs/releasenotes/appcast.rst @@ -4,6 +4,7 @@ Release Notes .. toctree:: :maxdepth: 1 + 2.2.2 2.2.1 2.2.0 announce diff --git a/docs/releasenotes/issues.rst b/docs/releasenotes/issues.rst index 03f96bf85..9f6b82386 100644 --- a/docs/releasenotes/issues.rst +++ b/docs/releasenotes/issues.rst @@ -31,12 +31,15 @@ Windows / macOS - Der Installationsdialog (bei Installation und auch Deinstallation) richtet sich nicht nach der Systemsprache. +- Auf macOS ist derzeit keine Unterstützung für die Funktion "Full Keyboard + Access" gegeben. + Android / iOS """"""""""""" - Zu Nutzungseinschränkungen einzelner Geräte beachten Sie bitte unsere - Homepage https://www.ausweisapp.bund.de/aa2/mobile-devices + Webseite https://www.ausweisapp.bund.de/aa2/mobile-devices - Unter Umständen kommt es zu Stabilitätsproblemen der NFC-Schnittstelle. @@ -45,6 +48,9 @@ Android / iOS Dazu zählt die Änderung der Systemsprache und die Änderung des Typs der Navigationsleiste (Gesten / Schaltflächen). +- Unter iOS ist derzeit keine Unterstützung für die Funktion "Full Keyboard + Access" gegeben. + Barrierearmut """"""""""""" diff --git a/docs/releasenotes/support.rst b/docs/releasenotes/support.rst index 9d43b48e5..96cfbb0f5 100644 --- a/docs/releasenotes/support.rst +++ b/docs/releasenotes/support.rst @@ -14,6 +14,8 @@ Betriebssysteme - macOS 14.0 +- macOS 15.0 + - Windows 10 (64 Bit) ab Version 1809 - Windows 11 @@ -24,7 +26,7 @@ Betriebssysteme - Windows Server 2022 -- Android 9 und höher (armeabi-v7a, arm64-v8a) +- Android 9 und höher (armeabi-v7a, arm64-v8a, x86_64) - iOS 14 und höher @@ -54,55 +56,73 @@ und sollte daher mit allen marktüblichen Browsern verwendet werden können. Im Rahmen der Qualitätssicherung werden die folgenden Browserversionen getestet. -- Chrome 126 +- Chrome 129 -- Firefox 127 +- Firefox 131 -- Safari 17.4 (macOS) +- Safari 18.0 (macOS) -- Edge 126 +- Edge 129 Kartenleser ~~~~~~~~~~~ Alle Kartenleser, die die Online-Ausweisfunktion unterstützen und nach -BSI TR-03119 zertifiziert sind. Details hierzu befinden sich auf der Homepage -des BSI unter "Nach Technischen Richtlinien zertifizierte Produkte". +BSI TR-03119 zertifiziert sind. Details hierzu befinden sich auf der Website +des BSI unter `Zertifizierte Produkte - Chipkartenleser mit PA-Unterstützung +`_. + + +- ACS ACR1281U-C1 -Zusätzlich werden folgende nicht zertifizierte Kartenleser getestet. +- ACS ACR1581U-C1 + +- Cherry Secure Board 1.0 + +- Cherry ST-1275 - Cherry TC-1200 - Cherry TC-1300 -- Identiv Cloud 4701 F +- HID OMNIKEY 5021 CL -- Identiv SCL3711 +- HID OMNIKEY 5022 CL -- Identiv Cloud 3700 F +- HID OMNIKEY 5421 -- Identiv CLOUD 4700 F +- HID OMNIKEY 5422 -- ACR1252U +- Identiv 3700 F -- OMNIKEY 5021 CL +- Identiv 3720 F + +- Identiv 3721 F + +- Identiv 4701 F + +- Identiv Cloud 4700 F + +- Identiv SCL01x + +- Identiv SCL3711 -- OMNIKEY 5421 +- REINER SCT cyberJack wave (via USB) -- cyberJack wave (via USB) +- Signotec Omega Pad -Aktuelle Informationen zu Kartenlesern finden Sie auf unserer Webseite: -https://www.ausweisapp.bund.de/aa2/cardreader +Aktuelle Informationen zu Kartenlesern finden Sie auf unserer Website unter +`USB-Kartenleser `_. Alle NFC-fähigen Smartphones bzw. Tablets, die die Online-Ausweisfunktion unterstützen, können als Kartenleser verwendet werden. Dabei ist es notwendig die mobile |AppName| auf dem jeweiligen Smartphone zu installieren und zu starten. -Details hierzu befinden sich auf der Homepage: -https://www.ausweisapp.bund.de/aa2/mobile-devices +Details hierzu befinden sich auf unserer Website unter +`Smartphones & Tablets `_. Android / iOS @@ -120,18 +140,18 @@ folgenden Browser zu verwenden. - Chrome 126 (iOS/Android) -- Firefox 127 (iOS/Android) +- Firefox 131 (iOS/Android) -- Samsung Internet 25 (Android) +- Samsung Internet 26 (Android) -- Safari 17.4 (iOS) +- Safari 18.0 (iOS) Kartenleser ~~~~~~~~~~~ Alle NFC-fähigen Smartphones bzw. Tablets, die die Online-Ausweisfunktion -unterstützen. Details hierzu befinden sich auf der Homepage: -https://www.ausweisapp.bund.de/aa2/mobile-devices +unterstützen. Details hierzu befinden sich auf unserer Website unter +`Smartphones & Tablets `_. Ebenfalls ist es möglich ein weiteres Smartphone als Kartenleser zu verwenden. Dabei ist es notwendig die mobile |AppName| auf dem jeweiligen Smartphone zu diff --git a/docs/releasenotes/versions.rst b/docs/releasenotes/versions.rst index c7e6d0c36..e9ae92b2e 100644 --- a/docs/releasenotes/versions.rst +++ b/docs/releasenotes/versions.rst @@ -6,6 +6,7 @@ Versionszweig 2.2 .. toctree:: :maxdepth: 1 + 2.2.2 2.2.1 2.2.0 diff --git a/docs/sdk/android.rst b/docs/sdk/android.rst index 874544e65..91739e523 100644 --- a/docs/sdk/android.rst +++ b/docs/sdk/android.rst @@ -35,7 +35,7 @@ be fetched by Android's default build system **gradle**. SDK --- The |AppName| SDK is distributed as an AAR package that contains -native **arm64-v8a** libraries only. +native **arm64-v8a**, **x86_64** and **armeabi-v7a** libraries only. The AAR package is available in the default repository of Android. The following listing shows the required **mavenCentral** in **build.gradle**. diff --git a/docs/sdk/changelog.rst b/docs/sdk/changelog.rst index 817a04372..94b5618e2 100644 --- a/docs/sdk/changelog.rst +++ b/docs/sdk/changelog.rst @@ -1,6 +1,18 @@ Changelog ========= +Version 2.2.2 +^^^^^^^^^^^^^ +* Added Android ABIs armeabi-v7a and x86_64 in addition to arm64-v8a. + + +Version 2.2.1 +^^^^^^^^^^^^^ +* Stabilized fast SDK restarts on iOS. +* Support 16 KB page sizes on Android. +* Updated Android NDK to r27b (27.1.12297006). + + Version 2.2.0 ^^^^^^^^^^^^^ * Introduced the following additions in :ref:`api_level` **3**: diff --git a/libs/README.rst b/libs/README.rst index 97442200c..3b9a6f6f1 100644 --- a/libs/README.rst +++ b/libs/README.rst @@ -6,7 +6,7 @@ Abhängigkeiten und die Compilertools beinhaltet. Unterstützte C++17 Compiler: -- MinGW / GCC >= 11.2 +- MinGW / GCC >= 13.1 - Clang >= 5.0 @@ -145,7 +145,8 @@ MinGW - https://wiki.qt.io/MinGW -- Getestet: x86_64-11.2.0-release-posix-seh-rt_v9-rev3 +- Getestet: 13.1.0-202407240918mingw1310 + https://download.qt.io/online/qtsdkrepository/windows_x86/desktop/tools_mingw1310 - Pfad zu MinGW-bin-Verzeichnis muss zur Path-Umgebungsvariable hinzugefügt werden diff --git a/libs/patch.py b/libs/patch.py index 088fbbab3..e1114fb14 100644 --- a/libs/patch.py +++ b/libs/patch.py @@ -31,7 +31,7 @@ from __future__ import print_function __author__ = "Conan.io " -__version__ = "1.17.4" +__version__ = "1.18.0" __license__ = "MIT" __url__ = "https://github.com/conan-io/python-patch" @@ -424,7 +424,7 @@ def lineno(self): hunkparsed = False # state after successfully parsed hunk # regexp to match start of hunk, used groups - 1,3,4,6 - re_hunk_start = re.compile(b"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@") + re_hunk_start = re.compile(br"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@") self.errors = 0 # temp buffers for header and filenames info @@ -575,7 +575,7 @@ def lineno(self): # strptime function and %z support is patchy, so we drop # everything from the . onwards and group the year and time # separately. - re_filename_date_time = b"^--- ([^\t]+)(?:\s([0-9-]+)\s([0-9:]+)|.*)" + re_filename_date_time = br"^--- ([^\t]+)(?:\s([0-9-]+)\s([0-9:]+)|.*)" match = re.match(re_filename_date_time, line) # todo: support spaces in filenames if match: @@ -618,7 +618,7 @@ def lineno(self): filenames = False headscan = True else: - re_filename_date_time = b"^\+\+\+ ([^\t]+)(?:\s([0-9-]+)\s([0-9:]+)|.*)" + re_filename_date_time = br"^\+\+\+ ([^\t]+)(?:\s([0-9-]+)\s([0-9:]+)|.*)" match = re.match(re_filename_date_time, line) if not match: warning("skipping invalid patch - no target filename at line %d" % (lineno+1)) @@ -650,7 +650,7 @@ def lineno(self): continue if hunkhead: - match = re.match(b"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@(.*)", line) + match = re.match(br"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@(.*)", line) if not match: if not p.hunks: warning("skipping invalid patch with no hunks for file %s" % p.source) diff --git a/libs/patches/openssl-0002-Harden-BN_GF2m_poly2arr-against-misuse.patch b/libs/patches/openssl-0002-Harden-BN_GF2m_poly2arr-against-misuse.patch new file mode 100644 index 000000000..5c45e147b --- /dev/null +++ b/libs/patches/openssl-0002-Harden-BN_GF2m_poly2arr-against-misuse.patch @@ -0,0 +1,199 @@ +From 080b220bd1cacb498a65b07d937a2fbc26c30f94 Mon Sep 17 00:00:00 2001 +From: Viktor Dukhovni +Date: Thu, 19 Sep 2024 01:02:40 +1000 +Subject: Harden BN_GF2m_poly2arr against misuse. + +The BN_GF2m_poly2arr() function converts characteristic-2 field +(GF_{2^m}) Galois polynomials from a representation as a BIGNUM bitmask, +to a compact array with just the exponents of the non-zero terms. + +These polynomials are then used in BN_GF2m_mod_arr() to perform modular +reduction. A precondition of calling BN_GF2m_mod_arr() is that the +polynomial must have a non-zero constant term (i.e. the array has `0` as +its final element). + +Internally, callers of BN_GF2m_poly2arr() did not verify that +precondition, and binary EC curve parameters with an invalid polynomial +could lead to out of bounds memory reads and writes in BN_GF2m_mod_arr(). + +The precondition is always true for polynomials that arise from the +standard form of EC parameters for characteristic-two fields (X9.62). +See the "Finite Field Identification" section of: + + https://www.itu.int/ITU-T/formal-language/itu-t/x/x894/2018-cor1/ANSI-X9-62.html + +The OpenSSL GF(2^m) code supports only the trinomial and pentanomial +basis X9.62 forms. + +This commit updates BN_GF2m_poly2arr() to return `0` (failure) when +the constant term is zero (i.e. the input bitmask BIGNUM is not odd). + +Additionally, the return value is made unambiguous when there is not +enough space to also pad the array with a final `-1` sentinel value. +The return value is now always the number of elements (including the +final `-1`) that would be filled when the output array is sufficiently +large. Previously the same count was returned both when the array has +just enough room for the final `-1` and when it had only enough space +for non-sentinel values. + +Finally, BN_GF2m_poly2arr() is updated to reject polynomials whose +degree exceeds `OPENSSL_ECC_MAX_FIELD_BITS`, this guards against +CPU exhausition attacks via excessively large inputs. + +The above issues do not arise in processing X.509 certificates. These +generally have EC keys from "named curves", and RFC5840 (Section 2.1.1) +disallows explicit EC parameters. The TLS code in OpenSSL enforces this +constraint only after the certificate is decoded, but, even if explicit +parameters are specified, they are in X9.62 form, which cannot represent +problem values as noted above. + +Initially reported as oss-fuzz issue 71623. + +A closely related issue was earlier reported in +. + +Severity: Low, CVE-2024-9143 + +Reviewed-by: Matt Caswell +Reviewed-by: Bernd Edlinger +Reviewed-by: Paul Dale +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/25639) + +(cherry picked from commit 8e008cb8b23ec7dc75c45a66eeed09c815b11cd2) +(cherry picked from commit c0d3e4d32d2805f49bec30547f225bc4d092e1f4) +--- + crypto/bn/bn_gf2m.c | 28 +++++++++++++++------- + test/ec_internal_test.c | 51 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+), 8 deletions(-) + +diff --git x/crypto/bn/bn_gf2m.c y/crypto/bn/bn_gf2m.c +index 444c5ca7a37554f24b3d9cca83a330c7b5e1757e..ae7e9d751c29cefa3703b380edbfc0303eca5623 100644 +--- x/crypto/bn/bn_gf2m.c ++++ y/crypto/bn/bn_gf2m.c +@@ -15,6 +15,7 @@ + #include "bn_local.h" + + #ifndef OPENSSL_NO_EC2M ++# include + + /* + * Maximum number of iterations before BN_GF2m_mod_solve_quad_arr should +@@ -1130,16 +1131,26 @@ int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + /* + * Convert the bit-string representation of a polynomial ( \sum_{i=0}^n a_i * + * x^i) into an array of integers corresponding to the bits with non-zero +- * coefficient. Array is terminated with -1. Up to max elements of the array +- * will be filled. Return value is total number of array elements that would +- * be filled if array was large enough. ++ * coefficient. The array is intended to be suitable for use with ++ * `BN_GF2m_mod_arr()`, and so the constant term of the polynomial must not be ++ * zero. This translates to a requirement that the input BIGNUM `a` is odd. ++ * ++ * Given sufficient room, the array is terminated with -1. Up to max elements ++ * of the array will be filled. ++ * ++ * The return value is total number of array elements that would be filled if ++ * array was large enough, including the terminating `-1`. It is `0` when `a` ++ * is not odd or the constant term is zero contrary to requirement. ++ * ++ * The return value is also `0` when the leading exponent exceeds ++ * `OPENSSL_ECC_MAX_FIELD_BITS`, this guards against CPU exhaustion attacks, + */ + int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max) + { + int i, j, k = 0; + BN_ULONG mask; + +- if (BN_is_zero(a)) ++ if (!BN_is_odd(a)) + return 0; + + for (i = a->top - 1; i >= 0; i--) { +@@ -1157,12 +1168,13 @@ int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max) + } + } + +- if (k < max) { ++ if (k > 0 && p[0] > OPENSSL_ECC_MAX_FIELD_BITS) ++ return 0; ++ ++ if (k < max) + p[k] = -1; +- k++; +- } + +- return k; ++ return k + 1; + } + + /* +diff --git x/test/ec_internal_test.c y/test/ec_internal_test.c +index 5076f9894d5b8ab76bdc8311d6bfc326394d0202..92904cfc42b20a28592d661a856dffc4bfe9969b 100644 +--- x/test/ec_internal_test.c ++++ y/test/ec_internal_test.c +@@ -155,6 +155,56 @@ static int field_tests_ecp_mont(void) + } + + #ifndef OPENSSL_NO_EC2M ++/* Test that decoding of invalid GF2m field parameters fails. */ ++static int ec2m_field_sanity(void) ++{ ++ int ret = 0; ++ BN_CTX *ctx = BN_CTX_new(); ++ BIGNUM *p, *a, *b; ++ EC_GROUP *group1 = NULL, *group2 = NULL, *group3 = NULL; ++ ++ TEST_info("Testing GF2m hardening\n"); ++ ++ BN_CTX_start(ctx); ++ p = BN_CTX_get(ctx); ++ a = BN_CTX_get(ctx); ++ if (!TEST_ptr(b = BN_CTX_get(ctx)) ++ || !TEST_true(BN_one(a)) ++ || !TEST_true(BN_one(b))) ++ goto out; ++ ++ /* Even pentanomial value should be rejected */ ++ if (!TEST_true(BN_set_word(p, 0xf2))) ++ goto out; ++ if (!TEST_ptr_null(group1 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("Zero constant term accepted in GF2m polynomial"); ++ ++ /* Odd hexanomial should also be rejected */ ++ if (!TEST_true(BN_set_word(p, 0xf3))) ++ goto out; ++ if (!TEST_ptr_null(group2 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("Hexanomial accepted as GF2m polynomial"); ++ ++ /* Excessive polynomial degree should also be rejected */ ++ if (!TEST_true(BN_set_word(p, 0x71)) ++ || !TEST_true(BN_set_bit(p, OPENSSL_ECC_MAX_FIELD_BITS + 1))) ++ goto out; ++ if (!TEST_ptr_null(group3 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("GF2m polynomial degree > %d accepted", ++ OPENSSL_ECC_MAX_FIELD_BITS); ++ ++ ret = group1 == NULL && group2 == NULL && group3 == NULL; ++ ++ out: ++ EC_GROUP_free(group1); ++ EC_GROUP_free(group2); ++ EC_GROUP_free(group3); ++ BN_CTX_end(ctx); ++ BN_CTX_free(ctx); ++ ++ return ret; ++} ++ + /* test EC_GF2m_simple_method directly */ + static int field_tests_ec2_simple(void) + { +@@ -443,6 +493,7 @@ int setup_tests(void) + ADD_TEST(field_tests_ecp_simple); + ADD_TEST(field_tests_ecp_mont); + #ifndef OPENSSL_NO_EC2M ++ ADD_TEST(ec2m_field_sanity); + ADD_TEST(field_tests_ec2_simple); + #endif + ADD_ALL_TESTS(field_tests_default, crv_len); diff --git a/libs/patches/qtconnectivity-0003-iOS-Improve-reporting-of-NFCReaderTransceiveErrorSes.patch b/libs/patches/qtconnectivity-0003-iOS-Improve-reporting-of-NFCReaderTransceiveErrorSes.patch new file mode 100644 index 000000000..f113876bf --- /dev/null +++ b/libs/patches/qtconnectivity-0003-iOS-Improve-reporting-of-NFCReaderTransceiveErrorSes.patch @@ -0,0 +1,119 @@ +From 974c647cc989b635a9214e3a81daaa7548637c60 Mon Sep 17 00:00:00 2001 +From: Timon Sassor +Date: Fri, 11 Oct 2024 15:57:51 +0200 +Subject: iOS: Improve reporting of NFCReaderTransceiveErrorSessionInvalidated + +In 9163f0081459fd9303aa6c31602f4e1b95e5e1b6 the reporting of unsupported NFC +cards was improved on iOS by emitting QNearFieldTarget::UnsupportedTargetError. +In the meantime, Apple has changed the behavior. Current versions of iOS no +longer use NFCReaderErrorSecurityViolation during connect but use +NFCReaderTransceiveErrorSessionInvalidated or +NFCReaderTransceiveErrorTagNotConnected in sendCommandAPDU. + +Change-Id: I4fd553ed25718a03de9aecfe4e67501714c78376 +--- + src/nfc/qnearfieldtarget_ios.mm | 30 +++++++++++++++++++++++------- + src/nfc/qnearfieldtarget_ios_p.h | 7 ++++--- + 2 files changed, 27 insertions(+), 10 deletions(-) + +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_ios.mm y/qtconnectivity/src/nfc/qnearfieldtarget_ios.mm +index 256393da290c1db19f403196eb97143b9f8b3b67..5a6738bfe15548f897b46c2036cd27a56fe14188 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_ios.mm ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_ios.mm +@@ -19,8 +19,8 @@ QT_BEGIN_NAMESPACE + + Q_APPLICATION_STATIC(ResponseProvider, responseProvider) + +-void ResponseProvider::provideResponse(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer) { +- Q_EMIT responseReceived(requestId, success, recvBuffer); ++void ResponseProvider::provideResponse(QNearFieldTarget::RequestId requestId, QNearFieldTarget::Error error, QByteArray recvBuffer) { ++ Q_EMIT responseReceived(requestId, error, recvBuffer); + } + + void NfcDeleter::operator()(void *obj) +@@ -275,6 +275,7 @@ bool QNearFieldTargetPrivateImpl::connect() + requestInProgress = QNearFieldTarget::RequestId(); + if (errorCode == -1) { + connected = true; ++ justConnected = true; + onExecuteRequest(); + } else { + const auto requestId = queue.dequeue().first; +@@ -428,23 +429,38 @@ void QNearFieldTargetPrivateImpl::onExecuteRequest() + QByteArray recvBuffer = QByteArray::fromNSData(responseData); + recvBuffer += static_cast(sw1); + recvBuffer += static_cast(sw2); +- const bool success = error == nil; +- responseProvider->provideResponse(request.first, success, recvBuffer); ++ auto errorToReport = QNearFieldTarget::NoError; ++ if (error != nil) ++ { ++ switch (error.code) { ++ case NFCReaderError::NFCReaderTransceiveErrorSessionInvalidated: ++ case NFCReaderError::NFCReaderTransceiveErrorTagNotConnected: ++ if (justConnected) { ++ errorToReport = QNearFieldTarget::SecurityViolation; ++ justConnected = false; ++ break; ++ } ++ Q_FALLTHROUGH(); ++ default: ++ errorToReport = QNearFieldTarget::CommandError; ++ } ++ } ++ responseProvider->provideResponse(request.first, errorToReport, recvBuffer); + }]; + } + } + +-void QNearFieldTargetPrivateImpl::onResponseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer) ++void QNearFieldTargetPrivateImpl::onResponseReceived(QNearFieldTarget::RequestId requestId, QNearFieldTarget::Error error, QByteArray recvBuffer) + { + if (requestInProgress != requestId) + return; + + requestInProgress = QNearFieldTarget::RequestId(); +- if (success) { ++ if (error == QNearFieldTarget::NoError) { + setResponseForRequest(requestId, recvBuffer, true); + onExecuteRequest(); + } else { +- reportError(QNearFieldTarget::CommandError, requestId); ++ reportError(error, requestId); + invalidate(); + } + } +diff --git x/qtconnectivity/src/nfc/qnearfieldtarget_ios_p.h y/qtconnectivity/src/nfc/qnearfieldtarget_ios_p.h +index c0cde0b621c9f64bc14d36a4b469462a88c5b9b0..9c9b1d302ff1e107fbec27f2d2cbaf885608a155 100644 +--- x/qtconnectivity/src/nfc/qnearfieldtarget_ios_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldtarget_ios_p.h +@@ -33,10 +33,10 @@ class ResponseProvider : public QObject + Q_OBJECT + + public: +- void provideResponse(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer); ++ void provideResponse(QNearFieldTarget::RequestId requestId, QNearFieldTarget::Error error, QByteArray recvBuffer); + + Q_SIGNALS: +- void responseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer); ++ void responseReceived(QNearFieldTarget::RequestId requestId, QNearFieldTarget::Error error, QByteArray recvBuffer); + }; + + struct NfcDeleter +@@ -95,6 +95,7 @@ private: + bool hasNDEFMessage = false; + + bool connected = false; ++ bool justConnected = false; + QTimer targetCheckTimer; + QNearFieldTarget::RequestId requestInProgress; + QQueue> queue; +@@ -108,7 +109,7 @@ private Q_SLOTS: + void onTargetCheck(); + void onTargetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id); + void onExecuteRequest(); +- void onResponseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer); ++ void onResponseReceived(QNearFieldTarget::RequestId requestId, QNearFieldTarget::Error error, QByteArray recvBuffer); + // NDEF: + void messageRead(const QNdefMessage &ndefMessage, QNearFieldTarget::RequestId request); + void messageWritten(QNearFieldTarget::RequestId request); diff --git a/resources/ausweisapp.qrc b/resources/ausweisapp.qrc index 2daf82129..144262037 100644 --- a/resources/ausweisapp.qrc +++ b/resources/ausweisapp.qrc @@ -78,6 +78,7 @@ images/material_refresh.svg images/mydata_tile.svg images/npa.svg + images/no_internet.svg images/open_website.svg images/phone_to_pc.svg images/puk_correct_darkmode.svg diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index 1ec68dea3..ec684d274 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -16,9 +16,6 @@ images/mobile/material_view_headline.svg images/mobile/mydata.svg images/mobile/mydata_button.svg - images/mobile/no_internet_darkmode.svg - images/mobile/no_internet_highcontrast.svg - images/mobile/no_internet_lightmode.svg images/mobile/phone_card_reader.svg images/mobile/phone_nfc.svg images/mobile/phone_nfc_info.svg diff --git a/resources/images/mobile/no_internet_darkmode.svg b/resources/images/mobile/no_internet_darkmode.svg deleted file mode 100644 index ebc9275c2..000000000 --- a/resources/images/mobile/no_internet_darkmode.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - diff --git a/resources/images/mobile/no_internet_highcontrast.svg b/resources/images/mobile/no_internet_highcontrast.svg deleted file mode 100644 index a569d5a16..000000000 --- a/resources/images/mobile/no_internet_highcontrast.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - diff --git a/resources/images/mobile/no_internet_lightmode.svg b/resources/images/no_internet.svg similarity index 100% rename from resources/images/mobile/no_internet_lightmode.svg rename to resources/images/no_internet.svg diff --git a/resources/jenkins/check_formatting.sh b/resources/jenkins/check_formatting.sh index 80b33c316..080cc4707 100755 --- a/resources/jenkins/check_formatting.sh +++ b/resources/jenkins/check_formatting.sh @@ -5,6 +5,12 @@ echo "Warning: This script should be called on jenkins only" exit 1 fi +if [ -n "$1" ]; then + PATCH=$1 +else + PATCH="../patch.diff" +fi + REVISION_CURRENT=$(hg id -i) # Check if the current repository state is formatted @@ -18,7 +24,7 @@ if [ "$STATUS_CURRENT" != "0" ]; then fi REVISION_FORMATTED=$(hg id -i) -if [ ! -f ../patch.diff ] && [ -n "$NO_PATCH" ]; then +if [ ! -f "$PATCH" ] && [ -n "$NO_PATCH" ]; then if [ "$STATUS_CURRENT" != "0" ]; then echo 'FORMATTING FAILED' else @@ -31,7 +37,7 @@ fi hg update -C -r "$REVISION_CURRENT" # Apply patch on the current repository state -hg --config patch.eol=auto --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' ../patch.diff +hg --config patch.eol=auto --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' "$PATCH" if [ "$?" != "0" ]; then echo 'FORMATTING FAILED: Patch cannot be applied' exit 0 @@ -58,7 +64,7 @@ fi hg update -C -r "$REVISION_FORMATTED" # Apply patch on the formatted repository state -hg --config patch.eol=auto --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' ../patch.diff +hg --config patch.eol=auto --config phases.new-commit=secret import -m 'jenkins patch formatting' -d 'today' -u 'jenkins' "$PATCH" if [ "$?" != "0" ]; then echo 'FORMATTING FAILED: Patch cannot be applied, because the current repository state is unformatted and the patch conflicts with the formatted repository state without fixing the formatting!' exit 0 diff --git a/resources/jenkins/docker/Dockerfile b/resources/jenkins/docker/Dockerfile index 6e8a94634..dd979ef30 100644 --- a/resources/jenkins/docker/Dockerfile +++ b/resources/jenkins/docker/Dockerfile @@ -1,6 +1,6 @@ ARG ALPINE_VERSION=3.17 -FROM alpine:$ALPINE_VERSION as builder +FROM alpine:$ALPINE_VERSION AS builder # Install development stuff RUN apk --no-cache upgrade -a && \ apk --no-cache add patch cmake ccache make ninja g++ pkgconf pcsc-lite-dev binutils-gold eudev-libs \ diff --git a/resources/jenkins/docker/alpine-common/Dockerfile b/resources/jenkins/docker/alpine-common/Dockerfile index 6a3865f79..831a0cdc8 100644 --- a/resources/jenkins/docker/alpine-common/Dockerfile +++ b/resources/jenkins/docker/alpine-common/Dockerfile @@ -1,5 +1,4 @@ FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm -MAINTAINER Governikus KG ARG UNCRUSTIFY=0.74.0 ENV NAME=Common LABELS=Common diff --git a/resources/jenkins/docker/alpine-docs/Dockerfile b/resources/jenkins/docker/alpine-docs/Dockerfile index eff4c708b..4fd5992de 100644 --- a/resources/jenkins/docker/alpine-docs/Dockerfile +++ b/resources/jenkins/docker/alpine-docs/Dockerfile @@ -1,5 +1,4 @@ FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm -MAINTAINER Governikus KG ENV NAME=Docs LABELS=Docs diff --git a/resources/jenkins/docker/alpine-linux/Dockerfile b/resources/jenkins/docker/alpine-linux/Dockerfile index d580d9aeb..63618d99d 100644 --- a/resources/jenkins/docker/alpine-linux/Dockerfile +++ b/resources/jenkins/docker/alpine-linux/Dockerfile @@ -1,10 +1,9 @@ FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm -MAINTAINER Governikus KG ENV NAME=Linux LABELS="Linux g++ clang++ clazy" PACKAGES_DIR=/home/governikus/packages RUN apk --no-cache add g++ clang clang-analyzer ccache gcovr cloc clazy cppcheck pkgconf pcsc-lite-dev binutils-gold lld \ - py3-setuptools py3-jsonschema mesa-dev libx11-dev libxkbcommon-dev xcb-util-wm-dev xcb-util-image-dev xcb-util-keysyms-dev && \ + py3-setuptools check-jsonschema mesa-dev libx11-dev libxkbcommon-dev xcb-util-wm-dev xcb-util-image-dev xcb-util-keysyms-dev && \ ln -s /usr/libexec/c++-analyzer /usr/local/bin && ln -s /usr/libexec/ccc-analyzer /usr/local/bin USER governikus diff --git a/resources/jenkins/docker/alpine-swarm/Dockerfile b/resources/jenkins/docker/alpine-swarm/Dockerfile index 6f8a40d0f..661674cef 100644 --- a/resources/jenkins/docker/alpine-swarm/Dockerfile +++ b/resources/jenkins/docker/alpine-swarm/Dockerfile @@ -1,11 +1,11 @@ -FROM alpine:3.19 -MAINTAINER Governikus KG +FROM alpine:3.20 -ARG JENKINS_SWARM_VERSION=3.44 +ARG JENKINS_SWARM_VERSION=3.47 ENV EXECUTOR=3 LABELS= NAME= PASSWORD= RUN adduser governikus -s /bin/sh -D -RUN apk --no-cache add openjdk11-jre-headless cmake samurai make tini mercurial py3-pip py3-hglib wget rbtools +RUN apk --no-cache add openjdk11-jre-headless cmake samurai make tini gnupg mercurial py3-pip wget rbtools && \ + pip3 install --break-system-packages python-hglib RUN wget -O /swarm-client.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/$JENKINS_SWARM_VERSION/swarm-client-$JENKINS_SWARM_VERSION.jar ADD swarm.sh / diff --git a/resources/jenkins/docker/alpine-trigger/Dockerfile b/resources/jenkins/docker/alpine-trigger/Dockerfile index 4271630d7..03cde287c 100644 --- a/resources/jenkins/docker/alpine-trigger/Dockerfile +++ b/resources/jenkins/docker/alpine-trigger/Dockerfile @@ -1,5 +1,4 @@ FROM dev-docker.governikus.de/ausweisapp2/alpine:swarm -MAINTAINER Governikus KG ENV NAME=Trigger LABELS="Trigger Seeder" diff --git a/resources/jenkins/docker/ubuntu-android/Dockerfile b/resources/jenkins/docker/ubuntu-android/Dockerfile index b63621a86..9622a0749 100644 --- a/resources/jenkins/docker/ubuntu-android/Dockerfile +++ b/resources/jenkins/docker/ubuntu-android/Dockerfile @@ -1,21 +1,24 @@ FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm -MAINTAINER Governikus KG ARG ANDROID_CMDLINE_TOOLS=11076708 ARG ANDROID_NDK_VERSION=27.1.12297006 -ARG CMAKE=3.30.3 +ARG CMAKE=3.30.5 +ARG MAVEN=3.9.9 ENV NAME=Android LABELS="Android" PACKAGES_DIR=/home/governikus/packages ENV ANDROID_SDK_ROOT /opt/android-sdk ENV ANDROID_NDK_ROOT $ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION RUN apt-get update && \ - apt-get -y install g++ make ccache ninja-build perl unzip gradle maven patch openjdk-17-jdk-headless && \ + apt-get -y install g++ make ccache ninja-build perl unzip gradle patch openjdk-17-jdk-headless && \ rm -rf /var/lib/apt/lists/* RUN wget https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE-Linux-x86_64.sh -O /tmp/cmake.sh && \ sh /tmp/cmake.sh --prefix=/usr --skip-license --exclude-subdir && rm /tmp/cmake.sh +RUN wget https://dlcdn.apache.org/maven/maven-3/$MAVEN/binaries/apache-maven-$MAVEN-bin.tar.gz -O /tmp/maven.tar.gz && \ + tar xf /tmp/maven.tar.gz --strip-components=1 -C /usr/local && rm /tmp/maven.tar.gz + RUN mkdir -p /tmp/dl && cd /tmp/dl && wget -O sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS}_latest.zip && \ unzip sdk.zip && \ yes | /tmp/dl/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "cmdline-tools;12.0" "build-tools;34.0.0" "platforms;android-35" "ndk;${ANDROID_NDK_VERSION}" && \ diff --git a/resources/jenkins/docker/ubuntu-swarm/Dockerfile b/resources/jenkins/docker/ubuntu-swarm/Dockerfile index b26415373..9595f9a88 100644 --- a/resources/jenkins/docker/ubuntu-swarm/Dockerfile +++ b/resources/jenkins/docker/ubuntu-swarm/Dockerfile @@ -1,7 +1,6 @@ -FROM ubuntu:23.04 -MAINTAINER Governikus KG +FROM ubuntu:24.04 -ARG JENKINS_SWARM_VERSION=3.44 +ARG JENKINS_SWARM_VERSION=3.47 ENV EXECUTOR=3 LABELS= NAME= PASSWORD= ENV DEBIAN_FRONTEND noninteractive ENV PIP_BREAK_SYSTEM_PACKAGES=1 @@ -13,7 +12,7 @@ ENV CCACHE_REMOTE_STORAGE= CCACHE_RESHARE=true CCACHE_REMOTE_ONLY= RUN useradd -m governikus -g users -u 1111 RUN apt-get update && \ apt-get -y install openjdk-17-jre-headless tini python3-pip wget && \ - pip3 install rbtools mercurial python-hglib && \ + pip3 install --break-system-packages rbtools mercurial python-hglib && \ rm -rf /var/lib/apt/lists/* RUN wget -O /swarm-client.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/$JENKINS_SWARM_VERSION/swarm-client-$JENKINS_SWARM_VERSION.jar diff --git a/resources/jenkins/docker/ubuntu-vanilla/Dockerfile b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile index 14a6d7615..cfcfcc107 100644 --- a/resources/jenkins/docker/ubuntu-vanilla/Dockerfile +++ b/resources/jenkins/docker/ubuntu-vanilla/Dockerfile @@ -1,5 +1,4 @@ FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm -MAINTAINER Governikus KG ENV NAME=Vanilla LABELS="Vanilla" PACKAGES_DIR=/home/governikus/packages diff --git a/resources/jenkins/dsl/Builds/Build_Android.groovy b/resources/jenkins/dsl/Builds/Build_Android.groovy index 12b1f1bb4..e70196c6e 100644 --- a/resources/jenkins/dsl/Builds/Build_Android.groovy +++ b/resources/jenkins/dsl/Builds/Build_Android.groovy @@ -28,12 +28,7 @@ j.with steps { - shell("cd source; cmake --preset ci-android-apk -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") - shell('cmake --build build') - shell('cmake --build build --target apk') - shell('cmake --build build --target verify.signature') - shell('cmake --build build --target dump.apk') - shell('ctest --test-dir build --output-on-failure') + shell("cmake -P source/ci.cmake -- -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") } publishers { @@ -63,7 +58,7 @@ for(ARCH in Constants.AndroidArchAAR) def j = new Build ( - name: 'Android_AAR', + name: 'Android_AAR_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', artifacts: 'build/dist/**,build/**/debug.symbols/*' @@ -73,11 +68,7 @@ j.with { steps { - shell('cd source; cmake --preset ci-android-aar') - shell('cmake --build build') - shell('cmake --build build --target aar') - shell('ctest --test-dir build --output-on-failure') - shell("cd build/dist; cmake -DCMD=DEPLOY_NEXUS -P \$WORKSPACE/source/cmake/cmd.cmake") + shell("cmake -P source/ci.cmake -- -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") } publishers { @@ -99,3 +90,33 @@ j.with } } + + +def build = new Build + ( + name: 'Android_AAR', + label: 'Android', + artifacts: 'build/dist/**' + ) + +def j = build.generate(this) + +j.with +{ + steps + { + for(ARCH in Constants.AndroidArchAAR) + { + copyArtifacts(build.getSourceJobName('Android_AAR_' + ARCH)) + { + flatten() + buildSelector + { + latestSuccessful(true) + } + } + } + + shell('cmake -P source/ci.cmake') + } +} diff --git a/resources/jenkins/dsl/Builds/Build_Container.groovy b/resources/jenkins/dsl/Builds/Build_Container.groovy index 8980d2781..729e708af 100644 --- a/resources/jenkins/dsl/Builds/Build_Container.groovy +++ b/resources/jenkins/dsl/Builds/Build_Container.groovy @@ -11,37 +11,8 @@ def j = new Build j.with { - wrappers - { - environmentVariables - { - env('TAG', 'dev-${MERCURIAL_REVISION_BRANCH}') - } - } - steps { - shell('docker container prune -f') - - shell(strip('''\ - docker build --pull - -t dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" - source - ''')) - - shell('docker save -o build/AusweisApp-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""}') - shell('docker push dev-docker.govkg.de/ausweisapp/sdk:${TAG//-default/""}') - - shell('''\ - IMAGES=`docker images --filter "dangling=true" -q | tail -n +50` - if [ -z "$IMAGES" ] - then - echo "No old dangling images" - else - echo "Remove dangling images" - docker rmi -f $IMAGES - fi - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy b/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy index 5287eefd0..3dc8a23c0 100644 --- a/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy +++ b/resources/jenkins/dsl/Builds/Build_Docker_VNC.groovy @@ -11,37 +11,8 @@ def j = new Build j.with { - wrappers - { - environmentVariables - { - env('TAG', 'dev-${MERCURIAL_REVISION_BRANCH}') - } - } - steps { - shell(strip('''\ - docker build --pull - -t dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" - -f source/resources/jenkins/docker/Dockerfile - source - ''')) - - shell('docker run --rm dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""} AusweisApp --help') - shell('docker save -o build/AusweisApp-VNC-${MERCURIAL_REVISION_SHORT}.tar dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""}') - shell('docker push dev-docker.govkg.de/ausweisapp/vnc:${TAG//-default/""}') - - shell('''\ - IMAGES=`docker images --filter "dangling=true" -q | tail -n +50` - if [ -z "$IMAGES" ] - then - echo "No old dangling images" - else - echo "Remove dangling images" - docker rmi -f $IMAGES - fi - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Docs.groovy b/resources/jenkins/dsl/Builds/Build_Docs.groovy index 19dac6f00..87cdeea8c 100644 --- a/resources/jenkins/dsl/Builds/Build_Docs.groovy +++ b/resources/jenkins/dsl/Builds/Build_Docs.groovy @@ -12,23 +12,6 @@ j.with { steps { - shell('cd source; cmake --preset ci-tools') - - shell('cmake --build build --target notes') - shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') - - shell('cmake --build build --target sdk') - shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') - - shell('cmake --build build --target failurecodes') - shell('cmake --build build --target failurecodes.latex.pdf') - - shell('cmake --build build --target installation_integration.latex.pdf') - - shell('cmake --build build --target license') - - shell('cmake --build build --target doc8') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy b/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy index 80b0d2931..8a72aa290 100644 --- a/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy +++ b/resources/jenkins/dsl/Builds/Build_FreeBSD.groovy @@ -11,27 +11,8 @@ def j = new Build j.with { - wrappers - { - environmentVariables - { - env("QT_PLUGIN_PATH", '$WORKSPACE/libs/dist/plugins') - } - } - steps { - shell('cd source; cmake --preset ci-bsd') - - shell('''\ - export LD_LIBRARY_PATH=$WORKSPACE/libs/dist/lib:$LD_LIBRARY_PATH - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QML2_IMPORT_PATH=$WORKSPACE/libs/dist/qml - export LD_LIBRARY_PATH=$WORKSPACE/libs/dist/lib:$LD_LIBRARY_PATH - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Linux.groovy b/resources/jenkins/dsl/Builds/Build_Linux.groovy index f9f607786..05279afe3 100644 --- a/resources/jenkins/dsl/Builds/Build_Linux.groovy +++ b/resources/jenkins/dsl/Builds/Build_Linux.groovy @@ -11,39 +11,32 @@ def j = new Build j.with { - wrappers - { - environmentVariables - { - env("QT_PLUGIN_PATH", '$WORKSPACE/libs/dist/plugins') - } - } - steps { - shell('cd source; cmake --preset ci-linux') - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QML2_IMPORT_PATH=$WORKSPACE/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) - - shell('''\ - DESTDIR=$WORKSPACE/install cmake --install build - '''.stripIndent().trim()) - - shell('cmake --build build --target gcovr') - - shell('cmake --build build --target cloc.report') + shell('cmake -P source/ci.cmake') } publishers { - cobertura('build/gcovr.xml') + recordCoverage + { + sourceDirectories + { + sourceCodeDirectory + { + path('source') + } + } + + tools + { + coverageTool + { + parser('COBERTURA') + pattern('build/gcovr.xml') + } + } + } slocCount { diff --git a/resources/jenkins/dsl/Builds/Build_Linux_Integrated.groovy b/resources/jenkins/dsl/Builds/Build_Linux_Integrated.groovy index 6fff719a0..87066ada3 100644 --- a/resources/jenkins/dsl/Builds/Build_Linux_Integrated.groovy +++ b/resources/jenkins/dsl/Builds/Build_Linux_Integrated.groovy @@ -12,17 +12,6 @@ j.with { steps { - shell('cd source; cmake --preset ci-integrated') - - shell('cmake --build build') - - shell('ctest --test-dir build --output-on-failure') - - shell('cmake --build build --target gcovr') - } - - publishers - { - cobertura('build/gcovr.xml') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_MacOS.groovy b/resources/jenkins/dsl/Builds/Build_MacOS.groovy index 470254b9b..10ea79c19 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS.groovy @@ -13,18 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos') - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins - export QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml - ctest -C Debug --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_MacOS_DMG_PKG.groovy b/resources/jenkins/dsl/Builds/Build_MacOS_DMG_PKG.groovy index e6344c51f..adc1b5bca 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS_DMG_PKG.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS_DMG_PKG.groovy @@ -13,17 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos-release') - - shell('''\ - cmake --build build --target package --config MinSizeRel - '''.stripIndent().trim()) - - shell('cd build/_CPack_Packages/Darwin/; codesign -vvvv **/**/*.app') - shell('cd build/_CPack_Packages/Darwin/DragNDrop; spctl -a -vv **/*.app') - - shell('cd build/; cmake -P ../source/cmake/Notarization.cmake') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_MacOS_Integrated.groovy b/resources/jenkins/dsl/Builds/Build_MacOS_Integrated.groovy index 21f0c99ff..1967462db 100644 --- a/resources/jenkins/dsl/Builds/Build_MacOS_Integrated.groovy +++ b/resources/jenkins/dsl/Builds/Build_MacOS_Integrated.groovy @@ -13,17 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos-integrated') - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_SonarQube.groovy b/resources/jenkins/dsl/Builds/Build_SonarQube.groovy index 52b7f13bb..5a4a3c95e 100644 --- a/resources/jenkins/dsl/Builds/Build_SonarQube.groovy +++ b/resources/jenkins/dsl/Builds/Build_SonarQube.groovy @@ -24,31 +24,6 @@ j.with steps { - shell('mkdir -p cache') - - shell('cmake -P source/cmake/prepare_sonarqube_env.cmake') - - shell('cd source; cmake --preset ci-linux') - - shell('''\ - cd build; - $WORKSPACE/sonarqubetools/dependency-check/bin/dependency-check.sh --enableExperimental -f HTML -f JSON --scan $WORKSPACE/source/cmake --noupdate --connectionString=jdbc:mariadb://dependency-check-db.govkg.de/dependencycheck --dbUser=${DEPENDENCY_CHECK_USER} --dbPassword=${DEPENDENCY_CHECK_PASSWORD} --dbDriverName=org.mariadb.jdbc.Driver - '''.stripIndent().trim()) - - shell('$WORKSPACE/sonarqubetools/sonar-build-wrapper/build-wrapper-linux-x86-64 --out-dir build cmake --build build') - - shell('ctest -LE qml -E Test_ui_qml_Qml --test-dir build --output-on-failure') - - shell('cmake --build build --target gcovr.sonar') - - shell(strip('''\ - cd build; - $WORKSPACE/sonarqubetools/sonar-scanner/bin/sonar-scanner - -Dsonar.scanner.metadataFilePath=${WORKSPACE}/tmp/sonar-metadata.txt - -Dsonar.branch.name=${MERCURIAL_REVISION_BRANCH} - -Dsonar.token=${SONARQUBE_TOKEN} - -Dsonar.qualitygate.wait=true - -Dsonar.qualitygate.timeout=90 - ''')) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Source.groovy b/resources/jenkins/dsl/Builds/Build_Source.groovy index 8f6690672..c4314ee63 100644 --- a/resources/jenkins/dsl/Builds/Build_Source.groovy +++ b/resources/jenkins/dsl/Builds/Build_Source.groovy @@ -4,7 +4,7 @@ def j = new Build ( name: 'Source', label: 'Common', - artifacts: 'build/*.tar.gz' + artifacts: 'build/*.tar.gz*' ).generate(this) @@ -12,7 +12,6 @@ j.with { steps { - shell('cd source; cmake --preset ci-tools') - shell('cmake --build build --target package_source') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_GNU.groovy b/resources/jenkins/dsl/Builds/Build_Win64_GNU.groovy index 5ef0249a1..490b79182 100644 --- a/resources/jenkins/dsl/Builds/Build_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win64_GNU.groovy @@ -14,16 +14,6 @@ j.with { steps { - batchFile('cd source & cmake --preset ci-win') - - batchFile('cmake --build build') - - batchFile('''\ - set PATH=%WORKSPACE%/libs/dist/bin;%PATH% - set PATH=%WORKSPACE%/build/src;%WORKSPACE%/build/test/helper;%PATH% - set QT_PLUGIN_PATH=%WORKSPACE%/libs/dist/plugins - set QML2_IMPORT_PATH=%WORKSPACE%/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI.groovy b/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI.groovy index 654647aa3..9c6777202 100644 --- a/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win64_GNU_MSI.groovy @@ -14,12 +14,6 @@ j.with { steps { - batchFile('cd source & cmake --preset ci-win-release') - - batchFile('cmake --build build --target package') - - batchFile('cmake --build build --target package.sign') - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_MSVC.groovy b/resources/jenkins/dsl/Builds/Build_Win64_MSVC.groovy index 4080ab69e..c3f7722e4 100644 --- a/resources/jenkins/dsl/Builds/Build_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win64_MSVC.groovy @@ -13,21 +13,6 @@ j.with { steps { - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build - '''.stripIndent().trim()) - - batchFile('''\ - set PATH=%WORKSPACE%/libs/dist/bin;%PATH% - set QT_PLUGIN_PATH=%WORKSPACE%/libs/dist/plugins - set QML2_IMPORT_PATH=%WORKSPACE%/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI.groovy b/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI.groovy index e743f1e72..eef336b3d 100644 --- a/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI.groovy @@ -13,21 +13,6 @@ j.with { steps { - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win-release - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package.sign - '''.stripIndent().trim()) - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI_dev.groovy b/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI_dev.groovy index 1ef7f503e..50bf5f0e6 100644 --- a/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI_dev.groovy +++ b/resources/jenkins/dsl/Builds/Build_Win64_MSVC_MSI_dev.groovy @@ -13,21 +13,6 @@ j.with { steps { - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win-debug - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package.sign - '''.stripIndent().trim()) - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_Win64_clang_MSI.groovy b/resources/jenkins/dsl/Builds/Build_Win64_clang_MSI.groovy new file mode 100644 index 000000000..2c8908fb8 --- /dev/null +++ b/resources/jenkins/dsl/Builds/Build_Win64_clang_MSI.groovy @@ -0,0 +1,25 @@ +import common.Build +import common.Build.JobType + +def j = new Build + ( + name: 'Win64_clang_MSI', + libraries: 'Win64_MSVC', + label: 'MSVC', + artifacts: 'build/*.msi', + jobType: JobType.Matrix + ).generate(this) + + +j.with +{ + axes + { + label('Compiler', 'clang-cl') + } + + steps + { + batchFile('cmake -P source/ci.cmake -- -DCMAKE_CXX_COMPILER=%Compiler%') + } +} diff --git a/resources/jenkins/dsl/Builds/Build_iOS_Framework.groovy b/resources/jenkins/dsl/Builds/Build_iOS_Framework.groovy index 05b14fdb9..3c0bc5de8 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_Framework.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_Framework.groovy @@ -13,11 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy index 1690a7841..d4b89712f 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_IPA.groovy @@ -13,13 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios') - - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') - shell('cd build; xcodebuild -configuration MinSizeRel -target ipa') - shell('ctest --test-dir build --output-on-failure -C MinSizeRel') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_iOS_Simulator_Framework.groovy b/resources/jenkins/dsl/Builds/Build_iOS_Simulator_Framework.groovy index b16b0440b..bf7328e6b 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_Simulator_Framework.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_Simulator_Framework.groovy @@ -13,11 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_iOS_Simulator_arm64_Framework.groovy b/resources/jenkins/dsl/Builds/Build_iOS_Simulator_arm64_Framework.groovy index b9ed0aa9e..cb1d72ec4 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_Simulator_arm64_Framework.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_Simulator_arm64_Framework.groovy @@ -13,11 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator-arm64') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Builds/Build_iOS_SwiftPackage.groovy b/resources/jenkins/dsl/Builds/Build_iOS_SwiftPackage.groovy index 5b741716d..af12c81bb 100644 --- a/resources/jenkins/dsl/Builds/Build_iOS_SwiftPackage.groovy +++ b/resources/jenkins/dsl/Builds/Build_iOS_SwiftPackage.groovy @@ -16,7 +16,8 @@ j.with { copyArtifacts(build.getSourceJobName('iOS_Framework')) { - targetDirectory('build/arm64') + targetDirectory('arm64') + flatten() buildSelector { latestSuccessful(true) @@ -25,7 +26,8 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_Framework')) { - targetDirectory('build/x86_64-simulator') + targetDirectory('x86_64-simulator') + flatten() buildSelector { latestSuccessful(true) @@ -34,13 +36,14 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_arm64_Framework')) { - targetDirectory('build/arm64-simulator') + targetDirectory('arm64-simulator') + flatten() buildSelector { latestSuccessful(true) } } - shell('cd build; cmake -P ../source/cmake/SwiftPackage.cmake') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Libraries/Libs_Android.groovy b/resources/jenkins/dsl/Libraries/Libs_Android.groovy index 50339f6d8..146cd3f4f 100644 --- a/resources/jenkins/dsl/Libraries/Libs_Android.groovy +++ b/resources/jenkins/dsl/Libraries/Libs_Android.groovy @@ -1,7 +1,7 @@ import common.Library import common.Constants -for(ARCH in Constants.AndroidArch) +for(ARCH in Constants.AndroidArchLibs) { def j = new Library diff --git a/resources/jenkins/dsl/Releases/Release_Android.groovy b/resources/jenkins/dsl/Releases/Release_Android.groovy index f7386b4e6..65fd38da6 100644 --- a/resources/jenkins/dsl/Releases/Release_Android.groovy +++ b/resources/jenkins/dsl/Releases/Release_Android.groovy @@ -39,16 +39,11 @@ j.with buildDescription('', 'ANDROID_VERSION_CODE: ${ANDROID_VERSION_CODE}
BUILD_PREVIEW: ${BUILD_PREVIEW}') shell(strip("""\ - cd source; cmake --preset ci-android-apk + cmake -P source/ci.cmake -- -DCMAKE_ANDROID_ARCH_ABI=${ARCH} -DANDROID_VERSION_CODE=\${ANDROID_VERSION_CODE} -DBUILD_PREVIEW=\${BUILD_PREVIEW} """)) - - shell('cmake --build build') - shell('cmake --build build --target apk') - shell('cmake --build build --target verify.signature') - shell('cmake --build build --target dump.apk') } } @@ -61,7 +56,7 @@ for(ARCH in Constants.AndroidArchAAR) def j = new Release ( - name: 'Android_AAR', + name: 'Android_AAR_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', artifacts: 'libs/Toolchain_*,build/dist/**,build/**/debug.symbols/*' @@ -79,14 +74,58 @@ j.with buildDescription('', 'BUILD_PREVIEW: ${BUILD_PREVIEW}') shell(strip("""\ - cd source; cmake --preset ci-android-aar + cmake -P source/ci.cmake -- + -DCMAKE_ANDROID_ARCH_ABI=${ARCH} -DBUILD_PREVIEW=\${BUILD_PREVIEW} """)) - - shell('cmake --build build') - shell('cmake --build build --target aar') - shell("cd build/dist; cmake -DCMD=DEPLOY_NEXUS -P \$WORKSPACE/source/cmake/cmd.cmake") } } } + + +def build = new Release + ( + name: 'Android_AAR', + label: 'Android', + artifacts: 'build/dist/**' + ) + +def j = build.generate(this) + +j.with +{ + parameters + { + booleanParam("PUBLISH", false, "Publish to maven central") + + for(ARCH in Constants.AndroidArchAAR) + { + buildSelectorParam(build.getSourceJobNameParam('Android_AAR_' + ARCH)) + { + defaultBuildSelector + { + latestSuccessful(true) + } + description('Build of ' + ARCH) + } + } + } + + steps + { + for(ARCH in Constants.AndroidArchAAR) + { + copyArtifacts(build.getSourceJobName('Android_AAR_' + ARCH)) + { + flatten() + buildSelector + { + buildParameter(build.getSourceJobNameParam('Android_AAR_' + ARCH)) + } + } + } + + shell('cmake -P source/ci.cmake') + } +} diff --git a/resources/jenkins/dsl/Releases/Release_Container.groovy b/resources/jenkins/dsl/Releases/Release_Container.groovy index dbdf112f9..3bcfb4559 100644 --- a/resources/jenkins/dsl/Releases/Release_Container.groovy +++ b/resources/jenkins/dsl/Releases/Release_Container.groovy @@ -18,28 +18,6 @@ j.with steps { - shell(strip('''\ - docker build --pull - -t dev-docker.govkg.de/ausweisapp/sdk:${changeset} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" - source - ''')) - - shell('docker save -o build/AusweisApp-${changeset}.tar dev-docker.govkg.de/ausweisapp/sdk:${changeset}') - shell('docker push dev-docker.govkg.de/ausweisapp/sdk:${changeset}') - - conditionalSteps - { - condition - { - booleanCondition('${LATEST}') - } - - steps - { - shell('docker tag dev-docker.govkg.de/ausweisapp/sdk:${changeset} dev-docker.govkg.de/ausweisapp/sdk:latest') - shell('docker push dev-docker.govkg.de/ausweisapp/sdk:latest') - } - } + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_Docs.groovy b/resources/jenkins/dsl/Releases/Release_Docs.groovy index f7c7d7b22..fa67f9194 100644 --- a/resources/jenkins/dsl/Releases/Release_Docs.groovy +++ b/resources/jenkins/dsl/Releases/Release_Docs.groovy @@ -17,21 +17,6 @@ j.with steps { - shell('cd source; cmake --preset ci-tools -DENABLE_DVCS=\${ENABLE_DVCS}') - - shell('cmake --build build --target notes') - shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') - - shell('cmake --build build --target sdk') - shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') - - shell('cmake --build build --target failurecodes') - shell('cmake --build build --target failurecodes.latex.pdf') - - shell('cmake --build build --target installation_integration.latex.pdf') - - shell('cmake --build build --target license') + shell('cmake -P source/ci.cmake -- -DENABLE_DVCS=\${ENABLE_DVCS}') } } diff --git a/resources/jenkins/dsl/Releases/Release_MacOS.groovy b/resources/jenkins/dsl/Releases/Release_MacOS.groovy index 962041d47..61742b33a 100644 --- a/resources/jenkins/dsl/Releases/Release_MacOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_MacOS.groovy @@ -20,32 +20,6 @@ j.with { buildDescription('', 'USE_DISTRIBUTION_PROFILE: ${USE_DISTRIBUTION_PROFILE}') - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos-release -DUSE_DISTRIBUTION_PROFILE=${USE_DISTRIBUTION_PROFILE}') - - shell('''\ - cmake --build build --target package --config MinSizeRel - '''.stripIndent().trim()) - - shell('cd build/src/MinSizeRel/; cmake -E tar cf ../../AusweisApp.app.dSYM.zip --format=zip AusweisApp.app.dSYM') - - shell('cd build/_CPack_Packages/Darwin/; codesign -vvvv **/**/*.app') - shell('cd build/_CPack_Packages/Darwin/DragNDrop; spctl -a -vv **/*.app') - - shell('cd build/; cmake -P ../source/cmake/Notarization.cmake') - - conditionalSteps - { - condition - { - booleanCondition('${USE_DISTRIBUTION_PROFILE}') - } - - steps - { - shell('cd build/; xcrun altool -t osx --upload-app -u "ausweisapp@governikus.com" -p @env:PASSWORD -f *.pkg') - } - } + shell('cmake -P source/ci.cmake -- -DUSE_DISTRIBUTION_PROFILE=${USE_DISTRIBUTION_PROFILE}') } } diff --git a/resources/jenkins/dsl/Releases/Release_Source.groovy b/resources/jenkins/dsl/Releases/Release_Source.groovy index 4a19db4cd..9630b18bd 100644 --- a/resources/jenkins/dsl/Releases/Release_Source.groovy +++ b/resources/jenkins/dsl/Releases/Release_Source.groovy @@ -4,7 +4,7 @@ def j = new Release ( name: 'Source', label: 'Common', - artifacts: 'build/*.tar.gz' + artifacts: 'build/*.tar.gz*' ).generate(this) @@ -12,7 +12,6 @@ j.with { steps { - shell('cd source; cmake --preset ci-tools') - shell('cmake --build build --target package_source') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_Win64_GNU.groovy b/resources/jenkins/dsl/Releases/Release_Win64_GNU.groovy index 709480019..4c51d8e85 100644 --- a/resources/jenkins/dsl/Releases/Release_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Releases/Release_Win64_GNU.groovy @@ -14,10 +14,6 @@ j.with { steps { - batchFile('cd source & cmake --preset ci-win-release') - - batchFile('cmake --build build --target package') - - batchFile('cmake --build build --target package.sign') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_Win64_MSVC.groovy b/resources/jenkins/dsl/Releases/Release_Win64_MSVC.groovy index f540af485..3e7a8cbd2 100644 --- a/resources/jenkins/dsl/Releases/Release_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Releases/Release_Win64_MSVC.groovy @@ -13,19 +13,6 @@ j.with { steps { - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win-release - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package.sign - '''.stripIndent().trim()) + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS.groovy b/resources/jenkins/dsl/Releases/Release_iOS.groovy index 7e30ba054..73e26caa6 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS.groovy @@ -20,28 +20,6 @@ j.with { buildDescription('', 'USE_DISTRIBUTION_PROFILE: ${USE_DISTRIBUTION_PROFILE}') - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios -DUSE_DISTRIBUTION_PROFILE=${USE_DISTRIBUTION_PROFILE}') - - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -scheme AusweisAppBinary archive') - shell('cd build; xcodebuild -configuration MinSizeRel -archivePath AusweisApp.xcarchive -exportArchive -exportOptionsPlist exportOptions.plist -exportPath .') - shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') - shell('cd build; xcodebuild -configuration MinSizeRel -target ipa') - - conditionalSteps - { - condition - { - booleanCondition('${USE_DISTRIBUTION_PROFILE}') - } - - steps - { - shell('cd build; xcrun altool -t ios --validate-app --verbose -u "ausweisapp@governikus.com" -p @env:PASSWORD -f *.ipa') - - shell('cd build; xcrun altool -t ios --upload-app -u "ausweisapp@governikus.com" -p @env:PASSWORD -f *.ipa') - } - } + shell('cmake -P source/ci.cmake -- -DUSE_DISTRIBUTION_PROFILE=${USE_DISTRIBUTION_PROFILE}') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy index a0f8e9b91..c0f682452 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Framework.groovy @@ -13,12 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy index 9d185586b..6232a20b1 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_Framework.groovy @@ -13,12 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy index 2ef774018..ac0034391 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_Simulator_arm64_Framework.groovy @@ -13,12 +13,6 @@ j.with { steps { - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator-arm64') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cmake -E tar cf AusweisApp_BuildDir.tar.zstd --zstd build') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Releases/Release_iOS_SwiftPackage.groovy b/resources/jenkins/dsl/Releases/Release_iOS_SwiftPackage.groovy index 57a53da96..1232d01f4 100644 --- a/resources/jenkins/dsl/Releases/Release_iOS_SwiftPackage.groovy +++ b/resources/jenkins/dsl/Releases/Release_iOS_SwiftPackage.groovy @@ -45,7 +45,8 @@ j.with { copyArtifacts(build.getSourceJobName('iOS_Framework')) { - targetDirectory('build/arm64') + targetDirectory('arm64') + flatten() buildSelector { buildParameter('iOS_Framework_Build') @@ -54,7 +55,8 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_Framework')) { - targetDirectory('build/x86_64-simulator') + targetDirectory('x86_64-simulator') + flatten() buildSelector { buildParameter('iOS_Simulator_Framework_Build') @@ -63,13 +65,14 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_arm64_Framework')) { - targetDirectory('build/arm64-simulator') + targetDirectory('arm64-simulator') + flatten() buildSelector { buildParameter('iOS_Simulator_arm64_Framework_Build') } } - shell('cd build; cmake -P ../source/cmake/SwiftPackage.cmake') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Android.groovy index d45c60a17..25d93ec3f 100644 --- a/resources/jenkins/dsl/Reviews/Review_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Android.groovy @@ -18,14 +18,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell("cd source; cmake --preset ci-android-apk-review -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") - shell('cmake --build build') - shell('cmake --build build --target apk') - shell('cmake --build build --target verify.signature') - shell('cmake --build build --target dump.apk') - shell('ctest --test-dir build --output-on-failure') + shell("cmake -P source/ci.cmake -- -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") } publishers { @@ -50,12 +43,12 @@ j.with // ----------------------------------------------------------------- AAR -for(ARCH in Constants.AndroidArchAAR) +for(ARCH in Constants.AndroidArchAARReview) { def j = new Review ( - name: 'Android_AAR', + name: 'Android_AAR_' + ARCH, libraries: 'Android_' + ARCH, label: 'Android', artifacts: 'build/dist/**,build/debug.symbols/*' @@ -65,11 +58,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - shell('cd source; cmake --preset ci-android-aar-review') - shell('cmake --build build') - shell('cmake --build build --target aar') - shell('ctest --test-dir build --output-on-failure') + shell("cmake -P source/ci.cmake -- -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") } publishers { @@ -91,3 +80,41 @@ j.with } } + + +def build = new Review + ( + name: 'Android_AAR', + label: 'Common', + artifacts: 'build/dist/**' + ) + +def j = build.generate(this) + +j.with +{ + parameters + { + for(ARCH in Constants.AndroidArchAARReview) + { + stringParam(build.getSourceJobNameParam('Android_AAR_' + ARCH), '', 'Build of ' + ARCH) + } + } + + steps + { + for(ARCH in Constants.AndroidArchAARReview) + { + copyArtifacts(build.getSourceJobName('Android_AAR_' + ARCH)) + { + flatten() + buildSelector + { + buildNumber('${' + build.getSourceJobNameParam('Android_AAR_' + ARCH) + '}') + } + } + } + + shell('cmake -P source/ci.cmake') + } +} diff --git a/resources/jenkins/dsl/Reviews/Review_Configuration.groovy b/resources/jenkins/dsl/Reviews/Review_Configuration.groovy index 0be27f7a9..8d5d9eb88 100644 --- a/resources/jenkins/dsl/Reviews/Review_Configuration.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Configuration.groovy @@ -14,23 +14,8 @@ def j = new Review j.with { - wrappers - { - environmentVariables - { - env("QT_PLUGIN_PATH", '$WORKSPACE/libs/dist/plugins') - } - } - steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('cd source; cmake --preset ci-linux') - - shell('cmake --build build --target ALL_Test_configuration') - - shell('ctest --test-dir build --output-on-failure -R Test_configuration') - shell('ctest --test-dir build --output-on-failure -L json') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Container.groovy b/resources/jenkins/dsl/Reviews/Review_Container.groovy index 85319b982..6103607f7 100644 --- a/resources/jenkins/dsl/Reviews/Review_Container.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Container.groovy @@ -13,17 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell(strip('''\ - docker build - -t dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" - source - ''')) - - shell('docker save -o build/AusweisApp-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG}') - - shell('docker rmi -f dev-docker.govkg.de/ausweisapp/sdk:${BUILD_TAG}') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy b/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy index abfdb2f54..0a32750d8 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docker_VNC.groovy @@ -13,19 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell(strip('''\ - docker build - -t dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG} - --build-arg CCACHE_REMOTE_STORAGE="redis://${CCACHE_REMOTE_STORAGE_HOST}" - -f source/resources/jenkins/docker/Dockerfile - source - ''')) - - shell('docker run --rm dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG} AusweisApp --help') - shell('docker save -o build/AusweisApp-VNC-${BUILD_TAG}.tar dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG}') - - shell('docker rmi -f dev-docker.govkg.de/ausweisapp/vnc:${BUILD_TAG}') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Docs.groovy b/resources/jenkins/dsl/Reviews/Review_Docs.groovy index 37667a586..1be9b04bf 100644 --- a/resources/jenkins/dsl/Reviews/Review_Docs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Docs.groovy @@ -14,25 +14,6 @@ j.with steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('cd source; cmake --preset ci-tools') - - shell('cmake --build build --target notes') - shell('cmake --build build --target notes.latex.pdf') - shell('cd build/docs/notes; cmake -E tar cfJ ../AusweisApp_ReleaseNotes.tar.xz .') - - shell('cmake --build build --target sdk') - shell('cmake --build build --target sdk.latex.pdf') - shell('cd build/docs/sdk/html; cmake -E tar cfJ ../../AusweisApp_SDK.tar.xz .') - - shell('cmake --build build --target failurecodes') - shell('cmake --build build --target failurecodes.latex.pdf') - - shell('cmake --build build --target installation_integration.latex.pdf') - - shell('cmake --build build --target license') - - shell('cmake --build build --target doc8') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy index 1d95651de..f234d8461 100644 --- a/resources/jenkins/dsl/Reviews/Review_Formatting.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Formatting.groovy @@ -14,18 +14,7 @@ j.with steps { - shell('''\ - cd source - hg revert -a -C - hg --config extensions.hgext.purge= purge --all - hg --config extensions.hgext.strip= strip -r 'secret() or draft()' --no-backup --force 2>/dev/null || echo "No changeset stripped" - '''.stripIndent().trim()) - - shell('cd source; cmake --preset ci-tools-with-libs') - - shell('cd source; resources/jenkins/check_formatting.sh') - - shell('cd source; cmake -DCMD=CHECK_FAILURE_CODES -P cmake/cmd.cmake') + shell('cmake -DPENDING=OFF -P source/ci.cmake') } publishers diff --git a/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy index 3f756c8b7..839d1eb1e 100644 --- a/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy +++ b/resources/jenkins/dsl/Reviews/Review_FreeBSD.groovy @@ -13,29 +13,8 @@ def j = new Review j.with { - wrappers - { - environmentVariables - { - env("QT_PLUGIN_PATH", '$WORKSPACE/libs/dist/plugins') - } - } - steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('cd source; cmake --preset ci-bsd') - - shell('''\ - export LD_LIBRARY_PATH=$WORKSPACE/libs/dist/lib:$LD_LIBRARY_PATH - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml - export LD_LIBRARY_PATH=$WORKSPACE/libs/dist/lib:$LD_LIBRARY_PATH - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy index 804575d00..5de8c98d8 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Android.groovy @@ -1,7 +1,7 @@ import common.LibraryReview import common.Constants -for(ARCH in Constants.AndroidArch) +for(ARCH in Constants.AndroidArchLibsReview) { def j = new LibraryReview @@ -15,7 +15,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell("cd source/libs; cmake --preset ci-android -DCMAKE_ANDROID_ARCH_ABI=${ARCH}") diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy index 9b8d1fe7e..e85d86847 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_FreeBSD.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('cd source/libs; cmake --preset ci-debug') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy index a1939c031..39da19093 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Linux.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('cd source/libs; cmake --preset ci-release') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy index 4facd29cc..a27bdfdaa 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_MacOS.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('cd source/libs; cmake --preset ci-release') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy index 06c61ed12..6eb17d50b 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_GNU.groovy @@ -23,7 +23,7 @@ j.with steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + batchFile('cmake -DPATCH_ONLY=ON -P source/ci.cmake') batchFile('cd source/libs & cmake --preset ci-gnu-release') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy index 636078c66..dfb451b89 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC.groovy @@ -21,7 +21,7 @@ j.with steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + batchFile('cmake -DPATCH_ONLY=ON -P source/ci.cmake') batchFile('''\ call vcvarsall.bat amd64 diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy index 649b7185b..833ac6c12 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_Win64_MSVC_dev.groovy @@ -21,7 +21,7 @@ j.with steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + batchFile('cmake -DPATCH_ONLY=ON -P source/ci.cmake') batchFile('''\ call vcvarsall.bat amd64 diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy index bdeb28836..d1a4464e9 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_iOS.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator.groovy index b1b166b34..58659537b 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') diff --git a/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator_arm64.groovy b/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator_arm64.groovy index c3fb08bc5..037e4090a 100644 --- a/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator_arm64.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Libs_iOS_Simulator_arm64.groovy @@ -11,7 +11,7 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') + shell('cmake -DPATCH_ONLY=ON -P source/ci.cmake') shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') diff --git a/resources/jenkins/dsl/Reviews/Review_Linux.groovy b/resources/jenkins/dsl/Reviews/Review_Linux.groovy index 0cd87a5ec..84a0a2ee0 100644 --- a/resources/jenkins/dsl/Reviews/Review_Linux.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Linux.groovy @@ -16,40 +16,14 @@ def j = new Review j.with { - wrappers - { - environmentVariables - { - env("QT_PLUGIN_PATH", '$WORKSPACE/libs/dist/plugins') - } - } - axes { label('Compiler', 'g++', 'clang++') + label('Agent', 'Linux') } steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell(strip('''\ - cd source; - cmake --preset ci-linux - -DCMAKE_CXX_COMPILER=${Compiler} - ''')) - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) - - shell('''\ - DESTDIR=$WORKSPACE/install cmake --install build - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake -- -DCMAKE_CXX_COMPILER=${Compiler}') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Linux_Integrated.groovy b/resources/jenkins/dsl/Reviews/Review_Linux_Integrated.groovy index 349f63bdb..035a4a4c1 100644 --- a/resources/jenkins/dsl/Reviews/Review_Linux_Integrated.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Linux_Integrated.groovy @@ -15,12 +15,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('cd source; cmake --preset ci-integrated') - - shell('cmake --build build') - - shell('ctest --test-dir build --output-on-failure') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy index 72178e548..2be176f96 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS.groovy @@ -15,20 +15,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos') - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins - export QML2_IMPORT_PATH=${WORKSPACE}/libs/dist/qml - ctest -C Debug --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS_DMG_PKG.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS_DMG_PKG.groovy index c6a1f1a46..154bbdd11 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS_DMG_PKG.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS_DMG_PKG.groovy @@ -13,17 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos-release -DOSX_TIMESTAMP=OFF') - - shell('''\ - cmake --build build --target package --config MinSizeRel - '''.stripIndent().trim()) - - shell('cd build/_CPack_Packages/Darwin/; codesign -vvvv **/**/*.app') - shell('cd build/_CPack_Packages/Darwin/DragNDrop; spctl -a -vv **/*.app') + shell('cmake -P source/ci.cmake -- -DOSX_TIMESTAMP=OFF') } } diff --git a/resources/jenkins/dsl/Reviews/Review_MacOS_Integrated.groovy b/resources/jenkins/dsl/Reviews/Review_MacOS_Integrated.groovy index 8fd757e66..d19209a6a 100644 --- a/resources/jenkins/dsl/Reviews/Review_MacOS_Integrated.groovy +++ b/resources/jenkins/dsl/Reviews/Review_MacOS_Integrated.groovy @@ -15,19 +15,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain ${KEYCHAIN_CREDENTIALS} ${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-macos-integrated') - - shell('''\ - cmake --build build - '''.stripIndent().trim()) - - shell('''\ - export QT_PLUGIN_PATH=${WORKSPACE}/libs/dist/plugins - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy b/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy index 48464e22b..959a38b3d 100644 --- a/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy +++ b/resources/jenkins/dsl/Reviews/Review_SonarQube.groovy @@ -25,36 +25,6 @@ j.with steps { - shell('mkdir -p cache') - - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('cmake -P source/cmake/prepare_sonarqube_env.cmake') - - shell('cd source; cmake --preset ci-linux') - - shell('''\ - cd build; - $WORKSPACE/sonarqubetools/dependency-check/bin/dependency-check.sh --enableExperimental -f HTML -f JSON --scan $WORKSPACE/source/cmake --noupdate --connectionString=jdbc:mariadb://dependency-check-db.govkg.de/dependencycheck --dbUser=${DEPENDENCY_CHECK_USER} --dbPassword=${DEPENDENCY_CHECK_PASSWORD} --dbDriverName=org.mariadb.jdbc.Driver - '''.stripIndent().trim()) - - - shell('$WORKSPACE/sonarqubetools/sonar-build-wrapper/build-wrapper-linux-x86-64 --out-dir build cmake --build build') - - shell('ctest -LE qml -E Test_ui_qml_Qml --test-dir build --output-on-failure') - - shell('cmake --build build --target gcovr.sonar') - - shell(strip('''\ - cd build; - $WORKSPACE/sonarqubetools/sonar-scanner/bin/sonar-scanner - -Dsonar.scanner.metadataFilePath=${WORKSPACE}/tmp/sonar-metadata.txt - -Dsonar.pullrequest.key=${REVIEWBOARD_REVIEW_ID} - -Dsonar.pullrequest.branch=${REVIEWBOARD_REVIEW_ID} - -Dsonar.pullrequest.base=${MERCURIAL_REVISION_BRANCH} - -Dsonar.token=${SONARQUBE_TOKEN} - -Dsonar.qualitygate.wait=true - -Dsonar.qualitygate.timeout=90 - ''')) + shell('cmake -DSPLITTED=OFF -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Source.groovy b/resources/jenkins/dsl/Reviews/Review_Source.groovy index f5b1081fe..ac3c26a25 100644 --- a/resources/jenkins/dsl/Reviews/Review_Source.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Source.groovy @@ -4,7 +4,7 @@ def j = new Review ( name: 'Source', label: 'Common', - artifacts: 'build/*.tar.gz' + artifacts: 'build/*.tar.gz*' ).generate(this) @@ -14,8 +14,6 @@ j.with steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - shell('cd source; cmake --preset ci-tools') - shell('cmake --build build --target package_source') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy index 66b3ad3d3..d83ff850c 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger.groovy @@ -8,14 +8,18 @@ def getJobs() { def list = ['Formatting', 'Source', 'Docs'] - def packages = ['Container', 'MacOS_DMG_PKG', 'Win64_GNU_MSI', 'Win64_MSVC_MSI', 'iOS_IPA', 'iOS_Framework', 'iOS_Simulator_Framework', 'iOS_Simulator_arm64_Framework', 'Android_AAR'] + def packages = ['Container', 'MacOS_DMG_PKG', 'Win64_GNU_MSI', 'Win64_MSVC_MSI', 'iOS_IPA', 'iOS_Framework', 'iOS_Simulator_Framework', 'iOS_Simulator_arm64_Framework'] + for(ARCH in Constants.AndroidArchAARReview) + { + packages << 'Android_AAR_' + ARCH + } for(ARCH in Constants.AndroidArchAPKReview) { packages << 'Android_APK_' + ARCH } list += packages - def subPackages = ['iOS_SwiftPackage'] + def subPackages = ['Android_AAR', 'iOS_SwiftPackage'] list += subPackages def unitTests = ['Linux', 'Linux_Integrated', 'MacOS', 'MacOS_Integrated', 'Win64_GNU', 'Win64_MSVC', 'FreeBSD', 'SonarQube', 'Docker_VNC'] @@ -29,6 +33,11 @@ String getName(String name) return "${MERCURIAL_REVISION_BRANCH}_Review_" + name } +String getNameParam(String name) +{ + return getName(name).replace('-', '_') + '_Build' +} + def reviewMessage = createReviewMessage(getJobs(), this.&getName) + ' | Libraries: ${Libraries}' + ' | SonarQube Analysis: ${SONARQUBE_ANALYSIS_MESSAGE}' @@ -69,7 +78,10 @@ j.with phase('Packages', 'UNSTABLE') { - phaseJob(getName('Android_AAR')) + for(ARCH in Constants.AndroidArchAARReview) + { + phaseJob(getName('Android_AAR_' + ARCH)) + } for(ARCH in Constants.AndroidArchAPKReview) { @@ -95,6 +107,17 @@ j.with phase('Sub-Packages', 'UNSTABLE') { + phaseJob(getName('Android_AAR')) + { + parameters + { + for(ARCH in Constants.AndroidArchAARReview) + { + predefinedProp(getNameParam('Android_AAR_' + ARCH), getEnvNumber(getName('Android_AAR_' + ARCH))) + } + } + } + phaseJob(getName('iOS_SwiftPackage')) { parameters diff --git a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy index abb305572..cac548310 100644 --- a/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Trigger_Libs.groovy @@ -6,7 +6,7 @@ import static common.Constants.createReviewMessage def getJobs() { def list = ['Linux', 'MacOS', 'Win64_GNU', 'Win64_MSVC', 'Win64_MSVC_dev', 'iOS', 'iOS_Simulator', 'iOS_Simulator_arm64', 'FreeBSD'] - for(ARCH in Constants.AndroidArchAPKReview) + for(ARCH in Constants.AndroidArchLibsReview) { list << 'Android_' + ARCH } @@ -54,7 +54,7 @@ j.with killPhaseCondition('NEVER') } - for(ARCH in Constants.AndroidArchAPKReview) + for(ARCH in Constants.AndroidArchLibsReview) { phaseJob(getName('Android_' + ARCH)) { diff --git a/resources/jenkins/dsl/Reviews/Review_Win64_GNU.groovy b/resources/jenkins/dsl/Reviews/Review_Win64_GNU.groovy index eece6ec78..59ccad6ed 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win64_GNU.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win64_GNU.groovy @@ -16,18 +16,6 @@ j.with { steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - batchFile('cd source & cmake --preset ci-win') - - batchFile('cmake --build build') - - batchFile('''\ - set PATH=%WORKSPACE%/libs/dist/bin;%PATH% - set PATH=%WORKSPACE%/build/src;%WORKSPACE%/build/test/helper;%PATH% - set QT_PLUGIN_PATH=%WORKSPACE%/libs/dist/plugins - set QML2_IMPORT_PATH=%WORKSPACE%/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Win64_GNU_MSI.groovy b/resources/jenkins/dsl/Reviews/Review_Win64_GNU_MSI.groovy index df6a0309c..6a8b034c8 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win64_GNU_MSI.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win64_GNU_MSI.groovy @@ -14,14 +14,6 @@ j.with { steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - batchFile('cd source & cmake --preset ci-win-release') - - batchFile('cmake --build build --target package') - - batchFile('cmake --build build --target package.sign') - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Win64_MSVC.groovy b/resources/jenkins/dsl/Reviews/Review_Win64_MSVC.groovy index ced3daaf4..8351f6fb3 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win64_MSVC.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win64_MSVC.groovy @@ -15,23 +15,6 @@ j.with { steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build - '''.stripIndent().trim()) - - batchFile('''\ - set PATH=%WORKSPACE%/libs/dist/bin;%PATH% - set QT_PLUGIN_PATH=%WORKSPACE%/libs/dist/plugins - set QML2_IMPORT_PATH=%WORKSPACE%/libs/dist/qml - ctest --test-dir build --output-on-failure - '''.stripIndent().trim()) + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_Win64_MSVC_MSI.groovy b/resources/jenkins/dsl/Reviews/Review_Win64_MSVC_MSI.groovy index cb964b2a8..6c0f987ea 100644 --- a/resources/jenkins/dsl/Reviews/Review_Win64_MSVC_MSI.groovy +++ b/resources/jenkins/dsl/Reviews/Review_Win64_MSVC_MSI.groovy @@ -13,23 +13,6 @@ j.with { steps { - batchFile('cd source & cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - batchFile('''\ - call vcvarsall.bat amd64 - cd source & cmake --preset ci-win-release - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package - '''.stripIndent().trim()) - - batchFile('''\ - call vcvarsall.bat amd64 - cmake --build build --target package.sign - '''.stripIndent().trim()) - - batchFile('cmake -DCMD=CHECK_WIX_WARNING -DFILE=build/_CPack_Packages/win64/WIX/wix.log -P source/cmake/cmd.cmake') + batchFile('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_iOS_Framework.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_Framework.groovy index 8ff418488..d58877b9f 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_Framework.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_Framework.groovy @@ -13,13 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy index 6779f51bc..c52d8a894 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_IPA.groovy @@ -13,14 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target ipa') - shell('ctest --test-dir build --output-on-failure -C MinSizeRel') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_Framework.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_Framework.groovy index 94f549c42..cb7f264ee 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_Framework.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_Framework.groovy @@ -13,13 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_arm64_Framework.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_arm64_Framework.groovy index a8fbd9b72..69d358204 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_arm64_Framework.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_Simulator_arm64_Framework.groovy @@ -13,13 +13,6 @@ j.with { steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - - shell('security unlock-keychain \${KEYCHAIN_CREDENTIALS} \${HOME}/Library/Keychains/login.keychain-db') - - shell('cd source; cmake --preset ci-ios-framework-simulator-arm64') - - shell('cd build; xcodebuild -configuration MinSizeRel') - shell('cd build; xcodebuild -configuration MinSizeRel -target zip') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/Reviews/Review_iOS_SwiftPackage.groovy b/resources/jenkins/dsl/Reviews/Review_iOS_SwiftPackage.groovy index 11b545c3b..c7ed86262 100644 --- a/resources/jenkins/dsl/Reviews/Review_iOS_SwiftPackage.groovy +++ b/resources/jenkins/dsl/Reviews/Review_iOS_SwiftPackage.groovy @@ -21,11 +21,10 @@ j.with steps { - shell('cd source; cmake -DCMD=IMPORT_PATCH -P cmake/cmd.cmake') - copyArtifacts(build.getSourceJobName('iOS_Framework')) { - targetDirectory('build/arm64') + targetDirectory('arm64') + flatten() buildSelector { buildNumber('${iOS_Framework_Build}') @@ -34,7 +33,8 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_Framework')) { - targetDirectory('build/x86_64-simulator') + targetDirectory('x86_64-simulator') + flatten() buildSelector { buildNumber('${iOS_Simulator_Framework_Build}') @@ -43,13 +43,14 @@ j.with copyArtifacts(build.getSourceJobName('iOS_Simulator_arm64_Framework')) { - targetDirectory('build/arm64-simulator') + targetDirectory('arm64-simulator') + flatten() buildSelector { buildNumber('${iOS_Simulator_arm64_Framework_Build}') } } - shell('cd build; cmake -P ../source/cmake/SwiftPackage.cmake') + shell('cmake -P source/ci.cmake') } } diff --git a/resources/jenkins/dsl/common/Build.groovy b/resources/jenkins/dsl/common/Build.groovy index 98c097b46..4e62db2a2 100644 --- a/resources/jenkins/dsl/common/Build.groovy +++ b/resources/jenkins/dsl/common/Build.groovy @@ -56,6 +56,11 @@ class Build return buildName(getNamePrefix(), artifactJob) } + String getSourceJobNameParam(String artifactJob) + { + return getSourceJobName(artifactJob).replace('-', '_') + '_Build' + } + String getLibName(String partialLibName) { def prefix = 'Libs_' diff --git a/resources/jenkins/dsl/common/Constants.groovy b/resources/jenkins/dsl/common/Constants.groovy index c30b383cd..c2b40196e 100644 --- a/resources/jenkins/dsl/common/Constants.groovy +++ b/resources/jenkins/dsl/common/Constants.groovy @@ -4,8 +4,11 @@ class Constants { static final AndroidArchAPKReview = ["arm64-v8a", "x86_64"] static final AndroidArchAPK = AndroidArchAPKReview + ["armeabi-v7a", "x86"] - static final AndroidArchAAR = ["arm64-v8a"] - static final AndroidArch = (AndroidArchAPK + AndroidArchAAR).unique() + static final AndroidArchAARReview = ["arm64-v8a", "x86_64", "armeabi-v7a"] + static final AndroidArchAAR = AndroidArchAARReview + + static final AndroidArchLibsReview = (AndroidArchAPKReview + AndroidArchAARReview).unique() + static final AndroidArchLibs = (AndroidArchAPK + AndroidArchAAR).unique() static String strip(String content) { diff --git a/resources/jenkins/dsl/install.py b/resources/jenkins/dsl/install.py index d0b6db8c0..30e7b4819 100755 --- a/resources/jenkins/dsl/install.py +++ b/resources/jenkins/dsl/install.py @@ -63,7 +63,7 @@ def installPlugin(plugin): plugins = [] plugins.append('build-timeout') plugins.append('categorized-view') -plugins.append('cobertura') +plugins.append('coverage') plugins.append('copyartifact') plugins.append('cppcheck') plugins.append('depgraph-view') @@ -71,18 +71,17 @@ def installPlugin(plugin): plugins.append('description-setter') plugins.append('envinject') plugins.append('extra-columns') -plugins.append('google-play-android-publisher') -plugins.append('greenballs') plugins.append('heavy-job') plugins.append('htmlpublisher') plugins.append('jenkins-multijob-plugin') plugins.append('jobConfigHistory') plugins.append('job-dsl') plugins.append('mercurial') -plugins.append('msbuild') plugins.append('naginator') plugins.append('nodelabelparameter') plugins.append('parameterized-trigger') +plugins.append('pipeline-stage-view') +plugins.append('pipeline-utility-steps') plugins.append('postbuildscript') plugins.append('show-build-parameters') plugins.append('sloccount') @@ -90,8 +89,9 @@ def installPlugin(plugin): plugins.append('swarm') plugins.append('text-finder') plugins.append('timestamper') -plugins.append('valgrind') +plugins.append('uno-choice') plugins.append('warnings-ng') +plugins.append('workflow-aggregator') plugins.append('ws-cleanup') plugins.append('xunit') diff --git a/resources/jenkins/import.py b/resources/jenkins/import.py index 3367f0b61..0d247d5c7 100755 --- a/resources/jenkins/import.py +++ b/resources/jenkins/import.py @@ -3,16 +3,123 @@ import hglib from hglib.util import b +import argparse import os +import glob import sys +from pathlib import Path + + +class CommandLineParser(argparse.ArgumentParser): + def __init__(self): + super().__init__() + self.add_argument('--no-pending', + help='Do not apply patch', action='store_true') + self.add_argument('--clean', + help='Clean up patches', action='store_true') + self.add_argument('--clean-only', + help='Clean up only', action='store_true') + self.add_argument('--splitted', + help='Apply patches splitted', action='store_true') + self.add_argument('--repatch', + help="Repatch previous series", action='store_true') + self.add_argument('--patch', + help="Patch file", default='../patch.diff') + self.args = self.parse_args() + + def pending(self): + return not self.args.no_pending + + def clean(self): + return self.args.clean or self.clean_only() + + def clean_only(self): + return self.args.clean_only + + def splitted(self): + return self.args.splitted + + def repatch(self): + return self.args.repatch + + def patch(self): + return self.args.patch + + +class PatchProcessor(): + def __init__(self, file, repatch): + self.file = file.decode('utf-8') + self.dir = os.path.dirname(os.path.realpath(self.file)) + self.patch_series = sorted(glob.glob(self.dir + os.sep + '*.patch'), + key=lambda x: int(Path(x).stem)) + self.applied = self.dir + os.sep + 'applied' + self.applied_patches = [] + + if os.path.isfile(self.applied): + with open(self.applied, 'r') as f: + self.applied_patches = list(filter(None, f.read().split('\n'))) + if repatch and len(self.applied_patches) > 0: + self.applied_patches.pop() + + def clean(self): + if os.path.isfile(self.applied): + os.remove(self.applied) + for patch in self.patch_series: + os.remove(patch) + + self.patch_series = [] + self.applied_patches = [] + + def split(self): + def nextFilename(): + self.patch_series.append(self.dir + os.sep + + str(len(self.patch_series)) + + '.patch') + return open(self.patch_series[-1], 'wb') + + with open(self.file, 'rb') as f: + file = nextFilename() + for line in f: + if line == b'# HG changeset patch\n' and file.tell() > 0: + file.close() + file = nextFilename() + file.write(line) + file.close() + + def isSplitted(self): + return len(self.patch_series) > 0 + + def apply(self, client, splitted, applyPending): + if self.patch_series == self.applied_patches or not splitted: + print('Apply all patches: %s' % len(self.patch_series)) + client.import_([s.encode('utf-8') for s in self.patch_series], + nocommit=True) + return + + with open(self.applied, 'w') as f: + for patch in self.patch_series: + pending = patch not in self.applied_patches + if not pending or applyPending and pending: + print('Apply patch: {} (pending: {})'.format(patch, + pending)) + client.import_([patch.encode('utf-8')], + user='CI', + date='now', + message=patch, + nocommit=pending) + + f.write(patch) + f.write('\n') + if pending: + print('Pending patch: {}'.format(patch)) + break + def main(): - if len(sys.argv) > 2: - print('Unknown parameter: {}'.format(sys.argv)) - return -1 + parser = CommandLineParser() - patch = b(sys.argv[1]) if len(sys.argv) == 2 else b('../patch.diff') + patch = b(parser.patch()) if not os.path.isfile(patch): if not os.path.isfile(patch): print('Patch file "{}" does not exists'.format(patch)) @@ -45,9 +152,19 @@ def main(): b('--no-backup'), b('--force')]) - print('Import patch: {}'.format(patch)) - client.import_([patch], nocommit=True) + processor = PatchProcessor(patch, parser.repatch()) + if parser.clean(): + processor.clean() + + if parser.clean_only(): + return 0 + + if not processor.isSplitted(): + print('Split patch: {}'.format(patch)) + processor.split() + print('Wrote {} patch(es)'.format(len(processor.patch_series))) + processor.apply(client, parser.splitted(), parser.pending()) return 0 diff --git a/resources/jenkins/kubernetes/android.yaml b/resources/jenkins/kubernetes/android.yaml index 1edb7127a..c054b891f 100644 --- a/resources/jenkins/kubernetes/android.yaml +++ b/resources/jenkins/kubernetes/android.yaml @@ -64,6 +64,30 @@ spec: key: sonarqube name: dependency-check-credentials optional: false + - name: GPG_PSW + valueFrom: + secretKeyRef: + key: GPG_PSW + name: gpg + optional: false + - name: GPG_ID + valueFrom: + secretKeyRef: + key: GPG_ID + name: gpg + optional: false + - name: CENTRAL_PSW + valueFrom: + secretKeyRef: + key: CENTRAL_PSW + name: android-passwords + optional: false + - name: CENTRAL_USERNAME + valueFrom: + secretKeyRef: + key: CENTRAL_USERNAME + name: android-passwords + optional: false image: dev-docker.governikus.de/ausweisapp2/ubuntu:android imagePullPolicy: Always lifecycle: @@ -74,6 +98,7 @@ spec: - -c - base64 -d /secrets/debug.keystore > /home/governikus/.android/debug.keystore && base64 -d /secrets/release.keystore > /home/governikus/release.keystore + && gpg --batch --passphrase $GPG_PSW --pinentry-mode loopback --import /gpg/GPG_PRIVATE name: android resources: limits: @@ -119,3 +144,8 @@ spec: - name: ccache persistentVolumeClaim: claimName: ccache-android + - name: gpg + secret: + defaultMode: 420 + optional: false + secretName: gpg diff --git a/resources/jenkins/kubernetes/common.yaml b/resources/jenkins/kubernetes/common.yaml index 1322fc2f8..ac082e75f 100644 --- a/resources/jenkins/kubernetes/common.yaml +++ b/resources/jenkins/kubernetes/common.yaml @@ -22,8 +22,28 @@ spec: key: PASSWORD name: android-passwords optional: false + - name: GPG_PSW + valueFrom: + secretKeyRef: + key: GPG_PSW + name: gpg + optional: false + - name: GPG_ID + valueFrom: + secretKeyRef: + key: GPG_ID + name: gpg + optional: false image: dev-docker.governikus.de/ausweisapp2/alpine:common imagePullPolicy: Always + lifecycle: + postStart: + exec: + command: + - sh + - '-c' + - >- + gpg --batch --passphrase $GPG_PSW --pinentry-mode loopback --import /gpg/GPG_PRIVATE name: common resources: limits: @@ -42,3 +62,9 @@ spec: tty: true restartPolicy: Always terminationGracePeriodSeconds: 30 + volumes: + - name: gpg + secret: + defaultMode: 420 + optional: false + secretName: gpg diff --git a/resources/translations/ausweisapp_de.ts b/resources/translations/ausweisapp_de.ts index 0331716eb..da7a33d66 100644 --- a/resources/translations/ausweisapp_de.ts +++ b/resources/translations/ausweisapp_de.ts @@ -172,9 +172,9 @@ Authentisierung fehlgeschlagen - Back to start page + Return to provider LABEL ANDROID IOS - Zur Startseite + Zurück zum Anbieter @@ -962,6 +962,23 @@ LABEL ANDROID IOS Setzt das Erscheinungsbild der Anwendung auf hell + + DataGroup + + %1, optional right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + %1, optionales Recht, Element %2 von %3 + + + %1, required right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + %1, erforderliches Recht, Element %2 von %3 + + DebugSettings @@ -1546,9 +1563,29 @@ LABEL IOS_PHONE ANDROID_PHONE Sprache wechseln - Play animations + Use images instead of animations LABEL DESKTOP - Animationen abspielen + Bilder statt Animationen verwenden + + + Accessibility + LABEL DESKTOP + Barrierefreiheit + + + Hide key animations when entering PIN + LABEL DESKTOP + Tastenanimationen bei PIN-Eingabe ausblenden + + + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. + LABEL DESKTOP + Nach dem Ausweisen erfolgt die Weiterleitung zurück zum Anbieter erst nach Bestätigung. Ansonsten erfolgt die Weiterleitung automatisch nach wenigen Sekunden. + + + Manual redirection back to the provider + LABEL DESKTOP + Manuelle Weiterleitung zurück zum Anbieter @@ -1583,9 +1620,9 @@ LABEL IOS_PHONE ANDROID_PHONE Es wurde kein Ausweis erkannt. Bitte stellen Sie sicher, dass Ihr Ausweis auf dem Kartenleser aufliegt. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. + No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and ready. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. - Es wurde kein Kartenleser gefunden. Bitte überprüfen Sie, ob ein USB-Kartenleser angeschlossen bzw. ein Smartphone als Kartenleser gekoppelt und verfügbar ist. Öffnen Sie die Einstellungen, um Kartenleser zu konfigurieren und weitere Hinweise zu erhalten. + Es wurde kein Kartenleser gefunden. Bitte überprüfen Sie, ob ein USB-Kartenleser angeschlossen bzw. ein Smartphone als Kartenleser gekoppelt und bereit ist. Öffnen Sie die Einstellungen, um Kartenleser zu konfigurieren und weitere Hinweise zu erhalten. Please observe the display of your card reader. @@ -2097,6 +2134,31 @@ LABEL ANDROID IOS Card reader Kartenleser + + %1 of %2 + ANDROID IOS LABEL Relative position of current navigation tab in navigation view. %1 is replaced with the current tab's index, %2 with the total count of tabs + %1 von %2 + + + Tab + ANDROID IOS LABEL + Tab + + + Selection + IOS Selected navigation tab. + Auswahl + + + Tab bar + IOS Name of a11y element of selected navigation tab. + Tab-Leiste + + + Selected + ANDROID Currently selected navigation tab of navigation view. + Ausgewählt + NfcWorkflow @@ -2204,9 +2266,9 @@ LABEL ANDROID IOS NumberField - The password is hidden. + The number is hidden. LABEL DESKTOP Screenreader text for the password field - Das Passwort ist ausgeblendet. + Die Geheimzahl ist ausgeblendet. You entered %1 of %2 digits. @@ -2214,19 +2276,19 @@ LABEL ANDROID IOS Sie haben %1 von %2 Ziffern eingegeben. - Press to hide the password + Press to hide the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Drücken Sie die Taste um das Passwort auszublenden + Drücken Sie die Taste um die Geheimnummer einzublenden - Press to show the password + Press to show the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Drücken Sie die Taste um das Passwort einzublenden + Drücken Sie die Taste um die Geheimnummer auszublenden - The password is visible. Digits entered so far: %1 + The number is visible. Digits entered so far: %1 LABEL DESKTOP Screenreader text for the password field - Das Passwort ist sichtbar. Bisher eingegebene Ziffern: %1 + Die Geheimnummer ist sichtbar. Bisher eingegebene Ziffern: %1 @@ -2572,7 +2634,7 @@ LABEL ALL_PLATFORMS The 6-digit card PIN is a %1number that you choose yourself%2 when you set up the eID function for the first time. It %1replaces%2 your %1 5-digit Transport PIN%2. INFO ALL_PLATFORMS Description text explaining the PINs 4/7 - Die 6-stellige Karten-PIN ist das %1Passwort, das Sie selbst wählen%2, wenn Sie Ihren Online-Ausweis zum ersten Mal einrichten. Sie %1ersetzt%2 Ihre %1 5-stellige Transport-PIN%2. + Die 6-stellige Karten-PIN ist %1eine Geheimnummer, die Sie selbst wählen%2, wenn Sie Ihren Online-Ausweis zum ersten Mal einrichten. Sie %1ersetzt%2 Ihre %1 5-stellige Transport-PIN%2. The Smart-eID PIN also has six digits. You also choose that PIN yourself while setting up the Smart-eID for the first time. @@ -2652,7 +2714,7 @@ LABEL ALL_PLATFORMS If you applied for a %1PIN Reset letter%2, a new card PIN was already set for you. You can change your card PIN at %1any time in %3%2. INFO ALL_PLATFORMS Description text explaining the PINs (%1 is replaced with the application name) 7/7 - Falls Sie einen %1PIN-Rücksetzbrief%2 bestellt haben, wurde Ihnen bereits eine Karten-PIN gesetzt. Sie können Ihre Karten-PIN jedoch %1jederzeit in der %3 ändern%2. + Falls Sie einen %1PIN-Rücksetzbrief%2 bestellt haben, wurde Ihnen bereits eine Karten-PIN gesetzt. Sie können Ihre Karten-PIN jedoch %1jederzeit in der %3 ändern%2. I can't recall my PIN @@ -3037,19 +3099,29 @@ LABEL DESKTOP Title of the proxy credentials popup. RedirectView - Remove the ID card from the card reader. + Remove the ID card from the card reader INFO DESKTOP Hint to user that the ID card should be removed - Entfernen Sie nun den Ausweis vom Kartenleser. + Entfernen Sie nun den Ausweis vom Kartenleser - Remove the ID card from the NFC interface. + Remove the ID card from the NFC interface INFO ANDROID IOS Hint to user that the ID card should be removed - Entfernen Sie jetzt Ihren Ausweis von der NFC-Schnittstelle. + Entfernen Sie jetzt Ihren Ausweis von der NFC-Schnittstelle + + + If you have any questions or encounter any errors during the process, please contact the corresponding provider. + LABEL ALL_PLATFORMS + Bei Rückfragen oder auftretenden Fehlern zum Vorgang wenden Sie sich bitte an den jeweiligen Anbieter. + + + You will be automatically redirected to the provider in a few seconds. If you are not automatically redirected, click on the "%1" button. + INFO ALL_PLATFORMS Redirect information when automatic redirect is enabled + Die automatische Weiterleitung zum Anbieter erfolgt in wenigen Sekunden. Falls Sie nicht automatisch weitergeleitet werden, drücken Sie auf den Button "%1". - You will now leave the %1. For any further questions regarding the current process or occurring errors contact the corresponding provider. - INFO ALL_PLATFORMS User message that the redirect to the provider is immanent and the user will leave the AusweisApp - Sie verlassen nun die %1. Bei Rückfragen zum Vorgang oder auftretenden Fehlern wenden Sie sich an den jeweiligen Anbieter. + Press the button to complete the authentication and return to the provider. + INFO ALL_PLATFORMS Redirect information when automatic redirect is disabled + Drücken Sie auf den Button, um die Authentisierung abzuschließen und zum Anbieter zurückzukehren. Return to provider @@ -3061,11 +3133,6 @@ LABEL DESKTOP Title of the proxy credentials popup. LABEL ALL_PLATFORMS Authentisierung erfolgreich - - You will be redirected to the provider - LABEL ALL_PLATFORMS - Sie werden zum Anbieter zurückgeleitet - ReleaseNotes @@ -3190,14 +3257,14 @@ LABEL ANDROID IOS Kartenzugriff - Waiting for connection + Card reader ready LABEL ANDROID IOS - Warte auf Verbindung + Kartenleser bereit - Waiting for connection from a paired device... + To do this, start a process on a paired device. INFO ANDROID IOS - Warte auf eine Verbindung eines gekoppelten Gerätes... + Starten Sie hierzu auf einem gekoppelten Gerät einen Vorgang. Pairing code: <b>%1</b> @@ -3220,9 +3287,9 @@ LABEL ANDROID IOS Gerät koppeln - Allow connection + Activate card reader LABEL ANDROID IOS - Verbindung erlauben + Kartenleser aktivieren You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. @@ -3288,6 +3355,11 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel LABEL ANDROID IOS Kein NFC verfügbar + + Stop card reader + LABEL ANDROID IOS + Kartenleser beenden + RemoteServiceViewRemote @@ -3415,15 +3487,16 @@ Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppel ResultErrorView - - Details - Details - Error code: LABEL ANDROID IOS Fehlercode: + + Show Details + LABEL ANDROID IOS + Details anzeigen + ResultView @@ -3463,9 +3536,9 @@ LABEL ANDROID IOS SecurityAndPrivacySettings - Onscreen keypad + Numeric keypad LABEL DESKTOP - Bildschirmtastatur + Ziffernblock Software updates @@ -3473,9 +3546,9 @@ LABEL ANDROID IOS Software-Aktualisierungen - Check at program start + Check for updates at program start LABEL DESKTOP - Automatisch bei Programmstart prüfen + Automatisch bei Programmstart nach Updates suchen Show update @@ -3508,19 +3581,19 @@ LABEL ANDROID IOS Keine Aktualisierungsinformationen vorhanden, bitte prüfen Sie manuell auf verfügbare Aktualisierungen. - Shuffle digits of on screen keypad + Shuffle keys LABEL DESKTOP - Ziffern der Bildschirmtastatur zufällig anordnen + Tasten zufällig anordnen - Button animation + Hide key animations LABEL DESKTOP - Tasten-Animationen + Tasten Animationen ausblenden - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry LABEL DESKTOP - Eingaben auf der Bildschirmtastatur optisch hervorheben + Erschwert eine Erkennung der PIN-Eingabe durch Außenstehende @@ -3634,11 +3707,14 @@ LABEL ANDROID IOS Security and privacy - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Sicherheit und Datenschutz + + Numeric keypad + LABEL ANDROID IOS + Ziffernblock + Debug options LABEL DESKTOP @@ -3669,14 +3745,14 @@ LABEL ANDROID IOS PIN-Eingabe auf diesem Gerät - Randomize the order of the on screen keypad buttons + Shuffle keys LABEL ANDROID IOS - Ziffern der Bildschirmtastatur zufällig anordnen + Tasten zufällig anordnen - Keypad animations + Hide key animations LABEL ANDROID IOS - Tasten-Animationen + Tasten Animationen ausblenden Skip rights page @@ -3794,14 +3870,34 @@ LABEL ANDROID IOS Bei der Authentisierung eine Testmusterkarte simulieren - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry + LABEL ANDROID IOS + Erschwert eine Erkennung der PIN-Eingabe durch Außenstehende + + + Use images instead of animations + LABEL ANDROID IOS + Bilder statt Animationen verwenden + + + Accessibility + LABEL ANDROID IOS + Barrierefreiheit + + + Hide key animations when entering PIN + LABEL ANDROID IOS + Tastenanimationen bei PIN-Eingabe ausblenden + + + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. LABEL ANDROID IOS - Eingaben auf der Bildschirmtastatur optisch hervorheben + Nach dem Ausweisen erfolgt die Weiterleitung zurück zum Anbieter erst nach Bestätigung. Ansonsten erfolgt die Weiterleitung automatisch nach wenigen Sekunden. - Play animations + Manual redirection back to the provider LABEL ANDROID IOS - Animationen abspielen + Manuelle Weiterleitung zurück zum Anbieter @@ -4309,13 +4405,19 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Show in-app notifications of %1 - Zeige den internen Benachrichtigungsdialog der %1 + LABEL DESKTOP + Internen Benachrichtigungsdialog der %1 einblenden Title bar LABEL DESKTOP Titelleiste + + Hide in-app notifications of %1 + LABEL DESKTOP + Internen Benachrichtigungsdialog der %1 ausblenden + TitleBarNavigation @@ -4747,7 +4849,7 @@ Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle au Authentisierung erfolgreich - Back to provider + Return to provider LABEL ALL_PLATFORMS Zurück zum Anbieter diff --git a/resources/translations/ausweisapp_ru.ts b/resources/translations/ausweisapp_ru.ts index 1dca6b345..924b826c1 100644 --- a/resources/translations/ausweisapp_ru.ts +++ b/resources/translations/ausweisapp_ru.ts @@ -172,9 +172,9 @@ Сбой аутентификации - Back to start page + Return to provider LABEL ANDROID IOS - Назад к начальной странице + Вернуться к провайдеру @@ -962,6 +962,23 @@ LABEL ANDROID IOS Установить для приложения светлую тему + + DataGroup + + %1, optional right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + + + + %1, required right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + + + DebugSettings @@ -1546,9 +1563,29 @@ LABEL IOS_PHONE ANDROID_PHONE Изменить язык - Play animations + Use images instead of animations + LABEL DESKTOP + + + + Accessibility + LABEL DESKTOP + + + + Hide key animations when entering PIN + LABEL DESKTOP + + + + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. + LABEL DESKTOP + + + + Manual redirection back to the provider LABEL DESKTOP - Воспроизвести анимации + @@ -1583,9 +1620,9 @@ LABEL IOS_PHONE ANDROID_PHONE Идентификационная карта не обнаружена. Убедитесь в том, что идентификационная карта размещена на устройстве чтения карт. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. + No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and ready. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. - Устройство чтения карт не обнаружено. Убедитесь в том, что USB-устройство чтения карт подключено или используемый в качестве устройства чтения карт смартфон сопряжен и доступен. Откройте настройки устройства чтения карт для конфигурирования устройств чтения карт и получения подробной информации о поддерживаемых устройствах чтения карт. + Устройство чтения карт не обнаружено. Убедитесь в том, что USB-устройство чтения карт подключено или используемый в качестве устройства чтения карт смартфон сопряжен и доступен. Откройте настройки устройства чтения карт для конфигурирования устройств чтения карт и получения подробной информации о поддерживаемых устройствах чтения карт. Please observe the display of your card reader. @@ -2097,6 +2134,31 @@ LABEL ANDROID IOS Card reader Устройство чтения карт + + %1 of %2 + ANDROID IOS LABEL Relative position of current navigation tab in navigation view. %1 is replaced with the current tab's index, %2 with the total count of tabs + + + + Tab + ANDROID IOS LABEL + + + + Selection + IOS Selected navigation tab. + + + + Tab bar + IOS Name of a11y element of selected navigation tab. + + + + Selected + ANDROID Currently selected navigation tab of navigation view. + + NfcWorkflow @@ -2204,9 +2266,9 @@ LABEL ANDROID IOS NumberField - The password is hidden. + The number is hidden. LABEL DESKTOP Screenreader text for the password field - Пароль скрыт. + You entered %1 of %2 digits. @@ -2214,19 +2276,19 @@ LABEL ANDROID IOS Вы ввели %1 из %2 знаков. - Press to hide the password + Press to hide the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Нажмите, чтобы скрыть пароль + - Press to show the password + Press to show the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Нажмите, чтобы показать пароль + - The password is visible. Digits entered so far: %1 + The number is visible. Digits entered so far: %1 LABEL DESKTOP Screenreader text for the password field - Пароль отображается. Цифры, введенные ранее: %1 + @@ -3037,19 +3099,29 @@ LABEL DESKTOP Title of the proxy credentials popup. RedirectView - Remove the ID card from the card reader. + Remove the ID card from the card reader INFO DESKTOP Hint to user that the ID card should be removed - Извлеките идентификационную карту из устройства чтоения карт. + Извлеките идентификационную карту из устройства чтоения карт - Remove the ID card from the NFC interface. + Remove the ID card from the NFC interface INFO ANDROID IOS Hint to user that the ID card should be removed - Извлеките идентификационную карту из интерфейса NFC. + Извлеките идентификационную карту из интерфейса NFC + + + If you have any questions or encounter any errors during the process, please contact the corresponding provider. + LABEL ALL_PLATFORMS + + + + You will be automatically redirected to the provider in a few seconds. If you are not automatically redirected, click on the "%1" button. + INFO ALL_PLATFORMS Redirect information when automatic redirect is enabled + - You will now leave the %1. For any further questions regarding the current process or occurring errors contact the corresponding provider. - INFO ALL_PLATFORMS User message that the redirect to the provider is immanent and the user will leave the AusweisApp - Вы покидаете %1. По всем дополнительным вопросам, касающимся текущего процесса или возникающих ошибок, обращайтесь к соответствующему провайдеру. + Press the button to complete the authentication and return to the provider. + INFO ALL_PLATFORMS Redirect information when automatic redirect is disabled + Return to provider @@ -3061,11 +3133,6 @@ LABEL DESKTOP Title of the proxy credentials popup. LABEL ALL_PLATFORMS Аутентификация выполнена успешно - - You will be redirected to the provider - LABEL ALL_PLATFORMS - Вас перенаправят к провайдеру - ReleaseNotes @@ -3190,14 +3257,14 @@ LABEL ANDROID IOS Выполняется доступ к карте - Waiting for connection + Card reader ready LABEL ANDROID IOS - Ожидание соединения + Ожидание соединения - Waiting for connection from a paired device... + To do this, start a process on a paired device. INFO ANDROID IOS - Ожидание соединения сопряженного устройства… + Pairing code: <b>%1</b> @@ -3220,9 +3287,9 @@ LABEL ANDROID IOS Выполнить сопряжение устройства - Allow connection + Activate card reader LABEL ANDROID IOS - Разрешить подключение + Разрешить подключение You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. @@ -3288,6 +3355,11 @@ To do this you first have to pair that device with this smartphone. LABEL ANDROID IOS Функция NFC недоступна + + Stop card reader + LABEL ANDROID IOS + + RemoteServiceViewRemote @@ -3415,15 +3487,16 @@ To do this you first have to pair that device with this smartphone. ResultErrorView - - Details - Подробная информация - Error code: LABEL ANDROID IOS Код ошибки: + + Show Details + LABEL ANDROID IOS + Подробная информация + ResultView @@ -3463,9 +3536,9 @@ LABEL ANDROID IOS SecurityAndPrivacySettings - Onscreen keypad + Numeric keypad LABEL DESKTOP - Экранная клавиатура + Экранная клавиатура Software updates @@ -3473,9 +3546,9 @@ LABEL ANDROID IOS Обновления программного обеспечения - Check at program start + Check for updates at program start LABEL DESKTOP - Проверить при запуске программы + Проверить при запуске программы Show update @@ -3508,19 +3581,19 @@ LABEL ANDROID IOS Нет информации об обновлениях, проверьте наличие доступных обновлений вручную. - Shuffle digits of on screen keypad + Shuffle keys LABEL DESKTOP - Перетасовать цифры экранной клавиатуры + Перетасовать цифры экранной клавиатуры - Button animation + Hide key animations LABEL DESKTOP - Анимация кнопок + Анимация кнопок - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry LABEL DESKTOP - Визуальное выделение нажатой клавиши на экранной клавиатуре + Визуальное выделение нажатой клавиши на экранной клавиатуре @@ -3634,11 +3707,14 @@ LABEL ANDROID IOS Security and privacy - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Безопасность и защита данных + + Numeric keypad + LABEL ANDROID IOS + Безопасность и защита данных + Debug options LABEL DESKTOP @@ -3669,14 +3745,14 @@ LABEL ANDROID IOS Ввести PIN-код на этом устройстве - Randomize the order of the on screen keypad buttons + Shuffle keys LABEL ANDROID IOS - Случайное расположение кнопок экранной клавиатуры + Случайное расположение кнопок экранной клавиатуры - Keypad animations + Hide key animations LABEL ANDROID IOS - Анимация кнопок + Анимация кнопок Skip rights page @@ -3794,14 +3870,34 @@ LABEL ANDROID IOS Моделировать тестовую карту в процессах аутентификации - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry + LABEL ANDROID IOS + Визуальное выделение нажатой клавиши на экранной клавиатуре + + + Use images instead of animations + LABEL ANDROID IOS + + + + Accessibility + LABEL ANDROID IOS + + + + Hide key animations when entering PIN LABEL ANDROID IOS - Визуальное выделение нажатой клавиши на экранной клавиатуре + - Play animations + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. LABEL ANDROID IOS - Воспроизвести анимации + + + + Manual redirection back to the provider + LABEL ANDROID IOS + @@ -4309,6 +4405,7 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Show in-app notifications of %1 + LABEL DESKTOP Показать внутренние оповещения в приложении %1 @@ -4316,6 +4413,11 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u LABEL DESKTOP Строка заголовка + + Hide in-app notifications of %1 + LABEL DESKTOP + + TitleBarNavigation @@ -4747,9 +4849,9 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Аутентификация выполнена успешно - Back to provider + Return to provider LABEL ALL_PLATFORMS - Назад к провайдеру + Вернуться к провайдеру Back to start page diff --git a/resources/translations/ausweisapp_uk.ts b/resources/translations/ausweisapp_uk.ts index 76e96794c..8760377cb 100644 --- a/resources/translations/ausweisapp_uk.ts +++ b/resources/translations/ausweisapp_uk.ts @@ -172,9 +172,9 @@ Не вдалося виконати автентифікацію - Back to start page + Return to provider LABEL ANDROID IOS - Повернутися до початкової сторінки + Повернутися до постачальника @@ -962,6 +962,23 @@ LABEL ANDROID IOS Налаштувати зовнішній вигляд програми на світлий режим + + DataGroup + + %1, optional right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + + + + %1, required right, element %2 of %3 + LABEL DESKTOP +---------- +LABEL ANDROID IOS + + + DebugSettings @@ -1546,9 +1563,29 @@ LABEL IOS_PHONE ANDROID_PHONE Змінити мову - Play animations + Use images instead of animations LABEL DESKTOP - Відтворення анімації + + + + Accessibility + LABEL DESKTOP + + + + Hide key animations when entering PIN + LABEL DESKTOP + + + + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. + LABEL DESKTOP + + + + Manual redirection back to the provider + LABEL DESKTOP + @@ -1583,9 +1620,9 @@ LABEL IOS_PHONE ANDROID_PHONE ID-картку не виявлено. Розташуйте ID-картку на пристрої читання карток. - No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers. + No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and ready. Open the reader settings to configure readers and get more information about supported readers. INFO DESKTOP AA2 is waiting for the card reader or the ID card. - Пристрій читання карток не виявлено. Переконайтеся, що USB-пристрій читання карток підключено, або смартфон як пристрій читання карток з’єднаний та доступний. Відкрийте параметри пристрою читання, щоб налаштувати пристрої читання та отримати більше інформації про підтримувані пристрої читання карток. + Пристрій читання карток не виявлено. Переконайтеся, що USB-пристрій читання карток підключено, або смартфон як пристрій читання карток з’єднаний та доступний. Відкрийте параметри пристрою читання, щоб налаштувати пристрої читання та отримати більше інформації про підтримувані пристрої читання карток. Please observe the display of your card reader. @@ -2097,6 +2134,31 @@ LABEL ANDROID IOS Card reader Пристрій читання карток + + %1 of %2 + ANDROID IOS LABEL Relative position of current navigation tab in navigation view. %1 is replaced with the current tab's index, %2 with the total count of tabs + + + + Tab + ANDROID IOS LABEL + + + + Selection + IOS Selected navigation tab. + + + + Tab bar + IOS Name of a11y element of selected navigation tab. + + + + Selected + ANDROID Currently selected navigation tab of navigation view. + + NfcWorkflow @@ -2204,9 +2266,9 @@ LABEL ANDROID IOS NumberField - The password is hidden. + The number is hidden. LABEL DESKTOP Screenreader text for the password field - Пароль приховано. + You entered %1 of %2 digits. @@ -2214,19 +2276,19 @@ LABEL ANDROID IOS Ви ввели %1 з %2 знаків. - Press to hide the password + Press to hide the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Натисніть, щоб приховати пароль + - Press to show the password + Press to show the number LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - Натисніть, щоб показати пароль + - The password is visible. Digits entered so far: %1 + The number is visible. Digits entered so far: %1 LABEL DESKTOP Screenreader text for the password field - Пароль показано. Наразі введені цифри: %1 + @@ -3037,19 +3099,29 @@ LABEL DESKTOP Title of the proxy credentials popup. RedirectView - Remove the ID card from the card reader. + Remove the ID card from the card reader INFO DESKTOP Hint to user that the ID card should be removed - Вийміть ID-картку із пристрою читання карток. + Вийміть ID-картку із пристрою читання карток - Remove the ID card from the NFC interface. + Remove the ID card from the NFC interface INFO ANDROID IOS Hint to user that the ID card should be removed - Вийміть ID-картку з інтерфейсу NFC. + Вийміть ID-картку з інтерфейсу NFC + + + If you have any questions or encounter any errors during the process, please contact the corresponding provider. + LABEL ALL_PLATFORMS + + + + You will be automatically redirected to the provider in a few seconds. If you are not automatically redirected, click on the "%1" button. + INFO ALL_PLATFORMS Redirect information when automatic redirect is enabled + - You will now leave the %1. For any further questions regarding the current process or occurring errors contact the corresponding provider. - INFO ALL_PLATFORMS User message that the redirect to the provider is immanent and the user will leave the AusweisApp - Ви залишаєте %1. З будь-якими подальшими запитаннями щодо поточного процесу або помилок, що виникають, звертайтеся до відповідного постачальника. + Press the button to complete the authentication and return to the provider. + INFO ALL_PLATFORMS Redirect information when automatic redirect is disabled + Return to provider @@ -3061,11 +3133,6 @@ LABEL DESKTOP Title of the proxy credentials popup. LABEL ALL_PLATFORMS Автентифікацію виконано успішно - - You will be redirected to the provider - LABEL ALL_PLATFORMS - Вас буде переспрямовано до постачальника - ReleaseNotes @@ -3190,14 +3257,14 @@ LABEL ANDROID IOS Виконується доступ до картки - Waiting for connection + Card reader ready LABEL ANDROID IOS - Очікування підключення + Очікування підключення - Waiting for connection from a paired device... + To do this, start a process on a paired device. INFO ANDROID IOS - Очікування підключення від пристрою, з яким створено пару… + Pairing code: <b>%1</b> @@ -3220,9 +3287,9 @@ LABEL ANDROID IOS Створити пару з пристроєм - Allow connection + Activate card reader LABEL ANDROID IOS - Дозволити з’єднання + Дозволити з’єднання You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. @@ -3288,6 +3355,11 @@ To do this you first have to pair that device with this smartphone. LABEL ANDROID IOS NFC недоступно + + Stop card reader + LABEL ANDROID IOS + + RemoteServiceViewRemote @@ -3415,15 +3487,16 @@ To do this you first have to pair that device with this smartphone. ResultErrorView - - Details - Відомості - Error code: LABEL ANDROID IOS Код помилки: + + Show Details + LABEL ANDROID IOS + Відомості + ResultView @@ -3463,9 +3536,9 @@ LABEL ANDROID IOS SecurityAndPrivacySettings - Onscreen keypad + Numeric keypad LABEL DESKTOP - Екранна клавіатура + Екранна клавіатура Software updates @@ -3473,9 +3546,9 @@ LABEL ANDROID IOS Оновлення програмного забезпечення - Check at program start + Check for updates at program start LABEL DESKTOP - Перевіряти під час запуску програми + Перевіряти під час запуску програми Show update @@ -3508,19 +3581,19 @@ LABEL ANDROID IOS Інформація про оновлення недоступна, перевірте наявність оновлення вручну. - Shuffle digits of on screen keypad + Shuffle keys LABEL DESKTOP - Перемішати цифри на екранній клавіатурі + Перемішати цифри на екранній клавіатурі - Button animation + Hide key animations LABEL DESKTOP - Анімація кнопок + Анімація кнопок - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry LABEL DESKTOP - Візуальне виділення натискань кнопок на екранній клавіатурі + Візуальне виділення натискань кнопок на екранній клавіатурі @@ -3634,11 +3707,14 @@ LABEL ANDROID IOS Security and privacy - LABEL DESKTOP ----------- -LABEL ANDROID IOS + LABEL DESKTOP Безпека й конфіденційність + + Numeric keypad + LABEL ANDROID IOS + Безпека й конфіденційність + Debug options LABEL DESKTOP @@ -3669,14 +3745,14 @@ LABEL ANDROID IOS Введіть PIN-код на цьому пристрої - Randomize the order of the on screen keypad buttons + Shuffle keys LABEL ANDROID IOS - Налаштувати довільний порядок кнопок на екранній клавіатурі + Налаштувати довільний порядок кнопок на екранній клавіатурі - Keypad animations + Hide key animations LABEL ANDROID IOS - Анімація клавіатури + Анімація клавіатури Skip rights page @@ -3794,14 +3870,34 @@ LABEL ANDROID IOS Імітація картки тестового зразка в автентифікації - Visually highlight key presses on screen keypad + Makes it difficult for outsiders to detect PIN entry + LABEL ANDROID IOS + Візуальне виділення натискань кнопок на екранній клавіатурі + + + Use images instead of animations + LABEL ANDROID IOS + + + + Accessibility + LABEL ANDROID IOS + + + + Hide key animations when entering PIN LABEL ANDROID IOS - Візуальне виділення натискань кнопок на екранній клавіатурі + - Play animations + After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds. LABEL ANDROID IOS - Відтворення анімації + + + + Manual redirection back to the provider + LABEL ANDROID IOS + @@ -4309,6 +4405,7 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Show in-app notifications of %1 + LABEL DESKTOP Показувати сповіщення в програмі щодо %1 @@ -4316,6 +4413,11 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u LABEL DESKTOP Рядок заголовка + + Hide in-app notifications of %1 + LABEL DESKTOP + + TitleBarNavigation @@ -4747,7 +4849,7 @@ To proceed use your ID card by selecting the NFC interface. If you want to set u Автентифікацію виконано успішно - Back to provider + Return to provider LABEL ALL_PLATFORMS Повернутися до постачальника diff --git a/resources/updatable-files/supported-providers.json b/resources/updatable-files/supported-providers.json index d74540403..9ff9d58d8 100644 --- a/resources/updatable-files/supported-providers.json +++ b/resources/updatable-files/supported-providers.json @@ -620,15 +620,15 @@ { "eidSupport": false, "shortName": { - "": "Bürgerservice-Portal Stadt Lage" + "": "Onlinedienste Stadt Lage" }, "longName": { - "": "Bürgerservice-Portal Stadt Lage" + "": "Onlinedienste Stadt Lage" }, "longDescription": { - "": "Das Bürgerservice-Portal bietet die Möglichkeit, Anträge an die Verwaltung der Stadt Lage online zu erfassen und elektronisch zur weiteren Bearbeitung weiterzuleiten." + "": "Die Onlinedienste der Stadt Lage bieten die Möglichkeit, Anträge an die Verwaltung der Stadt Lage online zu erfassen und elektronisch zur weiteren Bearbeitung weiterzuleiten." }, - "address": "https://www.buergerserviceportal.nrw/krz/lage", + "address": "https://onlinedienste-owl.de/Lage", "homepage": "https://www.lage.de", "phone": "+49 5232 601300", "email": "Buergerbuero@lage.de", diff --git a/resources/updatable-files/supported-readers.json b/resources/updatable-files/supported-readers.json index cb4dc63db..27ac36fe0 100644 --- a/resources/updatable-files/supported-readers.json +++ b/resources/updatable-files/supported-readers.json @@ -224,7 +224,7 @@ "os": "win" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304820&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-windows" }, { "Platforms": [ @@ -232,7 +232,7 @@ "os": "mac" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304820&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-mac" }, { "Platforms": [ @@ -240,7 +240,7 @@ "os": "unknown" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304820&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-linux" } ], "Information": [ @@ -285,7 +285,7 @@ "os": "win" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Windows&productGroup=77304735&product=77304856&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-windows" }, { "Platforms": [ @@ -294,7 +294,7 @@ "max": "13" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=MacOS&productGroup=77304735&product=77304856&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-mac" }, { "Platforms": [ @@ -311,7 +311,7 @@ "os": "unknown" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304856&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-linux" } ], "Information": [ @@ -354,8 +354,8 @@ "min": "14" } ], - "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite.", - "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system." + "DE": "Es ist notwendig, die Treiber vom Hersteller zu installieren. Dazu folgen Sie bitte dem jeweiligen Link für Ihr Betriebssystem zur Herstellerseite. Nach der Installation ist ein Neustart erforderlich.", + "EN": "It is necessary to install the drivers from the manufacturer. Please follow the relevant link for your operating system. A reboot is required after the installation of the driver." } ] }, @@ -366,7 +366,7 @@ "0x0505" ], "Name": "REINER SCT cyberJack wave", - "Pattern": "REINER SCT cyberJack wave( USB)?( \\d{1,1})?$", + "Pattern": "REINER SCT cyberJack wave", "Icon": "img_cyberjack_wave.png", "IconWithNPA": "img_cyberjack_wave_mit_ausweis.png", "Drivers": [ @@ -376,7 +376,7 @@ "os": "win" } ], - "URL": "https://help.reiner-sct.com/de/support/solutions/articles/101000475765" + "URL": "https://www.reiner-sct.com/treiber-windows" }, { "Platforms": [ @@ -384,7 +384,7 @@ "os": "mac" } ], - "URL": "https://help.reiner-sct.com/de/support/solutions/articles/101000480002" + "URL": "https://www.reiner-sct.com/treiber-mac" }, { "Platforms": [ @@ -392,7 +392,7 @@ "os": "unknown" } ], - "URL": "https://www.reiner-sct.com/support/support-anfrage/?os=Linux&productGroup=77304735&product=77304828&q=driver#choice5" + "URL": "https://www.reiner-sct.com/treiber-linux" } ], "Information": [ diff --git a/src/card/base/Card.cpp b/src/card/base/Card.cpp index bf439cac6..92cfd7fb5 100644 --- a/src/card/base/Card.cpp +++ b/src/card/base/Card.cpp @@ -31,13 +31,12 @@ void Card::setErrorMessage(const QString& pMessage) } -EstablishPaceChannelOutput Card::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds) +EstablishPaceChannelOutput Card::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) { Q_UNUSED(pPasswordId) Q_UNUSED(pPreferredPinLength) Q_UNUSED(pChat) Q_UNUSED(pCertificateDescription) - Q_UNUSED(pTimeoutSeconds) qCWarning(card) << "Establishment of PACE channel not supported"; return EstablishPaceChannelOutput(CardReturnCode::COMMAND_FAILED); } diff --git a/src/card/base/Card.h b/src/card/base/Card.h index e5fa8a83c..37d45a439 100644 --- a/src/card/base/Card.h +++ b/src/card/base/Card.h @@ -48,6 +48,8 @@ class Card Q_OBJECT public: + static constexpr int DEFAULT_PINPAD_TIMEOUT = 90; + Card(); ~Card() override = default; @@ -83,7 +85,7 @@ class Card /*! * Establishes a PACE channel, i.e. the corresponding reader is no basic reader. */ - virtual EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds = 60); + virtual EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription); /*! * Destroys an existing PACE channel, i.e. the corresponding reader is no basic reader. diff --git a/src/card/base/CardConnection.h b/src/card/base/CardConnection.h index 488d32eb1..1d81f4aa6 100644 --- a/src/card/base/CardConnection.h +++ b/src/card/base/CardConnection.h @@ -167,7 +167,7 @@ class CardConnection template QMetaObject::Connection callSetEidPinCommand(const typename QtPrivate::FunctionPointer::Object* pReceiver, T pFunc, const QByteArray& pNewPin, - quint8 pTimeoutSeconds = 60) + quint8 pTimeoutSeconds = Card::DEFAULT_PINPAD_TIMEOUT) { auto command = createSetEidPinCommand(pNewPin, pTimeoutSeconds); return call(command, pReceiver, pFunc); diff --git a/src/card/nfc/NfcCard.cpp b/src/card/nfc/NfcCard.cpp index afb650137..2f18553d7 100644 --- a/src/card/nfc/NfcCard.cpp +++ b/src/card/nfc/NfcCard.cpp @@ -134,6 +134,7 @@ ResponseApduResult NfcCard::transmit(const CommandApdu& pCmd) } const QByteArray recvBuffer = response.toByteArray(); - qCDebug(card_nfc) << "Transmit response APDU:" << recvBuffer.toHex(); - return {CardReturnCode::OK, ResponseApdu(recvBuffer)}; + const ResponseApdu responseApdu(recvBuffer); + qCDebug(card_nfc) << "Transmit response APDU:" << responseApdu; + return {CardReturnCode::OK, responseApdu}; } diff --git a/src/card/pcsc/PcscCard.cpp b/src/card/pcsc/PcscCard.cpp index 3340a0fff..6c52664cb 100644 --- a/src/card/pcsc/PcscCard.cpp +++ b/src/card/pcsc/PcscCard.cpp @@ -264,7 +264,7 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer, QByteArray data(8192, '\0'); auto dataReceived = static_cast(data.size()); - qCDebug(card_pcsc) << "SCardTransmit cmdBuffer:" << pSendBuffer.toHex(); + qCDebug(card_pcsc) << "Transmit command APDU::" << CommandApdu(pSendBuffer); const PCSC_RETURNCODE returnCode = SCardTransmit(mCardHandle, pSendPci, reinterpret_cast(pSendBuffer.data()), @@ -273,13 +273,13 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer, reinterpret_cast(data.data()), &dataReceived); - qCDebug(card_pcsc) << "SCardTransmit for" << mReader->getName() << ':' << pcsc::toString(returnCode); + qCDebug(card_pcsc) << "Transmit for" << mReader->getName() << ':' << pcsc::toString(returnCode); switch (returnCode) { case pcsc::Scard_S_Success: data.resize(static_cast(dataReceived)); - qCDebug(card_pcsc) << "SCardTransmit resBuffer:" << data.toHex(); + qCDebug(card_pcsc) << "Transmit response APDU:" << ResponseApdu(data); if (data.size() < 2) { @@ -320,19 +320,15 @@ PcscCard::CardResult PcscCard::transmit(const QByteArray& pSendBuffer, EstablishPaceChannelOutput PcscCard::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, - const QByteArray& pCertificateDescription, - quint8 pTimeoutSeconds) + const QByteArray& pCertificateDescription) { Q_UNUSED(pPreferredPinLength) - Q_UNUSED(pTimeoutSeconds) if (!mReader->hasFeature(FeatureID::EXECUTE_PACE)) { return EstablishPaceChannelOutput(CardReturnCode::COMMAND_FAILED); } - disableOverlay(); - PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::EXECUTE_PACE); EstablishPaceChannel builder(pPasswordId, pChat, pCertificateDescription); auto [returnCode, controlRes] = control(cmdID, builder.createASN1Struct()); @@ -401,23 +397,6 @@ PcscCard::CardResult PcscCard::control(PCSC_INT pCntrCode, const QByteArray& pCn } -#ifdef Q_OS_WIN -void PcscCard::disableOverlay() -{ - const auto& cardResult = control(SCARD_CTL_CODE(3105), QByteArray::fromHex("02")); - if (cardResult.mReturnCode == pcsc::Scard_S_Success) - { - qCDebug(card_pcsc) << "Control to disable overlay succeed"; - return; - } - - qCWarning(card_pcsc) << "Control to disable overlay failed"; - -} - - -#endif - ResponseApduResult PcscCard::setEidPin(quint8 pTimeoutSeconds) { if (!mReader->hasFeature(FeatureID::MODIFY_PIN_DIRECT)) @@ -425,8 +404,6 @@ ResponseApduResult PcscCard::setEidPin(quint8 pTimeoutSeconds) return {CardReturnCode::COMMAND_FAILED}; } - disableOverlay(); - PCSC_INT cmdID = mReader->getFeatureValue(FeatureID::MODIFY_PIN_DIRECT); PinModify pinModify(pTimeoutSeconds); auto [returnCode, controlRes] = control(cmdID, pinModify.createCcid()); diff --git a/src/card/pcsc/PcscCard.h b/src/card/pcsc/PcscCard.h index 2ed0560b0..f9e4cee6c 100644 --- a/src/card/pcsc/PcscCard.h +++ b/src/card/pcsc/PcscCard.h @@ -43,15 +43,6 @@ class PcscCard CardResult transmit(const QByteArray& pSendBuffer); CardResult transmit(const QByteArray& pSendBuffer, const SCARD_IO_REQUEST* pSendPci); CardResult control(PCSC_INT pCntrCode, const QByteArray& pCntrInput); -#ifdef Q_OS_WIN - void disableOverlay(); -#else - void disableOverlay() const - { - } - - -#endif private Q_SLOTS: void sendSCardStatus(); @@ -66,7 +57,7 @@ class PcscCard ResponseApduResult transmit(const CommandApdu& pCmd) override; - EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds) override; + EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) override; CardReturnCode destroyPaceChannel() override; diff --git a/src/card/simulator/SimulatorCard.cpp b/src/card/simulator/SimulatorCard.cpp index 87491d78b..6d5cb2951 100644 --- a/src/card/simulator/SimulatorCard.cpp +++ b/src/card/simulator/SimulatorCard.cpp @@ -167,12 +167,11 @@ ResponseApduResult SimulatorCard::transmit(const CommandApdu& pCmd) } -EstablishPaceChannelOutput SimulatorCard::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds) +EstablishPaceChannelOutput SimulatorCard::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) { Q_UNUSED(pPasswordId) Q_UNUSED(pPreferredPinLength) Q_UNUSED(pCertificateDescription) - Q_UNUSED(pTimeoutSeconds) QThread::msleep(Env::getSingleton()->getDelay()); EstablishPaceChannelOutput output(CardReturnCode::OK); diff --git a/src/card/simulator/SimulatorCard.h b/src/card/simulator/SimulatorCard.h index b709d175b..69cf8343a 100644 --- a/src/card/simulator/SimulatorCard.h +++ b/src/card/simulator/SimulatorCard.h @@ -51,7 +51,7 @@ class SimulatorCard ResponseApduResult transmit(const CommandApdu& pCmd) override; - EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds) override; + EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) override; CardReturnCode destroyPaceChannel() override; diff --git a/src/ifd/base/ConnectRequest.cpp b/src/ifd/base/ConnectRequest.cpp index 9fa227cbe..82ef8d26a 100644 --- a/src/ifd/base/ConnectRequest.cpp +++ b/src/ifd/base/ConnectRequest.cpp @@ -168,7 +168,14 @@ void ConnectRequest::onConnected() void ConnectRequest::onError(QAbstractSocket::SocketError pError) { - qCWarning(ifd) << "Connection error:" << pError; + if (mSocket) + { + qCWarning(ifd) << "Connection error:" << pError << mSocket->errorString(); + } + else + { + qCWarning(ifd) << "Connection error:" << pError; + } mTimer.stop(); if (pError == QAbstractSocket::SocketError::RemoteHostClosedError diff --git a/src/ifd/base/IfdCard.cpp b/src/ifd/base/IfdCard.cpp index 65b34ebf1..b6fc6df30 100644 --- a/src/ifd/base/IfdCard.cpp +++ b/src/ifd/base/IfdCard.cpp @@ -216,12 +216,13 @@ ResponseApduResult IfdCard::transmit(const CommandApdu& pCommand) return {CardReturnCode::COMMAND_FAILED}; } - qCDebug(card_remote) << "Transmit response APDU:" << response.getResponseApdu().toHex(); - return {CardReturnCode::OK, ResponseApdu(response.getResponseApdu())}; + const ResponseApdu responseApdu(response.getResponseApdu()); + qCDebug(card_remote) << "Transmit response APDU:" << responseApdu; + return {CardReturnCode::OK, responseApdu}; } -EstablishPaceChannelOutput IfdCard::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds) +EstablishPaceChannelOutput IfdCard::establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) { EstablishPaceChannel establishPaceChannel(pPasswordId, pChat, pCertificateDescription); if (Env::getSingleton()->isUsedAsSDK()) @@ -230,7 +231,7 @@ EstablishPaceChannelOutput IfdCard::establishPaceChannel(PacePasswordId pPasswor } const QSharedPointer& message = QSharedPointer::create(mSlotHandle, establishPaceChannel, pPreferredPinLength); - if (!sendMessage(message, IfdMessageType::IFDEstablishPACEChannelResponse, pTimeoutSeconds * 1000)) + if (!sendMessage(message, IfdMessageType::IFDEstablishPACEChannelResponse, DEFAULT_PINPAD_TIMEOUT * 1000)) { return EstablishPaceChannelOutput(CardReturnCode::INPUT_TIME_OUT); } diff --git a/src/ifd/base/IfdCard.h b/src/ifd/base/IfdCard.h index 330f552f4..d1f58a7d6 100644 --- a/src/ifd/base/IfdCard.h +++ b/src/ifd/base/IfdCard.h @@ -61,7 +61,7 @@ class IfdCard ResponseApduResult transmit(const CommandApdu& pCmd) override; - EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription, quint8 pTimeoutSeconds = 60) override; + EstablishPaceChannelOutput establishPaceChannel(PacePasswordId pPasswordId, int pPreferredPinLength, const QByteArray& pChat, const QByteArray& pCertificateDescription) override; CardReturnCode destroyPaceChannel() override; diff --git a/src/services/Service.cpp b/src/services/Service.cpp index 826735bc0..51deb112c 100644 --- a/src/services/Service.cpp +++ b/src/services/Service.cpp @@ -7,6 +7,7 @@ #include "AppSettings.h" #include "AppUpdater.h" #include "ProviderConfiguration.h" +#include "SecureStorage.h" #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #include "ReaderConfiguration.h" @@ -122,8 +123,18 @@ bool Service::isUpdateScheduled() const } -void Service::runUpdateIfNeeded() +void Service::runUpdateIfNeeded(bool pSkipProxy) { + if (pSkipProxy) + { + const auto& appcastUrl = Env::getSingleton()->getAppcastUpdateUrl(); + const auto& proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(appcastUrl)); + if (!proxies.isEmpty() && proxies.first().type() != QNetworkProxy::NoProxy) + { + return; + } + } + if (mUpdateScheduled) { mUpdateScheduled = false; diff --git a/src/services/Service.h b/src/services/Service.h index fc78ec5f7..963bd54b4 100644 --- a/src/services/Service.h +++ b/src/services/Service.h @@ -40,7 +40,7 @@ class Service public: void updateAppcast(); [[nodiscard]] bool isUpdateScheduled() const; - void runUpdateIfNeeded(); + void runUpdateIfNeeded(bool pSkipProxy = false); [[nodiscard]] const AppUpdateData& getUpdateData() const; Q_SIGNALS: diff --git a/src/settings/AutoStart_osx.mm b/src/settings/AutoStart_osx.mm index 042374043..d524c6397 100644 --- a/src/settings/AutoStart_osx.mm +++ b/src/settings/AutoStart_osx.mm @@ -58,7 +58,11 @@ bool AutoStart::setInternal(bool pEnabled) { - if (SMLoginItemSetEnabled(static_cast(autostartBundleIdentifier), pEnabled)) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + const bool callSucceeded = SMLoginItemSetEnabled(static_cast(autostartBundleIdentifier), pEnabled); + QT_WARNING_POP + if (callSucceeded) { qCDebug(settings) << "Setting autostart to" << pEnabled << "succeeded"; return true; diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index cf6ea8d84..b6779f813 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -26,6 +26,7 @@ namespace { SETTINGS_NAME(SETTINGS_NAME_PERSISTENT_SETTINGS_VERSION, "persistentSettingsVersion") SETTINGS_NAME(SETTINGS_NAME_AUTO_CLOSE_WINDOW, "autoCloseWindow") +SETTINGS_NAME(SETTINGS_NAME_AUTO_REDIRECT, "autoRedirect") SETTINGS_NAME(SETTINGS_NAME_UI_STARTUP_MODULE, "uiStartupModule") SETTINGS_NAME(SETTINGS_NAME_REMIND_USER_TO_CLOSE, "remindToClose") SETTINGS_NAME(SETTINGS_NAME_TRANSPORT_PIN_REMINDER, "transportPinReminder") @@ -209,6 +210,23 @@ void GeneralSettings::setAutoCloseWindowAfterAuthentication(bool pAutoClose) } +bool GeneralSettings::isAutoRedirectAfterAuthentication() const +{ + return mStore->value(SETTINGS_NAME_AUTO_REDIRECT(), true).toBool(); +} + + +void GeneralSettings::setAutoRedirectAfterAuthentication(bool pAutoRedirect) +{ + if (pAutoRedirect != isAutoRedirectAfterAuthentication()) + { + mStore->setValue(SETTINGS_NAME_AUTO_REDIRECT(), pAutoRedirect); + save(mStore); + Q_EMIT fireSettingsChanged(); + } +} + + QString GeneralSettings::getStartupModule() const { return mStore->value(SETTINGS_NAME_UI_STARTUP_MODULE(), QString()).toString(); diff --git a/src/settings/GeneralSettings.h b/src/settings/GeneralSettings.h index 0efff941a..58ef79347 100644 --- a/src/settings/GeneralSettings.h +++ b/src/settings/GeneralSettings.h @@ -55,6 +55,9 @@ class GeneralSettings [[nodiscard]] bool isAutoCloseWindowAfterAuthentication() const; void setAutoCloseWindowAfterAuthentication(bool pAutoClose); + [[nodiscard]] bool isAutoRedirectAfterAuthentication() const; + void setAutoRedirectAfterAuthentication(bool pAutoRedirect); + [[nodiscard]] QString getStartupModule() const; void setStartupModule(const QString& pModule); diff --git a/src/ui/qml/AuthModel.cpp b/src/ui/qml/AuthModel.cpp index 90719f1b6..63071e429 100644 --- a/src/ui/qml/AuthModel.cpp +++ b/src/ui/qml/AuthModel.cpp @@ -3,6 +3,7 @@ */ #include "AuthModel.h" +#include "context/SelfAuthContext.h" using namespace governikus; @@ -168,30 +169,22 @@ QString AuthModel::getResultViewButtonText() const { return QString(); } - - if (mContext->getStatus().getStatusCode() == GlobalStatus::Code::Workflow_Browser_Transmission_Error) + if (mContext.objectCast()) { //: LABEL ALL_PLATFORMS - return tr("Back to provider"); + return tr("Back to start page"); } - //: LABEL ALL_PLATFORMS - return tr("Back to start page"); + return tr("Return to provider"); } QUrl AuthModel::getResultViewButtonLink() const { - if (!mContext) - { - return QUrl(); - } - - if (mContext->getStatus().getStatusCode() == GlobalStatus::Code::Workflow_Browser_Transmission_Error) + if (mContext && mContext->isReceivedBrowserSendFailed()) { return mContext->getRefreshUrl(); } - return QUrl(); } diff --git a/src/ui/qml/SettingsModel.cpp b/src/ui/qml/SettingsModel.cpp index 5ec2ffb6f..21e04e476 100644 --- a/src/ui/qml/SettingsModel.cpp +++ b/src/ui/qml/SettingsModel.cpp @@ -364,6 +364,23 @@ void SettingsModel::setAutoCloseWindowAfterAuthentication(bool pEnabled) } +bool SettingsModel::isAutoRedirectAfterAuthentication() const +{ + return Env::getSingleton()->getGeneralSettings().isAutoRedirectAfterAuthentication(); +} + + +void SettingsModel::setAutoRedirectAfterAuthentication(bool pEnabled) +{ + if (isAutoRedirectAfterAuthentication() != pEnabled) + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + settings.setAutoRedirectAfterAuthentication(pEnabled); + Q_EMIT fireAutoRedirectAfterAuthenticationChanged(); + } +} + + bool SettingsModel::isAutoUpdateAvailable() const { return Env::getSingleton()->getGeneralSettings().isAutoUpdateAvailable(); diff --git a/src/ui/qml/SettingsModel.h b/src/ui/qml/SettingsModel.h index 99ee84468..900e9a7de 100644 --- a/src/ui/qml/SettingsModel.h +++ b/src/ui/qml/SettingsModel.h @@ -52,6 +52,7 @@ class SettingsModel Q_PROPERTY(bool autoStartSetByAdmin READ autoStartIsSetByAdmin CONSTANT) Q_PROPERTY(bool autoUpdateAvailable READ isAutoUpdateAvailable CONSTANT) Q_PROPERTY(bool autoCloseWindowAfterAuthentication READ isAutoCloseWindowAfterAuthentication WRITE setAutoCloseWindowAfterAuthentication NOTIFY fireAutoCloseWindowAfterAuthenticationChanged) + Q_PROPERTY(bool autoRedirectAfterAuthentication READ isAutoRedirectAfterAuthentication WRITE setAutoRedirectAfterAuthentication NOTIFY fireAutoRedirectAfterAuthenticationChanged) Q_PROPERTY(bool autoUpdateCheck READ isAutoUpdateCheck WRITE setAutoUpdateCheck NOTIFY fireAutoUpdateCheckChanged) Q_PROPERTY(bool autoUpdateCheckSetByAdmin READ autoUpdateCheckIsSetByAdmin CONSTANT) Q_PROPERTY(bool remindUserToClose READ isRemindUserToClose WRITE setRemindUserToClose NOTIFY fireRemindUserToCloseChanged) @@ -134,6 +135,9 @@ class SettingsModel [[nodiscard]] bool isAutoCloseWindowAfterAuthentication() const; void setAutoCloseWindowAfterAuthentication(bool pEnabled); + [[nodiscard]] bool isAutoRedirectAfterAuthentication() const; + void setAutoRedirectAfterAuthentication(bool pEnabled); + [[nodiscard]] bool isAutoUpdateAvailable() const; [[nodiscard]] bool isAutoUpdateCheck() const; [[nodiscard]] bool autoUpdateCheckIsSetByAdmin() const; @@ -190,6 +194,7 @@ class SettingsModel void fireStartupModuleChanged(); void fireAutoStartChanged(); void fireAutoCloseWindowAfterAuthenticationChanged(); + void fireAutoRedirectAfterAuthenticationChanged(); void fireAutoUpdateCheckChanged(); void fireRemindUserToCloseChanged(); void fireTransportPinReminderChanged(); diff --git a/src/ui/qml/TrayIcon.cpp b/src/ui/qml/TrayIcon.cpp index be2d9f0cb..c7c61f965 100644 --- a/src/ui/qml/TrayIcon.cpp +++ b/src/ui/qml/TrayIcon.cpp @@ -166,18 +166,6 @@ void TrayIcon::setVisible(bool pVisible) } -bool TrayIcon::isVisible() const -{ -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (mTrayIcon) - { - mTrayIcon->isVisible(); - } -#endif - return false; -} - - void TrayIcon::showMessage(const QString& pTitle, const QString& pMessage) { #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) diff --git a/src/ui/qml/TrayIcon.h b/src/ui/qml/TrayIcon.h index 054c7a608..bc7886038 100644 --- a/src/ui/qml/TrayIcon.h +++ b/src/ui/qml/TrayIcon.h @@ -42,7 +42,6 @@ class TrayIcon void create(); void shutdown(); void setVisible(bool pVisible); - [[nodiscard]] bool isVisible() const; void showMessage(const QString& pTitle, const QString& pMessage); diff --git a/src/ui/qml/UiPluginQml.cpp b/src/ui/qml/UiPluginQml.cpp index 1fd3b5e9b..a8d531af7 100644 --- a/src/ui/qml/UiPluginQml.cpp +++ b/src/ui/qml/UiPluginQml.cpp @@ -243,6 +243,12 @@ void UiPluginQml::init() } onWindowPaletteChanged(); + +#ifdef Q_OS_WIN + QMetaObject::invokeMethod(this, [] { + Env::getSingleton()->runUpdateIfNeeded(true); + }, Qt::QueuedConnection); +#endif } diff --git a/src/ui/qml/modules/AuthView/+desktop/AuthView.qml b/src/ui/qml/modules/AuthView/+desktop/AuthView.qml index d2c0acb4d..fdf80a424 100644 --- a/src/ui/qml/modules/AuthView/+desktop/AuthView.qml +++ b/src/ui/qml/modules/AuthView/+desktop/AuthView.qml @@ -143,12 +143,15 @@ SectionPage { ProgressView { id: checkConnectivityView + icon: "qrc:///images/no_internet.svg" + //: INFO DESKTOP Content of the message that no network connection is present during the authentication procedure. subText: qsTr("Please establish an internet connection.") subTextColor: Style.color.textNormal.basic //: INFO DESKTOP Header of the message that no network connection is present during the authentication procedure. text: qsTr("No network connectivity") + tintColor: Style.color.image visible: d.activeView === AuthView.SubViews.Connectivity } EditRights { diff --git a/src/ui/qml/modules/AuthView/+desktop/EditRights.qml b/src/ui/qml/modules/AuthView/+desktop/EditRights.qml index 7fa930aa2..08c769760 100644 --- a/src/ui/qml/modules/AuthView/+desktop/EditRights.qml +++ b/src/ui/qml/modules/AuthView/+desktop/EditRights.qml @@ -106,8 +106,9 @@ SectionPage { Accessible.name: transactionText.text activeFocusOnTab: true + objectName: "transactionText" text: AuthModel.transactionInfo - textFormat: Text.PlainText + textFormat: Text.StyledText visible: !!text FocusFrame { diff --git a/src/ui/qml/modules/AuthView/+desktop/internal/DataGroup.qml b/src/ui/qml/modules/AuthView/+desktop/internal/DataGroup.qml index cda92dc67..1bcfe49ef 100644 --- a/src/ui/qml/modules/AuthView/+desktop/internal/DataGroup.qml +++ b/src/ui/qml/modules/AuthView/+desktop/internal/DataGroup.qml @@ -51,6 +51,7 @@ ColumnLayout { id: rightItem property bool isLast: index === repeater.count - 1 + property int modelIndex: index property string modelName: name property bool modelSelected: selected property bool modelWriteRight: writeRight @@ -93,6 +94,8 @@ ColumnLayout { GCheckBox { id: checkBox + //: LABEL DESKTOP + Accessible.name: qsTr("%1, optional right, element %2 of %3").arg(text).arg(modelIndex + 1).arg(repeater.count) checked: modelSelected focusFrameVisible: false horizontalPadding: Constants.text_spacing @@ -109,6 +112,8 @@ ColumnLayout { GText { id: dataText + //: LABEL DESKTOP + Accessible.name: qsTr("%1, required right, element %2 of %3").arg(text).arg(modelIndex + 1).arg(repeater.count) activeFocusOnTab: true leftPadding: Constants.text_spacing rightPadding: Constants.text_spacing diff --git a/src/ui/qml/modules/AuthView/+mobile/CheckConnectivityView.qml b/src/ui/qml/modules/AuthView/+mobile/CheckConnectivityView.qml index 9d8f062da..4154f8dd7 100644 --- a/src/ui/qml/modules/AuthView/+mobile/CheckConnectivityView.qml +++ b/src/ui/qml/modules/AuthView/+mobile/CheckConnectivityView.qml @@ -11,13 +11,12 @@ ProgressView { signal cancel - icon: "qrc:///images/mobile/no_internet_%1.svg".arg(Style.currentTheme.name) + icon: "qrc:///images/no_internet.svg" //: INFO ANDROID IOS No network connection, the user needs to active the network interface or abort the procedure. subText: qsTr("Please establish an internet connection.") subTextColor: Style.color.textNormal.basic //: LABEL ANDROID IOS text: qsTr("No network connectivity") - tintEnabled: false navigationAction: NavigationAction { action: NavigationAction.Action.Cancel diff --git a/src/ui/qml/modules/AuthView/+mobile/EditRights.qml b/src/ui/qml/modules/AuthView/+mobile/EditRights.qml index de3a7adf0..97f201750 100644 --- a/src/ui/qml/modules/AuthView/+mobile/EditRights.qml +++ b/src/ui/qml/modules/AuthView/+mobile/EditRights.qml @@ -86,8 +86,9 @@ FlickableSectionPage { GText { activeFocusOnTab: true + objectName: "transactionText" text: workflowModel.transactionInfo - textFormat: Text.PlainText + textFormat: Text.StyledText visible: !!text width: parent.width } diff --git a/src/ui/qml/modules/AuthView/+mobile/internal/AuthController.qml b/src/ui/qml/modules/AuthView/+mobile/internal/AuthController.qml index 9c298c8c0..201ce16fc 100644 --- a/src/ui/qml/modules/AuthView/+mobile/internal/AuthController.qml +++ b/src/ui/qml/modules/AuthView/+mobile/internal/AuthController.qml @@ -415,7 +415,7 @@ Controller { ResultErrorView { //: LABEL ANDROID IOS - buttonText: qsTr("Back to start page") + buttonText: qsTr("Return to provider") errorCode: AuthModel.statusCodeString errorDescription: AuthModel.errorText //: LABEL ANDROID IOS diff --git a/src/ui/qml/modules/AuthView/+mobile/internal/DataGroup.qml b/src/ui/qml/modules/AuthView/+mobile/internal/DataGroup.qml index fba171e41..9d08fad7a 100644 --- a/src/ui/qml/modules/AuthView/+mobile/internal/DataGroup.qml +++ b/src/ui/qml/modules/AuthView/+mobile/internal/DataGroup.qml @@ -56,6 +56,7 @@ Column { id: delegateLoader property bool isLast: index === repeater.count - 1 + property int modelIndex: index property string modelName: name property bool modelSelected: selected property bool modelWriteRight: writeRight @@ -89,6 +90,8 @@ Column { GCheckBox { id: checkBox + //: LABEL ANDROID IOS + Accessible.name: qsTr("%1, optional right, element %2 of %3").arg(text).arg(modelIndex + 1).arg(repeater.count) checked: modelSelected horizontalPadding: Constants.pane_padding layoutDirection: Qt.RightToLeft @@ -112,6 +115,8 @@ Column { id: requiredDelegate GText { + //: LABEL ANDROID IOS + Accessible.name: qsTr("%1, required right, element %2 of %3").arg(text).arg(modelIndex + 1).arg(repeater.count) activeFocusOnTab: true bottomPadding: Constants.text_spacing leftPadding: Constants.pane_padding diff --git a/src/ui/qml/modules/AuthView/+mobile/internal/SelfAuthenticationData.qml b/src/ui/qml/modules/AuthView/+mobile/internal/SelfAuthenticationData.qml index cafcb081b..3b54e356e 100644 --- a/src/ui/qml/modules/AuthView/+mobile/internal/SelfAuthenticationData.qml +++ b/src/ui/qml/modules/AuthView/+mobile/internal/SelfAuthenticationData.qml @@ -16,6 +16,7 @@ FlickableSectionPage { signal done signal requestBack + spacing: Constants.pane_spacing //: LABEL ANDROID IOS title: qsTr("Identify") diff --git a/src/ui/qml/modules/AuthView/internal/RedirectView.qml b/src/ui/qml/modules/AuthView/internal/RedirectView.qml index 2f1989914..ca48ce56d 100644 --- a/src/ui/qml/modules/AuthView/internal/RedirectView.qml +++ b/src/ui/qml/modules/AuthView/internal/RedirectView.qml @@ -2,21 +2,25 @@ * Copyright (c) 2024 Governikus GmbH & Co. KG, Germany */ +import QtQml + import Governikus.Global import Governikus.ResultView import Governikus.Style import Governikus.Type ResultView { - //: INFO ALL_PLATFORMS User message that the redirect to the provider is immanent and the user will leave the AusweisApp - readonly property string leaveText: qsTr("You will now leave the %1. For any further questions regarding the current process or occurring errors contact the corresponding provider.").arg(Qt.application.name) - readonly property string removeCardText: { - if (Constants.is_desktop) { - //: INFO DESKTOP Hint to user that the ID card should be removed - return qsTr("Remove the ID card from the card reader."); + id: root + + //: LABEL ALL_PLATFORMS + readonly property string leaveText: qsTr("If you have any questions or encounter any errors during the process, please contact the corresponding provider.") + readonly property string redirectText: { + if (SettingsModel.autoRedirectAfterAuthentication) { + //: INFO ALL_PLATFORMS Redirect information when automatic redirect is enabled + return qsTr("You will be automatically redirected to the provider in a few seconds. If you are not automatically redirected, click on the \"%1\" button.").arg(buttonText); } - //: INFO ANDROID IOS Hint to user that the ID card should be removed - return qsTr("Remove the ID card from the NFC interface."); + //: INFO ALL_PLATFORMS Redirect information when automatic redirect is disabled + return qsTr("Press the button to complete the authentication and return to the provider."); } buttonIcon: "qrc:///images/open_website.svg" @@ -25,12 +29,37 @@ ResultView { //: LABEL ALL_PLATFORMS header: qsTr("Authentication successful") icon: "qrc:///images/status_ok_%1.svg".arg(Style.currentTheme.name) - //: LABEL ALL_PLATFORMS - subheader: qsTr("You will be redirected to the provider") + subheader: { + if (Constants.is_desktop) { + //: INFO DESKTOP Hint to user that the ID card should be removed + return qsTr("Remove the ID card from the card reader"); + } + //: INFO ANDROID IOS Hint to user that the ID card should be removed + return qsTr("Remove the ID card from the NFC interface"); + } text: { if (AuthModel.showRemoveCardFeedback) { - return "%1

%2".arg(leaveText).arg(removeCardText); + return "%1

%2".arg(leaveText).arg(redirectText); } return leaveText; } + + Component.onCompleted: { + if (!Constants.is_desktop && SettingsModel.autoRedirectAfterAuthentication) { + timeout.start(); + } + } + onVisibleChanged: { + if (Constants.is_desktop && visible && SettingsModel.autoRedirectAfterAuthentication) { + timeout.start(); + } + } + + Timer { + id: timeout + + interval: 7000 + + onTriggered: root.confirm() + } } diff --git a/src/ui/qml/modules/EnterPasswordView/internal/NumberPad.qml b/src/ui/qml/modules/EnterPasswordView/internal/NumberPad.qml index afb21b07f..54e7dce07 100644 --- a/src/ui/qml/modules/EnterPasswordView/internal/NumberPad.qml +++ b/src/ui/qml/modules/EnterPasswordView/internal/NumberPad.qml @@ -71,7 +71,7 @@ GridLayout { onClicked: baseItem.digitPressed(text) } - NumberPadButton { + SubmitButton { id: submitButton Layout.fillHeight: true diff --git a/src/ui/qml/modules/EnterPasswordView/internal/NumberPadButton.qml b/src/ui/qml/modules/EnterPasswordView/internal/NumberPadButton.qml index ae40dea5f..b74ae44f5 100644 --- a/src/ui/qml/modules/EnterPasswordView/internal/NumberPadButton.qml +++ b/src/ui/qml/modules/EnterPasswordView/internal/NumberPadButton.qml @@ -14,6 +14,7 @@ AbstractButton { property string a11yDisabledText: qsTr("Disabled") property string a11yText: "" + readonly property alias colors: colors property real fontScale: 1 property bool visualPrivacy: SettingsModel.visualPrivacy diff --git a/src/ui/qml/modules/EnterPasswordView/internal/SubmitButton.qml b/src/ui/qml/modules/EnterPasswordView/internal/SubmitButton.qml new file mode 100644 index 000000000..5f5a190f4 --- /dev/null +++ b/src/ui/qml/modules/EnterPasswordView/internal/SubmitButton.qml @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2024 Governikus GmbH & Co. KG, Germany + */ + +import Governikus.Global + +NumberPadButton { + id: root + + colors.paneBackground: colors.controlBackground + colors.paneBorder: colors.controlBorder + colors.textHeadline: colors.controlContent +} diff --git a/src/ui/qml/modules/Global/+desktop/ConfirmationPopup.qml b/src/ui/qml/modules/Global/+desktop/ConfirmationPopup.qml index da6aa7b35..d7f840e9e 100644 --- a/src/ui/qml/modules/Global/+desktop/ConfirmationPopup.qml +++ b/src/ui/qml/modules/Global/+desktop/ConfirmationPopup.qml @@ -17,13 +17,13 @@ BaseConfirmationPopup { GButton { text: root.okButtonText - visible: style & ConfirmationPopup.PopupStyle.OkButton + visible: root.style & ConfirmationPopup.PopupStyle.OkButton onClicked: root.accept() } GButton { text: root.cancelButtonText - visible: style & ConfirmationPopup.PopupStyle.CancelButton + visible: root.style & ConfirmationPopup.PopupStyle.CancelButton onClicked: root.cancel() } diff --git a/src/ui/qml/modules/Global/+mobile/+android/ConfirmationPopup.qml b/src/ui/qml/modules/Global/+mobile/+android/ConfirmationPopup.qml index 0fb71ab56..b521c88e2 100644 --- a/src/ui/qml/modules/Global/+mobile/+android/ConfirmationPopup.qml +++ b/src/ui/qml/modules/Global/+mobile/+android/ConfirmationPopup.qml @@ -4,7 +4,6 @@ import QtQuick import QtQuick.Controls import Governikus.Global -import Governikus.Style BaseConfirmationPopup { id: root @@ -14,19 +13,15 @@ BaseConfirmationPopup { spacing: 0 width: parent.width - GButton { - background: null + GLink { text: root.okButtonText - textStyle: Style.text.normal - visible: style & ConfirmationPopup.PopupStyle.OkButton + visible: root.style & ConfirmationPopup.PopupStyle.OkButton onClicked: root.accept() } - GButton { - background: null + GLink { text: root.cancelButtonText - textStyle: Style.text.normal - visible: style & ConfirmationPopup.PopupStyle.CancelButton + visible: root.style & ConfirmationPopup.PopupStyle.CancelButton onClicked: root.cancel() } diff --git a/src/ui/qml/modules/Global/+mobile/+ios/ConfirmationPopup.qml b/src/ui/qml/modules/Global/+mobile/+ios/ConfirmationPopup.qml index 4a6a1744a..5d997c842 100644 --- a/src/ui/qml/modules/Global/+mobile/+ios/ConfirmationPopup.qml +++ b/src/ui/qml/modules/Global/+mobile/+ios/ConfirmationPopup.qml @@ -5,7 +5,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Governikus.Global -import Governikus.Style BaseConfirmationPopup { id: root @@ -18,33 +17,29 @@ BaseConfirmationPopup { GSeparator { Layout.fillWidth: true - visible: style !== ConfirmationPopup.PopupStyle.NoButtons + visible: root.style !== ConfirmationPopup.PopupStyle.NoButtons } RowLayout { spacing: 0 - GButton { + GLink { Layout.maximumWidth: Number.POSITIVE_INFINITY - background: null implicitWidth: 1 text: root.cancelButtonText - textStyle: Style.text.normal - visible: style & ConfirmationPopup.PopupStyle.CancelButton + visible: root.style & ConfirmationPopup.PopupStyle.CancelButton onClicked: root.cancel() } GSeparator { Layout.fillHeight: true orientation: Qt.Vertical - visible: style & ConfirmationPopup.PopupStyle.CancelButton && style & ConfirmationPopup.PopupStyle.OkButton + visible: root.style & ConfirmationPopup.PopupStyle.CancelButton && root.style & ConfirmationPopup.PopupStyle.OkButton } - GButton { + GLink { Layout.maximumWidth: Number.POSITIVE_INFINITY - background: null implicitWidth: 1 text: root.okButtonText - textStyle: Style.text.normal - visible: style & ConfirmationPopup.PopupStyle.OkButton + visible: root.style & ConfirmationPopup.PopupStyle.OkButton onClicked: root.accept() } diff --git a/src/ui/qml/modules/Global/GButton.qml b/src/ui/qml/modules/Global/GButton.qml index fdac59403..e9fd32e8e 100644 --- a/src/ui/qml/modules/Global/GButton.qml +++ b/src/ui/qml/modules/Global/GButton.qml @@ -13,7 +13,7 @@ AbstractButton { id: root property int borderWidth: Style.dimens.border_width - property alias buttonColor: d.color + property alias buttonColor: colors.controlBackground property alias cursorShape: mouseArea.cursorShape property string disabledTooltipText @@ -24,6 +24,7 @@ AbstractButton { property alias layoutDirection: contentLayout.layoutDirection property alias maximumLineCount: buttonText.maximumLineCount property real radius: Style.dimens.control_radius + property alias style: colors.controlStyle property TextStyle textStyle: Style.text.button property bool tintIcon: false @@ -42,9 +43,9 @@ AbstractButton { verticalPadding: Constants.control_verticalPadding background: Rectangle { - border.color: d.borderColor + border.color: colors.controlBorder border.width: root.borderWidth - color: d.color + color: colors.controlBackground radius: root.radius } contentItem: RowLayout { @@ -62,7 +63,7 @@ AbstractButton { source: root.icon.source sourceSize.height: 1.2 * buttonText.effectiveFirstLineHeight - tintColor: d.contentColor + tintColor: colors.controlContent tintEnabled: tintIcon visible: source != "" } @@ -72,7 +73,7 @@ AbstractButton { Accessible.ignored: true Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: Number.POSITIVE_INFINITY - color: d.contentColor + color: colors.controlContent elide: Text.ElideRight font: root.font horizontalAlignment: { @@ -96,60 +97,13 @@ AbstractButton { id: hoverHandler } - Item { - id: d + StatefulColors { + id: colors - property color borderColor: color === Style.color.control.background.basic ? Style.color.control.border.basic : color - property color color: Style.color.control.background.basic - property color contentColor: root.textStyle.textColor - - states: [ - State { - name: "disabled" - when: !root.enabled || !root.enableButton - - PropertyChanges { - d.borderColor: Style.color.control.border.disabled - d.color: Style.color.control.background.disabled - d.contentColor: Style.color.control.content.disabled - } - }, - State { - name: "pressed" - when: root.pressed - - PropertyChanges { - d.borderColor: Style.color.control.border.pressed - d.color: Style.color.control.background.pressed - d.contentColor: Style.color.control.content.pressed - } - }, - State { - name: "hovered" - when: hoverHandler.hovered - - PropertyChanges { - d.borderColor: Style.color.control.border.hovered - d.color: Style.color.control.background.hovered - d.contentColor: root.textStyle === Style.text.button ? Style.color.control.content.hovered : Style.color.control.content.pressed - } - }, - State { - name: "checked" - when: root.checked - - PropertyChanges { - d.borderColor: Style.color.control.border.checked - d.color: Style.color.control.background.checked - d.contentColor: Style.color.control.content.checked - } - } - ] - transitions: [ - EaseInPressedTransition { - target: d - } - ] + controlBorder: controlBackground === controlStyle.background.basic ? controlStyle.border.basic : controlBackground + disabledCondition: !root.enableButton || !root.enabled + hoveredCondition: hoverHandler.hovered + statefulControl: root } FocusFrame { marginFactor: root.background ? 0.8 : 1 diff --git a/src/ui/qml/modules/Global/GCollapsible.qml b/src/ui/qml/modules/Global/GCollapsible.qml index a000eae6d..6817c4fc3 100644 --- a/src/ui/qml/modules/Global/GCollapsible.qml +++ b/src/ui/qml/modules/Global/GCollapsible.qml @@ -12,6 +12,7 @@ ColumnLayout { id: root property bool alwaysReserveSelectionTitleHeight: false + property bool arrowToLeft: false property alias backgroundColor: collapsibleContentBackground.color property int contentBottomMargin: Constants.groupbox_spacing property int contentHorizontalMargin: horizontalMargin @@ -68,8 +69,12 @@ ColumnLayout { anchors.verticalCenter: parent.verticalCenter spacing: 0 + LeftRightArrow { + isLeft: root.arrowToLeft + visible: root.arrowToLeft + } ColumnLayout { - Layout.leftMargin: horizontalMargin + Layout.leftMargin: root.arrowToLeft ? 0 : root.horizontalMargin spacing: Constants.subtext_spacing GText { @@ -115,20 +120,15 @@ ColumnLayout { TintableIcon { id: selectionIcon + Layout.rightMargin: root.arrowToLeft ? root.horizontalMargin : 0 sourceSize.height: Style.dimens.small_icon_size tintColor: Style.color.textNormal.basic tintEnabled: false visible: source.toString() !== "" } - TintableIcon { - id: arrow - - Layout.leftMargin: Constants.text_spacing - Layout.rightMargin: horizontalMargin - source: expanded ? "qrc:///images/material_expand_less.svg" : "qrc:///images/material_expand_more.svg" - sourceSize.height: Style.text.normal.textSize - tintColor: Style.color.textNormal.basic - tintEnabled: true + LeftRightArrow { + isLeft: root.arrowToLeft + visible: !root.arrowToLeft } } @@ -176,4 +176,15 @@ ColumnLayout { } } } + + component LeftRightArrow: TintableIcon { + property bool isLeft: false + + Layout.leftMargin: isLeft ? root.horizontalMargin : Constants.text_spacing + Layout.rightMargin: isLeft ? Constants.text_spacing : root.horizontalMargin + source: expanded ? "qrc:///images/material_expand_less.svg" : "qrc:///images/material_expand_more.svg" + sourceSize.height: Style.text.normal.textSize + tintColor: Style.color.textNormal.basic + tintEnabled: true + } } diff --git a/src/ui/qml/modules/Global/GText.qml b/src/ui/qml/modules/Global/GText.qml index 4d4ece30e..4474eb9d5 100644 --- a/src/ui/qml/modules/Global/GText.qml +++ b/src/ui/qml/modules/Global/GText.qml @@ -23,11 +23,12 @@ Text { } } + Accessible.focusable: true Accessible.ignored: text === "" Accessible.name: ApplicationModel.stripHtmlTags(text) + (Constants.is_desktop && hasLink ? //: INFO DESKTOP Text read by screen reader if the text contains a weblink which may be opened. " %1: %2".arg(qsTr("Press space to open link")).arg(d.link) : "") - Accessible.role: Constants.is_desktop && hasLink ? Accessible.Button : Accessible.StaticText + Accessible.role: Constants.is_desktop && hasLink ? Accessible.Button : d.isHeadline ? Accessible.Heading : Accessible.StaticText Layout.fillWidth: true Layout.maximumWidth: Math.ceil(implicitWidth) color: textStyle.textColor @@ -49,6 +50,7 @@ Text { QtObject { id: d + readonly property bool isHeadline: [Style.text.headline, Style.text.subline].includes(root.textStyle) property string link: "" readonly property bool nonMultilineElided: maximumLineCount === 1 && elide !== Text.ElideNone diff --git a/src/ui/qml/modules/Global/NumberField.qml b/src/ui/qml/modules/Global/NumberField.qml index edd6098a0..d6b4377ea 100644 --- a/src/ui/qml/modules/Global/NumberField.qml +++ b/src/ui/qml/modules/Global/NumberField.qml @@ -55,9 +55,9 @@ Control { Accessible.name: (eye.activated ? //: LABEL DESKTOP Screenreader text for the password field - qsTr("The password is visible. Digits entered so far: %1").arg(root.number.split("").join(" ")) : + qsTr("The number is visible. Digits entered so far: %1").arg(root.number.split("").join(" ")) : //: LABEL DESKTOP Screenreader text for the password field - qsTr("The password is hidden.")) + (text === undefined ? " " + passwordState : "") + qsTr("The number is hidden.")) + (text === undefined ? " " + passwordState : "") Accessible.role: Accessible.StaticText Layout.maximumWidth: contentItem.Layout.maximumWidth + leftPadding + rightPadding Layout.minimumWidth: contentItem.Layout.minimumWidth + leftPadding + rightPadding @@ -135,9 +135,9 @@ Control { padding: Constants.text_spacing / 2 text: (activated ? //: LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - qsTr("Press to hide the password") : + qsTr("Press to hide the number") : //: LABEL DESKTOP Screenreader text for the eye icon to change the password visibility - qsTr("Press to show the password")) + qsTr("Press to show the number")) contentItem: TintableIcon { source: eye.activated ? "qrc:///images/eye_visibility_on.svg" : "qrc:///images/eye_visibility_off.svg" diff --git a/src/ui/qml/modules/Global/internal/BaseConfirmationPopup.qml b/src/ui/qml/modules/Global/internal/BaseConfirmationPopup.qml index 435936bd6..6e90e76ba 100644 --- a/src/ui/qml/modules/Global/internal/BaseConfirmationPopup.qml +++ b/src/ui/qml/modules/Global/internal/BaseConfirmationPopup.qml @@ -95,6 +95,7 @@ Popup { id: mainText Layout.maximumWidth: Number.POSITIVE_INFINITY + Layout.preferredWidth: Math.ceil(hiddenText.implicitWidth) activeFocusOnTab: true horizontalAlignment: root.horizontalTextAlignment text: root.text @@ -103,6 +104,12 @@ Popup { FocusFrame { } + GText { + id: hiddenText + + text: root.text + visible: false + } } Item { id: customContent diff --git a/src/ui/qml/modules/MainView/+mobile/MainView.qml b/src/ui/qml/modules/MainView/+mobile/MainView.qml index f639e21bb..6ae12b396 100644 --- a/src/ui/qml/modules/MainView/+mobile/MainView.qml +++ b/src/ui/qml/modules/MainView/+mobile/MainView.qml @@ -130,7 +130,7 @@ FlickableSectionPage { preferredHighlightEnd: width / 2 + itemWidth / 2 snapMode: ListView.SnapOneItem - Component.onCompleted: { + onCountChanged: { updateTileLimits(); currentIndex = 1; } diff --git a/src/ui/qml/modules/Navigation/+mobile/internal/NavigationItem.qml b/src/ui/qml/modules/Navigation/+mobile/internal/NavigationItem.qml index 1527530f3..9dcbef66a 100644 --- a/src/ui/qml/modules/Navigation/+mobile/internal/NavigationItem.qml +++ b/src/ui/qml/modules/Navigation/+mobile/internal/NavigationItem.qml @@ -15,7 +15,7 @@ AbstractButton { property alias source: tabImage.source Accessible.name: text - Accessible.role: Accessible.Button + Accessible.role: checked ? Accessible.PageTab : Accessible.Button Layout.minimumWidth: tabImage.implicitWidth + leftPadding + rightPadding padding: Constants.text_spacing / 2 diff --git a/src/ui/qml/modules/Navigation/+mobile/internal/NavigationView.qml b/src/ui/qml/modules/Navigation/+mobile/internal/NavigationView.qml index 108770e6d..65f2d1a39 100644 --- a/src/ui/qml/modules/Navigation/+mobile/internal/NavigationView.qml +++ b/src/ui/qml/modules/Navigation/+mobile/internal/NavigationView.qml @@ -44,8 +44,26 @@ Control { delegate: NavigationItem { readonly property var mainViewSubViews: [UiModule.IDENTIFY, UiModule.SELF_AUTHENTICATION, UiModule.PINMANAGEMENT, UiModule.CHECK_ID_CARD, UiModule.SMART_EID] + //: ANDROID IOS LABEL Relative position of current navigation tab in navigation view. %1 is replaced with the current tab's index, %2 with the total count of tabs + readonly property string tabPositionA11y: qsTr("%1 of %2").arg(index + 1).arg(repeater.count) Accessible.ignored: root.Accessible.ignored + Accessible.name: { + //: ANDROID IOS LABEL + var a11yName = [text, qsTr("Tab"), tabPositionA11y]; + if (checked) { + if (Qt.platform.os === "ios") { + //: IOS Selected navigation tab. + a11yName.unshift(qsTr("Selection")); + //: IOS Name of a11y element of selected navigation tab. + a11yName.unshift(qsTr("Tab bar")); + } else { + //: ANDROID Currently selected navigation tab of navigation view. + a11yName.unshift(qsTr("Selected")); + } + } + return a11yName.join(". "); + } Layout.fillHeight: true Layout.fillWidth: true Layout.preferredWidth: repeater.maxItemWidth diff --git a/src/ui/qml/modules/ProgressView/+desktop/ProgressView.qml b/src/ui/qml/modules/ProgressView/+desktop/ProgressView.qml index 3c45acd3d..586708b99 100644 --- a/src/ui/qml/modules/ProgressView/+desktop/ProgressView.qml +++ b/src/ui/qml/modules/ProgressView/+desktop/ProgressView.qml @@ -11,14 +11,30 @@ import Governikus.View SectionPage { id: baseItem + property alias icon: statusIcon.source property alias progressBarVisible: progressBar.visible property alias progressText: progressText.text property alias progressValue: progressBar.value property alias subText: subText.text property alias subTextColor: subText.color property alias text: text.text + property alias tintColor: statusIcon.tintColor HourglassAnimation { + visible: !statusIcon.visible + + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: Constants.component_spacing + } + } + TintableIcon { + id: statusIcon + + sourceSize.height: Style.dimens.header_icon_size + visible: source.toString() !== "" + anchors { horizontalCenter: parent.horizontalCenter top: parent.top diff --git a/src/ui/qml/modules/ProgressView/+mobile/ProgressView.qml b/src/ui/qml/modules/ProgressView/+mobile/ProgressView.qml index 5e593565a..5bea7e894 100644 --- a/src/ui/qml/modules/ProgressView/+mobile/ProgressView.qml +++ b/src/ui/qml/modules/ProgressView/+mobile/ProgressView.qml @@ -18,7 +18,6 @@ FlickableSectionPage { property alias subText: subText.text property alias subTextColor: subText.color property alias text: text.text - property alias tintEnabled: statusIcon.tintEnabled HourglassAnimation { Layout.alignment: Qt.AlignHCenter @@ -29,6 +28,7 @@ FlickableSectionPage { Layout.alignment: Qt.AlignHCenter sourceSize.height: Style.dimens.header_icon_size + tintColor: Style.color.image visible: source.toString() !== "" } GText { diff --git a/src/ui/qml/modules/RemoteServiceView/+mobile/RemoteServiceView.qml b/src/ui/qml/modules/RemoteServiceView/+mobile/RemoteServiceView.qml index 06c80a9ad..2a88d306e 100644 --- a/src/ui/qml/modules/RemoteServiceView/+mobile/RemoteServiceView.qml +++ b/src/ui/qml/modules/RemoteServiceView/+mobile/RemoteServiceView.qml @@ -70,7 +70,7 @@ FlickableSectionPage { //: LABEL ANDROID IOS RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") : //: LABEL ANDROID IOS - RemoteServiceModel.running ? qsTr("Waiting for connection") : "" + RemoteServiceModel.running ? qsTr("Card reader ready") : "" ColumnLayout { spacing: Constants.component_spacing @@ -132,16 +132,11 @@ FlickableSectionPage { when: RemoteServiceModel.running && knownDeviceList.count > 0 PropertyChanges { + infoText.text: "%1\n\n%2" //: INFO ANDROID IOS - infoText.text: qsTr("Paired devices may use this Smartphone as a card reader now.") - } - }, - State { - when: RemoteServiceModel.running - - PropertyChanges { + .arg(qsTr("Paired devices may use this Smartphone as a card reader now.")) //: INFO ANDROID IOS - infoText.text: qsTr("Waiting for connection from a paired device...") + .arg(qsTr("To do this, start a process on a paired device.")) } } ] @@ -211,17 +206,15 @@ FlickableSectionPage { title: remoteDeviceName } } - GButton { + GLink { //: LABEL ANDROID IOS Accessible.name: qsTr("Start pairing of a new device") Layout.alignment: Qt.AlignLeft Layout.topMargin: knownDevices.spacing - background: null icon.source: "qrc:///images/material_add.svg" padding: 0 //: LABEL ANDROID IOS text: qsTr("Pair new device") - textStyle: Style.text.link tintIcon: true visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running @@ -297,7 +290,7 @@ FlickableSectionPage { PropertyChanges { //: LABEL ANDROID IOS - pairConnectButton.text: qsTr("Allow connection") + pairConnectButton.text: qsTr("Activate card reader") pairConnectButton.onClicked: RemoteServiceModel.setRunning(true) } @@ -320,6 +313,16 @@ FlickableSectionPage { pairConnectButton.text: qsTr("Cancel pairing") pairConnectButton.visible: true + pairConnectButton.onClicked: RemoteServiceModel.setRunning(false, false) + } + }, + State { + when: RemoteServiceModel.running + + PropertyChanges { + //: LABEL ANDROID IOS + pairConnectButton.text: qsTr("Stop card reader") + pairConnectButton.onClicked: RemoteServiceModel.setRunning(false, false) } } diff --git a/src/ui/qml/modules/ResultView/+desktop/ResultView.qml b/src/ui/qml/modules/ResultView/+desktop/ResultView.qml index b3ef63753..7d4ef9eec 100644 --- a/src/ui/qml/modules/ResultView/+desktop/ResultView.qml +++ b/src/ui/qml/modules/ResultView/+desktop/ResultView.qml @@ -33,6 +33,10 @@ FlickableSectionPage { signal emailButtonPressed signal hintClicked + function confirm() { + button.clicked(); + } + spacing: Constants.pane_spacing Keys.onEnterPressed: button.clicked() diff --git a/src/ui/qml/modules/ResultView/+mobile/ResultErrorView.qml b/src/ui/qml/modules/ResultView/+mobile/ResultErrorView.qml index 1cc30e7dc..86f5b4082 100644 --- a/src/ui/qml/modules/ResultView/+mobile/ResultErrorView.qml +++ b/src/ui/qml/modules/ResultView/+mobile/ResultErrorView.qml @@ -30,8 +30,10 @@ ResultView { Layout.fillWidth: true Layout.leftMargin: -Constants.pane_padding * 2 Layout.rightMargin: -Constants.pane_padding * 2 + arrowToLeft: true horizontalMargin: Constants.pane_padding * 2 - title: qsTr("Details") + //: LABEL ANDROID IOS + title: qsTr("Show Details") visible: hasErrorDetails GText { diff --git a/src/ui/qml/modules/ResultView/+mobile/ResultView.qml b/src/ui/qml/modules/ResultView/+mobile/ResultView.qml index 27d868ac9..0e1d7775d 100644 --- a/src/ui/qml/modules/ResultView/+mobile/ResultView.qml +++ b/src/ui/qml/modules/ResultView/+mobile/ResultView.qml @@ -27,6 +27,10 @@ FlickableSectionPage { signal continueClicked signal hintClicked + function confirm() { + buttonContinue.clicked(); + } + spacing: Constants.component_spacing navigationAction: NavigationAction { diff --git a/src/ui/qml/modules/SettingsView/+desktop/internal/GeneralSettings.qml b/src/ui/qml/modules/SettingsView/+desktop/internal/GeneralSettings.qml index 3590a6d0a..4bf67d289 100644 --- a/src/ui/qml/modules/SettingsView/+desktop/internal/GeneralSettings.qml +++ b/src/ui/qml/modules/SettingsView/+desktop/internal/GeneralSettings.qml @@ -36,6 +36,7 @@ ColumnLayout { //: LABEL DESKTOP description: qsTr("Toggling will restart the %1").arg(Qt.application.name) + drawBottomCorners: true //: LABEL DESKTOP text: qsTr("Use the system font") @@ -46,14 +47,40 @@ ColumnLayout { } } } + } + GPane { + Layout.fillWidth: true + contentPadding: 0 + spacing: 0 + //: LABEL DESKTOP + title: qsTr("Accessibility") + GSwitch { Layout.fillWidth: true - checked: SettingsModel.useAnimations + checked: !SettingsModel.useAnimations + //: LABEL DESKTOP + text: qsTr("Use images instead of animations") + + onCheckedChanged: SettingsModel.useAnimations = !checked + } + GSwitch { + Layout.fillWidth: true + checked: SettingsModel.visualPrivacy + //: LABEL DESKTOP + text: qsTr("Hide key animations when entering PIN") + + onCheckedChanged: SettingsModel.visualPrivacy = checked + } + GSwitch { + Layout.fillWidth: true + checked: !SettingsModel.autoRedirectAfterAuthentication + //: LABEL DESKTOP + description: qsTr("After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds.") drawBottomCorners: true //: LABEL DESKTOP - text: qsTr("Play animations") + text: qsTr("Manual redirection back to the provider") - onCheckedChanged: SettingsModel.useAnimations = checked + onCheckedChanged: SettingsModel.autoRedirectAfterAuthentication = !checked } } GPane { diff --git a/src/ui/qml/modules/SettingsView/+desktop/internal/SecurityAndPrivacySettings.qml b/src/ui/qml/modules/SettingsView/+desktop/internal/SecurityAndPrivacySettings.qml index ab7636eb5..dbc6a4c94 100644 --- a/src/ui/qml/modules/SettingsView/+desktop/internal/SecurityAndPrivacySettings.qml +++ b/src/ui/qml/modules/SettingsView/+desktop/internal/SecurityAndPrivacySettings.qml @@ -17,28 +17,30 @@ ColumnLayout { contentPadding: 0 spacing: 0 //: LABEL DESKTOP - title: qsTr("Onscreen keypad") + title: qsTr("Numeric keypad") GSwitch { Layout.fillWidth: true checked: SettingsModel.shuffleScreenKeyboard + //: LABEL DESKTOP + description: qsTr("Makes it difficult for outsiders to detect PIN entry") //: LABEL DESKTOP - text: qsTr("Shuffle digits of on screen keypad") + text: qsTr("Shuffle keys") onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked } GSwitch { Layout.fillWidth: true - checked: !SettingsModel.visualPrivacy + checked: SettingsModel.visualPrivacy //: LABEL DESKTOP - description: qsTr("Visually highlight key presses on screen keypad") + description: qsTr("Makes it difficult for outsiders to detect PIN entry") drawBottomCorners: true //: LABEL DESKTOP - text: qsTr("Button animation") + text: qsTr("Hide key animations") - onCheckedChanged: SettingsModel.visualPrivacy = !checked + onCheckedChanged: SettingsModel.visualPrivacy = checked } } GPane { @@ -55,7 +57,7 @@ ColumnLayout { enabled: !SettingsModel.autoUpdateCheckSetByAdmin //: LABEL DESKTOP - text: qsTr("Check at program start") + text: qsTr("Check for updates at program start") onCheckedChanged: SettingsModel.autoUpdateCheck = checked } diff --git a/src/ui/qml/modules/SettingsView/+mobile/DarkModeButtons.qml b/src/ui/qml/modules/SettingsView/+mobile/DarkModeButtons.qml index 26066a69d..e94ef2ee0 100644 --- a/src/ui/qml/modules/SettingsView/+mobile/DarkModeButtons.qml +++ b/src/ui/qml/modules/SettingsView/+mobile/DarkModeButtons.qml @@ -14,6 +14,7 @@ ColumnLayout { readonly property string selectedText: checkedButton.title signal buttonClicked + signal receivedFocus(var pItem) function onAppearanceButtonClicked(mode) { if (SettingsModel.userDarkMode === mode) @@ -43,6 +44,8 @@ ColumnLayout { title: qsTr("System") onClicked: root.onAppearanceButtonClicked(mode) + onFocusChanged: if (focus) + root.receivedFocus(this) } GCollapsibleSubButton { id: dark @@ -58,6 +61,8 @@ ColumnLayout { title: qsTr("Dark") onClicked: root.onAppearanceButtonClicked(mode) + onFocusChanged: if (focus) + root.receivedFocus(this) } GCollapsibleSubButton { id: light @@ -73,5 +78,7 @@ ColumnLayout { title: qsTr("Light") onClicked: root.onAppearanceButtonClicked(mode) + onFocusChanged: if (focus) + root.receivedFocus(this) } } diff --git a/src/ui/qml/modules/SettingsView/+mobile/SettingsView.qml b/src/ui/qml/modules/SettingsView/+mobile/SettingsView.qml index d8dd1481b..8db507626 100644 --- a/src/ui/qml/modules/SettingsView/+mobile/SettingsView.qml +++ b/src/ui/qml/modules/SettingsView/+mobile/SettingsView.qml @@ -106,8 +106,7 @@ FlickableSectionPage { width: parent.width onButtonClicked: appearanceCollapsible.expanded = false - onFocusChanged: if (focus) - baseItem.positionViewAtItem(this) + onReceivedFocus: pItem => baseItem.positionViewAtItem(pItem) } } GSeparator { @@ -119,7 +118,7 @@ FlickableSectionPage { GSwitch { //: LABEL ANDROID IOS description: qsTr("Toggling will restart the %1").arg(Qt.application.name) - + drawBottomCorners: true //: LABEL ANDROID IOS text: qsTr("Use system font") width: parent.width @@ -136,6 +135,24 @@ FlickableSectionPage { onFocusChanged: if (focus) baseItem.positionViewAtItem(this) } + } + GOptionsContainer { + Layout.fillWidth: true + //: LABEL ANDROID IOS + title: qsTr("Accessibility") + + GSwitch { + checked: !SettingsModel.useAnimations + drawTopCorners: true + + //: LABEL ANDROID IOS + text: qsTr("Use images instead of animations") + width: parent.width + + onCheckedChanged: SettingsModel.useAnimations = !checked + onFocusChanged: if (focus) + baseItem.positionViewAtItem(this) + } GSeparator { anchors.left: parent.left anchors.leftMargin: Constants.component_spacing @@ -143,14 +160,31 @@ FlickableSectionPage { anchors.rightMargin: Constants.component_spacing } GSwitch { - checked: SettingsModel.useAnimations - drawBottomCorners: true + checked: SettingsModel.visualPrivacy + //: LABEL ANDROID IOS + text: qsTr("Hide key animations when entering PIN") + width: parent.width + onCheckedChanged: SettingsModel.visualPrivacy = checked + onFocusChanged: if (focus) + baseItem.positionViewAtItem(this) + } + GSeparator { + anchors.left: parent.left + anchors.leftMargin: Constants.component_spacing + anchors.right: parent.right + anchors.rightMargin: Constants.component_spacing + } + GSwitch { + checked: !SettingsModel.autoRedirectAfterAuthentication + //: LABEL ANDROID IOS + description: qsTr("After identification, you will only be redirected back to the provider after confirmation. Otherwise, you will be redirected automatically after a few seconds.") + drawBottomCorners: true //: LABEL ANDROID IOS - text: qsTr("Play animations") + text: qsTr("Manual redirection back to the provider") width: parent.width - onCheckedChanged: SettingsModel.useAnimations = checked + onCheckedChanged: SettingsModel.autoRedirectAfterAuthentication = !checked onFocusChanged: if (focus) baseItem.positionViewAtItem(this) } @@ -256,14 +290,16 @@ FlickableSectionPage { GOptionsContainer { Layout.fillWidth: true //: LABEL ANDROID IOS - title: qsTr("Security and privacy") + title: qsTr("Numeric keypad") GSwitch { checked: SettingsModel.shuffleScreenKeyboard + //: LABEL ANDROID IOS + description: qsTr("Makes it difficult for outsiders to detect PIN entry") drawTopCorners: true //: LABEL ANDROID IOS - text: qsTr("Randomize the order of the on screen keypad buttons") + text: qsTr("Shuffle keys") width: parent.width onCheckedChanged: SettingsModel.shuffleScreenKeyboard = checked @@ -277,16 +313,16 @@ FlickableSectionPage { anchors.rightMargin: Constants.component_spacing } GSwitch { - checked: !SettingsModel.visualPrivacy + checked: SettingsModel.visualPrivacy //: LABEL ANDROID IOS - description: qsTr("Visually highlight key presses on screen keypad") + description: qsTr("Makes it difficult for outsiders to detect PIN entry") drawBottomCorners: true //: LABEL ANDROID IOS - text: qsTr("Keypad animations") + text: qsTr("Hide key animations") width: parent.width - onCheckedChanged: SettingsModel.visualPrivacy = !checked + onCheckedChanged: SettingsModel.visualPrivacy = checked onFocusChanged: if (focus) baseItem.positionViewAtItem(this) } diff --git a/src/ui/qml/modules/Style/+desktop/internal/PlatformColorsContrast.qml b/src/ui/qml/modules/Style/+desktop/internal/PlatformColorsContrast.qml index eda250f82..7c6a025a0 100644 --- a/src/ui/qml/modules/Style/+desktop/internal/PlatformColorsContrast.qml +++ b/src/ui/qml/modules/Style/+desktop/internal/PlatformColorsContrast.qml @@ -29,6 +29,10 @@ Colors { background.pressed: textNormal.basic content.basic: textNormal.basic } + controlOptional: DefaultControlColors { + content.basic: palette.buttonText + content.checked: textNormal.basic + } controlRadiobutton: DefaultControlColors { background.pressed: textNormal.basic content.basic: textNormal.basic diff --git a/src/ui/qml/modules/Style/internal/Colors.qml b/src/ui/qml/modules/Style/internal/Colors.qml index 5b1011d72..5540e67bd 100644 --- a/src/ui/qml/modules/Style/internal/Colors.qml +++ b/src/ui/qml/modules/Style/internal/Colors.qml @@ -10,6 +10,7 @@ QtObject { readonly property color card_smart: "#327509" required property ControlComponents control required property ControlComponents controlCheckbox + required property ControlComponents controlOptional required property ControlComponents controlRadiobutton required property ControlComponents controlScrollbar required property ControlComponents controlSwitch diff --git a/src/ui/qml/modules/Style/internal/ColorsDark.qml b/src/ui/qml/modules/Style/internal/ColorsDark.qml index 93ce25041..e829c6324 100644 --- a/src/ui/qml/modules/Style/internal/ColorsDark.qml +++ b/src/ui/qml/modules/Style/internal/ColorsDark.qml @@ -29,6 +29,14 @@ Colors { content.checked: "#0098eb" content.pressed: "#ffffff" } + controlOptional: DefaultControlColors { + background.basic: transparent + background.pressed: "#0098eb" + border.basic: "#0098eb" + border.pressed: "#0098eb" + content.basic: "#0098eb" + content.pressed: "#ffffff" + } controlRadiobutton: DefaultControlColors { background.pressed: "#0098eb" content.basic: "#ffffff" diff --git a/src/ui/qml/modules/Style/internal/ColorsLight.qml b/src/ui/qml/modules/Style/internal/ColorsLight.qml index f4fa62a2d..1b67fb60c 100644 --- a/src/ui/qml/modules/Style/internal/ColorsLight.qml +++ b/src/ui/qml/modules/Style/internal/ColorsLight.qml @@ -27,6 +27,14 @@ Colors { border.pressed: "#80cdec" content.pressed: "#ffffff" } + controlOptional: DefaultControlColors { + background.basic: transparent + background.pressed: "#0077b6" + border.basic: "#0077b6" + border.pressed: "#0077b6" + content.basic: "#0077b6" + content.pressed: "#ffffff" + } controlRadiobutton: DefaultControlColors { background.pressed: "#0077b6" } diff --git a/src/ui/qml/modules/TechnologyInfo/+mobile/TechnologySwitch.qml b/src/ui/qml/modules/TechnologyInfo/+mobile/TechnologySwitch.qml index 95657b6c3..0760a5373 100644 --- a/src/ui/qml/modules/TechnologyInfo/+mobile/TechnologySwitch.qml +++ b/src/ui/qml/modules/TechnologyInfo/+mobile/TechnologySwitch.qml @@ -57,6 +57,7 @@ GFlickableColumnLayout { checkable: !checked checked: selectedTechnology === ReaderManagerPluginType.NFC icon.source: "qrc:///images/mobile/icon_nfc.svg" + style: Style.color.controlOptional //: LABEL ANDROID IOS text: qsTr("NFC") tintIcon: true @@ -71,6 +72,7 @@ GFlickableColumnLayout { checkable: !checked checked: selectedTechnology === ReaderManagerPluginType.SMART icon.source: "qrc:///images/mobile/icon_smart.svg" + style: Style.color.controlOptional //: LABEL ANDROID IOS text: qsTr("SMART") tintIcon: true @@ -87,6 +89,7 @@ GFlickableColumnLayout { checkable: !checked checked: selectedTechnology === ReaderManagerPluginType.REMOTE_IFD icon.source: "qrc:///images/mobile/icon_remote.svg" + style: Style.color.controlOptional //: LABEL ANDROID IOS text: qsTr("WiFi") tintIcon: true @@ -103,6 +106,7 @@ GFlickableColumnLayout { checkable: !checked checked: selectedTechnology === ReaderManagerPluginType.SIMULATOR icon.source: "qrc:///images/mobile/icon_simulator.svg" + style: Style.color.controlOptional //: LABEL ANDROID IOS text: qsTr("SIM") tintIcon: true diff --git a/src/ui/qml/modules/TitleBar/+desktop/Notifications.qml b/src/ui/qml/modules/TitleBar/+desktop/Notifications.qml index 3b5096bdf..8560199b9 100644 --- a/src/ui/qml/modules/TitleBar/+desktop/Notifications.qml +++ b/src/ui/qml/modules/TitleBar/+desktop/Notifications.qml @@ -20,6 +20,7 @@ Item { return Style.color.textNormal.basic; } readonly property bool unreadMessages: d.unreadMsg + readonly property bool visibleToUser: d.fadeIn && !fadeOutTimer.running signal newNotification @@ -76,7 +77,7 @@ Item { GListView { id: logEntryList - activeFocusOnTab: d.fadeIn && !fadeOutTimer.running + activeFocusOnTab: baseItem.visibleToUser anchors.fill: parent bottomMargin: Constants.pane_padding clip: true diff --git a/src/ui/qml/modules/TitleBar/+desktop/TitleBar.qml b/src/ui/qml/modules/TitleBar/+desktop/TitleBar.qml index bdc2b3475..a908b0f2d 100644 --- a/src/ui/qml/modules/TitleBar/+desktop/TitleBar.qml +++ b/src/ui/qml/modules/TitleBar/+desktop/TitleBar.qml @@ -100,7 +100,14 @@ Rectangle { TitleBarButton { id: notifyButton - Accessible.description: qsTr("Show in-app notifications of %1").arg(Qt.application.name) + Accessible.description: checked ? + //: LABEL DESKTOP + qsTr("Hide in-app notifications of %1").arg(Qt.application.name) : + //: LABEL DESKTOP + qsTr("Show in-app notifications of %1").arg(Qt.application.name) + Accessible.role: Accessible.CheckBox + checkable: true + checked: notifications.visibleToUser height: rightTitleBarActions.height iconColor: notifications.iconColor source: notifications.unreadMessages ? "qrc:///images/desktop/notifications_on.svg" : "qrc:///images/desktop/notifications_off.svg" diff --git a/src/ui/qml/modules/Workflow/+desktop/GeneralWorkflow.qml b/src/ui/qml/modules/Workflow/+desktop/GeneralWorkflow.qml index 00ab2b259..116131def 100644 --- a/src/ui/qml/modules/Workflow/+desktop/GeneralWorkflow.qml +++ b/src/ui/qml/modules/Workflow/+desktop/GeneralWorkflow.qml @@ -164,7 +164,7 @@ SectionPage { switch (waitingFor) { case Workflow.WaitingFor.Reader: //: INFO DESKTOP AA2 is waiting for the card reader or the ID card. - return d.foundSelectedReader ? requestCardText : qsTr("No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and available. Open the reader settings to configure readers and get more information about supported readers."); + return d.foundSelectedReader ? requestCardText : qsTr("No card reader detected. Please make sure that an USB card reader is connected or a smartphone as card reader is paired and ready. Open the reader settings to configure readers and get more information about supported readers."); case Workflow.WaitingFor.Password: //: INFO DESKTOP The card reader is a comfort reader with its own display, the user is requested to pay attention to that display (instead of the AA2). return qsTr("Please observe the display of your card reader."); diff --git a/src/workflows/base/context/AuthContext.cpp b/src/workflows/base/context/AuthContext.cpp index 4e31d79fa..bc628b7dd 100644 --- a/src/workflows/base/context/AuthContext.cpp +++ b/src/workflows/base/context/AuthContext.cpp @@ -17,6 +17,7 @@ AuthContext::AuthContext(const Action pAction, bool pActivateUi, const QUrl& pAc : WorkflowContext(pAction, pActivateUi) , mTcTokenNotFound(true) , mErrorReportedToServer(false) + , mReceivedBrowserSendFailed(false) , mSkipMobileRedirect(false) , mShowChangePinView(false) , mActivationUrl(pActivationUrl) @@ -53,6 +54,16 @@ AuthContext::AuthContext(bool pActivateUi, const QUrl& pActivationUrl, const Bro } +void AuthContext::setReceivedBrowserSendFailed(bool pReceivedBrowserSendFailed) +{ + if (mReceivedBrowserSendFailed != pReceivedBrowserSendFailed) + { + mReceivedBrowserSendFailed = pReceivedBrowserSendFailed; + Q_EMIT fireResultChanged(); + } +} + + void AuthContext::requestChangePinView() { if (mShowChangePinView) diff --git a/src/workflows/base/context/AuthContext.h b/src/workflows/base/context/AuthContext.h index 69f906d74..882f589ba 100644 --- a/src/workflows/base/context/AuthContext.h +++ b/src/workflows/base/context/AuthContext.h @@ -59,6 +59,7 @@ class AuthContext private: bool mTcTokenNotFound; bool mErrorReportedToServer; + bool mReceivedBrowserSendFailed; bool mSkipMobileRedirect; bool mShowChangePinView; @@ -110,6 +111,15 @@ class AuthContext } + [[nodiscard]] bool isReceivedBrowserSendFailed() const + { + return mReceivedBrowserSendFailed; + } + + + void setReceivedBrowserSendFailed(bool pReceivedBrowserSendFailed); + + void setErrorReportedToServer(bool pErrorReportedToServer) { mErrorReportedToServer = pErrorReportedToServer; @@ -139,7 +149,6 @@ class AuthContext [[nodiscard]] QList getAcceptedEidTypes() const override { - if (isCanAllowedMode() || !mDIDAuthenticateEAC1) { return {AcceptedEidType::CARD_CERTIFIED}; diff --git a/src/workflows/base/paos/ElementDetector.cpp b/src/workflows/base/paos/ElementDetector.cpp index e2ba608b6..1baf62eee 100644 --- a/src/workflows/base/paos/ElementDetector.cpp +++ b/src/workflows/base/paos/ElementDetector.cpp @@ -41,7 +41,7 @@ void ElementDetector::detectStartElements(const QStringList& pStartElementNames) bool ElementDetector::handleStartElements(const QStringList& pStartElementNames) { - const QStringView name = mReader.name(); + const QString name = mReader.name().toString(); if (pStartElementNames.contains(name)) { QXmlStreamAttributes attributes = mReader.attributes(); diff --git a/src/workflows/base/states/StateRedirectBrowser.cpp b/src/workflows/base/states/StateRedirectBrowser.cpp index 3e48a2669..82831b4cb 100644 --- a/src/workflows/base/states/StateRedirectBrowser.cpp +++ b/src/workflows/base/states/StateRedirectBrowser.cpp @@ -69,6 +69,7 @@ void StateRedirectBrowser::run() if (const auto& error = handler(context); !error.isEmpty()) { qCritical() << "Cannot send page to caller:" << error; + context->setReceivedBrowserSendFailed(true); updateStatus({GlobalStatus::Code::Workflow_Browser_Transmission_Error, {GlobalStatus::ExternalInformation::ACTIVATION_ERROR, error} }); Q_EMIT fireAbort(FailureCode::Reason::Browser_Send_Failed); diff --git a/test/helper/common/TestAuthContext.cpp b/test/helper/common/TestAuthContext.cpp index 413a7dcd8..dc030b868 100644 --- a/test/helper/common/TestAuthContext.cpp +++ b/test/helper/common/TestAuthContext.cpp @@ -35,7 +35,7 @@ TestAuthContext::TestAuthContext(const QString& pFileName) } -const QSharedPointer TestAuthContext::getTerminalCvc(QSharedPointer pEac1) const +const QSharedPointer TestAuthContext::getTerminalCvc(QSharedPointer pEac1) { for (const auto& cvc : pEac1->getCvCertificates()) { diff --git a/test/helper/common/TestAuthContext.h b/test/helper/common/TestAuthContext.h index c85466f8c..88af78a5c 100644 --- a/test/helper/common/TestAuthContext.h +++ b/test/helper/common/TestAuthContext.h @@ -23,9 +23,9 @@ class TestAuthContext private: QList mAcceptedEidTypes; - const QSharedPointer getTerminalCvc(QSharedPointer pEac1) const; - public: + static const QSharedPointer getTerminalCvc(QSharedPointer pEac1); + explicit TestAuthContext(const QString& pFileName = QString()); ~TestAuthContext() override; diff --git a/test/qml/AuthView/test_EditRights.qml b/test/qml/AuthView/test_EditRights.qml new file mode 100644 index 000000000..21d0fbde8 --- /dev/null +++ b/test/qml/AuthView/test_EditRights.qml @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2024 Governikus GmbH & Co. KG, Germany + */ +import QtQuick +import QtTest + +TestCase { + id: testCase + + function createTestObject() { + return createTemporaryQmlObject(" + import Governikus.AuthView + + EditRights { + } + ", testCase); + } + function test_load() { + let testObject = createTestObject(); + verify(testObject, "Object loaded"); + let transactionText = findChild(testObject, "transactionText"); + verify(transactionText, "Child found"); + + // Text.StyledText will show HTML-Escaped text again + compare(transactionText.textFormat, Text.StyledText); + } + + name: "test_EditRights" + visible: true + when: windowShown +} diff --git a/test/qml/QmlTestRunner.cpp b/test/qml/QmlTestRunner.cpp index 9fd5cbcfe..32bfee836 100644 --- a/test/qml/QmlTestRunner.cpp +++ b/test/qml/QmlTestRunner.cpp @@ -65,6 +65,11 @@ class QmlTestRunner #else pEngine->rootContext()->setContextProperty(QStringLiteral("hasBindingLoop"), false); #endif +#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 2)) + pEngine->rootContext()->setContextProperty(QStringLiteral("hasPolishLoop"), true); +#else + pEngine->rootContext()->setContextProperty(QStringLiteral("hasPolishLoop"), false); +#endif connect(pEngine, &QQmlEngine::warnings, this, [](const QList& pWarnings){ bool fail = false; diff --git a/test/qml/View/+mobile/test_ContentArea.qml b/test/qml/View/+mobile/test_ContentArea.qml index 3bcf247a9..d5db7029a 100644 --- a/test/qml/View/+mobile/test_ContentArea.qml +++ b/test/qml/View/+mobile/test_ContentArea.qml @@ -11,6 +11,9 @@ TestCase { return createTemporaryQmlObject("import Governikus.View; ContentArea { width: 500 }", testCase); } function test_load() { + if (hasPolishLoop) { + skip("Skip test because of old Qt version with unfixed Polish Loops"); + } let testObject = createTestObject(); verify(testObject, "Object loaded"); } diff --git a/test/qt/card/simulator/test_SimulatorCard.cpp b/test/qt/card/simulator/test_SimulatorCard.cpp index d9324020d..787886604 100644 --- a/test/qt/card/simulator/test_SimulatorCard.cpp +++ b/test/qt/card/simulator/test_SimulatorCard.cpp @@ -160,7 +160,7 @@ class test_SimulatorCard } const QByteArray data(isAuthentication ? "Chat/CertificateDescription" : ""); - QCOMPARE(card.establishPaceChannel(PacePasswordId::PACE_PIN, 6, data, data, 60), output); + QCOMPARE(card.establishPaceChannel(PacePasswordId::PACE_PIN, 6, data, data), output); } diff --git a/test/qt/configuration/test_ReaderConfiguration.cpp b/test/qt/configuration/test_ReaderConfiguration.cpp index 8cf61ec20..6c9ae1572 100644 --- a/test/qt/configuration/test_ReaderConfiguration.cpp +++ b/test/qt/configuration/test_ReaderConfiguration.cpp @@ -112,7 +112,7 @@ class test_ReaderConfiguration QTest::newRow("REINER SCT cyberJack RFID komfort FON") << UsbId(0x0C4B, 0x2007) << "REINER SCT cyberJack RFID komfort FON" << "REINER SCT cyberJack RFID komfort FON" << "img_Reiner_SCT_cyberjack_RFID_komfort" << "^REINER SCT cyberJack RFID komfort FON"; QTest::newRow("REINER SCT cyberJack RFID standard") << UsbId(0x0C4B, 0x0500) << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard" << "img_Reiner_SCT_cyberjack_RFID_standard" << "REINER SCT cyberJack RFID standard"; QTest::newRow("REINER SCT cyberJack RFID basis") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis" << "img_Reiner_SCT_cyberjack_RFID_basis" << "REINER SCT cyberJack RFID basis"; - QTest::newRow("REINER SCT cyberJack wave") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave" << "img_cyberjack_wave" << "REINER SCT cyberJack wave( USB)?( \\d{1,1})?$"; + QTest::newRow("REINER SCT cyberJack wave") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave" << "img_cyberjack_wave" << "REINER SCT cyberJack wave"; QTest::newRow("KOBIL IDToken") << UsbId(0x0D46, 0x301D) << "KOBIL Systems IDToken" << "KOBIL IDToken" << "img_KOBIL_ID_Token" << "^KOBIL (Systems )?IDToken"; @@ -187,21 +187,21 @@ class test_ReaderConfiguration QTest::newRow("Simulator") << UsbId(0x0000, 0x0002) << "Simulator" << "Simulator"; QTest::newRow("REINER SCT cyberJack RFID komfort-windows-10-11") << UsbId(0x0C4B, 0x0501) << "REINER SCT cyberJack RFID komfort USB 1" << "REINER SCT cyberJack RFID komfort"; - QTest::newRow("REINER SCT cyberJack RFID komfort-macosx-12-14") << UsbId(0x0C4B, 0x0501) << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; + QTest::newRow("REINER SCT cyberJack RFID komfort-macosx-12-15") << UsbId(0x0C4B, 0x0501) << "REINER SCT cyberJack RFID komfort" << "REINER SCT cyberJack RFID komfort"; QTest::newRow("REINER SCT cyberJack RFID komfort-FON-windows-7-10") << UsbId(0x0C4B, 0x2007) << "REINER SCT cyberJack RFID komfort FON USB 52" << "REINER SCT cyberJack RFID komfort FON"; QTest::newRow("REINER SCT cyberJack RFID komfort-FON-macosx-10.13-11.0") << UsbId(0x0C4B, 0x2007) << "REINER SCT cyberJack RFID komfort FON" << "REINER SCT cyberJack RFID komfort FON"; QTest::newRow("REINER SCT cyberJack RFID standard-windows-10-11") << UsbId(0x0C4B, 0x0500) << "REINER SCT cyberJack RFID standard USB 1" << "REINER SCT cyberJack RFID standard"; - QTest::newRow("REINER SCT cyberJack RFID standard-macosx-12-14") << UsbId(0x0C4B, 0x0500) << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; + QTest::newRow("REINER SCT cyberJack RFID standard-macosx-12-15") << UsbId(0x0C4B, 0x0500) << "REINER SCT cyberJack RFID standard" << "REINER SCT cyberJack RFID standard"; QTest::newRow("REINER SCT cyberJack RFID basis-windows-10-11") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis 0" << "REINER SCT cyberJack RFID basis"; - QTest::newRow("REINER SCT cyberJack RFID basis-macosx-11-13") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; + QTest::newRow("REINER SCT cyberJack RFID basis-macosx-11-15") << UsbId(0x0C4B, 0x9102) << "REINER SCT cyberJack RFID basis" << "REINER SCT cyberJack RFID basis"; QTest::newRow("REINER SCT cyberJack wave-windows-10-11-1") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave 0" << "REINER SCT cyberJack wave"; QTest::newRow("REINER SCT cyberJack wave-windows-10-11-1") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave 1" << "REINER SCT cyberJack wave"; QTest::newRow("REINER SCT cyberJack wave-windows-10-11-2") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave USB 1" << "REINER SCT cyberJack wave"; - QTest::newRow("REINER SCT cyberJack wave-macosx-12-14") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; + QTest::newRow("REINER SCT cyberJack wave-macosx-12-15") << UsbId(0x0C4B, 0x0505) << "REINER SCT cyberJack wave" << "REINER SCT cyberJack wave"; QTest::newRow("KOBIL IDToken-windows-10-11-1") << UsbId(0x0D46, 0x301D) << "KOBIL IDToken 0" << "KOBIL IDToken"; QTest::newRow("KOBIL IDToken-windows-10-11-2") << UsbId(0x0D46, 0x301D) << "KOBIL IDToken 1" << "KOBIL IDToken"; diff --git a/test/qt/settings/test_GeneralSettings.cpp b/test/qt/settings/test_GeneralSettings.cpp index 65cd07289..6be5162a2 100644 --- a/test/qt/settings/test_GeneralSettings.cpp +++ b/test/qt/settings/test_GeneralSettings.cpp @@ -73,6 +73,30 @@ class test_GeneralSettings } + void testAutoRedirectAfterAuthentication() + { + auto& settings = Env::getSingleton()->getGeneralSettings(); + QSignalSpy spy(&settings, &GeneralSettings::fireSettingsChanged); + QCOMPARE(settings.isAutoRedirectAfterAuthentication(), true); + + settings.setAutoRedirectAfterAuthentication(false); + QCOMPARE(spy.size(), 1); + QCOMPARE(settings.isAutoRedirectAfterAuthentication(), false); + + settings.setAutoRedirectAfterAuthentication(false); + QCOMPARE(spy.size(), 1); + QCOMPARE(settings.isAutoRedirectAfterAuthentication(), false); + + settings.setAutoRedirectAfterAuthentication(true); + QCOMPARE(spy.size(), 2); + QCOMPARE(settings.isAutoRedirectAfterAuthentication(), true); + + settings.setAutoRedirectAfterAuthentication(true); + QCOMPARE(spy.size(), 2); + QCOMPARE(settings.isAutoRedirectAfterAuthentication(), true); + } + + void testAutoCheck() { auto& settings = Env::getSingleton()->getGeneralSettings(); diff --git a/test/qt/ui/qml/test_AuthModel.cpp b/test/qt/ui/qml/test_AuthModel.cpp index 070371f8d..4840c19a5 100644 --- a/test/qt/ui/qml/test_AuthModel.cpp +++ b/test/qt/ui/qml/test_AuthModel.cpp @@ -9,6 +9,7 @@ #include "AuthModel.h" #include "context/AuthContext.h" +#include "context/SelfAuthContext.h" #include "paos/retrieve/DidAuthenticateEac1Parser.h" @@ -30,7 +31,7 @@ class test_AuthModel private Q_SLOTS: void test_ResetContext() { - const auto model = Env::getSingleton(); + auto* const model = Env::getSingleton(); const QSharedPointer context(new AuthContext()); QSignalSpy spyWorkflowStarted(model, &WorkflowModel::fireWorkflowStarted); @@ -59,50 +60,187 @@ class test_AuthModel } + void test_progressValue() + { + auto* const model = Env::getSingleton(); + + model->resetAuthContext(nullptr); + QCOMPARE(model->getProgressValue(), 0); + + const QSharedPointer context(new AuthContext()); + context->setProgress(50, QString()); + model->resetAuthContext(context); + QCOMPARE(model->getProgressValue(), 50); + } + + + void test_progressMessage() + { + auto* const model = Env::getSingleton(); + + model->resetAuthContext(nullptr); + QCOMPARE(model->getProgressMessage(), QString()); + + const QSharedPointer context(new AuthContext()); + context->setProgress(0, QStringLiteral("TEST")); + model->resetAuthContext(context); + QCOMPARE(model->getProgressMessage(), QStringLiteral("TEST")); + } + + + void test_showChangePinView() + { + auto* const model = Env::getSingleton(); + + model->resetAuthContext(nullptr); + QCOMPARE(model->getShowChangePinView(), false); + + const QSharedPointer context(new AuthContext()); + context->requestChangePinView(); + model->resetAuthContext(context); + QCOMPARE(model->getShowChangePinView(), true); + } + + void test_resultHeader_data() { + QTest::addColumn>("context"); QTest::addColumn("statusCode"); QTest::addColumn("resultHeader"); - QTest::addRow("Any error") << GlobalStatus::Code::Card_Communication_Error << "Authentication failed"; - QTest::addRow("No error") << GlobalStatus::Code::No_Error << "Authentication successful"; - QTest::addRow("Browser_Transmission_Error") << GlobalStatus::Code::Workflow_Browser_Transmission_Error << "Redirect failed"; + QTest::addRow("No context") << QSharedPointer() << GlobalStatus::Code::No_Error << ""; + QTest::addRow("Any error") << QSharedPointer::create() << GlobalStatus::Code::Card_Communication_Error << "Authentication failed"; + QTest::addRow("No error") << QSharedPointer::create() << GlobalStatus::Code::No_Error << "Authentication successful"; + QTest::addRow("Browser_Transmission_Error") << QSharedPointer::create() << GlobalStatus::Code::Workflow_Browser_Transmission_Error << "Redirect failed"; } void test_resultHeader() { + QFETCH(QSharedPointer, context); QFETCH(GlobalStatus::Code, statusCode); QFETCH(QString, resultHeader); - const auto model = Env::getSingleton(); - const QSharedPointer context(new AuthContext()); - context->setStatus(GlobalStatus(statusCode)); + auto* const model = Env::getSingleton(); + if (context) + { + context->setStatus(GlobalStatus(statusCode)); + } model->resetAuthContext(context); QCOMPARE(model->getResultHeader(), resultHeader); } + void test_getErrorHeader() + { + auto* const model = Env::getSingleton(); + + model->resetAuthContext(nullptr); + QCOMPARE(model->getErrorHeader(), QString()); + + const QSharedPointer context(new AuthContext()); + model->resetAuthContext(context); + QCOMPARE(model->getErrorHeader(), QString()); + + context->setTcTokenUrl(QUrl("https://www.governikus.de/tcToken"_L1)); + QCOMPARE(model->getErrorHeader(), QStringLiteral("https://www.governikus.de")); + } + + + void test_getErrorText_data() + { + QTest::addColumn>("context"); + QTest::addColumn("status"); + QTest::addColumn("result"); + + const GlobalStatus::ExternalInfoMap infoMap { + {GlobalStatus::ExternalInformation::LAST_URL, "https://www.governikus.de"_L1} + }; + + QTest::addRow("No context") << QSharedPointer(nullptr) << GlobalStatus(GlobalStatus::Code::No_Error) << ""; + QTest::addRow("No error") << QSharedPointer::create() << GlobalStatus(GlobalStatus::Code::No_Error) << "No error occurred."; + + QTest::addRow("Any error - No info - No reason") << QSharedPointer::create() << GlobalStatus(GlobalStatus::Code::Card_Communication_Error) << "An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again."; + QTest::addRow("Any error - Info - No reason") << QSharedPointer::create() << GlobalStatus(GlobalStatus::Code::Card_Communication_Error, infoMap) << "An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again.
(https://www.governikus.de)"; + + const auto context = QSharedPointer::create(); + context->setFailureCode(FailureCode::Reason::Card_Removed); + QTest::addRow("Any error - No info - Reason") << context << GlobalStatus(GlobalStatus::Code::Card_Communication_Error) << "An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again.

Reason:
Card_Removed"; + QTest::addRow("Any error - Info - Reason") << context << GlobalStatus(GlobalStatus::Code::Card_Communication_Error, infoMap) << "An error occurred while communicating with the ID card. Please make sure that your ID card is placed correctly on the card reader and try again.
(https://www.governikus.de)

Reason:
Card_Removed"; + } + + + void test_getErrorText() + { + QFETCH(QSharedPointer, context); + QFETCH(GlobalStatus, status); + QFETCH(QString, result); + + auto* const model = Env::getSingleton(); + if (context) + { + context->setStatus(status); + } + model->resetAuthContext(context); + + QCOMPARE(model->getErrorText(), result); + } + + + void test_getStatusCodeString_data() + { + QTest::addColumn>("context"); + QTest::addColumn("statusCode"); + QTest::addColumn("result"); + + QTest::addRow("No context") << QSharedPointer(nullptr) << GlobalStatus::Code::No_Error << "Unknown_Error"; + QTest::addRow("Any error") << QSharedPointer::create() << GlobalStatus::Code::Card_Communication_Error << "Card_Communication_Error"; + QTest::addRow("No error") << QSharedPointer::create() << GlobalStatus::Code::No_Error << "No_Error"; + } + + + void test_getStatusCodeString() + { + QFETCH(QSharedPointer, context); + QFETCH(GlobalStatus::Code, statusCode); + QFETCH(QString, result); + + auto* const model = Env::getSingleton(); + if (context) + { + context->setStatus(GlobalStatus(statusCode)); + } + model->resetAuthContext(context); + + QCOMPARE(model->getStatusCodeString(), result); + } + + void test_resultViewButtonIcon_data() { + QTest::addColumn>("context"); QTest::addColumn("statusCode"); QTest::addColumn("buttonIcon"); - QTest::addRow("Any error") << GlobalStatus::Code::Card_Communication_Error << ""; - QTest::addRow("No error") << GlobalStatus::Code::No_Error << ""; - QTest::addRow("Browser_Transmission_Error") << GlobalStatus::Code::Workflow_Browser_Transmission_Error << "qrc:///images/open_website.svg"; + QTest::addRow("No context") << QSharedPointer(nullptr) << GlobalStatus::Code::No_Error << ""; + QTest::addRow("Any error") << QSharedPointer::create() << GlobalStatus::Code::Card_Communication_Error << ""; + QTest::addRow("No error") << QSharedPointer::create() << GlobalStatus::Code::No_Error << ""; + QTest::addRow("Browser_Transmission_Error") << QSharedPointer::create() << GlobalStatus::Code::Workflow_Browser_Transmission_Error << "qrc:///images/open_website.svg"; } void test_resultViewButtonIcon() { + QFETCH(QSharedPointer, context); QFETCH(GlobalStatus::Code, statusCode); QFETCH(QString, buttonIcon); - const auto model = Env::getSingleton(); - const QSharedPointer context(new AuthContext()); - context->setStatus(GlobalStatus(statusCode)); + auto* const model = Env::getSingleton(); + if (context) + { + context->setStatus(GlobalStatus(statusCode)); + } model->resetAuthContext(context); QCOMPARE(model->getResultViewButtonIcon(), buttonIcon); @@ -111,23 +249,21 @@ class test_AuthModel void test_resultViewButtonText_data() { - QTest::addColumn("statusCode"); + QTest::addColumn>("context"); QTest::addColumn("buttonText"); - QTest::addRow("Any error") << GlobalStatus::Code::Card_Communication_Error << "Back to start page"; - QTest::addRow("No error") << GlobalStatus::Code::No_Error << "Back to start page"; - QTest::addRow("Browser_Transmission_Error") << GlobalStatus::Code::Workflow_Browser_Transmission_Error << "Back to provider"; + QTest::addRow("No context") << QSharedPointer(nullptr) << ""; + QTest::addRow("Auth") << QSharedPointer(new AuthContext()) << "Return to provider"; + QTest::addRow("SelfAuth") << QSharedPointer(new SelfAuthContext()) << "Back to start page"; } void test_resultViewButtonText() { - QFETCH(GlobalStatus::Code, statusCode); + QFETCH(QSharedPointer, context); QFETCH(QString, buttonText); - const auto model = Env::getSingleton(); - const QSharedPointer context(new AuthContext()); - context->setStatus(GlobalStatus(statusCode)); + auto* const model = Env::getSingleton(); model->resetAuthContext(context); QCOMPARE(model->getResultViewButtonText(), buttonText); @@ -136,27 +272,36 @@ class test_AuthModel void test_resultViewButtonLink_data() { + QTest::addColumn>("context"); QTest::addColumn("statusCode"); + QTest::addColumn("receivedBrowserSendFail"); QTest::addColumn("refreshUrl"); QTest::addColumn("buttonLink"); const auto& refreshUrl = QUrl("https://dummy.url"_L1); - QTest::addRow("Any error") << GlobalStatus::Code::Card_Communication_Error << refreshUrl << QUrl(); - QTest::addRow("No error") << GlobalStatus::Code::No_Error << refreshUrl << QUrl(); - QTest::addRow("Browser_Transmission_Error") << GlobalStatus::Code::Workflow_Browser_Transmission_Error << refreshUrl << refreshUrl; + + QTest::addRow("No context") << QSharedPointer(nullptr) << GlobalStatus::Code::No_Error << false << refreshUrl << QUrl(); + QTest::addRow("Any error") << QSharedPointer::create() << GlobalStatus::Code::Card_Communication_Error << false << refreshUrl << QUrl(); + QTest::addRow("No error") << QSharedPointer::create() << GlobalStatus::Code::No_Error << false << refreshUrl << QUrl(); + QTest::addRow("Browser_Send_Failed") << QSharedPointer::create() << GlobalStatus::Code::No_Error << true << refreshUrl << refreshUrl; } void test_resultViewButtonLink() { + QFETCH(QSharedPointer, context); QFETCH(GlobalStatus::Code, statusCode); + QFETCH(bool, receivedBrowserSendFail); QFETCH(QUrl, refreshUrl); QFETCH(QUrl, buttonLink); - const auto model = Env::getSingleton(); - const QSharedPointer context(new AuthContext()); - context->setStatus(GlobalStatus(statusCode)); - context->setRefreshUrl(refreshUrl); + auto* const model = Env::getSingleton(); + if (context) + { + context->setReceivedBrowserSendFailed(receivedBrowserSendFail); + context->setStatus(GlobalStatus(statusCode)); + context->setRefreshUrl(refreshUrl); + } model->resetAuthContext(context); QCOMPARE(model->getResultViewButtonLink(), buttonLink); diff --git a/test/qt/ui/qml/test_SettingsModel.cpp b/test/qt/ui/qml/test_SettingsModel.cpp index ebe50545c..2a6285242 100644 --- a/test/qt/ui/qml/test_SettingsModel.cpp +++ b/test/qt/ui/qml/test_SettingsModel.cpp @@ -21,6 +21,32 @@ class test_SettingsModel Q_OBJECT private Q_SLOTS: + void testAutoRedirect() + { + auto* model = Env::getSingleton(); + QSignalSpy spy(model, &SettingsModel::fireAutoRedirectAfterAuthenticationChanged); + + QCOMPARE(spy.count(), 0); + QCOMPARE(model->isAutoRedirectAfterAuthentication(), true); + + model->setAutoRedirectAfterAuthentication(false); + QCOMPARE(spy.count(), 1); + QCOMPARE(model->isAutoRedirectAfterAuthentication(), false); + + model->setAutoRedirectAfterAuthentication(false); + QCOMPARE(spy.count(), 1); + QCOMPARE(model->isAutoRedirectAfterAuthentication(), false); + + model->setAutoRedirectAfterAuthentication(true); + QCOMPARE(spy.count(), 2); + QCOMPARE(model->isAutoRedirectAfterAuthentication(), true); + + model->setAutoRedirectAfterAuthentication(true); + QCOMPARE(spy.count(), 2); + QCOMPARE(model->isAutoRedirectAfterAuthentication(), true); + } + + void testAnimations() { const auto* model = Env::getSingleton(); diff --git a/test/qt/workflows/context/test_AuthContext.cpp b/test/qt/workflows/context/test_AuthContext.cpp index 11a8b4278..0b36a328f 100644 --- a/test/qt/workflows/context/test_AuthContext.cpp +++ b/test/qt/workflows/context/test_AuthContext.cpp @@ -10,7 +10,9 @@ #include "AppSettings.h" #include "TestAuthContext.h" +#include "TestFileHelper.h" #include "VolatileSettings.h" +#include "paos/retrieve/DidAuthenticateEac1Parser.h" #include #include @@ -26,6 +28,68 @@ class test_AuthContext Q_OBJECT private Q_SLOTS: + void test_ReceivedBrowserSendFailed() + { + AuthContext context; + QSignalSpy spy(&context, &AuthContext::fireResultChanged); + + QCOMPARE(context.isReceivedBrowserSendFailed(), false); + + context.setReceivedBrowserSendFailed(true); + QCOMPARE(spy.size(), 1); + QCOMPARE(context.isReceivedBrowserSendFailed(), true); + + context.setReceivedBrowserSendFailed(true); + QCOMPARE(spy.size(), 1); + QCOMPARE(context.isReceivedBrowserSendFailed(), true); + + context.setReceivedBrowserSendFailed(false); + QCOMPARE(spy.size(), 2); + QCOMPARE(context.isReceivedBrowserSendFailed(), false); + + context.setReceivedBrowserSendFailed(false); + QCOMPARE(spy.size(), 2); + QCOMPARE(context.isReceivedBrowserSendFailed(), false); + } + + + void test_requestChangePinView() + { + AuthContext context; + QSignalSpy spy(&context, &AuthContext::fireShowChangePinViewChanged); + + QCOMPARE(context.isSkipMobileRedirect(), false); + + context.requestChangePinView(); + QCOMPARE(spy.size(), 1); + QCOMPARE(context.isSkipMobileRedirect(), true); + + context.requestChangePinView(); + QCOMPARE(spy.size(), 1); + QCOMPARE(context.isSkipMobileRedirect(), true); + } + + + void test_acceptedEidTypes() + { + QByteArray content = TestFileHelper::readFile(":/paos/DIDAuthenticateEAC1_template.xml"_L1); + content = content.replace(QByteArray(""), QByteArray("SECertified")); + QSharedPointer eac1(static_cast(DidAuthenticateEac1Parser().parse(content))); + + AuthContext context; + QCOMPARE(context.getAcceptedEidTypes(), {AcceptedEidType::CARD_CERTIFIED}); + + context.setDidAuthenticateEac1(eac1); + QCOMPARE(context.getAcceptedEidTypes(), {AcceptedEidType::SE_CERTIFIED}); + + context.initAccessRightManager(TestAuthContext::getTerminalCvc(eac1)); + QCOMPARE(context.getAcceptedEidTypes(), {AcceptedEidType::CARD_CERTIFIED}); + + context.setDidAuthenticateEac1(nullptr); + QCOMPARE(context.getAcceptedEidTypes(), {AcceptedEidType::CARD_CERTIFIED}); + } + + void test_CanAllowed_data() { QTest::addColumn("usedAsSdk"); diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 6238bbaea..08372db29 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -17,7 +17,7 @@ if(JSONSCHEMA_BIN) else() add_test(NAME ${filename} COMMAND ${JSONSCHEMA_BIN} -i ${file} ${schema}) endif() - set_tests_properties(${filename} PROPERTIES LABELS "json" TIMEOUT 10) + set_tests_properties(${filename} PROPERTIES LABELS "json" TIMEOUT 30) endforeach() endif()