diff --git a/.github/actions/fetch-firmware-versions/action.yml b/.github/actions/fetch-firmware-versions/action.yml new file mode 100644 index 0000000..324f955 --- /dev/null +++ b/.github/actions/fetch-firmware-versions/action.yml @@ -0,0 +1,66 @@ +name: Fetch Firmware Versions +description: Clones the firmware repo and extracts available tags. +inputs: + token: + description: GitHub token for API access + required: true +outputs: + versions: + description: JSON array of firmware tags + value: ${{ steps.set-output.outputs.versions }} +runs: + using: "composite" + steps: + - name: Fetch firmware tags via REST + id: set-output + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.token }} + run: | + REPO=merckgroup/mtrust-device-sim + + # Debug: Check the raw response + echo "Fetching tags from $REPO..." + response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO/tags?per_page=100") + + # Debug: Show response structure + echo "Response preview:" + echo "$response" | head -c 200 + echo "..." + + # Check if response is valid JSON and contains expected data + if echo "$response" | jq -e 'type == "array"' > /dev/null; then + echo "Valid JSON array received" + tags=$(echo "$response" | jq -r '.[].name // empty') + if [ -n "$tags" ]; then + # Filter for major.minor versions only (no patch versions) + # This regex matches versions like v1.0, v2.1, v10.5, etc. + major_minor_tags=$(echo "$tags" | grep -E '^v[0-9]+\.[0-9]+$' || true) + + if [ -n "$major_minor_tags" ]; then + # Sort by version and take the 3 latest + latest_3_tags=$(echo "$major_minor_tags" | sort -V | tail -3) + + echo "Found major.minor firmware versions:" + echo "$major_minor_tags" + echo "" + echo "Latest 3 major.minor firmware versions:" + echo "$latest_3_tags" + + tags_json=$(echo "$latest_3_tags" | jq -R . | jq -s -c .) + echo "versions=$tags_json" >> $GITHUB_OUTPUT + else + echo "No major.minor version tags found" + echo "versions=[]" >> $GITHUB_OUTPUT + fi + else + echo "No tags found in response" + echo "versions=[]" >> $GITHUB_OUTPUT + fi + else + echo "Invalid response or error from GitHub API" + echo "Full response: $response" + echo "versions=[]" >> $GITHUB_OUTPUT + fi + \ No newline at end of file diff --git a/.github/actions/fetch-sdk-versions/action.yml b/.github/actions/fetch-sdk-versions/action.yml new file mode 100644 index 0000000..6c2419a --- /dev/null +++ b/.github/actions/fetch-sdk-versions/action.yml @@ -0,0 +1,26 @@ +name: Fetch SDK Versions +description: Gets the current SDK version from pubspec.yaml. +outputs: + versions: + description: JSON array containing only the current SDK version + value: ${{ steps.set-output.outputs.versions }} +runs: + using: "composite" + steps: + - name: Get current SDK version from pubspec.yaml + id: set-output + shell: bash + run: | + # Read the current version from pubspec.yaml + current_version=$(grep '^version:' pubspec.yaml | awk '{print $2}') + + if [ -n "$current_version" ]; then + echo "Current SDK version from pubspec.yaml: $current_version" + + # Create JSON array with only the current version + versions_json=$(echo "[\"v$current_version\"]" | jq -c .) + echo "versions=$versions_json" >> $GITHUB_OUTPUT + else + echo "Error: Could not read version from pubspec.yaml" + echo "versions=[]" >> $GITHUB_OUTPUT + fi diff --git a/.github/actions/generate-matrix/action.yml b/.github/actions/generate-matrix/action.yml new file mode 100644 index 0000000..6cc01db --- /dev/null +++ b/.github/actions/generate-matrix/action.yml @@ -0,0 +1,64 @@ +name: Generate Compatibility Matrix +description: Converts test result artifacts into a firmware-SDK compatibility matrix. +runs: + using: "composite" + steps: + - name: Download all compatibility artifacts + uses: actions/download-artifact@v4 + with: + path: all-results + + - name: Install dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y jq + + - name: Generate SDK to firmware compatibility map + shell: bash + run: | + mkdir -p assets + tmpfile=$(mktemp) + + echo '{}' > $tmpfile + + # Read package version from pubspec.yaml + package_version=$(grep '^version:' pubspec.yaml | awk '{print $2}') + + # Extract and group firmware versions per SDK + find all-results -name compat.json | while read file; do + sdk=$(jq -r .sdk "$file") + fw=$(jq -r .firmware "$file") + + # Remove leading 'v' if present + sdk=${sdk#v} + fw=${fw#v} + + tmp=$(mktemp) + jq --arg sdk "$sdk" --arg fw "$fw" ' + .[$sdk] += [$fw] // {($sdk): [$fw]} + ' "$tmpfile" > "$tmp" && mv "$tmp" "$tmpfile" + done + + # Convert lists to semver ranges and create final JSON structure + jq --arg version "$package_version" ' + { + package_version: $version, + compatibility: ( + to_entries | + map({ + key: .key, + value: ( + .value | sort_by(split(".") | map(tonumber)) | + "\(.[0]) - \(.[-1])" + ) + }) | from_entries + ) + } + ' "$tmpfile" > assets/firmware_compatibility.json + + - name: Upload full matrix + uses: actions/upload-artifact@v4 + with: + name: compatibility-matrix + path: assets/firmware_compatibility.json diff --git a/.github/actions/test-compatibility/action.yml b/.github/actions/test-compatibility/action.yml new file mode 100644 index 0000000..0ce6a79 --- /dev/null +++ b/.github/actions/test-compatibility/action.yml @@ -0,0 +1,68 @@ +name: Test Firmware/SDK Compatibility +description: Runs compatibility tests between a firmware version and an SDK version. +inputs: + firmware_version: + required: true + description: Firmware version tag + sdk_version: + required: true + description: SDK version tag + token: + required: true + description: GitHub token for accessing private repositories +runs: + using: "composite" + steps: + - name: Checkout SDK + uses: actions/checkout@v4 + with: + repository: emdgroup/mtrust-sec-kit + ref: ${{ inputs.sdk_version }} + path: sdk + + - name: Checkout device sim repo + uses: actions/checkout@v4 + with: + repository: merckgroup/mtrust-device-sim + ref: dev + path: mtrust-device-sim + token: ${{ inputs.token }} + + - name: Start device sim + id: urp-sim + uses: ./mtrust-device-sim/.github/actions/start-urp-sim + with: + repository: "mtrust-urp-os" + tag: ${{ inputs.firmware_version }} + environment: "d" + token: '' + + - name: Default tests for device sim + uses: ./mtrust-device-sim/.github/actions/test-urp-sim + + - name: Validate SDK + uses: emdgroup/mtrust-urp/.github/shared_actions/validate-flutter@dev + with: + directory: sdk + is_package: true + api_url: "https://api.dev.mtrust.io" + + - name: Mark compatibility as passed + if: success() + shell: bash + run: | + mkdir -p result + echo '{"firmware": "${{ inputs.firmware_version }}", "sdk": "${{ inputs.sdk_version }}"}' > result/compat.json + + - name: Upload result + if: success() + uses: actions/upload-artifact@v4 + with: + name: compat-${{ inputs.firmware_version }}-${{ inputs.sdk_version }} + path: result/compat.json + + - name: Stop device sim + uses: ./mtrust-device-sim/.github/actions/stop-urp-sim + with: + websocket_pid: ${{ steps.urp-sim.outputs.websocket_pid }} + pio_pid: ${{ steps.urp-sim.outputs.pio_pid }} diff --git a/.github/workflows/build_dev.yaml b/.github/workflows/build_dev.yaml index 5fa2e52..e6b2410 100644 --- a/.github/workflows/build_dev.yaml +++ b/.github/workflows/build_dev.yaml @@ -82,17 +82,137 @@ jobs: with: directory: "." + matrix-generation: + name: Generate Compatibility Matrix + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.generate-matrix.outputs.matrix }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Fetch firmware versions + uses: ./.github/actions/fetch-firmware-versions + id: fetch-firmware-versions + with: + token: ${{secrets.ELEVATED_TOKEN}} + + - name: Fetch SDK versions + uses: ./.github/actions/fetch-sdk-versions + id: fetch-sdk-versions + + - name: Generate compatibility matrix + id: generate-matrix + run: | + # Parse the JSON arrays and create a matrix + firmware_versions=$(echo '${{ steps.fetch-firmware-versions.outputs.versions }}' | jq -r '.[]') + sdk_versions=$(echo '${{ steps.fetch-sdk-versions.outputs.versions }}' | jq -r '.[]') + + echo "Latest 3 major.minor firmware versions:" + echo "$firmware_versions" + echo "" + echo "Current SDK version:" + echo "$sdk_versions" + echo "" + + # Create matrix combinations using current SDK version with latest 3 firmware versions + matrix_combinations="[]" + count=0 + + while IFS= read -r firmware; do + # For each firmware version, use the current SDK version + combination=$(jq -n --arg fw "$firmware" --arg sdk "$sdk_versions" '{firmware: $fw, sdk: $sdk}') + + # Add to matrix array + matrix_combinations=$(echo "$matrix_combinations" | jq --argjson combo "$combination" '. += [$combo]') + count=$((count + 1)) + done <<< "$firmware_versions" + + # Validate JSON before output + if echo "$matrix_combinations" | jq empty 2>/dev/null; then + echo "matrix=$matrix_combinations" >> $GITHUB_OUTPUT + echo "Generated matrix with $count combinations (latest 3 firmware × current SDK version)" + echo "Matrix preview:" + echo "$matrix_combinations" | jq '.[0:3]' # Show first 3 combinations + else + echo "Error: Invalid JSON generated" + echo "Generated content:" + echo "$matrix_combinations" + exit 1 + fi + + compatibility-tests: + name: Compatibility Tests + needs: matrix-generation + runs-on: ubuntu-latest + strategy: + matrix: + include: ${{ fromJson(needs.matrix-generation.outputs.matrix) }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Test compatibility + uses: ./.github/actions/test-compatibility + with: + token: ${{secrets.ELEVATED_TOKEN}} + firmware_version: ${{ matrix.firmware }} + sdk_version: ${{ matrix.sdk }} + + generate-compatibility-matrix: + name: Generate Compatibility Matrix + needs: [version, compatibility-tests] + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Generate matrix + uses: ./.github/actions/generate-matrix + + - name: Upload compatibility matrix artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-compatibility-matrix + path: assets/firmware_compatibility.json + + release: + name: Release Package + needs: [version, generate-compatibility-matrix] + runs-on: macos-latest + environment: release + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{secrets.ELEVATED_TOKEN}} + + - name: Download compatibility matrix + uses: actions/download-artifact@v4 + with: + name: firmware-compatibility-matrix + path: assets/ + + - name: 📇 Configure git + run: | + git fetch --prune --unshallow + git config --global user.name "GitHub Actions" + git config --global user.email "gh-actions@merckgroup.com" + shell: bash + # We first commit with proper message and add an empty commit to keep the files history clean - name: Update repo versions run: | git add . - git commit -m "chore(release): ${{ steps.get_new_version.outputs.result }}" - git commit --allow-empty -m "chore(release): ${{ steps.get_new_version.outputs.result }} [skip ci]" + git commit -m "chore(release): ${{ needs.version.outputs.version }}" + git commit --allow-empty -m "chore(release): ${{ needs.version.outputs.version }} [skip ci]" git push origin dev # For this part it is important to not push a commit with [skip ci] before the tag release - name: Push tag for pub.dev run: | - git commit --allow-empty -m "chore(release): ${{ steps.get_new_version.outputs.result }}" - git tag -a v${{ steps.get_new_version.outputs.result }} -m "Pub.dev version ${{ steps.get_new_version.outputs.result }}" - git push origin v${{ steps.get_new_version.outputs.result }} + git commit --allow-empty -m "chore(release): ${{ needs.version.outputs.version }}" + git tag -a v${{ needs.version.outputs.version }} -m "Pub.dev version ${{ needs.version.outputs.version }}" + git push origin v${{ needs.version.outputs.version }} diff --git a/.github/workflows/pr_dev.yaml b/.github/workflows/pr_dev.yaml index d075208..6d994bc 100644 --- a/.github/workflows/pr_dev.yaml +++ b/.github/workflows/pr_dev.yaml @@ -66,3 +66,100 @@ jobs: uses: emdgroup/mtrust-urp/.github/shared_actions/check-dart-licenses@dev with: directory: . + + matrix-generation: + name: Generate Compatibility Matrix + needs: validate_pr + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.generate-matrix.outputs.matrix }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Fetch firmware versions + uses: ./.github/actions/fetch-firmware-versions + id: fetch-firmware-versions + with: + token: ${{secrets.ELEVATED_TOKEN}} + + - name: Fetch SDK versions + uses: ./.github/actions/fetch-sdk-versions + id: fetch-sdk-versions + + - name: Generate compatibility matrix + id: generate-matrix + run: | + # Parse the JSON arrays and create a matrix + firmware_versions=$(echo '${{ steps.fetch-firmware-versions.outputs.versions }}' | jq -r '.[]') + sdk_versions=$(echo '${{ steps.fetch-sdk-versions.outputs.versions }}' | jq -r '.[]') + + echo "Latest 3 major.minor firmware versions:" + echo "$firmware_versions" + echo "" + echo "Current SDK version:" + echo "$sdk_versions" + echo "" + + # Create matrix combinations using current SDK version with latest 3 firmware versions + matrix_combinations="[]" + count=0 + + while IFS= read -r firmware; do + # For each firmware version, use the current SDK version + combination=$(jq -n --arg fw "$firmware" --arg sdk "$sdk_versions" '{firmware: $fw, sdk: $sdk}') + + # Add to matrix array + matrix_combinations=$(echo "$matrix_combinations" | jq --argjson combo "$combination" '. += [$combo]') + count=$((count + 1)) + done <<< "$firmware_versions" + + # Validate JSON before output + if echo "$matrix_combinations" | jq empty 2>/dev/null; then + # Use jq to compact the JSON for GitHub Actions output + compact_matrix=$(echo "$matrix_combinations" | jq -c .) + echo "matrix=$compact_matrix" >> $GITHUB_OUTPUT + echo "Generated matrix with $count combinations (latest 3 firmware × current SDK version)" + echo "Matrix preview:" + echo "$matrix_combinations" | jq '.[0:3]' # Show first 3 combinations + else + echo "Error: Invalid JSON generated" + echo "Generated content:" + echo "$matrix_combinations" + exit 1 + fi + + compatibility-tests: + name: Compatibility Tests + needs: matrix-generation + runs-on: ubuntu-latest + strategy: + matrix: + include: ${{ fromJson(needs.matrix-generation.outputs.matrix) }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Test compatibility + uses: ./.github/actions/test-compatibility + with: + token: ${{secrets.ELEVATED_TOKEN}} + firmware_version: ${{ matrix.firmware }} + sdk_version: ${{ matrix.sdk }} + + generate-compatibility-matrix: + name: Generate Compatibility Matrix + needs: [build_library, compatibility-tests] + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Generate matrix + uses: ./.github/actions/generate-matrix + + - name: Upload compatibility matrix artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-compatibility-matrix + path: assets/firmware_compatibility.json diff --git a/assets/firmware_compatibility.json b/assets/firmware_compatibility.json new file mode 100644 index 0000000..3df4e65 --- /dev/null +++ b/assets/firmware_compatibility.json @@ -0,0 +1,7 @@ +{ + "package_version": "3.0.0-1", + "compatibility": { + "3.0.0": "3.5.5 - 3.7.2", + "3.0.0-1": "3.1.9-R - 3.7.2" + } +} \ No newline at end of file diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 7af0528..573a563 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,11 +6,13 @@ import FlutterMacOS import Foundation import device_info_plus -import flutter_blue_plus +import flutter_blue_plus_darwin +import package_info_plus import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/example/pubspec.lock b/example/pubspec.lock index 12299fc..e7ff6a4 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: archive - sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a" + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.7" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: dependency: transitive description: @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.13.0" + bluez: + dependency: transitive + description: + name: bluez + sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" + url: "https://pub.dev" + source: hosted + version: "0.8.3" boolean_selector: dependency: transitive description: @@ -45,10 +53,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" cli_util: dependency: transitive description: @@ -81,22 +89,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" device_info_plus: dependency: transitive description: name: device_info_plus - sha256: b37d37c2f912ad4e8ec694187de87d05de2a3cb82b465ff1f65f65a2d05de544 + sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" url: "https://pub.dev" source: hosted - version: "11.2.1" + version: "11.5.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f url: "https://pub.dev" source: hosted - version: "7.0.2" + version: "7.0.3" fake_async: dependency: transitive description: @@ -109,18 +125,18 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: @@ -138,26 +154,66 @@ packages: dependency: transitive description: name: flutter_animate - sha256: "7c8a6594a9252dad30cc2ef16e33270b6248c4dedc3b3d06c86c4f3f4dc05ae5" + sha256: "7befe2d3252728afb77aecaaea1dec88a89d35b9b1d2eea6d04479e8af9117b5" url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.5.2" flutter_blue_plus: dependency: transitive description: name: flutter_blue_plus - sha256: ddbed8d86199ab4342152b2f5ce9a7ea8b348219f6880da3e7899f0a73d2dae3 + sha256: bfae0d24619940516261045d8b3c74b4c80ca82222426e05ffbf7f3ea9dbfb1a url: "https://pub.dev" source: hosted - version: "1.33.4" + version: "1.35.5" + flutter_blue_plus_android: + dependency: transitive + description: + name: flutter_blue_plus_android + sha256: "9723dd4ba7dcc3f27f8202e1159a302eb4cdb88ae482bb8e0dd733b82230a258" + url: "https://pub.dev" + source: hosted + version: "4.0.5" + flutter_blue_plus_darwin: + dependency: transitive + description: + name: flutter_blue_plus_darwin + sha256: f34123795352a9761e321589aa06356d3b53f007f13f7e23e3c940e733259b2d + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_blue_plus_linux: + dependency: transitive + description: + name: flutter_blue_plus_linux + sha256: "635443d1d333e3695733fd70e81ee0d87fa41e78aa81844103d2a8a854b0d593" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_blue_plus_platform_interface: + dependency: transitive + description: + name: flutter_blue_plus_platform_interface + sha256: a4bb70fa6fd09e0be163b004d773bf19e31104e257a4eb846b67f884ddd87de2 + url: "https://pub.dev" + source: hosted + version: "4.0.2" + flutter_blue_plus_web: + dependency: transitive + description: + name: flutter_blue_plus_web + sha256: "03023c259dbbba1bc5ce0fcd4e88b364f43eec01d45425f393023b9b2722cf4d" + url: "https://pub.dev" + source: hosted + version: "3.0.1" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5" + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" url: "https://pub.dev" source: hosted - version: "0.14.2" + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -183,10 +239,10 @@ packages: dependency: transitive description: name: flutter_shaders - sha256: "02750b545c01ff4d8e9bbe8f27a7731aa3778402506c67daa1de7f5fc3f4befe" + sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2" url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.3" flutter_sticky_header: dependency: transitive description: @@ -199,10 +255,10 @@ packages: dependency: transitive description: name: flutter_svg - sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 url: "https://pub.dev" source: hosted - version: "2.0.10+1" + version: "2.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -217,10 +273,10 @@ packages: dependency: transitive description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.4" fuzzy: dependency: transitive description: @@ -249,26 +305,26 @@ packages: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.4.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: transitive description: name: image - sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6" + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" url: "https://pub.dev" source: hosted - version: "4.5.2" + version: "4.5.4" intl: dependency: transitive description: @@ -281,10 +337,10 @@ packages: dependency: transitive description: name: jiffy - sha256: "1c1b86459969ff9f32dc5b0ffe392f1e08181e66396cf9dd8fa7c90552a691af" + sha256: "9bafbfe6d97587048bf449165e050029e716a12438f54a3d39e7e3a256decdac" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.4.3" json_annotation: dependency: transitive description: @@ -337,26 +393,26 @@ packages: dependency: transitive description: name: logger - sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4 + sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.6.0" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" lucide_icons_flutter: dependency: transitive description: name: lucide_icons_flutter - sha256: "98b5935ab5caeeadfc6efc6649c776b8bb9ffeb4879a1e24d0b78e4b104f40a1" + sha256: "2cc30b669d2e9329072bdd4e3f50d4a31d4dd6ee9e9748d639dab95cd2edd0ce" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" matcher: dependency: transitive description: @@ -392,18 +448,18 @@ packages: dependency: "direct main" description: name: mtrust_urp_ble_strategy - sha256: "5100452a073f9af8597ceaf76424038de60077b3e268da996338f6d63b7f2d5a" + sha256: "64afc172376f3e00bf12f571b6bc834d8a3f0f93c39574776223d7aa7ed8c434" url: "https://pub.dev" source: hosted - version: "9.1.0-7" + version: "9.1.0-11" mtrust_urp_core: dependency: transitive description: name: mtrust_urp_core - sha256: "225745795a036ded39ec83eb1d88c53ff3f3d37afd6446a9bdf495f90637b7d3" + sha256: dff6c497d85abdbb0f973200d7e12eab8a5bcdf19e884b9b671da28d340a00c2 url: "https://pub.dev" source: hosted - version: "9.1.0-9" + version: "9.1.0-11" mtrust_urp_types: dependency: "direct main" description: @@ -416,18 +472,18 @@ packages: dependency: "direct main" description: name: mtrust_urp_ui - sha256: ae8e8826dfd84a71662dcb560c3865609893e9ec237430f5c12e9f17ea097f93 + sha256: bbcee739e6fa685c312af9faad4f43d1955706c0532751c7fb0b09418950c712 url: "https://pub.dev" source: hosted - version: "9.1.0-9" + version: "9.1.0-11" mtrust_urp_virtual_strategy: dependency: "direct main" description: name: mtrust_urp_virtual_strategy - sha256: "3686e02ad12854f9a10d189c6499a21734cd347c81170561beca97ef7ad80006" + sha256: d6e227c0e242c5d75db075fcad8e531e9754e84b9ef3ddf66b044ae6ce98dcd0 url: "https://pub.dev" source: hosted - version: "9.1.0-7" + version: "9.1.0-11" multi_split_view: dependency: transitive description: @@ -444,6 +500,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + url: "https://pub.dev" + source: hosted + version: "3.2.0" path: dependency: transitive description: @@ -456,10 +528,10 @@ packages: dependency: transitive description: name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" path_provider_linux: dependency: transitive description: @@ -480,26 +552,26 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -512,10 +584,10 @@ packages: dependency: transitive description: name: posix - sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" protobuf: dependency: transitive description: @@ -528,10 +600,26 @@ packages: dependency: transitive description: name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" responsive_builder: dependency: transitive description: @@ -540,46 +628,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.1" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" sensors_plus: dependency: transitive description: name: sensors_plus - sha256: "6898cd4490ffc27fea4de5976585e92fae55355175d46c6c3b3d719d42f9e230" + sha256: "905282c917c6bb731c242f928665c2ea15445aa491249dea9d98d7c79dc8fd39" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "6.1.1" sensors_plus_platform_interface: dependency: transitive description: name: sensors_plus_platform_interface - sha256: bc472d6cfd622acb4f020e726433ee31788b038056691ba433fec80e448a094f + sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.1" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84 + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -600,10 +696,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: @@ -677,10 +773,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" value_layout_builder: dependency: transitive description: @@ -693,26 +789,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.19" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.17" vector_math: dependency: transitive description: @@ -733,42 +829,42 @@ packages: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" win32: dependency: transitive description: name: win32 - sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" url: "https://pub.dev" source: hosted - version: "5.5.4" + version: "5.14.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "2.1.0" wolt_modal_sheet: dependency: transitive description: name: wolt_modal_sheet - sha256: b2d1c2af08ff70c17a66325d6e510cb2f902f432c887cc55e72c55701a94fac4 + sha256: "03e28e39dd4de44dc58a7c623877488a89ca3b41a62fc3e70bfc86b64be067d6" url: "https://pub.dev" source: hosted - version: "0.9.4" + version: "0.11.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: @@ -786,5 +882,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.7.0-0 <4.0.0" + dart: ">=3.8.0 <4.0.0" flutter: ">=3.32.0" diff --git a/lib/src/sec_reader.dart b/lib/src/sec_reader.dart index f3e10d2..67f3f07 100644 --- a/lib/src/sec_reader.dart +++ b/lib/src/sec_reader.dart @@ -1,8 +1,11 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:mtrust_sec_kit/mtrust_sec_kit.dart'; +import 'package:pub_semver/pub_semver.dart'; /// [SECReader] is a class that provides a high-level API to interact with /// a SEC reader. @@ -97,6 +100,48 @@ class SECReader extends CmdWrapper { return SECReader(connectionStrategy: connectionStrategy); } + Future> _loadFirmwareCompatibility() async { + final jsonStr = await rootBundle.loadString('packages/mtrust_sec_kit/assets/firmware_compatibility.json'); + return json.decode(jsonStr) as Map; + } + + /// Returns the required firmware version (as a range of versions) for the currently used SDK + Future requiredFirmwareRange() async { + final map = await _loadFirmwareCompatibility(); + final sdkVersion = map['package_version'] as String; + final compat = map['compatibility'] as Map; + final compatibilityMap = compat.map((key, value) => MapEntry(key, value.toString())); + return compatibilityMap[sdkVersion]; + } + + /// Checks wether the current SDK is compatible with the firmware installed on the device. + Future compatibilityCheck(String firmwareVersion) async { + final fwRange = await requiredFirmwareRange(); + if(fwRange == null) { + return false; + } + + // NOTE: It's important to split at ' - ' inlcuding the spaces as version can have an appending + // as described in Semantic Versioning Specification (e.g. 1.0.0-alpha) + final parts = fwRange.split(' - ').map((s) => s.trim()).toList(); + if(parts.length != 2) { + return false; + } + + final fwMin = Version.parse(parts[0]); + final fwMax = Version.parse(parts[1]); + final currentFw = Version.parse(firmwareVersion); + + final constraint = VersionRange( + min: fwMin, + max: fwMax, + includeMin: true, + includeMax: true, + ); + + return constraint.allows(currentFw); + } + Future _addCommandToQueue({ UrpCoreCommand? coreCommand, UrpSecDeviceCommand? deviceCommand, diff --git a/lib/src/ui/l10n/sec_de.arb b/lib/src/ui/l10n/sec_de.arb index 9f196fe..c85ada5 100644 --- a/lib/src/ui/l10n/sec_de.arb +++ b/lib/src/ui/l10n/sec_de.arb @@ -7,6 +7,7 @@ "buttonContinue": "Weiter", "retry": "Wiederholen", "connected": "Verbunden", + "disconnect": "Verbindung trennen", "turnOnPrompt": "Zum Einschalten Taste drücken", "timeHint": "Sobald der Vorgang gestartet wurde, haben Sie 30 Sekunden Zeit zum Scannen", "readyToScan": "Bereit zum Scannen", @@ -17,7 +18,9 @@ "scanning": "Scannen...", "secondsLeft": "{seconds}s\nverbleibend", "searchingHint": "Stellen Sie sicher, dass die LED \n am Reader blau blinkt.", - "incompatibleFirmware": "Inkompatible Firmware. Bitte Update durchführen!", + "incompatibleFirmware": "Reader Firmware inkompatibel", + "requiredFirmware": "Diese App benötigt einen Reader mit einer Firmware Version von", + "firmwareHint": "Wenn Sie der Besitzer des Readers sind, können Sie die Firmware in the M-Trust Konsole aktualisieren", "tokenFailed": "Die Vorbereitung für den Scan ist fehlgeschlagen. Bitte stellen Sie sicher, dass Sie eine funktionierende Internetverbindung haben.", "readingsLeft": "Internetverbindung in {n} Messungen notwendig" } \ No newline at end of file diff --git a/lib/src/ui/l10n/sec_en.arb b/lib/src/ui/l10n/sec_en.arb index ee1588f..0c9f19d 100644 --- a/lib/src/ui/l10n/sec_en.arb +++ b/lib/src/ui/l10n/sec_en.arb @@ -8,6 +8,7 @@ "buttonContinue": "Continue", "retry": "Retry", "connected": "Connected", + "disconnect": "Disconnect", "turnOnPrompt": "Press the button on the reader to turn it on", "timeHint": "Once started you will have 30s to scan", "readyToScan": "Ready to scan", @@ -19,7 +20,9 @@ "searching": "Searching...", "scanning": "Scanning...", "secondsLeft": "{seconds}s\nleft", - "incompatibleFirmware": "Firmware incompatible. Please update!", + "incompatibleFirmware": "Reader version incompatible", + "requiredFirmware": "This app requires a reader with a firmware version of", + "firmwareHint": "If you are the device owner, you can update the device firmware in the M-Trust console", "tokenFailed": "Failed to prepare for scan. Please make sure you have a working internet connection", "readingsLeft": "Internet connection required in {n} measurements" } \ No newline at end of file diff --git a/lib/src/ui/l10n/sec_locale.dart b/lib/src/ui/l10n/sec_locale.dart index bd28543..3839ba4 100644 --- a/lib/src/ui/l10n/sec_locale.dart +++ b/lib/src/ui/l10n/sec_locale.dart @@ -63,7 +63,7 @@ import 'sec_locale_en.dart'; /// property. abstract class SecLocalizations { SecLocalizations(String locale) - : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); final String localeName; @@ -86,16 +86,16 @@ abstract class SecLocalizations { /// of delegates is preferred or required. static const List> localizationsDelegates = >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ Locale('de'), - Locale('en'), + Locale('en') ]; /// No description provided for @successfullyVerified. @@ -146,6 +146,12 @@ abstract class SecLocalizations { /// **'Connected'** String get connected; + /// No description provided for @disconnect. + /// + /// In en, this message translates to: + /// **'Disconnect'** + String get disconnect; + /// No description provided for @turnOnPrompt. /// /// In en, this message translates to: @@ -215,9 +221,21 @@ abstract class SecLocalizations { /// No description provided for @incompatibleFirmware. /// /// In en, this message translates to: - /// **'Firmware incompatible. Please update!'** + /// **'Reader version incompatible'** String get incompatibleFirmware; + /// No description provided for @requiredFirmware. + /// + /// In en, this message translates to: + /// **'This app requires a reader with a firmware version of'** + String get requiredFirmware; + + /// No description provided for @firmwareHint. + /// + /// In en, this message translates to: + /// **'If you are the device owner, you can update the device firmware in the M-Trust console'** + String get firmwareHint; + /// No description provided for @tokenFailed. /// /// In en, this message translates to: @@ -258,9 +276,8 @@ SecLocalizations lookupSecLocalizations(Locale locale) { } throw FlutterError( - 'SecLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.', - ); + 'SecLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); } diff --git a/lib/src/ui/l10n/sec_locale_de.dart b/lib/src/ui/l10n/sec_locale_de.dart index a639319..4149605 100644 --- a/lib/src/ui/l10n/sec_locale_de.dart +++ b/lib/src/ui/l10n/sec_locale_de.dart @@ -32,6 +32,9 @@ class SecLocalizationsDe extends SecLocalizations { @override String get connected => 'Verbunden'; + @override + String get disconnect => 'Verbindung trennen'; + @override String get turnOnPrompt => 'Zum Einschalten Taste drücken'; @@ -70,8 +73,15 @@ class SecLocalizationsDe extends SecLocalizations { } @override - String get incompatibleFirmware => - 'Inkompatible Firmware. Bitte Update durchführen!'; + String get incompatibleFirmware => 'Reader Firmware inkompatibel'; + + @override + String get requiredFirmware => + 'Diese App benötigt einen Reader mit einer Firmware Version von'; + + @override + String get firmwareHint => + 'Wenn Sie der Besitzer des Readers sind, können Sie die Firmware in the M-Trust Konsole aktualisieren'; @override String get tokenFailed => diff --git a/lib/src/ui/l10n/sec_locale_en.dart b/lib/src/ui/l10n/sec_locale_en.dart index d9aad73..83a9c94 100644 --- a/lib/src/ui/l10n/sec_locale_en.dart +++ b/lib/src/ui/l10n/sec_locale_en.dart @@ -32,6 +32,9 @@ class SecLocalizationsEn extends SecLocalizations { @override String get connected => 'Connected'; + @override + String get disconnect => 'Disconnect'; + @override String get turnOnPrompt => 'Press the button on the reader to turn it on'; @@ -69,7 +72,15 @@ class SecLocalizationsEn extends SecLocalizations { } @override - String get incompatibleFirmware => 'Firmware incompatible. Please update!'; + String get incompatibleFirmware => 'Reader version incompatible'; + + @override + String get requiredFirmware => + 'This app requires a reader with a firmware version of'; + + @override + String get firmwareHint => + 'If you are the device owner, you can update the device firmware in the M-Trust console'; @override String get tokenFailed => diff --git a/lib/src/ui/sec_widget.dart b/lib/src/ui/sec_widget.dart index 2f9bd41..f5e10bd 100644 --- a/lib/src/ui/sec_widget.dart +++ b/lib/src/ui/sec_widget.dart @@ -61,6 +61,18 @@ class SecWidget extends StatelessWidget { connectionStrategy: strategy, ); + final info = await reader.info(); + final compatible = await reader.compatibilityCheck(info.fwVersion); + final requiredFirmware = await reader.requiredFirmwareRange(); + if(!compatible) { + throw LdException( + message: 'Required version: $requiredFirmware', + exception: SecReaderException( + type: SecReaderExceptionType.incompatibleFirmware, + ), + ); + } + if (tokenAmount != null) { reader.setTokenAmount(tokenAmount!); } @@ -73,6 +85,41 @@ class SecWidget extends StatelessWidget { var message = controller.state.error?.message ?? 'Unknown error'; + if(controller.state.error?.exception is SecReaderException) { + final error = controller.state.error?.exception as SecReaderException; + if(error.type == SecReaderExceptionType.incompatibleFirmware) { + final fwRange = message.split('Required version: ').last; + return LdAutoSpace( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LdTextHs( + SecLocalizations.of(context).incompatibleFirmware, + textAlign: TextAlign.center, + ), + ldSpacerL, + LdTextP( + '${SecLocalizations.of(context).requiredFirmware} $fwRange', + textAlign: TextAlign.center, + ), + ldSpacerS, + LdMute( + child: LdTextP( + SecLocalizations.of(context).firmwareHint, + textAlign: TextAlign.center, + ), + ), + ldSpacerL, + LdButtonWarning( + onPressed: strategy.disconnectDevice, + context: context, + child: Text( + SecLocalizations.of(context).disconnect, + ), + ), + ], + ); + } + } if (controller.state.error?.exception.runtimeType is ApiException) { message = locale.tokenFailed; diff --git a/pubspec.yaml b/pubspec.yaml index 4d19d72..f3e51d9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,8 @@ dependencies: mtrust_urp_core: ^9.1.0-9 mtrust_urp_types: ^6.2.0 mtrust_urp_ui: ^9.1.0-9 + package_info_plus: ^8.3.0 + pub_semver: ^2.2.0 dev_dependencies: flutter_test: sdk: flutter diff --git a/test/test_utils.dart b/test/test_utils.dart index 54a6ad3..4095ae2 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -27,6 +27,13 @@ class CompleterStrategy { CompleterStrategy({bool withReaders = false, this.useDelays = false}) { strategy = UrpVirtualStrategy((UrpRequest request) async { final payload = UrpSecCommandWrapper.fromBuffer(request.payload); + if(payload.coreCommand.command == UrpCommand.urpGetInfo) { + return UrpResponse( + payload: UrpDeviceInfo( + fwVersion: '3.5.5', + ).writeToBuffer(), + ); + } switch (payload.deviceCommand.command) { case (UrpSecCommand.urpSecPrime): primeCompleter = Completer();